REST server fixes and improvements. (#5422)
* Move from Option[T] to Opt[T] usage. * Add `finalized` flag. * Fix compilation issue. * Http415 error code for some REST API calls. Introduce more comprehensive error reporting for block calls. Deprecate decodeEthConsensusVersion() function. * Bump http-utils. * Fix copyright year. * Fix serialization issue. * Address review comments. * Post rebase fixes.
This commit is contained in:
parent
96e05e4f37
commit
4fb95d000d
|
@ -339,11 +339,17 @@ proc getForkedBlock*(
|
|||
dag.db.getForkedBlock(root)
|
||||
|
||||
func isCanonical*(dag: ChainDAGRef, bid: BlockId): bool =
|
||||
## Return true iff the given `bid` is part of the history selected by `dag.head`
|
||||
## Returns `true` if the given `bid` is part of the history selected by
|
||||
## `dag.head`.
|
||||
let current = dag.getBlockIdAtSlot(bid.slot).valueOr:
|
||||
return false # We don't know, so ..
|
||||
return current.bid == bid
|
||||
|
||||
func isFinalized*(dag: ChainDAGRef, bid: BlockId): bool =
|
||||
## Returns `true` if the given `bid` is part of the finalized history
|
||||
## selected by `dag.finalizedHead`.
|
||||
dag.isCanonical(bid) and (bid.slot <= dag.finalizedHead.slot)
|
||||
|
||||
func parent*(dag: ChainDAGRef, bid: BlockId): Opt[BlockId] =
|
||||
if bid.slot == 0:
|
||||
return err()
|
||||
|
|
|
@ -322,7 +322,7 @@ proc restValidatorExit(config: BeaconNodeConf) {.async.} =
|
|||
else:
|
||||
hadErrors = true
|
||||
let responseError = try:
|
||||
Json.decode(response.data, RestErrorMessage)
|
||||
RestJson.decode(response.data, RestErrorMessage)
|
||||
except CatchableError as exc:
|
||||
error "Failed to decode invalid error server response on " &
|
||||
"`submitPoolVoluntaryExit` request", reason = exc.msg
|
||||
|
|
|
@ -148,7 +148,7 @@ proc ETHBeaconStateCreateFromSsz(
|
|||
## * https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/specs/capella/beacon-chain.md#beaconstate
|
||||
## * https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/configs/README.md
|
||||
let
|
||||
consensusFork = decodeEthConsensusVersion($consensusVersion).valueOr:
|
||||
consensusFork = ConsensusFork.decodeString($consensusVersion).valueOr:
|
||||
return nil
|
||||
state = ForkedHashedBeaconState.new()
|
||||
try:
|
||||
|
@ -328,7 +328,7 @@ proc ETHLightClientStoreCreateFromBootstrap(
|
|||
## * https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.2/specs/phase0/weak-subjectivity.md#weak-subjectivity-period
|
||||
let
|
||||
mediaType = MediaType.init($mediaType)
|
||||
consensusFork = decodeEthConsensusVersion($consensusVersion).valueOr:
|
||||
consensusFork = ConsensusFork.decodeString($consensusVersion).valueOr:
|
||||
return nil
|
||||
var bootstrap =
|
||||
try:
|
||||
|
@ -603,7 +603,7 @@ proc ETHLightClientStoreProcessFinalityUpdate(
|
|||
finUpdateBytes.toOpenArray(0, numFinUpdateBytes - 1),
|
||||
Opt.none(ConsensusFork), cfg[])
|
||||
else:
|
||||
let consensusFork = decodeEthConsensusVersion(
|
||||
let consensusFork = ConsensusFork.decodeString(
|
||||
$consensusVersion).valueOr:
|
||||
return 1
|
||||
ForkedLightClientFinalityUpdate.decodeHttpLightClientObject(
|
||||
|
@ -688,7 +688,7 @@ proc ETHLightClientStoreProcessOptimisticUpdate(
|
|||
optUpdateBytes.toOpenArray(0, numOptUpdateBytes - 1),
|
||||
Opt.none(ConsensusFork), cfg[])
|
||||
else:
|
||||
let consensusFork = decodeEthConsensusVersion(
|
||||
let consensusFork = ConsensusFork.decodeString(
|
||||
$consensusVersion).valueOr:
|
||||
return 1
|
||||
ForkedLightClientOptimisticUpdate.decodeHttpLightClientObject(
|
||||
|
|
|
@ -167,9 +167,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
$error)
|
||||
|
||||
node.withStateForBlockSlotId(bslot):
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
(root: stateRoot),
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
@ -190,7 +191,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
$error)
|
||||
|
||||
node.withStateForBlockSlotId(bslot):
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
(
|
||||
previous_version:
|
||||
getStateField(state, fork).previous_version,
|
||||
|
@ -199,7 +200,8 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
epoch:
|
||||
getStateField(state, fork).epoch
|
||||
),
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
||||
|
@ -220,7 +222,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
$error)
|
||||
|
||||
node.withStateForBlockSlotId(bslot):
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
(
|
||||
previous_justified:
|
||||
getStateField(state, previous_justified_checkpoint),
|
||||
|
@ -229,7 +231,8 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
finalized:
|
||||
getStateField(state, finalized_checkpoint)
|
||||
),
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
||||
|
@ -255,7 +258,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
InvalidValidatorIdValueError)
|
||||
let ires = id.get()
|
||||
if len(ires) > ServerMaximumValidatorIds:
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
return RestApiResponse.jsonError(Http414,
|
||||
MaximumNumberOfValidatorIdsError)
|
||||
ires
|
||||
|
||||
|
@ -353,9 +356,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
res.add(RestValidator.init(index, balance, toString(status),
|
||||
validator))
|
||||
res
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
response,
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
||||
|
@ -417,9 +421,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
ValidatorStatusNotFoundError,
|
||||
$sres.get())
|
||||
toString(sres.get())
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
RestValidator.init(vindex, balance, status, validator),
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
||||
|
@ -507,9 +512,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
let balance = getStateField(state, balances).item(index)
|
||||
res.add(RestValidatorBalance.init(index, balance))
|
||||
res
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
response,
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
@ -623,9 +629,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
else:
|
||||
forSlot(vslot.get(), vindex, res)
|
||||
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
res,
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
@ -703,10 +710,11 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
offset.inc(length)
|
||||
res
|
||||
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
RestEpochSyncCommittee(validators: indices,
|
||||
validator_aggregates: aggregates),
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
@ -762,9 +770,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
# Fall back to full state computation
|
||||
node.withStateForBlockSlotId(bslot):
|
||||
withState(state):
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
RestEpochRandao(randao: get_randao_mix(forkyState.data, qepoch)),
|
||||
node.getStateOptimistic(state)
|
||||
node.getStateOptimistic(state),
|
||||
node.dag.isFinalized(bslot.bid)
|
||||
)
|
||||
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
@ -796,19 +805,20 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
|
||||
return
|
||||
withBlck(bdata):
|
||||
RestApiResponse.jsonResponseWOpt(
|
||||
let bid = BlockId(root: forkyBlck.root, slot: forkyBlck.message.slot)
|
||||
RestApiResponse.jsonResponseFinalized(
|
||||
[
|
||||
(
|
||||
root: forkyBlck.root,
|
||||
canonical: node.dag.isCanonical(
|
||||
BlockId(root: forkyBlck.root, slot: forkyBlck.message.slot)),
|
||||
canonical: node.dag.isCanonical(bid),
|
||||
header: (
|
||||
message: forkyBlck.toBeaconBlockHeader,
|
||||
signature: forkyBlck.signature
|
||||
)
|
||||
)
|
||||
],
|
||||
node.getBlockOptimistic(bdata)
|
||||
node.getBlockOptimistic(bdata),
|
||||
node.dag.isFinalized(bid)
|
||||
)
|
||||
|
||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/getBlockHeader
|
||||
|
@ -824,17 +834,18 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
|
||||
return
|
||||
withBlck(bdata):
|
||||
RestApiResponse.jsonResponseWOpt(
|
||||
let bid = BlockId(root: forkyBlck.root, slot: forkyBlck.message.slot)
|
||||
RestApiResponse.jsonResponseFinalized(
|
||||
(
|
||||
root: forkyBlck.root,
|
||||
canonical: node.dag.isCanonical(
|
||||
BlockId(root: forkyBlck.root, slot: forkyBlck.message.slot)),
|
||||
canonical: node.dag.isCanonical(bid),
|
||||
header: (
|
||||
message: forkyBlck.toBeaconBlockHeader,
|
||||
signature: forkyBlck.signature
|
||||
)
|
||||
),
|
||||
node.getBlockOptimistic(bdata)
|
||||
node.getBlockOptimistic(bdata),
|
||||
node.dag.isFinalized(bid)
|
||||
)
|
||||
|
||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/publishBlock
|
||||
|
@ -850,8 +861,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
var
|
||||
restBlock = decodeBody(RestPublishedSignedBlockContents, body,
|
||||
version).valueOr:
|
||||
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError,
|
||||
$error)
|
||||
return RestApiResponse.jsonError(error)
|
||||
forked = ForkedSignedBeaconBlock.init(restBlock)
|
||||
|
||||
if restBlock.kind != node.dag.cfg.consensusForkAtEpoch(
|
||||
|
@ -912,8 +922,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
var
|
||||
restBlock = decodeBodyJsonOrSsz(RestPublishedSignedBlockContents,
|
||||
body, version).valueOr:
|
||||
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError,
|
||||
$error)
|
||||
return RestApiResponse.jsonError(error)
|
||||
forked = ForkedSignedBeaconBlock.init(restBlock)
|
||||
|
||||
# TODO (henridf): handle broadcast_validation flag
|
||||
|
@ -978,19 +987,38 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
version = request.headers.getString("eth-consensus-version")
|
||||
body = contentBody.get()
|
||||
|
||||
if body.contentType == OctetStreamMediaType and
|
||||
currentEpochFork.toString != version:
|
||||
if (body.contentType == OctetStreamMediaType) and
|
||||
(currentEpochFork.toString != version):
|
||||
return RestApiResponse.jsonError(Http400, BlockIncorrectFork)
|
||||
|
||||
case currentEpochFork
|
||||
of ConsensusFork.Deneb:
|
||||
return RestApiResponse.jsonError(Http500, $denebImplementationMissing)
|
||||
let
|
||||
restBlock = decodeBodyJsonOrSsz(deneb_mev.SignedBlindedBeaconBlock,
|
||||
body).valueOr:
|
||||
return RestApiResponse.jsonError(error)
|
||||
|
||||
payloadBuilderClient = node.getPayloadBuilderClient(
|
||||
restBlock.message.proposer_index).valueOr:
|
||||
return RestApiResponse.jsonError(
|
||||
Http400, "Unable to initialize payload builder client: " & $error)
|
||||
res = await node.unblindAndRouteBlockMEV(
|
||||
payloadBuilderClient, restBlock)
|
||||
|
||||
if res.isErr():
|
||||
return RestApiResponse.jsonError(
|
||||
Http503, BeaconNodeInSyncError, $res.error())
|
||||
if res.get().isNone():
|
||||
return RestApiResponse.jsonError(Http202, BlockValidationError)
|
||||
|
||||
return RestApiResponse.jsonMsgResponse(BlockValidationSuccess)
|
||||
of ConsensusFork.Capella:
|
||||
let
|
||||
restBlock = decodeBodyJsonOrSsz(
|
||||
capella_mev.SignedBlindedBeaconBlock, body).valueOr:
|
||||
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError,
|
||||
$error)
|
||||
restBlock =
|
||||
decodeBodyJsonOrSsz(capella_mev.SignedBlindedBeaconBlock,
|
||||
body).valueOr:
|
||||
return RestApiResponse.jsonError(error)
|
||||
|
||||
payloadBuilderClient = node.getPayloadBuilderClient(
|
||||
restBlock.message.proposer_index).valueOr:
|
||||
return RestApiResponse.jsonError(
|
||||
|
@ -1006,7 +1034,8 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
|
||||
return RestApiResponse.jsonMsgResponse(BlockValidationSuccess)
|
||||
of ConsensusFork.Bellatrix:
|
||||
return RestApiResponse.jsonError(Http400, "FOO")
|
||||
return RestApiResponse.jsonError(Http400,
|
||||
"Bellatrix builder API unsupported")
|
||||
of ConsensusFork.Altair, ConsensusFork.Phase0:
|
||||
# Pre-Bellatrix, this endpoint will accept a `SignedBeaconBlock`.
|
||||
#
|
||||
|
@ -1015,8 +1044,7 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
var
|
||||
restBlock = decodeBody(RestPublishedSignedBeaconBlock, body,
|
||||
version).valueOr:
|
||||
return RestApiResponse.jsonError(Http400, InvalidBlockObjectError,
|
||||
$error)
|
||||
return RestApiResponse.jsonError(error)
|
||||
forked = ForkedSignedBeaconBlock(restBlock)
|
||||
|
||||
if forked.kind != node.dag.cfg.consensusForkAtEpoch(
|
||||
|
@ -1076,7 +1104,8 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
|
||||
RestApiResponse.jsonResponseBlock(
|
||||
bdata.asSigned(),
|
||||
node.getBlockOptimistic(bdata)
|
||||
node.getBlockOptimistic(bdata),
|
||||
node.dag.isFinalized(bid)
|
||||
)
|
||||
else:
|
||||
RestApiResponse.jsonError(Http500, InvalidAcceptError)
|
||||
|
@ -1095,9 +1124,10 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
bdata = node.dag.getForkedBlock(bid).valueOr:
|
||||
return RestApiResponse.jsonError(Http404, BlockNotFoundError)
|
||||
|
||||
return RestApiResponse.jsonResponseWOpt(
|
||||
return RestApiResponse.jsonResponseFinalized(
|
||||
(root: bid.root),
|
||||
node.getBlockOptimistic(bdata)
|
||||
node.getBlockOptimistic(bdata),
|
||||
node.dag.isFinalized(bid)
|
||||
)
|
||||
|
||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/getBlockAttestations
|
||||
|
@ -1105,18 +1135,19 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
"/eth/v1/beacon/blocks/{block_id}/attestations") do (
|
||||
block_id: BlockIdent) -> RestApiResponse:
|
||||
let
|
||||
bid = block_id.valueOr:
|
||||
blockIdent = block_id.valueOr:
|
||||
return RestApiResponse.jsonError(Http400, InvalidBlockIdValueError,
|
||||
$error)
|
||||
|
||||
bdata = node.getForkedBlock(bid).valueOr:
|
||||
bdata = node.getForkedBlock(blockIdent).valueOr:
|
||||
return RestApiResponse.jsonError(Http404, BlockNotFoundError)
|
||||
|
||||
return
|
||||
withBlck(bdata):
|
||||
RestApiResponse.jsonResponseWOpt(
|
||||
let bid = BlockId(root: forkyBlck.root, slot: forkyBlck.message.slot)
|
||||
RestApiResponse.jsonResponseFinalized(
|
||||
forkyBlck.message.body.attestations.asSeq(),
|
||||
node.getBlockOptimistic(bdata)
|
||||
node.getBlockOptimistic(bdata),
|
||||
node.dag.isFinalized(bid)
|
||||
)
|
||||
|
||||
# https://ethereum.github.io/beacon-APIs/#/Beacon/getPoolAttestations
|
||||
|
|
|
@ -123,7 +123,7 @@ proc handleRemoveValidatorReq(host: KeymanagerHost,
|
|||
return RemoteKeystoreStatus(status: KeystoreStatus.notFound)
|
||||
else:
|
||||
return RemoteKeystoreStatus(status: KeystoreStatus.error,
|
||||
message: some($res.error()))
|
||||
message: Opt.some($res.error()))
|
||||
|
||||
proc handleAddRemoteValidatorReq(host: KeymanagerHost,
|
||||
keystore: RemoteKeystore): RequestItemStatus =
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
{.push raises: [].}
|
||||
|
||||
import std/[options, macros],
|
||||
stew/byteutils, presto,
|
||||
import std/macros,
|
||||
results, stew/byteutils, presto,
|
||||
../spec/[forks],
|
||||
../spec/eth2_apis/[rest_types, eth2_rest_serialization, rest_common],
|
||||
../validators/beacon_validators,
|
||||
|
@ -17,7 +17,7 @@ import std/[options, macros],
|
|||
"."/[rest_constants, state_ttl_cache]
|
||||
|
||||
export
|
||||
options, eth2_rest_serialization, blockchain_dag, presto, rest_types,
|
||||
results, eth2_rest_serialization, blockchain_dag, presto, rest_types,
|
||||
rest_constants, rest_common
|
||||
|
||||
type
|
||||
|
@ -256,8 +256,8 @@ func syncCommitteeParticipants*(forkedState: ForkedHashedBeaconState,
|
|||
func keysToIndices*(cacheTable: var Table[ValidatorPubKey, ValidatorIndex],
|
||||
forkedState: ForkedHashedBeaconState,
|
||||
keys: openArray[ValidatorPubKey]
|
||||
): seq[Option[ValidatorIndex]] =
|
||||
var indices = newSeq[Option[ValidatorIndex]](len(keys))
|
||||
): seq[Opt[ValidatorIndex]] =
|
||||
var indices = newSeq[Opt[ValidatorIndex]](len(keys))
|
||||
let totalValidatorsInState = getStateField(forkedState, validators).lenu64
|
||||
var keyset =
|
||||
block:
|
||||
|
@ -266,7 +266,7 @@ func keysToIndices*(cacheTable: var Table[ValidatorPubKey, ValidatorIndex],
|
|||
# Try to search in cache first.
|
||||
cacheTable.withValue(pubkey, vindex):
|
||||
if uint64(vindex[]) < totalValidatorsInState:
|
||||
indices[inputIndex] = some(vindex[])
|
||||
indices[inputIndex] = Opt.some(vindex[])
|
||||
do:
|
||||
res[pubkey] = inputIndex
|
||||
res
|
||||
|
@ -276,48 +276,48 @@ func keysToIndices*(cacheTable: var Table[ValidatorPubKey, ValidatorIndex],
|
|||
# Store pair (pubkey, index) into cache table.
|
||||
cacheTable[validator.pubkey] = ValidatorIndex(validatorIndex)
|
||||
# Fill result sequence.
|
||||
indices[listIndex[]] = some(ValidatorIndex(validatorIndex))
|
||||
indices[listIndex[]] = Opt.some(ValidatorIndex(validatorIndex))
|
||||
indices
|
||||
|
||||
proc getBidOptimistic*(node: BeaconNode, bid: BlockId): Option[bool] =
|
||||
proc getBidOptimistic*(node: BeaconNode, bid: BlockId): Opt[bool] =
|
||||
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
|
||||
some[bool](node.dag.is_optimistic(bid))
|
||||
Opt.some(node.dag.is_optimistic(bid))
|
||||
else:
|
||||
none[bool]()
|
||||
Opt.none(bool)
|
||||
|
||||
proc getShufflingOptimistic*(node: BeaconNode,
|
||||
dependentSlot: Slot,
|
||||
dependentRoot: Eth2Digest): Option[bool] =
|
||||
dependentRoot: Eth2Digest): Opt[bool] =
|
||||
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
|
||||
# `slot` in this `BlockId` may be higher than block's actual slot,
|
||||
# this is alright for the purpose of calling `is_optimistic`.
|
||||
let bid = BlockId(slot: dependentSlot, root: dependentRoot)
|
||||
some[bool](node.dag.is_optimistic(bid))
|
||||
Opt.some(node.dag.is_optimistic(bid))
|
||||
else:
|
||||
none[bool]()
|
||||
Opt.none(bool)
|
||||
|
||||
proc getStateOptimistic*(node: BeaconNode,
|
||||
state: ForkedHashedBeaconState): Option[bool] =
|
||||
state: ForkedHashedBeaconState): Opt[bool] =
|
||||
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
|
||||
if state.kind >= ConsensusFork.Bellatrix:
|
||||
# A state is optimistic iff the block which created it is
|
||||
let stateBid = withState(state): forkyState.latest_block_id
|
||||
some[bool](node.dag.is_optimistic(stateBid))
|
||||
Opt.some(node.dag.is_optimistic(stateBid))
|
||||
else:
|
||||
some[bool](false)
|
||||
Opt.some(false)
|
||||
else:
|
||||
none[bool]()
|
||||
Opt.none(bool)
|
||||
|
||||
proc getBlockOptimistic*(node: BeaconNode,
|
||||
blck: ForkedTrustedSignedBeaconBlock |
|
||||
ForkedSignedBeaconBlock): Option[bool] =
|
||||
ForkedSignedBeaconBlock): Opt[bool] =
|
||||
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
|
||||
if blck.kind >= ConsensusFork.Bellatrix:
|
||||
some[bool](node.dag.is_optimistic(blck.toBlockId()))
|
||||
Opt.some(node.dag.is_optimistic(blck.toBlockId()))
|
||||
else:
|
||||
some[bool](false)
|
||||
Opt.some(false)
|
||||
else:
|
||||
none[bool]()
|
||||
Opt.none(bool)
|
||||
|
||||
const
|
||||
jsonMediaType* = MediaType.init("application/json")
|
||||
|
|
|
@ -309,7 +309,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
return RestApiResponse.jsonResponseWOpt(res, optimistic)
|
||||
else:
|
||||
let res = emptyResponse()
|
||||
return RestApiResponse.jsonResponseWOpt(res, execOpt = some(false))
|
||||
return RestApiResponse.jsonResponseWOpt(res, execOpt = Opt.some(false))
|
||||
|
||||
return RestApiResponse.jsonError(Http404, StateNotFoundError)
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
# beacon_chain
|
||||
# Copyright (c) 2021-2022 Status Research & Development GmbH
|
||||
# Copyright (c) 2021-2023 Status Research & Development GmbH
|
||||
# Licensed and distributed under either of
|
||||
# * 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).
|
||||
|
@ -31,7 +31,7 @@ type
|
|||
KeystoresAndSlashingProtection* = object
|
||||
keystores*: seq[Keystore]
|
||||
passwords*: seq[string]
|
||||
slashing_protection*: Option[SPDIR]
|
||||
slashing_protection*: Opt[SPDIR]
|
||||
|
||||
DeleteKeystoresBody* = object
|
||||
pubkeys*: seq[ValidatorPubKey]
|
||||
|
@ -64,7 +64,7 @@ type
|
|||
|
||||
RemoteKeystoreStatus* = object
|
||||
status*: KeystoreStatus
|
||||
message*: Option[string]
|
||||
message*: Opt[string]
|
||||
|
||||
DeleteRemoteKeystoresResponse* = object
|
||||
data*: seq[RemoteKeystoreStatus]
|
||||
|
|
|
@ -209,7 +209,7 @@ proc getLightClientBootstrap*(
|
|||
return
|
||||
case resp.status
|
||||
of 200:
|
||||
let consensusForkRes = decodeEthConsensusVersion(
|
||||
let consensusForkRes = ConsensusFork.decodeString(
|
||||
resp.headers.getString("eth-consensus-version"))
|
||||
if consensusForkRes.isErr:
|
||||
raiseRestDecodingBytesError(cstring(consensusForkRes.error))
|
||||
|
@ -291,7 +291,7 @@ proc getLightClientFinalityUpdate*(
|
|||
return
|
||||
case resp.status
|
||||
of 200:
|
||||
let consensusForkRes = decodeEthConsensusVersion(
|
||||
let consensusForkRes = ConsensusFork.decodeString(
|
||||
resp.headers.getString("eth-consensus-version"))
|
||||
if consensusForkRes.isErr:
|
||||
raiseRestDecodingBytesError(cstring(consensusForkRes.error))
|
||||
|
@ -333,7 +333,7 @@ proc getLightClientOptimisticUpdate*(
|
|||
return
|
||||
case resp.status
|
||||
of 200:
|
||||
let consensusForkRes = decodeEthConsensusVersion(
|
||||
let consensusForkRes = ConsensusFork.decodeString(
|
||||
resp.headers.getString("eth-consensus-version"))
|
||||
if consensusForkRes.isErr:
|
||||
raiseRestDecodingBytesError(cstring(consensusForkRes.error))
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
import
|
||||
std/[json, tables],
|
||||
stew/base10, web3/ethtypes,
|
||||
stew/base10, web3/ethtypes, httputils,
|
||||
".."/forks,
|
||||
".."/datatypes/[phase0, altair, bellatrix, deneb],
|
||||
".."/mev/[capella_mev, deneb_mev]
|
||||
|
@ -23,7 +23,7 @@ import
|
|||
from ".."/datatypes/capella import BeaconBlockBody
|
||||
|
||||
export forks, phase0, altair, bellatrix, capella, capella_mev, deneb_mev,
|
||||
tables
|
||||
tables, httputils
|
||||
|
||||
const
|
||||
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validator_balances.yaml#L17
|
||||
|
@ -189,7 +189,7 @@ type
|
|||
## https://github.com/ethereum/beacon-APIs/blob/v2.4.0/types/http.yaml#L130
|
||||
code*: int
|
||||
message*: string
|
||||
stacktraces*: Option[seq[string]]
|
||||
stacktraces*: Opt[seq[string]]
|
||||
|
||||
RestIndexedErrorMessage* = object
|
||||
## https://github.com/ethereum/beacon-APIs/blob/v2.4.0/types/http.yaml#L145
|
||||
|
@ -447,8 +447,8 @@ type
|
|||
ValidatorRegistration
|
||||
|
||||
Web3SignerRequest* = object
|
||||
signingRoot*: Option[Eth2Digest]
|
||||
forkInfo* {.serializedFieldName: "fork_info".}: Option[Web3SignerForkInfo]
|
||||
signingRoot*: Opt[Eth2Digest]
|
||||
forkInfo* {.serializedFieldName: "fork_info".}: Opt[Web3SignerForkInfo]
|
||||
case kind* {.dontSerialize.}: Web3SignerRequestKind
|
||||
of Web3SignerRequestKind.AggregationSlot:
|
||||
aggregationSlot* {.
|
||||
|
@ -641,11 +641,11 @@ func init*(t: typedesc[RestValidatorBalance], index: ValidatorIndex,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, data: Slot,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.AggregationSlot,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -654,11 +654,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, data: AggregateAndProof,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.AggregateAndProof,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -667,11 +667,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, data: AttestationData,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.Attestation,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -681,11 +681,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest,
|
||||
data: Web3SignerForkedBeaconBlock,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.BlockV2,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -696,11 +696,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
genesis_validators_root: Eth2Digest,
|
||||
data: Web3SignerForkedBeaconBlock,
|
||||
proofs: openArray[Web3SignerMerkleProof],
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.BlockV2,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -710,7 +710,7 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], genesisForkVersion: Version,
|
||||
data: DepositMessage,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.Deposit,
|
||||
|
@ -725,11 +725,11 @@ func init*(t: typedesc[Web3SignerRequest], genesisForkVersion: Version,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, data: Epoch,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.RandaoReveal,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -738,11 +738,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, data: VoluntaryExit,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.VoluntaryExit,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -751,11 +751,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
|
||||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest, blockRoot: Eth2Digest,
|
||||
slot: Slot, signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
slot: Slot, signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.SyncCommitteeMessage,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -767,11 +767,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest,
|
||||
data: SyncAggregatorSelectionData,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.SyncCommitteeSelectionProof,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -781,11 +781,11 @@ func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
|||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest,
|
||||
data: ContributionAndProof,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.SyncCommitteeContributionAndProof,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -797,11 +797,11 @@ from stew/byteutils import to0xHex
|
|||
func init*(t: typedesc[Web3SignerRequest], fork: Fork,
|
||||
genesis_validators_root: Eth2Digest,
|
||||
data: ValidatorRegistrationV1,
|
||||
signingRoot: Option[Eth2Digest] = none[Eth2Digest]()
|
||||
signingRoot: Opt[Eth2Digest] = Opt.none(Eth2Digest)
|
||||
): Web3SignerRequest =
|
||||
Web3SignerRequest(
|
||||
kind: Web3SignerRequestKind.ValidatorRegistration,
|
||||
forkInfo: some(Web3SignerForkInfo(
|
||||
forkInfo: Opt.some(Web3SignerForkInfo(
|
||||
fork: fork, genesis_validators_root: genesis_validators_root
|
||||
)),
|
||||
signingRoot: signingRoot,
|
||||
|
@ -864,3 +864,31 @@ func init*(t: typedesc[RestSignedContributionAndProof],
|
|||
signature: signature)
|
||||
|
||||
func len*(p: RestWithdrawalPrefix): int = sizeof(p)
|
||||
|
||||
func init*(t: typedesc[RestErrorMessage], code: int,
|
||||
message: string): RestErrorMessage =
|
||||
RestErrorMessage(code: code, message: message)
|
||||
|
||||
func init*(t: typedesc[RestErrorMessage], code: int,
|
||||
message: string, stacktrace: string): RestErrorMessage =
|
||||
RestErrorMessage(code: code, message: message,
|
||||
stacktraces: Opt.some(@[stacktrace]))
|
||||
|
||||
func init*(t: typedesc[RestErrorMessage], code: int,
|
||||
message: string, stacktrace: openArray[string]): RestErrorMessage =
|
||||
RestErrorMessage(code: code, message: message,
|
||||
stacktraces: Opt.some(@stacktrace))
|
||||
|
||||
func init*(t: typedesc[RestErrorMessage], code: HttpCode,
|
||||
message: string): RestErrorMessage =
|
||||
RestErrorMessage(code: code.toInt(), message: message)
|
||||
|
||||
func init*(t: typedesc[RestErrorMessage], code: HttpCode,
|
||||
message: string, stacktrace: string): RestErrorMessage =
|
||||
RestErrorMessage(code: code.toInt(), message: message,
|
||||
stacktraces: Opt.some(@[stacktrace]))
|
||||
|
||||
func init*(t: typedesc[RestErrorMessage], code: HttpCode,
|
||||
message: string, stacktrace: openArray[string]): RestErrorMessage =
|
||||
RestErrorMessage(code: code.toInt(), message: message,
|
||||
stacktraces: Opt.some(@stacktrace))
|
||||
|
|
|
@ -15,20 +15,6 @@ import
|
|||
|
||||
suite "Serialization/deserialization test suite":
|
||||
test "RestErrorMessage parser tests":
|
||||
proc init(t: typedesc[RestErrorMessage], status: int,
|
||||
message: string): RestErrorMessage =
|
||||
RestErrorMessage(
|
||||
code: status, message: message,
|
||||
stacktraces: none[seq[string]]()
|
||||
)
|
||||
proc init(t: typedesc[RestErrorMessage], status: int,
|
||||
message: string,
|
||||
stacktraces: openArray[string]): RestErrorMessage =
|
||||
RestErrorMessage(
|
||||
code: status, message: message,
|
||||
stacktraces: some(@stacktraces)
|
||||
)
|
||||
|
||||
const GoodTestVectors = [
|
||||
(
|
||||
"""{"code": 500, "message": "block not found"}""",
|
||||
|
@ -138,6 +124,7 @@ suite "Serialization/deserialization test suite":
|
|||
Opt.some(contentType))
|
||||
checkpoint test
|
||||
check res.isErr()
|
||||
|
||||
test "RestErrorMessage writer tests":
|
||||
proc `==`(a: RestApiResponse, b: string): bool =
|
||||
case a.kind
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a85bd52ae0a956983ca6b3267c72961d2ec0245f
|
||||
Subproject commit 87b7cbf032c90b9e6b446081f4a647e950362cec
|
Loading…
Reference in New Issue