mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-05 08:45:27 +00:00
dbe3393f5c
* Fix eth/common & web3 related deprecation warnings for fluffy This commit uses the new types in the new eth/common/ structure to remove deprecation warnings. It is however more than just a mass replace as also all places where eth/common or eth/common/eth_types or eth/common/eth_types_rlp got imported have been revised and adjusted to a better per submodule based import. There are still a bunch of toMDigest deprecation warnings but that convertor is not needed for fluffy code anymore so in theory it should not be used (bug?). It seems to still get imported via export leaks ffrom imported nimbus code I think. * Address review comments * Remove two more unused eth/common imports
425 lines
13 KiB
Nim
425 lines
13 KiB
Nim
# Fluffy
|
|
# Copyright (c) 2021-2024 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: [].}
|
|
|
|
import
|
|
std/[os, strutils],
|
|
uri,
|
|
confutils,
|
|
confutils/std/net,
|
|
chronicles,
|
|
eth/common/keys,
|
|
eth/p2p/discoveryv5/[enr, node, routing_table],
|
|
nimcrypto/hash,
|
|
stew/byteutils,
|
|
eth/net/nat, # must be late (compilation annoyance)
|
|
./logging,
|
|
./network/wire/portal_protocol_config
|
|
|
|
proc defaultDataDir*(): string =
|
|
let dataDir =
|
|
when defined(windows):
|
|
"AppData" / "Roaming" / "Fluffy"
|
|
elif defined(macosx):
|
|
"Library" / "Application Support" / "Fluffy"
|
|
else:
|
|
".cache" / "fluffy"
|
|
|
|
getHomeDir() / dataDir
|
|
|
|
const
|
|
defaultListenAddress* = (static parseIpAddress("0.0.0.0"))
|
|
defaultAdminListenAddress* = (static parseIpAddress("127.0.0.1"))
|
|
|
|
defaultListenAddressDesc = $defaultListenAddress
|
|
defaultAdminListenAddressDesc = $defaultAdminListenAddress
|
|
defaultDataDirDesc = defaultDataDir()
|
|
defaultStorageCapacity* = 2000'u32 # 2 GB default
|
|
defaultStorageCapacityDesc* = $defaultStorageCapacity
|
|
|
|
defaultTableIpLimitDesc* = $defaultPortalProtocolConfig.tableIpLimits.tableIpLimit
|
|
defaultBucketIpLimitDesc* = $defaultPortalProtocolConfig.tableIpLimits.bucketIpLimit
|
|
defaultBitsPerHopDesc* = $defaultPortalProtocolConfig.bitsPerHop
|
|
defaultMaxGossipNodesDesc* = $defaultPortalProtocolConfig.maxGossipNodes
|
|
defaultRpcApis* = @["eth", "portal"]
|
|
defaultRpcApisDesc* = "eth,portal"
|
|
|
|
type
|
|
RpcFlag* {.pure.} = enum
|
|
eth
|
|
debug
|
|
portal
|
|
portal_debug
|
|
discovery
|
|
|
|
TrustedDigest* = MDigest[32 * 8]
|
|
|
|
PortalCmd* = enum
|
|
noCommand
|
|
|
|
PortalConf* = object
|
|
logLevel* {.
|
|
desc:
|
|
"Sets the log level for process and topics (e.g. \"DEBUG; TRACE:discv5,portal_wire; REQUIRED:none; DISABLED:none\")",
|
|
defaultValue: "INFO",
|
|
name: "log-level"
|
|
.}: string
|
|
|
|
logStdout* {.
|
|
hidden,
|
|
desc:
|
|
"Specifies what kind of logs should be written to stdout (auto, colors, nocolors, json)",
|
|
defaultValueDesc: "auto",
|
|
defaultValue: StdoutLogKind.Auto,
|
|
name: "log-format"
|
|
.}: StdoutLogKind
|
|
|
|
udpPort* {.defaultValue: 9009, desc: "UDP listening port", name: "udp-port".}:
|
|
uint16
|
|
|
|
listenAddress* {.
|
|
defaultValue: defaultListenAddress,
|
|
defaultValueDesc: $defaultListenAddressDesc,
|
|
desc: "Listening address for the Discovery v5 traffic",
|
|
name: "listen-address"
|
|
.}: IpAddress
|
|
|
|
network* {.
|
|
desc:
|
|
"Select which Portal network to join. This will set the " &
|
|
"Portal network specific bootstrap nodes automatically",
|
|
defaultValue: PortalNetwork.mainnet,
|
|
name: "network"
|
|
.}: PortalNetwork
|
|
|
|
portalSubnetworks* {.
|
|
desc: "Select which networks (Portal sub-protocols) to enable",
|
|
defaultValue: {PortalSubnetwork.history, PortalSubnetwork.state},
|
|
name: "portal-subnetworks"
|
|
.}: set[PortalSubnetwork]
|
|
|
|
# Note: This will add bootstrap nodes for both Discovery v5 network and each
|
|
# enabled Portal network. No distinction is made on bootstrap nodes per
|
|
# specific network.
|
|
bootstrapNodes* {.
|
|
desc:
|
|
"ENR URI of node to bootstrap Discovery v5 and the Portal networks from. Argument may be repeated",
|
|
name: "bootstrap-node"
|
|
.}: seq[Record]
|
|
|
|
bootstrapNodesFile* {.
|
|
desc:
|
|
"Specifies a line-delimited file of ENR URIs to bootstrap Discovery v5 and Portal networks from",
|
|
defaultValue: "",
|
|
name: "bootstrap-file"
|
|
.}: InputFile
|
|
|
|
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
|
|
|
|
enrAutoUpdate* {.
|
|
defaultValue: false,
|
|
desc:
|
|
"Discovery can automatically update its ENR with the IP address " &
|
|
"and UDP port as seen by other nodes it communicates with. " &
|
|
"This option allows to enable/disable this functionality",
|
|
name: "enr-auto-update"
|
|
.}: bool
|
|
|
|
dataDir* {.
|
|
desc: "The directory where fluffy will store the content data",
|
|
defaultValue: defaultDataDir(),
|
|
defaultValueDesc: $defaultDataDirDesc,
|
|
name: "data-dir"
|
|
.}: OutDir
|
|
|
|
networkKeyFile* {.
|
|
desc: "Source of network (secp256k1) private key file",
|
|
defaultValue: config.dataDir / "netkey",
|
|
name: "netkey-file"
|
|
.}: string
|
|
|
|
networkKey* {.
|
|
hidden,
|
|
desc: "Private key (secp256k1) for the p2p network, hex encoded.",
|
|
defaultValue: none(PrivateKey),
|
|
defaultValueDesc: "none",
|
|
name: "netkey-unsafe"
|
|
.}: Option[PrivateKey]
|
|
|
|
accumulatorFile* {.
|
|
desc:
|
|
"Get the master accumulator snapshot from a file containing an " &
|
|
"pre-build SSZ encoded master accumulator.",
|
|
defaultValue: none(InputFile),
|
|
defaultValueDesc: "none",
|
|
name: "accumulator-file"
|
|
.}: Option[InputFile]
|
|
|
|
metricsEnabled* {.
|
|
defaultValue: false, desc: "Enable the metrics server", name: "metrics"
|
|
.}: bool
|
|
|
|
metricsAddress* {.
|
|
defaultValue: defaultAdminListenAddress,
|
|
defaultValueDesc: $defaultAdminListenAddressDesc,
|
|
desc: "Listening address of the metrics server",
|
|
name: "metrics-address"
|
|
.}: IpAddress
|
|
|
|
metricsPort* {.
|
|
defaultValue: 8008,
|
|
desc: "Listening HTTP port of the metrics server",
|
|
name: "metrics-port"
|
|
.}: Port
|
|
|
|
rpcEnabled* {.
|
|
desc: "Enable the HTTP JSON-RPC server", defaultValue: false, name: "rpc"
|
|
.}: bool
|
|
|
|
rpcAddress* {.
|
|
desc: "Listening address of the RPC server",
|
|
defaultValue: defaultAdminListenAddress,
|
|
defaultValueDesc: $defaultAdminListenAddressDesc,
|
|
name: "rpc-address"
|
|
.}: IpAddress
|
|
|
|
rpcPort* {.
|
|
desc: "Port for the HTTP JSON-RPC server", defaultValue: 8545, name: "rpc-port"
|
|
.}: Port
|
|
|
|
rpcApi* {.
|
|
desc:
|
|
"Enable specific set of RPC APIs (available: eth, debug, portal, portal_debug, discovery)",
|
|
defaultValue: defaultRpcApis,
|
|
defaultValueDesc: $defaultRpcApisDesc,
|
|
name: "rpc-api"
|
|
.}: seq[string]
|
|
|
|
wsEnabled* {.
|
|
desc: "Enable the WebSocket JSON-RPC server", defaultValue: false, name: "ws"
|
|
.}: bool
|
|
|
|
wsPort* {.
|
|
desc: "Port for the WebSocket JSON-RPC server",
|
|
defaultValue: 8546,
|
|
name: "ws-port"
|
|
.}: Port
|
|
|
|
wsCompression* {.
|
|
desc: "Enable compression for the WebSocket JSON-RPC server",
|
|
defaultValue: false,
|
|
name: "ws-compression"
|
|
.}: bool
|
|
|
|
tableIpLimit* {.
|
|
hidden,
|
|
desc:
|
|
"Maximum amount of nodes with the same IP in the routing table. " &
|
|
"This option is currently required as many nodes are running from " &
|
|
"the same machines. The option might be removed/adjusted in the future",
|
|
defaultValue: defaultPortalProtocolConfig.tableIpLimits.tableIpLimit,
|
|
defaultValueDesc: $defaultTableIpLimitDesc,
|
|
name: "table-ip-limit"
|
|
.}: uint
|
|
|
|
bucketIpLimit* {.
|
|
hidden,
|
|
desc:
|
|
"Maximum amount of nodes with the same IP in the routing table's buckets. " &
|
|
"This option is currently required as many nodes are running from " &
|
|
"the same machines. The option might be removed/adjusted in the future",
|
|
defaultValue: defaultPortalProtocolConfig.tableIpLimits.bucketIpLimit,
|
|
defaultValueDesc: $defaultBucketIpLimitDesc,
|
|
name: "bucket-ip-limit"
|
|
.}: uint
|
|
|
|
bitsPerHop* {.
|
|
hidden,
|
|
desc: "Kademlia's b variable, increase for less hops per lookup",
|
|
defaultValue: defaultPortalProtocolConfig.bitsPerHop,
|
|
defaultValueDesc: $defaultBitsPerHopDesc,
|
|
name: "bits-per-hop"
|
|
.}: int
|
|
|
|
maxGossipNodes* {.
|
|
hidden,
|
|
desc: "The maximum number of nodes to send content to during gossip",
|
|
defaultValue: defaultPortalProtocolConfig.maxGossipNodes,
|
|
defaultValueDesc: $defaultMaxGossipNodesDesc,
|
|
name: "max-gossip-nodes"
|
|
.}: int
|
|
|
|
radiusConfig* {.
|
|
desc:
|
|
"Radius configuration for a fluffy node. Radius can be either `dynamic` " &
|
|
"where the node adjusts the radius based on `storage-size` option, " &
|
|
"or `static:<logRadius>` where the node has a hardcoded logarithmic radius value. " &
|
|
"Warning: `static:<logRadius>` disables `storage-size` limits and " &
|
|
"makes the node store a fraction of the network based on set radius.",
|
|
defaultValue: defaultRadiusConfig,
|
|
defaultValueDesc: $defaultRadiusConfigDesc,
|
|
name: "radius"
|
|
.}: RadiusConfig
|
|
|
|
# TODO maybe it is worth defining minimal storage size and throw error if
|
|
# value provided is smaller than minimum
|
|
storageCapacityMB* {.
|
|
desc:
|
|
"Maximum amount (in megabytes) of content which will be stored " &
|
|
"in the local database.",
|
|
defaultValue: defaultStorageCapacity,
|
|
defaultValueDesc: $defaultStorageCapacityDesc,
|
|
name: "storage-capacity"
|
|
.}: uint64
|
|
|
|
trustedBlockRoot* {.
|
|
desc:
|
|
"Recent trusted finalized block root to initialize the consensus light client from. " &
|
|
"If not provided by the user, portal light client will be disabled.",
|
|
defaultValue: none(TrustedDigest),
|
|
name: "trusted-block-root"
|
|
.}: Option[TrustedDigest]
|
|
|
|
forcePrune* {.
|
|
hidden,
|
|
desc:
|
|
"Force the pruning of the database. This should be used when the " &
|
|
"database is decreased in size, e.g. when a lower static radius " &
|
|
"or a lower storage capacity is set.",
|
|
defaultValue: false,
|
|
name: "force-prune"
|
|
.}: bool
|
|
|
|
disablePoke* {.
|
|
hidden,
|
|
desc: "Disable POKE functionality for gossip mechanisms testing",
|
|
defaultValue: defaultDisablePoke,
|
|
defaultValueDesc: $defaultDisablePoke,
|
|
name: "disable-poke"
|
|
.}: bool
|
|
|
|
disableStateRootValidation* {.
|
|
hidden,
|
|
desc: "Disables state root validation for content received by the state network.",
|
|
defaultValue: false,
|
|
name: "disable-state-root-validation"
|
|
.}: bool
|
|
|
|
case cmd* {.command, defaultValue: noCommand.}: PortalCmd
|
|
of noCommand:
|
|
discard
|
|
|
|
func parseCmdArg*(T: type TrustedDigest, input: string): T {.raises: [ValueError].} =
|
|
TrustedDigest.fromHex(input)
|
|
|
|
func completeCmdArg*(T: type TrustedDigest, input: string): seq[string] =
|
|
return @[]
|
|
|
|
proc parseCmdArg*(T: type enr.Record, p: string): T {.raises: [ValueError].} =
|
|
let res = enr.Record.fromURI(p)
|
|
if res.isErr():
|
|
raise newException(ValueError, "Invalid ENR: " & $res.error)
|
|
res.value
|
|
|
|
proc completeCmdArg*(T: type enr.Record, val: string): seq[string] =
|
|
return @[]
|
|
|
|
proc parseCmdArg*(T: type Node, p: string): T {.raises: [ValueError].} =
|
|
let res = enr.Record.fromURI(p)
|
|
if res.isErr():
|
|
raise newException(ValueError, "Invalid ENR: " & $res.error)
|
|
|
|
let n = Node.fromRecord(res.value)
|
|
if n.address.isNone():
|
|
raise newException(ValueError, "ENR without address")
|
|
|
|
n
|
|
|
|
proc completeCmdArg*(T: type Node, val: string): seq[string] =
|
|
return @[]
|
|
|
|
proc parseCmdArg*(T: type PrivateKey, p: string): T {.raises: [ValueError].} =
|
|
try:
|
|
result = PrivateKey.fromHex(p).tryGet()
|
|
except CatchableError:
|
|
raise newException(ValueError, "Invalid private key")
|
|
|
|
proc completeCmdArg*(T: type PrivateKey, val: string): seq[string] =
|
|
return @[]
|
|
|
|
proc parseCmdArg*(
|
|
T: type set[PortalSubnetwork], p: string
|
|
): T {.raises: [ValueError].} =
|
|
var res: set[PortalSubnetwork] = {}
|
|
let values = p.split({' ', ','})
|
|
for value in values:
|
|
let stripped = value.strip()
|
|
let network =
|
|
try:
|
|
parseEnum[PortalSubnetwork](stripped)
|
|
except ValueError:
|
|
raise newException(ValueError, "Invalid network: " & stripped)
|
|
|
|
res.incl(network)
|
|
res
|
|
|
|
proc completeCmdArg*(T: type set[PortalSubnetwork], val: string): seq[string] =
|
|
return @[]
|
|
|
|
chronicles.formatIt(InputDir):
|
|
$it
|
|
chronicles.formatIt(OutDir):
|
|
$it
|
|
chronicles.formatIt(InputFile):
|
|
$it
|
|
|
|
func 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)
|
|
|
|
iterator repeatingList(listOfList: openArray[string]): string =
|
|
for strList in listOfList:
|
|
var list = newSeq[string]()
|
|
processList(strList, list)
|
|
for item in list:
|
|
yield item
|
|
|
|
proc getRpcFlags*(rpcApis: openArray[string]): set[RpcFlag] =
|
|
if rpcApis.len == 0:
|
|
error "No RPC APIs specified"
|
|
quit QuitFailure
|
|
|
|
var rpcFlags: set[RpcFlag]
|
|
for apiStr in rpcApis.repeatingList():
|
|
case apiStr.toLowerAscii()
|
|
of "eth":
|
|
rpcFlags.incl RpcFlag.eth
|
|
of "debug":
|
|
rpcFlags.incl RpcFlag.debug
|
|
of "portal":
|
|
rpcFlags.incl RpcFlag.portal
|
|
of "portal_debug":
|
|
rpcFlags.incl RpcFlag.portal_debug
|
|
of "discovery":
|
|
rpcFlags.incl RpcFlag.discovery
|
|
else:
|
|
error "Unknown RPC API: ", name = apiStr
|
|
quit QuitFailure
|
|
|
|
rpcFlags
|