{.used.} import std/[sequtils, strutils], stew/byteutils, stew/shims/net as stewNet, testutils/unittests, chronicles, chronos, libp2p/crypto/crypto, libp2p/crypto/secp, libp2p/multiaddress, libp2p/switch, libp2p/protocols/pubsub/rpc/messages, libp2p/protocols/pubsub/pubsub, libp2p/protocols/pubsub/gossipsub, libp2p/nameresolving/mockresolver, eth/p2p/discoveryv5/enr import waku/[waku_core, waku_node, node/peer_manager, waku_relay, waku_peer_exchange], ./testlib/wakucore, ./testlib/wakunode suite "WakuNode": asyncTest "Protocol matcher works as expected": let nodeKey1 = generateSecp256k1Key() node1 = newTestWakuNode(nodeKey1, parseIpAddress("0.0.0.0"), Port(61000)) nodeKey2 = generateSecp256k1Key() node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"), Port(61002)) shard = DefaultRelayShard contentTopic = ContentTopic("/waku/2/default-content/proto") payload = "hello world".toBytes() message = WakuMessage(payload: payload, contentTopic: contentTopic) # Setup node 1 with stable codec "/vac/waku/relay/2.0.0" await node1.start() await node1.mountRelay(@[shard]) node1.wakuRelay.codec = "/vac/waku/relay/2.0.0" # Setup node 2 with beta codec "/vac/waku/relay/2.0.0-beta2" await node2.start() await node2.mountRelay(@[shard]) node2.wakuRelay.codec = "/vac/waku/relay/2.0.0-beta2" check: # Check that mounted codecs are actually different node1.wakuRelay.codec == "/vac/waku/relay/2.0.0" node2.wakuRelay.codec == "/vac/waku/relay/2.0.0-beta2" # Now verify that protocol matcher returns `true` and relay works await node1.connectToNodes(@[node2.switch.peerInfo.toRemotePeerInfo()]) var completionFut = newFuture[bool]() proc relayHandler( topic: PubsubTopic, msg: WakuMessage ): Future[void] {.async, gcsafe.} = check: topic == $shard msg.contentTopic == contentTopic msg.payload == payload completionFut.complete(true) node2.subscribe((kind: PubsubSub, topic: $shard), some(relayHandler)) await sleepAsync(2000.millis) var res = await node1.publish(some($shard), message) assert res.isOk(), $res.error await sleepAsync(2000.millis) check: (await completionFut.withTimeout(5.seconds)) == true await allFutures(node1.stop(), node2.stop()) asyncTest "resolve and connect to dns multiaddrs": let resolver = MockResolver.new() resolver.ipResponses[("localhost", false)] = @["127.0.0.1"] let nodeKey1 = generateSecp256k1Key() node1 = newTestWakuNode( nodeKey1, parseIpAddress("0.0.0.0"), Port(61020), nameResolver = resolver ) nodeKey2 = generateSecp256k1Key() node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"), Port(61022)) # Construct DNS multiaddr for node2 let node2PeerId = $(node2.switch.peerInfo.peerId) node2Dns4Addr = "/dns4/localhost/tcp/61022/p2p/" & node2PeerId await node1.mountRelay() await node2.mountRelay() await allFutures([node1.start(), node2.start()]) await node1.connectToNodes(@[node2Dns4Addr]) check: node1.switch.connManager.connCount(node2.switch.peerInfo.peerId) == 1 await allFutures([node1.stop(), node2.stop()]) asyncTest "Maximum connections can be configured": let maxConnections = 2 nodeKey1 = generateSecp256k1Key() node1 = newTestWakuNode( nodeKey1, parseIpAddress("0.0.0.0"), Port(60010), maxConnections = maxConnections, ) nodeKey2 = generateSecp256k1Key() node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"), Port(60012)) nodeKey3 = generateSecp256k1Key() node3 = newTestWakuNode(nodeKey3, parseIpAddress("0.0.0.0"), Port(60013)) check: # Sanity check, to verify config was applied node1.switch.connManager.inSema.size == maxConnections # Node with connection limit set to 1 await node1.start() await node1.mountRelay() # Remote node 1 await node2.start() await node2.mountRelay() # Remote node 2 await node3.start() await node3.mountRelay() discard await node1.peerManager.connectRelay(node2.switch.peerInfo.toRemotePeerInfo()) await sleepAsync(3.seconds) discard await node1.peerManager.connectRelay(node3.switch.peerInfo.toRemotePeerInfo()) check: # Verify that only the first connection succeeded node1.switch.isConnected(node2.switch.peerInfo.peerId) node1.switch.isConnected(node3.switch.peerInfo.peerId) == false await allFutures([node1.stop(), node2.stop(), node3.stop()]) asyncTest "Messages fails with wrong key path": let nodeKey1 = generateSecp256k1Key() expect ResultDefect: # gibberish discard newTestWakuNode( nodeKey1, parseIpAddress("0.0.0.0"), bindPort = Port(61004), wsBindPort = Port(8000), wssEnabled = true, secureKey = "../../waku/node/key_dummy.txt", ) asyncTest "Peer info updates with correct announced addresses": let nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(61006) extIp = some(parseIpAddress("127.0.0.1")) extPort = some(Port(61008)) node = newTestWakuNode(nodeKey, bindIp, bindPort, extIp, extPort) let bindEndpoint = MultiAddress.init(bindIp, tcpProtocol, bindPort) announcedEndpoint = MultiAddress.init(extIp.get(), tcpProtocol, extPort.get()) check: # Check that underlying peer info contains only bindIp before starting node.switch.peerInfo.listenAddrs.len == 1 node.switch.peerInfo.listenAddrs.contains(bindEndpoint) # Underlying peer info has not updated addrs before starting node.switch.peerInfo.addrs.len == 0 node.announcedAddresses.len == 1 node.announcedAddresses.contains(announcedEndpoint) await node.start() check: node.started # Underlying peer info listenAddrs has not changed node.switch.peerInfo.listenAddrs.len == 1 node.switch.peerInfo.listenAddrs.contains(bindEndpoint) # Check that underlying peer info is updated with announced address node.switch.peerInfo.addrs.len == 1 node.switch.peerInfo.addrs.contains(announcedEndpoint) await node.stop() asyncTest "Node can use dns4 in announced addresses": let nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(61010) extIp = some(parseIpAddress("127.0.0.1")) extPort = some(Port(61012)) domainName = "example.com" expectedDns4Addr = MultiAddress.init("/dns4/" & domainName & "/tcp/" & $(extPort.get())).get() node = newTestWakuNode( nodeKey, bindIp, bindPort, extIp, extPort, dns4DomainName = some(domainName) ) check: node.announcedAddresses.len == 1 node.announcedAddresses.contains(expectedDns4Addr) asyncTest "Node uses dns4 resolved ip in announced addresses if no extIp is provided": let nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(0) domainName = "status.im" node = newTestWakuNode(nodeKey, bindIp, bindPort, dns4DomainName = some(domainName)) var ipStr = "" var enrIp = node.enr.tryGet("ip", array[4, byte]) if enrIp.isSome(): ipStr &= $ipv4(enrIp.get()) # Check that the IP filled is the one received by the DNS lookup # As IPs may change, we check that it's not empty, not the 0 IP and not localhost check: ipStr.len() > 0 not ipStr.contains("0.0.0.0") not ipStr.contains("127.0.0.1") asyncTest "Node creation fails when invalid dns4 address is provided": let nodeKey = generateSecp256k1Key() bindIp = parseIpAddress("0.0.0.0") bindPort = Port(0) inexistentDomain = "thisdomain.doesnot.exist" invalidDomain = "" expectedError = "Could not resolve IP from DNS: empty response" var inexistentDomainErr, invalidDomainErr: string = "" # Create node with inexistent domain try: let node = newTestWakuNode( nodeKey, bindIp, bindPort, dns4DomainName = some(inexistentDomain) ) except Exception as e: inexistentDomainErr = e.msg # Create node with invalid domain try: let node = newTestWakuNode(nodeKey, bindIp, bindPort, dns4DomainName = some(invalidDomain)) except Exception as e: invalidDomainErr = e.msg # Check that exceptions were raised in both cases check: inexistentDomainErr == expectedError invalidDomainErr == expectedError asyncTest "Agent string is set and advertised correctly": let # custom agent string expectedAgentString1 = "node1-agent-string" # bump when updating nim-libp2p expectedAgentString2 = "nim-libp2p/0.0.1" let # node with custom agent string nodeKey1 = generateSecp256k1Key() node1 = newTestWakuNode( nodeKey1, parseIpAddress("0.0.0.0"), Port(61014), agentString = some(expectedAgentString1), ) # node with default agent string from libp2p nodeKey2 = generateSecp256k1Key() node2 = newTestWakuNode(nodeKey2, parseIpAddress("0.0.0.0"), Port(61016)) 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 node1Agent = node2.switch.peerStore[AgentBook][node1.switch.peerInfo.toRemotePeerInfo().peerId] let node2Agent = node1.switch.peerStore[AgentBook][node2.switch.peerInfo.toRemotePeerInfo().peerId] check: node1Agent == expectedAgentString1 node2Agent == expectedAgentString2 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 = generateSecp256k1Key() node1 = newTestWakuNode( nodeKey1, parseIpAddress("0.0.0.0"), Port(61018), extMultiAddrs = @[expectedMultiaddress1], ) # node with default multiaddress nodeKey2 = generateSecp256k1Key() node2 = newTestWakuNode(nodeKey2, parseIpAddress("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())