mirror of https://github.com/waku-org/nwaku.git
feat(wakunode): advertise custom multiaddresses (#1509)
* feat(wakunode2): ability to advertise custom multiaddresses * test(wakunode): test the feature * fix(wakunode): remove rln diff * revert(rln-relay): change that creeped into the diff * fix(wakunode): move extMultiaddrs closer to nat * fix(waku_node): idiomatic default arg * fix(config): shortened validation * fix(wakunode): discoverable via discv5 and dnsdisc
This commit is contained in:
parent
ea4703e9a2
commit
d09ec815ce
|
@ -10,6 +10,7 @@ import
|
||||||
confutils/toml/std/net as confTomlNet,
|
confutils/toml/std/net as confTomlNet,
|
||||||
libp2p/crypto/crypto,
|
libp2p/crypto/crypto,
|
||||||
libp2p/crypto/secp,
|
libp2p/crypto/secp,
|
||||||
|
libp2p/multiaddress,
|
||||||
nimcrypto/utils
|
nimcrypto/utils
|
||||||
import
|
import
|
||||||
../../waku/common/confutils/envvar/defs as confEnvvarDefs,
|
../../waku/common/confutils/envvar/defs as confEnvvarDefs,
|
||||||
|
@ -75,6 +76,10 @@ type
|
||||||
"Must be one of: any, none, upnp, pmp, extip:<IP>."
|
"Must be one of: any, none, upnp, pmp, extip:<IP>."
|
||||||
defaultValue: "any" }: string
|
defaultValue: "any" }: string
|
||||||
|
|
||||||
|
extMultiAddrs* {.
|
||||||
|
desc: "External multiaddresses to advertise to the network. Argument may be repeated."
|
||||||
|
name: "ext-multiaddr" }: seq[string]
|
||||||
|
|
||||||
maxConnections* {.
|
maxConnections* {.
|
||||||
desc: "Maximum allowed number of libp2p connections."
|
desc: "Maximum allowed number of libp2p connections."
|
||||||
defaultValue: 50
|
defaultValue: 50
|
||||||
|
@ -513,6 +518,12 @@ proc validateStoreMessageRetentionPolicy*(val: string): ConfResult[string] =
|
||||||
else:
|
else:
|
||||||
err("invalid 'store message retention policy' option format: " & val)
|
err("invalid 'store message retention policy' option format: " & val)
|
||||||
|
|
||||||
|
proc validateExtMultiAddrs*(vals: seq[string]): ConfResult[seq[MultiAddress]] =
|
||||||
|
var multiaddrs: seq[MultiAddress]
|
||||||
|
for val in vals:
|
||||||
|
let multiaddr = ? MultiAddress.init(val)
|
||||||
|
multiaddrs.add(multiaddr)
|
||||||
|
ok(multiaddrs)
|
||||||
|
|
||||||
## Load
|
## Load
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,14 @@ proc initNode(conf: WakuNodeConf,
|
||||||
some(Port(uint16(conf.tcpPort) + conf.portsShift))
|
some(Port(uint16(conf.tcpPort) + conf.portsShift))
|
||||||
else:
|
else:
|
||||||
extTcpPort
|
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 = initWakuFlags(conf.lightpush,
|
wakuFlags = initWakuFlags(conf.lightpush,
|
||||||
conf.filter,
|
conf.filter,
|
||||||
|
@ -266,6 +274,7 @@ proc initNode(conf: WakuNodeConf,
|
||||||
node = WakuNode.new(conf.nodekey,
|
node = WakuNode.new(conf.nodekey,
|
||||||
conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift),
|
conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift),
|
||||||
extIp, extPort,
|
extIp, extPort,
|
||||||
|
extMultiAddrs,
|
||||||
pStorage,
|
pStorage,
|
||||||
conf.maxConnections.int,
|
conf.maxConnections.int,
|
||||||
Port(uint16(conf.websocketPort) + conf.portsShift),
|
Port(uint16(conf.websocketPort) + conf.portsShift),
|
||||||
|
@ -279,8 +288,7 @@ proc initNode(conf: WakuNodeConf,
|
||||||
dns4DomainName,
|
dns4DomainName,
|
||||||
discv5UdpPort,
|
discv5UdpPort,
|
||||||
some(conf.agentString),
|
some(conf.agentString),
|
||||||
some(conf.peerStoreCapacity),
|
some(conf.peerStoreCapacity))
|
||||||
)
|
|
||||||
except:
|
except:
|
||||||
return err("failed to create waku node instance: " & getCurrentExceptionMsg())
|
return err("failed to create waku node instance: " & getCurrentExceptionMsg())
|
||||||
|
|
||||||
|
|
|
@ -4,8 +4,8 @@ import
|
||||||
stew/byteutils,
|
stew/byteutils,
|
||||||
stew/shims/net as stewNet,
|
stew/shims/net as stewNet,
|
||||||
testutils/unittests,
|
testutils/unittests,
|
||||||
chronicles,
|
chronicles,
|
||||||
chronos,
|
chronos,
|
||||||
libp2p/crypto/crypto,
|
libp2p/crypto/crypto,
|
||||||
libp2p/crypto/secp,
|
libp2p/crypto/secp,
|
||||||
libp2p/multiaddress,
|
libp2p/multiaddress,
|
||||||
|
@ -24,7 +24,7 @@ import
|
||||||
|
|
||||||
procSuite "WakuNode":
|
procSuite "WakuNode":
|
||||||
let rng = crypto.newRng()
|
let rng = crypto.newRng()
|
||||||
|
|
||||||
asyncTest "Protocol matcher works as expected":
|
asyncTest "Protocol matcher works as expected":
|
||||||
let
|
let
|
||||||
nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
@ -153,9 +153,9 @@ procSuite "WakuNode":
|
||||||
expect IOError:
|
expect IOError:
|
||||||
# gibberish
|
# gibberish
|
||||||
discard WakuNode.new(nodeKey1, ValidIpAddress.init("0.0.0.0"),
|
discard WakuNode.new(nodeKey1, ValidIpAddress.init("0.0.0.0"),
|
||||||
bindPort = Port(61004),
|
bindPort = Port(61004),
|
||||||
wsBindPort = Port(8000),
|
wsBindPort = Port(8000),
|
||||||
wssEnabled = true,
|
wssEnabled = true,
|
||||||
secureKey = "../../waku/v2/node/key_dummy.txt")
|
secureKey = "../../waku/v2/node/key_dummy.txt")
|
||||||
|
|
||||||
asyncTest "Peer info updates with correct announced addresses":
|
asyncTest "Peer info updates with correct announced addresses":
|
||||||
|
@ -216,7 +216,7 @@ procSuite "WakuNode":
|
||||||
node.announcedAddresses.len == 1
|
node.announcedAddresses.len == 1
|
||||||
node.announcedAddresses.contains(expectedDns4Addr)
|
node.announcedAddresses.contains(expectedDns4Addr)
|
||||||
|
|
||||||
|
|
||||||
asyncTest "Agent string is set and advertised correctly":
|
asyncTest "Agent string is set and advertised correctly":
|
||||||
let
|
let
|
||||||
# custom agent string
|
# custom agent string
|
||||||
|
@ -250,4 +250,37 @@ procSuite "WakuNode":
|
||||||
node1Agent == expectedAgentString1
|
node1Agent == expectedAgentString1
|
||||||
node2Agent == expectedAgentString2
|
node2Agent == expectedAgentString2
|
||||||
|
|
||||||
await allFutures(node1.stop(), node2.stop())
|
await allFutures(node1.stop(), node2.stop())
|
||||||
|
|
||||||
|
asyncTest "Custom multiaddresses are set and advertised correctly":
|
||||||
|
let
|
||||||
|
# custom multiaddress
|
||||||
|
expectedMultiaddress1 = MultiAddress.init("/ip4/200.200.200.200/tcp/1234").get()
|
||||||
|
|
||||||
|
# Note: this could have been done with a single node, but it is useful to
|
||||||
|
# have two nodes to check that the multiaddress is advertised correctly
|
||||||
|
let
|
||||||
|
# node with custom multiaddress
|
||||||
|
nodeKey1 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node1 = WakuNode.new(nodeKey1, ValidIpAddress.init("0.0.0.0"), Port(61018),
|
||||||
|
extMultiAddrs = @[expectedMultiaddress1])
|
||||||
|
|
||||||
|
# node with default multiaddress
|
||||||
|
nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
|
||||||
|
node2 = WakuNode.new(nodeKey2, ValidIpAddress.init("0.0.0.0"), Port(61020))
|
||||||
|
|
||||||
|
await node1.start()
|
||||||
|
await node1.mountRelay()
|
||||||
|
|
||||||
|
await node2.start()
|
||||||
|
await node2.mountRelay()
|
||||||
|
|
||||||
|
await node1.connectToNodes(@[node2.switch.peerInfo.toRemotePeerInfo()])
|
||||||
|
await node2.connectToNodes(@[node1.switch.peerInfo.toRemotePeerInfo()])
|
||||||
|
|
||||||
|
let node1MultiAddrs = node2.switch.peerStore[AddressBook][node1.switch.peerInfo.toRemotePeerInfo().peerId]
|
||||||
|
|
||||||
|
check:
|
||||||
|
node1MultiAddrs.contains(expectedMultiaddress1)
|
||||||
|
|
||||||
|
await allFutures(node1.stop(), node2.stop())
|
||||||
|
|
|
@ -136,6 +136,7 @@ proc new*(T: type WakuNode,
|
||||||
bindPort: Port,
|
bindPort: Port,
|
||||||
extIp = none(ValidIpAddress),
|
extIp = none(ValidIpAddress),
|
||||||
extPort = none(Port),
|
extPort = none(Port),
|
||||||
|
extMultiAddrs = newSeq[MultiAddress](),
|
||||||
peerStorage: PeerStorage = nil,
|
peerStorage: PeerStorage = nil,
|
||||||
maxConnections = builders.MaxConnections,
|
maxConnections = builders.MaxConnections,
|
||||||
wsBindPort: Port = (Port)8000,
|
wsBindPort: Port = (Port)8000,
|
||||||
|
@ -178,12 +179,17 @@ proc new*(T: type WakuNode,
|
||||||
if (wsHostAddress.isSome()):
|
if (wsHostAddress.isSome()):
|
||||||
wsExtAddress = some(ip4TcpEndPoint(extIp.get(), wsBindPort) & wsFlag(wssEnabled))
|
wsExtAddress = some(ip4TcpEndPoint(extIp.get(), wsBindPort) & wsFlag(wssEnabled))
|
||||||
|
|
||||||
var announcedAddresses: seq[MultiAddress]
|
var announcedAddresses = newSeq[MultiAddress]()
|
||||||
|
|
||||||
if hostExtAddress.isSome():
|
if hostExtAddress.isSome():
|
||||||
announcedAddresses.add(hostExtAddress.get())
|
announcedAddresses.add(hostExtAddress.get())
|
||||||
else:
|
else:
|
||||||
announcedAddresses.add(hostAddress) # We always have at least a bind address for the host
|
announcedAddresses.add(hostAddress) # We always have at least a bind address for the host
|
||||||
|
|
||||||
|
# External multiaddrs that the operator may have configured
|
||||||
|
if extMultiAddrs.len > 0:
|
||||||
|
announcedAddresses.add(extMultiAddrs)
|
||||||
|
|
||||||
if wsExtAddress.isSome():
|
if wsExtAddress.isSome():
|
||||||
announcedAddresses.add(wsExtAddress.get())
|
announcedAddresses.add(wsExtAddress.get())
|
||||||
elif wsHostAddress.isSome():
|
elif wsHostAddress.isSome():
|
||||||
|
@ -196,9 +202,12 @@ proc new*(T: type WakuNode,
|
||||||
else: some(bindIp)
|
else: some(bindIp)
|
||||||
enrTcpPort = if extPort.isSome(): extPort
|
enrTcpPort = if extPort.isSome(): extPort
|
||||||
else: some(bindPort)
|
else: some(bindPort)
|
||||||
enrMultiaddrs = if wsExtAddress.isSome(): @[wsExtAddress.get()] # Only add ws/wss to `multiaddrs` field
|
# enrMultiaddrs are just addresses which cannot be represented in ENR, as described in
|
||||||
elif wsHostAddress.isSome(): @[wsHostAddress.get()]
|
# https://rfc.vac.dev/spec/31/#many-connection-types
|
||||||
else: @[]
|
enrMultiaddrs = announcedAddresses.filterIt(it.hasProtocol("dns4") or
|
||||||
|
it.hasProtocol("dns6") or
|
||||||
|
it.hasProtocol("ws") or
|
||||||
|
it.hasProtocol("wss"))
|
||||||
enr = initEnr(nodeKey,
|
enr = initEnr(nodeKey,
|
||||||
enrIp,
|
enrIp,
|
||||||
enrTcpPort,
|
enrTcpPort,
|
||||||
|
@ -816,6 +825,7 @@ when defined(rln):
|
||||||
return
|
return
|
||||||
node.wakuRlnRelay = rlnRelayRes.get()
|
node.wakuRlnRelay = rlnRelayRes.get()
|
||||||
|
|
||||||
|
|
||||||
## Waku peer-exchange
|
## Waku peer-exchange
|
||||||
|
|
||||||
proc mountPeerExchange*(node: WakuNode) {.async, raises: [Defect, LPError].} =
|
proc mountPeerExchange*(node: WakuNode) {.async, raises: [Defect, LPError].} =
|
||||||
|
|
|
@ -13,6 +13,7 @@ import
|
||||||
libp2p/crypto/[crypto, secp],
|
libp2p/crypto/[crypto, secp],
|
||||||
libp2p/[errors,
|
libp2p/[errors,
|
||||||
multiaddress,
|
multiaddress,
|
||||||
|
multicodec,
|
||||||
peerid,
|
peerid,
|
||||||
peerinfo,
|
peerinfo,
|
||||||
routing_record]
|
routing_record]
|
||||||
|
@ -169,3 +170,15 @@ proc toRemotePeerInfo*(peerInfo: PeerInfo): RemotePeerInfo =
|
||||||
peerInfo.listenAddrs,
|
peerInfo.listenAddrs,
|
||||||
none(enr.Record), # we could generate an ENR from PeerInfo
|
none(enr.Record), # we could generate an ENR from PeerInfo
|
||||||
peerInfo.protocols)
|
peerInfo.protocols)
|
||||||
|
|
||||||
|
## Checks if a multiaddress contains a given protocol
|
||||||
|
## Useful for filtering multiaddresses based on their protocols
|
||||||
|
proc hasProtocol*(ma: MultiAddress, proto: string): bool =
|
||||||
|
## Returns ``true`` if ``ma`` contains protocol ``proto``.
|
||||||
|
let protos = ma.protocols()
|
||||||
|
if protos.isErr():
|
||||||
|
return false
|
||||||
|
for p in protos.get():
|
||||||
|
if p == MultiCodec.codec(proto):
|
||||||
|
return true
|
||||||
|
return false
|
||||||
|
|
Loading…
Reference in New Issue