nwaku/tests/test_wakunode.nim

359 lines
11 KiB
Nim
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{.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/waku_node,
../../waku/node/peer_manager,
../../waku/waku_relay,
../../waku/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))
pubSubTopic = "/waku/2/default-waku/proto"
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(@[pubSubTopic])
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(@[pubSubTopic])
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 == pubSubTopic
msg.contentTopic == contentTopic
msg.payload == payload
completionFut.complete(true)
node2.subscribe((kind: PubsubSub, topic: pubsubTopic), some(relayHandler))
await sleepAsync(2000.millis)
var res = await node1.publish(some(pubSubTopic), 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())