logos-delivery/tests/test_wakunode.nim

450 lines
15 KiB
Nim
Raw Normal View History

{.used.}
import
feat(mix): DoS protection + libp2p v2.0.0 + stateless RLN + tests (rebased onto #3935) Squash of 13 commits from feat/mix-dos-protection-libp2p-v2.0.0 onto the logos_delivery/ folder-restructure base from #3935 (build-messaging-folder). Original commit history (squashed): - d8e6dcef feat(mix): integrate mix protocol with extended kademlia + RLN spam protection - fb72f18d refactor(mix): split DoS-protection self-registration into background retry - d8bbef0c feat(mix): bump libp2p stack to v2.0.0 + adopt stateless RLN spam protection - 2f24448a fix(tests): use HmacDrbgContext.new() instead of crypto.newRng() - 5a21455c fix(ci): regen nimble.lock for v2.0.0 + disambiguate rng in wakucore - 03ef02a2 fix(tests): wrap HmacDrbgContext via newBearSslRng for libp2p v2.0.0 - 167ab1df fix(nix): regenerate deps.nix from updated nimble.lock - 97a27222 fix(tests): wrap or pass Rng correctly for 3-arg PrivateKey.random - 5561fcb5 fix(tests): replace removed newStandardSwitch with SwitchBuilder - ba39ee4a fix(tests): libp2p v2.0.0 API migrations across test suite - 328e11df fix: gitignore test binaries + remove accidentally-committed binary - cc712444 fix(tests): more v2.0.0 API migrations (rng template, PeerId.random, etc.) - 412d97a9 fix(tests): unblock CI — nph, excise orphan waku_noise, complete v2.0.0 Rng migration Conflict resolutions (#3935 → ours): - 11 import-path migrations: waku/X → logos_delivery/waku/X - waku_node/waku_node/relay.nim: dropped our `registerRelayHandler` proc (relocated to subscription_manager.nim by #3935; see cascade fix below) - factory/builder.nim: combined both sides' new imports (net_config + waku_switch) - factory/conf_builder/mix_conf_builder.nim: libp2p_mix package (not libp2p/protocols/mix) - waku_mix/protocol.nim: combined paths + our mix_rln_spam_protection/relay/nimchronos imports - 3 test files: dropped noise_utils import (replicates noise excision from original PR) - 2 UA file moves: option_shims.nim and waku_mix_coordination.nim added at new paths Cascade fixes (#3935 lost our work, restored): - subscription_manager.nim: added `mixHandler` to #3935's `registerRelayHandler`, and added `waku_mix` to its imports. Without this, mix messages were silently dropped from the relay handler chain. - config.nims: option_shims auto-import path migrated to logos_delivery/... Validation: - nph check on all 82 staged .nim files: clean (0 reformats needed) - wakunode2 build: exit 0, 38 MB binary - (sim PASS confirmed in earlier identical-state run: 5/5 mix init, 5 RLN proofs gen/verify, 0 errors) Backup tag at original tip: backup/3931-pre-3935-rebase (412d97a9).
2026-06-08 18:38:06 +05:30
std/[options, sequtils, strutils, net],
2022-11-04 10:52:08 +01:00
stew/byteutils,
testutils/unittests,
chronicles,
chronos,
libp2p/crypto/crypto,
libp2p/crypto/secp,
libp2p/multiaddress,
libp2p/switch,
libp2p/muxers/muxer,
libp2p/stream/connection,
libp2p/protocols/pubsub/rpc/messages,
libp2p/protocols/pubsub/pubsub,
libp2p/protocols/pubsub/gossipsub,
libp2p/nameresolving/mockresolver,
eth/p2p/discoveryv5/enr,
eth/net/utils
2022-11-04 10:52:08 +01:00
import
logos_delivery/waku/[waku_core, waku_node, node/peer_manager],
./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()).isOkOr:
assert false, "Failed to mount relay"
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()).isOkOr:
assert false, "Failed to mount relay"
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
2022-01-10 16:07:35 +01:00
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)
## The following unsubscription is necessary to remove the default relay handler, which is
## added when mountRelay is called.
node2.unsubscribe((kind: PubsubUnsub, topic: $shard)).isOkOr:
assert false, "Failed to unsubscribe from topic: " & $error
## Subscribe to the relay topic to add the custom relay handler defined above
node2.subscribe((kind: PubsubSub, topic: $shard), relayHandler).isOkOr:
assert false, "Failed to subscribe to topic"
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()).isOkOr:
assert false, "Failed to mount relay"
(await node2.mountRelay()).isOkOr:
assert false, "Failed to mount relay"
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 with 20 nodes":
let
maxConnections = 20
nodeKey1 = generateSecp256k1Key()
node1 = newTestWakuNode(
nodeKey1, parseIpAddress("127.0.0.1"), Port(0), maxConnections = maxConnections
)
# Initialize and start node1
await node1.start()
(await node1.mountRelay()).isOkOr:
assert false, "Failed to mount relay"
# Create an array to hold the other nodes
var otherNodes: seq[WakuNode] = @[]
# Create and start 20 other nodes
for _ in 0 ..< maxConnections + 1:
let
nodeKey = generateSecp256k1Key()
node = newTestWakuNode(nodeKey, parseIpAddress("127.0.0.1"), Port(0))
await node.start()
(await node.mountRelay()).isOkOr:
assert false, "Failed to mount relay"
otherNodes.add(node)
# Connect all other nodes to node1
for node in otherNodes:
discard
await node1.peerManager.connectPeer(node.switch.peerInfo.toRemotePeerInfo())
await sleepAsync(2.seconds) # Small delay to avoid hammering the connection process
# Check that the number of connections matches the maxConnections
check:
node1.switch.isConnected(otherNodes[0].switch.peerInfo.peerId)
node1.switch.isConnected(otherNodes[8].switch.peerInfo.peerId)
node1.switch.isConnected(otherNodes[14].switch.peerInfo.peerId)
node1.switch.isConnected(otherNodes[20].switch.peerInfo.peerId) == false
# Stop all nodes
var stopFutures = @[node1.stop()]
for node in otherNodes:
stopFutures.add(node.stop())
await allFutures(stopFutures)
asyncTest "Messages fails with wrong key path":
let nodeKey1 = generateSecp256k1Key()
expect ResultDefect:
Secure websocket (#759) * add config Signed-off-by: rshiv <reeshav96@gmail.com> * secure websocket integration Signed-off-by: rshiv <reeshav96@gmail.com> * secure websocket debug Signed-off-by: rshiv <reeshav96@gmail.com> * config change Signed-off-by: rshiv <reeshav96@gmail.com> * working secure websocket changes Signed-off-by: rshiv <reeshav96@gmail.com> * Update submodules (#761) * Release v0.6 (#760) * Read from path Signed-off-by: rshiv <reeshav96@gmail.com> * Tests for secure websockets Signed-off-by: rshiv <reeshav96@gmail.com> * CI failure fix Signed-off-by: rshiv <reeshav96@gmail.com> * path resolver CI Signed-off-by: rshiv <reeshav96@gmail.com> * self review fix Signed-off-by: rshiv <reeshav96@gmail.com> * Update examples/v2/config_chat2.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * review comment fix Signed-off-by: rshiv <reeshav96@gmail.com> * review comment fix Signed-off-by: rshiv <reeshav96@gmail.com> * Update waku/v2/utils/peers.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * Update waku/v2/node/wakunode2.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * review comment fix Signed-off-by: rshiv <reeshav96@gmail.com> * Update tests/v2/test_wakunode.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * handle review comments Signed-off-by: rshiv <reeshav96@gmail.com> Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com>
2021-11-10 12:05:36 +00:00
# gibberish
discard newTestWakuNode(
nodeKey1,
parseIpAddress("0.0.0.0"),
bindPort = Port(61004),
wsBindPort = Port(8000),
wssEnabled = true,
secureKey = "../../waku/node/key_dummy.txt",
)
Secure websocket (#759) * add config Signed-off-by: rshiv <reeshav96@gmail.com> * secure websocket integration Signed-off-by: rshiv <reeshav96@gmail.com> * secure websocket debug Signed-off-by: rshiv <reeshav96@gmail.com> * config change Signed-off-by: rshiv <reeshav96@gmail.com> * working secure websocket changes Signed-off-by: rshiv <reeshav96@gmail.com> * Update submodules (#761) * Release v0.6 (#760) * Read from path Signed-off-by: rshiv <reeshav96@gmail.com> * Tests for secure websockets Signed-off-by: rshiv <reeshav96@gmail.com> * CI failure fix Signed-off-by: rshiv <reeshav96@gmail.com> * path resolver CI Signed-off-by: rshiv <reeshav96@gmail.com> * self review fix Signed-off-by: rshiv <reeshav96@gmail.com> * Update examples/v2/config_chat2.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * review comment fix Signed-off-by: rshiv <reeshav96@gmail.com> * review comment fix Signed-off-by: rshiv <reeshav96@gmail.com> * Update waku/v2/utils/peers.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * Update waku/v2/node/wakunode2.nim Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> * review comment fix Signed-off-by: rshiv <reeshav96@gmail.com> * Update tests/v2/test_wakunode.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * Update waku/v2/utils/wakuswitch.nim Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com> * handle review comments Signed-off-by: rshiv <reeshav96@gmail.com> Co-authored-by: Hanno Cornelius <68783915+jm-clius@users.noreply.github.com> Co-authored-by: Sanaz Taheri Boshrooyeh <35961250+staheri14@users.noreply.github.com>
2021-11-10 12:05:36 +00:00
asyncTest "Peer info updates with correct announced addresses":
let
nodeKey = generateSecp256k1Key()
bindIp = parseIpAddress("0.0.0.0")
bindPort = Port(61006)
extIp = some(getPrimaryIPAddr())
extPort = some(Port(61008))
# tcp-only: asserts exact single listen addr; quic variant below
node =
newTestWakuNode(nodeKey, bindIp, bindPort, extIp, extPort, quicEnabled = false)
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 "Peer info updates with correct announced addresses (QUIC)":
# dual-stack node announces both tcp and quic-v1
let
nodeKey = generateSecp256k1Key()
bindIp = parseIpAddress("0.0.0.0")
bindPort = Port(61006)
extIp = some(getPrimaryIPAddr())
extPort = some(Port(61008))
node =
newTestWakuNode(nodeKey, bindIp, bindPort, extIp, extPort, quicEnabled = true)
let tcpAnnounced = MultiAddress.init(extIp.get(), tcpProtocol, extPort.get())
check:
node.announcedAddresses.len >= 2
node.announcedAddresses.contains(tcpAnnounced)
node.announcedAddresses.anyIt("/quic-v1" in $it)
await node.start()
check:
node.started
node.switch.peerInfo.addrs.len >= 2
node.switch.peerInfo.addrs.contains(tcpAnnounced)
node.switch.peerInfo.addrs.anyIt("/quic-v1" in $it)
await node.stop()
test "toRemotePeerInfo sorts quic-v1 addresses first":
let
nodeKey = generateSecp256k1Key()
node =
newTestWakuNode(nodeKey, parseIpAddress("0.0.0.0"), Port(0), quicEnabled = true)
# peerinfo path
let fromPeerInfo = node.switch.peerInfo.toRemotePeerInfo()
check:
fromPeerInfo.addrs.anyIt("/quic-v1" in $it)
"/quic-v1" in $fromPeerInfo.addrs[0]
# enr path
let fromEnr = toRemotePeerInfo(node.enr).valueOr:
raiseAssert "toRemotePeerInfo(enr) failed: " & $error
check:
fromEnr.addrs.anyIt("/quic-v1" in $it)
"/quic-v1" in $fromEnr.addrs[0]
asyncTest "Dual-stack nodes connect over QUIC":
let
nodeKey1 = generateSecp256k1Key()
node1 = newTestWakuNode(
nodeKey1, parseIpAddress("0.0.0.0"), Port(0), quicEnabled = true
)
nodeKey2 = generateSecp256k1Key()
node2 = newTestWakuNode(
nodeKey2, parseIpAddress("0.0.0.0"), Port(0), quicEnabled = true
)
await allFutures(node1.start(), node2.start())
await node1.connectToNodes(@[node2.switch.peerInfo.toRemotePeerInfo()])
let conns = node1.switch.connManager.getConnections().getOrDefault(
node2.switch.peerInfo.peerId
)
check conns.len >= 1
let obAddr = conns[0].connection.observedAddr.valueOr:
raiseAssert "connection has no observed address"
check:
"/udp/" in $obAddr
"/tcp/" notin $obAddr
await allFutures(node1.stop(), node2.stop())
asyncTest "Node can use dns4 in announced addresses":
let
nodeKey = generateSecp256k1Key()
bindIp = parseIpAddress("0.0.0.0")
bindPort = Port(61010)
extIp = some(getPrimaryIPAddr())
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:
# dual-stack also adds a dns4 quic addr, don't assert exact count
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()).isOkOr:
assert false, "Failed to mount relay"
await node2.start()
(await node2.mountRelay()).isOkOr:
assert false, "Failed to mount relay"
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()).isOkOr:
assert false, "Failed to mount relay"
await node2.start()
(await node2.mountRelay()).isOkOr:
assert false, "Failed to mount relay"
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())