2020-04-22 07:53:02 +02:00
{. push raises : [ Defect ] . }
2018-11-24 01:58:49 +02:00
import
2019-12-10 15:20:40 +01:00
os , options , strformat , strutils ,
2020-02-11 19:35:42 +02:00
chronicles , confutils , json_serialization ,
2020-03-17 00:28:54 +02:00
confutils / defs , confutils / std / net ,
chronicles / options as chroniclesOptions ,
2019-10-25 12:59:56 +02:00
spec / [ crypto ]
2018-12-19 14:58:53 +02:00
export
2020-03-17 00:28:54 +02:00
defs , enabledLogLevel , parseCmdArg , completeCmdArg
2019-03-26 21:44:51 +02:00
2018-11-24 01:58:49 +02:00
type
2019-03-18 05:54:08 +02:00
ValidatorKeyPath * = TypedInputFile [ ValidatorPrivKey , Txt , " privkey " ]
2018-11-24 01:58:49 +02:00
2020-05-22 20:04:52 +03:00
BNStartUpCmd * = enum
2018-12-19 14:58:53 +02:00
noCommand
2019-03-26 01:26:11 +02:00
importValidator
2019-03-26 12:01:13 +02:00
createTestnet
2019-09-01 17:02:49 +02:00
makeDeposits
2019-11-01 11:53:06 +02:00
query
2020-05-22 20:04:52 +03:00
VCStartUpCmd * = enum
VCNoCommand
2019-11-01 11:53:06 +02:00
QueryCmd * = enum
nimQuery
get
2019-03-18 05:54:08 +02:00
2019-10-29 01:04:52 +02:00
Eth1Network * = enum
custom
mainnet
rinkeby
goerli
2018-11-29 03:08:34 +02:00
BeaconNodeConf * = object
2019-01-17 01:01:15 +02:00
logLevel * {.
2020-04-28 01:39:04 +03:00
defaultValue : " DEBUG "
2019-11-11 14:43:12 +00:00
desc : " Sets the log level. "
2020-04-28 01:39:04 +03:00
name : " log-level " } : string
2019-03-18 05:54:08 +02:00
2019-10-29 01:04:52 +02: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 19:22:17 +02:00
2019-09-09 16:34:50 -04:00
quickStart * {.
2019-10-29 01:04:52 +02:00
defaultValue : false
2019-11-11 14:43:12 +00:00
desc : " Run in quickstart mode "
name : " quick-start " } : bool
2019-09-09 16:34:50 -04:00
2019-03-19 19:22:17 +02:00
dataDir * {.
2019-10-29 01:04:52 +02: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-17 01:01:15 +02:00
2020-03-24 13:13:07 +02:00
web3Url * {.
2019-10-29 01:04:52 +02: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 17:02:49 +02:00
depositContractAddress * {.
2019-10-29 01:04:52 +02:00
defaultValue : " "
2019-11-11 14:43:12 +00:00
desc : " Address of the deposit contract. "
name : " deposit-contract " } : string
2019-10-03 04:51:44 +03:00
2018-12-19 14:58:53 +02:00
case cmd * {.
command
2020-05-22 20:04:52 +03:00
defaultValue : noCommand } : BNStartUpCmd
2018-12-19 14:58:53 +02: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-24 01:58:49 +02:00
2018-12-19 14:58:53 +02:00
bootstrapNodesFile * {.
2019-10-29 01:04:52 +02: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-24 01:58:49 +02:00
2020-03-18 21:36:22 +02:00
libp2pAddress * {.
defaultValue : defaultListenAddress ( config )
desc : " Listening address for the Ethereum LibP2P traffic. "
name : " listen-address " } : IpAddress
2018-12-19 14:58:53 +02:00
tcpPort * {.
2020-03-17 00:28:54 +02:00
defaultValue : defaultEth2TcpPort
2020-03-18 21:36:22 +02:00
desc : " Listening TCP port for Ethereum LibP2P traffic. "
2020-03-17 00:28:54 +02:00
name : " tcp-port " } : Port
2018-11-24 01:58:49 +02:00
2018-12-19 14:58:53 +02:00
udpPort * {.
2020-03-17 00:28:54 +02:00
defaultValue : defaultEth2TcpPort
2020-03-18 21:36:22 +02:00
desc : " Listening UDP port for node discovery. "
2020-03-17 00:28:54 +02:00
name : " udp-port " } : Port
2018-11-24 01:58:49 +02:00
2019-12-18 03:11:20 +02:00
maxPeers * {.
defaultValue : 10
desc : " The maximum number of peers to connect to "
name : " max-peers " } : int
2019-03-18 21:57:19 -06:00
nat * {.
2019-10-29 01:04:52 +02: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-18 21:57:19 -06:00
2018-12-19 14:58:53 +02:00
validators * {.
required
2019-10-29 01:04:52 +02: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 14:58:53 +02:00
2020-05-22 20:04:52 +03: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 14:58:53 +02:00
stateSnapshot * {.
2019-10-29 01:04:52 +02: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 14:58:53 +02:00
2019-10-29 01:04:52 +02:00
nodeName * {.
2019-11-11 14:43:12 +00:00
defaultValue : " "
2019-03-22 16:35:20 +02:00
desc : " A name for this node that will appear in the logs. " &
2019-10-29 01:04:52 +02: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 16:35:20 +02:00
2020-02-17 19:24:14 +01:00
verifyFinalization * {.
defaultValue : false
desc : " Specify whether to verify finalization occurs on schedule, for testing. "
name : " verify-finalization " } : bool
2020-02-17 22:22:50 +01:00
stopAtEpoch * {.
2020-02-17 19:24:14 +01:00
defaultValue : 0
2020-02-17 22:22:50 +01:00
desc : " A positive epoch selects the epoch at which to stop. "
name : " stop-at-epoch " } : uint64
2020-02-17 19:24:14 +01:00
2020-03-17 00:28:54 +02:00
metricsEnabled * {.
2019-10-29 01:04:52 +02:00
defaultValue : false
2019-11-11 14:43:12 +00:00
desc : " Enable the metrics server. "
2020-03-17 00:28:54 +02:00
name : " metrics " } : bool
2019-09-07 13:48:05 -04:00
2020-03-17 00:28:54 +02:00
metricsAddress * {.
2020-03-18 21:36:22 +02:00
defaultValue : defaultAdminListenAddress ( config )
2019-11-11 14:43:12 +00:00
desc : " Listening address of the metrics server. "
2020-03-17 00:28:54 +02:00
name : " metrics-address " } : IpAddress
2019-09-07 13:48:05 -04:00
2020-03-17 00:28:54 +02:00
metricsPort * {.
2019-10-29 01:04:52 +02:00
defaultValue : 8008
2019-11-11 14:43:12 +00:00
desc : " Listening HTTP port of the metrics server. "
2020-03-17 00:28:54 +02:00
name : " metrics-port " } : Port
2019-09-07 13:48:05 -04:00
2020-03-18 21:36:22 +02: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 12:32:27 +01:00
defaultValue : false
desc : " Write SSZ dumps of blocks, attestations and states to data dir "
2020-03-18 21:36:22 +02:00
name : " dump " } : bool
2019-12-03 12:32:27 +01:00
2019-03-19 19:22:17 +02:00
of createTestnet :
2019-03-07 07:59:28 -06:00
validatorsDir * {.
2019-10-29 01:04:52 +02: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 07:59:28 -06:00
2019-03-27 14:06:06 +02:00
totalValidators * {.
2019-10-29 01:04:52 +02: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 07:59:28 -06:00
firstValidator * {.
2019-10-29 01:04:52 +02: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 19:22:17 +02:00
2019-03-27 14:06:06 +02:00
lastUserValidator * {.
2019-10-29 01:04:52 +02: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 19:22:17 +02:00
bootstrapAddress * {.
2020-03-17 00:28:54 +02: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-17 00:28:54 +02:00
name : " bootstrap-address " } : IpAddress
2019-03-19 19:22:17 +02:00
bootstrapPort * {.
2020-03-17 00:28:54 +02: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-17 00:28:54 +02:00
name : " bootstrap-port " } : Port
2018-12-19 14:58:53 +02:00
2019-02-15 10:33:32 -06:00
genesisOffset * {.
2019-10-29 01:04:52 +02: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 10:33:32 -06:00
2019-03-19 19:22:17 +02:00
outputGenesis * {.
2019-10-29 01:04:52 +02: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 05:54:08 +02:00
2019-09-10 17:55:58 -04:00
withGenesisRoot * {.
2019-10-29 01:04:52 +02: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 17:55:58 -04:00
2019-10-29 01:04:52 +02: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 18:13:27 -04:00
2019-03-26 01:26:11 +02:00
of importValidator :
2019-03-19 21:50:22 +02:00
keyFiles * {.
2019-10-29 01:04:52 +02: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-24 01:58:49 +02:00
2019-09-01 17:02:49 +02:00
of makeDeposits :
2019-10-29 04:43:23 +02: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 04:43:23 +02: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 17:02:49 +02:00
2019-09-10 18:13:27 -04:00
depositsDir * {.
2019-10-29 01:04:52 +02:00
defaultValue : " validators "
2019-11-11 14:43:12 +00:00
desc : " Folder to write deposits to. "
name : " deposits-dir " } : string
2019-09-01 17:02:49 +02:00
2019-11-05 20:16:10 +02: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 20:16:10 +02:00
2020-03-24 13:13:07 +02: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 11:53:06 +02:00
of query :
case queryCmd * {.
defaultValue : nimQuery
2019-11-11 14:43:12 +00:00
command
2019-11-01 11:53:06 +02: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 20:04:52 +03: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 19:22:17 +02:00
let dataDir = when defined ( windows ) :
" AppData " / " Roaming " / " Nimbus "
elif defined ( macosx ) :
" Library " / " Application Support " / " Nimbus "
else :
" .cache " / " nimbus "
2018-12-09 10:25:02 +02:00
2019-10-29 01:04:52 +02:00
getHomeDir ( ) / dataDir / " BeaconNode "
2018-11-29 03:08:34 +02:00
2019-03-18 05:54:08 +02:00
proc validatorFileBaseName * ( validatorIdx : int ) : string =
# there can apparently be tops 4M validators so we use 7 digits..
2020-04-22 07:53:02 +02:00
try :
fmt" v{validatorIdx:07} "
except ValueError as e :
raiseAssert e . msg
2019-12-03 12:32:27 +01:00
2020-05-22 20:04:52 +03:00
func dumpDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-12-03 12:32:27 +01:00
conf . dataDir / " dump "
2019-12-10 15:20:40 +01:00
2020-05-22 20:04:52 +03:00
func localValidatorsDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-12-10 15:20:40 +01:00
conf . dataDir / " validators "
2020-05-22 20:04:52 +03:00
func databaseDir * ( conf : BeaconNodeConf | ValidatorClientConf ) : string =
2019-12-10 15:20:40 +01:00
conf . dataDir / " db "
2020-05-22 20:04:52 +03:00
func defaultListenAddress * ( conf : BeaconNodeConf | ValidatorClientConf ) : IpAddress =
2020-03-17 00:28:54 +02:00
# TODO: How should we select between IPv4 and IPv6
# Maybe there should be a config option for this.
2020-04-22 07:53:02 +02:00
return static : parseIpAddress ( " 0.0.0.0 " )
2020-03-17 00:28:54 +02:00
2020-05-22 20:04:52 +03:00
func defaultAdminListenAddress * ( conf : BeaconNodeConf | ValidatorClientConf ) : IpAddress =
2020-04-22 07:53:02 +02:00
return static : parseIpAddress ( " 127.0.0.1 " )
2020-03-18 21:36:22 +02:00
2020-05-22 20:04:52 +03:00
iterator validatorKeys * ( conf : BeaconNodeConf | ValidatorClientConf ) : ValidatorPrivKey =
2019-12-10 15:20:40 +01: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 07:53:02 +02: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 19:35:42 +02:00
template writeValue * ( writer : var JsonWriter ,
value : TypedInputFile | InputFile | InputDir | OutPath | OutDir | OutFile ) =
writer . writeValue ( string value )