Add support for passing bootstrap file and write local enr file (#892)

Also use this now in the local testnet script instead of hardcoded
values.
This commit is contained in:
Kim De Mey 2021-11-24 12:12:25 +01:00 committed by GitHub
parent 903350bdde
commit 77cc9b6215
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 21 deletions

View File

@ -0,0 +1,45 @@
# 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
std/[os, strutils],
chronicles,
eth/p2p/discoveryv5/enr
iterator strippedLines(filename: string): string {.raises: [ref IOError].} =
for line in lines(filename):
let stripped = strip(line)
if stripped.startsWith('#'): # Comments
continue
if stripped.len > 0:
yield stripped
proc addBootstrapNode(bootstrapAddr: string,
bootstrapEnrs: var seq[Record]) =
var enrRec: enr.Record
if enrRec.fromURI(bootstrapAddr):
bootstrapEnrs.add enrRec
else:
warn "Ignoring invalid bootstrap ENR", bootstrapAddr
proc loadBootstrapFile*(bootstrapFile: string,
bootstrapEnrs: var seq[Record]) =
if bootstrapFile.len == 0: return
let ext = splitFile(bootstrapFile).ext
if cmpIgnoreCase(ext, ".txt") == 0 or cmpIgnoreCase(ext, ".enr") == 0 :
try:
for ln in strippedLines(bootstrapFile):
addBootstrapNode(ln, bootstrapEnrs)
except IOError as e:
fatal "Could not read bootstrap file", msg = e.msg
quit 1
else:
fatal "Unknown bootstrap file format", ext
quit 1

View File

@ -56,9 +56,14 @@ type
desc: "Listening address for the Discovery v5 traffic" desc: "Listening address for the Discovery v5 traffic"
name: "listen-address" }: ValidIpAddress name: "listen-address" }: ValidIpAddress
bootnodes* {. bootstrapNodes* {.
desc: "ENR URI of node to bootstrap Discovery v5 with. Argument may be repeated" desc: "ENR URI of node to bootstrap Discovery v5 from. Argument may be repeated"
name: "bootnode" .}: seq[Record] name: "bootstrap-node" .}: seq[Record]
bootstrapNodesFile* {.
desc: "Specifies a line-delimited file of ENR URIs to bootstrap Discovery v5 from"
defaultValue: ""
name: "bootstrap-file" }: InputFile
nat* {. nat* {.
desc: "Specify method to use for determining public address. " & desc: "Specify method to use for determining public address. " &
@ -88,9 +93,14 @@ type
# Note: This will add bootstrap nodes for each enabled Portal network. # Note: This will add bootstrap nodes for each enabled Portal network.
# No distinction is being made on bootstrap nodes for a specific network. # No distinction is being made on bootstrap nodes for a specific network.
portalBootnodes* {. portalBootstrapNodes* {.
desc: "ENR URI of node to bootstrap the Portal protocols with. Argument may be repeated" desc: "ENR URI of node to bootstrap the Portal networks from. Argument may be repeated"
name: "portal-bootnode" .}: seq[Record] name: "portal-bootstrap-node" .}: seq[Record]
portalBootstrapNodesFile* {.
desc: "Specifies a line-delimited file of ENR URIs to bootstrap the Portal networks from"
defaultValue: ""
name: "portal-bootstrap-file" }: InputFile
metricsEnabled* {. metricsEnabled* {.
defaultValue: false defaultValue: false

View File

@ -11,10 +11,11 @@ import
std/os, std/os,
confutils, confutils/std/net, chronicles, chronicles/topics_registry, confutils, confutils/std/net, chronicles, chronicles/topics_registry,
chronos, metrics, metrics/chronos_httpserver, json_rpc/clients/httpclient, chronos, metrics, metrics/chronos_httpserver, json_rpc/clients/httpclient,
json_rpc/rpcproxy, stew/byteutils, json_rpc/rpcproxy, stew/[byteutils, io2],
eth/keys, eth/net/nat, eth/keys, eth/net/nat,
eth/p2p/discoveryv5/protocol as discv5_protocol, eth/p2p/discoveryv5/protocol as discv5_protocol,
./conf, ./rpc/[rpc_eth_api, bridge_client, rpc_discovery_api, rpc_portal_api], ./conf, ./common/common_utils,
./rpc/[rpc_eth_api, bridge_client, rpc_discovery_api, rpc_portal_api],
./network/state/[state_network, state_content], ./network/state/[state_network, state_content],
./network/history/[history_network, history_content], ./network/history/[history_network, history_content],
./content_db ./content_db
@ -47,9 +48,13 @@ proc run(config: PortalConf) {.raises: [CatchableError, Defect].} =
# TODO: Ideally we don't have the Exception here # TODO: Ideally we don't have the Exception here
except Exception as exc: raiseAssert exc.msg except Exception as exc: raiseAssert exc.msg
var bootstrapRecords: seq[Record]
loadBootstrapFile(string config.bootstrapNodesFile, bootstrapRecords)
bootstrapRecords.add(config.bootstrapNodes)
let d = newProtocol(config.nodeKey, let d = newProtocol(config.nodeKey,
extIp, none(Port), extUdpPort, extIp, none(Port), extUdpPort,
bootstrapRecords = config.bootnodes, bootstrapRecords = bootstrapRecords,
bindIp = bindIp, bindPort = udpPort, bindIp = bindIp, bindPort = udpPort,
enrAutoUpdate = config.enrAutoUpdate, enrAutoUpdate = config.enrAutoUpdate,
rng = rng) rng = rng)
@ -63,12 +68,23 @@ proc run(config: PortalConf) {.raises: [CatchableError, Defect].} =
ContentDB.new(config.dataDir / "db" / "contentdb_" & ContentDB.new(config.dataDir / "db" / "contentdb_" &
d.localNode.id.toByteArrayBE().toOpenArray(0, 8).toHex()) d.localNode.id.toByteArrayBE().toOpenArray(0, 8).toHex())
var portalBootstrapRecords: seq[Record]
loadBootstrapFile(string config.portalBootstrapNodesFile, portalBootstrapRecords)
portalBootstrapRecords.add(config.portalBootstrapNodes)
let let
stateNetwork = StateNetwork.new(d, db, stateNetwork = StateNetwork.new(d, db,
bootstrapRecords = config.portalBootnodes) bootstrapRecords = portalBootstrapRecords)
historyNetwork = HistoryNetwork.new(d, db, historyNetwork = HistoryNetwork.new(d, db,
bootstrapRecords = config.portalBootnodes) bootstrapRecords = portalBootstrapRecords)
# 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
if config.metricsEnabled: if config.metricsEnabled:
let let

View File

@ -217,7 +217,6 @@ if [[ "${TIMEOUT_DURATION}" != "0" ]]; then
fi fi
PIDS="" PIDS=""
BOOTSTRAP_TIMEOUT=30 # in seconds
NUM_JOBS=${NUM_NODES} NUM_JOBS=${NUM_NODES}
dump_logs() { dump_logs() {
@ -230,11 +229,8 @@ dump_logs() {
} }
BOOTSTRAP_NODE=0 BOOTSTRAP_NODE=0
# TODO: BOOTSTRAP_TIMEOUT=5 # in seconds
# For now we just hardcode a network key and the resulting ENR until fluffy BOOTSTRAP_ENR_FILE="${DATA_DIR}/node${BOOTSTRAP_NODE}/fluffy_node.enr"
# stores network keys and enrs locally in files.
NETWORK_KEY="0x29738ba0c1a4397d6a65f292eee07f02df8e58d41594ba2be3cf84ce0fc58169"
HARDCODED_BOOTSTRAP_ENR="enr:-IS4QDBoE7JdB3W9Jqc3Yoatk3Zw3PgkAcnhDKNFszdiPfm3IGNlvPl5CKiJLn9u5Kk-2QaieAGYvtMgR-EBqIWIqe0BgmlkgnY0gmlwhH8AAAGJc2VjcDI1NmsxoQNStnoFzDBxNc8-0t6xLnFpoJbovjIq_QeEHCVcfOKck4N1ZHCCIyg"
for NUM_NODE in $(seq 0 $(( NUM_NODES - 1 ))); do for NUM_NODE in $(seq 0 $(( NUM_NODES - 1 ))); do
NODE_DATA_DIR="${DATA_DIR}/node${NUM_NODE}" NODE_DATA_DIR="${DATA_DIR}/node${NUM_NODE}"
@ -245,10 +241,21 @@ done
echo "Starting ${NUM_NODES} nodes." echo "Starting ${NUM_NODES} nodes."
for NUM_NODE in $(seq 0 $(( NUM_NODES - 1 ))); do for NUM_NODE in $(seq 0 $(( NUM_NODES - 1 ))); do
NODE_DATA_DIR="${DATA_DIR}/node${NUM_NODE}" NODE_DATA_DIR="${DATA_DIR}/node${NUM_NODE}"
if [[ ${NUM_NODE} == ${BOOTSTRAP_NODE} ]]; then
BOOTSTRAP_ARG="--nodekey:${NETWORK_KEY}" if [[ ${NUM_NODE} != ${BOOTSTRAP_NODE} ]]; then
else BOOTSTRAP_ARG="--bootstrap-file=${BOOTSTRAP_ENR_FILE} --portal-bootstrap-file=${BOOTSTRAP_ENR_FILE}"
BOOTSTRAP_ARG="--bootnode=${HARDCODED_BOOTSTRAP_ENR} --portal-bootnode=${HARDCODED_BOOTSTRAP_ENR}"
# Wait for the bootstrap node to write out its enr file
START_TIMESTAMP=$(date +%s)
while [[ ! -f "${BOOTSTRAP_ENR_FILE}" ]]; do
sleep 0.1
NOW_TIMESTAMP=$(date +%s)
if [[ "$(( NOW_TIMESTAMP - START_TIMESTAMP - GENESIS_OFFSET ))" -ge "$BOOTSTRAP_TIMEOUT" ]]; then
echo "Bootstrap node failed to start in ${BOOTSTRAP_TIMEOUT} seconds. Aborting."
dump_logs
exit 1
fi
done
fi fi
# Increasing the loopback address here with NUM_NODE as listen address to # Increasing the loopback address here with NUM_NODE as listen address to