Allow duplicate validator identifiers in REST requests. (#2992)
Missing validators are not error anymore. Fix tests.
This commit is contained in:
parent
75a8fe3b2c
commit
073389377e
|
@ -253,9 +253,6 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
for item in validatorIds:
|
||||
case item.kind
|
||||
of ValidatorQueryKind.Key:
|
||||
if item.key in keyset:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
UniqueValidatorKeyError)
|
||||
keyset.incl(item.key)
|
||||
of ValidatorQueryKind.Index:
|
||||
let vindex =
|
||||
|
@ -270,27 +267,20 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
return RestApiResponse.jsonError(Http500,
|
||||
UnsupportedValidatorIndexValueError)
|
||||
let index = vres.get()
|
||||
if uint64(index) >= validatorsCount:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
ValidatorNotFoundError)
|
||||
if index in indexset:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
UniqueValidatorIndexError)
|
||||
index
|
||||
indexset.incl(vindex)
|
||||
if uint64(vindex) < validatorsCount:
|
||||
# We only adding validator indices which are present in
|
||||
# validators list at this moment.
|
||||
indexset.incl(vindex)
|
||||
|
||||
if len(keyset) > 0:
|
||||
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
||||
keyset.toSeq())
|
||||
# Remove all the duplicates.
|
||||
for item in optIndices:
|
||||
if item.isNone():
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
ValidatorNotFoundError)
|
||||
let vindex = item.get()
|
||||
if vindex in indexset:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
UniqueValidatorIndexError)
|
||||
indexset.incl(vindex)
|
||||
# We ignore missing keys.
|
||||
if item.isSome():
|
||||
indexset.incl(item.get())
|
||||
indexset.toSeq()
|
||||
|
||||
let response =
|
||||
|
@ -369,7 +359,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
||||
[vid.key])
|
||||
if optIndices[0].isNone():
|
||||
return RestApiResponse.jsonError(Http400, ValidatorNotFoundError)
|
||||
return RestApiResponse.jsonError(Http404, ValidatorNotFoundError)
|
||||
optIndices[0].get()
|
||||
of ValidatorQueryKind.Index:
|
||||
let vres = vid.index.toValidatorIndex()
|
||||
|
@ -383,7 +373,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
UnsupportedValidatorIndexValueError)
|
||||
let index = vres.get()
|
||||
if uint64(index) >= validatorsCount:
|
||||
return RestApiResponse.jsonError(Http400, ValidatorNotFoundError)
|
||||
return RestApiResponse.jsonError(Http404, ValidatorNotFoundError)
|
||||
index
|
||||
|
||||
let
|
||||
|
@ -445,9 +435,6 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
for item in validatorIds:
|
||||
case item.kind
|
||||
of ValidatorQueryKind.Key:
|
||||
if item.key in keyset:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
UniqueValidatorKeyError)
|
||||
keyset.incl(item.key)
|
||||
of ValidatorQueryKind.Index:
|
||||
let vindex =
|
||||
|
@ -461,28 +448,20 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
of ValidatorIndexError.UnsupportedValue:
|
||||
return RestApiResponse.jsonError(Http500,
|
||||
UnsupportedValidatorIndexValueError)
|
||||
let index = vres.get()
|
||||
if uint64(index) >= validatorsCount:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
ValidatorNotFoundError)
|
||||
if index in indexset:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
UniqueValidatorIndexError)
|
||||
index
|
||||
indexset.incl(vindex)
|
||||
vres.get()
|
||||
# We only adding validator indices which are present in
|
||||
# validators list at this moment.
|
||||
if uint64(vindex) < validatorsCount:
|
||||
indexset.incl(vindex)
|
||||
|
||||
if len(keyset) > 0:
|
||||
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
||||
keyset.toSeq())
|
||||
# Remove all the duplicates.
|
||||
for item in optIndices:
|
||||
if item.isNone():
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
ValidatorNotFoundError)
|
||||
let vindex = item.get()
|
||||
if vindex in indexset:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
UniqueValidatorIndexError)
|
||||
indexset.incl(vindex)
|
||||
# We ignore missing keys.
|
||||
if item.isSome():
|
||||
indexset.incl(item.get())
|
||||
indexset.toSeq()
|
||||
|
||||
let response =
|
||||
|
@ -648,8 +627,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
var res: seq[ValidatorIndex]
|
||||
let optIndices = keysToIndices(node.restKeysCache, stateData().data,
|
||||
keys)
|
||||
# Remove all the duplicates.
|
||||
for item in optIndices:
|
||||
if item.isNone():
|
||||
# This should not be happened, because keys are from state.
|
||||
return RestApiResponse.jsonError(Http500, InternalServerError,
|
||||
"Could not get validator indices")
|
||||
res.add(item.get())
|
||||
|
|
|
@ -108,14 +108,10 @@ const
|
|||
"Could not find validator"
|
||||
ValidatorStatusNotFoundError* =
|
||||
"Could not obtain validator's status"
|
||||
UniqueValidatorKeyError* =
|
||||
"Only unique validator's keys are allowed"
|
||||
TooHighValidatorIndexValueError* =
|
||||
"Validator index exceeds maximum number of validators allowed"
|
||||
UnsupportedValidatorIndexValueError* =
|
||||
"Validator index exceeds maximum supported number of validators"
|
||||
UniqueValidatorIndexError* =
|
||||
"Only unique validator's index are allowed"
|
||||
StateNotFoundError* =
|
||||
"Could not get requested state"
|
||||
SlotNotFoundError* =
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
||||
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
||||
import std/[typetraits, strutils, sequtils]
|
||||
import std/[typetraits, strutils, sets, sequtils]
|
||||
import stew/[results, base10], chronicles, json_serialization,
|
||||
json_serialization/std/[options, net],
|
||||
nimcrypto/utils as ncrutils
|
||||
|
@ -31,7 +31,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
return RestApiResponse.jsonError(Http400,
|
||||
InvalidValidatorIndexValueError,
|
||||
$dres.error())
|
||||
var res: seq[ValidatorIndex]
|
||||
var res: HashSet[ValidatorIndex]
|
||||
let items = dres.get()
|
||||
for item in items:
|
||||
let vres = item.toValidatorIndex()
|
||||
|
@ -43,7 +43,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
of ValidatorIndexError.UnsupportedValue:
|
||||
return RestApiResponse.jsonError(Http500,
|
||||
UnsupportedValidatorIndexValueError)
|
||||
res.add(vres.get())
|
||||
res.incl(vres.get())
|
||||
if len(res) == 0:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
EmptyValidatorIndexArrayError)
|
||||
|
@ -203,7 +203,8 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
kres
|
||||
|
||||
# TODO: We doing this because `participants` are stored as array of
|
||||
# validator keys, so we need to convert it to indices.
|
||||
# validator keys, so we need to convert it to indices, and if any of
|
||||
# public keys are missing, it means some unexpected error.
|
||||
let participantIndices =
|
||||
block:
|
||||
var res: seq[ValidatorIndex]
|
||||
|
@ -220,10 +221,10 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
block:
|
||||
var res: Table[ValidatorIndex, int]
|
||||
for listIndex, validatorIndex in indexList.pairs():
|
||||
if uint64(validatorIndex) >= validatorsCount:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
ValidatorNotFoundError)
|
||||
res[validatorIndex] = listIndex
|
||||
# We ignore indices which could not fit in current list of
|
||||
# validators.
|
||||
if uint64(validatorIndex) < validatorsCount:
|
||||
res[validatorIndex] = listIndex
|
||||
res
|
||||
|
||||
template isEmpty(duty: RestSyncCommitteeDuty): bool =
|
||||
|
|
|
@ -672,9 +672,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -685,9 +685,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -698,9 +698,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -880,9 +880,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -893,9 +893,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -997,7 +997,7 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "oneof", "value": ["400", "200"]},
|
||||
"status": {"operator": "oneof", "value": ["404", "200"]},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
}
|
||||
},
|
||||
|
@ -1155,7 +1155,7 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "404"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
}
|
||||
|
@ -1168,7 +1168,7 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "404"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
}
|
||||
|
@ -1359,9 +1359,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1372,9 +1372,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -1385,9 +1385,9 @@
|
|||
"headers": {"Accept": "application/json"}
|
||||
},
|
||||
"response": {
|
||||
"status": {"operator": "equals", "value": "400"},
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": [{"index": "", "balance": "", "status": "", "validator": {"pubkey": "", "withdrawal_credentials": "", "effective_balance": "", "slashed": false, "activation_eligibility_epoch": "", "activation_epoch": "", "exit_epoch": "", "withdrawable_epoch": ""}}]}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue