From e8c6af0636f6a7e8eb0e6146e53dc8705948ed88 Mon Sep 17 00:00:00 2001 From: tersec Date: Wed, 7 Jun 2023 21:27:15 +0000 Subject: [PATCH] add getNextWithdrawals Beacon API (#5021) --- beacon_chain/nimbus_beacon_node.nim | 1 + beacon_chain/rpc/rest_api.nim | 16 ++-- beacon_chain/rpc/rest_builder_api.nim | 44 ++++++++++ ncli/resttest-rules.json | 112 ++++++++++++++++++++++++++ 4 files changed, 165 insertions(+), 8 deletions(-) create mode 100644 beacon_chain/rpc/rest_builder_api.nim diff --git a/beacon_chain/nimbus_beacon_node.nim b/beacon_chain/nimbus_beacon_node.nim index 3656aa96b..391fc61a8 100644 --- a/beacon_chain/nimbus_beacon_node.nim +++ b/beacon_chain/nimbus_beacon_node.nim @@ -1418,6 +1418,7 @@ func connectedPeersCount(node: BeaconNode): int = proc installRestHandlers(restServer: RestServerRef, node: BeaconNode) = restServer.router.installBeaconApiHandlers(node) + restServer.router.installBuilderApiHandlers(node) restServer.router.installConfigApiHandlers(node) restServer.router.installDebugApiHandlers(node) restServer.router.installEventApiHandlers(node) diff --git a/beacon_chain/rpc/rest_api.nim b/beacon_chain/rpc/rest_api.nim index de9922aed..96740e104 100644 --- a/beacon_chain/rpc/rest_api.nim +++ b/beacon_chain/rpc/rest_api.nim @@ -8,8 +8,8 @@ {.push raises: [].} ## The `rest_api` module is a server implementation for the common REST API for -## Ethereum 2 found at https://ethereum.github.io/eth2.0-APIs/# -## along with several nimbus-specific extensions. It is used by the validator +## Ethereum found at https://ethereum.github.io/beacon-APIs/ +## along with several Nimbus-specific extensions. It is used by the validator ## client as well as many community utilities. ## A corresponding client can be found in the ## `spec/eth2_apis/rest_beacon_client` module @@ -17,12 +17,12 @@ import "."/[ rest_utils, - rest_beacon_api, rest_config_api, rest_debug_api, rest_event_api, - rest_key_management_api, rest_light_client_api, rest_nimbus_api, - rest_node_api, rest_validator_api] + rest_beacon_api, rest_builder_api, rest_config_api, rest_debug_api, + rest_event_api, rest_key_management_api, rest_light_client_api, + rest_nimbus_api, rest_node_api, rest_validator_api] export rest_utils, - rest_beacon_api, rest_config_api, rest_debug_api, rest_event_api, - rest_key_management_api, rest_light_client_api, rest_nimbus_api, - rest_node_api, rest_validator_api + rest_beacon_api, rest_builder_api, rest_config_api, rest_debug_api, + rest_event_api, rest_key_management_api, rest_light_client_api, + rest_nimbus_api, rest_node_api, rest_validator_api diff --git a/beacon_chain/rpc/rest_builder_api.nim b/beacon_chain/rpc/rest_builder_api.nim new file mode 100644 index 000000000..00cad2bdf --- /dev/null +++ b/beacon_chain/rpc/rest_builder_api.nim @@ -0,0 +1,44 @@ +# beacon_chain +# Copyright (c) 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). +# at your option. This file may not be copied, modified, or distributed except according to those terms. + +import + ./rest_utils, + ./state_ttl_cache, + ../beacon_node + +export rest_utils + +logScope: topics = "rest_builderapi" + +proc installBuilderApiHandlers*(router: var RestRouter, node: BeaconNode) = + # https://ethereum.github.io/beacon-APIs/?urls.primaryName=v2.4.0#/Builder/getNextWithdrawals + # https://github.com/ethereum/beacon-APIs/blob/v2.4.0/apis/builder/states/expected_withdrawals.yaml + router.api(MethodGet, "/eth/v1/builder/states/{state_id}/expected_withdrawals") do ( + state_id: StateIdent) -> RestApiResponse: + let + sid = state_id.valueOr: + return RestApiResponse.jsonError(Http400, InvalidStateIdValueError, + $error) + bslot = node.getBlockSlotId(sid).valueOr: + if sid.kind == StateQueryKind.Root: + # TODO (cheatfate): Its impossible to retrieve state by `state_root` + # in current version of database. + return RestApiResponse.jsonError(Http500, NoImplementationError) + return RestApiResponse.jsonError(Http404, StateNotFoundError, + $error) + + node.withStateForBlockSlotId(bslot): + withState(state): + when consensusFork >= ConsensusFork.Capella: + return RestApiResponse.jsonResponseWOpt( + get_expected_withdrawals(forkyState.data), + node.getStateOptimistic(state)) + else: + return RestApiResponse.jsonError( + Http400, "The specified state is not a capella state") + + return RestApiResponse.jsonError(Http404, StateNotFoundError) diff --git a/ncli/resttest-rules.json b/ncli/resttest-rules.json index b7181342e..fd3c948ef 100644 --- a/ncli/resttest-rules.json +++ b/ncli/resttest-rules.json @@ -2669,6 +2669,118 @@ "body": [{"operator": "jstructcmps", "start": ["data"],"value": [{"message": {"validator_index": "", "from_bls_pubkey": "", "to_execution_address": ""}, "signature": ""}]}] } }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/head/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/genesis/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/finalized/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/justified/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/heat/expected_withdrawals"}, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/genezis/expected_withdrawals"}, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/finalised/expected_withdrawals"}, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/justilied/expected_withdrawals"}, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/0/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/18446744073709551615/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "comment": "Maximum value for uint64", + "response": {"status": {"operator": "equals", "value": "404"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": { + "url": "/eth/v1/builder/states/18446744073709551616/expected_withdrawals", + "headers": {"Accept": "application/json"} + }, + "comment": "Overflow uint64 value test", + "response": { + "status": {"operator": "equals", "value": "400"}, + "headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}], + "body": [{"operator": "jstructcmpns", "value": {"code": 400, "message": ""}}] + } + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/0x/expected_withdrawals"}, + "comment": "Hexadecimal state root tests", + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/0x0/expected_withdrawals"}, + "comment": "Hexadecimal state root tests", + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/0x00/expected_withdrawals"}, + "comment": "Hexadecimal state root tests", + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/0x1/expected_withdrawals"}, + "comment": "Hexadecimal state root tests", + "response": {"status": {"operator": "equals", "value": "400"}} + }, + { + "topics": ["builder", "states_expected_withdrawals"], + "request": {"url": "/eth/v1/builder/states/0x11/expected_withdrawals"}, + "comment": "Hexadecimal state root tests", + "response": {"status": {"operator": "equals", "value": "400"}} + }, { "topics": ["config"], "request": {