2020-04-22 05:53:02 +00:00
{. push raises : [ Defect ] . }
2018-11-23 23:58:49 +00:00
import
2019-12-10 14:20:40 +00:00
os , options , strformat , strutils ,
2020-02-11 17:35:42 +00:00
chronicles , confutils , json_serialization ,
2020-03-16 22:28:54 +00:00
confutils / defs , confutils / std / net ,
chronicles / options as chroniclesOptions ,
2019-10-25 10:59:56 +00:00
spec / [ crypto ]
2018-12-19 12:58:53 +00:00
export
2020-03-16 22:28:54 +00:00
defs , enabledLogLevel , parseCmdArg , completeCmdArg
2019-03-26 19:44:51 +00:00
2018-11-23 23:58:49 +00:00
type
2019-03-18 03:54:08 +00:00
ValidatorKeyPath * = TypedInputFile [ ValidatorPrivKey , Txt , " privkey " ]
2018-11-23 23:58:49 +00:00
2020-05-22 17:04:52 +00:00
BNStartUpCmd * = enum
2018-12-19 12:58:53 +00:00
noCommand
2019-03-25 23:26:11 +00:00
importValidator
2019-03-26 10:01:13 +00:00
createTestnet
2019-09-01 15:02:49 +00:00
makeDeposits
2019-11-01 09:53:06 +00:00
query
2020-05-22 17:04:52 +00:00
VCStartUpCmd * = enum
VCNoCommand
2019-11-01 09:53:06 +00:00
QueryCmd * = enum
nimQuery
get
2019-03-18 03:54:08 +00:00
2019-10-28 23:04:52 +00:00
Eth1Network * = enum
custom
mainnet
rinkeby
goerli
2018-11-29 01:08:34 +00:00
BeaconNodeConf * = object
2019-01-16 23:01:15 +00:00
logLevel * {.
2020-04-27 22:39:04 +00:00
defaultValue : " DEBUG "
2019-11-11 14:43:12 +00:00
desc : " Sets the log level. "
2020-04-27 22:39:04 +00:00
name : " log-level " } : string
2019-03-18 03:54:08 +00:00
2019-10-28 23:04:52 +00:00
eth1Network * {.
defaultValue : goerli
2019-11-11 14:43:12 +00:00
desc : " The Eth1 network tracked by the beacon node. "
name : " eth1-network " } : Eth1Network
2019-03-19 17:22:17 +00:00
2019-09-09 20:34:50 +00:00
quickStart * {.
2019-10-28 23:04:52 +00:00
defaultValue : false
2019-11-11 14:43:12 +00:00
desc : " Run in quickstart mode "
name : " quick-start " } : bool
2019-09-09 20:34:50 +00:00
2019-03-19 17:22:17 +00:00
dataDir * {.
2019-10-28 23:04:52 +00:00
defaultValue : config . defaultDataDir ( )
2019-11-11 14:43:12 +00:00
desc : " The directory where nimbus will store all blockchain data. "
abbr : " d "
name : " data-dir " } : OutDir
2019-01-16 23:01:15 +00:00
2020-03-24 11:13:07 +00:00
web3Url * {.
2019-10-28 23:04:52 +00:00
defaultValue : " "
2019-11-11 14:43:12 +00:00
desc : " URL of the Web3 server to observe Eth1. "
name : " web3-url " } : string
2019-09-01 15:02:49 +00:00
depositContractAddress * {.
2019-10-28 23:04:52 +00:00
defaultValue : " "
2019-11-11 14:43:12 +00:00
desc : " Address of the deposit contract. "
name : " deposit-contract " } : string
2019-10-03 01:51:44 +00:00
2018-12-19 12:58:53 +00:00
case cmd * {.
command
2020-05-22 17:04:52 +00:00
defaultValue : noCommand } : BNStartUpCmd
2018-12-19 12:58:53 +00:00
of noCommand :
bootstrapNodes * {.
desc : " Specifies one or more bootstrap nodes to use when connecting to the network. "
2019-11-11 14:43:12 +00:00
abbr : " b "
name : " bootstrap-node " } : seq [ string ]
2018-11-23 23:58:49 +00:00
2018-12-19 12:58:53 +00:00
bootstrapNodesFile * {.
2019-10-28 23:04:52 +00:00
defaultValue : " "
2019-11-11 14:43:12 +00:00
desc : " Specifies a line-delimited file of bootsrap Ethereum network addresses. "
name : " bootstrap-file " } : InputFile
2018-11-23 23:58:49 +00:00
2020-03-18 19:36:22 +00:00
libp2pAddress * {.
defaultValue : defaultListenAddress ( config )
desc : " Listening address for the Ethereum LibP2P traffic. "
name : " listen-address " } : IpAddress
2018-12-19 12:58:53 +00:00
tcpPort * {.
2020-03-16 22:28:54 +00:00
defaultValue : defaultEth2TcpPort
2020-03-18 19:36:22 +00:00
desc : " Listening TCP port for Ethereum LibP2P traffic. "
2020-03-16 22:28:54 +00:00
name : " tcp-port " } : Port
2018-11-23 23:58:49 +00:00
2018-12-19 12:58:53 +00:00
udpPort * {.
2020-03-16 22:28:54 +00:00
defaultValue : defaultEth2TcpPort
2020-03-18 19:36:22 +00:00
desc : " Listening UDP port for node discovery. "
2020-03-16 22:28:54 +00:00
name : " udp-port " } : Port
2018-11-23 23:58:49 +00:00
2019-12-18 01:11:20 +00:00
maxPeers * {.
defaultValue : 10
desc : " The maximum number of peers to connect to "
name : " max-peers " } : int
2019-03-19 03:57:19 +00:00
nat * {.
2019-10-28 23:04:52 +00:00
desc : " Specify method to use for determining public address. " &
" Must be one of: any, none, upnp, pmp, extip:<IP>. "
defaultValue : " any " } : string
2019-03-19 03:57:19 +00:00
2018-12-19 12:58:53 +00:00
validators * {.
required
2019-10-28 23:04:52 +00:00
desc : " Path to a validator private key, as generated by makeDeposits. "
2019-11-11 14:43:12 +00:00
abbr : " v "
name : " validator " } : seq [ ValidatorKeyPath ]
2018-12-19 12:58:53 +00:00
2020-05-22 17:04:52 +00:00
externalValidators * {.
defaultValue : false
desc : " Specify whether validators should be in an external process (a validator client) which communicates with the beacon node or they should be embedded. "
name : " external-validators " } : bool
2018-12-19 12:58:53 +00:00
stateSnapshot * {.
2019-10-28 23:04:52 +00:00
desc : " Json file specifying a recent state snapshot. "
2019-11-11 14:43:12 +00:00
abbr : " s "
name : " state-snapshot " } : Option [ InputFile ]
2018-12-19 12:58:53 +00:00
2019-10-28 23:04:52 +00:00
nodeName * {.
2019-11-11 14:43:12 +00:00
defaultValue : " "
2019-03-22 14:35:20 +00:00
desc : " A name for this node that will appear in the logs. " &
2019-10-28 23:04:52 +00:00
" If you set this to ' auto ' , a persistent automatically generated ID will be seleceted for each --dataDir folder. "
2019-11-11 14:43:12 +00:00
name : " node-name " } : string
2019-03-22 14:35:20 +00:00
2020-02-17 18:24:14 +00:00
verifyFinalization * {.
defaultValue : false
desc : " Specify whether to verify finalization occurs on schedule, for testing. "
name : " verify-finalization " } : bool
2020-02-17 21:22:50 +00:00
stopAtEpoch * {.
2020-02-17 18:24:14 +00:00
defaultValue : 0
2020-02-17 21:22:50 +00:00
desc : " A positive epoch selects the epoch at which to stop. "
name : " stop-at-epoch " } : uint64
2020-02-17 18:24:14 +00:00
2020-03-16 22:28:54 +00:00
metricsEnabled * {.
2019-10-28 23:04:52 +00:00
defaultValue : false
2019-11-11 14:43:12 +00:00
desc : " Enable the metrics server. "
2020-03-16 22:28:54 +00:00
name : " metrics " } : bool
2019-09-07 17:48:05 +00:00
2020-03-16 22:28:54 +00:00
metricsAddress * {.
2020-03-18 19:36:22 +00:00
defaultValue : defaultAdminListenAddress ( config )
2019-11-11 14:43:12 +00:00
desc : " Listening address of the metrics server. "
2020-03-16 22:28:54 +00:00
name : " metrics-address " } : IpAddress
2019-09-07 17:48:05 +00:00
2020-03-16 22:28:54 +00:00
metricsPort * {.
2019-10-28 23:04:52 +00:00
defaultValue : 8008
2019-11-11 14:43:12 +00:00
desc : " Listening HTTP port of the metrics server. "
2020-03-16 22:28:54 +00:00
name : " metrics-port " } : Port
2019-09-07 17:48:05 +00:00
2020-03-18 19:36:22 +00:00
statusBarEnabled * {.
defaultValue : true
desc : " Display a status bar at the bottom of the terminal screen. "
name : " status-bar " } : bool
statusBarContents * {.
defaultValue : " peers: $connected_peers ; " &
" epoch: $epoch , slot: $epoch_slot / $slots_per_epoch ( $slot ); " &
" finalized epoch: $last_finalized_epoch | " &
" ETH: $attached_validators_balance "
desc : " Textual template for the contents of the status bar. "
name : " status-bar-contents " } : string
rpcEnabled * {.
defaultValue : false
desc : " Enable the JSON-RPC server "
name : " rpc " } : bool
rpcPort * {.
defaultValue : defaultEth2RpcPort
desc : " HTTP port for the JSON-RPC service. "
name : " rpc-port " } : Port
rpcAddress * {.
defaultValue : defaultAdminListenAddress ( config )
desc : " Listening address of the RPC server "
name : " rpc-address " } : IpAddress
dumpEnabled * {.
2019-12-03 11:32:27 +00:00
defaultValue : false
desc : " Write SSZ dumps of blocks, attestations and states to data dir "
2020-03-18 19:36:22 +00:00
name : " dump " } : bool
2019-12-03 11:32:27 +00:00
2019-03-19 17:22:17 +00:00
of createTestnet :
2019-03-07 13:59:28 +00:00
validatorsDir * {.
2019-10-28 23:04:52 +00:00
desc : " Directory containing validator descriptors named ' vXXXXXXX.deposit.json ' . "
2019-11-11 14:43:12 +00:00
abbr : " d "
name : " validators-dir " } : InputDir
2019-03-07 13:59:28 +00:00
2019-03-27 12:06:06 +00:00
totalValidators * {.
2019-10-28 23:04:52 +00:00
desc : " The number of validators in the newly created chain. "
2019-11-11 14:43:12 +00:00
name : " total-validators " } : uint64
2019-03-07 13:59:28 +00:00
firstValidator * {.
2019-10-28 23:04:52 +00:00
defaultValue : 0
2019-11-11 14:43:12 +00:00
desc : " Index of first validator to add to validator list. "
name : " first-validator " } : uint64
2019-03-19 17:22:17 +00:00
2019-03-27 12:06:06 +00:00
lastUserValidator * {.
2019-10-28 23:04:52 +00:00
defaultValue : config . totalValidators - 1 ,
2019-11-11 14:43:12 +00:00
desc : " The last validator index that will free for taking from a testnet participant. "
name : " last-user-validator " } : uint64
2019-03-19 17:22:17 +00:00
bootstrapAddress * {.
2020-03-16 22:28:54 +00:00
defaultValue : parseIpAddress ( " 127.0.0.1 " )
2019-11-11 14:43:12 +00:00
desc : " The public IP address that will be advertised as a bootstrap node for the testnet. "
2020-03-16 22:28:54 +00:00
name : " bootstrap-address " } : IpAddress
2019-03-19 17:22:17 +00:00
bootstrapPort * {.
2020-03-16 22:28:54 +00:00
defaultValue : defaultEth2TcpPort
2019-11-11 14:43:12 +00:00
desc : " The TCP/UDP port that will be used by the bootstrap node. "
2020-03-16 22:28:54 +00:00
name : " bootstrap-port " } : Port
2018-12-19 12:58:53 +00:00
2019-02-15 16:33:32 +00:00
genesisOffset * {.
2019-10-28 23:04:52 +00:00
defaultValue : 5
2019-11-11 14:43:12 +00:00
desc : " Seconds from now to add to genesis time. "
abbr : " g "
name : " genesis-offset " } : int
2019-02-15 16:33:32 +00:00
2019-03-19 17:22:17 +00:00
outputGenesis * {.
2019-10-28 23:04:52 +00:00
desc : " Output file where to write the initial state snapshot. "
2019-11-11 14:43:12 +00:00
name : " output-genesis " } : OutFile
2019-03-18 03:54:08 +00:00
2019-09-10 21:55:58 +00:00
withGenesisRoot * {.
2019-10-28 23:04:52 +00:00
defaultValue : false
2019-11-11 14:43:12 +00:00
desc : " Include a genesis root in ' network.json ' . "
name : " with-genesis-root " } : bool
2019-09-10 21:55:58 +00:00
2019-10-28 23:04:52 +00:00
outputBootstrapFile * {.
desc : " Output file with list of bootstrap nodes for the network. "
2019-11-11 14:43:12 +00:00
name : " output-bootstrap-file " } : OutFile
2019-09-10 22:13:27 +00:00
2019-03-25 23:26:11 +00:00
of importValidator :
2019-03-19 19:50:22 +00:00
keyFiles * {.
2019-10-28 23:04:52 +00:00
desc : " File with validator key to be imported (in hex form). "
2019-11-11 14:43:12 +00:00
name : " keyfile " } : seq [ ValidatorKeyPath ]
2018-11-23 23:58:49 +00:00
2019-09-01 15:02:49 +00:00
of makeDeposits :
2019-10-29 02:43:23 +00:00
totalQuickstartDeposits * {.
defaultValue : 0
2019-11-11 14:43:12 +00:00
desc : " Number of quick-start deposits to generate. "
name : " quickstart-deposits " } : int
2019-10-29 02:43:23 +00:00
totalRandomDeposits * {.
defaultValue : 0
2019-11-11 14:43:12 +00:00
desc : " Number of secure random deposits to generate. "
name : " random-deposits " } : int
2019-09-01 15:02:49 +00:00
2019-09-10 22:13:27 +00:00
depositsDir * {.
2019-10-28 23:04:52 +00:00
defaultValue : " validators "
2019-11-11 14:43:12 +00:00
desc : " Folder to write deposits to. "
name : " deposits-dir " } : string
2019-09-01 15:02:49 +00:00
2019-11-05 18:16:10 +00:00
depositPrivateKey * {.
defaultValue : " "
2019-11-11 14:43:12 +00:00
desc : " Private key of the controlling (sending) account " ,
name : " deposit-private-key " } : string
2019-11-05 18:16:10 +00:00
2020-03-24 11:13:07 +00:00
minDelay * {.
defaultValue : 0 .0
desc : " Minimum possible delay between making two deposits (in seconds) "
name : " min-delay " } : float
maxDelay * {.
defaultValue : 0 .0
desc : " Maximum possible delay between making two deposits (in seconds) "
name : " max-delay " } : float
2019-11-01 09:53:06 +00:00
of query :
case queryCmd * {.
defaultValue : nimQuery
2019-11-11 14:43:12 +00:00
command
2019-11-01 09:53:06 +00:00
desc : " Query the beacon node database and print the result " } : QueryCmd
of nimQuery :
nimQueryExpression * {.
argument
desc : " Nim expression to evaluate (using limited syntax) " } : string
of get :
getQueryPath * {.
argument
desc : " REST API path to evaluate " } : string
2020-05-22 17:04:52 +00:00
ValidatorClientConf * = object
logLevel * {.
defaultValue : " DEBUG "
desc : " Sets the log level. "
name : " log-level " } : string
dataDir * {.
defaultValue : config . defaultDataDir ( )
desc : " The directory where nimbus will store all blockchain data. "
abbr : " d "
name : " data-dir " } : OutDir
case cmd * {.
command
defaultValue : VCNoCommand } : VCStartUpCmd
of VCNoCommand :
rpcPort * {.
defaultValue : defaultEth2RpcPort
desc : " HTTP port of the server to connect to for RPC. "
name : " rpc-port " } : Port
rpcAddress * {.
defaultValue : defaultAdminListenAddress ( config )
desc : " Address of the server to connect to for RPC. "
name : " rpc-address " } : IpAddress
validators * {.
required
desc : " Path to a validator private key, as generated by makeDeposits. "
abbr : " v "
name : " validator " } : seq [ ValidatorKeyPath ]
stateSnapshot * {.
desc : " Json file specifying a recent state snapshot. "
abbr : " s "
name : " state-snapshot " } : Option [ InputFile ]
delayStart * {.
defaultValue : 0
desc : " Seconds from now to delay the starting of the validator client (useful for debug purposes when starting before the beacon node in a script). "
abbr : " g "
name : " delay-start " } : int
proc defaultDataDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-03-19 17:22:17 +00:00
let dataDir = when defined ( windows ) :
" AppData " / " Roaming " / " Nimbus "
elif defined ( macosx ) :
" Library " / " Application Support " / " Nimbus "
else :
" .cache " / " nimbus "
2018-12-09 08:25:02 +00:00
2019-10-28 23:04:52 +00:00
getHomeDir ( ) / dataDir / " BeaconNode "
2018-11-29 01:08:34 +00:00
2019-03-18 03:54:08 +00:00
proc validatorFileBaseName * ( validatorIdx : int ) : string =
# there can apparently be tops 4M validators so we use 7 digits..
2020-04-22 05:53:02 +00:00
try :
fmt" v{validatorIdx:07} "
except ValueError as e :
raiseAssert e . msg
2019-12-03 11:32:27 +00:00
2020-05-22 17:04:52 +00:00
func dumpDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-12-03 11:32:27 +00:00
conf . dataDir / " dump "
2019-12-10 14:20:40 +00:00
2020-05-22 17:04:52 +00:00
func localValidatorsDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-12-10 14:20:40 +00:00
conf . dataDir / " validators "
2020-05-22 17:04:52 +00:00
func databaseDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-12-10 14:20:40 +00:00
conf . dataDir / " db "
2020-05-22 17:04:52 +00:00
func defaultListenAddress * ( conf : BeaconNodeConf | ValidatorClientConf ) : IpAddress =
2020-03-16 22:28:54 +00:00
# TODO: How should we select between IPv4 and IPv6
# Maybe there should be a config option for this.
2020-04-22 05:53:02 +00:00
return static : parseIpAddress ( " 0.0.0.0 " )
2020-03-16 22:28:54 +00:00
2020-05-22 17:04:52 +00:00
func defaultAdminListenAddress * ( conf : BeaconNodeConf | ValidatorClientConf ) : IpAddress =
2020-04-22 05:53:02 +00:00
return static : parseIpAddress ( " 127.0.0.1 " )
2020-03-18 19:36:22 +00:00
2020-05-22 17:04:52 +00:00
iterator validatorKeys * ( conf : BeaconNodeConf | ValidatorClientConf ) : ValidatorPrivKey =
2019-12-10 14:20:40 +00:00
for validatorKeyFile in conf . validators :
try :
yield validatorKeyFile . load
except CatchableError as err :
warn " Failed to load validator private key " ,
file = validatorKeyFile . string , err = err . msg
2020-04-22 05:53:02 +00:00
try :
for kind , file in walkDir ( conf . localValidatorsDir ) :
if kind in { pcFile , pcLinkToFile } and
cmpIgnoreCase ( " .privkey " , splitFile ( file ) . ext ) = = 0 :
try :
yield ValidatorPrivKey . init ( readFile ( file ) . string )
except CatchableError as err :
warn " Failed to load a validator private key " , file , err = err . msg
except OSError as err :
warn " Cannot load validator keys " ,
dir = conf . localValidatorsDir , err = err . msg
2020-02-11 17:35:42 +00:00
template writeValue * ( writer : var JsonWriter ,
value : TypedInputFile | InputFile | InputDir | OutPath | OutDir | OutFile ) =
writer . writeValue ( string value )