mirror of
https://github.com/waku-org/nwaku.git
synced 2025-01-27 07:06:42 +00:00
feat: implementing port 0 support (#2125)
This commit is contained in:
parent
3be6163639
commit
f7b9afc26f
@ -8,6 +8,8 @@ import
|
||||
stew/results,
|
||||
chronicles,
|
||||
chronos,
|
||||
libp2p/wire,
|
||||
libp2p/multicodec,
|
||||
libp2p/crypto/crypto,
|
||||
libp2p/nameresolving/dnsresolver,
|
||||
libp2p/protocols/pubsub/gossipsub,
|
||||
@ -117,39 +119,8 @@ proc init*(T: type App, rng: ref HmacDrbgContext, conf: WakuNodeConf): T =
|
||||
quit(QuitFailure)
|
||||
else: netConfigRes.get()
|
||||
|
||||
var enrBuilder = EnrBuilder.init(key)
|
||||
let recordRes = enrConfiguration(conf, netConfig, key)
|
||||
|
||||
enrBuilder.withIpAddressAndPorts(
|
||||
netConfig.enrIp,
|
||||
netConfig.enrPort,
|
||||
netConfig.discv5UdpPort
|
||||
)
|
||||
|
||||
if netConfig.wakuFlags.isSome():
|
||||
enrBuilder.withWakuCapabilities(netConfig.wakuFlags.get())
|
||||
|
||||
enrBuilder.withMultiaddrs(netConfig.enrMultiaddrs)
|
||||
|
||||
let topics =
|
||||
if conf.pubsubTopics.len > 0 or conf.contentTopics.len > 0:
|
||||
let shardsRes = conf.contentTopics.mapIt(getShard(it))
|
||||
for res in shardsRes:
|
||||
if res.isErr():
|
||||
error "failed to shard content topic", error=res.error
|
||||
quit(QuitFailure)
|
||||
|
||||
let shards = shardsRes.mapIt(it.get())
|
||||
|
||||
conf.pubsubTopics & shards
|
||||
else:
|
||||
conf.topics
|
||||
|
||||
let addShardedTopics = enrBuilder.withShardedTopics(topics)
|
||||
if addShardedTopics.isErr():
|
||||
error "failed to add sharded topics to ENR", error=addShardedTopics.error
|
||||
quit(QuitFailure)
|
||||
|
||||
let recordRes = enrBuilder.build()
|
||||
let record =
|
||||
if recordRes.isErr():
|
||||
error "failed to create record", error=recordRes.error
|
||||
@ -329,6 +300,72 @@ proc setupWakuApp*(app: var App): AppResult[void] =
|
||||
|
||||
ok()
|
||||
|
||||
proc getPorts(listenAddrs: seq[MultiAddress]):
|
||||
AppResult[tuple[tcpPort, websocketPort: Option[Port]]] =
|
||||
|
||||
var tcpPort, websocketPort = none(Port)
|
||||
|
||||
for a in listenAddrs:
|
||||
if a.isWsAddress():
|
||||
if websocketPort.isNone():
|
||||
let wsAddress = initTAddress(a).valueOr:
|
||||
return err("getPorts wsAddr error:" & $error)
|
||||
websocketPort = some(wsAddress.port)
|
||||
elif tcpPort.isNone():
|
||||
let tcpAddress = initTAddress(a).valueOr:
|
||||
return err("getPorts tcpAddr error:" & $error)
|
||||
tcpPort = some(tcpAddress.port)
|
||||
|
||||
return ok((tcpPort: tcpPort, websocketPort: websocketPort))
|
||||
|
||||
proc updateNetConfig(app: var App): AppResult[void] =
|
||||
|
||||
var conf = app.conf
|
||||
let (tcpPort, websocketPort) = getPorts(app.node.switch.peerInfo.listenAddrs).valueOr:
|
||||
return err("Could not retrieve ports " & error)
|
||||
|
||||
if tcpPort.isSome():
|
||||
conf.tcpPort = tcpPort.get()
|
||||
|
||||
if websocketPort.isSome():
|
||||
conf.websocketPort = websocketPort.get()
|
||||
|
||||
# Rebuild NetConfig with bound port values
|
||||
let netConf = networkConfiguration(conf, clientId).valueOr:
|
||||
return err("Could not update NetConfig: " & error)
|
||||
|
||||
app.netConf = netConf
|
||||
|
||||
return ok()
|
||||
|
||||
proc updateEnr(app: var App): AppResult[void] =
|
||||
|
||||
let record = enrConfiguration(app.conf, app.netConf, app.key).valueOr:
|
||||
return err(error)
|
||||
|
||||
app.record = record
|
||||
app.node.enr = record
|
||||
|
||||
if app.conf.discv5Discovery:
|
||||
app.wakuDiscV5 = some(app.setupDiscoveryV5())
|
||||
|
||||
return ok()
|
||||
|
||||
proc updateApp(app: var App): AppResult[void] =
|
||||
|
||||
if app.conf.tcpPort == Port(0) or app.conf.websocketPort == Port(0):
|
||||
|
||||
updateNetConfig(app).isOkOr:
|
||||
return err("error calling updateNetConfig: " & $error)
|
||||
|
||||
updateEnr(app).isOkOr:
|
||||
return err("error calling updateEnr: " & $error)
|
||||
|
||||
app.node.announcedAddresses = app.netConf.announcedAddresses
|
||||
|
||||
printNodeNetworkInfo(app.node)
|
||||
|
||||
return ok()
|
||||
|
||||
## Mount protocols
|
||||
|
||||
@ -548,7 +585,18 @@ proc startNode(node: WakuNode, conf: WakuNodeConf,
|
||||
|
||||
return ok()
|
||||
|
||||
proc startApp*(app: App): Future[AppResult[void]] {.async.} =
|
||||
proc startApp*(app: var App): AppResult[void] =
|
||||
|
||||
try:
|
||||
(waitFor startNode(app.node,app.conf,app.dynamicBootstrapNodes)).isOkOr:
|
||||
return err(error)
|
||||
except CatchableError:
|
||||
return err("exception starting node: " & getCurrentExceptionMsg())
|
||||
|
||||
# Update app data that is set dynamically on node start
|
||||
app.updateApp().isOkOr:
|
||||
return err("Error in updateApp: " & $error)
|
||||
|
||||
if app.wakuDiscv5.isSome():
|
||||
let wakuDiscv5 = app.wakuDiscv5.get()
|
||||
|
||||
@ -559,11 +607,8 @@ proc startApp*(app: App): Future[AppResult[void]] {.async.} =
|
||||
asyncSpawn wakuDiscv5.searchLoop(app.node.peerManager)
|
||||
asyncSpawn wakuDiscv5.subscriptionsListener(app.node.topicSubscriptionQueue)
|
||||
|
||||
return await startNode(
|
||||
app.node,
|
||||
app.conf,
|
||||
app.dynamicBootstrapNodes
|
||||
)
|
||||
return ok()
|
||||
|
||||
|
||||
|
||||
## Monitoring and external interfaces
|
||||
|
@ -4,15 +4,61 @@ import
|
||||
libp2p/crypto/crypto,
|
||||
libp2p/multiaddress,
|
||||
libp2p/nameresolving/dnsresolver,
|
||||
std/options,
|
||||
std/[options, sequtils],
|
||||
stew/results,
|
||||
stew/shims/net
|
||||
import
|
||||
../../waku/common/utils/nat,
|
||||
../../waku/node/config,
|
||||
../../waku/waku_enr/capabilities,
|
||||
../../waku/waku_enr,
|
||||
../../waku/waku_core,
|
||||
./external_config
|
||||
|
||||
proc enrConfiguration*(conf: WakuNodeConf, netConfig: NetConfig, key: crypto.PrivateKey):
|
||||
Result[enr.Record, string] =
|
||||
|
||||
var enrBuilder = EnrBuilder.init(key)
|
||||
|
||||
enrBuilder.withIpAddressAndPorts(
|
||||
netConfig.enrIp,
|
||||
netConfig.enrPort,
|
||||
netConfig.discv5UdpPort
|
||||
)
|
||||
|
||||
if netConfig.wakuFlags.isSome():
|
||||
enrBuilder.withWakuCapabilities(netConfig.wakuFlags.get())
|
||||
|
||||
enrBuilder.withMultiaddrs(netConfig.enrMultiaddrs)
|
||||
|
||||
let topics =
|
||||
if conf.pubsubTopics.len > 0 or conf.contentTopics.len > 0:
|
||||
let shardsRes = conf.contentTopics.mapIt(getShard(it))
|
||||
for res in shardsRes:
|
||||
if res.isErr():
|
||||
error "failed to shard content topic", error=res.error
|
||||
return err($res.error)
|
||||
|
||||
let shards = shardsRes.mapIt(it.get())
|
||||
|
||||
conf.pubsubTopics & shards
|
||||
else:
|
||||
conf.topics
|
||||
|
||||
let addShardedTopics = enrBuilder.withShardedTopics(topics)
|
||||
if addShardedTopics.isErr():
|
||||
error "failed to add sharded topics to ENR", error=addShardedTopics.error
|
||||
return err($addShardedTopics.error)
|
||||
|
||||
let recordRes = enrBuilder.build()
|
||||
let record =
|
||||
if recordRes.isErr():
|
||||
error "failed to create record", error=recordRes.error
|
||||
return err($recordRes.error)
|
||||
else: recordRes.get()
|
||||
|
||||
return ok(record)
|
||||
|
||||
proc validateExtMultiAddrs*(vals: seq[string]):
|
||||
Result[seq[MultiAddress], string] =
|
||||
var multiaddrs: seq[MultiAddress]
|
||||
|
@ -87,7 +87,7 @@ when isMainModule:
|
||||
|
||||
debug "5/7 Starting node and mounted protocols"
|
||||
|
||||
let res6 = waitFor wakunode2.startApp()
|
||||
let res6 = wakunode2.startApp()
|
||||
if res6.isErr():
|
||||
error "5/7 Starting node and protocols failed", error=res6.error
|
||||
quit(QuitFailure)
|
||||
|
@ -12,7 +12,9 @@ import
|
||||
import
|
||||
../testlib/common,
|
||||
../testlib/wakucore,
|
||||
../testlib/wakunode,
|
||||
../testlib/wakunode
|
||||
|
||||
include
|
||||
../../apps/wakunode2/app
|
||||
|
||||
suite "Wakunode2 - App":
|
||||
@ -27,7 +29,7 @@ suite "Wakunode2 - App":
|
||||
|
||||
## Then
|
||||
check:
|
||||
version == app.git_version
|
||||
version == git_version
|
||||
|
||||
suite "Wakunode2 - App initialization":
|
||||
test "peer persistence setup should be successfully mounted":
|
||||
@ -53,7 +55,7 @@ suite "Wakunode2 - App initialization":
|
||||
require wakunode2.setupDyamicBootstrapNodes().isOk()
|
||||
require wakunode2.setupWakuApp().isOk()
|
||||
require isOk(waitFor wakunode2.setupAndMountProtocols())
|
||||
require isOk(waitFor wakunode2.startApp())
|
||||
require isOk(wakunode2.startApp())
|
||||
require wakunode2.setupMonitoringAndExternalInterfaces().isOk()
|
||||
|
||||
## Then
|
||||
@ -67,3 +69,43 @@ suite "Wakunode2 - App initialization":
|
||||
|
||||
## Cleanup
|
||||
waitFor wakunode2.stop()
|
||||
|
||||
test "app properly handles dynamic port configuration":
|
||||
## Given
|
||||
var conf = defaultTestWakuNodeConf()
|
||||
conf.tcpPort = Port(0)
|
||||
|
||||
## When
|
||||
var wakunode2 = App.init(rng(), conf)
|
||||
require wakunode2.setupPeerPersistence().isOk()
|
||||
require wakunode2.setupDyamicBootstrapNodes().isOk()
|
||||
require wakunode2.setupWakuApp().isOk()
|
||||
require isOk(waitFor wakunode2.setupAndMountProtocols())
|
||||
require isOk(wakunode2.startApp())
|
||||
require wakunode2.setupMonitoringAndExternalInterfaces().isOk()
|
||||
|
||||
## Then
|
||||
let
|
||||
node = wakunode2.node
|
||||
typedNodeEnr = node.enr.toTypedRecord()
|
||||
typedAppEnr = wakunode2.record.toTypedRecord()
|
||||
|
||||
assert typedNodeEnr.isOk(), $typedNodeEnr.error
|
||||
assert typedAppEnr.isOk(), $typedAppEnr.error
|
||||
|
||||
check:
|
||||
# App started properly
|
||||
not node.isNil()
|
||||
node.wakuArchive.isNil()
|
||||
node.wakuStore.isNil()
|
||||
not node.wakuStoreClient.isNil()
|
||||
not node.rendezvous.isNil()
|
||||
|
||||
# DS structures are updated with dynamic ports
|
||||
wakunode2.netConf.bindPort != Port(0)
|
||||
wakunode2.netConf.enrPort.get() != Port(0)
|
||||
typedNodeEnr.get().tcp.get() != 0
|
||||
typedAppEnr.get().tcp.get() != 0
|
||||
|
||||
## Cleanup
|
||||
waitFor wakunode2.stop()
|
||||
|
@ -59,7 +59,7 @@ proc formatListenAddress(inputMultiAdd: MultiAddress): MultiAddress =
|
||||
# If MultiAddress contains "0.0.0.0", replace it for "127.0.0.1"
|
||||
return MultiAddress.init(inputStr.replace("0.0.0.0", "127.0.0.1")).get()
|
||||
|
||||
proc isWsAddress(ma: MultiAddress): bool =
|
||||
proc isWsAddress*(ma: MultiAddress): bool =
|
||||
let
|
||||
isWs = ma.contains(multiCodec("ws")).get()
|
||||
isWss = ma.contains(multiCodec("wss")).get()
|
||||
|
@ -1073,6 +1073,26 @@ proc mountRendezvous*(node: WakuNode) {.async, raises: [Defect, LPError].} =
|
||||
|
||||
node.switch.mount(node.rendezvous)
|
||||
|
||||
proc isBindIpWithZeroPort(inputMultiAdd: MultiAddress): bool =
|
||||
let inputStr = $inputMultiAdd
|
||||
if inputStr.contains("0.0.0.0/tcp/0") or inputStr.contains("127.0.0.1/tcp/0"):
|
||||
return true
|
||||
|
||||
return false
|
||||
|
||||
proc printNodeNetworkInfo*(node: WakuNode): void =
|
||||
let peerInfo = node.switch.peerInfo
|
||||
var listenStr = ""
|
||||
|
||||
info "PeerInfo", peerId = peerInfo.peerId, addrs = peerInfo.addrs
|
||||
|
||||
for address in node.announcedAddresses:
|
||||
var fulladdr = "[" & $address & "/p2p/" & $peerInfo.peerId & "]"
|
||||
listenStr &= fulladdr
|
||||
|
||||
## XXX: this should be /ip4..., / stripped?
|
||||
info "Listening on", full = listenStr
|
||||
info "DNS: discoverable ENR ", enr = node.enr.toUri()
|
||||
|
||||
proc start*(node: WakuNode) {.async.} =
|
||||
## Starts a created Waku Node and
|
||||
@ -1081,16 +1101,15 @@ proc start*(node: WakuNode) {.async.} =
|
||||
waku_version.set(1, labelValues=[git_version])
|
||||
info "Starting Waku node", version=git_version
|
||||
|
||||
let peerInfo = node.switch.peerInfo
|
||||
info "PeerInfo", peerId = peerInfo.peerId, addrs = peerInfo.addrs
|
||||
var listenStr = ""
|
||||
var zeroPortPresent = false
|
||||
for address in node.announcedAddresses:
|
||||
var fulladdr = "[" & $address & "/p2p/" & $peerInfo.peerId & "]"
|
||||
listenStr &= fulladdr
|
||||
if isBindIpWithZeroPort(address):
|
||||
zeroPortPresent = true
|
||||
|
||||
## XXX: this should be /ip4..., / stripped?
|
||||
info "Listening on", full = listenStr
|
||||
info "DNS: discoverable ENR ", enr = node.enr.toUri()
|
||||
if not zeroPortPresent:
|
||||
printNodeNetworkInfo(node)
|
||||
else:
|
||||
info "Listening port is dynamically allocated, address and ENR generation postponed"
|
||||
|
||||
# Perform relay-specific startup tasks TODO: this should be rethought
|
||||
if not node.wakuRelay.isNil():
|
||||
|
Loading…
x
Reference in New Issue
Block a user