mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-02 09:46:26 +00:00
REST: Add implementation of postStateValidators and postStateValidatorBalances. (#5632)
* Add implementation POST versions of /eth/v1/beacon/states/{state_id}/validators and /eth/v1/beacon/states/{state_id}/validator_balances. Add tests. * Address review comments. Fix toList() issue. * Fix tests. * Address review comments 2. * Address review comments 3. Fix unique check for validator identifiers. * Address review comments. * Fix constant value.
This commit is contained in:
parent
beb915e308
commit
26bcb7057c
@ -236,6 +236,136 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||||||
)
|
)
|
||||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||||
|
|
||||||
|
proc getIndices(
|
||||||
|
node: BeaconNode,
|
||||||
|
validatorIds: openArray[ValidatorIdent],
|
||||||
|
state: ForkedHashedBeaconState
|
||||||
|
): Result[seq[ValidatorIndex], RestErrorMessage] =
|
||||||
|
var
|
||||||
|
keyset: HashSet[ValidatorPubKey]
|
||||||
|
indexset: HashSet[ValidatorIndex]
|
||||||
|
|
||||||
|
let validatorsCount = lenu64(getStateField(state, validators))
|
||||||
|
|
||||||
|
for item in validatorIds:
|
||||||
|
case item.kind
|
||||||
|
of ValidatorQueryKind.Key:
|
||||||
|
# Test for uniqueness of value.
|
||||||
|
if keyset.containsOrIncl(item.key):
|
||||||
|
return err(RestErrorMessage.init(
|
||||||
|
Http400, NonUniqueValidatorIdError, $item.key))
|
||||||
|
of ValidatorQueryKind.Index:
|
||||||
|
let vindex = item.index.toValidatorIndex().valueOr:
|
||||||
|
case error
|
||||||
|
of ValidatorIndexError.TooHighValue:
|
||||||
|
return err(RestErrorMessage.init(
|
||||||
|
Http400, TooHighValidatorIndexValueError))
|
||||||
|
of ValidatorIndexError.UnsupportedValue:
|
||||||
|
return err(RestErrorMessage.init(
|
||||||
|
Http500, UnsupportedValidatorIndexValueError))
|
||||||
|
if uint64(vindex) < validatorsCount:
|
||||||
|
# We're only adding validator indices which are present in
|
||||||
|
# validators list at this moment.
|
||||||
|
if indexset.containsOrIncl(vindex):
|
||||||
|
return err(RestErrorMessage.init(
|
||||||
|
Http400, NonUniqueValidatorIdError,
|
||||||
|
Base10.toString(uint64(vindex))))
|
||||||
|
|
||||||
|
if len(keyset) > 0:
|
||||||
|
let optIndices = keysToIndices(node.restKeysCache, state, keyset.toSeq())
|
||||||
|
# Remove all the duplicates.
|
||||||
|
for item in optIndices:
|
||||||
|
# We ignore missing keys.
|
||||||
|
if item.isSome():
|
||||||
|
indexset.incl(item.get())
|
||||||
|
ok(indexset.toSeq())
|
||||||
|
|
||||||
|
proc getValidators(
|
||||||
|
node: BeaconNode,
|
||||||
|
bslot: BlockSlotId,
|
||||||
|
validatorsMask: ValidatorFilter,
|
||||||
|
validatorIds: openArray[ValidatorIdent]
|
||||||
|
): RestApiResponse =
|
||||||
|
node.withStateForBlockSlotId(bslot):
|
||||||
|
let
|
||||||
|
stateEpoch = getStateField(state, slot).epoch()
|
||||||
|
validatorsCount = lenu64(getStateField(state, validators))
|
||||||
|
indices = node.getIndices(validatorIds, state).valueOr:
|
||||||
|
return RestApiResponse.jsonError(error)
|
||||||
|
response =
|
||||||
|
block:
|
||||||
|
var res: seq[RestValidator]
|
||||||
|
if len(indices) == 0:
|
||||||
|
# Case when `len(indices) == 0 and len(validatorIds) != 0` means
|
||||||
|
# that we can't find validator identifiers in state, so we should
|
||||||
|
# return empty response.
|
||||||
|
if len(validatorIds) == 0:
|
||||||
|
# There are no indices, so we're going to filter all the
|
||||||
|
# validators.
|
||||||
|
for index, validator in getStateField(state, validators):
|
||||||
|
let
|
||||||
|
balance = getStateField(state, balances).item(index)
|
||||||
|
status = validator.getStatus(stateEpoch).valueOr:
|
||||||
|
return RestApiResponse.jsonError(
|
||||||
|
Http400, ValidatorStatusNotFoundError, $error)
|
||||||
|
if status in validatorsMask:
|
||||||
|
res.add(RestValidator.init(ValidatorIndex(index), balance,
|
||||||
|
toString(status), validator))
|
||||||
|
else:
|
||||||
|
for index in indices:
|
||||||
|
let
|
||||||
|
validator = getStateField(state, validators).item(index)
|
||||||
|
balance = getStateField(state, balances).item(index)
|
||||||
|
status = validator.getStatus(stateEpoch).valueOr:
|
||||||
|
return RestApiResponse.jsonError(
|
||||||
|
Http400, ValidatorStatusNotFoundError, $error)
|
||||||
|
if status in validatorsMask:
|
||||||
|
res.add(RestValidator.init(index, balance, toString(status),
|
||||||
|
validator))
|
||||||
|
res
|
||||||
|
return RestApiResponse.jsonResponseFinalized(
|
||||||
|
response,
|
||||||
|
node.getStateOptimistic(state),
|
||||||
|
node.dag.isFinalized(bslot.bid)
|
||||||
|
)
|
||||||
|
RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||||
|
|
||||||
|
proc getBalances(
|
||||||
|
node: BeaconNode,
|
||||||
|
bslot: BlockSlotId,
|
||||||
|
validatorIds: openArray[ValidatorIdent]
|
||||||
|
): RestApiResponse =
|
||||||
|
node.withStateForBlockSlotId(bslot):
|
||||||
|
let
|
||||||
|
validatorsCount = lenu64(getStateField(state, validators))
|
||||||
|
indices = node.getIndices(validatorIds, state).valueOr:
|
||||||
|
return RestApiResponse.jsonError(error)
|
||||||
|
response =
|
||||||
|
block:
|
||||||
|
var res: seq[RestValidatorBalance]
|
||||||
|
if len(indices) == 0:
|
||||||
|
# Case when `len(indices) == 0 and len(validatorIds) != 0` means
|
||||||
|
# that we can't find validator identifiers in state, so we should
|
||||||
|
# return empty response.
|
||||||
|
if len(validatorIds) == 0:
|
||||||
|
# There are no indices, so we're going to return balances of all
|
||||||
|
# known validators.
|
||||||
|
for index, balance in getStateField(state, balances):
|
||||||
|
res.add(RestValidatorBalance.init(ValidatorIndex(index),
|
||||||
|
balance))
|
||||||
|
else:
|
||||||
|
for index in indices:
|
||||||
|
let balance = getStateField(state, balances).item(index)
|
||||||
|
res.add(RestValidatorBalance.init(index, balance))
|
||||||
|
res
|
||||||
|
|
||||||
|
return RestApiResponse.jsonResponseFinalized(
|
||||||
|
response,
|
||||||
|
node.getStateOptimistic(state),
|
||||||
|
node.dag.isFinalized(bslot.bid)
|
||||||
|
)
|
||||||
|
RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||||
|
|
||||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidators
|
# https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidators
|
||||||
router.api(MethodGet, "/eth/v1/beacon/states/{state_id}/validators") do (
|
router.api(MethodGet, "/eth/v1/beacon/states/{state_id}/validators") do (
|
||||||
state_id: StateIdent, id: seq[ValidatorIdent],
|
state_id: StateIdent, id: seq[ValidatorIdent],
|
||||||
@ -249,119 +379,54 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||||||
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
|
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
|
||||||
# in current version of database.
|
# in current version of database.
|
||||||
return RestApiResponse.jsonError(Http500, NoImplementationError)
|
return RestApiResponse.jsonError(Http500, NoImplementationError)
|
||||||
return RestApiResponse.jsonError(Http404, StateNotFoundError,
|
return RestApiResponse.jsonError(
|
||||||
$error)
|
Http404, StateNotFoundError, $error)
|
||||||
let validatorIds =
|
validatorIds =
|
||||||
block:
|
block:
|
||||||
if id.isErr():
|
if id.isErr():
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(
|
||||||
InvalidValidatorIdValueError)
|
Http400, InvalidValidatorIdValueError)
|
||||||
let ires = id.get()
|
let ires = id.get()
|
||||||
if len(ires) > ServerMaximumValidatorIds:
|
if len(ires) > ServerMaximumValidatorIds:
|
||||||
return RestApiResponse.jsonError(Http414,
|
return RestApiResponse.jsonError(
|
||||||
MaximumNumberOfValidatorIdsError)
|
Http414, MaximumNumberOfValidatorIdsError)
|
||||||
ires
|
ires
|
||||||
|
validatorsMask =
|
||||||
let validatorsMask =
|
|
||||||
block:
|
block:
|
||||||
if status.isErr():
|
if status.isErr():
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(Http400,
|
||||||
InvalidValidatorStatusValueError)
|
InvalidValidatorStatusValueError)
|
||||||
let res = validateFilter(status.get())
|
validateFilter(status.get()).valueOr:
|
||||||
if res.isErr():
|
return RestApiResponse.jsonError(
|
||||||
return RestApiResponse.jsonError(Http400,
|
Http400, InvalidValidatorStatusValueError, $error)
|
||||||
InvalidValidatorStatusValueError,
|
getValidators(node, bslot, validatorsMask, validatorIds)
|
||||||
$res.error())
|
|
||||||
res.get()
|
|
||||||
|
|
||||||
node.withStateForBlockSlotId(bslot):
|
# https://ethereum.github.io/beacon-APIs/#/Beacon/postStateValidators
|
||||||
|
router.api(MethodPost, "/eth/v1/beacon/states/{state_id}/validators") do (
|
||||||
|
state_id: StateIdent, contentBody: Option[ContentBody]) -> RestApiResponse:
|
||||||
let
|
let
|
||||||
current_epoch = getStateField(state, slot).epoch()
|
(validatorIds, validatorsMask) =
|
||||||
validatorsCount = lenu64(getStateField(state, validators))
|
|
||||||
|
|
||||||
let indices =
|
|
||||||
block:
|
block:
|
||||||
var keyset: HashSet[ValidatorPubKey]
|
if contentBody.isNone():
|
||||||
var indexset: HashSet[ValidatorIndex]
|
return RestApiResponse.jsonError(Http400, EmptyRequestBodyError)
|
||||||
for item in validatorIds:
|
let request =
|
||||||
case item.kind
|
decodeBody(RestValidatorRequest, contentBody.get()).valueOr:
|
||||||
of ValidatorQueryKind.Key:
|
return RestApiResponse.jsonError(
|
||||||
keyset.incl(item.key)
|
Http400, InvalidRequestBodyError, $error)
|
||||||
of ValidatorQueryKind.Index:
|
|
||||||
let vindex =
|
|
||||||
block:
|
|
||||||
let vres = item.index.toValidatorIndex()
|
|
||||||
if vres.isErr():
|
|
||||||
case vres.error()
|
|
||||||
of ValidatorIndexError.TooHighValue:
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
TooHighValidatorIndexValueError)
|
|
||||||
of ValidatorIndexError.UnsupportedValue:
|
|
||||||
return RestApiResponse.jsonError(Http500,
|
|
||||||
UnsupportedValidatorIndexValueError)
|
|
||||||
let index = vres.get()
|
|
||||||
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, state,
|
|
||||||
keyset.toSeq())
|
|
||||||
# Remove all the duplicates.
|
|
||||||
for item in optIndices:
|
|
||||||
# We ignore missing keys.
|
|
||||||
if item.isSome():
|
|
||||||
indexset.incl(item.get())
|
|
||||||
indexset.toSeq()
|
|
||||||
|
|
||||||
let response =
|
|
||||||
block:
|
|
||||||
var res: seq[RestValidator]
|
|
||||||
if len(indices) == 0:
|
|
||||||
# Case when `len(indices) == 0 and len(validatorIds) != 0` means
|
|
||||||
# that we can't find validator identifiers in state, so we should
|
|
||||||
# return empty response.
|
|
||||||
if len(validatorIds) == 0:
|
|
||||||
# There is no indices, so we going to filter all the validators.
|
|
||||||
for index, validator in getStateField(state, validators):
|
|
||||||
let
|
let
|
||||||
balance = getStateField(state, balances).item(index)
|
ids = request.ids.valueOr: @[]
|
||||||
status =
|
filter = request.status.valueOr: {}
|
||||||
block:
|
(ids, filter)
|
||||||
let sres = validator.getStatus(current_epoch)
|
sid = state_id.valueOr:
|
||||||
if sres.isErr():
|
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
|
||||||
return RestApiResponse.jsonError(Http400,
|
$error)
|
||||||
ValidatorStatusNotFoundError,
|
bslot = node.getBlockSlotId(sid).valueOr:
|
||||||
$sres.get())
|
if sid.kind == StateQueryKind.Root:
|
||||||
sres.get()
|
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
|
||||||
if status in validatorsMask:
|
# in current version of database.
|
||||||
res.add(RestValidator.init(ValidatorIndex(index), balance,
|
return RestApiResponse.jsonError(Http500, NoImplementationError)
|
||||||
toString(status), validator))
|
return RestApiResponse.jsonError(Http404, StateNotFoundError, $error)
|
||||||
else:
|
getValidators(node, bslot, validatorsMask, validatorIds)
|
||||||
for index in indices:
|
|
||||||
let
|
|
||||||
validator = getStateField(state, validators).item(index)
|
|
||||||
balance = getStateField(state, balances).item(index)
|
|
||||||
status =
|
|
||||||
block:
|
|
||||||
let sres = validator.getStatus(current_epoch)
|
|
||||||
if sres.isErr():
|
|
||||||
return RestApiResponse.jsonError(Http400,
|
|
||||||
ValidatorStatusNotFoundError,
|
|
||||||
$sres.get())
|
|
||||||
sres.get()
|
|
||||||
if status in validatorsMask:
|
|
||||||
res.add(RestValidator.init(index, balance, toString(status),
|
|
||||||
validator))
|
|
||||||
res
|
|
||||||
return RestApiResponse.jsonResponseFinalized(
|
|
||||||
response,
|
|
||||||
node.getStateOptimistic(state),
|
|
||||||
node.dag.isFinalized(bslot.bid)
|
|
||||||
)
|
|
||||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
|
||||||
|
|
||||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidator
|
# https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidator
|
||||||
router.api(MethodGet,
|
router.api(MethodGet,
|
||||||
@ -441,84 +506,42 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||||||
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
|
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
|
||||||
# in current version of database.
|
# in current version of database.
|
||||||
return RestApiResponse.jsonError(Http500, NoImplementationError)
|
return RestApiResponse.jsonError(Http500, NoImplementationError)
|
||||||
return RestApiResponse.jsonError(Http404, StateNotFoundError,
|
return RestApiResponse.jsonError(Http404, StateNotFoundError, $error)
|
||||||
$error)
|
validatorIds =
|
||||||
|
|
||||||
let validatorIds =
|
|
||||||
block:
|
block:
|
||||||
if id.isErr():
|
if id.isErr():
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(
|
||||||
InvalidValidatorIdValueError)
|
Http400, InvalidValidatorIdValueError)
|
||||||
let ires = id.get()
|
let ires = id.get()
|
||||||
if len(ires) > ServerMaximumValidatorIds:
|
if len(ires) > ServerMaximumValidatorIds:
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(
|
||||||
MaximumNumberOfValidatorIdsError)
|
Http400, MaximumNumberOfValidatorIdsError)
|
||||||
ires
|
ires
|
||||||
|
getBalances(node, bslot, validatorIds)
|
||||||
|
|
||||||
node.withStateForBlockSlotId(bslot):
|
# https://ethereum.github.io/beacon-APIs/#/Beacon/postStateValidatorBalances
|
||||||
let validatorsCount = lenu64(getStateField(state, validators))
|
router.api(MethodPost,
|
||||||
|
"/eth/v1/beacon/states/{state_id}/validator_balances") do (
|
||||||
let indices =
|
state_id: StateIdent, contentBody: Option[ContentBody]) -> RestApiResponse:
|
||||||
|
let
|
||||||
|
validatorIds =
|
||||||
block:
|
block:
|
||||||
var keyset: HashSet[ValidatorPubKey]
|
if contentBody.isNone():
|
||||||
var indexset: HashSet[ValidatorIndex]
|
return RestApiResponse.jsonError(Http400, EmptyRequestBodyError)
|
||||||
for item in validatorIds:
|
let body = contentBody.get()
|
||||||
case item.kind
|
decodeBody(seq[ValidatorIdent], body).valueOr:
|
||||||
of ValidatorQueryKind.Key:
|
return RestApiResponse.jsonError(
|
||||||
keyset.incl(item.key)
|
Http400, InvalidValidatorIdValueError, $error)
|
||||||
of ValidatorQueryKind.Index:
|
sid = state_id.valueOr:
|
||||||
let vindex =
|
return RestApiResponse.jsonError(Http400, InvalidStateIdValueError,
|
||||||
block:
|
$error)
|
||||||
let vres = item.index.toValidatorIndex()
|
bslot = node.getBlockSlotId(sid).valueOr:
|
||||||
if vres.isErr():
|
if sid.kind == StateQueryKind.Root:
|
||||||
case vres.error()
|
# TODO (cheatfate): Its impossible to retrieve state by `state_root`
|
||||||
of ValidatorIndexError.TooHighValue:
|
# in current version of database.
|
||||||
return RestApiResponse.jsonError(Http400,
|
return RestApiResponse.jsonError(Http500, NoImplementationError)
|
||||||
TooHighValidatorIndexValueError)
|
return RestApiResponse.jsonError(Http404, StateNotFoundError, $error)
|
||||||
of ValidatorIndexError.UnsupportedValue:
|
getBalances(node, bslot, validatorIds)
|
||||||
return RestApiResponse.jsonError(Http500,
|
|
||||||
UnsupportedValidatorIndexValueError)
|
|
||||||
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, state,
|
|
||||||
keyset.toSeq())
|
|
||||||
# Remove all the duplicates.
|
|
||||||
for item in optIndices:
|
|
||||||
# We ignore missing keys.
|
|
||||||
if item.isSome():
|
|
||||||
indexset.incl(item.get())
|
|
||||||
indexset.toSeq()
|
|
||||||
|
|
||||||
let response =
|
|
||||||
block:
|
|
||||||
var res: seq[RestValidatorBalance]
|
|
||||||
if len(indices) == 0:
|
|
||||||
# Case when `len(indices) == 0 and len(validatorIds) != 0` means
|
|
||||||
# that we can't find validator identifiers in state, so we should
|
|
||||||
# return empty response.
|
|
||||||
if len(validatorIds) == 0:
|
|
||||||
# There is no indices, so we going to return balances of all
|
|
||||||
# known validators.
|
|
||||||
for index, balance in getStateField(state, balances):
|
|
||||||
res.add(RestValidatorBalance.init(ValidatorIndex(index),
|
|
||||||
balance))
|
|
||||||
else:
|
|
||||||
for index in indices:
|
|
||||||
let balance = getStateField(state, balances).item(index)
|
|
||||||
res.add(RestValidatorBalance.init(index, balance))
|
|
||||||
res
|
|
||||||
return RestApiResponse.jsonResponseFinalized(
|
|
||||||
response,
|
|
||||||
node.getStateOptimistic(state),
|
|
||||||
node.dag.isFinalized(bslot.bid)
|
|
||||||
)
|
|
||||||
|
|
||||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
|
||||||
|
|
||||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/getEpochCommittees
|
# https://ethereum.github.io/beacon-APIs/#/Beacon/getEpochCommittees
|
||||||
router.api(MethodGet,
|
router.api(MethodGet,
|
||||||
|
@ -25,7 +25,9 @@ const
|
|||||||
BlockNotFoundError* =
|
BlockNotFoundError* =
|
||||||
"Block header/data has not been found"
|
"Block header/data has not been found"
|
||||||
EmptyRequestBodyError* =
|
EmptyRequestBodyError* =
|
||||||
"Empty request's body"
|
"Empty request body"
|
||||||
|
InvalidRequestBodyError* =
|
||||||
|
"Invalid request body"
|
||||||
InvalidBlockObjectError* =
|
InvalidBlockObjectError* =
|
||||||
"Unable to decode block object(s)"
|
"Unable to decode block object(s)"
|
||||||
InvalidAttestationObjectError* =
|
InvalidAttestationObjectError* =
|
||||||
@ -100,7 +102,9 @@ const
|
|||||||
InvalidBlockIdValueError* =
|
InvalidBlockIdValueError* =
|
||||||
"Invalid block identifier value"
|
"Invalid block identifier value"
|
||||||
InvalidValidatorIdValueError* =
|
InvalidValidatorIdValueError* =
|
||||||
"Invalid validator's identifier value(s)"
|
"Invalid validator identifier value(s)"
|
||||||
|
NonUniqueValidatorIdError* =
|
||||||
|
"Non-unique validator identifier value(s)"
|
||||||
MaximumNumberOfValidatorIdsError* =
|
MaximumNumberOfValidatorIdsError* =
|
||||||
"Maximum number of validator identifier values exceeded"
|
"Maximum number of validator identifier values exceeded"
|
||||||
InvalidValidatorStatusValueError* =
|
InvalidValidatorStatusValueError* =
|
||||||
|
@ -3991,6 +3991,45 @@ proc encodeString*(value: set[EventTopic]): Result[string, cstring] =
|
|||||||
res.setLen(len(res) - 1)
|
res.setLen(len(res) - 1)
|
||||||
ok(res)
|
ok(res)
|
||||||
|
|
||||||
|
proc toList*(value: set[ValidatorFilterKind]): seq[string] =
|
||||||
|
const
|
||||||
|
pendingSet = {ValidatorFilterKind.PendingInitialized,
|
||||||
|
ValidatorFilterKind.PendingQueued}
|
||||||
|
activeSet = {ValidatorFilterKind.ActiveOngoing,
|
||||||
|
ValidatorFilterKind.ActiveExiting,
|
||||||
|
ValidatorFilterKind.ActiveSlashed}
|
||||||
|
exitedSet = {ValidatorFilterKind.ExitedUnslashed,
|
||||||
|
ValidatorFilterKind.ExitedSlashed}
|
||||||
|
withdrawSet = {ValidatorFilterKind.WithdrawalPossible,
|
||||||
|
ValidatorFilterKind.WithdrawalDone}
|
||||||
|
var
|
||||||
|
res: seq[string]
|
||||||
|
v = value
|
||||||
|
|
||||||
|
template processSet(argSet, argName: untyped): untyped =
|
||||||
|
if argSet * v == argSet:
|
||||||
|
res.add(argName)
|
||||||
|
v.excl(argSet)
|
||||||
|
|
||||||
|
template processSingle(argSingle, argName): untyped =
|
||||||
|
if argSingle in v:
|
||||||
|
res.add(argName)
|
||||||
|
|
||||||
|
processSet(pendingSet, "pending")
|
||||||
|
processSet(activeSet, "active")
|
||||||
|
processSet(exitedSet, "exited")
|
||||||
|
processSet(withdrawSet, "withdrawal")
|
||||||
|
processSingle(ValidatorFilterKind.PendingInitialized, "pending_initialized")
|
||||||
|
processSingle(ValidatorFilterKind.PendingQueued, "pending_queued")
|
||||||
|
processSingle(ValidatorFilterKind.ActiveOngoing, "active_ongoing")
|
||||||
|
processSingle(ValidatorFilterKind.ActiveExiting, "active_exiting")
|
||||||
|
processSingle(ValidatorFilterKind.ActiveSlashed, "active_slashed")
|
||||||
|
processSingle(ValidatorFilterKind.ExitedUnslashed, "exited_unslashed")
|
||||||
|
processSingle(ValidatorFilterKind.ExitedSlashed, "exited_slashed")
|
||||||
|
processSingle(ValidatorFilterKind.WithdrawalPossible, "withdrawal_possible")
|
||||||
|
processSingle(ValidatorFilterKind.WithdrawalDone, "withdrawal_done")
|
||||||
|
res
|
||||||
|
|
||||||
proc decodeString*(t: typedesc[ValidatorSig],
|
proc decodeString*(t: typedesc[ValidatorSig],
|
||||||
value: string): Result[ValidatorSig, cstring] =
|
value: string): Result[ValidatorSig, cstring] =
|
||||||
if len(value) != ValidatorSigSize + 2:
|
if len(value) != ValidatorSigSize + 2:
|
||||||
@ -4215,3 +4254,82 @@ proc decodeString*(t: typedesc[EventBeaconBlockObject],
|
|||||||
allowUnknownFields = true))
|
allowUnknownFields = true))
|
||||||
except SerializationError as exc:
|
except SerializationError as exc:
|
||||||
err(exc.formatMsg("<data>"))
|
err(exc.formatMsg("<data>"))
|
||||||
|
|
||||||
|
## ValidatorIdent
|
||||||
|
proc writeValue*(w: var JsonWriter[RestJson],
|
||||||
|
value: ValidatorIdent) {.raises: [IOError].} =
|
||||||
|
writeValue(w, value.encodeString().get())
|
||||||
|
|
||||||
|
proc readValue*(reader: var JsonReader[RestJson],
|
||||||
|
value: var ValidatorIdent) {.
|
||||||
|
raises: [IOError, SerializationError].} =
|
||||||
|
value = decodeString(ValidatorIdent, reader.readValue(string)).valueOr:
|
||||||
|
raise newException(SerializationError, $error)
|
||||||
|
|
||||||
|
## RestValidatorRequest
|
||||||
|
proc readValue*(reader: var JsonReader[RestJson],
|
||||||
|
value: var RestValidatorRequest) {.
|
||||||
|
raises: [IOError, SerializationError].} =
|
||||||
|
var
|
||||||
|
statuses: Opt[seq[string]]
|
||||||
|
ids: Opt[seq[string]]
|
||||||
|
|
||||||
|
for fieldName in readObjectFields(reader):
|
||||||
|
case fieldName
|
||||||
|
of "ids":
|
||||||
|
if ids.isSome():
|
||||||
|
reader.raiseUnexpectedField("Multiple `ids` fields found",
|
||||||
|
"RestValidatorRequest")
|
||||||
|
ids = Opt.some(reader.readValue(seq[string]))
|
||||||
|
of "statuses":
|
||||||
|
if statuses.isSome():
|
||||||
|
reader.raiseUnexpectedField("Multiple `statuses` fields found",
|
||||||
|
"RestValidatorRequest")
|
||||||
|
statuses = Opt.some(reader.readValue(seq[string]))
|
||||||
|
else:
|
||||||
|
unrecognizedFieldWarning()
|
||||||
|
|
||||||
|
let
|
||||||
|
validatorIds =
|
||||||
|
block:
|
||||||
|
# Test for uniqueness of value will be happened on higher layer.
|
||||||
|
if ids.isSome():
|
||||||
|
var res: seq[ValidatorIdent]
|
||||||
|
for item in ids.get():
|
||||||
|
let value = decodeString(ValidatorIdent, item).valueOr:
|
||||||
|
reader.raiseUnexpectedValue($error)
|
||||||
|
res.add(value)
|
||||||
|
Opt.some(res)
|
||||||
|
else:
|
||||||
|
Opt.none(seq[ValidatorIdent])
|
||||||
|
filter =
|
||||||
|
block:
|
||||||
|
if statuses.isSome():
|
||||||
|
var res: ValidatorFilter
|
||||||
|
for item in statuses.get():
|
||||||
|
let value = decodeString(ValidatorFilter, item).valueOr:
|
||||||
|
reader.raiseUnexpectedValue($error)
|
||||||
|
# Test for uniqueness of value.
|
||||||
|
if value * res != {}:
|
||||||
|
reader.raiseUnexpectedValue(
|
||||||
|
"The `statuses` array should consist of only unique values")
|
||||||
|
res.incl(value)
|
||||||
|
Opt.some(res)
|
||||||
|
else:
|
||||||
|
Opt.none(ValidatorFilter)
|
||||||
|
|
||||||
|
value = RestValidatorRequest(ids: validatorIds, status: filter)
|
||||||
|
|
||||||
|
proc writeValue*(writer: var JsonWriter[RestJson],
|
||||||
|
value: RestValidatorRequest) {.raises: [IOError].} =
|
||||||
|
writer.beginRecord()
|
||||||
|
if value.ids.isSome():
|
||||||
|
var res: seq[string]
|
||||||
|
for item in value.ids.get():
|
||||||
|
res.add(item.encodeString().get())
|
||||||
|
writer.writeField("ids", res)
|
||||||
|
if value.status.isSome():
|
||||||
|
let res = value.status.get().toList()
|
||||||
|
if len(res) > 0:
|
||||||
|
writer.writeField("statuses", res)
|
||||||
|
writer.endRecord()
|
||||||
|
@ -121,6 +121,10 @@ type
|
|||||||
|
|
||||||
RestNumeric* = distinct int
|
RestNumeric* = distinct int
|
||||||
|
|
||||||
|
RestValidatorRequest* = object
|
||||||
|
ids*: Opt[seq[ValidatorIdent]]
|
||||||
|
status*: Opt[ValidatorFilter]
|
||||||
|
|
||||||
RestAttesterDuty* = object
|
RestAttesterDuty* = object
|
||||||
pubkey*: ValidatorPubKey
|
pubkey*: ValidatorPubKey
|
||||||
validator_index*: ValidatorIndex
|
validator_index*: ValidatorIndex
|
||||||
|
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user