Allow duplicate validator identifiers in REST requests. (#2992)

Missing validators are not error anymore.
Fix tests.
This commit is contained in:
Eugene Kabanov 2021-10-18 11:54:20 +03:00 committed by GitHub
parent 75a8fe3b2c
commit 073389377e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 49 additions and 71 deletions

View File

@ -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
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
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())

View File

@ -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* =

View File

@ -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,9 +221,9 @@ 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)
# We ignore indices which could not fit in current list of
# validators.
if uint64(validatorIndex) < validatorsCount:
res[validatorIndex] = listIndex
res

View File

@ -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": ""}}]}]
}
},
{