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:
Eugene Kabanov 2023-09-27 17:45:33 +03:00 committed by GitHub
parent 96e05e4f37
commit 4fb95d000d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 609 additions and 455 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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]

View File

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

View File

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

View File

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