From c1874a46b385baba93249a034644698b12b49862 Mon Sep 17 00:00:00 2001 From: rymnc <43716372+rymnc@users.noreply.github.com> Date: Thu, 26 Jan 2023 17:22:27 +0530 Subject: [PATCH 1/7] feat(discv5): allow custom multiaddr advertisement in discv5 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 --- apps/wakunode2/wakunode2.nim | 95 ++++++------ examples/v2/publisher.nim | 1 - examples/v2/subscriber.nim | 1 - tests/v2/test_waku_discv5.nim | 78 +++++++++- tests/v2/test_waku_peer_exchange.nim | 4 +- waku/v2/node/discv5/waku_discv5.nim | 10 +- waku/v2/node/waku_node.nim | 213 +++++++++++++++++++++------ waku/v2/utils/peers.nim | 23 ++- waku/v2/utils/wakuenr.nim | 36 +++-- 9 files changed, 326 insertions(+), 135 deletions(-) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 8e35776b7b..4a3a360370 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -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), - 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 = 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, diff --git a/examples/v2/publisher.nim b/examples/v2/publisher.nim index 30c77848fd..15aa2b927e 100644 --- a/examples/v2/publisher.nim +++ b/examples/v2/publisher.nim @@ -48,7 +48,6 @@ proc setupAndPublish() {.async.} = bootstrapNodes = bootstrapNodes, privateKey = keys.PrivateKey(nodeKey.skkey), flags = flags, - enrFields = [], rng = node.rng) await node.start() diff --git a/examples/v2/subscriber.nim b/examples/v2/subscriber.nim index 9dcf79ec44..101f3b6709 100644 --- a/examples/v2/subscriber.nim +++ b/examples/v2/subscriber.nim @@ -44,7 +44,6 @@ proc setupAndSubscribe() {.async.} = bootstrapNodes = bootstrapNodes, privateKey = keys.PrivateKey(nodeKey.skkey), flags = flags, - enrFields = [], rng = node.rng) await node.start() diff --git a/tests/v2/test_waku_discv5.nim b/tests/v2/test_waku_discv5.nim index 2579f090d7..7e0b070635 100644 --- a/tests/v2/test_waku_discv5.nim +++ b/tests/v2/test_waku_discv5.nim @@ -2,6 +2,7 @@ import chronos, + chronicles, testutils/unittests, stew/byteutils, stew/shims/net, @@ -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) @@ -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), @@ -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, @@ -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, @@ -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 ) @@ -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.} = @@ -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) + diff --git a/tests/v2/test_waku_peer_exchange.nim b/tests/v2/test_waku_peer_exchange.nim index d32ccb60a3..1fb1bdae4d 100644 --- a/tests/v2/test_waku_peer_exchange.nim +++ b/tests/v2/test_waku_peer_exchange.nim @@ -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 ) @@ -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 ) diff --git a/waku/v2/node/discv5/waku_discv5.nim b/waku/v2/node/discv5/waku_discv5.nim index 6468e02953..39ca436df3 100644 --- a/waku/v2/node/discv5/waku_discv5.nim +++ b/waku/v2/node/discv5/waku_discv5.nim @@ -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, @@ -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 = @@ -155,7 +157,7 @@ proc new*(T: type WakuDiscoveryV5, enrAutoUpdate, privateKey, flags, - enrFields, + multiaddrs, rng, discv5Config ) diff --git a/waku/v2/node/waku_node.nim b/waku/v2/node/waku_node.nim index 7db205b38e..b425e5690b 100644 --- a/waku/v2/node/waku_node.nim +++ b/waku/v2/node/waku_node.nim @@ -130,36 +130,46 @@ template wsFlag(wssEnabled: bool): MultiAddress = if wssEnabled: MultiAddress.init("/wss").tryGet() else: MultiAddress.init("/ws").tryGet() -proc new*(T: type WakuNode, - nodeKey: crypto.PrivateKey, - bindIp: ValidIpAddress, - bindPort: Port, - extIp = none(ValidIpAddress), - extPort = none(Port), - extMultiAddrs = newSeq[MultiAddress](), - peerStorage: PeerStorage = nil, - maxConnections = builders.MaxConnections, - wsBindPort: Port = (Port)8000, - wsEnabled: bool = false, - wssEnabled: bool = false, - secureKey: string = "", - secureCert: string = "", - wakuFlags = none(WakuEnrBitfield), - nameResolver: NameResolver = nil, - sendSignedPeerRecord = false, - dns4DomainName = none(string), - discv5UdpPort = none(Port), - agentString = none(string), # defaults to nim-libp2p version - peerStoreCapacity = none(int), # defaults to 1.25 maxConnections - ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} = - ## Creates a Waku Node instance. - +type WakuNodeAddrMeta* = object + hostAddress*: MultiAddress + wsHostAddress*: Option[MultiAddress] + hostExtAddress*: Option[MultiAddress] + wsExtAddress*: Option[MultiAddress] + wssEnabled*: bool + extIp*: Option[ValidIpAddress] + extPort*: Option[Port] + dns4DomainName*: Option[string] + announcedAddresses*: seq[MultiAddress] + extMultiAddrs*: seq[MultiAddress] + enrMultiAddrs*: seq[MultiAddress] + enrIp*: Option[ValidIpAddress] + enrPort*: Option[Port] + discv5UdpPort*: Option[Port] + wakuFlags*: Option[WakuEnrBitfield] + bindIp*: ValidIpAddress + bindPort*: Port + +proc getWakuNodeAddrMeta*( + bindIp: ValidIpAddress, + bindPort: Port, + extIp = none(ValidIpAddress), + extPort = none(Port), + extMultiAddrs = newSeq[MultiAddress](), + wsBindPort: Port = (Port)8000, + wsEnabled: bool = false, + wssEnabled: bool = false, + dns4DomainName = none(string), + discv5UdpPort = none(Port), + wakuFlags = none(WakuEnrBitfield) +): WakuNodeAddrMeta {.raises: [LPError]} = ## Initialize addresses let # Bind addresses hostAddress = ip4TcpEndPoint(bindIp, bindPort) wsHostAddress = if wsEnabled or wssEnabled: some(ip4TcpEndPoint(bindIp, wsbindPort) & wsFlag(wssEnabled)) else: none(MultiAddress) + enrIp = if extIp.isSome(): extIp else: some(bindIp) + enrPort = if extPort.isSome(): extPort else: some(bindPort) # Setup external addresses, if available var @@ -195,26 +205,67 @@ proc new*(T: type WakuNode, elif wsHostAddress.isSome(): announcedAddresses.add(wsHostAddress.get()) - ## Initialize peer let - rng = crypto.newRng() - enrIp = if extIp.isSome(): extIp - else: some(bindIp) - enrTcpPort = if extPort.isSome(): extPort - else: some(bindPort) # enrMultiaddrs are just addresses which cannot be represented in ENR, as described in # https://rfc.vac.dev/spec/31/#many-connection-types enrMultiaddrs = announcedAddresses.filterIt(it.hasProtocol("dns4") or it.hasProtocol("dns6") or it.hasProtocol("ws") or it.hasProtocol("wss")) - enr = initEnr(nodeKey, - enrIp, - enrTcpPort, - discv5UdpPort, - wakuFlags, - enrMultiaddrs) + return WakuNodeAddrMeta( + hostAddress: hostAddress, + wsHostAddress: wsHostAddress, + hostExtAddress: hostExtAddress, + wsExtAddress: wsExtAddress, + extIp: extIp, + extPort: extPort, + wssEnabled: wssEnabled, + dns4DomainName: dns4DomainName, + announcedAddresses: announcedAddresses, + extMultiAddrs: extMultiAddrs, + enrMultiaddrs: enrMultiaddrs, + enrIp: enrIp, + enrPort: enrPort, + discv5UdpPort: discv5UdpPort, + bindIp: bindIp, + bindPort: bindPort, + wakuFlags: wakuFlags) + +proc getWakuDiscoveryV5*(addressMetadata: WakuNodeAddrMeta, + nodekey: crypto.PrivateKey, + discv5Config = defaultDiscoveryConfig, + discv5BootstrapEnrs = newSeq[enr.Record](), + discv5EnrAutoUpdate = false, + rng = crypto.newRng()): WakuDiscoveryV5 = + return WakuDiscoveryV5.new( + extIp = addressMetadata.extIp, + extTcpPort = addressMetadata.extPort, + extUdpPort = addressMetadata.discv5UdpPort, + bindIp = addressMetadata.bindIp, + discv5UdpPort = addressMetadata.discv5UdpPort.get(), + bootstrapEnrs = discv5BootstrapEnrs, + enrAutoUpdate = discv5EnrAutoUpdate, + privateKey = keys.PrivateKey(nodekey.skkey), + flags = addressMetadata.wakuFlags.get(), + multiaddrs = addressMetadata.enrMultiaddrs, + rng = rng, + discv5Config = discv5Config) + +proc getEnr*(addressMetadata: WakuNodeAddrMeta, + wakuDiscV5 = none(WakuDiscoveryV5), + nodeKey: crypto.PrivateKey): enr.Record = + if wakuDiscV5.isSome(): + return wakuDiscV5.get().protocol.getRecord() + + return initEnr(nodekey, + addressMetadata.enrIp, + addressMetadata.enrPort, + addressMetadata.discv5UdpPort, + addressMetadata.wakuFlags, + addressMetadata.enrMultiaddrs) + +proc getAutonatService*(rng = crypto.newRng()): AutonatService = ## AutonatService request other peers to dial us back ## flagging us as Reachable or NotReachable. ## minConfidence is used as threshold to determine the state. @@ -235,36 +286,104 @@ proc new*(T: type WakuNode, autonatService.statusAndConfidenceHandler(statusAndConfidenceHandler) - info "Initializing networking", addrs=announcedAddresses + return autonatService + +## retain old signature, but deprecate it +proc new*(T: type WakuNode, + nodeKey: crypto.PrivateKey, + bindIp: ValidIpAddress, + bindPort: Port, + extIp = none(ValidIpAddress), + extPort = none(Port), + extMultiAddrs = newSeq[MultiAddress](), + peerStorage: PeerStorage = nil, + maxConnections = builders.MaxConnections, + wsBindPort: Port = (Port)8000, + wsEnabled: bool = false, + wssEnabled: bool = false, + secureKey: string = "", + secureCert: string = "", + wakuFlags = none(WakuEnrBitfield), + nameResolver: NameResolver = nil, + sendSignedPeerRecord = false, + dns4DomainName = none(string), + discv5UdpPort = none(Port), + wakuDiscv5 = none(WakuDiscoveryV5), + agentString = none(string), # defaults to nim-libp2p version + peerStoreCapacity = none(int), # defaults to 1.25 maxConnections + ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError], deprecated: "Use AddressMetadata variant".} = + let addressMetadata = getWakuNodeAddrMeta( + bindIp = bindIp, + bindPort = bindPort, + extIp = extIp, + extPort = extPort, + extMultiAddrs = extMultiAddrs, + wsBindPort = wsBindPort, + wsEnabled = wsEnabled, + wssEnabled = wssEnabled, + wakuFlags = wakuFlags, + dns4DomainName = dns4DomainName, + discv5UdpPort = discv5UdpPort, + ) + + return WakuNode.new( + nodeKey = nodeKey, + addressMetadata = addressMetadata, + peerStorage = peerStorage, + maxConnections = maxConnections, + secureKey = secureKey, + secureCert = secureCert, + nameResolver = nameResolver, + sendSignedPeerRecord = sendSignedPeerRecord, + wakuDiscv5 = wakuDiscv5, + agentString = agentString, + peerStoreCapacity = peerStoreCapacity, + ) + +proc new*(T: type WakuNode, + nodeKey: crypto.PrivateKey, + addressMetadata: WakuNodeAddrMeta, + peerStorage: PeerStorage = nil, + maxConnections = builders.MaxConnections, + rng = crypto.newRng(), + secureKey: string = "", + secureCert: string = "", + nameResolver: NameResolver = nil, + sendSignedPeerRecord = false, + wakuDiscv5 = none(WakuDiscoveryV5), + agentString = none(string), # defaults to nim-libp2p version + peerStoreCapacity = none(int), # defaults to nim-libp2p max size + ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} = + ## Creates a Waku Node instance. + + info "Initializing networking", addrs=addressMetadata.announcedAddresses let switch = newWakuSwitch( some(nodekey), - hostAddress, - wsHostAddress, + address = addressMetadata.hostAddress, + wsAddress = addressMetadata.wsHostAddress, transportFlags = {ServerFlags.ReuseAddr}, rng = rng, maxConnections = maxConnections, - wssEnabled = wssEnabled, + wssEnabled = addressMetadata.wssEnabled, secureKeyPath = secureKey, secureCertPath = secureCert, nameResolver = nameResolver, sendSignedPeerRecord = sendSignedPeerRecord, agentString = agentString, peerStoreCapacity = peerStoreCapacity, - services = @[Service(autonatservice)], + services = @[Service(getAutonatService(rng))], ) - let wakuNode = WakuNode( + return WakuNode( peerManager: PeerManager.new(switch, peerStorage), switch: switch, rng: rng, - enr: enr, - announcedAddresses: announcedAddresses + enr: addressMetadata.getEnr(wakuDiscv5, nodekey), + announcedAddresses: addressMetadata.announcedAddresses, + wakuDiscv5: if wakuDiscV5.isSome(): wakuDiscV5.get() else: nil, ) - return wakuNode - - proc peerInfo*(node: WakuNode): PeerInfo = node.switch.peerInfo diff --git a/waku/v2/utils/peers.nim b/waku/v2/utils/peers.nim index 38eaefdd28..4c74ad2fc8 100644 --- a/waku/v2/utils/peers.nim +++ b/waku/v2/utils/peers.nim @@ -40,7 +40,7 @@ proc init*( addrs: addrs, enr: enr, protocols: protocols) - + return remotePeerInfo proc init*(p: typedesc[RemotePeerInfo], @@ -49,7 +49,7 @@ proc init*(p: typedesc[RemotePeerInfo], enr: Option[enr.Record] = none(enr.Record), protocols: seq[string] = @[]): RemotePeerInfo {.raises: [Defect, ResultError[cstring], LPError].} = - + let remotePeerInfo = RemotePeerInfo( peerId: PeerID.init(peerId).tryGet(), addrs: addrs, @@ -97,7 +97,7 @@ proc parseRemotePeerInfo*(address: string): RemotePeerInfo {.raises: [Defect, Va # nim-libp2p dialing requires remote peers to be initialised with a peerId and a wire address let - peerIdStr = p2pPart.toString()[].split("/")[^1] + peerIdStr = p2pPart.toString()[].split("/")[^1] wireAddr = nwPart & tcpPart & wsPart & wssPart if (not wireAddr.validWireAddr()): @@ -111,12 +111,12 @@ proc toRemotePeerInfo*(enr: enr.Record): Result[RemotePeerInfo, cstring] = if not typedR.secp256k1.isSome: return err("enr: no secp256k1 key in record") - + let pubKey = ? keys.PublicKey.fromRaw(typedR.secp256k1.get) peerId = ? PeerID.init(crypto.PublicKey(scheme: Secp256k1, skkey: secp.SkPublicKey(pubKey))) - + var addrs = newSeq[MultiAddress]() let transportProto = getTransportProtocol(typedR) @@ -182,3 +182,16 @@ proc hasProtocol*(ma: MultiAddress, proto: string): bool = if p == MultiCodec.codec(proto): return true return false + +func filterEnrPeersWithUdpPort*(peers: seq[RemotePeerInfo]): seq[enr.Record] = + var filteredEnrs: seq[enr.Record] + for peer in peers: + if peer.enr.isSome(): + let + enr = peer.enr.get() + typedEnrRes = enr.toTypedRecord() + if typedEnrRes.isOk(): + let typedEnr = typedEnrRes.get() + if typedEnr.udp.isSome() or typedEnr.udp6.isSome(): + filteredEnrs.add(enr) + return filteredEnrs diff --git a/waku/v2/utils/wakuenr.nim b/waku/v2/utils/wakuenr.nim index 403043caf4..bd6070a87f 100644 --- a/waku/v2/utils/wakuenr.nim +++ b/waku/v2/utils/wakuenr.nim @@ -34,21 +34,25 @@ type Filter = 2, Lightpush = 3, -func toFieldPair(multiaddrs: seq[MultiAddress]): FieldPair = - ## Converts a seq of multiaddrs to a `multiaddrs` ENR - ## field pair according to https://rfc.vac.dev/spec/31/ - +func getRawField*(multiaddrs: seq[MultiAddress]): seq[byte] = var fieldRaw: seq[byte] for multiaddr in multiaddrs: let maRaw = multiaddr.data.buffer # binary encoded multiaddr maSize = maRaw.len.uint16.toBytes(Endianness.bigEndian) # size as Big Endian unsigned 16-bit integer - + assert maSize.len == 2 fieldRaw.add(concat(@maSize, maRaw)) - + + return fieldRaw + +func toFieldPair*(multiaddrs: seq[MultiAddress]): FieldPair = + ## Converts a seq of multiaddrs to a `multiaddrs` ENR + ## field pair according to https://rfc.vac.dev/spec/31/ + let fieldRaw = multiaddrs.getRawField() + return toFieldPair(MULTIADDR_ENR_FIELD, fieldRaw) func stripPeerId(multiaddr: MultiAddress): MultiAddress = @@ -58,10 +62,10 @@ func stripPeerId(multiaddr: MultiAddress): MultiAddress = if item[].protoName()[] != "p2p": # Add all parts except p2p peerId discard cleanAddr.append(item[]) - + return cleanAddr -func stripPeerIds(multiaddrs: seq[MultiAddress]): seq[MultiAddress] = +func stripPeerIds*(multiaddrs: seq[MultiAddress]): seq[MultiAddress] = var cleanAddrs: seq[MultiAddress] for multiaddr in multiaddrs: @@ -69,19 +73,19 @@ func stripPeerIds(multiaddrs: seq[MultiAddress]): seq[MultiAddress] = cleanAddrs.add(multiaddr.stripPeerId()) else: cleanAddrs.add(multiaddr) - + return cleanAddrs func readBytes(rawBytes: seq[byte], numBytes: int, pos: var int = 0): Result[seq[byte], cstring] = - ## Attempts to read `numBytes` from a sequence, from + ## Attempts to read `numBytes` from a sequence, from ## position `pos`. Returns the requested slice or ## an error if `rawBytes` boundary is exceeded. - ## + ## ## If successful, `pos` is advanced by `numBytes` if rawBytes[pos..^1].len() < numBytes: return err("Exceeds maximum available bytes") - + let slicedSeq = rawBytes[pos.. Date: Wed, 1 Feb 2023 11:17:32 +0530 Subject: [PATCH 2/7] fix(waku_node): 1.25 max conns --- waku/v2/node/waku_node.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/waku/v2/node/waku_node.nim b/waku/v2/node/waku_node.nim index b425e5690b..18a3c34ac9 100644 --- a/waku/v2/node/waku_node.nim +++ b/waku/v2/node/waku_node.nim @@ -352,7 +352,7 @@ proc new*(T: type WakuNode, sendSignedPeerRecord = false, wakuDiscv5 = none(WakuDiscoveryV5), agentString = none(string), # defaults to nim-libp2p version - peerStoreCapacity = none(int), # defaults to nim-libp2p max size + peerStoreCapacity = none(int), # defaults to 1.25 maxConnections ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} = ## Creates a Waku Node instance. From 70e34bae069ff05abf979f8ab5b94374244b2aa1 Mon Sep 17 00:00:00 2001 From: rymnc <43716372+rymnc@users.noreply.github.com> Date: Thu, 2 Feb 2023 18:52:04 +0530 Subject: [PATCH 3/7] fix(discv5): s/WakuNodeAddrMeta/NetConfig/g --- apps/wakunode2/wakunode2.nim | 2 +- tests/v2/test_waku_discv5.nim | 4 ++-- waku/v2/node/waku_node.nim | 16 ++++++++-------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 4a3a360370..c4b1451888 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -274,7 +274,7 @@ proc initNode(conf: WakuNodeConf, var wakuDiscv5 = none(WakuDiscoveryV5) let rng = crypto.newRng() - let addressMetadata = getWakuNodeAddrMeta( + let addressMetadata = getNetConfig( bindIp = conf.listenAddress, bindPort = Port(uint16(conf.tcpPort) + conf.portsShift), extIp = extIp, diff --git a/tests/v2/test_waku_discv5.nim b/tests/v2/test_waku_discv5.nim index 7e0b070635..91092531cd 100644 --- a/tests/v2/test_waku_discv5.nim +++ b/tests/v2/test_waku_discv5.nim @@ -135,7 +135,7 @@ procSuite "Waku Discovery v5": nodeTcpPort1 = Port(9010) nodeUdpPort1 = Port(9012) node1Key = generateKey() - node1AddressMetadata = getWakuNodeAddrMeta(bindIp = bindIp, + node1AddressMetadata = getNetConfig(bindIp = bindIp, extIp = some(extIp), extPort = some(nodeTcpPort1), bindPort = nodeTcpPort1, @@ -154,7 +154,7 @@ procSuite "Waku Discovery v5": nodeTcpPort2 = Port(9014) nodeUdpPort2 = Port(9016) node2Key = generateKey() - node2AddressMetadata = getWakuNodeAddrMeta(bindIp = bindIp, + node2AddressMetadata = getNetConfig(bindIp = bindIp, extIp = some(extIp), extPort = some(nodeTcpPort2), bindPort = nodeTcpPort2, diff --git a/waku/v2/node/waku_node.nim b/waku/v2/node/waku_node.nim index 18a3c34ac9..0c800c0692 100644 --- a/waku/v2/node/waku_node.nim +++ b/waku/v2/node/waku_node.nim @@ -130,7 +130,7 @@ template wsFlag(wssEnabled: bool): MultiAddress = if wssEnabled: MultiAddress.init("/wss").tryGet() else: MultiAddress.init("/ws").tryGet() -type WakuNodeAddrMeta* = object +type NetConfig* = object hostAddress*: MultiAddress wsHostAddress*: Option[MultiAddress] hostExtAddress*: Option[MultiAddress] @@ -149,7 +149,7 @@ type WakuNodeAddrMeta* = object bindIp*: ValidIpAddress bindPort*: Port -proc getWakuNodeAddrMeta*( +proc getNetConfig*( bindIp: ValidIpAddress, bindPort: Port, extIp = none(ValidIpAddress), @@ -161,7 +161,7 @@ proc getWakuNodeAddrMeta*( dns4DomainName = none(string), discv5UdpPort = none(Port), wakuFlags = none(WakuEnrBitfield) -): WakuNodeAddrMeta {.raises: [LPError]} = +): NetConfig {.raises: [LPError]} = ## Initialize addresses let # Bind addresses @@ -213,7 +213,7 @@ proc getWakuNodeAddrMeta*( it.hasProtocol("ws") or it.hasProtocol("wss")) - return WakuNodeAddrMeta( + return NetConfig( hostAddress: hostAddress, wsHostAddress: wsHostAddress, hostExtAddress: hostExtAddress, @@ -232,7 +232,7 @@ proc getWakuNodeAddrMeta*( bindPort: bindPort, wakuFlags: wakuFlags) -proc getWakuDiscoveryV5*(addressMetadata: WakuNodeAddrMeta, +proc getWakuDiscoveryV5*(addressMetadata: NetConfig, nodekey: crypto.PrivateKey, discv5Config = defaultDiscoveryConfig, discv5BootstrapEnrs = newSeq[enr.Record](), @@ -252,7 +252,7 @@ proc getWakuDiscoveryV5*(addressMetadata: WakuNodeAddrMeta, rng = rng, discv5Config = discv5Config) -proc getEnr*(addressMetadata: WakuNodeAddrMeta, +proc getEnr*(addressMetadata: NetConfig, wakuDiscV5 = none(WakuDiscoveryV5), nodeKey: crypto.PrivateKey): enr.Record = if wakuDiscV5.isSome(): @@ -312,7 +312,7 @@ proc new*(T: type WakuNode, agentString = none(string), # defaults to nim-libp2p version peerStoreCapacity = none(int), # defaults to 1.25 maxConnections ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError], deprecated: "Use AddressMetadata variant".} = - let addressMetadata = getWakuNodeAddrMeta( + let addressMetadata = getNetConfig( bindIp = bindIp, bindPort = bindPort, extIp = extIp, @@ -342,7 +342,7 @@ proc new*(T: type WakuNode, proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, - addressMetadata: WakuNodeAddrMeta, + addressMetadata: NetConfig, peerStorage: PeerStorage = nil, maxConnections = builders.MaxConnections, rng = crypto.newRng(), From 8f854af7c3100627b9f5ecb1a73d46f007ea7898 Mon Sep 17 00:00:00 2001 From: rymnc <43716372+rymnc@users.noreply.github.com> Date: Thu, 2 Feb 2023 19:52:11 +0530 Subject: [PATCH 4/7] fix(discv5): address reviews --- apps/wakunode2/wakunode2.nim | 26 ++++++++----- tests/v2/test_enr_utils.nim | 54 +++++++++++++-------------- tests/v2/test_waku_discv5.nim | 54 ++++++++++++++++----------- waku/v2/node/discv5/waku_discv5.nim | 2 +- waku/v2/node/waku_node.nim | 58 ++++++++++------------------- waku/v2/utils/peers.nim | 26 +++++++------ waku/v2/utils/wakuenr.nim | 15 ++++---- 7 files changed, 120 insertions(+), 115 deletions(-) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index c4b1451888..76210021a9 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -274,7 +274,7 @@ proc initNode(conf: WakuNodeConf, var wakuDiscv5 = none(WakuDiscoveryV5) let rng = crypto.newRng() - let addressMetadata = getNetConfig( + let netConfig = NetConfig.init( bindIp = conf.listenAddress, bindPort = Port(uint16(conf.tcpPort) + conf.portsShift), extIp = extIp, @@ -288,7 +288,7 @@ proc initNode(conf: WakuNodeConf, wakuFlags = some(wakuFlags), ) if conf.discv5Discovery: - let dynamicBootstrapEnrs = filterEnrPeersWithUdpPort(@dynamicBootstrapNodes) + let dynamicBootstrapEnrs = dynamicBootstrapNodes.filterIt(it.hasUdpPort()) var discv5BootstrapEnrs: seq[enr.Record] # parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq for enrUri in conf.discv5BootstrapNodes: @@ -297,14 +297,22 @@ proc initNode(conf: WakuNodeConf, 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)) + wakuDiscv5 = some(WakuDiscoveryV5.new( + extIp = netConfig.extIp, + extTcpPort = netConfig.extPort, + extUdpPort = netConfig.discv5UdpPort, + bindIp = netConfig.bindIp, + discv5UdpPort = netConfig.discv5UdpPort, + bootstrapEnrs = discv5BootstrapEnrs, + enrAutoUpdate = conf.discv5EnrAutoUpdate, + privateKey = keys.PrivateKey(conf.nodekey.skkey), + flags = netConfig.wakuFlags.get(), + multiaddrs = netConfig.enrMultiaddrs, + rng = rng, + discv5Config = discv5Config, + )) node = WakuNode.new(nodekey = conf.nodekey, - addressMetadata = addressMetadata, + netConfig = netConfig, rng = rng, peerStorage = pStorage, maxConnections = conf.maxConnections.int, diff --git a/tests/v2/test_enr_utils.nim b/tests/v2/test_enr_utils.nim index 618fe0abae..fb9ae1a8cc 100644 --- a/tests/v2/test_enr_utils.nim +++ b/tests/v2/test_enr_utils.nim @@ -22,10 +22,10 @@ procSuite "ENR utils": tooShort = "0x000A047F0000010601BADD0301".hexToSeqByte() gibberish = "0x3270ac4e5011123c".hexToSeqByte() empty = newSeq[byte]() - + ## Note: we expect to fail optimistically, i.e. extract ## any addresses we can and ignore other errors. - ## Worst case scenario is we return an empty `multiaddrs` seq. + ## Worst case scenario is we return an empty `multiaddrs` seq. check: # Expected cases reasonable.toMultiAddresses().contains(MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]) @@ -50,19 +50,19 @@ procSuite "ENR utils": MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]] let - record = initEnr(enrKey, some(enrIp), + record = enr.Record.init(enrKey, some(enrIp), some(enrTcpPort), some(enrUdpPort), some(wakuFlags), multiaddrs) typedRecord = record.toTypedRecord.get() - + # Check EIP-778 ENR fields check: @(typedRecord.secp256k1.get()) == enrKey.getPublicKey()[].getRawBytes()[] ipv4(typedRecord.ip.get()) == enrIp Port(typedRecord.tcp.get()) == enrTcpPort Port(typedRecord.udp.get()) == enrUdpPort - + # Check Waku ENR fields let decodedFlags = record.get(WAKU_ENR_FIELD, seq[byte])[] @@ -71,7 +71,7 @@ procSuite "ENR utils": decodedFlags == @[wakuFlags.byte] decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]) decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]) - + asyncTest "Strip multiaddr peerId": # Tests that peerId is stripped of multiaddrs as per RFC31 let @@ -81,7 +81,7 @@ procSuite "ENR utils": multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss/p2p/16Uiu2HAm4v86W3bmT1BiH6oSPzcsSr31iDQpSN5Qa882BCjjwgrD")[]] let - record = initEnr(enrKey, some(enrIp), + record = enr.Record.init(enrKey, some(enrIp), some(enrTcpPort), some(enrUdpPort), none(WakuEnrBitfield), multiaddrs) @@ -89,7 +89,7 @@ procSuite "ENR utils": # Check Waku ENR fields let decodedAddrs = record.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses() - + check decodedAddrs.contains(MultiAddress.init("/ip4/127.0.0.1/tcp/443/wss")[]) # Peer Id has been stripped asyncTest "Decode ENR with multiaddrs field": @@ -110,7 +110,7 @@ procSuite "ENR utils": var enrRecord: Record check: enrRecord.fromURI(knownEnr) - + let typedRecord = enrRecord.toTypedRecord.get() # Check EIP-778 ENR fields @@ -118,11 +118,11 @@ procSuite "ENR utils": ipv4(typedRecord.ip.get()) == knownIp typedRecord.tcp == knownTcpPort typedRecord.udp == knownUdpPort - + # Check Waku ENR fields let decodedAddrs = enrRecord.get(MULTIADDR_ENR_FIELD, seq[byte])[].toMultiAddresses() - + for knownMultiaddr in knownMultiaddrs: check decodedAddrs.contains(knownMultiaddr) @@ -132,12 +132,12 @@ procSuite "ENR utils": enrTcpPort, enrUdpPort = Port(60000) enrKey = wakuenr.crypto.PrivateKey.random(Secp256k1, rng[])[] multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]] - - # TODO: Refactor initEnr, provide enums as inputs initEnr(capabilites=[Store,Filter]) + + # TODO: Refactor enr.Record.init, provide enums as inputs enr.Record.init(capabilites=[Store,Filter]) # TODO: safer than a util function and directly using the bits # test all flag combinations 2^4 = 16 (b0000-b1111) records = toSeq(0b0000_0000'u8..0b0000_1111'u8) - .mapIt(initEnr(enrKey, + .mapIt(enr.Record.init(enrKey, some(enrIp), some(enrTcpPort), some(enrUdpPort), @@ -161,7 +161,7 @@ procSuite "ENR utils": [true, true, false, true], [true, true, true, false], [true, true, true, true]] - + for i, record in records: for j, capability in @[Lightpush, Filter, Store, Relay]: check expectedCapabilities[i][j] == record.supportsCapability(capability) @@ -172,18 +172,18 @@ procSuite "ENR utils": enrTcpPort, enrUdpPort = Port(60000) enrKey = wakuenr.crypto.PrivateKey.random(Secp256k1, rng[])[] multiaddrs = @[MultiAddress.init("/ip4/127.0.0.1/tcp/442/ws")[]] - + records = @[0b0000_0000'u8, 0b0000_1111'u8, 0b0000_1001'u8, 0b0000_1110'u8, 0b0000_1000'u8,] - .mapIt(initEnr(enrKey, - some(enrIp), - some(enrTcpPort), - some(enrUdpPort), - some(uint8(it)), - multiaddrs)) + .mapIt(enr.Record.init(enrKey, + some(enrIp), + some(enrTcpPort), + some(enrUdpPort), + some(uint8(it)), + multiaddrs)) # expected capabilities, ordered LSB to MSB expectedCapabilities: seq[seq[Capabilities]] = @[ @@ -197,14 +197,14 @@ procSuite "ENR utils": check actualExpetedTuple[0].getCapabilities() == actualExpetedTuple[1] asyncTest "Get supported capabilities of a non waku node": - - # non waku enr, i.e. Ethereum one + + # non waku enr, i.e. Ethereum one let nonWakuEnr = "enr:-KG4QOtcP9X1FbIMOe17QNMKqDxCpm14jcX5tiOE4_TyMrFqbmhPZHK_ZPG2G"& "xb1GE2xdtodOfx9-cgvNtxnRyHEmC0ghGV0aDKQ9aX9QgAAAAD__________4JpZIJ2NIJpcIQDE8KdiXNl"& "Y3AyNTZrMaEDhpehBDbZjM_L9ek699Y7vhUJ-eAdMyQW_Fil522Y0fODdGNwgiMog3VkcIIjKA" - + var nonWakuEnrRecord: Record - + check: nonWakuEnrRecord.fromURI(nonWakuEnr) @@ -214,4 +214,4 @@ procSuite "ENR utils": nonWakuEnrRecord.supportsCapability(Relay) == false nonWakuEnrRecord.supportsCapability(Store) == false nonWakuEnrRecord.supportsCapability(Filter) == false - nonWakuEnrRecord.supportsCapability(Lightpush) == false \ No newline at end of file + nonWakuEnrRecord.supportsCapability(Lightpush) == false diff --git a/tests/v2/test_waku_discv5.nim b/tests/v2/test_waku_discv5.nim index 91092531cd..c088bd96bf 100644 --- a/tests/v2/test_waku_discv5.nim +++ b/tests/v2/test_waku_discv5.nim @@ -135,18 +135,24 @@ procSuite "Waku Discovery v5": nodeTcpPort1 = Port(9010) nodeUdpPort1 = Port(9012) node1Key = generateKey() - node1AddressMetadata = getNetConfig(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) + node1NetConfig = NetConfig.init(bindIp = bindIp, + extIp = some(extIp), + extPort = some(nodeTcpPort1), + bindPort = nodeTcpPort1, + extmultiAddrs = @[expectedMultiAddr], + wakuFlags = some(flags), + discv5UdpPort = some(nodeUdpPort1)) + node1discV5 = WakuDiscoveryV5.new(extIp = node1NetConfig.extIp, + extTcpPort = node1NetConfig.extPort, + extUdpPort = node1NetConfig.discv5UdpPort, + bindIp = node1NetConfig.bindIp, + discv5UdpPort = node1NetConfig.discv5UdpPort.get(), + privateKey = keys.PrivateKey(node1Key.skkey), + multiaddrs = node1NetConfig.enrMultiaddrs, + flags = node1NetConfig.wakuFlags.get(), + rng = rng) node1 = WakuNode.new(nodekey = node1Key, - addressMetadata = node1AddressMetadata, + netConfig = node1NetConfig, wakuDiscv5 = some(node1discV5), rng = rng) @@ -154,17 +160,23 @@ procSuite "Waku Discovery v5": nodeTcpPort2 = Port(9014) nodeUdpPort2 = Port(9016) node2Key = generateKey() - node2AddressMetadata = getNetConfig(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) + node2NetConfig = NetConfig.init(bindIp = bindIp, + extIp = some(extIp), + extPort = some(nodeTcpPort2), + bindPort = nodeTcpPort2, + wakuFlags = some(flags), + discv5UdpPort = some(nodeUdpPort2)) + node2discV5 = WakuDiscoveryV5.new(extIp = node2NetConfig.extIp, + extTcpPort = node2NetConfig.extPort, + extUdpPort = node2NetConfig.discv5UdpPort, + bindIp = node2NetConfig.bindIp, + discv5UdpPort = node2NetConfig.discv5UdpPort.get(), + bootstrapEnrs = @[node1.wakuDiscv5.protocol.localNode.record], + privateKey = keys.PrivateKey(node2Key.skkey), + flags = node2NetConfig.wakuFlags.get(), + rng = rng) node2 = WakuNode.new(nodeKey = node2Key, - addressMetadata = node2AddressMetadata, + netConfig = node2NetConfig, wakuDiscv5 = some(node2discV5)) await allFutures([node1.start(), node2.start()]) diff --git a/waku/v2/node/discv5/waku_discv5.nim b/waku/v2/node/discv5/waku_discv5.nim index 39ca436df3..90b62e62ba 100644 --- a/waku/v2/node/discv5/waku_discv5.nim +++ b/waku/v2/node/discv5/waku_discv5.nim @@ -103,7 +103,7 @@ proc new*(T: type WakuDiscoveryV5, extTcpPort, extUdpPort: Option[Port], bindIP: ValidIpAddress, discv5UdpPort: Port, - bootstrapEnrs: seq[enr.Record], + bootstrapEnrs = newSeq[enr.Record](), enrAutoUpdate = false, privateKey: keys.PrivateKey, flags: WakuEnrBitfield, diff --git a/waku/v2/node/waku_node.nim b/waku/v2/node/waku_node.nim index 0c800c0692..9ef2e1ad6a 100644 --- a/waku/v2/node/waku_node.nim +++ b/waku/v2/node/waku_node.nim @@ -149,7 +149,8 @@ type NetConfig* = object bindIp*: ValidIpAddress bindPort*: Port -proc getNetConfig*( +proc init*( + T: type NetConfig, bindIp: ValidIpAddress, bindPort: Port, extIp = none(ValidIpAddress), @@ -161,7 +162,7 @@ proc getNetConfig*( dns4DomainName = none(string), discv5UdpPort = none(Port), wakuFlags = none(WakuEnrBitfield) -): NetConfig {.raises: [LPError]} = +): T {.raises: [LPError]} = ## Initialize addresses let # Bind addresses @@ -232,38 +233,19 @@ proc getNetConfig*( bindPort: bindPort, wakuFlags: wakuFlags) -proc getWakuDiscoveryV5*(addressMetadata: NetConfig, - nodekey: crypto.PrivateKey, - discv5Config = defaultDiscoveryConfig, - discv5BootstrapEnrs = newSeq[enr.Record](), - discv5EnrAutoUpdate = false, - rng = crypto.newRng()): WakuDiscoveryV5 = - return WakuDiscoveryV5.new( - extIp = addressMetadata.extIp, - extTcpPort = addressMetadata.extPort, - extUdpPort = addressMetadata.discv5UdpPort, - bindIp = addressMetadata.bindIp, - discv5UdpPort = addressMetadata.discv5UdpPort.get(), - bootstrapEnrs = discv5BootstrapEnrs, - enrAutoUpdate = discv5EnrAutoUpdate, - privateKey = keys.PrivateKey(nodekey.skkey), - flags = addressMetadata.wakuFlags.get(), - multiaddrs = addressMetadata.enrMultiaddrs, - rng = rng, - discv5Config = discv5Config) -proc getEnr*(addressMetadata: NetConfig, +proc getEnr*(netConfig: NetConfig, wakuDiscV5 = none(WakuDiscoveryV5), nodeKey: crypto.PrivateKey): enr.Record = if wakuDiscV5.isSome(): return wakuDiscV5.get().protocol.getRecord() - return initEnr(nodekey, - addressMetadata.enrIp, - addressMetadata.enrPort, - addressMetadata.discv5UdpPort, - addressMetadata.wakuFlags, - addressMetadata.enrMultiaddrs) + return enr.Record.init(nodekey, + netConfig.enrIp, + netConfig.enrPort, + netConfig.discv5UdpPort, + netConfig.wakuFlags, + netConfig.enrMultiaddrs) proc getAutonatService*(rng = crypto.newRng()): AutonatService = ## AutonatService request other peers to dial us back @@ -311,8 +293,8 @@ proc new*(T: type WakuNode, wakuDiscv5 = none(WakuDiscoveryV5), agentString = none(string), # defaults to nim-libp2p version peerStoreCapacity = none(int), # defaults to 1.25 maxConnections - ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError], deprecated: "Use AddressMetadata variant".} = - let addressMetadata = getNetConfig( + ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError], deprecated: "Use NetConfig variant".} = + let netConfig = NetConfig.init( bindIp = bindIp, bindPort = bindPort, extIp = extIp, @@ -328,7 +310,7 @@ proc new*(T: type WakuNode, return WakuNode.new( nodeKey = nodeKey, - addressMetadata = addressMetadata, + netConfig = netConfig, peerStorage = peerStorage, maxConnections = maxConnections, secureKey = secureKey, @@ -342,7 +324,7 @@ proc new*(T: type WakuNode, proc new*(T: type WakuNode, nodeKey: crypto.PrivateKey, - addressMetadata: NetConfig, + netConfig: NetConfig, peerStorage: PeerStorage = nil, maxConnections = builders.MaxConnections, rng = crypto.newRng(), @@ -356,16 +338,16 @@ proc new*(T: type WakuNode, ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} = ## Creates a Waku Node instance. - info "Initializing networking", addrs=addressMetadata.announcedAddresses + info "Initializing networking", addrs=netConfig.announcedAddresses let switch = newWakuSwitch( some(nodekey), - address = addressMetadata.hostAddress, - wsAddress = addressMetadata.wsHostAddress, + address = netConfig.hostAddress, + wsAddress = netConfig.wsHostAddress, transportFlags = {ServerFlags.ReuseAddr}, rng = rng, maxConnections = maxConnections, - wssEnabled = addressMetadata.wssEnabled, + wssEnabled = netConfig.wssEnabled, secureKeyPath = secureKey, secureCertPath = secureCert, nameResolver = nameResolver, @@ -379,8 +361,8 @@ proc new*(T: type WakuNode, peerManager: PeerManager.new(switch, peerStorage), switch: switch, rng: rng, - enr: addressMetadata.getEnr(wakuDiscv5, nodekey), - announcedAddresses: addressMetadata.announcedAddresses, + enr: netConfig.getEnr(wakuDiscv5, nodekey), + announcedAddresses: netConfig.announcedAddresses, wakuDiscv5: if wakuDiscV5.isSome(): wakuDiscV5.get() else: nil, ) diff --git a/waku/v2/utils/peers.nim b/waku/v2/utils/peers.nim index 4c74ad2fc8..0c233a6e0b 100644 --- a/waku/v2/utils/peers.nim +++ b/waku/v2/utils/peers.nim @@ -183,15 +183,17 @@ proc hasProtocol*(ma: MultiAddress, proto: string): bool = return true return false -func filterEnrPeersWithUdpPort*(peers: seq[RemotePeerInfo]): seq[enr.Record] = - var filteredEnrs: seq[enr.Record] - for peer in peers: - if peer.enr.isSome(): - let - enr = peer.enr.get() - typedEnrRes = enr.toTypedRecord() - if typedEnrRes.isOk(): - let typedEnr = typedEnrRes.get() - if typedEnr.udp.isSome() or typedEnr.udp6.isSome(): - filteredEnrs.add(enr) - return filteredEnrs +func hasUdpPort*(peer: RemotePeerInfo): bool = + if peer.enr.isNone(): + return false + + let + enr = peer.enr.get() + typedEnrRes = enr.toTypedRecord() + + if typedEnrRes.isErr(): + return false + + let typedEnr = typedEnrRes.get() + typedEnr.udp.isSome() or typedEnr.udp6.isSome() + diff --git a/waku/v2/utils/wakuenr.nim b/waku/v2/utils/wakuenr.nim index bd6070a87f..8154377af7 100644 --- a/waku/v2/utils/wakuenr.nim +++ b/waku/v2/utils/wakuenr.nim @@ -105,8 +105,8 @@ func initWakuFlags*(lightpush, filter, store, relay: bool): WakuEnrBitfield = # TODO: With the changes in this PR, this can be refactored? Using the enum? # Perhaps refactor to: - # WaKuEnr.initEnr(..., capabilities=[Store, Lightpush]) - # WaKuEnr.initEnr(..., capabilities=[Store, Lightpush, Relay, Filter]) + # WaKuEnr.enr.Record.init(..., capabilities=[Store, Lightpush]) + # WaKuEnr.enr.Record.init(..., capabilities=[Store, Lightpush, Relay, Filter]) # Safer also since we dont inject WakuEnrBitfield, and we let this package # handle the bits according to the capabilities @@ -145,11 +145,12 @@ func toMultiAddresses*(multiaddrsField: seq[byte]): seq[MultiAddress] = return multiaddrs -func initEnr*(privateKey: crypto.PrivateKey, - enrIp: Option[ValidIpAddress], - enrTcpPort, enrUdpPort: Option[Port], - wakuFlags = none(WakuEnrBitfield), - multiaddrs: seq[MultiAddress] = @[]): enr.Record = +func init*(T: type enr.Record, + privateKey: crypto.PrivateKey, + enrIp: Option[ValidIpAddress], + enrTcpPort, enrUdpPort: Option[Port], + wakuFlags = none(WakuEnrBitfield), + multiaddrs: seq[MultiAddress] = @[]): T = assert privateKey.scheme == PKScheme.Secp256k1 From 29a3f1161deda26a35700e01f5d27390d4c99801 Mon Sep 17 00:00:00 2001 From: rymnc <43716372+rymnc@users.noreply.github.com> Date: Thu, 2 Feb 2023 20:27:17 +0530 Subject: [PATCH 5/7] fix(discv5): smaller try-catches --- apps/wakunode2/wakunode2.nim | 48 ++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 76210021a9..9a20df8bd1 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -270,11 +270,15 @@ proc initNode(conf: WakuNodeConf, let pStorage = if peerStore.isNone(): nil else: peerStore.get() - try: - var wakuDiscv5 = none(WakuDiscoveryV5) - let rng = crypto.newRng() - let netConfig = NetConfig.init( + 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 + var netConfigOpt = none(NetConfig) + + try: + netConfigOpt = some(NetConfig.init( bindIp = conf.listenAddress, bindPort = Port(uint16(conf.tcpPort) + conf.portsShift), extIp = extIp, @@ -286,23 +290,32 @@ proc initNode(conf: WakuNodeConf, dns4DomainName = dns4DomainName, discv5UdpPort = discv5UdpPort, wakuFlags = some(wakuFlags), - ) - if conf.discv5Discovery: - let dynamicBootstrapEnrs = dynamicBootstrapNodes.filterIt(it.hasUdpPort()) - 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) + )) + except: + return err("failed to create net config instance: " & getCurrentExceptionMsg()) + + let netConfig = netConfigOpt.get() + var wakuDiscv5 = none(WakuDiscoveryV5) + + if conf.discv5Discovery: + let dynamicBootstrapEnrs = dynamicBootstrapNodes + .filterIt(it.hasUdpPort()) + .mapIt(it.enr.get()) + 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) + try: wakuDiscv5 = some(WakuDiscoveryV5.new( extIp = netConfig.extIp, extTcpPort = netConfig.extPort, extUdpPort = netConfig.discv5UdpPort, bindIp = netConfig.bindIp, - discv5UdpPort = netConfig.discv5UdpPort, + discv5UdpPort = netConfig.discv5UdpPort.get(), bootstrapEnrs = discv5BootstrapEnrs, enrAutoUpdate = conf.discv5EnrAutoUpdate, privateKey = keys.PrivateKey(conf.nodekey.skkey), @@ -311,6 +324,9 @@ proc initNode(conf: WakuNodeConf, rng = rng, discv5Config = discv5Config, )) + except: + return err("failed to create waku discv5 instance: " & getCurrentExceptionMsg()) + try: node = WakuNode.new(nodekey = conf.nodekey, netConfig = netConfig, rng = rng, From 89626ccf8538267f28d677820d93c7280e04038a Mon Sep 17 00:00:00 2001 From: rymnc <43716372+rymnc@users.noreply.github.com> Date: Mon, 6 Feb 2023 17:39:32 +0530 Subject: [PATCH 6/7] fix(discv5): missing arg --- waku/v2/node/waku_node.nim | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/waku/v2/node/waku_node.nim b/waku/v2/node/waku_node.nim index 98b6e98f4e..d18357064e 100644 --- a/waku/v2/node/waku_node.nim +++ b/waku/v2/node/waku_node.nim @@ -294,6 +294,8 @@ proc new*(T: type WakuNode, wakuDiscv5 = none(WakuDiscoveryV5), agentString = none(string), # defaults to nim-libp2p version peerStoreCapacity = none(int), # defaults to 1.25 maxConnections + # TODO: make this argument required after tests are updated + rng: ref HmacDrbgContext = crypto.newRng() ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError], deprecated: "Use NetConfig variant".} = let netConfig = NetConfig.init( bindIp = bindIp, @@ -328,7 +330,6 @@ proc new*(T: type WakuNode, netConfig: NetConfig, peerStorage: PeerStorage = nil, maxConnections = builders.MaxConnections, - rng = crypto.newRng(), secureKey: string = "", secureCert: string = "", nameResolver: NameResolver = nil, @@ -336,6 +337,8 @@ proc new*(T: type WakuNode, wakuDiscv5 = none(WakuDiscoveryV5), agentString = none(string), # defaults to nim-libp2p version peerStoreCapacity = none(int), # defaults to 1.25 maxConnections + # TODO: make this argument required after tests are updated + rng: ref HmacDrbgContext = crypto.newRng() ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} = ## Creates a Waku Node instance. From 032b3a3a110a793cbbe788a3b5a29a9b9fba51a1 Mon Sep 17 00:00:00 2001 From: rymnc <43716372+rymnc@users.noreply.github.com> Date: Mon, 6 Feb 2023 18:10:10 +0530 Subject: [PATCH 7/7] fix: compile error --- apps/wakunode2/wakunode2.nim | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 3299eb6518..11d54b6947 100644 --- a/apps/wakunode2/wakunode2.nim +++ b/apps/wakunode2/wakunode2.nim @@ -326,7 +326,7 @@ proc initNode(conf: WakuNodeConf, discv5UdpPort = netConfig.discv5UdpPort.get(), bootstrapEnrs = discv5BootstrapEnrs, enrAutoUpdate = conf.discv5EnrAutoUpdate, - privateKey = keys.PrivateKey(conf.nodekey.skkey), + privateKey = keys.PrivateKey(nodekey.skkey), flags = netConfig.wakuFlags.get(), multiaddrs = netConfig.enrMultiaddrs, rng = rng, @@ -335,9 +335,8 @@ proc initNode(conf: WakuNodeConf, except: return err("failed to create waku discv5 instance: " & getCurrentExceptionMsg()) try: - node = WakuNode.new(nodekey = conf.nodekey, + node = WakuNode.new(nodekey = nodekey, netConfig = netConfig, - rng = rng, peerStorage = pStorage, maxConnections = conf.maxConnections.int, secureKey = conf.websocketSecureKeyPath,