2021-11-01 18:02:39 +00:00
|
|
|
{.used.}
|
|
|
|
|
|
|
|
import
|
2023-06-19 22:16:25 +00:00
|
|
|
std/[sequtils],
|
2023-06-06 14:36:20 +00:00
|
|
|
stew/results,
|
2023-04-05 07:46:13 +00:00
|
|
|
stew/shims/net,
|
2021-11-01 18:02:39 +00:00
|
|
|
chronos,
|
|
|
|
testutils/unittests,
|
2023-06-06 14:36:20 +00:00
|
|
|
libp2p/crypto/crypto as libp2p_keys,
|
|
|
|
eth/keys as eth_keys
|
2022-11-04 09:52:08 +00:00
|
|
|
import
|
2023-04-05 07:46:13 +00:00
|
|
|
../../waku/v2/waku_node,
|
2023-06-06 14:36:20 +00:00
|
|
|
../../waku/v2/waku_enr,
|
2023-04-18 13:22:10 +00:00
|
|
|
../../waku/v2/waku_discv5,
|
2023-02-13 10:43:49 +00:00
|
|
|
./testlib/common,
|
2023-04-05 14:01:51 +00:00
|
|
|
./testlib/wakucore,
|
|
|
|
./testlib/wakunode
|
2021-11-01 18:02:39 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
|
|
|
|
proc newTestEnrRecord(privKey: libp2p_keys.PrivateKey,
|
|
|
|
extIp: string, tcpPort: uint16, udpPort: uint16,
|
|
|
|
flags = none(CapabilitiesBitfield)): waku_enr.Record =
|
|
|
|
var builder = EnrBuilder.init(privKey)
|
|
|
|
builder.withIpAddressAndPorts(
|
|
|
|
ipAddr = some(ValidIpAddress.init(extIp)),
|
|
|
|
tcpPort = some(Port(tcpPort)),
|
|
|
|
udpPort = some(Port(udpPort)),
|
|
|
|
)
|
|
|
|
|
|
|
|
if flags.isSome():
|
|
|
|
builder.withWakuCapabilities(flags.get())
|
|
|
|
|
|
|
|
builder.build().tryGet()
|
|
|
|
|
|
|
|
|
|
|
|
proc newTestDiscv5Node(privKey: libp2p_keys.PrivateKey,
|
|
|
|
bindIp: string, tcpPort: uint16, udpPort: uint16,
|
|
|
|
record: waku_enr.Record,
|
|
|
|
bootstrapRecords = newSeq[waku_enr.Record]()): WakuNode =
|
|
|
|
let config = WakuDiscoveryV5Config(
|
|
|
|
privateKey: eth_keys.PrivateKey(privKey.skkey),
|
|
|
|
address: ValidIpAddress.init(bindIp),
|
|
|
|
port: Port(udpPort),
|
|
|
|
bootstrapRecords: bootstrapRecords,
|
|
|
|
)
|
|
|
|
|
|
|
|
let protocol = WakuDiscoveryV5.new(rng(), config, some(record))
|
|
|
|
let node = newTestWakuNode(
|
|
|
|
nodeKey = privKey,
|
|
|
|
bindIp = ValidIpAddress.init(bindIp),
|
|
|
|
bindPort = Port(tcpPort),
|
|
|
|
wakuDiscv5 = some(protocol)
|
|
|
|
)
|
|
|
|
|
|
|
|
return node
|
|
|
|
|
|
|
|
|
|
|
|
|
2021-11-01 18:02:39 +00:00
|
|
|
procSuite "Waku Discovery v5":
|
2023-06-06 14:36:20 +00:00
|
|
|
asyncTest "find random peers":
|
|
|
|
## Given
|
|
|
|
# Node 1
|
2021-11-01 18:02:39 +00:00
|
|
|
let
|
2023-06-06 14:36:20 +00:00
|
|
|
privKey1 = generateSecp256k1Key()
|
|
|
|
bindIp1 = "0.0.0.0"
|
|
|
|
extIp1 = "127.0.0.1"
|
|
|
|
tcpPort1 = 61500u16
|
|
|
|
udpPort1 = 9000u16
|
|
|
|
|
|
|
|
let record1 = newTestEnrRecord(
|
|
|
|
privKey = privKey1,
|
|
|
|
extIp = extIp1,
|
|
|
|
tcpPort = tcpPort1,
|
|
|
|
udpPort = udpPort1,
|
|
|
|
)
|
|
|
|
let node1 = newTestDiscv5Node(
|
|
|
|
privKey = privKey1,
|
|
|
|
bindIp = bindIp1,
|
|
|
|
tcpPort = tcpPort1,
|
|
|
|
udpPort = udpPort1,
|
|
|
|
record = record1
|
|
|
|
)
|
|
|
|
|
|
|
|
# Node 2
|
|
|
|
let
|
|
|
|
privKey2 = generateSecp256k1Key()
|
|
|
|
bindIp2 = "0.0.0.0"
|
|
|
|
extIp2 = "127.0.0.1"
|
|
|
|
tcpPort2 = 61502u16
|
|
|
|
udpPort2 = 9002u16
|
|
|
|
|
|
|
|
let record2 = newTestEnrRecord(
|
|
|
|
privKey = privKey2,
|
|
|
|
extIp = extIp2,
|
|
|
|
tcpPort = tcpPort2,
|
|
|
|
udpPort = udpPort2,
|
|
|
|
)
|
|
|
|
|
|
|
|
let node2 = newTestDiscv5Node(
|
|
|
|
privKey = privKey2,
|
|
|
|
bindIp = bindIp2,
|
|
|
|
tcpPort = tcpPort2,
|
|
|
|
udpPort = udpPort2,
|
|
|
|
record = record2,
|
|
|
|
)
|
|
|
|
|
|
|
|
# Node 3
|
|
|
|
let
|
|
|
|
privKey3 = generateSecp256k1Key()
|
|
|
|
bindIp3 = "0.0.0.0"
|
|
|
|
extIp3 = "127.0.0.1"
|
|
|
|
tcpPort3 = 61504u16
|
|
|
|
udpPort3 = 9004u16
|
|
|
|
|
|
|
|
let record3 = newTestEnrRecord(
|
|
|
|
privKey = privKey3,
|
|
|
|
extIp = extIp3,
|
|
|
|
tcpPort = tcpPort3,
|
|
|
|
udpPort = udpPort3,
|
|
|
|
)
|
|
|
|
|
|
|
|
let node3 = newTestDiscv5Node(
|
|
|
|
privKey = privKey3,
|
|
|
|
bindIp = bindIp3,
|
|
|
|
tcpPort = tcpPort3,
|
|
|
|
udpPort = udpPort3,
|
|
|
|
record = record3,
|
|
|
|
bootstrapRecords = @[record1, record2]
|
|
|
|
)
|
|
|
|
|
|
|
|
await allFutures(node1.start(), node2.start(), node3.start())
|
|
|
|
|
|
|
|
## When
|
|
|
|
# Starting discv5 via `WakuNode.startDiscV5()` starts the discv5 background task.
|
|
|
|
await allFutures(node1.startDiscv5(), node2.startDiscv5(), node3.startDiscv5())
|
|
|
|
|
|
|
|
await sleepAsync(5.seconds) # Wait for discv5 discovery loop to run
|
|
|
|
let res = await node1.wakuDiscv5.findRandomPeers()
|
|
|
|
|
|
|
|
## Then
|
2021-11-01 18:02:39 +00:00
|
|
|
check:
|
2023-06-06 14:36:20 +00:00
|
|
|
res.len >= 1
|
|
|
|
|
|
|
|
## Cleanup
|
|
|
|
await allFutures(node1.stop(), node2.stop(), node3.stop())
|
|
|
|
|
|
|
|
asyncTest "find random peers with predicate":
|
|
|
|
## Setup
|
|
|
|
# Records
|
|
|
|
let
|
|
|
|
privKey1 = generateSecp256k1Key()
|
|
|
|
bindIp1 = "0.0.0.0"
|
|
|
|
extIp1 = "127.0.0.1"
|
|
|
|
tcpPort1 = 61500u16
|
|
|
|
udpPort1 = 9000u16
|
2023-02-07 13:06:50 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
let record1 = newTestEnrRecord(
|
|
|
|
privKey = privKey1,
|
|
|
|
extIp = extIp1,
|
|
|
|
tcpPort = tcpPort1,
|
|
|
|
udpPort = udpPort1,
|
|
|
|
flags = some(CapabilitiesBitfield.init(Capabilities.Relay))
|
|
|
|
)
|
2021-11-01 18:02:39 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
let
|
|
|
|
privKey2 = generateSecp256k1Key()
|
|
|
|
bindIp2 = "0.0.0.0"
|
|
|
|
extIp2 = "127.0.0.1"
|
|
|
|
tcpPort2 = 61502u16
|
|
|
|
udpPort2 = 9002u16
|
2021-11-01 18:02:39 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
let record2 = newTestEnrRecord(
|
|
|
|
privKey = privKey2,
|
|
|
|
extIp = extIp2,
|
|
|
|
tcpPort = tcpPort2,
|
|
|
|
udpPort = udpPort2,
|
|
|
|
flags = some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store))
|
|
|
|
)
|
2021-11-01 18:02:39 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
let
|
|
|
|
privKey3 = generateSecp256k1Key()
|
|
|
|
bindIp3 = "0.0.0.0"
|
|
|
|
extIp3 = "127.0.0.1"
|
|
|
|
tcpPort3 = 61504u16
|
|
|
|
udpPort3 = 9004u16
|
2021-11-01 18:02:39 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
let record3 = newTestEnrRecord(
|
|
|
|
privKey = privKey3,
|
|
|
|
extIp = extIp3,
|
|
|
|
tcpPort = tcpPort3,
|
|
|
|
udpPort = udpPort3,
|
|
|
|
flags = some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Filter))
|
|
|
|
)
|
2023-02-07 13:06:50 +00:00
|
|
|
|
|
|
|
let
|
2023-06-06 14:36:20 +00:00
|
|
|
privKey4 = generateSecp256k1Key()
|
|
|
|
bindIp4 = "0.0.0.0"
|
|
|
|
extIp4 = "127.0.0.1"
|
|
|
|
tcpPort4 = 61506u16
|
|
|
|
udpPort4 = 9006u16
|
|
|
|
|
|
|
|
let record4 = newTestEnrRecord(
|
|
|
|
privKey = privKey4,
|
|
|
|
extIp = extIp4,
|
|
|
|
tcpPort = tcpPort4,
|
|
|
|
udpPort = udpPort4,
|
|
|
|
flags = some(CapabilitiesBitfield.init(Capabilities.Relay, Capabilities.Store))
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
# Nodes
|
|
|
|
let node1 = newTestDiscv5Node(
|
|
|
|
privKey = privKey1,
|
|
|
|
bindIp = bindIp1,
|
|
|
|
tcpPort = tcpPort1,
|
|
|
|
udpPort = udpPort1,
|
|
|
|
record = record1,
|
|
|
|
bootstrapRecords = @[record2]
|
|
|
|
)
|
|
|
|
let node2 = newTestDiscv5Node(
|
|
|
|
privKey = privKey2,
|
|
|
|
bindIp = bindIp2,
|
|
|
|
tcpPort = tcpPort2,
|
|
|
|
udpPort = udpPort2,
|
|
|
|
record = record2,
|
|
|
|
bootstrapRecords = @[record3, record4]
|
|
|
|
)
|
|
|
|
|
|
|
|
let node3 = newTestDiscv5Node(
|
|
|
|
privKey = privKey3,
|
|
|
|
bindIp = bindIp3,
|
|
|
|
tcpPort = tcpPort3,
|
|
|
|
udpPort = udpPort3,
|
|
|
|
record = record3
|
|
|
|
)
|
|
|
|
|
|
|
|
let node4 = newTestDiscv5Node(
|
|
|
|
privKey = privKey4,
|
|
|
|
bindIp = bindIp4,
|
|
|
|
tcpPort = tcpPort4,
|
|
|
|
udpPort = udpPort4,
|
|
|
|
record = record4
|
|
|
|
)
|
|
|
|
|
|
|
|
# Start nodes' discoveryV5 protocols
|
|
|
|
require node1.wakuDiscV5.start().isOk()
|
|
|
|
require node2.wakuDiscV5.start().isOk()
|
|
|
|
require node3.wakuDiscV5.start().isOk()
|
|
|
|
require node4.wakuDiscV5.start().isOk()
|
|
|
|
|
|
|
|
await allFutures(node1.start(), node2.start(), node3.start(), node4.start())
|
|
|
|
|
|
|
|
## Given
|
|
|
|
let recordPredicate = proc(record: waku_enr.Record): bool =
|
|
|
|
let typedRecord = record.toTyped()
|
|
|
|
if typedRecord.isErr():
|
|
|
|
return false
|
|
|
|
|
|
|
|
let capabilities = typedRecord.value.waku2
|
|
|
|
if capabilities.isNone():
|
|
|
|
return false
|
|
|
|
|
|
|
|
return capabilities.get().supportsCapability(Capabilities.Store)
|
|
|
|
|
|
|
|
|
|
|
|
## When
|
|
|
|
# # Do a random peer search with a predicate multiple times
|
|
|
|
# var peers = initHashSet[waku_enr.Record]()
|
|
|
|
# for i in 0..<10:
|
|
|
|
# for peer in await node1.wakuDiscv5.findRandomPeers(pred=recordPredicate):
|
|
|
|
# peers.incl(peer)
|
|
|
|
await sleepAsync(5.seconds) # Wait for discv5 discvery loop to run
|
|
|
|
let peers = await node1.wakuDiscv5.findRandomPeers(pred=recordPredicate)
|
2023-02-07 13:06:50 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
## Then
|
2023-02-07 13:06:50 +00:00
|
|
|
check:
|
2023-06-06 14:36:20 +00:00
|
|
|
peers.len >= 1
|
|
|
|
peers.allIt(it.supportsCapability(Capabilities.Store))
|
2023-02-07 13:06:50 +00:00
|
|
|
|
2023-06-06 14:36:20 +00:00
|
|
|
# Cleanup
|
|
|
|
await allFutures(node1.stop(), node2.stop(), node3.stop(), node4.stop())
|
2023-06-19 22:16:25 +00:00
|
|
|
|
|
|
|
asyncTest "get relayShards from topics":
|
|
|
|
## Given
|
|
|
|
let mixedTopics = @["/waku/2/thisisatest", "/waku/2/rs/0/2", "/waku/2/rs/0/8"]
|
|
|
|
let shardedTopics = @["/waku/2/rs/0/2", "/waku/2/rs/0/4", "/waku/2/rs/0/8"]
|
|
|
|
let namedTopics = @["/waku/2/thisisatest", "/waku/2/atestthisis", "/waku/2/isthisatest"]
|
|
|
|
let gibberish = @["aedyttydcb/uioasduyio", "jhdfsjhlsdfjhk/sadjhk", "khfsd/hjfdsgjh/dfs"]
|
|
|
|
let empty: seq[string] = @[]
|
|
|
|
|
|
|
|
let relayShards = RelayShards.init(0, @[uint16(2), uint16(4), uint16(8)])
|
|
|
|
|
|
|
|
## When
|
|
|
|
|
|
|
|
let mixedRes = topicsToRelayShards(mixedTopics)
|
|
|
|
let shardedRes = topicsToRelayShards(shardedTopics)
|
|
|
|
let namedRes = topicsToRelayShards(namedTopics)
|
|
|
|
let gibberishRes = topicsToRelayShards(gibberish)
|
|
|
|
let emptyRes = topicsToRelayShards(empty)
|
|
|
|
|
|
|
|
## Then
|
|
|
|
assert mixedRes.isErr(), $mixedRes.value
|
|
|
|
assert shardedRes.isOk(), shardedRes.error
|
|
|
|
assert shardedRes.value.isSome()
|
|
|
|
assert shardedRes.value.get() == relayShards, $shardedRes.value.get()
|
|
|
|
assert namedRes.isOk(), namedRes.error
|
|
|
|
assert namedRes.value.isNone(), $namedRes.value
|
|
|
|
assert gibberishRes.isErr(), $gibberishRes.value
|
|
|
|
assert emptyRes.isOk(), emptyRes.error
|
|
|
|
assert emptyRes.value.isNone(), $emptyRes.value
|
|
|
|
|