Skip to content

Commit

Permalink
feat(discv5): allow custom multiaddr advertisement in discv5
Browse files Browse the repository at this point in the history
feat(discv5): allow custom multiaddr advertisement in discv5

feat(discv5): move discv5 setup from wakunode2 to waku_node

fix(waku_node): def param

test(discv5): test for ext multiaddr

fix(discv5): address comments

fix(discv5): address comments

fix(wakunode2): discoveryconfig in var before init

fix(discv5): pass multiaddr to discv5 directly

fix(discv5): make multiaddrs optional

fix(test): discv5 init

fix(discv5): split discv5 mounting from waku_node

chore(discv5): s/WakuAddressMetadata/WakuNodeAddrMeta/g
  • Loading branch information
rymnc committed Jan 31, 2023
1 parent 67939bb commit f69810d
Show file tree
Hide file tree
Showing 9 changed files with 326 additions and 135 deletions.
95 changes: 44 additions & 51 deletions apps/wakunode2/wakunode2.nim
Original file line number Diff line number Diff line change
Expand Up @@ -271,60 +271,53 @@ proc initNode(conf: WakuNodeConf,
let pStorage = if peerStore.isNone(): nil
else: peerStore.get()
try:
node = WakuNode.new(conf.nodekey,
conf.listenAddress, Port(uint16(conf.tcpPort) + conf.portsShift),
extIp, extPort,
extMultiAddrs,
pStorage,
conf.maxConnections.int,
Port(uint16(conf.websocketPort) + conf.portsShift),
conf.websocketSupport,
conf.websocketSecureSupport,
conf.websocketSecureKeyPath,
conf.websocketSecureCertPath,
some(wakuFlags),
dnsResolver,
conf.relayPeerExchange, # We send our own signed peer record when peer exchange enabled
dns4DomainName,
discv5UdpPort,
some(conf.agentString),
some(conf.peerStoreCapacity))
var wakuDiscv5 = none(WakuDiscoveryV5)
let rng = crypto.newRng()

let addressMetadata = getWakuNodeAddrMeta(
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 conf.discv5Discovery:
let dynamicBootstrapEnrs = filterEnrPeersWithUdpPort(@dynamicBootstrapNodes)
var discv5BootstrapEnrs: seq[enr.Record]
# parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq
for enrUri in conf.discv5BootstrapNodes:
addBootstrapNode(enrUri, discv5BootstrapEnrs)
discv5BootstrapEnrs.add(dynamicBootstrapEnrs)
let discv5Config = DiscoveryConfig.init(conf.discv5TableIpLimit,
conf.discv5BucketIpLimit,
conf.discv5BitsPerHop)
wakuDiscv5 = some(getWakuDiscoveryV5(addressMetadata = addressMetadata,
nodekey = conf.nodekey,
discv5Config = discv5Config,
discv5BootstrapEnrs = discv5BootstrapEnrs,
discv5EnrAutoUpdate = conf.discv5EnrAutoUpdate,
rng = rng))
node = WakuNode.new(nodekey = conf.nodekey,
addressMetadata = addressMetadata,
rng = rng,
peerStorage = pStorage,
maxConnections = conf.maxConnections.int,
secureKey = conf.websocketSecureKeyPath,
secureCert = conf.websocketSecureCertPath,
nameResolver = dnsResolver,
sendSignedPeerRecord = conf.relayPeerExchange, # We send our own signed peer record when peer exchange enabled
wakuDiscv5 = wakuDiscv5,
agentString = some(conf.agentString),
peerStoreCapacity = some(conf.peerStoreCapacity))
except:
return err("failed to create waku node instance: " & getCurrentExceptionMsg())

if conf.discv5Discovery:
let
discoveryConfig = DiscoveryConfig.init(
conf.discv5TableIpLimit, conf.discv5BucketIpLimit, conf.discv5BitsPerHop)

# select dynamic bootstrap nodes that have an ENR containing a udp port.
# Discv5 only supports UDP https://github.com/ethereum/devp2p/blob/master/discv5/discv5-theory.md)
var discv5BootstrapEnrs: seq[enr.Record]
for n in dynamicBootstrapNodes:
if n.enr.isSome():
let
enr = n.enr.get()
tenrRes = enr.toTypedRecord()
if tenrRes.isOk() and (tenrRes.get().udp.isSome() or tenrRes.get().udp6.isSome()):
discv5BootstrapEnrs.add(enr)

# parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq
for enrUri in conf.discv5BootstrapNodes:
addBootstrapNode(enrUri, discv5BootstrapEnrs)

node.wakuDiscv5 = WakuDiscoveryV5.new(
extIP, extPort, discv5UdpPort,
conf.listenAddress,
discv5UdpPort.get(),
discv5BootstrapEnrs,
conf.discv5EnrAutoUpdate,
keys.PrivateKey(conf.nodekey.skkey),
wakuFlags,
[], # Empty enr fields, for now
node.rng,
discoveryConfig
)

ok(node)

proc setupProtocols(node: WakuNode, conf: WakuNodeConf,
Expand Down
1 change: 0 additions & 1 deletion examples/v2/publisher.nim
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ proc setupAndPublish() {.async.} =
bootstrapNodes = bootstrapNodes,
privateKey = keys.PrivateKey(nodeKey.skkey),
flags = flags,
enrFields = [],
rng = node.rng)

await node.start()
Expand Down
1 change: 0 additions & 1 deletion examples/v2/subscriber.nim
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,6 @@ proc setupAndSubscribe() {.async.} =
bootstrapNodes = bootstrapNodes,
privateKey = keys.PrivateKey(nodeKey.skkey),
flags = flags,
enrFields = [],
rng = node.rng)

await node.start()
Expand Down
78 changes: 70 additions & 8 deletions tests/v2/test_waku_discv5.nim
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import
chronos,
chronicles,
testutils/unittests,
stew/byteutils,
stew/shims/net,
Expand All @@ -25,7 +26,7 @@ procSuite "Waku Discovery v5":
nodeTcpPort1 = Port(61500)
nodeUdpPort1 = Port(9000)
node1 = WakuNode.new(nodeKey1, bindIp, nodeTcpPort1)

nodeKey2 = crypto.PrivateKey.random(Secp256k1, rng[])[]
nodeTcpPort2 = Port(61502)
nodeUdpPort2 = Port(9002)
Expand All @@ -46,7 +47,7 @@ procSuite "Waku Discovery v5":
contentTopic = ContentTopic("/waku/2/default-content/proto")
payload = "Can you see me?".toBytes()
message = WakuMessage(payload: payload, contentTopic: contentTopic)

# Mount discv5
node1.wakuDiscv5 = WakuDiscoveryV5.new(
some(extIp), some(nodeTcpPort1), some(nodeUdpPort1),
Expand All @@ -56,10 +57,10 @@ procSuite "Waku Discovery v5":
false,
keys.PrivateKey(nodeKey1.skkey),
flags,
[], # Empty enr fields, for now
newSeq[MultiAddress](), # Empty multiaddr fields, for now
node1.rng
)

node2.wakuDiscv5 = WakuDiscoveryV5.new(
some(extIp), some(nodeTcpPort2), some(nodeUdpPort2),
bindIp,
Expand All @@ -68,10 +69,10 @@ procSuite "Waku Discovery v5":
false,
keys.PrivateKey(nodeKey2.skkey),
flags,
[], # Empty enr fields, for now
newSeq[MultiAddress](), # Empty multiaddr fields, for now
node2.rng
)

node3.wakuDiscv5 = WakuDiscoveryV5.new(
some(extIp), some(nodeTcpPort3), some(nodeUdpPort3),
bindIp,
Expand All @@ -80,7 +81,7 @@ procSuite "Waku Discovery v5":
false,
keys.PrivateKey(nodeKey3.skkey),
flags,
[], # Empty enr fields, for now
newSeq[MultiAddress](), # Empty multiaddr fields, for now
node3.rng
)

Expand All @@ -97,7 +98,7 @@ procSuite "Waku Discovery v5":
node1.wakuDiscv5.protocol.nodesDiscovered > 0
node2.wakuDiscv5.protocol.nodesDiscovered > 0
node3.wakuDiscv5.protocol.nodesDiscovered > 0

# Let's see if we can deliver a message end-to-end
# var completionFut = newFuture[bool]()
# proc relayHandler(topic: string, data: seq[byte]) {.async, gcsafe.} =
Expand All @@ -119,3 +120,64 @@ procSuite "Waku Discovery v5":
# (await completionFut.withTimeout(6.seconds)) == true

await allFutures([node1.stop(), node2.stop(), node3.stop()])

asyncTest "Custom multiaddresses are advertised correctly":
let
bindIp = ValidIpAddress.init("0.0.0.0")
extIp = ValidIpAddress.init("127.0.0.1")
expectedMultiAddr = MultiAddress.init("/ip4/200.200.200.200/tcp/9000/wss").tryGet()

flags = initWakuFlags(lightpush = false,
filter = false,
store = false,
relay = true)

nodeTcpPort1 = Port(9010)
nodeUdpPort1 = Port(9012)
node1Key = generateKey()
node1AddressMetadata = getWakuNodeAddrMeta(bindIp = bindIp,
extIp = some(extIp),
extPort = some(nodeTcpPort1),
bindPort = nodeTcpPort1,
extmultiAddrs = @[expectedMultiAddr],
wakuFlags = some(flags),
discv5UdpPort = some(nodeUdpPort1))
node1discV5 = getWakuDiscoveryV5(addressMetadata = node1AddressMetadata,
nodekey = node1Key,
rng = rng)
node1 = WakuNode.new(nodekey = node1Key,
addressMetadata = node1AddressMetadata,
wakuDiscv5 = some(node1discV5),
rng = rng)


nodeTcpPort2 = Port(9014)
nodeUdpPort2 = Port(9016)
node2Key = generateKey()
node2AddressMetadata = getWakuNodeAddrMeta(bindIp = bindIp,
extIp = some(extIp),
extPort = some(nodeTcpPort2),
bindPort = nodeTcpPort2,
wakuFlags = some(flags),
discv5UdpPort = some(nodeUdpPort2))
node2discV5 = getWakuDiscoveryV5(addressMetadata = node2AddressMetadata,
discv5BootstrapEnrs = @[node1.wakuDiscv5.protocol.localNode.record],
nodekey = node2Key)
node2 = WakuNode.new(nodeKey = node2Key,
addressMetadata = node2AddressMetadata,
wakuDiscv5 = some(node2discV5))

await allFutures([node1.start(), node2.start()])

await allFutures([node1.startDiscv5(), node2.startDiscv5()])

await sleepAsync(3000.millis) # Give the algorithm some time to work its magic

let node1Enr = node2.wakuDiscv5.protocol.routingTable.buckets[0].nodes[0].record
let multiaddrs = node1Enr.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses()

check:
node1.wakuDiscv5.protocol.nodesDiscovered > 0
node2.wakuDiscv5.protocol.nodesDiscovered > 0
multiaddrs.contains(expectedMultiAddr)

4 changes: 2 additions & 2 deletions tests/v2/test_waku_peer_exchange.nim
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ procSuite "Waku Peer Exchange":
false,
keys.PrivateKey(nodeKey1.skkey),
flags,
[], # Empty enr fields, for now
newSeq[MultiAddress](), # Empty multiaddr fields, for now
node1.rng
)

Expand All @@ -115,7 +115,7 @@ procSuite "Waku Peer Exchange":
false,
keys.PrivateKey(nodeKey2.skkey),
flags,
[], # Empty enr fields, for now
newSeq[MultiAddress](), # Empty multiaddr fields, for now
node2.rng
)

Expand Down
10 changes: 6 additions & 4 deletions waku/v2/node/discv5/waku_discv5.nim
Original file line number Diff line number Diff line change
Expand Up @@ -107,14 +107,16 @@ proc new*(T: type WakuDiscoveryV5,
enrAutoUpdate = false,
privateKey: keys.PrivateKey,
flags: WakuEnrBitfield,
enrFields: openArray[(string, seq[byte])],
multiaddrs = newSeq[MultiAddress](),
rng: ref HmacDrbgContext,
discv5Config: protocol.DiscoveryConfig = protocol.defaultDiscoveryConfig): T =
## TODO: consider loading from a configurable bootstrap file

## We always add the waku field as specified
var enrInitFields = @[(WAKU_ENR_FIELD, @[flags.byte])]
enrInitFields.add(enrFields)

## Add multiaddresses to ENR
enrInitFields.add((MULTIADDR_ENR_FIELD, multiaddrs.getRawField()))

let protocol = newProtocol(
privateKey,
Expand All @@ -139,7 +141,7 @@ proc new*(T: type WakuDiscoveryV5,
enrAutoUpdate = false,
privateKey: keys.PrivateKey,
flags: WakuEnrBitfield,
enrFields: openArray[(string, seq[byte])],
multiaddrs = newSeq[MultiAddress](),
rng: ref HmacDrbgContext,
discv5Config: protocol.DiscoveryConfig = protocol.defaultDiscoveryConfig): T =

Expand All @@ -155,7 +157,7 @@ proc new*(T: type WakuDiscoveryV5,
enrAutoUpdate,
privateKey,
flags,
enrFields,
multiaddrs,
rng,
discv5Config
)
Expand Down
Loading

0 comments on commit f69810d

Please sign in to comment.