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:
parent
1101c745b9
commit
d35d408fa7
|
@ -53,7 +53,6 @@ type
|
|||
lightClientPool*: ref LightClientPool
|
||||
exitPool*: ref ExitPool
|
||||
eth1Monitor*: Eth1Monitor
|
||||
rpcServer*: RpcServer
|
||||
restServer*: RestServerRef
|
||||
keymanagerServer*: RestServerRef
|
||||
keymanagerToken*: Option[string]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||
}
|
|
@ -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))
|
|
@ -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()
|
|
@ -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
|
|
@ -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}
|
|
@ -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)
|
|
@ -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))
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue