2024-03-14 17:48:09 +01:00
|
|
|
|
{.used.}
|
|
|
|
|
|
|
|
|
|
|
|
import
|
|
|
|
|
|
std/[options, sequtils],
|
|
|
|
|
|
testutils/unittests,
|
|
|
|
|
|
chronos,
|
|
|
|
|
|
chronicles,
|
|
|
|
|
|
libp2p/switch,
|
|
|
|
|
|
libp2p/peerId,
|
|
|
|
|
|
libp2p/crypto/crypto,
|
|
|
|
|
|
eth/keys,
|
2026-06-04 15:53:27 -03:00
|
|
|
|
eth/p2p/discoveryv5/enr,
|
|
|
|
|
|
brokers/broker_context
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
import
|
2026-06-08 13:37:53 +02:00
|
|
|
|
logos_delivery/waku/
|
2026-06-04 23:06:54 +02:00
|
|
|
|
[waku_node, discovery/waku_discv5, waku_peer_exchange, node/peer_manager, waku_core],
|
2024-03-14 17:48:09 +01:00
|
|
|
|
../waku_peer_exchange/utils,
|
|
|
|
|
|
../testlib/[wakucore, wakunode, testasync]
|
|
|
|
|
|
|
|
|
|
|
|
suite "Waku Peer Exchange":
|
|
|
|
|
|
let
|
|
|
|
|
|
bindIp: IPAddress = parseIpAddress("0.0.0.0")
|
|
|
|
|
|
bindPort: Port = Port(0)
|
|
|
|
|
|
|
|
|
|
|
|
var node {.threadvar.}: WakuNode
|
|
|
|
|
|
|
|
|
|
|
|
suite "mountPeerExchange":
|
|
|
|
|
|
asyncSetup:
|
|
|
|
|
|
node = newTestWakuNode(generateSecp256k1Key(), bindIp, bindPort)
|
|
|
|
|
|
|
|
|
|
|
|
asyncTest "Started node mounts peer exchange":
|
|
|
|
|
|
# Given a started node without peer exchange mounted
|
|
|
|
|
|
await node.start()
|
|
|
|
|
|
check:
|
|
|
|
|
|
node.wakuPeerExchange == nil
|
|
|
|
|
|
|
|
|
|
|
|
# When mounting peer exchange
|
|
|
|
|
|
await node.mountPeerExchange()
|
|
|
|
|
|
|
|
|
|
|
|
# Then peer exchange is mounted
|
|
|
|
|
|
check:
|
|
|
|
|
|
node.wakuPeerExchange != nil
|
|
|
|
|
|
node.wakuPeerExchange.started == true
|
|
|
|
|
|
|
|
|
|
|
|
# Cleanup
|
|
|
|
|
|
await node.stop()
|
|
|
|
|
|
|
|
|
|
|
|
asyncTest "Stopped node mounts peer exchange":
|
|
|
|
|
|
# Given a stopped node without peer exchange mounted
|
|
|
|
|
|
check:
|
|
|
|
|
|
node.wakuPeerExchange == nil
|
|
|
|
|
|
|
|
|
|
|
|
# When mounting peer exchange
|
|
|
|
|
|
await node.mountPeerExchange()
|
|
|
|
|
|
|
|
|
|
|
|
# Then peer exchange is mounted
|
|
|
|
|
|
check:
|
|
|
|
|
|
node.wakuPeerExchange != nil
|
|
|
|
|
|
node.wakuPeerExchange.started == false
|
|
|
|
|
|
|
|
|
|
|
|
suite "fetchPeerExchangePeers":
|
|
|
|
|
|
var node2 {.threadvar.}: WakuNode
|
2025-12-08 06:34:57 -03:00
|
|
|
|
var node3 {.threadvar.}: WakuNode
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncSetup:
|
|
|
|
|
|
node = newTestWakuNode(generateSecp256k1Key(), bindIp, bindPort)
|
|
|
|
|
|
node2 = newTestWakuNode(generateSecp256k1Key(), bindIp, bindPort)
|
2025-12-08 06:34:57 -03:00
|
|
|
|
node3 = newTestWakuNode(generateSecp256k1Key(), bindIp, bindPort)
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
2025-12-08 06:34:57 -03:00
|
|
|
|
await allFutures(node.start(), node2.start(), node3.start())
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncTeardown:
|
2025-12-08 06:34:57 -03:00
|
|
|
|
await allFutures(node.stop(), node2.stop(), node3.stop())
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncTest "Node fetches without mounting peer exchange":
|
|
|
|
|
|
# When a node, without peer exchange mounted, fetches peers
|
|
|
|
|
|
let res = await node.fetchPeerExchangePeers(1)
|
|
|
|
|
|
|
|
|
|
|
|
# Then no peers are fetched
|
|
|
|
|
|
check:
|
2025-04-07 12:24:03 +02:00
|
|
|
|
node.peerManager.switch.peerStore.peers.len == 0
|
2024-09-18 15:58:07 +02:00
|
|
|
|
res.error.status_code == SERVICE_UNAVAILABLE
|
2025-08-13 12:04:01 +05:30
|
|
|
|
res.error.status_desc == some("PeerExchangeClient is not mounted")
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncTest "Node fetches with mounted peer exchange, but no peers":
|
|
|
|
|
|
# Given a node with peer exchange mounted
|
2025-08-13 12:04:01 +05:30
|
|
|
|
await node.mountPeerExchangeClient()
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
# When a node fetches peers
|
|
|
|
|
|
let res = await node.fetchPeerExchangePeers(1)
|
2024-09-18 15:58:07 +02:00
|
|
|
|
check:
|
|
|
|
|
|
res.error.status_code == SERVICE_UNAVAILABLE
|
|
|
|
|
|
res.error.status_desc == some("peer_not_found_failure")
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
# Then no peers are fetched
|
2025-04-07 12:24:03 +02:00
|
|
|
|
check node.peerManager.switch.peerStore.peers.len == 0
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncTest "Node succesfully exchanges px peers with faked discv5":
|
|
|
|
|
|
# Given both nodes mount peer exchange
|
2025-08-13 12:04:01 +05:30
|
|
|
|
await allFutures([node.mountPeerExchangeClient(), node2.mountPeerExchange()])
|
2025-04-07 12:24:03 +02:00
|
|
|
|
check node.peerManager.switch.peerStore.peers.len == 0
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
2025-12-08 06:34:57 -03:00
|
|
|
|
# Simulate node2 discovering node3 via Discv5
|
|
|
|
|
|
var rpInfo = node3.peerInfo.toRemotePeerInfo()
|
|
|
|
|
|
rpInfo.enr = some(node3.enr)
|
|
|
|
|
|
node2.peerManager.addPeer(rpInfo, PeerOrigin.Discv5)
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
# Set node2 as service peer (default one) for px protocol
|
|
|
|
|
|
node.peerManager.addServicePeer(
|
|
|
|
|
|
node2.peerInfo.toRemotePeerInfo(), WakuPeerExchangeCodec
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Request 1 peer from peer exchange protocol
|
|
|
|
|
|
let res = await node.fetchPeerExchangePeers(1)
|
|
|
|
|
|
check res.tryGet() == 1
|
|
|
|
|
|
|
|
|
|
|
|
# Check that the peer ended up in the peerstore
|
|
|
|
|
|
check:
|
2025-04-07 12:24:03 +02:00
|
|
|
|
node.peerManager.switch.peerStore.peers.anyIt(it.peerId == rpInfo.peerId)
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
suite "setPeerExchangePeer":
|
|
|
|
|
|
var node2 {.threadvar.}: WakuNode
|
|
|
|
|
|
|
|
|
|
|
|
asyncSetup:
|
|
|
|
|
|
node = newTestWakuNode(generateSecp256k1Key(), bindIp, bindPort)
|
|
|
|
|
|
node2 = newTestWakuNode(generateSecp256k1Key(), bindIp, bindPort)
|
|
|
|
|
|
|
|
|
|
|
|
await allFutures(node.start(), node2.start())
|
|
|
|
|
|
|
|
|
|
|
|
asyncTeardown:
|
|
|
|
|
|
await allFutures(node.stop(), node2.stop())
|
|
|
|
|
|
|
|
|
|
|
|
asyncTest "peer set successfully":
|
|
|
|
|
|
# Given a node with peer exchange mounted
|
|
|
|
|
|
await node.mountPeerExchange()
|
2025-04-07 12:24:03 +02:00
|
|
|
|
let initialPeers = node.peerManager.switch.peerStore.peers.len
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
# And a valid peer info
|
|
|
|
|
|
let remotePeerInfo2 = node2.peerInfo.toRemotePeerInfo()
|
|
|
|
|
|
|
|
|
|
|
|
# When making a request with a valid peer info
|
|
|
|
|
|
node.setPeerExchangePeer(remotePeerInfo2)
|
|
|
|
|
|
|
|
|
|
|
|
# Then the peer is added to the peer store
|
|
|
|
|
|
check:
|
2025-04-07 12:24:03 +02:00
|
|
|
|
node.peerManager.switch.peerStore.peers.len == (initialPeers + 1)
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncTest "peer exchange not mounted":
|
|
|
|
|
|
# Given a node without peer exchange mounted
|
|
|
|
|
|
check node.wakuPeerExchange == nil
|
2025-04-07 12:24:03 +02:00
|
|
|
|
let initialPeers = node.peerManager.switch.peerStore.peers.len
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
# And a valid peer info
|
|
|
|
|
|
let invalidMultiAddress = MultiAddress.init("/ip4/0.0.0.0/tcp/0").tryGet()
|
|
|
|
|
|
|
|
|
|
|
|
# When making any request with an invalid peer info
|
|
|
|
|
|
node.setPeerExchangePeer(invalidMultiAddress)
|
|
|
|
|
|
|
|
|
|
|
|
# Then no peer is added to the peer store
|
|
|
|
|
|
check:
|
2025-04-07 12:24:03 +02:00
|
|
|
|
node.peerManager.switch.peerStore.peers.len == initialPeers
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
asyncTest "peer info parse error":
|
|
|
|
|
|
# Given a node with peer exchange mounted
|
|
|
|
|
|
await node.mountPeerExchange()
|
2025-04-07 12:24:03 +02:00
|
|
|
|
let initialPeers = node.peerManager.switch.peerStore.peers.len
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
# And given a peer info with an invalid peer id
|
|
|
|
|
|
var remotePeerInfo2 = node2.peerInfo.toRemotePeerInfo()
|
|
|
|
|
|
remotePeerInfo2.peerId.data.add(255.byte)
|
|
|
|
|
|
|
|
|
|
|
|
# When making any request with an invalid peer info
|
|
|
|
|
|
node.setPeerExchangePeer("invalidpeerinfo")
|
|
|
|
|
|
|
|
|
|
|
|
# Then no peer is added to the peer store
|
|
|
|
|
|
check:
|
2025-04-07 12:24:03 +02:00
|
|
|
|
node.peerManager.switch.peerStore.peers.len == initialPeers
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
|
|
|
|
|
suite "Waku Peer Exchange with discv5":
|
|
|
|
|
|
asyncTest "Node successfully exchanges px peers with real discv5":
|
2026-06-04 15:53:27 -03:00
|
|
|
|
lockNewGlobalBrokerContext:
|
|
|
|
|
|
## Given (copied from test_waku_discv5.nim)
|
|
|
|
|
|
let
|
|
|
|
|
|
# todo: px flag
|
|
|
|
|
|
flags = CapabilitiesBitfield.init(
|
|
|
|
|
|
lightpush = false, filter = false, store = false, relay = true
|
|
|
|
|
|
)
|
|
|
|
|
|
bindIp = parseIpAddress("0.0.0.0")
|
|
|
|
|
|
|
|
|
|
|
|
nodeKey1 = generateSecp256k1Key()
|
2026-06-30 14:59:27 -03:00
|
|
|
|
node1 = newTestWakuNode(nodeKey1, bindIp, Port(0), wakuFlags = some(flags))
|
2026-06-04 15:53:27 -03:00
|
|
|
|
|
|
|
|
|
|
nodeKey2 = generateSecp256k1Key()
|
2026-06-30 14:59:27 -03:00
|
|
|
|
node2 = newTestWakuNode(nodeKey2, bindIp, Port(0), wakuFlags = some(flags))
|
2026-06-04 15:53:27 -03:00
|
|
|
|
|
|
|
|
|
|
nodeKey3 = generateSecp256k1Key()
|
2026-06-30 14:59:27 -03:00
|
|
|
|
node3 = newTestWakuNode(nodeKey3, bindIp, Port(0), wakuFlags = some(flags))
|
2026-06-04 15:53:27 -03:00
|
|
|
|
|
|
|
|
|
|
await allFutures(node1.start(), node2.start(), node3.start())
|
2026-06-30 14:59:27 -03:00
|
|
|
|
|
|
|
|
|
|
let disc1 = (
|
|
|
|
|
|
await startDiscv5WithAutoPort(node1, keys.PrivateKey(nodeKey1.skkey), bindIp)
|
|
|
|
|
|
).valueOr:
|
|
|
|
|
|
raiseAssert "disc1: " & error
|
|
|
|
|
|
let disc2 = (
|
|
|
|
|
|
await startDiscv5WithAutoPort(
|
|
|
|
|
|
node2, keys.PrivateKey(nodeKey2.skkey), bindIp, @[disc1.protocol.getRecord()]
|
|
|
|
|
|
)
|
|
|
|
|
|
).valueOr:
|
|
|
|
|
|
raiseAssert "disc2: " & error
|
2026-06-04 15:53:27 -03:00
|
|
|
|
|
|
|
|
|
|
## When
|
|
|
|
|
|
var attempts = 10
|
|
|
|
|
|
while (disc1.protocol.nodesDiscovered < 1 or disc2.protocol.nodesDiscovered < 1) and
|
|
|
|
|
|
attempts > 0:
|
|
|
|
|
|
await sleepAsync(1.seconds)
|
|
|
|
|
|
attempts -= 1
|
|
|
|
|
|
|
|
|
|
|
|
# node2 can be connected, so will be returned by peer exchange
|
|
|
|
|
|
require (
|
|
|
|
|
|
await node1.peerManager.connectPeer(node2.switch.peerInfo.toRemotePeerInfo())
|
2024-03-16 00:08:47 +01:00
|
|
|
|
)
|
2024-03-14 17:48:09 +01:00
|
|
|
|
|
2026-06-04 15:53:27 -03:00
|
|
|
|
# Mount peer exchange
|
|
|
|
|
|
await node1.mountPeerExchange()
|
|
|
|
|
|
await node3.mountPeerExchange()
|
|
|
|
|
|
await node3.mountPeerExchangeClient()
|
|
|
|
|
|
|
|
|
|
|
|
let dialResponse =
|
|
|
|
|
|
await node3.dialForPeerExchange(node1.switch.peerInfo.toRemotePeerInfo())
|
|
|
|
|
|
|
|
|
|
|
|
check dialResponse.isOk
|
|
|
|
|
|
|
|
|
|
|
|
let
|
|
|
|
|
|
requestPeers = 1
|
|
|
|
|
|
currentPeers = node3.peerManager.switch.peerStore.peers.len
|
|
|
|
|
|
let res = await node3.fetchPeerExchangePeers(1)
|
|
|
|
|
|
check res.tryGet() == 1
|
|
|
|
|
|
|
|
|
|
|
|
# Then node3 has received 1 peer from node1
|
|
|
|
|
|
check:
|
|
|
|
|
|
node3.peerManager.switch.peerStore.peers.len == currentPeers + requestPeers
|
|
|
|
|
|
|
|
|
|
|
|
await allFutures(
|
|
|
|
|
|
[node1.stop(), node2.stop(), node3.stop(), disc1.stop(), disc2.stop()]
|
|
|
|
|
|
)
|