mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-26 10:55:41 +00:00
* Rearrange/rename test_kintsugu => test_custom_network why: Debug, fix and test more general problems related to running nimbus on a custom network. * Update UInt265/Json parser for --custom-network command line option why: As found out with the Kintsugi configuration, block number and balance have the same Nim type which led to misunderstandings. This patch makes sure that UInt265 encoded string values "0x11" decodes to 17, and "b" and "11" to 11. * Refactored genesis.toBlock() => genesis.toBlockHeader() why: The function toBlock(g,db) may return different results depending on whether the db descriptor argument is nil, or initialised. This is due to the db.config data sub-descriptor which may give various outcomes for the baseFee field of the genesis header. Also, the version where db is non-nil initialised is used internally only. So the public rewrite toBlockHeader() that replaces the toBlock() function expects a full set of NetworkParams. * update comments * Rename toBlockHeader() => toGenesisHeader() why: Polymorphic prototype used for BaseChainDB or NetworkParams argument. With a BaseChainDB descriptor argument, the name shall imply that the header is generated from the config fields rather than fetched from the database. * Added command line option --static-peers-file why: Handy feature to keep peer nodes in a file, similar to the --bootstrap-file option.
685 lines
21 KiB
Nim
685 lines
21 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018-2021 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT))
|
|
# at your option.
|
|
# This file may not be copied, modified, or distributed except according to
|
|
# those terms.
|
|
|
|
import
|
|
std/[options, strutils, times, os],
|
|
pkg/[
|
|
chronicles,
|
|
confutils,
|
|
confutils/defs,
|
|
stew/byteutils,
|
|
confutils/std/net
|
|
],
|
|
stew/shims/net as stewNet,
|
|
eth/[p2p, common, net/nat, p2p/bootnodes],
|
|
"."/[db/select_backend, chain_config,
|
|
constants, vm_compile_info
|
|
]
|
|
|
|
export stewNet
|
|
|
|
const
|
|
NimbusName* = "nimbus-eth1"
|
|
## project name string
|
|
|
|
NimbusMajor*: int = 0
|
|
## is the major number of Nimbus' version.
|
|
|
|
NimbusMinor*: int = 1
|
|
## is the minor number of Nimbus' version.
|
|
|
|
NimbusPatch*: int = 0
|
|
## is the patch number of Nimbus' version.
|
|
|
|
NimbusVersion* = $NimbusMajor & "." & $NimbusMinor & "." & $NimbusPatch
|
|
## is the version of Nimbus as a string.
|
|
|
|
GitRevision = staticExec("git rev-parse --short HEAD").replace("\n") # remove CR
|
|
|
|
NimVersion = staticExec("nim --version").strip()
|
|
|
|
# TODO: fix this agent-string format to match other
|
|
# eth clients format
|
|
NimbusIdent* = "$# v$# [$#: $#, $#, $#, $#]" % [
|
|
NimbusName,
|
|
NimbusVersion,
|
|
hostOS,
|
|
hostCPU,
|
|
nimbus_db_backend,
|
|
VmName,
|
|
GitRevision
|
|
]
|
|
## project ident name for networking services
|
|
|
|
let
|
|
# e.g.: Copyright (c) 2018-2021 Status Research & Development GmbH
|
|
NimbusCopyright* = "Copyright (c) 2018-" &
|
|
$(now().utc.year) &
|
|
" Status Research & Development GmbH"
|
|
|
|
# e.g.:
|
|
# Nimbus v0.1.0 [windows: amd64, rocksdb, evmc, dda8914f]
|
|
# Copyright (c) 2018-2021 Status Research & Development GmbH
|
|
NimbusBuild* = "$#\p$#" % [
|
|
NimbusIdent,
|
|
NimbusCopyright,
|
|
]
|
|
|
|
NimbusHeader* = "$#\p\p$#" % [
|
|
NimbusBuild,
|
|
NimVersion
|
|
]
|
|
|
|
proc defaultDataDir*(): string =
|
|
when defined(windows):
|
|
getHomeDir() / "AppData" / "Roaming" / "Nimbus"
|
|
elif defined(macosx):
|
|
getHomeDir() / "Library" / "Application Support" / "Nimbus"
|
|
else:
|
|
getHomeDir() / ".cache" / "nimbus"
|
|
|
|
proc defaultKeystoreDir*(): string =
|
|
defaultDataDir() / "keystore"
|
|
|
|
proc getLogLevels(): string =
|
|
var logLevels: seq[string]
|
|
for level in LogLevel:
|
|
if level < enabledLogLevel:
|
|
continue
|
|
logLevels.add($level)
|
|
join(logLevels, ", ")
|
|
|
|
const
|
|
defaultDataDirDesc = defaultDataDir()
|
|
defaultPort = 30303
|
|
defaultMetricsServerPort = 9093
|
|
defaultEthRpcPort = 8545
|
|
defaultEthWsPort = 8546
|
|
defaultEthGraphqlPort = 8547
|
|
defaultEngineApiPort = 8550
|
|
defaultEngineApiWsPort = 8551
|
|
defaultListenAddress = (static ValidIpAddress.init("0.0.0.0"))
|
|
defaultAdminListenAddress = (static ValidIpAddress.init("127.0.0.1"))
|
|
defaultListenAddressDesc = $defaultListenAddress & ", meaning all network interfaces"
|
|
defaultAdminListenAddressDesc = $defaultAdminListenAddress & ", meaning local host only"
|
|
logLevelDesc = getLogLevels()
|
|
|
|
# `when` around an option doesn't work with confutils; it fails to compile.
|
|
# Workaround that by setting the `ignore` pragma on EVMC-specific options.
|
|
when defined(evmc_enabled):
|
|
{.pragma: includeIfEvmc.}
|
|
else:
|
|
{.pragma: includeIfEvmc, ignore.}
|
|
|
|
const sharedLibText = if defined(linux): " (*.so, *.so.N)"
|
|
elif defined(windows): " (*.dll)"
|
|
elif defined(macosx): " (*.dylib)"
|
|
else: ""
|
|
|
|
type
|
|
PruneMode* {.pure.} = enum
|
|
Full
|
|
Archive
|
|
|
|
NimbusCmd* {.pure.} = enum
|
|
noCommand
|
|
`import`
|
|
|
|
ProtocolFlag* {.pure.} = enum
|
|
## Protocol flags
|
|
Eth ## enable eth subprotocol
|
|
Les ## enable les subprotocol
|
|
|
|
RpcFlag* {.pure.} = enum
|
|
## RPC flags
|
|
Eth ## enable eth_ set of RPC API
|
|
Debug ## enable debug_ set of RPC API
|
|
|
|
DiscoveryType* {.pure.} = enum
|
|
None
|
|
V4
|
|
V5
|
|
|
|
NimbusConf* = object of RootObj
|
|
## Main Nimbus configuration object
|
|
|
|
dataDir* {.
|
|
separator: "ETHEREUM OPTIONS:"
|
|
desc: "The directory where nimbus will store all blockchain data"
|
|
defaultValue: defaultDataDir()
|
|
defaultValueDesc: $defaultDataDirDesc
|
|
abbr: "d"
|
|
name: "data-dir" }: OutDir
|
|
|
|
keyStore* {.
|
|
desc: "Load one or more keystore files from this directory"
|
|
defaultValue: defaultKeystoreDir()
|
|
defaultValueDesc: "inside datadir"
|
|
abbr: "k"
|
|
name: "key-store" }: OutDir
|
|
|
|
pruneMode* {.
|
|
desc: "Blockchain prune mode (Full or Archive)"
|
|
defaultValue: PruneMode.Full
|
|
defaultValueDesc: $PruneMode.Full
|
|
abbr : "p"
|
|
name: "prune-mode" }: PruneMode
|
|
|
|
importKey* {.
|
|
desc: "Import unencrypted 32 bytes hex private key from a file"
|
|
defaultValue: ""
|
|
abbr: "e"
|
|
name: "import-key" }: InputFile
|
|
|
|
engineSigner* {.
|
|
desc: "Set the signer address(as 20 bytes hex) and enable sealing engine to run and " &
|
|
"producing blocks at specified interval (only PoA/Clique supported)"
|
|
defaultValue: ZERO_ADDRESS
|
|
defaultValueDesc: ""
|
|
abbr: "s"
|
|
name: "engine-signer" }: EthAddress
|
|
|
|
verifyFrom* {.
|
|
desc: "Enable extra verification when current block number greater than verify-from"
|
|
defaultValueDesc: ""
|
|
name: "verify-from" }: Option[uint64]
|
|
|
|
evm* {.
|
|
desc: "Load alternative EVM from EVMC-compatible shared library" & sharedLibText
|
|
defaultValue: ""
|
|
name: "evm"
|
|
includeIfEvmc }: string
|
|
|
|
network {.
|
|
separator: "\pETHEREUM NETWORK OPTIONS:"
|
|
desc: "Name or id number of Ethereum network(mainnet(1), ropsten(3), rinkeby(4), goerli(5), kovan(42), other=custom)"
|
|
longDesc:
|
|
"- mainnet: Ethereum main network\n" &
|
|
"- ropsten: Test network (proof-of-work, the one most like Ethereum mainnet)\n" &
|
|
"- rinkeby: Test network (proof-of-authority, for those running Geth clients)\n" &
|
|
"- görli : Test network (proof-of-authority, works across all clients)\n" &
|
|
"- kovan : Test network (proof-of-authority, for those running OpenEthereum clients)"
|
|
defaultValue: "" # the default value is set in makeConfig
|
|
defaultValueDesc: "mainnet(1)"
|
|
abbr: "i"
|
|
name: "network" }: string
|
|
|
|
customNetwork {.
|
|
desc: "Use custom genesis block for private Ethereum Network (as /path/to/genesis.json)"
|
|
defaultValueDesc: ""
|
|
abbr: "c"
|
|
name: "custom-network" }: Option[NetworkParams]
|
|
|
|
networkId* {.
|
|
ignore # this field is not processed by confutils
|
|
defaultValue: MainNet # the defaultValue value is set by `makeConfig`
|
|
name: "network-id"}: NetworkId
|
|
|
|
networkParams* {.
|
|
ignore # this field is not processed by confutils
|
|
defaultValue: NetworkParams() # the defaultValue value is set by `makeConfig`
|
|
name: "network-params"}: NetworkParams
|
|
|
|
logLevel* {.
|
|
separator: "\pLOGGING AND DEBUGGING OPTIONS:"
|
|
desc: "Sets the log level for process and topics (" & logLevelDesc & ")"
|
|
defaultValue: LogLevel.INFO
|
|
defaultValueDesc: $LogLevel.INFO
|
|
name: "log-level" }: LogLevel
|
|
|
|
logFile* {.
|
|
desc: "Specifies a path for the written Json log file"
|
|
name: "log-file" }: Option[OutFile]
|
|
|
|
logMetricsEnabled* {.
|
|
desc: "Enable metrics logging"
|
|
defaultValue: false
|
|
name: "log-metrics" .}: bool
|
|
|
|
logMetricsInterval* {.
|
|
desc: "Interval at which to log metrics, in seconds"
|
|
defaultValue: 10
|
|
name: "log-metrics-interval" .}: int
|
|
|
|
bootstrapNodes {.
|
|
separator: "\pNETWORKING OPTIONS:"
|
|
desc: "Specifies one or more bootstrap nodes(as enode URL) to use when connecting to the network"
|
|
defaultValue: @[]
|
|
defaultValueDesc: ""
|
|
abbr: "b"
|
|
name: "bootstrap-node" }: seq[string]
|
|
|
|
bootstrapFile {.
|
|
desc: "Specifies a line-delimited file of bootstrap Ethereum network addresses(enode URL). " &
|
|
"By default, addresses will be added to bootstrap node list. " &
|
|
"But if the first line equals to `override` word, it will override built-in list"
|
|
defaultValue: ""
|
|
name: "bootstrap-file" }: InputFile
|
|
|
|
staticPeers {.
|
|
desc: "Connect to one or more trusted peers(as enode URL)"
|
|
defaultValue: @[]
|
|
defaultValueDesc: ""
|
|
name: "static-peers" }: seq[string]
|
|
|
|
staticPeersFile {.
|
|
desc: "Specifies a line-delimited file of trusted peers addresses(enode URL)" &
|
|
"to be added to the --staticPeers list. If the first line equals to the word `override`, "&
|
|
"the file contents will replace the --staticPeers list"
|
|
defaultValue: ""
|
|
name: "static-peers-file" }: InputFile
|
|
|
|
listenAddress* {.
|
|
desc: "Listening IP address for Ethereum P2P and Discovery traffic"
|
|
defaultValue: defaultListenAddress
|
|
defaultValueDesc: $defaultListenAddressDesc
|
|
name: "listen-address" }: ValidIpAddress
|
|
|
|
tcpPort* {.
|
|
desc: "Ethereum P2P network listening TCP port"
|
|
defaultValue: defaultPort
|
|
defaultValueDesc: $defaultPort
|
|
name: "tcp-port" }: Port
|
|
|
|
udpPort* {.
|
|
desc: "Ethereum P2P network listening UDP port"
|
|
defaultValue: 0 # set udpPort defaultValue in `makeConfig`
|
|
defaultValueDesc: "default to --tcp-port"
|
|
name: "udp-port" }: Port
|
|
|
|
maxPeers* {.
|
|
desc: "Maximum number of peers to connect to"
|
|
defaultValue: 25
|
|
name: "max-peers" }: int
|
|
|
|
nat* {.
|
|
desc: "Specify method to use for determining public address. " &
|
|
"Must be one of: any, none, upnp, pmp, extip:<IP>"
|
|
defaultValue: NatConfig(hasExtIp: false, nat: NatAny)
|
|
defaultValueDesc: "any"
|
|
name: "nat" .}: NatConfig
|
|
|
|
discovery* {.
|
|
desc: "Specify method to find suitable peer in an Ethereum network (None, V4, V5)"
|
|
longDesc:
|
|
"- None: Disables the peer discovery mechanism (manual peer addition)\n" &
|
|
"- V4 : Node Discovery Protocol v4(default)\n" &
|
|
"- V5 : Node Discovery Protocol v5"
|
|
defaultValue: DiscoveryType.V4
|
|
defaultValueDesc: $DiscoveryType.V4
|
|
name: "discovery" .}: DiscoveryType
|
|
|
|
terminalTotalDifficulty* {.
|
|
desc: "The terminal total difficulty of the eth2 merge transition block"
|
|
name: "terminal-total-difficulty" .}: Option[UInt256]
|
|
|
|
engineApiEnabled* {.
|
|
desc: "Enable the Engine API"
|
|
defaultValue: false
|
|
name: "engine-api" .}: bool
|
|
|
|
engineApiPort* {.
|
|
desc: "Listening port for the Engine API"
|
|
defaultValue: defaultEngineApiPort
|
|
defaultValueDesc: $defaultEngineApiPort
|
|
name: "engine-api-port" .}: Port
|
|
|
|
engineApiAddress* {.
|
|
desc: "Listening address for the Engine API"
|
|
defaultValue: defaultAdminListenAddress
|
|
defaultValueDesc: defaultAdminListenAddressDesc
|
|
name: "engine-api-address" .}: ValidIpAddress
|
|
|
|
engineApiWsEnabled* {.
|
|
desc: "Enable the WebSocket Engine API"
|
|
defaultValue: false
|
|
name: "engine-api-ws" .}: bool
|
|
|
|
engineApiWsPort* {.
|
|
desc: "Listening port for the WebSocket Engine API"
|
|
defaultValue: defaultEngineApiWsPort
|
|
defaultValueDesc: $defaultEngineApiWsPort
|
|
name: "engine-api-ws-port" .}: Port
|
|
|
|
engineApiWsAddress* {.
|
|
desc: "Listening address for the WebSocket Engine API"
|
|
defaultValue: defaultAdminListenAddress
|
|
defaultValueDesc: defaultAdminListenAddressDesc
|
|
name: "engine-api-ws-address" .}: ValidIpAddress
|
|
|
|
nodeKeyHex* {.
|
|
desc: "P2P node private key (as 32 bytes hex string)"
|
|
defaultValue: ""
|
|
defaultValueDesc: "random"
|
|
name: "node-key" .}: string
|
|
|
|
agentString* {.
|
|
desc: "Node agent string which is used as identifier in network"
|
|
defaultValue: NimbusIdent
|
|
defaultValueDesc: $NimbusIdent
|
|
name: "agent-string" .}: string
|
|
|
|
protocols {.
|
|
desc: "Enable specific set of protocols (available: Eth, Les)"
|
|
defaultValue: @[]
|
|
defaultValueDesc: $ProtocolFlag.Eth
|
|
name: "protocols" .}: seq[string]
|
|
|
|
case cmd* {.
|
|
command
|
|
defaultValue: NimbusCmd.noCommand }: NimbusCmd
|
|
|
|
of noCommand:
|
|
rpcEnabled* {.
|
|
separator: "\pLOCAL SERVICE OPTIONS:"
|
|
desc: "Enable the JSON-RPC server"
|
|
defaultValue: false
|
|
name: "rpc" }: bool
|
|
|
|
rpcPort* {.
|
|
desc: "Listening port of the JSON-RPC server"
|
|
defaultValue: defaultEthRpcPort
|
|
defaultValueDesc: $defaultEthRpcPort
|
|
name: "rpc-port" }: Port
|
|
|
|
rpcAddress* {.
|
|
desc: "Listening IP address of the JSON-RPC server"
|
|
defaultValue: defaultAdminListenAddress
|
|
defaultValueDesc: $defaultAdminListenAddressDesc
|
|
name: "rpc-address" }: ValidIpAddress
|
|
|
|
rpcApi {.
|
|
desc: "Enable specific set of RPC API (available: eth, debug)"
|
|
defaultValue: @[]
|
|
defaultValueDesc: $RpcFlag.Eth
|
|
name: "rpc-api" }: seq[string]
|
|
|
|
wsEnabled* {.
|
|
desc: "Enable the Websocket JSON-RPC server"
|
|
defaultValue: false
|
|
name: "ws" }: bool
|
|
|
|
wsPort* {.
|
|
desc: "Listening port of the Websocket JSON-RPC server"
|
|
defaultValue: defaultEthWsPort
|
|
defaultValueDesc: $defaultEthWsPort
|
|
name: "ws-port" }: Port
|
|
|
|
wsAddress* {.
|
|
desc: "Listening IP address of the Websocket JSON-RPC server"
|
|
defaultValue: defaultAdminListenAddress
|
|
defaultValueDesc: $defaultAdminListenAddressDesc
|
|
name: "ws-address" }: ValidIpAddress
|
|
|
|
wsApi {.
|
|
desc: "Enable specific set of Websocket RPC API (available: eth, debug)"
|
|
defaultValue: @[]
|
|
defaultValueDesc: $RpcFlag.Eth
|
|
name: "ws-api" }: seq[string]
|
|
|
|
graphqlEnabled* {.
|
|
desc: "Enable the GraphQL HTTP server"
|
|
defaultValue: false
|
|
name: "graphql" }: bool
|
|
|
|
graphqlPort* {.
|
|
desc: "Listening port of the GraphQL HTTP server"
|
|
defaultValue: defaultEthGraphqlPort
|
|
defaultValueDesc: $defaultEthGraphqlPort
|
|
name: "graphql-port" }: Port
|
|
|
|
graphqlAddress* {.
|
|
desc: "Listening IP address of the GraphQL HTTP server"
|
|
defaultValue: defaultAdminListenAddress
|
|
defaultValueDesc: $defaultAdminListenAddressDesc
|
|
name: "graphql-address" }: ValidIpAddress
|
|
|
|
metricsEnabled* {.
|
|
desc: "Enable the built-in metrics HTTP server"
|
|
defaultValue: false
|
|
name: "metrics" }: bool
|
|
|
|
metricsPort* {.
|
|
desc: "Listening port of the built-in metrics HTTP server"
|
|
defaultValue: defaultMetricsServerPort
|
|
defaultValueDesc: $defaultMetricsServerPort
|
|
name: "metrics-port" }: Port
|
|
|
|
metricsAddress* {.
|
|
desc: "Listening IP address of the built-in metrics HTTP server"
|
|
defaultValue: defaultAdminListenAddress
|
|
defaultValueDesc: $defaultAdminListenAddressDesc
|
|
name: "metrics-address" }: ValidIpAddress
|
|
|
|
of `import`:
|
|
|
|
blocksFile* {.
|
|
argument
|
|
desc: "Import RLP encoded block(s) from a file, validate, write to database and quit"
|
|
defaultValue: ""
|
|
name: "blocks-file" }: InputFile
|
|
|
|
proc parseCmdArg(T: type NetworkId, p: TaintedString): T =
|
|
parseInt(p.string).T
|
|
|
|
proc completeCmdArg(T: type NetworkId, val: TaintedString): seq[string] =
|
|
return @[]
|
|
|
|
proc parseCmdArg(T: type UInt256, p: TaintedString): T =
|
|
parse(string p, T)
|
|
|
|
proc completeCmdArg(T: type UInt256, val: TaintedString): seq[string] =
|
|
return @[]
|
|
|
|
proc parseCmdArg(T: type EthAddress, p: TaintedString): T =
|
|
try:
|
|
result = hexToByteArray(p.string, 20)
|
|
except CatchableError:
|
|
raise newException(ValueError, "failed to parse EthAddress")
|
|
|
|
proc completeCmdArg(T: type EthAddress, val: TaintedString): seq[string] =
|
|
return @[]
|
|
|
|
proc processList(v: string, o: var seq[string]) =
|
|
## Process comma-separated list of strings.
|
|
if len(v) > 0:
|
|
for n in v.split({' ', ','}):
|
|
if len(n) > 0:
|
|
o.add(n)
|
|
|
|
proc parseCmdArg(T: type NetworkParams, p: TaintedString): T =
|
|
try:
|
|
if not loadNetworkParams(p.string, result):
|
|
raise newException(ValueError, "failed to load customNetwork")
|
|
except Exception as exc:
|
|
# on linux/mac, nim compiler refuse to compile
|
|
# with unlisted exception error
|
|
raise newException(ValueError, "failed to load customNetwork")
|
|
|
|
proc completeCmdArg(T: type NetworkParams, val: TaintedString): seq[string] =
|
|
return @[]
|
|
|
|
proc setBootnodes(output: var seq[ENode], nodeUris: openarray[string]) =
|
|
output = newSeqOfCap[ENode](nodeUris.len)
|
|
for item in nodeUris:
|
|
output.add(ENode.fromString(item).tryGet())
|
|
|
|
iterator repeatingList(listOfList: openArray[string]): string =
|
|
for strList in listOfList:
|
|
var list = newSeq[string]()
|
|
processList(strList, list)
|
|
for item in list:
|
|
yield item
|
|
|
|
proc append(output: var seq[ENode], nodeUris: openArray[string]) =
|
|
for item in repeatingList(nodeUris):
|
|
let res = ENode.fromString(item)
|
|
if res.isErr:
|
|
warn "Ignoring invalid bootstrap address", address=item
|
|
continue
|
|
output.add res.get()
|
|
|
|
iterator strippedLines(filename: string): (int, string) =
|
|
var i = 0
|
|
for line in lines(filename):
|
|
let stripped = strip(line)
|
|
if stripped.startsWith('#'): # Comments
|
|
continue
|
|
|
|
if stripped.len > 0:
|
|
yield (i, stripped)
|
|
inc i
|
|
|
|
proc loadEnodeFile(fileName: string; output: var seq[Enode]; info: string) =
|
|
if fileName.len == 0:
|
|
return
|
|
|
|
try:
|
|
for i, ln in strippedLines(fileName):
|
|
if cmpIgnoreCase(ln, "override") == 0 and i == 0:
|
|
# override built-in list if the first line is 'override'
|
|
output = newSeq[ENode]()
|
|
continue
|
|
|
|
let res = ENode.fromString(ln)
|
|
if res.isErr:
|
|
warn "Ignoring invalid address", address=ln, line=i, file=fileName, purpose=info
|
|
continue
|
|
|
|
output.add res.get()
|
|
|
|
except IOError as e:
|
|
error "Could not read file", msg = e.msg, purpose = info
|
|
quit 1
|
|
|
|
proc loadBootstrapFile(fileName: string, output: var seq[Enode]) =
|
|
fileName.loadEnodeFile(output, "bootstrap")
|
|
|
|
proc loadStaticPeersFile(fileName: string, output: var seq[Enode]) =
|
|
fileName.loadEnodeFile(output, "static peers")
|
|
|
|
proc getNetworkId(conf: NimbusConf): Option[NetworkId] =
|
|
if conf.network.len == 0:
|
|
return none NetworkId
|
|
|
|
let network = toLowerAscii(conf.network)
|
|
case network
|
|
of "mainnet": return some MainNet
|
|
of "ropsten": return some RopstenNet
|
|
of "rinkeby": return some RinkebyNet
|
|
of "goerli" : return some GoerliNet
|
|
of "kovan" : return some KovanNet
|
|
else:
|
|
try:
|
|
some parseInt(network).NetworkId
|
|
except CatchableError:
|
|
error "Failed to parse network name or id", network
|
|
quit QuitFailure
|
|
|
|
proc getProtocolFlags*(conf: NimbusConf): set[ProtocolFlag] =
|
|
if conf.protocols.len == 0:
|
|
return {ProtocolFlag.Eth}
|
|
|
|
for item in repeatingList(conf.protocols):
|
|
case item.toLowerAscii()
|
|
of "eth": result.incl ProtocolFlag.Eth
|
|
of "les": result.incl ProtocolFlag.Les
|
|
else:
|
|
error "Unknown protocol", name=item
|
|
quit QuitFailure
|
|
|
|
proc getRpcFlags(api: openArray[string]): set[RpcFlag] =
|
|
if api.len == 0:
|
|
return {RpcFlag.Eth}
|
|
|
|
for item in repeatingList(api):
|
|
case item.toLowerAscii()
|
|
of "eth": result.incl RpcFlag.Eth
|
|
of "debug": result.incl RpcFlag.Debug
|
|
else:
|
|
error "Unknown RPC API: ", name=item
|
|
quit QuitFailure
|
|
|
|
proc getRpcFlags*(conf: NimbusConf): set[RpcFlag] =
|
|
getRpcFlags(conf.rpcApi)
|
|
|
|
proc getWsFlags*(conf: NimbusConf): set[RpcFlag] =
|
|
getRpcFlags(conf.wsApi)
|
|
|
|
proc getBootNodes*(conf: NimbusConf): seq[Enode] =
|
|
# Ignore standard bootnodes if customNetwork is loaded
|
|
if conf.customNetwork.isNone:
|
|
case conf.networkId
|
|
of MainNet:
|
|
result.setBootnodes(MainnetBootnodes)
|
|
of RopstenNet:
|
|
result.setBootnodes(RopstenBootnodes)
|
|
of RinkebyNet:
|
|
result.setBootnodes(RinkebyBootnodes)
|
|
of GoerliNet:
|
|
result.setBootnodes(GoerliBootnodes)
|
|
of KovanNet:
|
|
result.setBootnodes(KovanBootnodes)
|
|
else:
|
|
# custom network id
|
|
discard
|
|
|
|
# always allow custom boostrap nodes
|
|
# if it is set by user
|
|
if conf.bootstrapNodes.len > 0:
|
|
result.append(conf.bootstrapNodes)
|
|
|
|
# bootstrap nodes loaded from file might append or
|
|
# override built-in bootnodes
|
|
loadBootstrapFile(string conf.bootstrapFile, result)
|
|
|
|
proc getStaticPeers*(conf: NimbusConf): seq[Enode] =
|
|
result.append(conf.staticPeers)
|
|
loadStaticPeersFile(string conf.staticPeersFile, result)
|
|
|
|
proc makeConfig*(cmdLine = commandLineParams()): NimbusConf =
|
|
{.push warning[ProveInit]: off.}
|
|
result = NimbusConf.load(
|
|
cmdLine,
|
|
version = NimbusBuild,
|
|
copyrightBanner = NimbusHeader
|
|
)
|
|
{.pop.}
|
|
|
|
var networkId = result.getNetworkId()
|
|
|
|
if result.customNetwork.isSome:
|
|
result.networkParams = result.customNetwork.get()
|
|
if networkId.isNone:
|
|
# WARNING: networkId and chainId are two distinct things
|
|
# they usage should not be mixed in other places.
|
|
# We only set networkId to chainId if networkId not set in cli and
|
|
# --custom-network is set.
|
|
# If chainId is not defined in config file, it's ok because
|
|
# zero means CustomNet
|
|
networkId = some(NetworkId(result.networkParams.config.chainId))
|
|
|
|
if networkId.isNone:
|
|
# bootnodes is set via getBootNodes
|
|
networkId = some MainNet
|
|
|
|
result.networkId = networkId.get()
|
|
|
|
if result.customNetwork.isNone:
|
|
result.networkParams = networkParams(result.networkId)
|
|
|
|
if result.cmd == noCommand:
|
|
if result.udpPort == Port(0):
|
|
# if udpPort not set in cli, then
|
|
result.udpPort = result.tcpPort
|
|
|
|
when isMainModule:
|
|
# for testing purpose
|
|
discard makeConfig()
|