Skip to content

Commit d5c3ade

Browse files
authored
feat: add new metadata protocol (#2062)
1 parent 25d6e52 commit d5c3ade

12 files changed

+408
-13
lines changed

apps/wakunode2/external_config.nim

+5
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ type
5454
name: "log-format" .}: logging.LogFormat
5555

5656
## General node config
57+
clusterId* {.
58+
desc: "Cluster id that the node is running in. Node in a different cluster id is disconnected."
59+
defaultValue: 0
60+
name: "cluster-id" }: uint32
61+
5762
agentString* {.
5863
defaultValue: "nwaku",
5964
desc: "Node agent string which is used as identifier in network"

apps/wakunode2/internal_config.nim

+6-5
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,12 @@ proc validateExtMultiAddrs*(vals: seq[string]):
2222
return ok(multiaddrs)
2323

2424
proc dnsResolve*(domain: string, conf: WakuNodeConf): Future[Result[string, string]] {.async} =
25-
25+
2626
# Use conf's DNS servers
2727
var nameServers: seq[TransportAddress]
2828
for ip in conf.dnsAddrsNameServers:
2929
nameServers.add(initTAddress(ip, Port(53))) # Assume all servers use port 53
30-
30+
3131
let dnsResolver = DnsResolver.new(nameServers)
3232

3333
# Resolve domain IP
@@ -93,18 +93,19 @@ proc networkConfiguration*(conf: WakuNodeConf,
9393
if dns4DomainName.isSome() and extIp.isNone():
9494
try:
9595
let dnsRes = waitFor dnsResolve(conf.dns4DomainName, conf)
96-
96+
9797
if dnsRes.isErr():
9898
return err($dnsRes.error) # Pass error down the stack
99-
99+
100100
extIp = some(ValidIpAddress.init(dnsRes.get()))
101101
except CatchableError:
102102
return err("Could not update extIp to resolved DNS IP: " & getCurrentExceptionMsg())
103-
103+
104104
# Wrap in none because NetConfig does not have a default constructor
105105
# TODO: We could change bindIp in NetConfig to be something less restrictive
106106
# than ValidIpAddress, which doesn't allow default construction
107107
let netConfigRes = NetConfig.init(
108+
clusterId = conf.clusterId,
108109
bindIp = conf.listenAddress,
109110
bindPort = Port(uint16(conf.tcpPort) + conf.portsShift),
110111
extIp = extIp,

tests/test_peer_manager.nim

+44
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import
2626
../../waku/waku_filter,
2727
../../waku/waku_lightpush,
2828
../../waku/waku_peer_exchange,
29+
../../waku/waku_metadata,
2930
./testlib/common,
3031
./testlib/testutils,
3132
./testlib/wakucore,
@@ -38,6 +39,8 @@ procSuite "Peer Manager":
3839
await allFutures(nodes.mapIt(it.start()))
3940

4041
let connOk = await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())
42+
await sleepAsync(chronos.milliseconds(500))
43+
4144
check:
4245
connOk == true
4346
nodes[0].peerManager.peerStore.peers().anyIt(it.peerId == nodes[1].peerInfo.peerId)
@@ -53,6 +56,8 @@ procSuite "Peer Manager":
5356

5457
# Dial node2 from node1
5558
let conn = await nodes[0].peerManager.dialPeer(nodes[1].peerInfo.toRemotePeerInfo(), WakuLegacyFilterCodec)
59+
await sleepAsync(chronos.milliseconds(500))
60+
5661
# Check connection
5762
check:
5863
conn.isSome()
@@ -145,6 +150,7 @@ procSuite "Peer Manager":
145150
let nonExistentPeer = nonExistentPeerRes.value
146151
require:
147152
(await nodes[0].peerManager.connectRelay(nonExistentPeer)) == false
153+
await sleepAsync(chronos.milliseconds(500))
148154

149155
check:
150156
# Cannot connect to node2
@@ -153,6 +159,8 @@ procSuite "Peer Manager":
153159
# Successful connection
154160
require:
155161
(await nodes[0].peerManager.connectRelay(nodes[1].peerInfo.toRemotePeerInfo())) == true
162+
await sleepAsync(chronos.milliseconds(500))
163+
156164
check:
157165
# Currently connected to node2
158166
nodes[0].peerManager.peerStore.connectedness(nodes[1].peerInfo.peerId) == Connected
@@ -229,6 +237,8 @@ procSuite "Peer Manager":
229237

230238
require:
231239
(await node1.peerManager.connectRelay(peerInfo2.toRemotePeerInfo())) == true
240+
await sleepAsync(chronos.milliseconds(500))
241+
232242
check:
233243
# Currently connected to node2
234244
node1.peerManager.peerStore.peers().len == 1
@@ -257,6 +267,36 @@ procSuite "Peer Manager":
257267

258268
await allFutures([node1.stop(), node2.stop(), node3.stop()])
259269

270+
asyncTest "Peer manager drops conections to peers on different networks":
271+
let clusterId1 = 1.uint32
272+
let clusterId2 = 2.uint32
273+
274+
let
275+
# different network
276+
node1 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), clusterId = clusterId1)
277+
278+
# same network
279+
node2 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), clusterId = clusterId2)
280+
node3 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), clusterId = clusterId2)
281+
282+
# Start nodes
283+
await allFutures([node1.start(), node2.start(), node3.start()])
284+
285+
# 1->2 (fails)
286+
let conn1 = await node1.peerManager.dialPeer(node2.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
287+
288+
# 1->3 (fails)
289+
let conn2 = await node1.peerManager.dialPeer(node3.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
290+
291+
# 2->3 (succeeds)
292+
let conn3 = await node2.peerManager.dialPeer(node3.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
293+
294+
check:
295+
conn1.isNone
296+
conn2.isNone
297+
conn3.isSome
298+
299+
260300
# TODO: nwaku/issues/1377
261301
xasyncTest "Peer manager support multiple protocol IDs when reconnecting to peers":
262302
let
@@ -370,6 +410,8 @@ procSuite "Peer Manager":
370410
(await nodes[2].peerManager.connectRelay(peerInfos[0])) == true
371411
(await nodes[3].peerManager.connectRelay(peerInfos[0])) == true
372412

413+
await sleepAsync(chronos.milliseconds(500))
414+
373415
check:
374416
# Peerstore track all three peers
375417
nodes[0].peerManager.peerStore.peers().len == 3
@@ -749,13 +791,15 @@ procSuite "Peer Manager":
749791
# 2 in connections
750792
discard await nodes[1].peerManager.connectRelay(pInfos[0])
751793
discard await nodes[2].peerManager.connectRelay(pInfos[0])
794+
await sleepAsync(chronos.milliseconds(500))
752795

753796
# but one is pruned
754797
check nodes[0].peerManager.switch.connManager.getConnections().len == 1
755798

756799
# 2 out connections
757800
discard await nodes[0].peerManager.connectRelay(pInfos[3])
758801
discard await nodes[0].peerManager.connectRelay(pInfos[4])
802+
await sleepAsync(chronos.milliseconds(500))
759803

760804
# they are also prunned
761805
check nodes[0].peerManager.switch.connManager.getConnections().len == 1

tests/test_waku_metadata.nim

+50
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
{.used.}
2+
3+
import
4+
std/[options, sequtils, tables],
5+
testutils/unittests,
6+
chronos,
7+
chronicles,
8+
stew/shims/net,
9+
libp2p/switch,
10+
libp2p/peerId,
11+
libp2p/crypto/crypto,
12+
libp2p/multistream,
13+
libp2p/muxers/muxer,
14+
eth/keys,
15+
eth/p2p/discoveryv5/enr
16+
import
17+
../../waku/waku_node,
18+
../../waku/node/peer_manager,
19+
../../waku/waku_discv5,
20+
../../waku/waku_metadata,
21+
./testlib/wakucore,
22+
./testlib/wakunode
23+
24+
25+
procSuite "Waku Metadata Protocol":
26+
27+
# TODO: Add tests with shards when ready
28+
asyncTest "request() returns the supported metadata of the peer":
29+
let clusterId = 10.uint32
30+
let
31+
node1 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), clusterId = clusterId)
32+
node2 = newTestWakuNode(generateSecp256k1Key(), ValidIpAddress.init("0.0.0.0"), Port(0), clusterId = clusterId)
33+
34+
# Start nodes
35+
await allFutures([node1.start(), node2.start()])
36+
37+
# Create connection
38+
let connOpt = await node2.peerManager.dialPeer(node1.switch.peerInfo.toRemotePeerInfo(), WakuMetadataCodec)
39+
require:
40+
connOpt.isSome
41+
42+
# Request metadata
43+
let response1 = await node2.wakuMetadata.request(connOpt.get())
44+
45+
# Check the response or dont even continue
46+
require:
47+
response1.isOk
48+
49+
check:
50+
response1.get().clusterId.get() == clusterId

tests/test_waku_protobufs.nim

+45
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
{.used.}
2+
3+
import
4+
std/[options, sequtils, tables],
5+
testutils/unittests,
6+
chronos,
7+
chronicles
8+
import
9+
../../waku/waku_metadata,
10+
../../waku/waku_metadata/rpc,
11+
./testlib/wakucore,
12+
./testlib/wakunode
13+
14+
15+
procSuite "Waku Protobufs":
16+
# TODO: Missing test coverage in many encode/decode protobuf functions
17+
18+
test "WakuMetadataResponse":
19+
let res = WakuMetadataResponse(
20+
clusterId: some(7),
21+
shards: @[10, 23, 33],
22+
)
23+
24+
let buffer = res.encode()
25+
26+
let decodedBuff = WakuMetadataResponse.decode(buffer.buffer)
27+
check:
28+
decodedBuff.isOk()
29+
decodedBuff.get().clusterId.get() == res.clusterId.get()
30+
decodedBuff.get().shards == res.shards
31+
32+
test "WakuMetadataRequest":
33+
let req = WakuMetadataRequest(
34+
clusterId: some(5),
35+
shards: @[100, 2, 0],
36+
)
37+
38+
let buffer = req.encode()
39+
40+
let decodedBuff = WakuMetadataRequest.decode(buffer.buffer)
41+
check:
42+
decodedBuff.isOk()
43+
decodedBuff.get().clusterId.get() == req.clusterId.get()
44+
decodedBuff.get().shards == req.shards
45+

tests/testlib/wakunode.nim

+6-4
Original file line numberDiff line numberDiff line change
@@ -54,20 +54,21 @@ proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
5454
dns4DomainName = none(string),
5555
discv5UdpPort = none(Port),
5656
agentString = none(string),
57+
clusterId: uint32 = 0.uint32,
5758
peerStoreCapacity = none(int)): WakuNode =
58-
59+
5960
var resolvedExtIp = extIp
6061

61-
# Update extPort to default value if it's missing and there's an extIp or a DNS domain
62+
# Update extPort to default value if it's missing and there's an extIp or a DNS domain
6263
let extPort = if (extIp.isSome() or dns4DomainName.isSome()) and
6364
extPort.isNone():
6465
some(Port(60000))
6566
else:
6667
extPort
67-
68+
6869
if dns4DomainName.isSome() and extIp.isNone():
6970
let conf = defaultTestWakuNodeConf()
70-
# If there's an error resolving the IP, an exception is thrown and test fails
71+
# If there's an error resolving the IP, an exception is thrown and test fails
7172
let dnsRes = waitFor dnsResolve(dns4DomainName.get(), conf)
7273
if dnsRes.isErr():
7374
raise newException(Defect, $dnsRes.error)
@@ -76,6 +77,7 @@ proc newTestWakuNode*(nodeKey: crypto.PrivateKey,
7677

7778
let netConfigRes = NetConfig.init(
7879
bindIp = bindIp,
80+
clusterId = clusterId,
7981
bindPort = bindPort,
8082
extIp = resolvedExtIp,
8183
extPort = extPort,

waku/node/config.nim

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ import
1616

1717
type NetConfig* = object
1818
hostAddress*: MultiAddress
19+
clusterId*: uint32
1920
wsHostAddress*: Option[MultiAddress]
2021
hostExtAddress*: Option[MultiAddress]
2122
wsExtAddress*: Option[MultiAddress]
@@ -69,6 +70,7 @@ proc init*(T: type NetConfig,
6970
wssEnabled: bool = false,
7071
dns4DomainName = none(string),
7172
discv5UdpPort = none(Port),
73+
clusterId: uint32 = 0,
7274
wakuFlags = none(CapabilitiesBitfield)): NetConfigResult =
7375
## Initialize and validate waku node network configuration
7476

@@ -137,6 +139,7 @@ proc init*(T: type NetConfig,
137139

138140
ok(NetConfig(
139141
hostAddress: hostAddress,
142+
clusterId: clusterId,
140143
wsHostAddress: wsHostAddress,
141144
hostExtAddress: hostExtAddress,
142145
wsExtAddress: wsExtAddress,

0 commit comments

Comments
 (0)