Implement #3129 (Optimized history traversals in the REST API) (#3219)

* Fix REST some rest call signatures and implement a simple API benchmark tool

* Implement #3129 (Optimized history traversals in the REST API)

Other notable changes:

The `updateStateData` procedure in the `blockchain_dag.nim` module is
optimized to not rewind down to the last snapshot state saved in the
database if the supplied input state can be used as a starting point
instead.

* Disallow await in withStateForBlockSlot
This commit is contained in:
zah 2022-01-05 16:49:10 +02:00 committed by GitHub
parent 5878d34117
commit fba1f08a5e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 339 additions and 97 deletions

View File

@ -23,7 +23,8 @@ import
sync_committee_msg_pool], sync_committee_msg_pool],
./spec/datatypes/base, ./spec/datatypes/base,
./sync/[sync_manager, request_manager], ./sync/[sync_manager, request_manager],
./validators/[action_tracker, validator_monitor, validator_pool] ./validators/[action_tracker, validator_monitor, validator_pool],
./rpc/state_ttl_cache
export export
osproc, chronos, httpserver, presto, action_tracker, beacon_clock, osproc, chronos, httpserver, presto, action_tracker, beacon_clock,
@ -70,6 +71,7 @@ type
onAttestationSent*: OnAttestationCallback onAttestationSent*: OnAttestationCallback
restKeysCache*: Table[ValidatorPubKey, ValidatorIndex] restKeysCache*: Table[ValidatorPubKey, ValidatorIndex]
validatorMonitor*: ref ValidatorMonitor validatorMonitor*: ref ValidatorMonitor
stateTtlCache*: StateTtlCache
const const
MaxEmptySlotCount* = uint64(10*60) div SECONDS_PER_SLOT MaxEmptySlotCount* = uint64(10*60) div SECONDS_PER_SLOT

View File

@ -328,6 +328,18 @@ type
defaultValueDesc: "127.0.0.1" defaultValueDesc: "127.0.0.1"
name: "rest-address" }: ValidIpAddress name: "rest-address" }: ValidIpAddress
restCacheSize* {.
defaultValue: 3
desc: "The maximum number of recently accessed states that are kept in " &
"memory. Speeds up requests obtaining information for consecutive " &
"slots or epochs."
name: "rest-statecache-size" }: Natural
restCacheTtl* {.
defaultValue: 60
desc: "The number of seconds to keep recently accessed states in memory"
name: "rest-statecache-ttl" }: Natural
keymanagerEnabled* {. keymanagerEnabled* {.
desc: "Enable the REST keymanager API (BETA version)" desc: "Enable the REST keymanager API (BETA version)"
defaultValue: false defaultValue: false

View File

@ -609,6 +609,7 @@ proc getEpochRef*(dag: ChainDAGRef, blck: BlockRef, epoch: Epoch): EpochRef =
let let
ancestor = epochAncestor(blck, epoch) ancestor = epochAncestor(blck, epoch)
dag.epochRefState.blck = BlockRef()
dag.withState( dag.withState(
dag.epochRefState, ancestor.blck.atEpochStart(ancestor.epoch)): dag.epochRefState, ancestor.blck.atEpochStart(ancestor.epoch)):
dag.getEpochRef(stateData, cache) dag.getEpochRef(stateData, cache)
@ -944,8 +945,10 @@ proc updateStateData*(
# Look for a state in the database and load it - as long as it cannot be # Look for a state in the database and load it - as long as it cannot be
# found, keep track of the blocks that are needed to reach it from the # found, keep track of the blocks that are needed to reach it from the
# state that eventually will be found # state that eventually will be found. Besides finding the state in the
while not dag.getState(state, cur): # database we may also reach the input state provided to the function.
# It can also act as a viable starting point for the block replay later.
while not canAdvance(state, cur) and not dag.getState(state, cur):
# There's no state saved for this particular BlockSlot combination, keep # There's no state saved for this particular BlockSlot combination, keep
# looking... # looking...
if cur.slot == cur.blck.slot: if cur.slot == cur.blck.slot:

View File

@ -34,7 +34,7 @@ import
validator_duties, validator_monitor, validator_pool, validator_duties, validator_monitor, validator_pool,
slashing_protection, keystore_management], slashing_protection, keystore_management],
./sync/[sync_protocol], ./sync/[sync_protocol],
./rpc/[rest_api, rpc_api], ./rpc/[rest_api, rpc_api, state_ttl_cache],
./spec/datatypes/[altair, merge, phase0], ./spec/datatypes/[altair, merge, phase0],
./spec/eth2_apis/rpc_beacon_client, ./spec/eth2_apis/rpc_beacon_client,
./spec/[ ./spec/[
@ -469,6 +469,13 @@ proc init*(T: type BeaconNode,
network.peerPool, SyncQueueKind.Forward, getLocalHeadSlot, getLocalWallSlot, network.peerPool, SyncQueueKind.Forward, getLocalHeadSlot, getLocalWallSlot,
getFirstSlotAtFinalizedEpoch, getBackfillSlot, blockVerifier) getFirstSlotAtFinalizedEpoch, getBackfillSlot, blockVerifier)
let stateTtlCache = if config.restCacheSize > 0:
StateTtlCache.init(
cacheSize = config.restCacheSize,
cacheTtl = chronos.seconds(config.restCacheTtl))
else:
nil
var node = BeaconNode( var node = BeaconNode(
nickname: nickname, nickname: nickname,
graffitiBytes: if config.graffiti.isSome: config.graffiti.get graffitiBytes: if config.graffiti.isSome: config.graffiti.get
@ -498,7 +505,8 @@ proc init*(T: type BeaconNode,
gossipState: {}, gossipState: {},
beaconClock: beaconClock, beaconClock: beaconClock,
onAttestationSent: onAttestationSent, onAttestationSent: onAttestationSent,
validatorMonitor: validatorMonitor validatorMonitor: validatorMonitor,
stateTtlCache: stateTtlCache
) )
debug "Loading validators", validatorsDir = config.validatorsDir() debug "Loading validators", validatorsDir = config.validatorsDir()

View File

@ -15,7 +15,8 @@ import
../consensus_object_pools/[blockchain_dag, exit_pool, spec_cache], ../consensus_object_pools/[blockchain_dag, exit_pool, spec_cache],
../validators/validator_duties, ../validators/validator_duties,
../spec/[eth2_merkleization, forks, network, validator], ../spec/[eth2_merkleization, forks, network, validator],
../spec/datatypes/[phase0, altair] ../spec/datatypes/[phase0, altair],
./state_ttl_cache
export rest_utils export rest_utils

View File

@ -9,7 +9,7 @@ import std/sequtils
import chronicles import chronicles
import ".."/[version, beacon_node], import ".."/[version, beacon_node],
".."/spec/forks, ".."/spec/forks,
"."/rest_utils "."/[rest_utils, state_ttl_cache]
export rest_utils export rest_utils

View File

@ -1,11 +1,11 @@
import std/options, import std/[options, macros],
presto, presto,
nimcrypto/utils as ncrutils, nimcrypto/utils as ncrutils,
../spec/[forks], ../spec/[forks],
../spec/eth2_apis/[rest_types, eth2_rest_serialization], ../spec/eth2_apis/[rest_types, eth2_rest_serialization],
../beacon_node, ../beacon_node,
../consensus_object_pools/blockchain_dag, ../consensus_object_pools/blockchain_dag,
./rest_constants "."/[rest_constants, state_ttl_cache]
export export
options, eth2_rest_serialization, blockchain_dag, presto, rest_types, options, eth2_rest_serialization, blockchain_dag, presto, rest_types,
@ -116,19 +116,77 @@ proc getBlockDataFromBlockIdent*(node: BeaconNode,
id: BlockIdent): Result[BlockData, cstring] = id: BlockIdent): Result[BlockData, cstring] =
ok(node.dag.get(? node.getBlockRef(id))) ok(node.dag.get(? node.getBlockRef(id)))
template withStateForBlockSlot*(node: BeaconNode, proc disallowInterruptionsAux(body: NimNode) =
blockSlot: BlockSlot, body: untyped): untyped = for n in body:
template isState(state: StateData): bool = const because =
state.blck.atSlot(getStateField(state.data, slot)) == blockSlot "because the `state` variable may be mutated (and thus invalidated) " &
"before the function resumes execution."
if isState(node.dag.headState): if n.kind == nnkYieldStmt:
withStateVars(node.dag.headState): macros.error "You cannot use yield in this block " & because, n
var cache {.inject, used.}: StateCache
body if (n.kind in {nnkCall, nnkCommand} and
else: n[0].kind in {nnkIdent, nnkSym} and
let rpcState = assignClone(node.dag.headState) $n[0] == "await"):
node.dag.withState(rpcState[], blockSlot): macros.error "You cannot use await in this block " & because, n
body
disallowInterruptionsAux(n)
macro disallowInterruptions(body: untyped) =
disallowInterruptionsAux(body)
template withStateForBlockSlot*(nodeParam: BeaconNode,
blockSlotParam: BlockSlot,
body: untyped): untyped =
block:
let
node = nodeParam
blockSlot = blockSlotParam
template isState(state: StateData): bool =
state.blck.atSlot(getStateField(state.data, slot)) == blockSlot
var cache {.inject, used.}: StateCache
# If we have a cache hit, there is a concern that the REST request
# handler may continue executing asynchronously while we hit the same
# advanced state is another request. We don't want the two requests
# to work over the same state object because mutations to it will be
# visible in both, so we must outlaw yielding within the `body` block.
# Please note that the problem is not limited to the situations where
# we have a cache hit. Working with the `headState` will result in the
# same problem as it may change while the request is executing.
#
# TODO
# The solution below is only partion, because it theory yields or awaits
# can still be hidden in the body through the use of helper templates
disallowInterruptions(body)
# TODO view-types
# Avoid the code bloat produced by the double `body` reference through a lent var
if isState(node.dag.headState):
withStateVars(node.dag.headState):
body
else:
let cachedState = if node.stateTtlCache != nil:
node.stateTtlCache.getClosestState(blockSlot)
else:
nil
let stateToAdvance = if cachedState != nil:
cachedState
else:
assignClone(node.dag.headState)
node.dag.updateStateData(stateToAdvance[], blockSlot, false, cache)
if cachedState == nil and node.stateTtlCache != nil:
# This was not a cached state, we can cache it now
node.stateTtlCache.add(stateToAdvance)
withStateVars(stateToAdvance[]):
body
proc toValidatorIndex*(value: RestValidatorIndex): Result[ValidatorIndex, proc toValidatorIndex*(value: RestValidatorIndex): Result[ValidatorIndex,
ValidatorIndexError] = ValidatorIndexError] =

View File

@ -6,14 +6,14 @@
import std/[typetraits, strutils, sets] import std/[typetraits, strutils, sets]
import stew/[results, base10], chronicles, import stew/[results, base10], chronicles,
nimcrypto/utils as ncrutils nimcrypto/utils as ncrutils
import "."/rest_utils, import ".."/[beacon_chain_db, beacon_node],
".."/[beacon_chain_db, beacon_node],
".."/networking/eth2_network, ".."/networking/eth2_network,
".."/consensus_object_pools/[blockchain_dag, spec_cache, ".."/consensus_object_pools/[blockchain_dag, spec_cache,
attestation_pool, sync_committee_msg_pool], attestation_pool, sync_committee_msg_pool],
".."/validators/validator_duties, ".."/validators/validator_duties,
".."/spec/[beaconstate, forks, network], ".."/spec/[beaconstate, forks, network],
".."/spec/datatypes/[phase0, altair] ".."/spec/datatypes/[phase0, altair],
"."/[rest_utils, state_ttl_cache]
export rest_utils export rest_utils

View File

@ -0,0 +1,110 @@
# 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.
import
chronos,
chronicles,
../consensus_object_pools/block_pools_types
type
CacheEntry = ref object
state: ref StateData
lastUsed: Moment
# This is ref object because we need to capture it by
# reference in the `scheduleEntryExpiration` function.
StateTtlCache* = ref object
entries: seq[CacheEntry]
ttl: Duration
const
slotDifferenceForCacheHit = 5 * SLOTS_PER_EPOCH
logScope:
topics = "state_ttl_cache"
proc init*(T: type StateTtlCache,
cacheSize: Natural,
cacheTtl: Duration): T =
doAssert cacheSize > 0
StateTtlCache(
entries: newSeq[CacheEntry](cacheSize),
ttl: cacheTtl)
proc scheduleEntryExpiration(cache: StateTtlCache,
entryIdx: int) =
proc removeElement(arg: pointer) =
if cache.entries[entryIdx] == nil:
return
let expirationTime = cache.entries[entryIdx].lastUsed + cache.ttl
if expirationTime > Moment.now:
return
cache.entries[entryIdx] = nil
debug "Cached REST state expired", index = entryIdx
discard setTimer(Moment.now + cache.ttl, removeElement)
proc add*(cache: StateTtlCache, state: ref StateData) =
var
now = Moment.now
lruTime = now
index = -1
for i in 0 ..< cache.entries.len:
if cache.entries[i] == nil:
index = i
break
if cache.entries[i].lastUsed <= lruTime:
index = i
lruTime = cache.entries[i].lastUsed
doAssert index != -1
cache.entries[index] = CacheEntry(state: state, lastUsed: now)
debug "Cached REST state added", index = index
cache.scheduleEntryExpiration(index)
proc getClosestState*(cache: StateTtlCache, bs: BlockSlot): ref StateData =
var
bestSlotDifference = Slot.high
index = -1
for i in 0 ..< cache.entries.len:
if cache.entries[i] == nil:
continue
let stateSlot = getStateField(cache.entries[i].state.data, slot)
if stateSlot > bs.slot:
# We can use only states that can be advanced forward in time.
continue
let slotDifference = bs.slot - stateSlot
if slotDifference > slotDifferenceForCacheHit:
# The state is too old to be useful as a rewind starting point.
continue
var cur = bs
for j in 0 ..< slotDifference:
cur = cur.parentOrSlot
if cur.blck != cache.entries[i].state.blck:
# The cached state and the requested BlockSlot are at different branches
# of history.
continue
if slotDifference < bestSlotDifference:
bestSlotDifference = slotDifference.Slot
index = i
if index == -1:
return nil
cache.entries[index].lastUsed = Moment.now
cache.scheduleEntryExpiration(index)
return cache.entries[index].state

View File

@ -61,18 +61,17 @@ proc getStateValidatorBalances*(state_id: StateIdent
meth: MethodGet.} meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidators ## https://ethereum.github.io/beacon-APIs/#/Beacon/getStateValidators
proc getEpochCommittees*(state_id: StateIdent proc getEpochCommittees*(state_id: StateIdent, epoch: Option[Epoch],
): RestResponse[GetEpochCommitteesResponse] {. ): RestResponse[GetEpochCommitteesResponse] {.
rest, endpoint: "/eth/v1/beacon/states/{state_id}/committees", rest, endpoint: "/eth/v1/beacon/states/{state_id}/committees",
meth: MethodGet.} meth: MethodGet.}
## https://ethereum.github.io/beacon-APIs/#/Beacon/getEpochCommittees ## https://ethereum.github.io/beacon-APIs/#/Beacon/getEpochCommittees
# TODO altair proc getEpochSyncCommittees*(state_id: StateIdent, epoch: Option[Epoch],
# proc getEpochSyncCommittees*(state_id: StateIdent ): RestResponse[GetEpochSyncCommitteesResponse] {.
# ): RestResponse[GetEpochSyncCommitteesResponse] {. rest, endpoint: "/eth/v1/beacon/states/{state_id}/sync_committees",
# rest, endpoint: "/eth/v1/beacon/states/{state_id}/sync_committees", meth: MethodGet.}
# meth: MethodGet.} ## https://ethereum.github.io/beacon-APIs/#/Beacon/getEpochSyncCommittees
# ## https://ethereum.github.io/beacon-APIs/#/Beacon/getEpochSyncCommittees
proc getBlockHeaders*(slot: Option[Slot], parent_root: Option[Eth2Digest] proc getBlockHeaders*(slot: Option[Slot], parent_root: Option[Eth2Digest]
): RestResponse[GetBlockHeadersResponse] {. ): RestResponse[GetBlockHeadersResponse] {.

View File

@ -219,6 +219,7 @@ type
RestMetadata* = object RestMetadata* = object
seq_number*: string seq_number*: string
syncnets*: string
attnets*: string attnets*: string
RestNetworkIdentity* = object RestNetworkIdentity* = object
@ -502,16 +503,19 @@ type
GetPhase0BlockSszResponse* = phase0.SignedBeaconBlock GetPhase0BlockSszResponse* = phase0.SignedBeaconBlock
GetAltairBlockSszResponse* = altair.SignedBeaconBlock GetAltairBlockSszResponse* = altair.SignedBeaconBlock
RestRoot* = object
root*: Eth2Digest
# Types based on the OAPI yaml file - used in responses to requests # Types based on the OAPI yaml file - used in responses to requests
GetAggregatedAttestationResponse* = DataEnclosedObject[Attestation] GetAggregatedAttestationResponse* = DataEnclosedObject[Attestation]
GetAttesterDutiesResponse* = DataRootEnclosedObject[seq[RestAttesterDuty]] GetAttesterDutiesResponse* = DataRootEnclosedObject[seq[RestAttesterDuty]]
GetBlockAttestationsResponse* = DataEnclosedObject[seq[Attestation]] GetBlockAttestationsResponse* = DataEnclosedObject[seq[Attestation]]
GetBlockHeaderResponse* = DataEnclosedObject[RestBlockHeaderInfo] GetBlockHeaderResponse* = DataEnclosedObject[RestBlockHeaderInfo]
GetBlockHeadersResponse* = DataEnclosedObject[seq[RestBlockHeaderInfo]] GetBlockHeadersResponse* = DataEnclosedObject[seq[RestBlockHeaderInfo]]
GetBlockRootResponse* = DataEnclosedObject[Eth2Digest] GetBlockRootResponse* = DataEnclosedObject[RestRoot]
GetDebugChainHeadsResponse* = DataEnclosedObject[seq[RestChainHead]] GetDebugChainHeadsResponse* = DataEnclosedObject[seq[RestChainHead]]
GetDepositContractResponse* = DataEnclosedObject[RestDepositContract] GetDepositContractResponse* = DataEnclosedObject[RestDepositContract]
GetEpochCommitteesResponse* = DataEnclosedObject[RestGenesis] GetEpochCommitteesResponse* = DataEnclosedObject[seq[RestBeaconStatesCommittees]]
GetForkScheduleResponse* = DataEnclosedObject[seq[Fork]] GetForkScheduleResponse* = DataEnclosedObject[seq[Fork]]
GetGenesisResponse* = DataEnclosedObject[RestGenesis] GetGenesisResponse* = DataEnclosedObject[RestGenesis]
GetNetworkIdentityResponse* = DataEnclosedObject[RestNetworkIdentity] GetNetworkIdentityResponse* = DataEnclosedObject[RestNetworkIdentity]
@ -528,7 +532,7 @@ type
GetSpecVCResponse* = DataEnclosedObject[RestSpecVC] GetSpecVCResponse* = DataEnclosedObject[RestSpecVC]
GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints] GetStateFinalityCheckpointsResponse* = DataEnclosedObject[RestBeaconStatesFinalityCheckpoints]
GetStateForkResponse* = DataEnclosedObject[Fork] GetStateForkResponse* = DataEnclosedObject[Fork]
GetStateRootResponse* = DataEnclosedObject[Eth2Digest] GetStateRootResponse* = DataEnclosedObject[RestRoot]
GetStateValidatorBalancesResponse* = DataEnclosedObject[seq[RestValidatorBalance]] GetStateValidatorBalancesResponse* = DataEnclosedObject[seq[RestValidatorBalance]]
GetStateValidatorResponse* = DataEnclosedObject[RestValidator] GetStateValidatorResponse* = DataEnclosedObject[RestValidator]
GetStateValidatorsResponse* = DataEnclosedObject[seq[RestValidator]] GetStateValidatorsResponse* = DataEnclosedObject[seq[RestValidator]]

View File

@ -0,0 +1,54 @@
import
chronicles, chronicles/[topics_registry, timings],
confutils, confutils/std/net,
../beacon_chain/spec/eth2_apis/rest_beacon_client
type
Config = object
serverIpAddress {.
defaultValue: ValidIpAddress.init("127.0.0.1")
defaultValueDesc: "127.0.0.1"
desc: "IP address of the beacon node's REST server"
abbr: "a"
name: "address" }: ValidIpAddress
serverPort {.
defaultValue: 5052
desc: "Listening port of the beacon node's REST server"
abbr: "p"
name: "port" }: Port
startSlot {.
defaultValue: 0
desc: "The starting slot from which to start history traversal"
abbr: "s"
name: "start-slot" }: uint
requestsCount {.
desc: "Number of requests to send to the beacon node's REST server"
abbr: "n"
name: "count" }: uint
proc main =
let config = Config.load
let serverAddress = initTAddress(config.serverIpAddress, config.serverPort)
let client = RestClientRef.new(serverAddress)
setLogLevel(LogLevel.INFO)
template benchmark(apiNameIdent: untyped): untyped {.dirty.} =
block:
const apiName = astToStr apiNameIdent
info "Benchmarking ...", apiName
info.logTime(apiName):
for slot in config.startSlot ..< (config.startSlot + config.requestsCount):
let ident = StateIdent(kind: StateQueryKind.Slot, slot: slot.Slot)
discard waitFor client.`apiNameIdent`(ident)
benchmark(getStateRoot)
benchmark(getStateFork)
benchmark(getStateFinalityCheckpoints)
benchmark(getStateValidatorBalances)
when isMainModule:
main()

View File

@ -0,0 +1,2 @@
-d:"chronicles_runtime_filtering=on"
-d:"chronicles_disable_thread_id"

View File

@ -21,61 +21,45 @@ nimbus_beacon_node [OPTIONS]... command
The following options are available: The following options are available:
--log-level Sets the log level for process and topics (e.g. "DEBUG; --log-level Sets the log level for process and topics (e.g. "DEBUG; TRACE:discv5,libp2p;
TRACE:discv5,libp2p; REQUIRED:none; DISABLED:none") [=INFO]. REQUIRED:none; DISABLED:none") [=INFO].
--log-format Specifies what kind of logs should be written to stdout (beta) --log-file Specifies a path for the written Json log file (deprecated).
(auto, colors, nocolors, json) [=auto].
--log-file Specifies a path for the written Json log file.
--network The Eth2 network to join [=mainnet]. --network The Eth2 network to join [=mainnet].
-d, --data-dir The directory where nimbus will store all blockchain data. -d, --data-dir The directory where nimbus will store all blockchain data.
--validators-dir A directory containing validator keystores. --validators-dir A directory containing validator keystores.
--secrets-dir A directory containing validator keystore passwords. --secrets-dir A directory containing validator keystore passwords.
--wallets-dir A directory containing wallet files. --wallets-dir A directory containing wallet files.
--web3-url One or more Web3 provider URLs used for obtaining deposit --web3-url One or more Web3 provider URLs used for obtaining deposit contract data.
contract data. --non-interactive Do not display interative prompts. Quit on missing configuration.
--non-interactive Do not display interative prompts. Quit on missing --netkey-file Source of network (secp256k1) private key file (random|<path>) [=random].
configuration. --insecure-netkey-password Use pre-generated INSECURE password for network private key file [=false].
--netkey-file Source of network (secp256k1) private key file --agent-string Node agent string which is used as identifier in network [=nimbus].
(random|<path>) [=random]. --subscribe-all-subnets Subscribe to all attestation subnet topics when gossiping [=false].
--insecure-netkey-password Use pre-generated INSECURE password for network private key --num-threads Number of worker threads (set this to 0 to use as many threads as there are CPU
file [=false]. cores available) [=1].
--agent-string Node agent string which is used as identifier in network -b, --bootstrap-node Specifies one or more bootstrap nodes to use when connecting to the network.
[=nimbus]. --bootstrap-file Specifies a line-delimited file of bootstrap Ethereum network addresses.
--subscribe-all-subnets Subscribe to all attestation subnet topics when gossiping --listen-address Listening address for the Ethereum LibP2P and Discovery v5 traffic [=0.0.0.0].
[=false].
--num-threads Number of worker threads (set this to 0 to use as many
threads as there are CPU cores available) [=1].
-b, --bootstrap-node Specifies one or more bootstrap nodes to use when connecting
to the network.
--bootstrap-file Specifies a line-delimited file of bootstrap Ethereum network
addresses.
--listen-address Listening address for the Ethereum LibP2P and Discovery v5
traffic [=0.0.0.0].
--tcp-port Listening TCP port for Ethereum LibP2P traffic [=9000]. --tcp-port Listening TCP port for Ethereum LibP2P traffic [=9000].
--udp-port Listening UDP port for node discovery [=9000]. --udp-port Listening UDP port for node discovery [=9000].
--max-peers The maximum number of peers to connect to [=160]. --max-peers The maximum number of peers to connect to [=160].
--nat Specify method to use for determining public address. Must be --nat Specify method to use for determining public address. Must be one of: any, none,
one of: any, none, upnp, pmp, extip:<IP> [=any]. upnp, pmp, extip:<IP> [=any].
--enr-auto-update Discovery can automatically update its ENR with the IP --enr-auto-update Discovery can automatically update its ENR with the IP address and UDP port as
address and UDP port as seen by other nodes it communicates seen by other nodes it communicates with. This option allows to enable/disable
with. This option allows to enable/disable this functionality this functionality [=false].
[=false]. --weak-subjectivity-checkpoint Weak subjectivity checkpoint in the format block_root:epoch_number.
--weak-subjectivity-checkpoint Weak subjectivity checkpoint in the format --node-name A name for this node that will appear in the logs. If you set this to 'auto', a
block_root:epoch_number. persistent automatically generated ID will be selected for each --data-dir
--node-name A name for this node that will appear in the logs. If you set folder.
this to 'auto', a persistent automatically generated ID will --graffiti The graffiti value that will appear in proposed blocks. You can use a
be selected for each --data-dir folder. 0x-prefixed hex encoded string to specify raw bytes.
--graffiti The graffiti value that will appear in proposed blocks. You --verify-finalization Specify whether to verify finalization occurs on schedule, for testing [=false].
can use a 0x-prefixed hex encoded string to specify raw
bytes.
--verify-finalization Specify whether to verify finalization occurs on schedule,
for testing [=false].
--stop-at-epoch A positive epoch selects the epoch at which to stop [=0]. --stop-at-epoch A positive epoch selects the epoch at which to stop [=0].
--metrics Enable the metrics server [=false]. --metrics Enable the metrics server [=false].
--metrics-address Listening address of the metrics server [=127.0.0.1]. --metrics-address Listening address of the metrics server [=127.0.0.1].
--metrics-port Listening HTTP port of the metrics server [=8008]. --metrics-port Listening HTTP port of the metrics server [=8008].
--status-bar Display a status bar at the bottom of the terminal screen --status-bar Display a status bar at the bottom of the terminal screen [=true].
[=true].
--status-bar-contents Textual template for the contents of the status bar. --status-bar-contents Textual template for the contents of the status bar.
--rpc Enable the JSON-RPC server [=false]. --rpc Enable the JSON-RPC server [=false].
--rpc-port HTTP port for the JSON-RPC service [=9190]. --rpc-port HTTP port for the JSON-RPC service [=9190].
@ -83,27 +67,32 @@ The following options are available:
--rest Enable the REST server [=false]. --rest Enable the REST server [=false].
--rest-port Port for the REST server [=5052]. --rest-port Port for the REST server [=5052].
--rest-address Listening address of the REST server [=127.0.0.1]. --rest-address Listening address of the REST server [=127.0.0.1].
--validator-api Enable the REST (BETA version) validator keystore management --rest-statecache-size The maximum number of recently accessed states that are kept in memory. Speeds
API [=false]. up requests obtaining information for consecutive slots or epochs. [=3].
--in-process-validators Disable the push model (the beacon node tells a signing --rest-statecache-ttl The number of seconds to keep recently accessed states in memory [=60].
process with the private keys of the validators what to sign --keymanager Enable the REST keymanager API (BETA version) [=false].
and when) and load the validators in the beacon node itself --keymanager-port Listening port for the REST keymanager API [=5052].
[=true]. --keymanager-address Listening port for the REST keymanager API [=127.0.0.1].
--keymanager-token-file A file specifying the authorizition token required for accessing the keymanager
API.
--in-process-validators Disable the push model (the beacon node tells a signing process with the private
keys of the validators what to sign and when) and load the validators in the
beacon node itself [=true].
--discv5 Enable Discovery v5 [=true]. --discv5 Enable Discovery v5 [=true].
--dump Write SSZ dumps of blocks, attestations and states to data --dump Write SSZ dumps of blocks, attestations and states to data dir [=false].
dir [=false]. --direct-peer The list of priviledged, secure and known peers to connect and maintain the
--direct-peer The list of priviledged, secure and known peers to connect connection to, this requires a not random netkey-file. In the complete
and maintain the connection to, this requires a not random multiaddress format like: /ip4/<address>/tcp/<port>/p2p/<peerId-public-key>.
netkey-file. In the complete multiaddress format like: Peering agreements are established out of band and must be reciprocal..
/ip4/<address>/tcp/<port>/p2p/<peerId-public-key>. Peering --doppelganger-detection If enabled, the beacon node prudently listens for 2 epochs for attestations from
agreements are established out of band and must be a validator with the same index (a doppelganger), before sending an attestation
reciprocal.. itself. This protects against slashing (due to double-voting) but means you will
--doppelganger-detection If enabled, the beacon node prudently listens for 2 epochs miss two attestations when restarting. [=true].
for attestations from a validator with the same index (a --validator-monitor-auto Automatically monitor locally active validators (BETA) [=false].
doppelganger), before sending an attestation itself. This --validator-monitor-pubkey One or more validators to monitor - works best when --subscribe-all-subnets is
protects against slashing (due to double-voting) but means enabled (BETA).
you will miss two attestations when restarting. [=true]. --validator-monitor-totals Publish metrics to single 'totals' label for better collection performance when
monitoring many validators (BETA) [=false].
... ...
``` ```