REST API client, JSON-RPC cleanups (#2756)

This refactoring puts the JSON-RPC and REST APIs on more equal footing
by renaming and moving things around, creating a separation between
client and server, and documenting what they are - the aim is to have a
simple-to-use base to start from when developing API clients, as well as
make it easier to navigate the code when looking for the legacy JSON-RPC
interface vs the new REST API.

* move REST client, serialization and supporting types to spec/eth2_apis
* REST stuff now starts with `rest_`, JSON-RPC stuff starts with `rpc_`,
more or less
* simplify imports such that there's a simple module to import for both
server and client
* map REST type and proc names to yaml spec more closely - in
particular, reuse operation and type names in `rest_types` to make
comparisons against spec more easy
* cleaner separation between client and server modules - modules common
between server and client such as `rest_types` and serialization move to
the spec folder - this allows the client to be built with less knowledge
about server internals
This commit is contained in:
Jacek Sieka 2021-08-03 17:17:11 +02:00 committed by GitHub
parent d638ca0c7f
commit 3d7bee8502
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 1208 additions and 725 deletions

View File

@ -24,7 +24,7 @@ import
./sync/[sync_manager, request_manager]
export
osproc, chronos, httpserver, conf, beacon_clock, beacon_chain_db,
osproc, chronos, httpserver, presto, conf, beacon_clock, beacon_chain_db,
attestation_pool, eth2_network, beacon_node_types, eth1_monitor,
request_manager, sync_manager, eth2_processor, blockchain_dag, block_quarantine,
base

View File

@ -34,13 +34,10 @@ import
attestation_aggregation, validator_duties, validator_pool,
slashing_protection, keystore_management],
./sync/[sync_manager, sync_protocol, request_manager],
./rpc/[rest_utils, config_rest_api, debug_rest_api, node_rest_api,
beacon_rest_api, event_rest_api, validator_rest_api, nimbus_rest_api],
./rpc/[beacon_api, config_api, debug_api, event_api, nimbus_api, node_api,
validator_api],
./rpc/[rest_api, rpc_api],
./spec/[
datatypes/phase0, datatypes/altair, digest, crypto,
forkedbeaconstate_helpers, beaconstate, eth2_apis/beacon_rpc_client,
forkedbeaconstate_helpers, beaconstate, eth2_apis/rpc_beacon_client,
helpers, network, presets, weak_subjectivity, signatures],
./consensus_object_pools/[
blockchain_dag, block_quarantine, block_clearance, block_pools_types,

View File

@ -7,14 +7,14 @@
import validator_client/[common, fallback_service, duties_service,
attestation_service, fork_service]
proc initGenesis*(vc: ValidatorClientRef): Future[RestBeaconGenesis] {.async.} =
proc initGenesis*(vc: ValidatorClientRef): Future[RestGenesis] {.async.} =
info "Initializing genesis", nodes_count = len(vc.beaconNodes)
var nodes = vc.beaconNodes
while true:
var pending: seq[Future[RestResponse[DataRestBeaconGenesis]]]
var pending: seq[Future[RestResponse[GetGenesisResponse]]]
for node in nodes:
debug "Requesting genesis information", endpoint = node
pending.add(node.client.getBeaconGenesis())
pending.add(node.client.getGenesis())
try:
await allFutures(pending)
@ -24,7 +24,7 @@ proc initGenesis*(vc: ValidatorClientRef): Future[RestBeaconGenesis] {.async.} =
let (errorNodes, genesisList) =
block:
var gres: seq[RestBeaconGenesis]
var gres: seq[RestGenesis]
var bres: seq[BeaconNodeServerRef]
for i in 0 ..< len(pending):
let fut = pending[i]
@ -60,7 +60,7 @@ proc initGenesis*(vc: ValidatorClientRef): Future[RestBeaconGenesis] {.async.} =
nodes = errorNodes
else:
# Boyer-Moore majority vote algorithm
var melem: RestBeaconGenesis
var melem: RestGenesis
var counter = 0
for item in genesisList:
if counter == 0:

View File

@ -2,7 +2,7 @@ import
strutils,
json_serialization/std/[sets, net], serialization/errors,
../spec/datatypes/base,
../spec/[crypto, digest, eth2_apis/beacon_rpc_client],
../spec/[crypto, digest, eth2_apis/rpc_beacon_client],
json_rpc/[client, jsonmarshal]
from os import DirSep, AltSep

View File

@ -0,0 +1,22 @@
# Copyright (c) 2018-2021 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.
## 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
## client as well as many community utilities.
## A corresponding client can be found in the
## `spec/eth2_apis/rest_beacon_client` module
import
"."/[
rest_utils,
rest_beacon_api, rest_config_api, rest_debug_api, rest_event_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_nimbus_api, rest_node_api, rest_validator_api

View File

@ -15,15 +15,10 @@ import
../spec/[crypto, digest, forkedbeaconstate_helpers, network],
../spec/datatypes/phase0,
../ssz/merkleization,
./eth2_json_rest_serialization, ./rest_utils
./rest_utils
logScope: topics = "rest_beaconapi"
const
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validator_balances.yaml#L17
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validators.yaml#L17
MaximumValidatorIds* = 30
proc validateFilter(filters: seq[ValidatorFilter]): Result[ValidatorFilter,
cstring] =
var res: ValidatorFilter
@ -940,38 +935,3 @@ proc installBeaconApiHandlers*(router: var RestRouter, node: BeaconNode) =
"/eth/v1/beacon/pool/voluntary_exits",
"/api/eth/v1/beacon/pool/voluntary_exits"
)
proc getBeaconGenesis*(): RestResponse[DataRestBeaconGenesis] {.
rest, endpoint: "/eth/v1/beacon/genesis",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getGenesis
proc getStateFork*(state_id: StateIdent): RestResponse[DataRestFork] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/fork",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateFork
proc publishBlock*(body: phase0.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/publishBlock
proc getStateValidator*(state_id: StateIdent,
validator_id: ValidatorIdent
): RestResponse[DataRestValidator] {.
rest,
endpoint: "/eth/v1/beacon/states/{state_id}/validators/{validator_id}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateValidator
proc getStateValidators*(state_id: StateIdent,
id: seq[ValidatorIdent]
): RestResponse[DataRestValidatorList] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/validators",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateValidators
proc submitPoolAttestations*(body: seq[Attestation]): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/pool/attestations",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/submitPoolAttestations

View File

@ -7,13 +7,12 @@
import
stew/[endians2, base10],
presto,
rest_utils,
chronicles,
nimcrypto/utils as ncrutils,
../beacon_node_common, ../eth1/eth1_monitor,
../spec/datatypes/base,
../spec/[digest, forkedbeaconstate_helpers, presets],
./eth2_json_rest_serialization, ./rest_utils
./rest_utils
logScope: topics = "rest_config"
@ -180,7 +179,3 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
"/eth/v1/config/deposit_contract",
"/api/eth/v1/config/deposit_contract"
)
proc getConfig*(): RestResponse[DataRestConfig] {.
rest, endpoint: "/eth/v1/config/spec", meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Config/getSpec

View File

@ -4,7 +4,7 @@ import
chronicles,
../version, ../beacon_node_common,
../spec/[datatypes, digest, presets],
./eth2_json_rest_serialization, ./rest_utils
./rest_utils
logScope: topics = "rest_debug"
@ -42,3 +42,8 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
"/eth/v1/debug/beacon/heads",
"/api/eth/v1/debug/beacon/heads"
)
proc getDebugChainHeads*(): RestResponse[GetDebugChainHeadsResponse] {.
rest, endpoint: "/eth/v1/debug/beacon/heads",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getDebugChainHeads

View File

@ -8,7 +8,7 @@ import
stew/results,
chronicles,
presto,
./eth2_json_rest_serialization, ./rest_utils,
./rest_utils,
../beacon_node_common
logScope: topics = "rest_eventapi"

View File

@ -11,7 +11,7 @@ import
presto,
libp2p/[multiaddress, multicodec],
libp2p/protocols/pubsub/pubsubpeer,
./eth2_json_rest_serialization, ./rest_utils,
./rest_utils,
../eth1/eth1_monitor,
../validators/validator_duties,
../spec/forkedbeaconstate_helpers,

View File

@ -9,8 +9,8 @@ import
../networking/[eth2_network, peer_pool],
../spec/datatypes/base,
../spec/[digest, presets],
../spec/eth2_apis/callsigs_types,
./eth2_json_rest_serialization, ./rest_utils
../spec/eth2_apis/rpc_types,
./rest_utils
logScope: topics = "rest_node"
@ -183,7 +183,7 @@ proc installNodeApiHandlers*(router: var RestRouter, node: BeaconNode) =
$dres.error())
dres.get()
var res: seq[NodePeerTuple]
var res: seq[RpcNodePeer]
for item in node.network.peers.values():
if (item.connectionState in connectionMask) and
(item.direction in directionMask):
@ -291,13 +291,3 @@ proc installNodeApiHandlers*(router: var RestRouter, node: BeaconNode) =
"/eth/v1/node/health",
"/api/eth/v1/node/health"
)
proc getSyncingStatus*(): RestResponse[DataRestSyncInfo] {.
rest, endpoint: "/eth/v1/node/syncing",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getSyncingStatus
proc getVersion*(): RestResponse[DataRestVersion] {.
rest, endpoint: "/eth/v1/node/version",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getNodeVersion

View File

@ -1,32 +1,14 @@
import presto, presto/client as presto_client,
libp2p/peerid,
stew/[base10, byteutils],
faststreams/[outputs],
serialization, json_serialization,
nimcrypto/utils as ncrutils,
../spec/[crypto, datatypes, digest, forkedbeaconstate_helpers],
../spec/eth2_apis/[rest_types, eth2_rest_serialization],
../beacon_node_common,
../consensus_object_pools/[block_pools_types, blockchain_dag]
export blockchain_dag, presto, presto_client
export
blockchain_dag, presto, presto_client, rest_types, eth2_rest_serialization
const
DecimalSet = {'0' .. '9'}
# Base10 (decimal) set of chars
HexadecimalSet = {'0'..'9', 'A'..'F', 'a'..'f'}
# Base16 (hexadecimal) set of chars
Base58Set = {'1'..'9', 'A'..'H', 'J'..'N', 'P'..'Z', 'a'..'k', 'm'..'z'}
# Base58 set of chars
MaxDecimalSize = len($high(uint64))
# Maximum size of `uint64` decimal value
MaxPeerIdSize = 128
# Maximum size of `PeerID` base58 encoded value
ValidatorKeySize = RawPubKeySize * 2
# Size of `ValidatorPubKey` hexadecimal value (without 0x)
ValidatorSigSize = RawSigSize * 2
# Size of `ValidatorSig` hexadecimal value (without 0x)
RootHashSize = sizeof(Eth2Digest) * 2
# Size of `xxx_root` hexadecimal value (without 0x)
FarFutureEpochString* = "18446744073709551615"
MaxEpoch* = compute_epoch_at_slot(not(0'u64))
BlockValidationError* =
@ -159,69 +141,9 @@ const
"Not implemented yet"
type
ValidatorQueryKind* {.pure.} = enum
Index, Key
RestValidatorIndex* = distinct uint64
ValidatorIndexError* {.pure.} = enum
UnsupportedValue, TooHighValue
ValidatorIdent* = object
case kind*: ValidatorQueryKind
of ValidatorQueryKind.Index:
index*: RestValidatorIndex
of ValidatorQueryKind.Key:
key*: ValidatorPubKey
ValidatorFilterKind* {.pure.} = enum
PendingInitialized, PendingQueued,
ActiveOngoing, ActiveExiting, ActiveSlashed,
ExitedUnslashed, ExitedSlashed,
WithdrawalPossible, WithdrawalDone
ValidatorFilter* = set[ValidatorFilterKind]
StateQueryKind* {.pure.} = enum
Slot, Root, Named
StateIdentType* {.pure.} = enum
Head, Genesis, Finalized, Justified
StateIdent* = object
case kind*: StateQueryKind
of StateQueryKind.Slot:
slot*: Slot
of StateQueryKind.Root:
root*: Eth2Digest
of StateQueryKind.Named:
value*: StateIdentType
BlockQueryKind* {.pure.} = enum
Slot, Root, Named
BlockIdentType* {.pure.} = enum
Head, Genesis, Finalized
BlockIdent* = object
case kind*: BlockQueryKind
of BlockQueryKind.Slot:
slot*: Slot
of BlockQueryKind.Root:
root*: Eth2Digest
of BlockQueryKind.Named:
value*: BlockIdentType
PeerStateKind* {.pure.} = enum
Disconnected, Connecting, Connected, Disconnecting
PeerDirectKind* {.pure.} = enum
Inbound, Outbound
EventTopic* {.pure.} = enum
Head, Block, Attestation, VoluntaryExit, FinalizedCheckpoint, ChainReorg
EventTopics* = set[EventTopic]
func match(data: openarray[char], charset: set[char]): int =
for ch in data:
if ch notin charset:
@ -247,228 +169,6 @@ proc validate(key: string, value: string): int =
else:
1
proc parseRoot(value: string): Result[Eth2Digest, cstring] =
try:
ok(Eth2Digest(data: hexToByteArray[32](value)))
except ValueError:
err("Unable to decode root value")
proc decodeString*(t: typedesc[Slot], value: string): Result[Slot, cstring] =
let res = ? Base10.decode(uint64, value)
ok(Slot(res))
proc decodeString*(t: typedesc[Epoch], value: string): Result[Epoch, cstring] =
let res = ? Base10.decode(uint64, value)
ok(Epoch(res))
proc decodeString*(t: typedesc[StateIdent],
value: string): Result[StateIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != RootHashSize + 2:
err("Incorrect state root value length")
else:
let res = ? parseRoot(value)
ok(StateIdent(kind: StateQueryKind.Root, root: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(StateIdent(kind: StateQueryKind.Slot, slot: Slot(res)))
else:
case value
of "head":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Head))
of "genesis":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Genesis))
of "finalized":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Finalized))
of "justified":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Justified))
else:
err("Incorrect state identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(StateIdent(kind: StateQueryKind.Slot, slot: Slot(res)))
proc decodeString*(t: typedesc[BlockIdent],
value: string): Result[BlockIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != RootHashSize + 2:
err("Incorrect block root value length")
else:
let res = ? parseRoot(value)
ok(BlockIdent(kind: BlockQueryKind.Root, root: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(BlockIdent(kind: BlockQueryKind.Slot, slot: Slot(res)))
else:
case value
of "head":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Head))
of "genesis":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Genesis))
of "finalized":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Finalized))
else:
err("Incorrect block identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(BlockIdent(kind: BlockQueryKind.Slot, slot: Slot(res)))
proc decodeString*(t: typedesc[ValidatorIdent],
value: string): Result[ValidatorIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != ValidatorKeySize + 2:
err("Incorrect validator's key value length")
else:
let res = ? ValidatorPubKey.fromHex(value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Key,
key: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Index,
index: RestValidatorIndex(res)))
else:
err("Incorrect validator identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Index,
index: RestValidatorIndex(res)))
proc decodeString*(t: typedesc[PeerID],
value: string): Result[PeerID, cstring] =
PeerID.init(value)
proc decodeString*(t: typedesc[CommitteeIndex],
value: string): Result[CommitteeIndex, cstring] =
let res = ? Base10.decode(uint64, value)
ok(CommitteeIndex(res))
proc decodeString*(t: typedesc[Eth2Digest],
value: string): Result[Eth2Digest, cstring] =
if len(value) != RootHashSize + 2:
return err("Incorrect root value length")
if value[0] != '0' and value[1] != 'x':
return err("Incorrect root value encoding")
parseRoot(value)
proc decodeString*(t: typedesc[ValidatorFilter],
value: string): Result[ValidatorFilter, cstring] =
case value
of "pending_initialized":
ok({ValidatorFilterKind.PendingInitialized})
of "pending_queued":
ok({ValidatorFilterKind.PendingQueued})
of "active_ongoing":
ok({ValidatorFilterKind.ActiveOngoing})
of "active_exiting":
ok({ValidatorFilterKind.ActiveExiting})
of "active_slashed":
ok({ValidatorFilterKind.ActiveSlashed})
of "exited_unslashed":
ok({ValidatorFilterKind.ExitedUnslashed})
of "exited_slashed":
ok({ValidatorFilterKind.ExitedSlashed})
of "withdrawal_possible":
ok({ValidatorFilterKind.WithdrawalPossible})
of "withdrawal_done":
ok({ValidatorFilterKind.WithdrawalDone})
of "pending":
ok({
ValidatorFilterKind.PendingInitialized,
ValidatorFilterKind.PendingQueued
})
of "active":
ok({
ValidatorFilterKind.ActiveOngoing,
ValidatorFilterKind.ActiveExiting,
ValidatorFilterKind.ActiveSlashed
})
of "exited":
ok({
ValidatorFilterKind.ExitedUnslashed,
ValidatorFilterKind.ExitedSlashed
})
of "withdrawal":
ok({
ValidatorFilterKind.WithdrawalPossible,
ValidatorFilterKind.WithdrawalDone
})
else:
err("Incorrect validator state identifier value")
proc decodeString*(t: typedesc[PeerStateKind],
value: string): Result[PeerStateKind, cstring] =
case value
of "disconnected":
ok(PeerStateKind.Disconnected)
of "connecting":
ok(PeerStateKind.Connecting)
of "connected":
ok(PeerStateKind.Connected)
of "disconnecting":
ok(PeerStateKind.Disconnecting)
else:
err("Incorrect peer's state value")
proc decodeString*(t: typedesc[PeerDirectKind],
value: string): Result[PeerDirectKind, cstring] =
case value
of "inbound":
ok(PeerDirectKind.Inbound)
of "outbound":
ok(PeerDirectKind.Outbound)
else:
err("Incorrect peer's direction value")
proc decodeString*(t: typedesc[EventTopic],
value: string): Result[EventTopic, cstring] =
case value
of "head":
ok(EventTopic.Head)
of "block":
ok(EventTopic.Block)
of "attestation":
ok(EventTopic.Attestation)
of "voluntary_exit":
ok(EventTopic.VoluntaryExit)
of "finalized_checkpoint":
ok(EventTopic.FinalizedCheckpoint)
of "chain_reorg":
ok(EventTopic.ChainReorg)
else:
err("Incorrect event's topic value")
proc decodeString*(t: typedesc[ValidatorSig],
value: string): Result[ValidatorSig, cstring] =
if len(value) != ValidatorSigSize + 2:
return err("Incorrect validator signature value length")
if value[0] != '0' and value[1] != 'x':
return err("Incorrect validator signature encoding")
ValidatorSig.fromHex(value)
proc decodeString*(t: typedesc[GraffitiBytes],
value: string): Result[GraffitiBytes, cstring] =
try:
ok(GraffitiBytes.init(value))
except ValueError:
err("Unable to decode graffiti value")
proc decodeString*(t: typedesc[string],
value: string): Result[string, cstring] =
ok(value)
proc getRouter*(): RestRouter =
RestRouter.init(validate)
proc getCurrentHead*(node: BeaconNode,
slot: Slot): Result[BlockRef, cstring] =
let res = node.dag.head
@ -570,17 +270,5 @@ proc toValidatorIndex*(value: RestValidatorIndex): Result[ValidatorIndex,
else:
doAssert(false, "ValidatorIndex type size is incorrect")
proc init*(t: typedesc[StateIdent], v: StateIdentType): StateIdent =
StateIdent(kind: StateQueryKind.Named, value: v)
proc init*(t: typedesc[StateIdent], v: Slot): StateIdent =
StateIdent(kind: StateQueryKind.Slot, slot: v)
proc init*(t: typedesc[StateIdent], v: Eth2Digest): StateIdent =
StateIdent(kind: StateQueryKind.Root, root: v)
proc init*(t: typedesc[ValidatorIdent], v: ValidatorIndex): ValidatorIdent =
ValidatorIdent(kind: ValidatorQueryKind.Index, index: RestValidatorIndex(v))
proc init*(t: typedesc[ValidatorIdent], v: ValidatorPubKey): ValidatorIdent =
ValidatorIdent(kind: ValidatorQueryKind.Key, key: v)
proc getRouter*(): RestRouter =
RestRouter.init(validate)

View File

@ -15,7 +15,7 @@ import
../spec/[crypto, digest, forkedbeaconstate_helpers, network],
../spec/datatypes/base,
../ssz/merkleization,
./eth2_json_rest_serialization, ./rest_utils
./rest_utils
logScope: topics = "rest_validatorapi"
@ -386,47 +386,3 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
"/eth/v1/validator/beacon_committee_subscriptions",
"/api/eth/v1/validator/beacon_committee_subscriptions"
)
proc getProposerDuties*(epoch: Epoch): RestResponse[DataRestProposerDuties] {.
rest, endpoint: "/eth/v1/validator/duties/proposer/{epoch}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/getProposerDuties
proc getAttesterDuties*(epoch: Epoch,
body: seq[ValidatorIndex]
): RestResponse[DataRestAttesterDuties] {.
rest, endpoint: "/eth/v1/validator/duties/attester/{epoch}",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/getAttesterDuties
proc produceBlock*(slot: Slot, randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestResponse[DataRestBeaconBlock] {.
rest, endpoint: "/eth/v1/validator/blocks/{slot}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/produceBlock
proc produceAttestationData*(slot: Slot,
committee_index: CommitteeIndex
): RestResponse[DataRestAttestationData] {.
rest, endpoint: "/eth/v1/validator/attestation_data",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/produceAttestationData
proc getAggregatedAttestation*(attestation_data_root: Eth2Digest,
slot: Slot): RestResponse[DataRestAttestation] {.
rest, endpoint: "/eth/v1/validator/aggregate_attestation"
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/getAggregatedAttestation
proc publishAggregateAndProofs*(body: seq[SignedAggregateAndProof]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/aggregate_and_proofs",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/publishAggregateAndProofs
proc prepareBeaconCommitteeSubnet*(body: seq[RestCommitteeSubscription]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/beacon_committee_subscriptions",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/prepareBeaconCommitteeSubnet

View File

@ -0,0 +1,24 @@
# Copyright (c) 2018-2021 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.
## The `rpc_api` module is a server implementation of a JSON-RPC-based API
## for Nimbus - it is based on the common REST API for Ethereum 2 found at
## https://ethereum.github.io/eth2.0-APIs/# but uses JSON-RPC as transport
## instead. There are also minor historical differences in encoding and data -
## these differences will likely remain so as to not break old tooling.
##
## The JSON-RPC is used by community utilities and tools and is kept for
## backwards compatibility mainly.
## A corresponding client can be found in the
## `spec/eth2_apis/rpc_beacon_client` module.
import
"."/[
rpc_beacon_api, rpc_config_api, rpc_debug_api, rpc_event_api,
rpc_nimbus_api, rpc_node_api, rpc_validator_api]
export
rpc_beacon_api, rpc_config_api, rpc_debug_api, rpc_event_api,
rpc_nimbus_api, rpc_node_api, rpc_validator_api

View File

@ -19,9 +19,8 @@ import
../gossip_processing/gossip_validation,
../consensus_object_pools/blockchain_dag,
../spec/[crypto, datatypes/phase0, digest, forkedbeaconstate_helpers, network],
../spec/eth2_apis/callsigs_types,
../ssz/merkleization,
./rpc_utils, ./eth2_json_rpc_serialization
./rpc_utils
logScope: topics = "beaconapi"
@ -180,7 +179,7 @@ proc getBlockDataFromBlockId(node: BeaconNode, blockId: string): BlockData {.rai
proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Exception].} = # TODO fix json-rpc
rpcServer.rpc("get_v1_beacon_genesis") do () -> BeaconGenesisTuple:
rpcServer.rpc("get_v1_beacon_genesis") do () -> RpcBeaconGenesis:
return (
genesis_time: getStateField(node.dag.headState.data, genesis_time),
genesis_validators_root:
@ -197,7 +196,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
return getStateField(stateData.data, fork)
rpcServer.rpc("get_v1_beacon_states_finality_checkpoints") do (
stateId: string) -> BeaconStatesFinalityCheckpointsTuple:
stateId: string) -> RpcBeaconStatesFinalityCheckpoints:
withStateForStateId(stateId):
return (previous_justified:
getStateField(stateData.data, previous_justified_checkpoint),
@ -207,7 +206,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_beacon_states_stateId_validators") do (
stateId: string, validatorIds: Option[seq[string]],
status: Option[seq[string]]) -> seq[BeaconStatesValidatorsTuple]:
status: Option[seq[string]]) -> seq[RpcBeaconStatesValidators]:
var vquery: ValidatorQuery
var squery: StatusQuery
let current_epoch = getStateField(node.dag.headState.data, slot).epoch
@ -221,7 +220,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
else:
false
var res: seq[BeaconStatesValidatorsTuple]
var res: seq[RpcBeaconStatesValidators]
withStateForStateId(stateId):
if status.isSome:
@ -279,7 +278,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
return res
rpcServer.rpc("get_v1_beacon_states_stateId_validators_validatorId") do (
stateId: string, validatorId: string) -> BeaconStatesValidatorsTuple:
stateId: string, validatorId: string) -> RpcBeaconStatesValidators:
let current_epoch = getStateField(node.dag.headState.data, slot).epoch
let vqres = createIdQuery([validatorId])
if vqres.isErr:
@ -310,9 +309,9 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raise newException(CatchableError, "Incorrect validator's state")
rpcServer.rpc("get_v1_beacon_states_stateId_validator_balances") do (
stateId: string, validatorsId: Option[seq[string]]) -> seq[BalanceTuple]:
stateId: string, validatorsId: Option[seq[string]]) -> seq[RpcBalance]:
var res: seq[BalanceTuple]
var res: seq[RpcBalance]
withStateForStateId(stateId):
if validatorsId.isNone():
for index, value in getStateField(stateData.data, balances).pairs():
@ -341,15 +340,15 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_beacon_states_stateId_committees_epoch") do (
stateId: string, epoch: Option[uint64], index: Option[uint64],
slot: Option[uint64]) -> seq[BeaconStatesCommitteesTuple]:
slot: Option[uint64]) -> seq[RpcBeaconStatesCommittees]:
withStateForStateId(stateId):
proc getCommittee(slot: Slot,
index: CommitteeIndex): BeaconStatesCommitteesTuple =
index: CommitteeIndex): RpcBeaconStatesCommittees =
let vals = get_beacon_committee(
stateData.data, slot, index, cache).mapIt(it.uint64)
return (index: index.uint64, slot: slot.uint64, validators: vals)
proc forSlot(slot: Slot, res: var seq[BeaconStatesCommitteesTuple]) =
proc forSlot(slot: Slot, res: var seq[RpcBeaconStatesCommittees]) =
let committees_per_slot =
get_committee_count_per_slot(stateData.data, slot.epoch, cache)
@ -360,7 +359,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
if index.get() < committees_per_slot:
res.add(getCommittee(slot, CommitteeIndex(index.get())))
var res: seq[BeaconStatesCommitteesTuple]
var res: seq[RpcBeaconStatesCommittees]
let qepoch =
if epoch.isNone:
@ -378,7 +377,7 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_beacon_headers") do (
slot: Option[uint64], parent_root: Option[string]) ->
seq[BeaconHeadersTuple]:
seq[RpcBeaconHeaders]:
unimplemented()
rpcServer.rpc("get_v1_beacon_headers_blockId") do (
@ -443,9 +442,9 @@ proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_beacon_pool_attestations") do (
slot: Option[uint64], committee_index: Option[uint64]) ->
seq[AttestationTuple]:
seq[RpcAttestation]:
var res: seq[AttestationTuple]
var res: seq[RpcAttestation]
let qslot =
if slot.isSome():

View File

@ -15,7 +15,7 @@ import
../networking/[eth2_network, peer_pool],
../spec/datatypes/phase0,
../spec/[digest, presets],
./rpc_utils, ./eth2_json_rpc_serialization
./rpc_utils
logScope: topics = "debugapi"

View File

@ -14,12 +14,12 @@ import
json_rpc/servers/httpserver,
libp2p/protocols/pubsub/pubsubpeer,
"."/[rpc_utils, eth2_json_rpc_serialization],
".."/[
beacon_node_common, nimbus_binary_common, networking/eth2_network,
eth1/eth1_monitor, validators/validator_duties],
../spec/datatypes/base,
../spec/[digest, forkedbeaconstate_helpers, presets]
../spec/[digest, forkedbeaconstate_helpers, presets],
./rpc_utils
logScope: topics = "nimbusapi"

View File

@ -13,13 +13,12 @@ import std/options,
eth/p2p/discoveryv5/enr,
libp2p/[multiaddress, multicodec],
nimcrypto/utils as ncrutils,
./eth2_json_rpc_serialization,
../beacon_node_common, ../version,
../networking/[eth2_network, peer_pool],
../sync/sync_manager,
../spec/datatypes/base,
../spec/[digest, presets],
../spec/eth2_apis/callsigs_types
./rpc_utils
logScope: topics = "nodeapi"
@ -152,7 +151,7 @@ proc getP2PAddresses(node: BeaconNode): Option[seq[string]] =
proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Exception].} = # TODO fix json-rpc
rpcServer.rpc("get_v1_node_identity") do () -> NodeIdentityTuple:
rpcServer.rpc("get_v1_node_identity") do () -> RpcNodeIdentity:
let discoveryAddresses =
block:
let res = node.getDiscoveryAddresses()
@ -179,8 +178,8 @@ proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
)
rpcServer.rpc("get_v1_node_peers") do (state: Option[seq[string]],
direction: Option[seq[string]]) -> seq[NodePeerTuple]:
var res = newSeq[NodePeerTuple]()
direction: Option[seq[string]]) -> seq[RpcNodePeer]:
var res = newSeq[RpcNodePeer]()
let rstates = validateState(state)
if rstates.isNone():
raise newException(CatchableError, "Incorrect state parameter")
@ -203,8 +202,8 @@ proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
res.add(peer)
return res
rpcServer.rpc("get_v1_node_peer_count") do () -> NodePeerCountTuple:
var res: NodePeerCountTuple
rpcServer.rpc("get_v1_node_peer_count") do () -> RpcNodePeerCount:
var res: RpcNodePeerCount
for item in node.network.peers.values():
case item.connectionState
of ConnectionState.Connecting:
@ -220,7 +219,7 @@ proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
return res
rpcServer.rpc("get_v1_node_peers_peerId") do (
peer_id: string) -> NodePeerTuple:
peer_id: string) -> RpcNodePeer:
let pres = PeerID.init(peer_id)
if pres.isErr():
raise newException(CatchableError,
@ -243,7 +242,7 @@ proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
rpcServer.rpc("get_v1_node_version") do () -> JsonNode:
return %*{"version": "Nimbus/" & fullVersionStr}
rpcServer.rpc("get_v1_node_syncing") do () -> SyncInfo:
rpcServer.rpc("get_v1_node_syncing") do () -> RpcSyncInfo:
return node.syncManager.getInfo()
rpcServer.rpc("get_v1_node_health") do () -> JsonNode:

View File

@ -13,9 +13,10 @@ import
../beacon_node_common, ../validators/validator_duties,
../consensus_object_pools/[block_pools_types, blockchain_dag],
../spec/datatypes/base,
../spec/[digest, forkedbeaconstate_helpers, helpers]
../spec/[digest, forkedbeaconstate_helpers, helpers],
../spec/eth2_apis/[rpc_types, eth2_json_rpc_serialization]
export blockchain_dag
export rpc_types, eth2_json_rpc_serialization, blockchain_dag
template withStateForStateId*(stateId: string, body: untyped): untyped =
let

View File

@ -19,12 +19,11 @@ import
# Local modules
../spec/[crypto, digest, forkedbeaconstate_helpers, helpers, network, signatures],
../spec/datatypes/phase0,
../spec/eth2_apis/callsigs_types,
../spec/eth2_apis/rpc_types,
../consensus_object_pools/[blockchain_dag, spec_cache, attestation_pool], ../ssz/merkleization,
../beacon_node_common, ../beacon_node_types,
../validators/validator_duties,
../networking/eth2_network,
./eth2_json_rpc_serialization,
./rpc_utils
logScope: topics = "valapi"
@ -86,7 +85,7 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
signature = shortLog(payload.signature)
rpcServer.rpc("get_v1_validator_duties_attester") do (
epoch: Epoch, public_keys: seq[ValidatorPubKey]) -> seq[AttesterDuties]:
epoch: Epoch, public_keys: seq[ValidatorPubKey]) -> seq[RpcAttesterDuties]:
debug "get_v1_validator_duties_attester", epoch = epoch
let
head = node.doChecksAndGetCurrentHead(epoch)
@ -109,7 +108,7 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
slot: slot))
rpcServer.rpc("get_v1_validator_duties_proposer") do (
epoch: Epoch) -> seq[ValidatorDutiesTuple]:
epoch: Epoch) -> seq[RpcValidatorDuties]:
debug "get_v1_validator_duties_proposer", epoch = epoch
let
head = node.doChecksAndGetCurrentHead(epoch)

View File

@ -1,16 +0,0 @@
import
std/os,
json_rpc/rpcclient,
../../rpc/eth2_json_rpc_serialization,
./callsigs_types
export
rpcclient,
callsigs_types,
eth2_json_rpc_serialization
createRpcSigs(RpcClient, currentSourcePath.parentDir / "beacon_callsigs.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "debug_callsigs.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "nimbus_callsigs.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "node_callsigs.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "validator_callsigs.nim")

View File

@ -29,8 +29,8 @@ import
json_rpc/jsonmarshal,
# Local modules
../ssz/types,
../spec/[datatypes, crypto, digest]
../../ssz/types,
".."/[datatypes, crypto, digest]
export jsonmarshal, datatypes, crypto, digest

View File

@ -1,135 +1,34 @@
# Copyright (c) 2018-2021 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
std/[typetraits],
stew/[results, base10, byteutils, endians2],
chronicles, presto,
faststreams/[outputs],
serialization, json_serialization,
presto,
libp2p/peerid,
json_serialization, json_serialization/std/[options, net],
nimcrypto/utils as ncrutils,
../beacon_node_common, ../networking/eth2_network,
../consensus_object_pools/[blockchain_dag, exit_pool],
../spec/[crypto, digest, datatypes/phase0, eth2_apis/callsigs_types],
../ssz/merkleization,
rest_utils
export json_serialization
../datatypes/[phase0, altair],
./rest_types
export results, peerid, presto, json_serialization, options, net, rest_types
Json.createFlavor RestJson
const
DecimalSet = {'0' .. '9'}
# Base10 (decimal) set of chars
ValidatorKeySize = RawPubKeySize * 2
# Size of `ValidatorPubKey` hexadecimal value (without 0x)
ValidatorSigSize = RawSigSize * 2
# Size of `ValidatorSig` hexadecimal value (without 0x)
RootHashSize = sizeof(Eth2Digest) * 2
# Size of `xxx_root` hexadecimal value (without 0x)
type
RestAttesterDuty* = object
pubkey*: ValidatorPubKey
validator_index*: ValidatorIndex
committee_index*: CommitteeIndex
committee_length*: uint64
committees_at_slot*: uint64
validator_committee_index*: ValidatorIndex
slot*: Slot
RestProposerDuty* = object
pubkey*: ValidatorPubKey
validator_index*: ValidatorIndex
slot*: Slot
RestCommitteeSubscription* = object
validator_index*: ValidatorIndex
committee_index*: CommitteeIndex
committees_at_slot*: uint64
slot*: Slot
is_aggregator*: bool
RestBeaconGenesis* = object
genesis_time*: uint64
genesis_validators_root*: Eth2Digest
genesis_fork_version*: Version
RestValidatorBalance* = object
index*: ValidatorIndex
balance*: string
RestBeaconStatesCommittees* = object
index*: CommitteeIndex
slot*: Slot
validators*: seq[ValidatorIndex]
RestAttestationsFailure* = object
index*: uint64
message*: string
RestValidator* = object
index*: ValidatorIndex
balance*: string
status*: string
validator*: Validator
RestVersion* = object
version*: string
RestSyncInfo* = object
head_slot*: Slot
sync_distance*: uint64
is_syncing*: bool
RestConfig* = object
CONFIG_NAME*: string
MAX_COMMITTEES_PER_SLOT*: uint64
TARGET_COMMITTEE_SIZE*: uint64
MAX_VALIDATORS_PER_COMMITTEE*: uint64
MIN_PER_EPOCH_CHURN_LIMIT*: uint64
CHURN_LIMIT_QUOTIENT*: uint64
SHUFFLE_ROUND_COUNT*: uint64
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT*: uint64
MIN_GENESIS_TIME*: uint64
HYSTERESIS_QUOTIENT*: uint64
HYSTERESIS_DOWNWARD_MULTIPLIER*: uint64
HYSTERESIS_UPWARD_MULTIPLIER*: uint64
SAFE_SLOTS_TO_UPDATE_JUSTIFIED*: uint64
ETH1_FOLLOW_DISTANCE*: uint64
TARGET_AGGREGATORS_PER_COMMITTEE*: uint64
RANDOM_SUBNETS_PER_VALIDATOR*: uint64
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION*: uint64
SECONDS_PER_ETH1_BLOCK*: uint64
DEPOSIT_CHAIN_ID*: uint64
DEPOSIT_NETWORK_ID*: uint64
DEPOSIT_CONTRACT_ADDRESS*: Eth1Address
MIN_DEPOSIT_AMOUNT*: uint64
MAX_EFFECTIVE_BALANCE*: uint64
EJECTION_BALANCE*: uint64
EFFECTIVE_BALANCE_INCREMENT*: uint64
GENESIS_FORK_VERSION*: Version
BLS_WITHDRAWAL_PREFIX*: byte
GENESIS_DELAY*: uint64
SECONDS_PER_SLOT*: uint64
MIN_ATTESTATION_INCLUSION_DELAY*: uint64
SLOTS_PER_EPOCH*: uint64
MIN_SEED_LOOKAHEAD*: uint64
MAX_SEED_LOOKAHEAD*: uint64
EPOCHS_PER_ETH1_VOTING_PERIOD*: uint64
SLOTS_PER_HISTORICAL_ROOT*: uint64
MIN_VALIDATOR_WITHDRAWABILITY_DELAY*: uint64
SHARD_COMMITTEE_PERIOD*: uint64
MIN_EPOCHS_TO_INACTIVITY_PENALTY*: uint64
EPOCHS_PER_HISTORICAL_VECTOR*: uint64
EPOCHS_PER_SLASHINGS_VECTOR*: uint64
HISTORICAL_ROOTS_LIMIT*: uint64
VALIDATOR_REGISTRY_LIMIT*: uint64
BASE_REWARD_FACTOR*: uint64
WHISTLEBLOWER_REWARD_QUOTIENT*: uint64
PROPOSER_REWARD_QUOTIENT*: uint64
INACTIVITY_PENALTY_QUOTIENT*: uint64
MIN_SLASHING_PENALTY_QUOTIENT*: uint64
PROPORTIONAL_SLASHING_MULTIPLIER*: uint64
MAX_PROPOSER_SLASHINGS*: uint64
MAX_ATTESTER_SLASHINGS*: uint64
MAX_ATTESTATIONS*: uint64
MAX_DEPOSITS*: uint64
MAX_VOLUNTARY_EXITS*: uint64
DOMAIN_BEACON_PROPOSER*: DomainType
DOMAIN_BEACON_ATTESTER*: DomainType
DOMAIN_RANDAO*: DomainType
DOMAIN_DEPOSIT*: DomainType
DOMAIN_VOLUNTARY_EXIT*: DomainType
DOMAIN_SELECTION_PROOF*: DomainType
DOMAIN_AGGREGATE_AND_PROOF*: DomainType
RestGenericError* = object
code*: uint64
message*: string
@ -140,36 +39,24 @@ type
message*: string
failures*: seq[RestAttestationsFailure]
DataEnclosedObject*[T] = object
data*: T
EncodeTypes* =
AttesterSlashing |
ProposerSlashing |
phase0.SignedBeaconBlock |
SignedVoluntaryExit
DataRootEnclosedObject*[T] = object
dependent_root*: Eth2Digest
data*: T
EncodeArrays* =
seq[ValidatorIndex] |
seq[Attestation] |
seq[SignedAggregateAndProof] |
seq[RestCommitteeSubscription]
DataRestBeaconGenesis* = DataEnclosedObject[RestBeaconGenesis]
DataRestFork* = DataEnclosedObject[Fork]
DataRestProposerDuties* = DataRootEnclosedObject[seq[RestProposerDuty]]
DataRestAttesterDuties* = DataRootEnclosedObject[seq[RestAttesterDuty]]
DataRestBeaconBlock* = DataEnclosedObject[phase0.BeaconBlock]
DataRestAttestationData* = DataEnclosedObject[AttestationData]
DataRestAttestation* = DataEnclosedObject[Attestation]
DataRestSyncInfo* = DataEnclosedObject[RestSyncInfo]
DataRestValidator* = DataEnclosedObject[RestValidator]
DataRestValidatorList* = DataEnclosedObject[seq[RestValidator]]
DataRestVersion* = DataEnclosedObject[RestVersion]
DataRestConfig* = DataEnclosedObject[RestConfig]
EncodeTypes* = phase0.SignedBeaconBlock
EncodeArrays* = seq[ValidatorIndex] | seq[Attestation] |
seq[SignedAggregateAndProof] | seq[RestCommitteeSubscription]
DecodeTypes* = DataRestBeaconGenesis | DataRestFork | DataRestProposerDuties |
DataRestAttesterDuties | DataRestBeaconBlock |
DataRestAttestationData | DataRestAttestation |
DataRestSyncInfo | DataRestValidator |
DataRestValidatorList | DataRestVersion |
DataRestConfig | RestGenericError | RestAttestationError
DecodeTypes* =
DataEnclosedObject |
DataMetaEnclosedObject |
DataRootEnclosedObject |
RestAttestationError |
RestGenericError
proc jsonResponseWRoot*(t: typedesc[RestApiResponse],
data: auto,
@ -568,6 +455,12 @@ proc writeValue*(writer: var JsonWriter[RestJson], value: GraffitiBytes) {.
raises: [IOError, Defect].} =
writeValue(writer, hexOriginal(distinctBase(value)))
proc parseRoot(value: string): Result[Eth2Digest, cstring] =
try:
ok(Eth2Digest(data: hexToByteArray[32](value)))
except ValueError:
err("Unable to decode root value")
proc decodeBody*[T](t: typedesc[T],
body: ContentBody): Result[T, cstring] =
if body.contentType != "application/json":
@ -620,12 +513,10 @@ proc decodeBytes*[T: DecodeTypes](t: typedesc[T], value: openarray[byte],
contentType: string): RestResult[T] =
case contentType
of "application/json":
let res =
try:
RestJson.decode(value, T)
except SerializationError:
return err("Serialization error")
ok(res)
try:
ok RestJson.decode(value, T)
except SerializationError as exc:
err("Serialization error")
else:
err("Content-Type not supported")
@ -667,3 +558,252 @@ proc encodeString*(value: StateIdent): RestResult[string] =
ok("finalized")
of StateIdentType.Justified:
ok("justified")
proc encodeString*(value: BlockIdent): RestResult[string] =
case value.kind
of BlockQueryKind.Slot:
ok(Base10.toString(uint64(value.slot)))
of BlockQueryKind.Root:
ok(hexOriginal(value.root.data))
of BlockQueryKind.Named:
case value.value
of BlockIdentType.Head:
ok("head")
of BlockIdentType.Genesis:
ok("genesis")
of BlockIdentType.Finalized:
ok("finalized")
proc decodeString*(t: typedesc[PeerStateKind],
value: string): Result[PeerStateKind, cstring] =
case value
of "disconnected":
ok(PeerStateKind.Disconnected)
of "connecting":
ok(PeerStateKind.Connecting)
of "connected":
ok(PeerStateKind.Connected)
of "disconnecting":
ok(PeerStateKind.Disconnecting)
else:
err("Incorrect peer's state value")
proc encodeString*(value: PeerStateKind): Result[string, cstring] =
case value
of PeerStateKind.Disconnected:
ok("disconnected")
of PeerStateKind.Connecting:
ok("connecting")
of PeerStateKind.Connected:
ok("connected")
of PeerStateKind.Disconnecting:
ok("disconnecting")
proc decodeString*(t: typedesc[PeerDirectKind],
value: string): Result[PeerDirectKind, cstring] =
case value
of "inbound":
ok(PeerDirectKind.Inbound)
of "outbound":
ok(PeerDirectKind.Outbound)
else:
err("Incorrect peer's direction value")
proc encodeString*(value: PeerDirectKind): Result[string, cstring] =
case value
of PeerDirectKind.Inbound:
ok("inbound")
of PeerDirectKind.Outbound:
ok("outbound")
proc encodeString*(peerid: PeerID): Result[string, cstring] =
ok($peerid)
proc decodeString*(t: typedesc[EventTopic],
value: string): Result[EventTopic, cstring] =
case value
of "head":
ok(EventTopic.Head)
of "block":
ok(EventTopic.Block)
of "attestation":
ok(EventTopic.Attestation)
of "voluntary_exit":
ok(EventTopic.VoluntaryExit)
of "finalized_checkpoint":
ok(EventTopic.FinalizedCheckpoint)
of "chain_reorg":
ok(EventTopic.ChainReorg)
else:
err("Incorrect event's topic value")
proc decodeString*(t: typedesc[ValidatorSig],
value: string): Result[ValidatorSig, cstring] =
if len(value) != ValidatorSigSize + 2:
return err("Incorrect validator signature value length")
if value[0] != '0' and value[1] != 'x':
return err("Incorrect validator signature encoding")
ValidatorSig.fromHex(value)
proc decodeString*(t: typedesc[GraffitiBytes],
value: string): Result[GraffitiBytes, cstring] =
try:
ok(GraffitiBytes.init(value))
except ValueError:
err("Unable to decode graffiti value")
proc decodeString*(t: typedesc[string],
value: string): Result[string, cstring] =
ok(value)
proc decodeString*(t: typedesc[Slot], value: string): Result[Slot, cstring] =
let res = ? Base10.decode(uint64, value)
ok(Slot(res))
proc decodeString*(t: typedesc[Epoch], value: string): Result[Epoch, cstring] =
let res = ? Base10.decode(uint64, value)
ok(Epoch(res))
proc decodeString*(t: typedesc[StateIdent],
value: string): Result[StateIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != RootHashSize + 2:
err("Incorrect state root value length")
else:
let res = ? parseRoot(value)
ok(StateIdent(kind: StateQueryKind.Root, root: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(StateIdent(kind: StateQueryKind.Slot, slot: Slot(res)))
else:
case value
of "head":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Head))
of "genesis":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Genesis))
of "finalized":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Finalized))
of "justified":
ok(StateIdent(kind: StateQueryKind.Named,
value: StateIdentType.Justified))
else:
err("Incorrect state identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(StateIdent(kind: StateQueryKind.Slot, slot: Slot(res)))
proc decodeString*(t: typedesc[BlockIdent],
value: string): Result[BlockIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != RootHashSize + 2:
err("Incorrect block root value length")
else:
let res = ? parseRoot(value)
ok(BlockIdent(kind: BlockQueryKind.Root, root: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(BlockIdent(kind: BlockQueryKind.Slot, slot: Slot(res)))
else:
case value
of "head":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Head))
of "genesis":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Genesis))
of "finalized":
ok(BlockIdent(kind: BlockQueryKind.Named,
value: BlockIdentType.Finalized))
else:
err("Incorrect block identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(BlockIdent(kind: BlockQueryKind.Slot, slot: Slot(res)))
proc decodeString*(t: typedesc[ValidatorIdent],
value: string): Result[ValidatorIdent, cstring] =
if len(value) > 2:
if (value[0] == '0') and (value[1] == 'x'):
if len(value) != ValidatorKeySize + 2:
err("Incorrect validator's key value length")
else:
let res = ? ValidatorPubKey.fromHex(value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Key,
key: res))
elif (value[0] in DecimalSet) and (value[1] in DecimalSet):
let res = ? Base10.decode(uint64, value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Index,
index: RestValidatorIndex(res)))
else:
err("Incorrect validator identifier value")
else:
let res = ? Base10.decode(uint64, value)
ok(ValidatorIdent(kind: ValidatorQueryKind.Index,
index: RestValidatorIndex(res)))
proc decodeString*(t: typedesc[PeerID],
value: string): Result[PeerID, cstring] =
PeerID.init(value)
proc decodeString*(t: typedesc[CommitteeIndex],
value: string): Result[CommitteeIndex, cstring] =
let res = ? Base10.decode(uint64, value)
ok(CommitteeIndex(res))
proc decodeString*(t: typedesc[Eth2Digest],
value: string): Result[Eth2Digest, cstring] =
if len(value) != RootHashSize + 2:
return err("Incorrect root value length")
if value[0] != '0' and value[1] != 'x':
return err("Incorrect root value encoding")
parseRoot(value)
proc decodeString*(t: typedesc[ValidatorFilter],
value: string): Result[ValidatorFilter, cstring] =
case value
of "pending_initialized":
ok({ValidatorFilterKind.PendingInitialized})
of "pending_queued":
ok({ValidatorFilterKind.PendingQueued})
of "active_ongoing":
ok({ValidatorFilterKind.ActiveOngoing})
of "active_exiting":
ok({ValidatorFilterKind.ActiveExiting})
of "active_slashed":
ok({ValidatorFilterKind.ActiveSlashed})
of "exited_unslashed":
ok({ValidatorFilterKind.ExitedUnslashed})
of "exited_slashed":
ok({ValidatorFilterKind.ExitedSlashed})
of "withdrawal_possible":
ok({ValidatorFilterKind.WithdrawalPossible})
of "withdrawal_done":
ok({ValidatorFilterKind.WithdrawalDone})
of "pending":
ok({
ValidatorFilterKind.PendingInitialized,
ValidatorFilterKind.PendingQueued
})
of "active":
ok({
ValidatorFilterKind.ActiveOngoing,
ValidatorFilterKind.ActiveExiting,
ValidatorFilterKind.ActiveSlashed
})
of "exited":
ok({
ValidatorFilterKind.ExitedUnslashed,
ValidatorFilterKind.ExitedSlashed
})
of "withdrawal":
ok({
ValidatorFilterKind.WithdrawalPossible,
ValidatorFilterKind.WithdrawalDone
})
else:
err("Incorrect validator state identifier value")

View File

@ -1,11 +0,0 @@
import
options,
callsigs_types
proc get_v1_node_identity(): NodeIdentityTuple
proc get_v1_node_version(): JsonNode
proc get_v1_node_syncing(): SyncInfo
proc get_v1_node_health(): JsonNode
proc get_v1_node_peers(state: Option[seq[string]],
direction: Option[seq[string]]): seq[NodePeerTuple]

View File

@ -0,0 +1,155 @@
# Copyright (c) 2018-2021 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.
{.push raises: [Defect].}
import
presto/client,
../datatypes/[phase0, altair],
"."/[rest_types, eth2_rest_serialization]
export client, rest_types, eth2_rest_serialization
proc getGenesis*(): RestResponse[GetGenesisResponse] {.
rest, endpoint: "/eth/v1/beacon/genesis",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getGenesis
proc getStateRoot*(state_id: StateIdent): RestResponse[GetStateRootResponse] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/root",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateRoot
proc getStateFork*(state_id: StateIdent): RestResponse[GetStateForkResponse] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/fork",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateFork
proc getStateFinalityCheckpoints*(state_id: StateIdent
): RestResponse[GetStateFinalityCheckpointsResponse] {.
rest, endpoint: "/api/eth/v1/beacon/states/{state_id}/finality_checkpoints",
meth: MethodGet.}
proc getStateValidators*(state_id: StateIdent,
id: seq[ValidatorIdent]
): RestResponse[GetStateValidatorsResponse] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/validators",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateValidators
proc getStateValidator*(state_id: StateIdent,
validator_id: ValidatorIdent
): RestResponse[GetStateValidatorResponse] {.
rest,
endpoint: "/eth/v1/beacon/states/{state_id}/validators/{validator_id}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateValidator
proc getStateValidatorBalances*(state_id: StateIdent
): RestResponse[GetStateValidatorBalancesResponse] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/validator_balances",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getStateValidators
proc getEpochCommittees*(state_id: StateIdent
): RestResponse[GetEpochCommitteesResponse] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/committees",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getEpochCommittees
# TODO altair
# proc getEpochSyncCommittees*(state_id: StateIdent
# ): RestResponse[GetEpochSyncCommitteesResponse] {.
# rest, endpoint: "/eth/v1/beacon/states/{state_id}/sync_committees",
# meth: MethodGet.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getEpochSyncCommittees
proc getBlockHeaders*(slot: Option[Slot], parent_root: Option[Eth2Digest]
): RestResponse[GetBlockHeadersResponse] {.
rest, endpoint: "/api/eth/v1/beacon/headers",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getBlockHeaders
proc getBlockHeader*(block_id: BlockIdent): RestResponse[GetBlockHeaderResponse] {.
rest, endpoint: "/api/eth/v1/beacon/headers/{block_id}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getBlockHeader
proc publishBlock*(body: phase0.SignedBeaconBlock): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/blocks",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/publishBlock
proc getBlock*(block_id: BlockIdent): RestResponse[GetBlockResponse] {.
rest, endpoint: "/api/eth/v1/beacon/blocks/{block_id}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getBlock
# TODO altair
# proc getBlockV2*(block_id: BlockIdent): RestResponse[GetBlockV2Response] {.
# rest, endpoint: "/api/eth/v2/beacon/blocks/{block_id}",
# meth: MethodGet.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getBlockV2
proc getBlockRoot*(block_id: BlockIdent): RestResponse[GetBlockRootResponse] {.
rest, endpoint: "/eth/v1/beacon/blocks/{block_id}/root",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getBlockRoot
proc getBlockAttestations*(block_id: BlockIdent
): RestResponse[GetBlockAttestationsResponse] {.
rest, endpoint: "/eth/v1/beacon/blocks/{block_id}/attestations",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getBlockAttestations
proc getPoolAttestations*(
slot: Option[Slot],
committee_index: Option[CommitteeIndex]
): RestResponse[GetPoolAttestationsResponse] {.
rest, endpoint: "/api/eth/v1/beacon/pool/attestations",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getPoolAttestations
proc submitPoolAttestations*(body: seq[Attestation]): RestPlainResponse {.
rest, endpoint: "/eth/v1/beacon/pool/attestations",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/submitPoolAttestations
proc getPoolAttesterSlashings*(): RestResponse[GetPoolAttesterSlashingsResponse] {.
rest, endpoint: "/api/eth/v1/beacon/pool/attester_slashings",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getPoolAttesterSlashings
proc submitPoolAttesterSlashings*(body: AttesterSlashing): RestPlainResponse {.
rest, endpoint: "/api/eth/v1/beacon/pool/attester_slashings",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/submitPoolAttesterSlashings
proc getPoolProposerSlashings*(): RestResponse[GetPoolProposerSlashingsResponse] {.
rest, endpoint: "/api/eth/v1/beacon/pool/proposer_slashings",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getPoolProposerSlashings
proc submitPoolProposerSlashings*(body: ProposerSlashing): RestPlainResponse {.
rest, endpoint: "/api/eth/v1/beacon/pool/proposer_slashings",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/submitPoolProposerSlashings
# TODO Altair
# proc submitPoolSyncCommitteeSignatures*(body: seq[RestSyncCommitteeSignature]): RestPlainResponse {.
# rest, endpoint: "/eth/v1/beacon/pool/sync_committees",
# meth: MethodPost.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Beacon/submitPoolSyncCommitteeSignatures
proc getPoolVoluntaryExits*(): RestResponse[GetPoolVoluntaryExitsResponse] {.
rest, endpoint: "/api/eth/v1/beacon/pool/voluntary_exits",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getPoolVoluntaryExits
proc submitPoolVoluntaryExit*(body: SignedVoluntaryExit): RestPlainResponse {.
rest, endpoint: "/api/eth/v1/beacon/pool/voluntary_exits",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/submitPoolVoluntaryExit

View File

@ -0,0 +1,19 @@
# Copyright (c) 2018-2021 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.
{.push raises: [Defect].}
import
presto/client,
"."/[
rest_beacon_calls, rest_config_calls, rest_debug_calls,
rest_node_calls, rest_validator_calls
]
export
client,
rest_beacon_calls, rest_config_calls, rest_debug_calls,
rest_node_calls, rest_validator_calls

View File

@ -0,0 +1,25 @@
# Copyright (c) 2018-2021 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.
{.push raises: [Defect].}
import
presto/client,
"."/[rest_types, eth2_rest_serialization]
export client, rest_types, eth2_rest_serialization
proc getForkSchedule*(): RestResponse[GetForkScheduleResponse] {.
rest, endpoint: "/eth/v1/config/fork_schedule", meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Config/getForkSchedule
proc getSpec*(): RestResponse[GetSpecResponse] {.
rest, endpoint: "/eth/v1/config/spec", meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Config/getSpec
proc getDepositContract*(): RestResponse[GetDepositContractResponse] {.
rest, endpoint: "/eth/v1/config/deposit_contract", meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Config/getDepositContract

View File

@ -0,0 +1,29 @@
# Copyright (c) 2018-2021 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.
{.push raises: [Defect].}
import
presto/client,
"."/[rest_types, eth2_rest_serialization]
export client, rest_types, eth2_rest_serialization
proc getState*(state_id: StateIdent): RestResponse[GetStateResponse] {.
rest, endpoint: "/eth/v1/debug/beacon/states/{state_id}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getState
# TODO altair
# proc getStateV2*(state_id: StateIdent): RestResponse[GetStateV2Response] {.
# rest, endpoint: "/eth/v2/debug/beacon/states/{state_id}",
# meth: MethodGet.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getState
proc getDebugChainHeads*(): RestResponse[GetDebugChainHeadsResponse] {.
rest, endpoint: "/eth/v1/debug/beacon/heads",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Beacon/getDebugChainHeads

View File

@ -0,0 +1,50 @@
# Copyright (c) 2018-2021 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.
{.push raises: [Defect].}
import
presto/client,
"."/[rest_types, eth2_rest_serialization]
export client, rest_types, eth2_rest_serialization
proc getNetworkIdentity*(): RestResponse[GetNetworkIdentityResponse] {.
rest, endpoint: "/eth/v1/node/identity",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getNetworkIdentity
proc getPeers*(
state: seq[PeerStateKind],
direction: seq[PeerDirectKind]): RestResponse[GetPeersResponse] {.
rest, endpoint: "/eth/v1/node/peers",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getPeers
proc getPeer*(peer_id: PeerId): RestResponse[GetPeerResponse] {.
rest, endpoint: "/eth/v1/node/peers/{peer_id}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getPeer
proc getPeerCount*(): RestResponse[GetPeerCountResponse] {.
rest, endpoint: "/eth/v1/node/peer_count",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getPeerCount
proc getNodeVersion*(): RestResponse[GetVersionResponse] {.
rest, endpoint: "/eth/v1/node/version",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getNodeVersion
proc getSyncingStatus*(): RestResponse[GetSyncingStatusResponse] {.
rest, endpoint: "/eth/v1/node/syncing",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getSyncingStatus
proc getHealth*(): RestPlainResponse {.
rest, endpoint: "/eth/v1/node/health",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Node/getHealth

View File

@ -0,0 +1,327 @@
# beacon_chain
# Copyright (c) 2018-2021 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.
# Types used by both client and server in the common REST API:
# https://ethereum.github.io/eth2.0-APIs/#/
# Be mindful that changing these changes the serialization and deserialization
# in the API which may lead to incompatibilities between clients - tread
# carefully!
{.push raises: [Defect].}
import
std/json,
".."/datatypes/[phase0, altair],
".."/[crypto, digest]
export phase0, altair, crypto, digest
const
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validator_balances.yaml#L17
# https://github.com/ethereum/eth2.0-APIs/blob/master/apis/beacon/states/validators.yaml#L17
MaximumValidatorIds* = 30
type
EventTopic* {.pure.} = enum
Head, Block, Attestation, VoluntaryExit, FinalizedCheckpoint, ChainReorg
EventTopics* = set[EventTopic]
RestValidatorIndex* = distinct uint64
ValidatorQueryKind* {.pure.} = enum
Index, Key
ValidatorIdent* = object
case kind*: ValidatorQueryKind
of ValidatorQueryKind.Index:
index*: RestValidatorIndex
of ValidatorQueryKind.Key:
key*: ValidatorPubKey
ValidatorFilterKind* {.pure.} = enum
PendingInitialized, PendingQueued,
ActiveOngoing, ActiveExiting, ActiveSlashed,
ExitedUnslashed, ExitedSlashed,
WithdrawalPossible, WithdrawalDone
ValidatorFilter* = set[ValidatorFilterKind]
StateQueryKind* {.pure.} = enum
Slot, Root, Named
StateIdentType* {.pure.} = enum
Head, Genesis, Finalized, Justified
StateIdent* = object
case kind*: StateQueryKind
of StateQueryKind.Slot:
slot*: Slot
of StateQueryKind.Root:
root*: Eth2Digest
of StateQueryKind.Named:
value*: StateIdentType
BlockQueryKind* {.pure.} = enum
Slot, Root, Named
BlockIdentType* {.pure.} = enum
Head, Genesis, Finalized
BlockIdent* = object
case kind*: BlockQueryKind
of BlockQueryKind.Slot:
slot*: Slot
of BlockQueryKind.Root:
root*: Eth2Digest
of BlockQueryKind.Named:
value*: BlockIdentType
PeerStateKind* {.pure.} = enum
Disconnected, Connecting, Connected, Disconnecting
PeerDirectKind* {.pure.} = enum
Inbound, Outbound
RestAttesterDuty* = object
pubkey*: ValidatorPubKey
validator_index*: ValidatorIndex
committee_index*: CommitteeIndex
committee_length*: uint64
committees_at_slot*: uint64
validator_committee_index*: ValidatorIndex
slot*: Slot
RestProposerDuty* = object
pubkey*: ValidatorPubKey
validator_index*: ValidatorIndex
slot*: Slot
RestCommitteeSubscription* = object
validator_index*: ValidatorIndex
committee_index*: CommitteeIndex
committees_at_slot*: uint64
slot*: Slot
is_aggregator*: bool
RestBeaconStatesFinalityCheckpoints* = object
previous_justified*: Checkpoint
current_justified*: Checkpoint
finalized*: Checkpoint
RestGenesis* = object
genesis_time*: uint64
genesis_validators_root*: Eth2Digest
genesis_fork_version*: Version
RestValidatorBalance* = object
index*: ValidatorIndex
balance*: string
RestBeaconStatesCommittees* = object
index*: CommitteeIndex
slot*: Slot
validators*: seq[ValidatorIndex]
RestAttestationsFailure* = object
index*: uint64
message*: string
RestValidator* = object
index*: ValidatorIndex
balance*: string
status*: string
validator*: Validator
RestBlockHeader* = object
slot*: Slot
proposer_index*: ValidatorIndex
parent_root*: Eth2Digest
state_root*: Eth2Digest
body_root*: Eth2Digest
RestSignedBlockHeader* = object
message*: RestBlockHeader
signature*: ValidatorSig
RestBlockHeaderInfo* = object
root*: Eth2Digest
canonical*: bool
header*: RestSignedBlockHeader
RestNodePeer* = object
peer_id*: string
enr*: string
last_seen_p2p_address*: string
state*: string
direction*: string
agent*: string # This is not part of specification
proto*: string # This is not part of specification
RestNodeVersion* = object
version*: string
RestSyncInfo* = object
head_slot*: Slot
sync_distance*: uint64
is_syncing*: bool
RestPeerCount* = object
disconnected*: uint64
connecting*: uint64
connected*: uint64
disconnecting*: uint64
RestChainHead* = object
root*: Eth2Digest
slot*: Slot
RestMetadata* = object
seq_number*: string
attnets*: string
RestNetworkIdentity* = object
peer_id*: string
enr*: string
p2p_addresses*: seq[string]
discovery_addresses*: seq[string]
metadata*: RestMetadata
RestSpec* = object
CONFIG_NAME*: string
MAX_COMMITTEES_PER_SLOT*: uint64
TARGET_COMMITTEE_SIZE*: uint64
MAX_VALIDATORS_PER_COMMITTEE*: uint64
MIN_PER_EPOCH_CHURN_LIMIT*: uint64
CHURN_LIMIT_QUOTIENT*: uint64
SHUFFLE_ROUND_COUNT*: uint64
MIN_GENESIS_ACTIVE_VALIDATOR_COUNT*: uint64
MIN_GENESIS_TIME*: uint64
HYSTERESIS_QUOTIENT*: uint64
HYSTERESIS_DOWNWARD_MULTIPLIER*: uint64
HYSTERESIS_UPWARD_MULTIPLIER*: uint64
SAFE_SLOTS_TO_UPDATE_JUSTIFIED*: uint64
ETH1_FOLLOW_DISTANCE*: uint64
TARGET_AGGREGATORS_PER_COMMITTEE*: uint64
RANDOM_SUBNETS_PER_VALIDATOR*: uint64
EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION*: uint64
SECONDS_PER_ETH1_BLOCK*: uint64
DEPOSIT_CHAIN_ID*: uint64
DEPOSIT_NETWORK_ID*: uint64
DEPOSIT_CONTRACT_ADDRESS*: Eth1Address
MIN_DEPOSIT_AMOUNT*: uint64
MAX_EFFECTIVE_BALANCE*: uint64
EJECTION_BALANCE*: uint64
EFFECTIVE_BALANCE_INCREMENT*: uint64
GENESIS_FORK_VERSION*: Version
BLS_WITHDRAWAL_PREFIX*: byte
GENESIS_DELAY*: uint64
SECONDS_PER_SLOT*: uint64
MIN_ATTESTATION_INCLUSION_DELAY*: uint64
SLOTS_PER_EPOCH*: uint64
MIN_SEED_LOOKAHEAD*: uint64
MAX_SEED_LOOKAHEAD*: uint64
EPOCHS_PER_ETH1_VOTING_PERIOD*: uint64
SLOTS_PER_HISTORICAL_ROOT*: uint64
MIN_VALIDATOR_WITHDRAWABILITY_DELAY*: uint64
SHARD_COMMITTEE_PERIOD*: uint64
MIN_EPOCHS_TO_INACTIVITY_PENALTY*: uint64
EPOCHS_PER_HISTORICAL_VECTOR*: uint64
EPOCHS_PER_SLASHINGS_VECTOR*: uint64
HISTORICAL_ROOTS_LIMIT*: uint64
VALIDATOR_REGISTRY_LIMIT*: uint64
BASE_REWARD_FACTOR*: uint64
WHISTLEBLOWER_REWARD_QUOTIENT*: uint64
PROPOSER_REWARD_QUOTIENT*: uint64
INACTIVITY_PENALTY_QUOTIENT*: uint64
MIN_SLASHING_PENALTY_QUOTIENT*: uint64
PROPORTIONAL_SLASHING_MULTIPLIER*: uint64
MAX_PROPOSER_SLASHINGS*: uint64
MAX_ATTESTER_SLASHINGS*: uint64
MAX_ATTESTATIONS*: uint64
MAX_DEPOSITS*: uint64
MAX_VOLUNTARY_EXITS*: uint64
DOMAIN_BEACON_PROPOSER*: DomainType
DOMAIN_BEACON_ATTESTER*: DomainType
DOMAIN_RANDAO*: DomainType
DOMAIN_DEPOSIT*: DomainType
DOMAIN_VOLUNTARY_EXIT*: DomainType
DOMAIN_SELECTION_PROOF*: DomainType
DOMAIN_AGGREGATE_AND_PROOF*: DomainType
RestDepositContract* = object
chain_id*: string
address*: string
DataEnclosedObject*[T] = object
data*: T
DataMetaEnclosedObject*[T] = object
data*: T
meta*: JsonNode
DataRootEnclosedObject*[T] = object
dependent_root*: Eth2Digest
data*: T
# Types based on the OAPI yaml file - used in responses to requests
GetAggregatedAttestationResponse* = DataEnclosedObject[Attestation]
GetAttesterDutiesResponse* = DataRootEnclosedObject[seq[RestAttesterDuty]]
GetBlockAttestationsResponse* = DataEnclosedObject[seq[Attestation]]
GetBlockHeaderResponse* = DataEnclosedObject[RestBlockHeaderInfo]
GetBlockHeadersResponse* = DataEnclosedObject[seq[RestBlockHeaderInfo]]
GetBlockResponse* = DataEnclosedObject[phase0.SignedBeaconBlock]
GetBlockRootResponse* = DataEnclosedObject[Eth2Digest]
GetDebugChainHeadsResponse* = DataEnclosedObject[seq[RestChainHead]]
GetDepositContractResponse* = DataEnclosedObject[RestDepositContract]
GetEpochCommitteesResponse* = DataEnclosedObject[RestGenesis]
GetForkScheduleResponse* = DataEnclosedObject[Fork]
GetGenesisResponse* = DataEnclosedObject[RestGenesis]
GetNetworkIdentityResponse* = DataEnclosedObject[RestNetworkIdentity]
GetPeerCountResponse* = DataMetaEnclosedObject[RestPeerCount]
GetPeerResponse* = DataMetaEnclosedObject[RestNodePeer]
GetPeersResponse* = DataMetaEnclosedObject[seq[RestNodePeer]]
GetPoolAttestationsResponse* = DataEnclosedObject[seq[Attestation]]
GetPoolAttesterSlashingsResponse* = DataEnclosedObject[seq[AttesterSlashing]]
GetPoolProposerSlashingsResponse* = DataEnclosedObject[seq[ProposerSlashing]]
GetPoolVoluntaryExitsResponse* = DataEnclosedObject[seq[SignedVoluntaryExit]]
GetProposerDutiesResponse* = DataRootEnclosedObject[seq[RestProposerDuty]]
GetSpecResponse* = DataEnclosedObject[RestSpec]
GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints]
GetStateForkResponse* = DataEnclosedObject[Fork]
GetStateResponse* = DataEnclosedObject[phase0.BeaconState]
GetStateRootResponse* = DataEnclosedObject[Eth2Digest]
GetStateValidatorBalancesResponse* = DataEnclosedObject[seq[RestValidatorBalance]]
GetStateValidatorResponse* = DataEnclosedObject[RestValidator]
GetStateValidatorsResponse* = DataEnclosedObject[seq[RestValidator]]
GetSyncingStatusResponse* = DataEnclosedObject[RestSyncInfo]
GetVersionResponse* = DataEnclosedObject[RestNodeVersion]
ProduceAttestationDataResponse* = DataEnclosedObject[AttestationData]
ProduceBlockResponse* = DataEnclosedObject[phase0.BeaconBlock]
func init*(t: typedesc[StateIdent], v: StateIdentType): StateIdent =
StateIdent(kind: StateQueryKind.Named, value: v)
func init*(t: typedesc[StateIdent], v: Slot): StateIdent =
StateIdent(kind: StateQueryKind.Slot, slot: v)
func init*(t: typedesc[StateIdent], v: Eth2Digest): StateIdent =
StateIdent(kind: StateQueryKind.Root, root: v)
func init*(t: typedesc[BlockIdent], v: BlockIdentType): BlockIdent =
BlockIdent(kind: BlockQueryKind.Named, value: v)
func init*(t: typedesc[BlockIdent], v: Slot): BlockIdent =
BlockIdent(kind: BlockQueryKind.Slot, slot: v)
func init*(t: typedesc[BlockIdent], v: Eth2Digest): BlockIdent =
BlockIdent(kind: BlockQueryKind.Root, root: v)
func init*(t: typedesc[ValidatorIdent], v: ValidatorIndex): ValidatorIdent =
ValidatorIdent(kind: ValidatorQueryKind.Index, index: RestValidatorIndex(v))
func init*(t: typedesc[ValidatorIdent], v: ValidatorPubKey): ValidatorIdent =
ValidatorIdent(kind: ValidatorQueryKind.Key, key: v)

View File

@ -0,0 +1,89 @@
# Copyright (c) 2018-2021 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.
{.push raises: [Defect].}
import
presto/client,
"."/[rest_types, eth2_rest_serialization]
export client, rest_types, eth2_rest_serialization
proc getAttesterDuties*(epoch: Epoch,
body: seq[ValidatorIndex]
): RestResponse[GetAttesterDutiesResponse] {.
rest, endpoint: "/eth/v1/validator/duties/attester/{epoch}",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/getAttesterDuties
proc getProposerDuties*(epoch: Epoch): RestResponse[GetProposerDutiesResponse] {.
rest, endpoint: "/eth/v1/validator/duties/proposer/{epoch}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/getProposerDuties
# TODO altair
# proc getSyncCommitteeDuties*(epoch: Epoch): RestResponse[DataRestSyncCommitteeDuties] {.
# rest, endpoint: "/eth/v1/validator/duties/sync/{epoch}",
# meth: MethodPost.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Validator/getSyncCommitteeDuties
proc produceBlock*(slot: Slot, randao_reveal: ValidatorSig,
graffiti: GraffitiBytes
): RestResponse[ProduceBlockResponse] {.
rest, endpoint: "/eth/v1/validator/blocks/{slot}",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/produceBlock
# TODO altair
# proc produceBlockV2*(slot: Slot, randao_reveal: ValidatorSig,
# graffiti: GraffitiBytes
# ): RestResponse[DataRestBlockV2] {.
# rest, endpoint: "/eth/v2/validator/blocks/{slot}",
# meth: MethodGet.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Validator/produceBlockV2
proc produceAttestationData*(slot: Slot,
committee_index: CommitteeIndex
): RestResponse[ProduceAttestationDataResponse] {.
rest, endpoint: "/eth/v1/validator/attestation_data",
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/produceAttestationData
proc getAggregatedAttestation*(attestation_data_root: Eth2Digest,
slot: Slot): RestResponse[GetAggregatedAttestationResponse] {.
rest, endpoint: "/eth/v1/validator/aggregate_attestation"
meth: MethodGet.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/getAggregatedAttestation
proc publishAggregateAndProofs*(body: seq[SignedAggregateAndProof]
): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/aggregate_and_proofs",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/publishAggregateAndProofs
proc prepareBeaconCommitteeSubnet*(body: seq[RestCommitteeSubscription]): RestPlainResponse {.
rest, endpoint: "/eth/v1/validator/beacon_committee_subscriptions",
meth: MethodPost.}
## https://ethereum.github.io/eth2.0-APIs/#/Validator/prepareBeaconCommitteeSubnet
# TODO altair
# proc prepareSyncCommitteeSubnets*(body: seq[int]
# ): RestPlainResponse {.
# rest, endpoint: "/eth/v1/validator/sync_committee_subscriptions",
# meth: MethodPost.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Validator/prepareSyncCommitteeSubnets
# proc produceSyncCommitteeContribution*(body: seq[int]
# ): RestPlainResponse {.
# rest, endpoint: "/eth/v1/validator/sync_committee_contribution",
# meth: MethodPost.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Validator/produceSyncCommitteeContribution
# proc publishContributionAndProofs*(body: seq[RestCommitteeSubscription]
# ): RestPlainResponse {.
# rest, endpoint: "/eth/v1/validator/contribution_and_proofs",
# meth: MethodPost.}
# ## https://ethereum.github.io/eth2.0-APIs/#/Validator/publishContributionAndProofs

View File

@ -1,8 +1,8 @@
import
options,
callsigs_types
rpc_types
proc get_v1_beacon_genesis(): BeaconGenesisTuple
proc get_v1_beacon_genesis(): RpcBeaconGenesis
# TODO stateId is part of the REST path
proc get_v1_beacon_states_root(stateId: string): Eth2Digest
@ -12,22 +12,22 @@ proc get_v1_beacon_states_fork(stateId: string): Fork
# TODO stateId is part of the REST path
proc get_v1_beacon_states_finality_checkpoints(
stateId: string): BeaconStatesFinalityCheckpointsTuple
stateId: string): RpcBeaconStatesFinalityCheckpoints
# TODO stateId is part of the REST path
proc get_v1_beacon_states_stateId_validators(
stateId: string, validatorIds: seq[string],
status: string): seq[BeaconStatesValidatorsTuple]
status: string): seq[RpcBeaconStatesValidators]
# TODO stateId and validatorId are part of the REST path
proc get_v1_beacon_states_stateId_validators_validatorId(
stateId: string, validatorId: string): BeaconStatesValidatorsTuple
stateId: string, validatorId: string): RpcBeaconStatesValidators
# TODO stateId and epoch are part of the REST path
proc get_v1_beacon_states_stateId_committees_epoch(stateId: string,
epoch: uint64, index: uint64, slot: uint64): seq[BeaconStatesCommitteesTuple]
epoch: uint64, index: uint64, slot: uint64): seq[RpcBeaconStatesCommittees]
proc get_v1_beacon_headers(slot: uint64, parent_root: Eth2Digest): seq[BeaconHeadersTuple]
proc get_v1_beacon_headers(slot: uint64, parent_root: Eth2Digest): seq[RpcBeaconHeaders]
# TODO blockId is part of the REST path
proc get_v1_beacon_headers_blockId(blockId: string):
@ -45,7 +45,7 @@ proc get_v1_beacon_blocks_blockId_attestations(blockId: string): seq[Attestation
# TODO POST /v1/beacon/pool/attester_slashings
# TODO POST /v1/beacon/pool/proposer_slashings
# TODO POST /v1/beacon/pool/attestations
proc get_v1_beacon_pool_attestations(slot: Option[uint64], committee_index: Option[uint64]): seq[AttestationTuple]
proc get_v1_beacon_pool_attestations(slot: Option[uint64], committee_index: Option[uint64]): seq[RpcAttestation]
proc post_v1_beacon_pool_attestations(attestation: Attestation): bool
proc get_v1_beacon_pool_attester_slashings(): seq[AttesterSlashing]

View File

@ -0,0 +1,15 @@
import
std/os,
json_rpc/rpcclient,
"."/[rpc_types, eth2_json_rpc_serialization]
export
rpcclient,
rpc_types,
eth2_json_rpc_serialization
createRpcSigs(RpcClient, currentSourcePath.parentDir / "rpc_beacon_calls.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "rpc_debug_calls.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "rpc_nimbus_calls.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "rpc_node_calls.nim")
createRpcSigs(RpcClient, currentSourcePath.parentDir / "rpc_validator_calls.nim")

View File

@ -1,7 +1,7 @@
import
callsigs_types
rpc_types
export callsigs_types
export rpc_types
proc get_v1_debug_beacon_states_stateId(stateId: string): BeaconState
proc get_v1_debug_beacon_heads(): seq[tuple[root: Eth2Digest, slot: Slot]]

View File

@ -1,7 +1,7 @@
import
callsigs_types
rpc_types
export callsigs_types
export rpc_types
proc getBeaconHead(): Slot
proc getChainHead(): JsonNode

View File

@ -0,0 +1,11 @@
import
options,
rpc_types
proc get_v1_node_identity(): RpcNodeIdentity
proc get_v1_node_version(): JsonNode
proc get_v1_node_syncing(): RpcSyncInfo
proc get_v1_node_health(): JsonNode
proc get_v1_node_peers(state: Option[seq[string]],
direction: Option[seq[string]]): seq[RpcNodePeer]

View File

@ -1,3 +1,15 @@
# beacon_chain
# Copyright (c) 2018-2021 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.
# Types used in the JSON-RPC (legacy) API - these are generally derived from
# the common REST API, https://ethereum.github.io/eth2.0-APIs/#/
{.push raises: [Defect].}
import
".."/datatypes/base,
".."/[digest, crypto]
@ -5,7 +17,7 @@ import
export base, crypto, digest
type
AttesterDuties* = tuple
RpcAttesterDuties* = tuple
public_key: ValidatorPubKey
validator_index: ValidatorIndex
committee_index: CommitteeIndex
@ -13,45 +25,45 @@ type
validator_committee_index: uint64
slot: Slot
ValidatorDutiesTuple* = tuple
RpcValidatorDuties* = tuple
public_key: ValidatorPubKey
validator_index: ValidatorIndex
slot: Slot
BeaconGenesisTuple* = tuple
RpcBeaconGenesis* = tuple
genesis_time: uint64
genesis_validators_root: Eth2Digest
genesis_fork_version: Version
BeaconStatesFinalityCheckpointsTuple* = tuple
RpcBeaconStatesFinalityCheckpoints* = tuple
previous_justified: Checkpoint
current_justified: Checkpoint
finalized: Checkpoint
BeaconStatesValidatorsTuple* = tuple
RpcBeaconStatesValidators* = tuple
validator: Validator
index: uint64
status: string
balance: uint64
BeaconStatesCommitteesTuple* = tuple
RpcBeaconStatesCommittees* = tuple
index: uint64
slot: uint64
validators: seq[uint64] # each object in the sequence should have an index field...
BeaconHeadersTuple* = tuple
RpcBeaconHeaders* = tuple
root: Eth2Digest
canonical: bool
header: SignedBeaconBlockHeader
NodeIdentityTuple* = tuple
RpcNodeIdentity* = tuple
peer_id: string
enr: string
p2p_addresses: seq[string]
discovery_addresses: seq[string]
metadata: tuple[seq_number: uint64, attnets: string]
NodePeerTuple* = tuple
RpcNodePeer* = tuple
peer_id: string
enr: string
last_seen_p2p_address: string
@ -60,22 +72,22 @@ type
agent: string # This is not part of specification
proto: string # This is not part of specification
NodePeerCountTuple* = tuple
RpcNodePeerCount* = tuple
disconnected: int
connecting: int
connected: int
disconnecting: int
AttestationTuple* = tuple
RpcAttestation* = tuple
aggregation_bits: string
data: AttestationData
signature: ValidatorSig
BalanceTuple* = tuple
RpcBalance* = tuple
index: uint64
balance: uint64
SyncInfo* = tuple
RpcSyncInfo* = tuple
head_slot: Slot
sync_distance: uint64
is_syncing: bool

View File

@ -1,6 +1,6 @@
import
options,
callsigs_types
rpc_types
# calls that return a bool are actually without a return type in the main REST API
# spec but nim-json-rpc requires that all RPC calls have a return type.
@ -16,10 +16,10 @@ proc get_v1_validator_aggregate_attestation(slot: Slot, attestation_data_root: E
proc post_v1_validator_aggregate_and_proofs(payload: SignedAggregateAndProof): bool
# TODO epoch is part of the REST path
proc get_v1_validator_duties_attester(epoch: Epoch, public_keys: seq[ValidatorPubKey]): seq[AttesterDuties]
proc get_v1_validator_duties_attester(epoch: Epoch, public_keys: seq[ValidatorPubKey]): seq[RpcAttesterDuties]
# TODO epoch is part of the REST path
proc get_v1_validator_duties_proposer(epoch: Epoch): seq[ValidatorDutiesTuple]
proc get_v1_validator_duties_proposer(epoch: Epoch): seq[RpcValidatorDuties]
proc post_v1_validator_beacon_committee_subscriptions(committee_index: CommitteeIndex,
slot: Slot,

View File

@ -10,7 +10,7 @@
import chronicles
import options, deques, heapqueue, tables, strutils, sequtils, math, algorithm
import stew/results, chronos, chronicles
import ../spec/[datatypes/phase0, datatypes/altair, digest, helpers, eth2_apis/callsigs_types, forkedbeaconstate_helpers],
import ../spec/[datatypes/phase0, datatypes/altair, digest, helpers, eth2_apis/rpc_types, forkedbeaconstate_helpers],
../networking/[peer_pool, eth2_network]
import ../gossip_processing/block_processor
@ -1200,7 +1200,7 @@ proc start*[A, B](man: SyncManager[A, B]) =
## Starts SyncManager's main loop.
man.syncFut = man.syncLoop()
proc getInfo*[A, B](man: SyncManager[A, B]): SyncInfo =
proc getInfo*[A, B](man: SyncManager[A, B]): RpcSyncInfo =
## Returns current synchronization information for RPC call.
let wallSlot = man.getLocalWallSlot()
let headSlot = man.getLocalHeadSlot()

View File

@ -1,4 +1,6 @@
import common
import
../spec/datatypes/[phase0, altair],
common
type
ApiResponse*[T] = Result[T, string]
@ -11,7 +13,7 @@ proc checkCompatible*(vc: ValidatorClientRef,
let info =
try:
debug "Requesting beacon node network configuration"
let res = await node.client.getConfig()
let res = await node.client.getSpec()
res.data.data
except CancelledError as exc:
error "Configuration request was interrupted"
@ -31,7 +33,7 @@ proc checkCompatible*(vc: ValidatorClientRef,
let genesis =
try:
debug "Requesting beacon node genesis information"
let res = await node.client.getBeaconGenesis()
let res = await node.client.getGenesis()
res.data.data
except CancelledError as exc:
error "Genesis request was interrupted"
@ -120,7 +122,7 @@ proc checkOnline*(node: BeaconNodeServerRef) {.async.} =
debug "Checking beacon node status"
let agent =
try:
let res = await node.client.getVersion()
let res = await node.client.getNodeVersion()
res.data.data
except CancelledError as exc:
error "Status request was interrupted"
@ -404,10 +406,10 @@ template firstSuccessTimeout*(vc: ValidatorClientRef, respType: typedesc,
break
proc getProposerDuties*(vc: ValidatorClientRef,
epoch: Epoch): Future[DataRestProposerDuties] {.
epoch: Epoch): Future[GetProposerDutiesResponse] {.
async.} =
logScope: request = "getProposerDuties"
vc.firstSuccessTimeout(RestResponse[DataRestProposerDuties], SlotDuration,
vc.firstSuccessTimeout(RestResponse[GetProposerDutiesResponse], SlotDuration,
getProposerDuties(it, epoch)):
if apiResponse.isErr():
debug "Unable to retrieve proposer duties", endpoint = node,
@ -440,9 +442,9 @@ proc getProposerDuties*(vc: ValidatorClientRef,
proc getAttesterDuties*(vc: ValidatorClientRef, epoch: Epoch,
validators: seq[ValidatorIndex]
): Future[DataRestAttesterDuties] {.async.} =
): Future[GetAttesterDutiesResponse] {.async.} =
logScope: request = "getAttesterDuties"
vc.firstSuccessTimeout(RestResponse[DataRestAttesterDuties], SlotDuration,
vc.firstSuccessTimeout(RestResponse[GetAttesterDutiesResponse], SlotDuration,
getAttesterDuties(it, epoch, validators)):
if apiResponse.isErr():
debug "Unable to retrieve attester duties", endpoint = node,
@ -476,7 +478,7 @@ proc getAttesterDuties*(vc: ValidatorClientRef, epoch: Epoch,
proc getHeadStateFork*(vc: ValidatorClientRef): Future[Fork] {.async.} =
logScope: request = "getHeadStateFork"
let stateIdent = StateIdent.init(StateIdentType.Head)
vc.firstSuccessTimeout(RestResponse[DataRestFork], SlotDuration,
vc.firstSuccessTimeout(RestResponse[GetStateForkResponse], SlotDuration,
getStateFork(it, stateIdent)):
if apiResponse.isErr():
debug "Unable to retrieve head state's fork", endpoint = node,
@ -508,7 +510,7 @@ proc getValidators*(vc: ValidatorClientRef,
async.} =
logScope: request = "getStateValidators"
let stateIdent = StateIdent.init(StateIdentType.Head)
vc.firstSuccessTimeout(RestResponse[DataRestValidatorList], SlotDuration,
vc.firstSuccessTimeout(RestResponse[GetStateValidatorsResponse], SlotDuration,
getStateValidators(it, stateIdent, id)):
if apiResponse.isErr():
debug "Unable to retrieve head state's validator information",
@ -540,7 +542,7 @@ proc produceAttestationData*(vc: ValidatorClientRef, slot: Slot,
committee_index: CommitteeIndex
): Future[AttestationData] {.async.} =
logScope: request = "produceAttestationData"
vc.firstSuccessTimeout(RestResponse[DataRestAttestationData],
vc.firstSuccessTimeout(RestResponse[ProduceAttestationDataResponse],
OneThirdDuration,
produceAttestationData(it, slot, committee_index)):
if apiResponse.isErr():
@ -633,7 +635,7 @@ proc getAggregatedAttestation*(vc: ValidatorClientRef, slot: Slot,
root: Eth2Digest): Future[Attestation] {.
async.} =
logScope: request = "getAggregatedAttestation"
vc.firstSuccessTimeout(RestResponse[DataRestAttestation],
vc.firstSuccessTimeout(RestResponse[GetAggregatedAttestationResponse],
OneThirdDuration,
getAggregatedAttestation(it, root, slot)):
if apiResponse.isErr():
@ -699,9 +701,9 @@ proc publishAggregateAndProofs*(vc: ValidatorClientRef,
proc produceBlock*(vc: ValidatorClientRef, slot: Slot,
randao_reveal: ValidatorSig,
graffiti: GraffitiBytes): Future[BeaconBlock] {.async.} =
graffiti: GraffitiBytes): Future[phase0.BeaconBlock] {.async.} =
logScope: request = "produceBlock"
vc.firstSuccessTimeout(RestResponse[DataRestBeaconBlock],
vc.firstSuccessTimeout(RestResponse[ProduceBlockResponse],
SlotDuration,
produceBlock(it, slot, randao_reveal, graffiti)):
if apiResponse.isErr():
@ -734,7 +736,7 @@ proc produceBlock*(vc: ValidatorClientRef, slot: Slot,
raise newException(ValidatorApiError, "Unable to retrieve block data")
proc publishBlock*(vc: ValidatorClientRef,
data: SignedBeaconBlock): Future[bool] {.async.} =
data: phase0.SignedBeaconBlock): Future[bool] {.async.} =
logScope: request = "publishBlock"
vc.firstSuccessTimeout(RestPlainResponse,
SlotDuration, publishBlock(it, data)):

View File

@ -1,3 +1,4 @@
import ../spec/datatypes/[phase0, altair]
import common, api
import chronicles
@ -35,7 +36,7 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
return
let blockRoot = hash_tree_root(beaconBlock)
var signedBlock = SignedBeaconBlock(message: beaconBlock,
var signedBlock = phase0.SignedBeaconBlock(message: beaconBlock,
root: hash_tree_root(beaconBlock))
# TODO: signing_root is recomputed in signBlockProposal just after
@ -49,7 +50,8 @@ proc publishBlock(vc: ValidatorClientRef, currentSlot, slot: Slot,
if notSlashable.isOk():
let signature = await validator.signBlockProposal(fork, genesisRoot, slot,
blockRoot)
let signedBlock = SignedBeaconBlock(message: beaconBlock, root: blockRoot,
let signedBlock =
phase0.SignedBeaconBlock(message: beaconBlock, root: blockRoot,
signature: signature)
let res =
try:

View File

@ -1,26 +1,24 @@
import std/[tables, os, sequtils, strutils]
import chronos, presto, presto/client as presto_client, chronicles, confutils,
json_serialization/std/[options, net],
stew/[base10, results, byteutils]
stew/[base10, results, byteutils],
eth/db/[kvstore, kvstore_sqlite3]
# Local modules
import ".."/networking/[eth2_network, eth2_discovery],
".."/spec/[datatypes, digest, crypto, helpers, signatures],
".."/rpc/[beacon_rest_api, node_rest_api, validator_rest_api,
config_rest_api, rest_utils, eth2_json_rest_serialization],
import ".."/spec/[datatypes, digest, crypto, helpers, signatures],
".."/spec/eth2_apis/rest_beacon_client,
".."/validators/[attestation_aggregation, keystore_management,
validator_pool, slashing_protection],
".."/[conf, beacon_clock, version, beacon_node_types,
nimbus_binary_common],
".."/ssz/merkleization,
./eth/db/[kvstore, kvstore_sqlite3]
".."/ssz/merkleization
export os, tables, sequtils, sequtils, chronos, presto, chronicles, confutils,
nimbus_binary_common, version, conf, options, tables, results, base10,
byteutils, eth2_json_rest_serialization, presto_client
byteutils, presto_client
export beacon_rest_api, node_rest_api, validator_rest_api, config_rest_api,
rest_utils,
datatypes, crypto, digest, signatures, merkleization,
export rest_beacon_client,
datatypes, crypto, digest, helpers, signatures, merkleization,
beacon_clock,
kvstore, kvstore_sqlite3,
keystore_management, slashing_protection, validator_pool,
@ -74,9 +72,9 @@ type
BeaconNodeServer* = object
client*: RestClientRef
endpoint*: string
config*: Option[RestConfig]
config*: Option[RestSpec]
ident*: Option[string]
genesis*: Option[RestBeaconGenesis]
genesis*: Option[RestGenesis]
syncInfo*: Option[RestSyncInfo]
status*: RestBeaconNodeStatus
@ -107,7 +105,7 @@ type
fork*: Option[Fork]
attesters*: AttesterMap
proposers*: ProposerMap
beaconGenesis*: RestBeaconGenesis
beaconGenesis*: RestGenesis
proposerTasks*: Table[Slot, seq[ProposerTask]]
ValidatorClientRef* = ref ValidatorClient

View File

@ -1,8 +1,10 @@
# JSON-RPC API
`nimbus-eth2` exposes a collection of APIs for querying the state of the application at runtime.
The `JSON-RPC API` is a collection of APIs for querying the state of the application at runtime.
Where applicable, these APIs mimic the [eth2 APIs](https://github.com/ethereum/eth2.0-APIs) with the exception that `JSON-RPC` is used instead of [http `REST`](./rest-api.md) (the method names, parameters and results are all the same except for the encoding / access method).
The API is based on the common [eth2 APIs](https://github.com/ethereum/eth2.0-APIs) with the exception that `JSON-RPC` is used instead of [http `REST`](./rest-api.md) (the method names, parameters and results are all the same except for the encoding / access method).
Nimbus also implements the [common REST API](./rest-api.md) - new applications should consider using it instead of JSON RPC.
## Introduction

View File

@ -1,6 +1,5 @@
# REST API
Nimbus supports the [common REST API](https://ethereum.github.io/eth2.0-APIs/#/) for runtime communication with the application. For historical reasons, a [JSON-RPC-based API](./api.md) is also supported.
The community has settled on REST as a common interface, as [documented here](https://ethereum.github.io/eth2.0-APIs/#/) -- the `REST` API is an updated version of the [`JSON-RPC` api](./api.md).
If you're looking to use this more standard API, you can enable it by running the Beacon Node with the `--rest` parameter (note this is currently in Beta).
The REST API is currently in BETA -- to enable it, use the `--rest` option when starting the beacon node, then access the API from http://localhost:5052/.