2021-06-16 19:18:45 +00:00
|
|
|
# Nimbus
|
|
|
|
# Copyright (c) 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.
|
|
|
|
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
|
|
|
import
|
2021-09-28 17:58:41 +00:00
|
|
|
std/os,
|
2021-06-16 19:18:45 +00:00
|
|
|
confutils, confutils/std/net, chronicles, chronicles/topics_registry,
|
2021-07-09 11:34:16 +00:00
|
|
|
chronos, metrics, metrics/chronos_httpserver, json_rpc/clients/httpclient,
|
2021-11-24 11:12:25 +00:00
|
|
|
json_rpc/rpcproxy, stew/[byteutils, io2],
|
2021-06-16 19:18:45 +00:00
|
|
|
eth/keys, eth/net/nat,
|
|
|
|
eth/p2p/discoveryv5/protocol as discv5_protocol,
|
2021-11-24 11:12:25 +00:00
|
|
|
./conf, ./common/common_utils,
|
2022-01-14 15:07:14 +00:00
|
|
|
./rpc/[rpc_eth_api, bridge_client, rpc_discovery_api, rpc_portal_api,
|
|
|
|
rpc_portal_debug_api],
|
2021-09-28 17:58:41 +00:00
|
|
|
./network/state/[state_network, state_content],
|
2021-10-09 11:22:03 +00:00
|
|
|
./network/history/[history_network, history_content],
|
2022-01-18 08:01:22 +00:00
|
|
|
./network/wire/[portal_stream, portal_protocol_config],
|
2022-01-18 14:08:02 +00:00
|
|
|
"."/[content_db, populate_db]
|
2021-07-02 05:30:48 +00:00
|
|
|
|
|
|
|
proc initializeBridgeClient(maybeUri: Option[string]): Option[BridgeClient] =
|
|
|
|
try:
|
|
|
|
if (maybeUri.isSome()):
|
|
|
|
let uri = maybeUri.unsafeGet()
|
|
|
|
# TODO: Add possiblity to start client on differnt transports based on uri.
|
|
|
|
let httpClient = newRpcHttpClient()
|
|
|
|
waitFor httpClient.connect(uri)
|
|
|
|
notice "Initialized bridge client:", uri = uri
|
|
|
|
return some[BridgeClient](httpClient)
|
|
|
|
else:
|
|
|
|
return none(BridgeClient)
|
|
|
|
except CatchableError as err:
|
|
|
|
notice "Failed to initialize bridge client", error = err.msg
|
|
|
|
return none(BridgeClient)
|
2021-06-16 19:18:45 +00:00
|
|
|
|
|
|
|
proc run(config: PortalConf) {.raises: [CatchableError, Defect].} =
|
|
|
|
let
|
|
|
|
rng = newRng()
|
|
|
|
bindIp = config.listenAddress
|
|
|
|
udpPort = Port(config.udpPort)
|
|
|
|
# TODO: allow for no TCP port mapping!
|
|
|
|
(extIp, _, extUdpPort) =
|
|
|
|
try: setupAddress(config.nat,
|
|
|
|
config.listenAddress, udpPort, udpPort, "dcli")
|
|
|
|
except CatchableError as exc: raise exc
|
|
|
|
# TODO: Ideally we don't have the Exception here
|
|
|
|
except Exception as exc: raiseAssert exc.msg
|
|
|
|
|
2021-11-24 11:12:25 +00:00
|
|
|
var bootstrapRecords: seq[Record]
|
|
|
|
loadBootstrapFile(string config.bootstrapNodesFile, bootstrapRecords)
|
|
|
|
bootstrapRecords.add(config.bootstrapNodes)
|
|
|
|
|
2021-12-13 08:06:29 +00:00
|
|
|
let d = newProtocol(
|
2021-12-13 13:12:51 +00:00
|
|
|
config.networkKey,
|
2021-12-13 08:06:29 +00:00
|
|
|
extIp, none(Port), extUdpPort,
|
|
|
|
bootstrapRecords = bootstrapRecords,
|
|
|
|
bindIp = bindIp, bindPort = udpPort,
|
|
|
|
enrAutoUpdate = config.enrAutoUpdate,
|
|
|
|
rng = rng)
|
2021-06-16 19:18:45 +00:00
|
|
|
|
|
|
|
d.open()
|
|
|
|
|
2021-09-28 17:58:41 +00:00
|
|
|
# Store the database at contentdb prefixed with the first 8 chars of node id.
|
|
|
|
# This is done because the content in the db is dependant on the `NodeId` and
|
|
|
|
# the selected `Radius`.
|
2022-01-14 15:07:14 +00:00
|
|
|
let
|
|
|
|
db = ContentDB.new(config.dataDir / "db" / "contentdb_" &
|
2021-09-28 17:58:41 +00:00
|
|
|
d.localNode.id.toByteArrayBE().toOpenArray(0, 8).toHex())
|
|
|
|
|
2022-01-14 15:07:14 +00:00
|
|
|
# One instance of PortalStream and thus UtpDiscv5Protocol is shared over all
|
|
|
|
# the Portal networks.
|
2022-01-18 08:01:22 +00:00
|
|
|
portalConfig = PortalProtocolConfig.init(
|
|
|
|
config.tableIpLimit, config.bucketIpLimit, config.bitsPerHop)
|
2022-01-14 15:07:14 +00:00
|
|
|
portalStream = PortalStream.new(d)
|
|
|
|
stateNetwork = StateNetwork.new(d, db, portalStream,
|
2022-01-18 08:01:22 +00:00
|
|
|
bootstrapRecords = bootstrapRecords, portalConfig = portalConfig)
|
2022-01-14 15:07:14 +00:00
|
|
|
historyNetwork = HistoryNetwork.new(d, db, portalStream,
|
2022-01-18 08:01:22 +00:00
|
|
|
bootstrapRecords = bootstrapRecords, portalConfig = portalConfig)
|
2021-10-09 11:22:03 +00:00
|
|
|
|
2021-11-24 11:12:25 +00:00
|
|
|
# TODO: If no new network key is generated then we should first check if an
|
|
|
|
# enr file exists, and in the case it does read out the seqNum from it and
|
|
|
|
# reuse that.
|
|
|
|
let enrFile = config.dataDir / "fluffy_node.enr"
|
|
|
|
if io2.writeFile(enrFile, d.localNode.record.toURI()).isErr:
|
|
|
|
fatal "Failed to write the enr file", file = enrFile
|
|
|
|
quit 1
|
2021-06-16 19:18:45 +00:00
|
|
|
|
|
|
|
if config.metricsEnabled:
|
|
|
|
let
|
|
|
|
address = config.metricsAddress
|
|
|
|
port = config.metricsPort
|
|
|
|
notice "Starting metrics HTTP server",
|
|
|
|
url = "http://" & $address & ":" & $port & "/metrics"
|
|
|
|
try:
|
|
|
|
chronos_httpserver.startMetricsHttpServer($address, port)
|
|
|
|
except CatchableError as exc: raise exc
|
|
|
|
# TODO: Ideally we don't have the Exception here
|
|
|
|
except Exception as exc: raiseAssert exc.msg
|
|
|
|
|
2021-06-18 17:20:48 +00:00
|
|
|
if config.rpcEnabled:
|
2021-07-07 12:13:27 +00:00
|
|
|
let ta = initTAddress(config.rpcAddress, config.rpcPort)
|
2021-08-05 06:14:25 +00:00
|
|
|
var rpcHttpServerWithProxy = RpcProxy.new([ta], config.proxyUri)
|
2021-07-07 12:13:27 +00:00
|
|
|
rpcHttpServerWithProxy.installEthApiHandlers()
|
2021-08-27 16:04:55 +00:00
|
|
|
rpcHttpServerWithProxy.installDiscoveryApiHandlers(d)
|
2021-11-24 13:53:01 +00:00
|
|
|
rpcHttpServerWithProxy.installPortalApiHandlers(stateNetwork.portalProtocol, "state")
|
2021-12-20 10:57:55 +00:00
|
|
|
rpcHttpServerWithProxy.installPortalApiHandlers(historyNetwork.portalProtocol, "history")
|
2022-01-14 15:07:14 +00:00
|
|
|
rpcHttpServerWithProxy.installPortalDebugApiHandlers(stateNetwork.portalProtocol, "state")
|
|
|
|
rpcHttpServerWithProxy.installPortalDebugApiHandlers(stateNetwork.portalProtocol, "history")
|
2021-07-07 12:13:27 +00:00
|
|
|
# TODO for now we can only proxy to local node (or remote one without ssl) to make it possible
|
|
|
|
# to call infura https://github.com/status-im/nim-json-rpc/pull/101 needs to get merged for http client to support https/
|
2021-08-05 06:14:25 +00:00
|
|
|
waitFor rpcHttpServerWithProxy.start()
|
2021-06-18 17:20:48 +00:00
|
|
|
|
2021-07-02 05:30:48 +00:00
|
|
|
let bridgeClient = initializeBridgeClient(config.bridgeUri)
|
|
|
|
|
2021-06-16 19:18:45 +00:00
|
|
|
d.start()
|
2021-09-22 15:07:14 +00:00
|
|
|
stateNetwork.start()
|
2021-10-09 11:22:03 +00:00
|
|
|
historyNetwork.start()
|
2021-06-16 19:18:45 +00:00
|
|
|
|
|
|
|
runForever()
|
|
|
|
|
|
|
|
when isMainModule:
|
|
|
|
{.pop.}
|
|
|
|
let config = PortalConf.load()
|
|
|
|
{.push raises: [Defect].}
|
|
|
|
|
|
|
|
setLogLevel(config.logLevel)
|
|
|
|
|
|
|
|
case config.cmd
|
2022-01-18 14:08:02 +00:00
|
|
|
of PortalCmd.noCommand:
|
|
|
|
run(config)
|
|
|
|
of PortalCmd.populateHistoryDb:
|
|
|
|
let res = populateHistoryDb(config.dbDir.string, config.dataFile.string)
|
|
|
|
if res.isErr():
|
|
|
|
fatal "Failed populating the history content db", error = $res.error
|
|
|
|
quit 1
|