diff --git a/apps/wakunode2/wakunode2.nim b/apps/wakunode2/wakunode2.nim index 793ea99817..47392b5780 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), - 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, 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 841d87854a..160793d6f1 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 nim-libp2p max size - ): 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 nim-libp2p max size + ): 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..