remove deprecated JSON-RPC server (#3656)

* remove deprecated JSON-RPC server

* keep the command-line options around as no-ops, temporarily

* service -> server; JSON-RPC is still used elsewhere
This commit is contained in:
tersec 2022-05-24 07:23:48 +00:00 committed by GitHub
parent 1101c745b9
commit d35d408fa7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 10 additions and 1502 deletions

View File

@ -53,7 +53,6 @@ type
lightClientPool*: ref LightClientPool
exitPool*: ref ExitPool
eth1Monitor*: Eth1Monitor
rpcServer*: RpcServer
restServer*: RestServerRef
keymanagerServer*: RestServerRef
keymanagerToken*: Option[string]

View File

@ -338,18 +338,21 @@ type
name: "status-bar-contents" }: string
rpcEnabled* {.
desc: "Enable the JSON-RPC server (deprecated)"
hidden
desc: "Enable the JSON-RPC server (deprecated for removal)"
defaultValue: false
name: "rpc" }: bool
rpcPort* {.
desc: "HTTP port for the JSON-RPC service"
defaultValue: defaultEth2RpcPort
hidden
desc: "HTTP port for the JSON-RPC service (deprecated for removal)"
defaultValue: 9190
defaultValueDesc: "9190"
name: "rpc-port" }: Port
rpcAddress* {.
desc: "Listening address of the RPC server"
hidden
desc: "Listening address of the RPC server (deprecated for removal)"
defaultValue: defaultAdminListenAddress
defaultValueDesc: "127.0.0.1"
name: "rpc-address" }: ValidIpAddress

View File

@ -14,7 +14,7 @@ import
stew/[byteutils, io2],
eth/p2p/discoveryv5/[enr, random2],
eth/keys,
./rpc/[rest_api, rpc_api, state_ttl_cache],
./rpc/[rest_api, state_ttl_cache],
./spec/datatypes/[altair, bellatrix, phase0],
./spec/[engine_authentication, weak_subjectivity],
./validators/[keystore_management, validator_duties],
@ -577,10 +577,8 @@ proc init*(T: type BeaconNode,
config.web3ForcePolling,
optJwtSecret)
let rpcServer = if config.rpcEnabled:
RpcServer.init(config.rpcAddress, config.rpcPort)
else:
nil
if config.rpcEnabled:
warn "Nimbus's JSON-RPC server has been removed. This includes the --rpc, --rpc-port, and --rpc-address configuration options. https://nimbus.guide/rest-api.html shows how to enable and configure the REST Beacon API server which replaces it."
let restServer = if config.restEnabled:
RestServerRef.init(
@ -676,7 +674,6 @@ proc init*(T: type BeaconNode,
config: config,
attachedValidators: validatorPool,
eth1Monitor: eth1Monitor,
rpcServer: rpcServer,
restServer: restServer,
keymanagerServer: keymanagerServer,
keymanagerToken: keymanagerToken,
@ -1293,16 +1290,6 @@ proc runOnSecondLoop(node: BeaconNode) {.async.} =
func connectedPeersCount(node: BeaconNode): int =
len(node.network.peerPool)
proc installRpcHandlers(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.installBeaconApiHandlers(node)
rpcServer.installConfigApiHandlers(node)
rpcServer.installDebugApiHandlers(node)
rpcServer.installEventApiHandlers(node)
rpcServer.installNimbusApiHandlers(node)
rpcServer.installNodeApiHandlers(node)
rpcServer.installValidatorApiHandlers(node)
proc installRestHandlers(restServer: RestServerRef, node: BeaconNode) =
restServer.router.installBeaconApiHandlers(node)
restServer.router.installConfigApiHandlers(node)
@ -1465,10 +1452,6 @@ proc startBackfillTask(node: BeaconNode) {.async.} =
proc run(node: BeaconNode) {.raises: [Defect, CatchableError].} =
bnStatus = BeaconNodeStatus.Running
if not(isNil(node.rpcServer)):
node.rpcServer.installRpcHandlers(node)
node.rpcServer.start()
if not(isNil(node.restServer)):
node.restServer.installRestHandlers(node)
node.restServer.start()

View File

@ -1,24 +0,0 @@
# 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

@ -1,513 +0,0 @@
# 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.
{.push raises: [Defect].}
import
std/[parseutils, sequtils, strutils, sets],
stew/[byteutils, results],
json_rpc/servers/httpserver,
chronicles,
../beacon_node,
../networking/eth2_network,
../validators/validator_duties,
../consensus_object_pools/blockchain_dag,
../spec/[eth2_merkleization, forks, network, validator],
../spec/datatypes/[phase0],
./rpc_utils
logScope: topics = "beaconapi"
type
RpcServer = RpcHttpServer
ValidatorQuery = object
# Security note / threat model:
# - The validator pubkey are stored in their raw bytes representation
# in the `keyset`.
# - While the input is from unknown source (as far as the beacon node is concerned),
# users are asked to not expose their
# RPC endpoints to untrusted network or use a reverse proxy in front.
# - At usage time, keys in the keyset are compared to keys registered
# in the Ethereum BeaconState which are valid
keyset: HashSet[ValidatorPubKey]
ids: seq[uint64]
StatusQuery = object
statset: HashSet[string]
template unimplemented() =
raise (ref CatchableError)(msg: "Unimplemented")
proc createIdQuery(ids: openArray[string]): Result[ValidatorQuery, cstring] =
# validatorIds array should have maximum 30 items, and all items should be
# unique.
if len(ids) > 30:
return err("The number of ids exceeds the limit")
# All ids in validatorIds must be unique.
if len(ids) != len(toHashSet(ids)):
return err("ids array must have unique item")
var res = ValidatorQuery(
keyset: initHashSet[ValidatorPubKey](),
ids: newSeq[uint64]()
)
for item in ids:
if item.startsWith("0x"):
let pubkey = ? ValidatorPubKey.fromHex(item)
res.keyset.incl(pubkey)
else:
var tmp: uint64
try:
if parseBiggestUInt(item, tmp) != len(item):
return err("Incorrect index value")
except ValueError:
return err("Cannot parse index value")
res.ids.add(tmp)
ok(res)
proc createStatusQuery(status: openArray[string]): Result[StatusQuery, string] =
const AllowedStatuses = [
"pending", "pending_initialized", "pending_queued",
"active", "active_ongoing", "active_exiting", "active_slashed",
"exited", "exited_unslashed", "exited_slashed",
"withdrawal", "withdrawal_possible", "withdrawal_done"
]
if len(status) > len(AllowedStatuses):
return err("The number of statuses exceeds the limit")
var res = StatusQuery(statset: initHashSet[string]())
# All ids in validatorIds must be unique.
if len(status) != len(toHashSet(status)):
return err("Status array must have unique items")
for item in status:
if item notin AllowedStatuses:
return err("Invalid status requested")
case item
of "pending":
res.statset.incl("pending_initialized")
res.statset.incl("pending_queued")
of "active":
res.statset.incl("active_ongoing")
res.statset.incl("active_exiting")
res.statset.incl("active_slashed")
of "exited":
res.statset.incl("exited_unslashed")
res.statset.incl("exited_slashed")
of "withdrawal":
res.statset.incl("withdrawal_possible")
res.statset.incl("withdrawal_done")
else:
res.statset.incl(item)
proc getStatus(validator: Validator,
current_epoch: Epoch): Result[string, string] =
if validator.activation_epoch > current_epoch:
# pending
if validator.activation_eligibility_epoch == FAR_FUTURE_EPOCH:
ok("pending_initialized")
else:
# validator.activation_eligibility_epoch < FAR_FUTURE_EPOCH:
ok("pending_queued")
elif (validator.activation_epoch <= current_epoch) and
(current_epoch < validator.exit_epoch):
# active
if validator.exit_epoch == FAR_FUTURE_EPOCH:
ok("active_ongoing")
elif not validator.slashed:
# validator.exit_epoch < FAR_FUTURE_EPOCH
ok("active_exiting")
else:
# validator.exit_epoch < FAR_FUTURE_EPOCH and validator.slashed:
ok("active_slashed")
elif (validator.exit_epoch <= current_epoch) and
(current_epoch < validator.withdrawable_epoch):
# exited
if not validator.slashed:
ok("exited_unslashed")
else:
# validator.slashed
ok("exited_slashed")
elif validator.withdrawable_epoch <= current_epoch:
# withdrawal
if validator.effective_balance != 0:
ok("withdrawal_possible")
else:
# validator.effective_balance == 0
ok("withdrawal_done")
else:
err("Invalid validator status")
proc getForkedBlockFromBlockId(
node: BeaconNode, blockId: string): ForkedTrustedSignedBeaconBlock {.
raises: [Defect, CatchableError].} =
case blockId:
of "head":
node.dag.getForkedBlock(node.dag.head.bid).valueOr:
raise newException(CatchableError, "Block not found")
of "genesis":
node.dag.getForkedBlock(node.dag.genesis).valueOr:
raise newException(CatchableError, "Block not found")
of "finalized":
node.dag.getForkedBlock(node.dag.finalizedHead.blck.bid).valueOr:
raise newException(CatchableError, "Block not found")
else:
if blockId.startsWith("0x"):
let
blckRoot = parseRoot(blockId)
node.dag.getForkedBlock(blckRoot).valueOr:
raise newException(CatchableError, "Block not found")
else:
let bid = node.getBlockIdFromString(blockId)
node.dag.getForkedBlock(bid).valueOr:
raise newException(CatchableError, "Block not found")
proc installBeaconApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.rpc("get_v1_beacon_genesis") do () -> RpcBeaconGenesis:
return (
genesis_time: getStateField(node.dag.headState, genesis_time),
genesis_validators_root:
getStateField(node.dag.headState, genesis_validators_root),
genesis_fork_version: node.dag.cfg.GENESIS_FORK_VERSION
)
rpcServer.rpc("get_v1_beacon_states_root") do (stateId: string) -> Eth2Digest:
withStateForStateId(stateId):
return stateRoot
rpcServer.rpc("get_v1_beacon_states_fork") do (stateId: string) -> Fork:
withStateForStateId(stateId):
return getStateField(state, fork)
rpcServer.rpc("get_v1_beacon_states_finality_checkpoints") do (
stateId: string) -> RpcBeaconStatesFinalityCheckpoints:
withStateForStateId(stateId):
return (previous_justified:
getStateField(state, previous_justified_checkpoint),
current_justified:
getStateField(state, current_justified_checkpoint),
finalized: getStateField(state, finalized_checkpoint))
rpcServer.rpc("get_v1_beacon_states_stateId_validators") do (
stateId: string, validatorIds: Option[seq[string]],
status: Option[seq[string]]) -> seq[RpcBeaconStatesValidators]:
var vquery: ValidatorQuery
var squery: StatusQuery
let current_epoch = getStateField(node.dag.headState, slot).epoch
template statusCheck(status, statusQuery, vstatus, current_epoch): bool =
if status.isNone():
true
else:
if vstatus in squery.statset:
true
else:
false
var res: seq[RpcBeaconStatesValidators]
withStateForStateId(stateId):
if status.isSome:
let sqres = createStatusQuery(status.get())
if sqres.isErr:
raise newException(CatchableError, sqres.error)
squery = sqres.get()
if validatorIds.isSome:
let vqres = createIdQuery(validatorIds.get())
if vqres.isErr:
raise newException(CatchableError, $vqres.error)
vquery = vqres.get()
if validatorIds.isNone():
for index, validator in getStateField(state, validators):
let sres = validator.getStatus(current_epoch)
if sres.isOk:
let vstatus = sres.get()
let includeFlag = statusCheck(status, squery, vstatus,
current_epoch)
if includeFlag:
res.add((validator: validator,
index: uint64(index),
status: vstatus,
balance: getStateField(state, balances).asSeq()[index]))
else:
for index in vquery.ids:
if index < lenu64(getStateField(state, validators)):
let validator = getStateField(state, validators).asSeq()[index]
let sres = validator.getStatus(current_epoch)
if sres.isOk:
let vstatus = sres.get()
let includeFlag = statusCheck(status, squery, vstatus,
current_epoch)
if includeFlag:
vquery.keyset.excl(validator.pubkey)
res.add((validator: validator,
index: uint64(index),
status: vstatus,
balance: getStateField(state, balances).asSeq()[index]))
for index, validator in getStateField(state, validators):
if validator.pubkey in vquery.keyset:
let sres = validator.getStatus(current_epoch)
if sres.isOk:
let vstatus = sres.get()
let includeFlag = statusCheck(status, squery, vstatus,
current_epoch)
if includeFlag:
res.add((validator: validator,
index: uint64(index),
status: vstatus,
balance: getStateField(state, balances).asSeq()[index]))
return res
rpcServer.rpc("get_v1_beacon_states_stateId_validators_validatorId") do (
stateId: string, validatorId: string) -> RpcBeaconStatesValidators:
let current_epoch = getStateField(node.dag.headState, slot).epoch
let vqres = createIdQuery([validatorId])
if vqres.isErr:
raise newException(CatchableError, $vqres.error)
let vquery = vqres.get()
withStateForStateId(stateId):
if len(vquery.ids) > 0:
let index = vquery.ids[0]
if index < lenu64(getStateField(state, validators)):
let validator = getStateField(state, validators).asSeq()[index]
let sres = validator.getStatus(current_epoch)
if sres.isOk:
return (validator: validator, index: uint64(index),
status: sres.get(),
balance: getStateField(state, balances).asSeq()[index])
else:
raise newException(CatchableError, "Incorrect validator's state")
else:
for index, validator in getStateField(state, validators):
if validator.pubkey in vquery.keyset:
let sres = validator.getStatus(current_epoch)
if sres.isOk:
return (validator: validator, index: uint64(index),
status: sres.get(),
balance: getStateField(state, balances).asSeq()[index])
else:
raise newException(CatchableError, "Incorrect validator's state")
rpcServer.rpc("get_v1_beacon_states_stateId_validator_balances") do (
stateId: string, validatorsId: Option[seq[string]]) -> seq[RpcBalance]:
var res: seq[RpcBalance]
withStateForStateId(stateId):
if validatorsId.isNone():
for index, value in getStateField(state, balances):
let balance = (index: uint64(index), balance: value)
res.add(balance)
else:
let vqres = createIdQuery(validatorsId.get())
if vqres.isErr:
raise newException(CatchableError, $vqres.error)
var vquery = vqres.get()
for index in vquery.ids:
if index < lenu64(getStateField(state, validators)):
let validator = getStateField(state, validators).asSeq()[index]
vquery.keyset.excl(validator.pubkey)
let balance = (index: uint64(index),
balance: getStateField(state, balances).asSeq()[index])
res.add(balance)
for index, validator in getStateField(state, validators):
if validator.pubkey in vquery.keyset:
let balance = (index: uint64(index),
balance: getStateField(state, balances).asSeq()[index])
res.add(balance)
return res
rpcServer.rpc("get_v1_beacon_states_stateId_committees_epoch") do (
stateId: string, epoch: Option[uint64], index: Option[uint64],
slot: Option[uint64]) -> seq[RpcBeaconStatesCommittees]:
withStateForStateId(stateId):
proc getCommittee(slot: Slot,
index: CommitteeIndex): RpcBeaconStatesCommittees =
let vals = get_beacon_committee(
state, slot, index, cache).mapIt(it.uint64)
return (index: index.uint64, slot: slot.uint64, validators: vals)
proc forSlot(slot: Slot, res: var seq[RpcBeaconStatesCommittees]) =
let committees_per_slot =
get_committee_count_per_slot(state, slot.epoch, cache)
if index.isNone:
for committee_index in get_committee_indices(committees_per_slot):
res.add(getCommittee(slot, committee_index))
else:
if index.get() < committees_per_slot:
let cindex = CommitteeIndex.init(index.get()).expect(
"valid because verified against committees_per_slot")
res.add(getCommittee(slot, cindex))
var res: seq[RpcBeaconStatesCommittees]
let qepoch =
if epoch.isNone:
epoch(getStateField(state, slot))
else:
Epoch(epoch.get())
if slot.isNone:
for slot in qepoch.slots():
forSlot(slot, res)
else:
forSlot(Slot(slot.get()), res)
return res
rpcServer.rpc("get_v1_beacon_headers") do (
slot: Option[uint64], parent_root: Option[string]) ->
seq[RpcBeaconHeaders]:
unimplemented()
rpcServer.rpc("get_v1_beacon_headers_blockId") do (
blockId: string) ->
tuple[canonical: bool, header: SignedBeaconBlockHeader]:
let bd = node.getForkedBlockFromBlockId(blockId)
return withBlck(bd):
static: doAssert blck.signature is TrustedSig and
sizeof(ValidatorSig) == sizeof(blck.signature)
(
canonical: node.dag.isCanonical(
BlockId(root: blck.root, slot: blck.message.slot)),
header: SignedBeaconBlockHeader(
message: blck.toBeaconBlockHeader
)
)
rpcServer.rpc("post_v1_beacon_blocks") do (blck: phase0.SignedBeaconBlock) -> int:
let res = await sendBeaconBlock(node, ForkedSignedBeaconBlock.init(blck))
if res.isErr():
raise (ref CatchableError)(msg: $res.error())
if res.get():
# The block was validated successfully and has been broadcast.
# It has also been integrated into the beacon node's database.
return 200
else:
# The block failed validation, but was successfully broadcast anyway.
# It was not integrated into the beacon node''s database.
return 202
rpcServer.rpc("get_v1_beacon_blocks_blockId") do (
blockId: string) -> phase0.TrustedSignedBeaconBlock:
let blck = node.getForkedBlockFromBlockId(blockId)
if blck.kind == BeaconBlockFork.Phase0:
return blck.phase0Data
else:
raiseNoAltairSupport()
rpcServer.rpc("get_v1_beacon_blocks_blockId_root") do (
blockId: string) -> Eth2Digest:
return withBlck(node.getForkedBlockFromBlockId(blockId)):
blck.root
rpcServer.rpc("get_v1_beacon_blocks_blockId_attestations") do (
blockId: string) -> seq[TrustedAttestation]:
return withBlck(node.getForkedBlockFromBlockId(blockId)):
blck.message.body.attestations.asSeq
rpcServer.rpc("get_v1_beacon_pool_attestations") do (
slot: Option[uint64], committee_index: Option[uint64]) ->
seq[RpcAttestation]:
var res: seq[RpcAttestation]
let qslot =
if slot.isSome():
some(Slot(slot.get()))
else:
none[Slot]()
let qindex =
if committee_index.isSome():
some(CommitteeIndex(committee_index.get()))
else:
none[CommitteeIndex]()
for item in node.attestationPool[].attestations(qslot, qindex):
let atuple = (
aggregation_bits: to0xHex(item.aggregation_bits.bytes),
data: item.data,
signature: item.signature
)
res.add(atuple)
return res
rpcServer.rpc("post_v1_beacon_pool_attestations") do (
attestation: Attestation) -> bool:
let res = await node.sendAttestation(attestation)
if not res.isOk():
raise (ref CatchableError)(msg: $res.error())
return true
rpcServer.rpc("get_v1_beacon_pool_attester_slashings") do (
) -> seq[AttesterSlashing]:
var res: seq[AttesterSlashing]
if isNil(node.exitPool):
return res
let length = len(node.exitPool.attester_slashings)
res = newSeqOfCap[AttesterSlashing](length)
for item in node.exitPool.attester_slashings.items():
res.add(item)
return res
rpcServer.rpc("post_v1_beacon_pool_attester_slashings") do (
slashing: AttesterSlashing) -> bool:
let res = node.sendAttesterSlashing(slashing)
if not res.isOk():
raise (ref CatchableError)(msg: $res.error())
return true
rpcServer.rpc("get_v1_beacon_pool_proposer_slashings") do (
) -> seq[ProposerSlashing]:
var res: seq[ProposerSlashing]
if isNil(node.exitPool):
return res
let length = len(node.exitPool.proposer_slashings)
res = newSeqOfCap[ProposerSlashing](length)
for item in node.exitPool.proposer_slashings.items():
res.add(item)
return res
rpcServer.rpc("post_v1_beacon_pool_proposer_slashings") do (
slashing: ProposerSlashing) -> bool:
let res = node.sendProposerSlashing(slashing)
if not res.isOk():
raise (ref CatchableError)(msg: $res.error())
return true
rpcServer.rpc("get_v1_beacon_pool_voluntary_exits") do (
) -> seq[SignedVoluntaryExit]:
var res: seq[SignedVoluntaryExit]
if isNil(node.exitPool):
return res
let length = len(node.exitPool.voluntary_exits)
res = newSeqOfCap[SignedVoluntaryExit](length)
for item in node.exitPool.voluntary_exits.items():
res.add(item)
return res
rpcServer.rpc("post_v1_beacon_pool_voluntary_exits") do (
exit: SignedVoluntaryExit) -> bool:
let res = node.sendVoluntaryExit(exit)
if not res.isOk():
raise (ref CatchableError)(msg: $res.error())
return true

View File

@ -1,109 +0,0 @@
# 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.
{.push raises: [Defect].}
import
stew/[byteutils],
json_rpc/servers/httpserver,
chronicles,
../beacon_node,
../eth1/eth1_monitor,
../spec/forks
logScope: topics = "configapi"
type
RpcServer = RpcHttpServer
proc installConfigApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.rpc("get_v1_config_fork_schedule") do () -> seq[Fork]:
return @[getStateField(node.dag.headState, fork)]
rpcServer.rpc("get_v1_config_spec") do () -> JsonNode:
return %*{
# Note: This is intentionally only returning v1.0 config values.
# Please use the REST API /eth/v1/config/spec to retrieve the full config.
# https://github.com/ethereum/consensus-specs/blob/v1.0.1/configs/mainnet/phase0.yaml
"MAX_COMMITTEES_PER_SLOT": $MAX_COMMITTEES_PER_SLOT,
"TARGET_COMMITTEE_SIZE": $TARGET_COMMITTEE_SIZE,
"MAX_VALIDATORS_PER_COMMITTEE": $MAX_VALIDATORS_PER_COMMITTEE,
"MIN_PER_EPOCH_CHURN_LIMIT": $node.dag.cfg.MIN_PER_EPOCH_CHURN_LIMIT,
"CHURN_LIMIT_QUOTIENT": $node.dag.cfg.CHURN_LIMIT_QUOTIENT,
"SHUFFLE_ROUND_COUNT": $SHUFFLE_ROUND_COUNT,
"MIN_GENESIS_ACTIVE_VALIDATOR_COUNT":
$node.dag.cfg.MIN_GENESIS_ACTIVE_VALIDATOR_COUNT,
"MIN_GENESIS_TIME": $node.dag.cfg.MIN_GENESIS_TIME,
"HYSTERESIS_QUOTIENT": $HYSTERESIS_QUOTIENT,
"HYSTERESIS_DOWNWARD_MULTIPLIER": $HYSTERESIS_DOWNWARD_MULTIPLIER,
"HYSTERESIS_UPWARD_MULTIPLIER": $HYSTERESIS_UPWARD_MULTIPLIER,
"SAFE_SLOTS_TO_UPDATE_JUSTIFIED": $SAFE_SLOTS_TO_UPDATE_JUSTIFIED,
"ETH1_FOLLOW_DISTANCE": $node.dag.cfg.ETH1_FOLLOW_DISTANCE,
"TARGET_AGGREGATORS_PER_COMMITTEE": $TARGET_AGGREGATORS_PER_COMMITTEE,
"RANDOM_SUBNETS_PER_VALIDATOR": $RANDOM_SUBNETS_PER_VALIDATOR,
"EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION":
$EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION,
"SECONDS_PER_ETH1_BLOCK": $node.dag.cfg.SECONDS_PER_ETH1_BLOCK,
"DEPOSIT_CHAIN_ID": $node.dag.cfg.DEPOSIT_CHAIN_ID,
"DEPOSIT_NETWORK_ID": $node.dag.cfg.DEPOSIT_NETWORK_ID,
"DEPOSIT_CONTRACT_ADDRESS": $node.dag.cfg.DEPOSIT_CONTRACT_ADDRESS,
"MIN_DEPOSIT_AMOUNT": $MIN_DEPOSIT_AMOUNT,
"MAX_EFFECTIVE_BALANCE": $MAX_EFFECTIVE_BALANCE,
"EJECTION_BALANCE": $node.dag.cfg.EJECTION_BALANCE,
"EFFECTIVE_BALANCE_INCREMENT": $EFFECTIVE_BALANCE_INCREMENT,
"GENESIS_FORK_VERSION":
"0x" & $node.dag.cfg.GENESIS_FORK_VERSION,
"BLS_WITHDRAWAL_PREFIX": to0xHex([BLS_WITHDRAWAL_PREFIX]),
"GENESIS_DELAY": $node.dag.cfg.GENESIS_DELAY,
"SECONDS_PER_SLOT": $SECONDS_PER_SLOT,
"MIN_ATTESTATION_INCLUSION_DELAY": $MIN_ATTESTATION_INCLUSION_DELAY,
"SLOTS_PER_EPOCH": $SLOTS_PER_EPOCH,
"MIN_SEED_LOOKAHEAD": $MIN_SEED_LOOKAHEAD,
"MAX_SEED_LOOKAHEAD": $MAX_SEED_LOOKAHEAD,
"EPOCHS_PER_ETH1_VOTING_PERIOD": $EPOCHS_PER_ETH1_VOTING_PERIOD,
"SLOTS_PER_HISTORICAL_ROOT": $SLOTS_PER_HISTORICAL_ROOT,
"MIN_VALIDATOR_WITHDRAWABILITY_DELAY":
$node.dag.cfg.MIN_VALIDATOR_WITHDRAWABILITY_DELAY,
"SHARD_COMMITTEE_PERIOD": $node.dag.cfg.SHARD_COMMITTEE_PERIOD,
"MIN_EPOCHS_TO_INACTIVITY_PENALTY": $MIN_EPOCHS_TO_INACTIVITY_PENALTY,
"EPOCHS_PER_HISTORICAL_VECTOR": $EPOCHS_PER_HISTORICAL_VECTOR,
"EPOCHS_PER_SLASHINGS_VECTOR": $EPOCHS_PER_SLASHINGS_VECTOR,
"HISTORICAL_ROOTS_LIMIT": $HISTORICAL_ROOTS_LIMIT,
"VALIDATOR_REGISTRY_LIMIT": $VALIDATOR_REGISTRY_LIMIT,
"BASE_REWARD_FACTOR": $BASE_REWARD_FACTOR,
"WHISTLEBLOWER_REWARD_QUOTIENT": $WHISTLEBLOWER_REWARD_QUOTIENT,
"PROPOSER_REWARD_QUOTIENT": $PROPOSER_REWARD_QUOTIENT,
"INACTIVITY_PENALTY_QUOTIENT": $INACTIVITY_PENALTY_QUOTIENT,
"MIN_SLASHING_PENALTY_QUOTIENT": $MIN_SLASHING_PENALTY_QUOTIENT,
"PROPORTIONAL_SLASHING_MULTIPLIER": $PROPORTIONAL_SLASHING_MULTIPLIER,
"MAX_PROPOSER_SLASHINGS": $MAX_PROPOSER_SLASHINGS,
"MAX_ATTESTER_SLASHINGS": $MAX_ATTESTER_SLASHINGS,
"MAX_ATTESTATIONS": $MAX_ATTESTATIONS,
"MAX_DEPOSITS": $MAX_DEPOSITS,
"MAX_VOLUNTARY_EXITS": $MAX_VOLUNTARY_EXITS,
"DOMAIN_BEACON_PROPOSER":
to0xHex(DOMAIN_BEACON_PROPOSER.data),
"DOMAIN_BEACON_ATTESTER":
to0xHex(DOMAIN_BEACON_ATTESTER.data),
"DOMAIN_RANDAO":
to0xHex(DOMAIN_RANDAO.data),
"DOMAIN_DEPOSIT":
to0xHex(DOMAIN_DEPOSIT.data),
"DOMAIN_VOLUNTARY_EXIT":
to0xHex(DOMAIN_VOLUNTARY_EXIT.data),
"DOMAIN_SELECTION_PROOF":
to0xHex(DOMAIN_SELECTION_PROOF.data),
"DOMAIN_AGGREGATE_AND_PROOF":
to0xHex(DOMAIN_AGGREGATE_AND_PROOF.data)
}
rpcServer.rpc("get_v1_config_deposit_contract") do () -> JsonNode:
return %*{
"chain_id": $node.dag.cfg.DEPOSIT_CHAIN_ID,
"address": node.dag.cfg.DEPOSIT_CONTRACT_ADDRESS
}

View File

@ -1,35 +0,0 @@
# 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.
{.push raises: [Defect].}
import
std/sequtils,
json_rpc/servers/httpserver,
chronicles,
../version, ../beacon_node,
../networking/[eth2_network, peer_pool],
../spec/datatypes/phase0,
./rpc_utils
logScope: topics = "debugapi"
type
RpcServer = RpcHttpServer
proc installDebugApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.rpc("get_v1_debug_beacon_states_stateId") do (
stateId: string) -> phase0.BeaconState:
withStateForStateId(stateId):
if state.kind == BeaconStateFork.Phase0:
return state.phase0Data.data
else:
raiseNoAltairSupport()
rpcServer.rpc("get_v1_debug_beacon_heads") do () -> seq[tuple[root: Eth2Digest, slot: Slot]]:
return node.dag.heads.mapIt((it.root, it.slot))

View File

@ -1,26 +0,0 @@
# 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.
{.push raises: [Defect].}
import
json_rpc/servers/httpserver,
chronicles,
../beacon_node
logScope: topics = "eventapi"
type
RpcServer = RpcHttpServer
template unimplemented() =
raise (ref CatchableError)(msg: "Unimplemented")
proc installEventApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.rpc("get_v1_events") do () -> JsonNode:
unimplemented()

View File

@ -1,230 +0,0 @@
# 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.
{.push raises: [Defect].}
import
std/[deques, sequtils, sets],
chronos,
stew/byteutils,
json_rpc/servers/httpserver,
libp2p/protocols/pubsub/pubsubpeer,
".."/[
beacon_node, nimbus_binary_common, networking/eth2_network,
eth1/eth1_monitor, validators/validator_duties],
../spec/datatypes/base,
../spec/[forks],
./rpc_utils
when defined(chronosFutureTracking):
import stew/base10
logScope: topics = "nimbusapi"
type
RpcServer = RpcHttpServer
FutureInfo* = object
id*: string
child_id*: string
procname*: string
filename*: string
line*: int
state*: string
proc installNimbusApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
## Install non-standard api handlers - some of these are used by 3rd-parties
## such as eth2stats, pending a full REST api
rpcServer.rpc("getBeaconHead") do () -> Slot:
return node.dag.head.slot
rpcServer.rpc("getChainHead") do () -> JsonNode:
let
head = node.dag.head
finalized = getStateField(node.dag.headState, finalized_checkpoint)
justified =
getStateField(node.dag.headState, current_justified_checkpoint)
return %* {
"head_slot": head.slot,
"head_block_root": head.root.data.toHex(),
"finalized_slot": finalized.epoch * SLOTS_PER_EPOCH,
"finalized_block_root": finalized.root.data.toHex(),
"justified_slot": justified.epoch * SLOTS_PER_EPOCH,
"justified_block_root": justified.root.data.toHex(),
}
rpcServer.rpc("getSyncing") do () -> bool:
return node.syncManager.inProgress
rpcServer.rpc("getNetworkPeerId") do () -> string:
return $node.network.peerId()
rpcServer.rpc("getNetworkPeers") do () -> seq[string]:
for peerId, peer in node.network.peerPool:
result.add $peerId
rpcServer.rpc("getNodeVersion") do () -> string:
return "Nimbus/" & fullVersionStr
rpcServer.rpc("peers") do () -> JsonNode:
var res = newJObject()
var peers = newJArray()
for id, peer in node.network.peerPool:
peers.add(
%(
id: shortLog(peer.peerId),
connectionState: $peer.connectionState,
score: peer.score,
)
)
res.add("peers", peers)
return res
rpcServer.rpc("setLogLevel") do (level: string) -> bool:
{.gcsafe.}: # It's probably not, actually. Hopefully we don't log from threads...
updateLogLevel(level)
return true
rpcServer.rpc("setGraffiti") do (graffiti: string) -> bool:
node.graffitiBytes = GraffitiBytes.init(graffiti)
return true
rpcServer.rpc("getEth1Chain") do () -> seq[Eth1Block]:
result = if node.eth1Monitor != nil:
mapIt(node.eth1Monitor.depositChainBlocks, it)
else:
@[]
rpcServer.rpc("getEth1ProposalData") do () -> BlockProposalEth1Data:
let
wallSlot = node.beaconClock.now.slotOrZero
head = node.doChecksAndGetCurrentHead(wallSlot)
let proposalState = assignClone(node.dag.headState)
node.dag.withUpdatedState(
proposalState[],
head.atSlot(wallSlot).toBlockSlotId().expect("not nil")):
return node.getBlockProposalEth1Data(state)
do:
raise (ref CatchableError)(msg: "Trying to access pruned state")
rpcServer.rpc("debug_getChronosFutures") do () -> seq[FutureInfo]:
when defined(chronosFutureTracking):
var res: seq[FutureInfo]
for item in pendingFutures():
let loc = item.location[LocCreateIndex][]
let futureId = Base10.toString(item.id)
let childId =
if isNil(item.child): ""
else: Base10.toString(item.child.id)
res.add FutureInfo(
id: futureId,
child_id: childId,
procname: $loc.procedure,
filename: $loc.file,
line: loc.line,
state: $item.state
)
return res
else:
raise (ref CatchableError)(
msg: "Compile with '-d:chronosFutureTracking' to enable this request")
rpcServer.rpc("debug_getGossipSubPeers") do () -> JsonNode:
var res = newJObject()
var gossipsub = newJObject()
proc toNode(v: PubSubPeer, backoff: Moment): JsonNode =
%(
peerId: $v.peerId,
score: v.score,
iWantBudget: v.iWantBudget,
iHaveBudget: v.iHaveBudget,
outbound: v.outbound,
appScore: v.appScore,
behaviourPenalty: v.behaviourPenalty,
sendConnAvail: v.sendConn != nil,
closed: v.sendConn != nil and v.sendConn.closed,
atEof: v.sendConn != nil and v.sendConn.atEof,
address: if v.address.isSome():
$v.address.get()
else:
"<no address>",
backoff: $(backoff - Moment.now()),
agent: when defined(libp2p_agents_metrics):
v.shortAgent
else:
"unknown",
)
for topic, v in node.network.pubsub.gossipsub:
var peers = newJArray()
let backoff = node.network.pubsub.backingOff.getOrDefault(topic)
for peer in v:
peers.add(peer.toNode(backoff.getOrDefault(peer.peerId)))
gossipsub.add(topic, peers)
res.add("gossipsub", gossipsub)
var mesh = newJObject()
for topic, v in node.network.pubsub.mesh:
var peers = newJArray()
let backoff = node.network.pubsub.backingOff.getOrDefault(topic)
for peer in v:
peers.add(peer.toNode(backoff.getOrDefault(peer.peerId)))
mesh.add(topic, peers)
res.add("mesh", mesh)
var coloc = newJArray()
for k, v in node.network.pubsub.peersInIP:
var a = newJObject()
var peers = newJArray()
for p in v:
peers.add(%($p))
a.add($k, peers)
coloc.add(a)
res.add("colocationPeers", coloc)
var stats = newJArray()
for peerId, pstats in node.network.pubsub.peerStats:
let
peer = node.network.pubsub.peers.getOrDefault(peerId)
null = isNil(peer)
connected = if null:
false
else :
peer.connected()
stats.add(%(
peerId: $peerId,
null: null,
connected: connected,
expire: $(pstats.expire - Moment.now()),
score: pstats.score
))
res.add("peerStats", stats)
var peers = newJArray()
for peerId, peer in node.network.pubsub.peers:
peers.add(%(
connected: peer.connected,
peerId: $peerId
))
res.add("allPeers", peers)
return res

View File

@ -1,256 +0,0 @@
# 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.
{.push raises: [Defect].}
import
std/[options, sequtils],
stew/byteutils,
chronicles,
json_rpc/servers/httpserver,
eth/p2p/discoveryv5/enr,
libp2p/[multiaddress, multicodec, peerstore],
../beacon_node, ../version,
../networking/[eth2_network, peer_pool],
../sync/sync_manager,
../spec/datatypes/base,
./rpc_utils
logScope: topics = "nodeapi"
type
RpcServer = RpcHttpServer
proc validateState(state: Option[seq[string]]): Option[set[ConnectionState]] =
var res: set[ConnectionState]
if state.isSome():
let states = state.get()
for item in states:
case item
of "disconnected":
if ConnectionState.Disconnected notin res:
res.incl(ConnectionState.Disconnected)
else:
# `state` values should be unique
return none(set[ConnectionState])
of "connecting":
if ConnectionState.Disconnected notin res:
res.incl(ConnectionState.Connecting)
else:
# `state` values should be unique
return none(set[ConnectionState])
of "connected":
if ConnectionState.Connected notin res:
res.incl(ConnectionState.Connected)
else:
# `state` values should be unique
return none(set[ConnectionState])
of "disconnecting":
if ConnectionState.Disconnecting notin res:
res.incl(ConnectionState.Disconnecting)
else:
# `state` values should be unique
return none(set[ConnectionState])
else:
# Found incorrect `state` string value
return none(set[ConnectionState])
if res == {}:
res = {ConnectionState.Connecting, ConnectionState.Connected,
ConnectionState.Disconnecting, ConnectionState.Disconnected}
some(res)
proc validateDirection(direction: Option[seq[string]]): Option[set[PeerType]] =
var res: set[PeerType]
if direction.isSome():
let directions = direction.get()
for item in directions:
case item
of "inbound":
if PeerType.Incoming notin res:
res.incl(PeerType.Incoming)
else:
# `direction` values should be unique
return none(set[PeerType])
of "outbound":
if PeerType.Outgoing notin res:
res.incl(PeerType.Outgoing)
else:
# `direction` values should be unique
return none(set[PeerType])
else:
# Found incorrect `direction` string value
return none(set[PeerType])
if res == {}:
res = {PeerType.Incoming, PeerType.Outgoing}
some(res)
proc toString(state: ConnectionState): string =
case state
of ConnectionState.Disconnected:
"disconnected"
of ConnectionState.Connecting:
"connecting"
of ConnectionState.Connected:
"connected"
of ConnectionState.Disconnecting:
"disconnecting"
else:
""
proc toString(direction: PeerType): string =
case direction:
of PeerType.Incoming:
"inbound"
of PeerType.Outgoing:
"outbound"
proc getLastSeenAddress(node: BeaconNode, id: PeerId): string =
# TODO (cheatfate): We need to provide filter here, which will be able to
# filter such multiaddresses like `/ip4/0.0.0.0` or local addresses or
# addresses with peer ids.
let addrs = node.network.switch.peerStore.addressBook.get(id).toSeq()
if len(addrs) > 0:
$addrs[len(addrs) - 1]
else:
""
proc getDiscoveryAddresses(node: BeaconNode): Option[seq[string]] =
let restr = node.network.enrRecord().toTypedRecord()
if restr.isErr():
return none[seq[string]]()
let respa = restr.get().toPeerAddr(udpProtocol)
if respa.isErr():
return none[seq[string]]()
let pa = respa.get()
let mpa = MultiAddress.init(multiCodec("p2p"), pa.peerId)
if mpa.isErr():
return none[seq[string]]()
var addresses = newSeqOfCap[string](len(pa.addrs))
for item in pa.addrs:
let resa = concat(item, mpa.get())
if resa.isOk():
addresses.add($(resa.get()))
return some(addresses)
proc getP2PAddresses(node: BeaconNode): Option[seq[string]] =
let pinfo = node.network.switch.peerInfo
let mpa = MultiAddress.init(multiCodec("p2p"), pinfo.peerId)
if mpa.isErr():
return none[seq[string]]()
var addresses = newSeqOfCap[string](len(pinfo.addrs))
for item in pinfo.addrs:
let resa = concat(item, mpa.get())
if resa.isOk():
addresses.add($(resa.get()))
return some(addresses)
proc installNodeApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.rpc("get_v1_node_identity") do () -> RpcNodeIdentity:
let discoveryAddresses =
block:
let res = node.getDiscoveryAddresses()
if res.isSome():
res.get()
else:
newSeq[string](0)
let p2pAddresses =
block:
let res = node.getP2PAddresses()
if res.isSome():
res.get()
else:
newSeq[string]()
return (
peer_id: $node.network.peerId(),
enr: node.network.enrRecord().toURI(),
p2p_addresses: p2pAddresses,
discovery_addresses: discoveryAddresses,
metadata: (node.network.metadata.seq_number,
to0xHex(node.network.metadata.attnets.bytes))
)
rpcServer.rpc("get_v1_node_peers") do (state: Option[seq[string]],
direction: Option[seq[string]]) -> seq[RpcNodePeer]:
var res = newSeq[RpcNodePeer]()
let rstates = validateState(state)
if rstates.isNone():
raise newException(CatchableError, "Incorrect state parameter")
let rdirs = validateDirection(direction)
if rdirs.isNone():
raise newException(CatchableError, "Incorrect direction parameter")
let states = rstates.get()
let dirs = rdirs.get()
for peer in node.network.peers.values():
if (peer.connectionState in states) and (peer.direction in dirs):
let resPeer = (
peer_id: $peer.peerId,
enr: if peer.enr.isSome(): peer.enr.get().toURI() else: "",
last_seen_p2p_address: getLastSeenAddress(node, peer.peerId),
state: peer.connectionState.toString(),
direction: peer.direction.toString(),
agent: node.network.switch.peerStore.agentBook.get(peer.peerId), # Fields `agent` and `proto` are not
proto: node.network.switch.peerStore.protoVersionBook.get(peer.peerId) # part of specification
)
res.add(resPeer)
return res
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:
inc(res.connecting)
of ConnectionState.Connected:
inc(res.connected)
of ConnectionState.Disconnecting:
inc(res.disconnecting)
of ConnectionState.Disconnected:
inc(res.disconnected)
of ConnectionState.None:
discard
return res
rpcServer.rpc("get_v1_node_peers_peerId") do (
peer_id: string) -> RpcNodePeer:
let pres = PeerId.init(peer_id)
if pres.isErr():
raise newException(CatchableError,
"The peer ID supplied could not be parsed")
let pid = pres.get()
let peer = node.network.peers.getOrDefault(pid)
if isNil(peer):
raise newException(CatchableError, "Peer not found")
return (
peer_id: $peer.peerId,
enr: if peer.enr.isSome(): peer.enr.get().toURI() else: "",
last_seen_p2p_address: getLastSeenAddress(node, peer.peerId),
state: peer.connectionState.toString(),
direction: peer.direction.toString(),
agent: node.network.switch.peerStore.agentBook.get(peer.peerId), # Fields `agent` and `proto` are not
proto: node.network.switch.peerStore.protoVersionBook.get(peer.peerId) # part of specification
)
rpcServer.rpc("get_v1_node_version") do () -> JsonNode:
return %*{"version": "Nimbus/" & fullVersionStr}
rpcServer.rpc("get_v1_node_syncing") do () -> RpcSyncInfo:
return node.syncManager.getInfo()
rpcServer.rpc("get_v1_node_health") do () -> JsonNode:
# TODO: There currently no way to situation when we node has issues, so
# its impossible to return HTTP ERROR 503 according to specification.
if node.syncManager.inProgress:
# We need to return HTTP ERROR 206 according to specification
return %*{"health": 206}
else:
return %*{"health": 200}

View File

@ -1,111 +0,0 @@
# 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.
{.push raises: [Defect].}
import
std/[strutils, parseutils],
stew/byteutils,
../beacon_node, ../validators/validator_duties,
../consensus_object_pools/[block_pools_types, blockchain_dag],
../spec/datatypes/base,
../spec/[forks, helpers],
../spec/eth2_apis/[rpc_types, eth2_json_rpc_serialization]
export forks, rpc_types, eth2_json_rpc_serialization, blockchain_dag
template raiseNoAltairSupport*() =
raise (ref ValueError)(msg:
"The JSON-RPC interface does not support certain Altair operations due to changes in block structure - see https://nimbus.guide/rest-api.html for full altair support")
template withStateForStateId*(stateId: string, body: untyped): untyped =
let
bsi = node.stateIdToBlockSlotId(stateId)
template isState(state: ForkedHashedBeaconState): bool =
state.matches_block_slot(bsi.bid.root, bsi.slot)
if isState(node.dag.headState):
withStateVars(node.dag.headState):
var cache {.inject, used.}: StateCache
body
else:
let rpcState = assignClone(node.dag.headState)
node.dag.withUpdatedState(rpcState[], bsi) do:
body
do:
raise (ref CatchableError)(msg: "Trying to access pruned state")
proc parseRoot*(str: string): Eth2Digest {.raises: [Defect, ValueError].} =
Eth2Digest(data: hexToByteArray[32](str))
func checkEpochToSlotOverflow*(epoch: Epoch) {.raises: [Defect, ValueError].} =
const maxEpoch = epoch(FAR_FUTURE_SLOT)
if epoch >= maxEpoch:
raise newException(
ValueError, "Requesting epoch for which slot would overflow")
proc doChecksAndGetCurrentHead*(node: BeaconNode, slot: Slot): BlockRef {.raises: [Defect, CatchableError].} =
result = node.dag.head
if not node.isSynced(result):
raise newException(CatchableError, "Cannot fulfill request until node is synced")
# TODO for now we limit the requests arbitrarily by up to 2 epochs into the future
if result.slot + uint64(2 * SLOTS_PER_EPOCH) < slot:
raise newException(CatchableError, "Requesting way ahead of the current head")
proc doChecksAndGetCurrentHead*(node: BeaconNode, epoch: Epoch): BlockRef {.raises: [Defect, CatchableError].} =
checkEpochToSlotOverflow(epoch)
node.doChecksAndGetCurrentHead(epoch.start_slot())
proc parseSlot(slot: string): Slot {.raises: [Defect, CatchableError].} =
if slot.len == 0:
raise newException(ValueError, "Empty slot number not allowed")
var parsed: BiggestUInt
if parseBiggestUInt(slot, parsed) != slot.len:
raise newException(ValueError, "Not a valid slot number")
Slot parsed
proc getBlockSlotIdFromString*(node: BeaconNode, slot: string): BlockSlotId {.raises: [Defect, CatchableError].} =
let parsed = parseSlot(slot)
discard node.doChecksAndGetCurrentHead(parsed)
node.dag.getBlockIdAtSlot(parsed).valueOr:
raise newException(ValueError, "Block not found")
proc getBlockIdFromString*(node: BeaconNode, slot: string): BlockId {.raises: [Defect, CatchableError].} =
let parsed = parseSlot(slot)
discard node.doChecksAndGetCurrentHead(parsed)
let bsid = node.dag.getBlockIdAtSlot(parsed)
if bsid.isSome and bsid.get.isProposed():
bsid.get().bid
else:
raise (ref ValueError)(msg: "Block not found")
proc stateIdToBlockSlotId*(node: BeaconNode, stateId: string): BlockSlotId {.raises: [Defect, CatchableError].} =
case stateId:
of "head":
node.dag.head.bid.atSlot()
of "genesis":
node.dag.genesis.atSlot()
of "finalized":
node.dag.finalizedHead.toBlockSlotId().expect("not nil")
of "justified":
node.dag.head.atEpochStart(
getStateField(
node.dag.headState, current_justified_checkpoint).epoch).
toBlockSlotId().valueOr:
raise (ref ValueError)(msg: "State not found")
else:
if stateId.startsWith("0x"):
let stateRoot = parseRoot(stateId)
if stateRoot == getStateRoot(node.dag.headState):
node.dag.head.bid.atSlot()
else:
# We don't have a state root -> BlockSlot mapping
raise (ref ValueError)(msg: "State not found")
else: # Parse as slot number
node.getBlockSlotIdFromString(stateId)

View File

@ -1,170 +0,0 @@
# 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.
{.push raises: [Defect].}
import
# Standard library
std/tables,
# Nimble packages
stew/objects,
json_rpc/servers/httpserver,
chronicles,
# Local modules
../spec/[forks, helpers, network, signatures],
../spec/datatypes/phase0,
../spec/eth2_apis/rpc_types,
../consensus_object_pools/[blockchain_dag, spec_cache, attestation_pool],
../beacon_node,
../validators/validator_duties,
../networking/eth2_network,
./rpc_utils
logScope: topics = "valapi"
type
RpcServer* = RpcHttpServer
proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) {.
raises: [Defect, CatchableError].} =
rpcServer.rpc("get_v1_validator_block") do (
slot: Slot, graffiti: GraffitiBytes, randao_reveal: ValidatorSig) -> phase0.BeaconBlock:
debug "get_v1_validator_block", slot = slot
let head = node.doChecksAndGetCurrentHead(slot)
let proposer = node.dag.getProposer(head, slot)
if proposer.isNone():
raise newException(CatchableError,
"could not retrieve block for slot: " & $slot)
let res = await makeBeaconBlockForHeadAndSlot(
node, randao_reveal, proposer.get(), graffiti, head, slot)
if res.isErr():
raise newException(CatchableError, res.error())
let blck = res.get()
case blck.kind
of BeaconBlockFork.Phase0:
return blck.phase0Data
else:
raiseNoAltairSupport()
rpcServer.rpc("get_v1_validator_attestation_data") do (
slot: Slot, committee_index: CommitteeIndex) -> AttestationData:
debug "get_v1_validator_attestation_data", slot = slot
let
head = node.doChecksAndGetCurrentHead(slot)
epochRef = block:
let tmp = node.dag.getEpochRef(head, slot.epoch, true)
if isErr(tmp):
raise (ref CatchableError)(msg: "Trying to access pruned state")
tmp.get()
return makeAttestationData(epochRef, head.atSlot(slot), committee_index)
rpcServer.rpc("get_v1_validator_aggregate_attestation") do (
slot: Slot, attestation_data_root: Eth2Digest)-> Attestation:
debug "get_v1_validator_aggregate_attestation"
let res = node.attestationPool[].getAggregatedAttestation(slot, attestation_data_root)
if res.isSome:
return res.get
raise newException(CatchableError, "Could not retrieve an aggregated attestation")
rpcServer.rpc("post_v1_validator_aggregate_and_proofs") do (
payload: SignedAggregateAndProof) -> bool:
debug "post_v1_validator_aggregate_and_proofs"
return (await node.sendAggregateAndProof(payload)).isOk()
rpcServer.rpc("get_v1_validator_duties_attester") do (
epoch: Epoch, public_keys: seq[ValidatorPubKey]) -> seq[RpcAttesterDuties]:
debug "get_v1_validator_duties_attester", epoch = epoch
let
head = node.doChecksAndGetCurrentHead(epoch)
epochRef = block:
let tmp = node.dag.getEpochRef(head, epoch, true)
if isErr(tmp):
raise (ref CatchableError)(msg: "Trying to access pruned state")
tmp.get()
let
committees_per_slot = get_committee_count_per_slot(epochRef)
for slot in epoch.slots():
for committee_index in get_committee_indices(committees_per_slot):
let committee = get_beacon_committee(epochRef, slot, committee_index)
for index_in_committee, validator_index in committee:
let curr_val_pubkey = epochRef.validatorKey(validator_index)
if curr_val_pubkey.isSome():
if public_keys.findIt(it == curr_val_pubkey.get().toPubKey()) != -1:
result.add((public_key: curr_val_pubkey.get().toPubKey(),
validator_index: validator_index,
committee_index: committee_index,
committee_length: committee.lenu64,
validator_committee_index: index_in_committee.uint64,
slot: slot))
rpcServer.rpc("get_v1_validator_duties_proposer") do (
epoch: Epoch) -> seq[RpcValidatorDuties]:
debug "get_v1_validator_duties_proposer", epoch = epoch
let
head = node.doChecksAndGetCurrentHead(epoch)
epochRef = block:
let tmp = node.dag.getEpochRef(head, epoch, true)
if isErr(tmp):
raise (ref CatchableError)(msg: "Trying to access pruned state")
tmp.get()
for i, bp in epochRef.beacon_proposers:
if bp.isSome():
result.add((public_key: epochRef.validatorKey(bp.get).get().toPubKey,
validator_index: bp.get(),
slot: epoch.start_slot() + i))
rpcServer.rpc("post_v1_validator_beacon_committee_subscriptions") do (
committee_index: CommitteeIndex, slot: Slot, aggregator: bool,
validator_pubkey: ValidatorPubKey, slot_signature: ValidatorSig) -> bool:
debug "post_v1_validator_beacon_committee_subscriptions",
committee_index, slot
if committee_index.uint64 >= MAX_COMMITTEES_PER_SLOT.uint64:
raise newException(CatchableError,
"Invalid committee index")
if node.syncManager.inProgress:
raise newException(CatchableError,
"Beacon node is currently syncing and not serving request on that endpoint")
let wallSlot = node.beaconClock.now.slotOrZero
if wallSlot > slot + 1:
raise newException(CatchableError,
"Past slot requested")
let epoch = slot.epoch
if epoch >= wallSlot.epoch and epoch - wallSlot.epoch > 1:
raise newException(CatchableError,
"Slot requested not in current or next wall-slot epoch")
if not verify_slot_signature(
getStateField(node.dag.headState, fork),
getStateField(node.dag.headState, genesis_validators_root),
slot, validator_pubkey, slot_signature):
raise newException(CatchableError,
"Invalid slot signature")
let
head = node.doChecksAndGetCurrentHead(epoch)
epochRef = block:
let tmp = node.dag.getEpochRef(head, epoch, true)
if isErr(tmp):
raise (ref CatchableError)(msg: "Trying to access pruned state")
tmp.get()
let
subnet_id = compute_subnet_for_attestation(
get_committee_count_per_slot(epochRef), slot, committee_index)
# The validator index here is invalid, but since JSON-RPC is on its way
# to deprecation, this is fine
node.registerDuty(
slot, subnet_id, 0.ValidatorIndex,
is_aggregator(epochRef, slot, committee_index, slot_signature))

View File

@ -37,9 +37,6 @@ const
defaultEth2TcpPort* = 9000
# This is not part of the spec yet! Keep in sync with BASE_RPC_PORT
defaultEth2RpcPort* = 9190
# This is not part of the spec! But its port which uses Lighthouse
DefaultEth2RestPort* = 5052