chore: discv5 re-org setup (#1815)

Key, netconfig, enr are created at App initialization and config files has been renamed.
This commit is contained in:
Simon-Pierre Vivier 2023-06-22 16:58:14 -04:00 committed by GitHub
parent a44d4bfbcd
commit 44f9d8dc0e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 198 additions and 104 deletions

View File

@ -41,7 +41,8 @@ import
../../waku/v2/waku_lightpush,
../../waku/v2/waku_filter,
./wakunode2_validator_signed,
./config
./internal_config,
./external_config
import
../../waku/v2/node/message_cache,
../../waku/v2/node/rest/server,
@ -69,8 +70,11 @@ type
App* = object
version: string
conf: WakuNodeConf
netConf: NetConfig
rng: ref HmacDrbgContext
key: crypto.PrivateKey
record: Record
peerStore: Option[WakuPeerStorage]
archiveDriver: Option[ArchiveDriver]
archiveRetentionPolicy: Option[RetentionPolicy]
@ -95,7 +99,41 @@ func version*(app: App): string =
## Initialisation
proc init*(T: type App, rng: ref HmacDrbgContext, conf: WakuNodeConf): T =
App(version: git_version, conf: conf, rng: rng, node: nil)
let key =
if conf.nodeKey.isSome():
conf.nodeKey.get()
else:
let keyRes = crypto.PrivateKey.random(Secp256k1, rng[])
if keyRes.isErr():
error "failed to generate key", error=keyRes.error
quit(QuitFailure)
keyRes.get()
let netConfigRes = networkConfiguration(conf)
let netConfig =
if netConfigRes.isErr():
error "failed to create internal config", error=netConfigRes.error
quit(QuitFailure)
else: netConfigRes.get()
let recordRes = createRecord(conf, netConfig, key)
let record =
if recordRes.isErr():
error "failed to create record", error=recordRes.error
quit(QuitFailure)
else: recordRes.get()
App(
version: git_version,
conf: conf,
netConf: netConfig,
rng: rng,
key: key,
record: record,
node: nil
)
## SQLite database
@ -318,7 +356,10 @@ proc setupDyamicBootstrapNodes*(app: var App): AppResult[void] =
## Init waku node instance
proc initNode(conf: WakuNodeConf,
netConfig: NetConfig,
rng: ref HmacDrbgContext,
nodeKey: crypto.PrivateKey,
record: enr.Record,
peerStore: Option[WakuPeerStorage],
dynamicBootstrapNodes: openArray[RemotePeerInfo] = @[]): AppResult[WakuNode] =
@ -335,83 +376,11 @@ proc initNode(conf: WakuNodeConf,
dnsResolver = DnsResolver.new(nameServers)
let
nodekey = if conf.nodekey.isSome():
conf.nodekey.get()
else:
let nodekeyRes = crypto.PrivateKey.random(Secp256k1, rng[])
if nodekeyRes.isErr():
return err("failed to generate nodekey: " & $nodekeyRes.error)
nodekeyRes.get()
## `udpPort` is only supplied to satisfy underlying APIs but is not
## actually a supported transport for libp2p traffic.
let udpPort = conf.tcpPort
let natRes = setupNat(conf.nat, clientId,
Port(uint16(conf.tcpPort) + conf.portsShift),
Port(uint16(udpPort) + conf.portsShift))
if natRes.isErr():
return err("failed to setup NAT: " & $natRes.error)
let (extIp, extTcpPort, _) = natRes.get()
let
dns4DomainName = if conf.dns4DomainName != "": some(conf.dns4DomainName)
else: none(string)
discv5UdpPort = if conf.discv5Discovery: some(Port(uint16(conf.discv5UdpPort) + conf.portsShift))
else: none(Port)
## TODO: the NAT setup assumes a manual port mapping configuration if extIp config is set. This probably
## implies adding manual config item for extPort as well. The following heuristic assumes that, in absence of manual
## config, the external port is the same as the bind port.
extPort = if (extIp.isSome() or dns4DomainName.isSome()) and extTcpPort.isNone():
some(Port(uint16(conf.tcpPort) + conf.portsShift))
else:
extTcpPort
extMultiAddrs = if (conf.extMultiAddrs.len > 0):
let extMultiAddrsValidationRes = validateExtMultiAddrs(conf.extMultiAddrs)
if extMultiAddrsValidationRes.isErr():
return err("invalid external multiaddress: " & extMultiAddrsValidationRes.error)
else:
extMultiAddrsValidationRes.get()
else:
@[]
wakuFlags = CapabilitiesBitfield.init(
lightpush = conf.lightpush,
filter = conf.filter,
store = conf.store,
relay = conf.relay
)
var node: WakuNode
let pStorage = if peerStore.isNone(): nil
else: peerStore.get()
let rng = crypto.newRng()
# Wrap in none because NetConfig does not have a default constructor
# TODO: We could change bindIp in NetConfig to be something less restrictive than ValidIpAddress,
# which doesn't allow default construction
let netConfigRes = NetConfig.init(
bindIp = conf.listenAddress,
bindPort = Port(uint16(conf.tcpPort) + conf.portsShift),
extIp = extIp,
extPort = extPort,
extMultiAddrs = extMultiAddrs,
wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift),
wsEnabled = conf.websocketSupport,
wssEnabled = conf.websocketSecureSupport,
dns4DomainName = dns4DomainName,
discv5UdpPort = discv5UdpPort,
wakuFlags = some(wakuFlags),
)
if netConfigRes.isErr():
return err("failed to create net config instance: " & netConfigRes.error)
let netConfig = netConfigRes.get()
var wakuDiscv5 = none(WakuDiscoveryV5)
if conf.discv5Discovery:
@ -449,6 +418,7 @@ proc initNode(conf: WakuNodeConf,
var builder = WakuNodeBuilder.init()
builder.withRng(rng)
builder.withNodeKey(nodekey)
builder.withRecord(record)
builder.withNetworkConfiguration(netConfig)
builder.withPeerStorage(pStorage, capacity = conf.peerStoreCapacity)
builder.withSwitchConfiguration(
@ -467,7 +437,7 @@ proc initNode(conf: WakuNodeConf,
proc setupWakuNode*(app: var App): AppResult[void] =
## Waku node
let initNodeRes = initNode(app.conf, app.rng, app.peerStore, app.dynamicBootstrapNodes)
let initNodeRes = initNode(app.conf, app.netConf, app.rng, app.key, app.record, app.peerStore, app.dynamicBootstrapNodes)
if initNodeRes.isErr():
return err("failed to init node: " & initNodeRes.error)
@ -477,7 +447,9 @@ proc setupWakuNode*(app: var App): AppResult[void] =
## Mount protocols
proc setupProtocols(node: WakuNode, conf: WakuNodeConf,
proc setupProtocols(node: WakuNode,
conf: WakuNodeConf,
nodeKey: crypto.PrivateKey,
archiveDriver: Option[ArchiveDriver],
archiveRetentionPolicy: Option[RetentionPolicy]): Future[AppResult[void]] {.async.} =
## Setup configured protocols on an existing Waku v2 node.
@ -626,6 +598,7 @@ proc setupAndMountProtocols*(app: App): Future[AppResult[void]] {.async.} =
return await setupProtocols(
app.node,
app.conf,
app.key,
app.archiveDriver,
app.archiveRetentionPolicy
)

View File

@ -16,7 +16,8 @@ import
import
../../waku/common/confutils/envvar/defs as confEnvvarDefs,
../../waku/common/confutils/envvar/std/net as confEnvvarNet,
../../waku/common/logging
../../waku/common/logging,
../../waku/v2/waku_enr
export
confTomlDefs,

View File

@ -0,0 +1,107 @@
import
stew/results,
libp2p/crypto/crypto
import
../../waku/common/utils/nat,
../../waku/v2/node/config,
../../waku/v2/node/waku_node,
../../waku/v2/waku_enr,
./external_config
proc networkConfiguration*(conf: WakuNodeConf): NetConfigResult =
## `udpPort` is only supplied to satisfy underlying APIs but is not
## actually a supported transport for libp2p traffic.
let udpPort = conf.tcpPort
let natRes = setupNat(conf.nat, clientId,
Port(uint16(conf.tcpPort) + conf.portsShift),
Port(uint16(udpPort) + conf.portsShift))
if natRes.isErr():
return err("failed to setup NAT: " & $natRes.error)
let (extIp, extTcpPort, _) = natRes.get()
let
dns4DomainName = if conf.dns4DomainName != "": some(conf.dns4DomainName)
else: none(string)
discv5UdpPort = if conf.discv5Discovery: some(Port(uint16(conf.discv5UdpPort) + conf.portsShift))
else: none(Port)
## TODO: the NAT setup assumes a manual port mapping configuration if extIp config is set. This probably
## implies adding manual config item for extPort as well. The following heuristic assumes that, in absence of manual
## config, the external port is the same as the bind port.
extPort = if (extIp.isSome() or dns4DomainName.isSome()) and extTcpPort.isNone():
some(Port(uint16(conf.tcpPort) + conf.portsShift))
else:
extTcpPort
extMultiAddrs = if (conf.extMultiAddrs.len > 0):
let extMultiAddrsValidationRes = validateExtMultiAddrs(conf.extMultiAddrs)
if extMultiAddrsValidationRes.isErr():
return err("invalid external multiaddress: " & $extMultiAddrsValidationRes.error)
else:
extMultiAddrsValidationRes.get()
else:
@[]
wakuFlags = CapabilitiesBitfield.init(
lightpush = conf.lightpush,
filter = conf.filter,
store = conf.store,
relay = conf.relay
)
# Wrap in none because NetConfig does not have a default constructor
# TODO: We could change bindIp in NetConfig to be something less restrictive than ValidIpAddress,
# which doesn't allow default construction
let netConfigRes = NetConfig.init(
bindIp = conf.listenAddress,
bindPort = Port(uint16(conf.tcpPort) + conf.portsShift),
extIp = extIp,
extPort = extPort,
extMultiAddrs = extMultiAddrs,
wsBindPort = Port(uint16(conf.websocketPort) + conf.portsShift),
wsEnabled = conf.websocketSupport,
wssEnabled = conf.websocketSecureSupport,
dns4DomainName = dns4DomainName,
discv5UdpPort = discv5UdpPort,
wakuFlags = some(wakuFlags),
)
netConfigRes
proc createRecord*(conf: WakuNodeConf, netConf: NetConfig, key: crypto.PrivateKey): Result[enr.Record, string] =
let relayShardsRes = topicsToRelayShards(conf.topics)
let relayShardOp =
if relayShardsRes.isErr():
return err("building ENR with relay sharding failed: " & $relayShardsRes.error)
else: relayShardsRes.get()
var builder = EnrBuilder.init(key)
builder.withIpAddressAndPorts(
ipAddr = netConf.extIp,
tcpPort = netConf.extPort,
udpPort = netConf.discv5UdpPort,
)
if netConf.wakuFlags.isSome():
builder.withWakuCapabilities(netConf.wakuFlags.get())
builder.withMultiaddrs(netConf.enrMultiaddrs)
if relayShardOp.isSome():
let res = builder.withWakuRelaySharding(relayShardOp.get())
if res.isErr():
return err("building ENR with relay sharding failed: " & $res.error)
let res = builder.build()
if res.isErr():
return err("building ENR failed: " & $res.error)
ok(res.get())

View File

@ -14,7 +14,7 @@ import
libp2p/crypto/crypto
import
../../waku/common/logging,
./config,
./external_config,
./app
logScope:

View File

@ -25,6 +25,7 @@ type
nodeRng: Option[ref crypto.HmacDrbgContext]
nodeKey: Option[crypto.PrivateKey]
netConfig: Option[NetConfig]
record: Option[enr.Record]
# Peer storage and peer manager
peerStorage: Option[PeerStorage]
@ -59,6 +60,9 @@ proc withRng*(builder: var WakuNodeBuilder, rng: ref crypto.HmacDrbgContext) =
proc withNodeKey*(builder: var WakuNodeBuilder, nodeKey: crypto.PrivateKey) =
builder.nodeKey = some(nodeKey)
proc withRecord*(builder: var WakuNodeBuilder, record: enr.Record) =
builder.record = some(record)
proc withNetworkConfiguration*(builder: var WakuNodeBuilder, config: NetConfig) =
builder.netConfig = some(config)
@ -151,6 +155,7 @@ proc build*(builder: WakuNodeBuilder): Result[WakuNode, string] =
rng = rng,
nodeKey = builder.nodeKey.get(),
netConfig = builder.netConfig.get(),
enr = builder.record,
peerStorage = builder.peerStorage.get(nil),
peerStoreCapacity = builder.peerStorageCapacity,
maxConnections = builder.switchMaxConnections.get(builders.MaxConnections),

View File

@ -8,6 +8,8 @@ import
stew/results,
stew/shims/net,
libp2p/multiaddress
import
../../waku/v2/waku_core/peers
import
../waku_enr

View File

@ -158,6 +158,7 @@ proc getAutonatService*(rng: ref HmacDrbgContext): AutonatService =
proc new*(T: type WakuNode,
nodeKey: crypto.PrivateKey,
netConfig: NetConfig,
enr: Option[enr.Record],
peerStorage: PeerStorage = nil,
maxConnections = builders.MaxConnections,
secureKey: string = "",
@ -191,15 +192,21 @@ proc new*(T: type WakuNode,
services = @[Service(getAutonatService(rng))],
)
let nodeEnrRes = getEnr(netConfig, wakuDiscv5, nodekey)
if nodeEnrRes.isErr():
raise newException(Defect, "failed to generate the node ENR record: " & $nodeEnrRes.error)
let enr =
if enr.isNone():
let nodeEnrRes = getEnr(netConfig, wakuDiscv5, nodekey)
if nodeEnrRes.isErr():
raise newException(Defect, "failed to generate the node ENR record: " & $nodeEnrRes.error)
nodeEnrRes.get()
else: enr.get()
return WakuNode(
peerManager: PeerManager.new(switch, peerStorage),
switch: switch,
rng: rng,
enr: nodeEnrRes.get(),
enr: enr,
announcedAddresses: netConfig.announcedAddresses,
wakuDiscv5: if wakuDiscV5.isSome(): wakuDiscV5.get() else: nil,
)

View File

@ -48,27 +48,6 @@ type WakuDiscoveryV5* = ref object
protocol*: protocol.Protocol
listening*: bool
func topicsToRelayShards*(topics: seq[string]): Result[Option[RelayShards], string] =
if topics.len < 1:
return ok(none(RelayShards))
let parsedTopicsRes = topics.mapIt(NsPubsubTopic.parse(it))
for res in parsedTopicsRes:
if res.isErr():
return err("failed to parse topic: " & $res.error)
if parsedTopicsRes.allIt(it.get().kind == NsPubsubTopicKind.NamedSharding):
return ok(none(RelayShards))
if parsedTopicsRes.anyIt(it.get().kind == NsPubsubTopicKind.NamedSharding):
return err("use named topics OR sharded ones not both.")
if parsedTopicsRes.anyIt(it.get().cluster != parsedTopicsRes[0].get().cluster):
return err("use sharded topics within the same cluster.")
return ok(some(RelayShards.init(parsedTopicsRes[0].get().cluster, parsedTopicsRes.mapIt(it.get().shard))))
proc new*(T: type WakuDiscoveryV5, rng: ref HmacDrbgContext, conf: WakuDiscoveryV5Config, record: Option[waku_enr.Record]): T =
let protocol = newProtocol(
rng = rng,

View File

@ -68,6 +68,26 @@ func init*(T: type RelayShards, cluster: uint16, indices: seq[uint16]): T =
RelayShards(cluster: cluster, indices: indicesSeq)
func topicsToRelayShards*(topics: seq[string]): Result[Option[RelayShards], string] =
if topics.len < 1:
return ok(none(RelayShards))
let parsedTopicsRes = topics.mapIt(NsPubsubTopic.parse(it))
for res in parsedTopicsRes:
if res.isErr():
return err("failed to parse topic: " & $res.error)
if parsedTopicsRes.allIt(it.get().kind == NsPubsubTopicKind.NamedSharding):
return ok(none(RelayShards))
if parsedTopicsRes.anyIt(it.get().kind == NsPubsubTopicKind.NamedSharding):
return err("use named topics OR sharded ones not both.")
if parsedTopicsRes.anyIt(it.get().cluster != parsedTopicsRes[0].get().cluster):
return err("use sharded topics within the same cluster.")
return ok(some(RelayShards.init(parsedTopicsRes[0].get().cluster, parsedTopicsRes.mapIt(it.get().shard))))
func contains*(rs: RelayShards, cluster, index: uint16): bool =
rs.cluster == cluster and rs.indices.contains(index)