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:
|
for item in validatorIds:
|
||||||
case item.kind
|
case item.kind
|
||||||
of ValidatorQueryKind.Key:
|
of ValidatorQueryKind.Key:
|
||||||
if item.key in keyset:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
UniqueValidatorKeyError)
|
|
||||||
keyset.incl(item.key)
|
keyset.incl(item.key)
|
||||||
of ValidatorQueryKind.Index:
|
of ValidatorQueryKind.Index:
|
||||||
let vindex =
|
let vindex =
|
||||||
|
@ -270,27 +267,20 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
return RestApiResponse.jsonError(Http500,
|
return RestApiResponse.jsonError(Http500,
|
||||||
UnsupportedValidatorIndexValueError)
|
UnsupportedValidatorIndexValueError)
|
||||||
let index = vres.get()
|
let index = vres.get()
|
||||||
if uint64(index) >= validatorsCount:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
ValidatorNotFoundError)
|
|
||||||
if index in indexset:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
UniqueValidatorIndexError)
|
|
||||||
index
|
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:
|
if len(keyset) > 0:
|
||||||
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
||||||
keyset.toSeq())
|
keyset.toSeq())
|
||||||
|
# Remove all the duplicates.
|
||||||
for item in optIndices:
|
for item in optIndices:
|
||||||
if item.isNone():
|
# We ignore missing keys.
|
||||||
return RestApiResponse.jsonError(Http400,
|
if item.isSome():
|
||||||
ValidatorNotFoundError)
|
indexset.incl(item.get())
|
||||||
let vindex = item.get()
|
|
||||||
if vindex in indexset:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
UniqueValidatorIndexError)
|
|
||||||
indexset.incl(vindex)
|
|
||||||
indexset.toSeq()
|
indexset.toSeq()
|
||||||
|
|
||||||
let response =
|
let response =
|
||||||
|
@ -369,7 +359,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
||||||
[vid.key])
|
[vid.key])
|
||||||
if optIndices[0].isNone():
|
if optIndices[0].isNone():
|
||||||
return RestApiResponse.jsonError(Http400, ValidatorNotFoundError)
|
return RestApiResponse.jsonError(Http404, ValidatorNotFoundError)
|
||||||
optIndices[0].get()
|
optIndices[0].get()
|
||||||
of ValidatorQueryKind.Index:
|
of ValidatorQueryKind.Index:
|
||||||
let vres = vid.index.toValidatorIndex()
|
let vres = vid.index.toValidatorIndex()
|
||||||
|
@ -383,7 +373,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
UnsupportedValidatorIndexValueError)
|
UnsupportedValidatorIndexValueError)
|
||||||
let index = vres.get()
|
let index = vres.get()
|
||||||
if uint64(index) >= validatorsCount:
|
if uint64(index) >= validatorsCount:
|
||||||
return RestApiResponse.jsonError(Http400, ValidatorNotFoundError)
|
return RestApiResponse.jsonError(Http404, ValidatorNotFoundError)
|
||||||
index
|
index
|
||||||
|
|
||||||
let
|
let
|
||||||
|
@ -445,9 +435,6 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
for item in validatorIds:
|
for item in validatorIds:
|
||||||
case item.kind
|
case item.kind
|
||||||
of ValidatorQueryKind.Key:
|
of ValidatorQueryKind.Key:
|
||||||
if item.key in keyset:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
UniqueValidatorKeyError)
|
|
||||||
keyset.incl(item.key)
|
keyset.incl(item.key)
|
||||||
of ValidatorQueryKind.Index:
|
of ValidatorQueryKind.Index:
|
||||||
let vindex =
|
let vindex =
|
||||||
|
@ -461,28 +448,20 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
of ValidatorIndexError.UnsupportedValue:
|
of ValidatorIndexError.UnsupportedValue:
|
||||||
return RestApiResponse.jsonError(Http500,
|
return RestApiResponse.jsonError(Http500,
|
||||||
UnsupportedValidatorIndexValueError)
|
UnsupportedValidatorIndexValueError)
|
||||||
let index = vres.get()
|
vres.get()
|
||||||
if uint64(index) >= validatorsCount:
|
# We only adding validator indices which are present in
|
||||||
return RestApiResponse.jsonError(Http400,
|
# validators list at this moment.
|
||||||
ValidatorNotFoundError)
|
if uint64(vindex) < validatorsCount:
|
||||||
if index in indexset:
|
indexset.incl(vindex)
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
UniqueValidatorIndexError)
|
|
||||||
index
|
|
||||||
indexset.incl(vindex)
|
|
||||||
|
|
||||||
if len(keyset) > 0:
|
if len(keyset) > 0:
|
||||||
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
let optIndices = keysToIndices(node.restKeysCache, stateData.data,
|
||||||
keyset.toSeq())
|
keyset.toSeq())
|
||||||
|
# Remove all the duplicates.
|
||||||
for item in optIndices:
|
for item in optIndices:
|
||||||
if item.isNone():
|
# We ignore missing keys.
|
||||||
return RestApiResponse.jsonError(Http400,
|
if item.isSome():
|
||||||
ValidatorNotFoundError)
|
indexset.incl(item.get())
|
||||||
let vindex = item.get()
|
|
||||||
if vindex in indexset:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
UniqueValidatorIndexError)
|
|
||||||
indexset.incl(vindex)
|
|
||||||
indexset.toSeq()
|
indexset.toSeq()
|
||||||
|
|
||||||
let response =
|
let response =
|
||||||
|
@ -648,8 +627,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
var res: seq[ValidatorIndex]
|
var res: seq[ValidatorIndex]
|
||||||
let optIndices = keysToIndices(node.restKeysCache, stateData().data,
|
let optIndices = keysToIndices(node.restKeysCache, stateData().data,
|
||||||
keys)
|
keys)
|
||||||
|
# Remove all the duplicates.
|
||||||
for item in optIndices:
|
for item in optIndices:
|
||||||
if item.isNone():
|
if item.isNone():
|
||||||
|
# This should not be happened, because keys are from state.
|
||||||
return RestApiResponse.jsonError(Http500, InternalServerError,
|
return RestApiResponse.jsonError(Http500, InternalServerError,
|
||||||
"Could not get validator indices")
|
"Could not get validator indices")
|
||||||
res.add(item.get())
|
res.add(item.get())
|
||||||
|
|
|
@ -108,14 +108,10 @@ const
|
||||||
"Could not find validator"
|
"Could not find validator"
|
||||||
ValidatorStatusNotFoundError* =
|
ValidatorStatusNotFoundError* =
|
||||||
"Could not obtain validator's status"
|
"Could not obtain validator's status"
|
||||||
UniqueValidatorKeyError* =
|
|
||||||
"Only unique validator's keys are allowed"
|
|
||||||
TooHighValidatorIndexValueError* =
|
TooHighValidatorIndexValueError* =
|
||||||
"Validator index exceeds maximum number of validators allowed"
|
"Validator index exceeds maximum number of validators allowed"
|
||||||
UnsupportedValidatorIndexValueError* =
|
UnsupportedValidatorIndexValueError* =
|
||||||
"Validator index exceeds maximum supported number of validators"
|
"Validator index exceeds maximum supported number of validators"
|
||||||
UniqueValidatorIndexError* =
|
|
||||||
"Only unique validator's index are allowed"
|
|
||||||
StateNotFoundError* =
|
StateNotFoundError* =
|
||||||
"Could not get requested state"
|
"Could not get requested state"
|
||||||
SlotNotFoundError* =
|
SlotNotFoundError* =
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * 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).
|
# * 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.
|
# 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,
|
import stew/[results, base10], chronicles, json_serialization,
|
||||||
json_serialization/std/[options, net],
|
json_serialization/std/[options, net],
|
||||||
nimcrypto/utils as ncrutils
|
nimcrypto/utils as ncrutils
|
||||||
|
@ -31,7 +31,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(Http400,
|
||||||
InvalidValidatorIndexValueError,
|
InvalidValidatorIndexValueError,
|
||||||
$dres.error())
|
$dres.error())
|
||||||
var res: seq[ValidatorIndex]
|
var res: HashSet[ValidatorIndex]
|
||||||
let items = dres.get()
|
let items = dres.get()
|
||||||
for item in items:
|
for item in items:
|
||||||
let vres = item.toValidatorIndex()
|
let vres = item.toValidatorIndex()
|
||||||
|
@ -43,7 +43,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
of ValidatorIndexError.UnsupportedValue:
|
of ValidatorIndexError.UnsupportedValue:
|
||||||
return RestApiResponse.jsonError(Http500,
|
return RestApiResponse.jsonError(Http500,
|
||||||
UnsupportedValidatorIndexValueError)
|
UnsupportedValidatorIndexValueError)
|
||||||
res.add(vres.get())
|
res.incl(vres.get())
|
||||||
if len(res) == 0:
|
if len(res) == 0:
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(Http400,
|
||||||
EmptyValidatorIndexArrayError)
|
EmptyValidatorIndexArrayError)
|
||||||
|
@ -203,7 +203,8 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
kres
|
kres
|
||||||
|
|
||||||
# TODO: We doing this because `participants` are stored as array of
|
# 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 =
|
let participantIndices =
|
||||||
block:
|
block:
|
||||||
var res: seq[ValidatorIndex]
|
var res: seq[ValidatorIndex]
|
||||||
|
@ -220,10 +221,10 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
block:
|
block:
|
||||||
var res: Table[ValidatorIndex, int]
|
var res: Table[ValidatorIndex, int]
|
||||||
for listIndex, validatorIndex in indexList.pairs():
|
for listIndex, validatorIndex in indexList.pairs():
|
||||||
if uint64(validatorIndex) >= validatorsCount:
|
# We ignore indices which could not fit in current list of
|
||||||
return RestApiResponse.jsonError(Http400,
|
# validators.
|
||||||
ValidatorNotFoundError)
|
if uint64(validatorIndex) < validatorsCount:
|
||||||
res[validatorIndex] = listIndex
|
res[validatorIndex] = listIndex
|
||||||
res
|
res
|
||||||
|
|
||||||
template isEmpty(duty: RestSyncCommitteeDuty): bool =
|
template isEmpty(duty: RestSyncCommitteeDuty): bool =
|
||||||
|
|
|
@ -672,9 +672,9 @@
|
||||||
"headers": {"Accept": "application/json"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "oneof", "value": ["400", "200"]},
|
"status": {"operator": "oneof", "value": ["404", "200"]},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1155,7 +1155,7 @@
|
||||||
"headers": {"Accept": "application/json"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "404"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||||
}
|
}
|
||||||
|
@ -1168,7 +1168,7 @@
|
||||||
"headers": {"Accept": "application/json"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "404"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||||
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
"body": [{"operator": "jstructcmpns", "value": {"code": "", "message": ""}}]
|
||||||
}
|
}
|
||||||
|
@ -1359,9 +1359,9 @@
|
||||||
"headers": {"Accept": "application/json"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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"}
|
"headers": {"Accept": "application/json"}
|
||||||
},
|
},
|
||||||
"response": {
|
"response": {
|
||||||
"status": {"operator": "equals", "value": "400"},
|
"status": {"operator": "equals", "value": "200"},
|
||||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
"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