Skip to content

Commit b0cd75f

Browse files
feat: update rendezvous to broadcast and discover WakuPeerRecords (#3617)
* update rendezvous to work with WakuPeeRecord and use libp2p updated version * split rendezvous client and service implementation * mount rendezvous client by default
1 parent 31e1a81 commit b0cd75f

File tree

23 files changed

+565
-290
lines changed

23 files changed

+565
-290
lines changed

Dockerfile.lightpushWithMix.compile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# BUILD NIM APP ----------------------------------------------------------------
2-
FROM rust:1.81.0-alpine3.19 AS nim-build
2+
FROM rustlang/rust:nightly-alpine3.19 AS nim-build
33

44
ARG NIMFLAGS
55
ARG MAKE_TARGET=lightpushwithmix

apps/chat2mix/chat2mix.nim

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ proc encode*(message: Chat2Message): ProtoBuffer =
124124

125125
return serialised
126126

127-
proc toString*(message: Chat2Message): string =
127+
proc `$`*(message: Chat2Message): string =
128128
# Get message date and timestamp in local time
129129
let time = message.timestamp.fromUnix().local().format("'<'MMM' 'dd,' 'HH:mm'>'")
130130

@@ -331,13 +331,14 @@ proc maintainSubscription(
331331
const maxFailedServiceNodeSwitches = 10
332332
var noFailedSubscribes = 0
333333
var noFailedServiceNodeSwitches = 0
334-
const RetryWaitMs = 2.seconds # Quick retry interval
335-
const SubscriptionMaintenanceMs = 30.seconds # Subscription maintenance interval
334+
# Use chronos.Duration explicitly to avoid mismatch with std/times.Duration
335+
let RetryWait = chronos.seconds(2) # Quick retry interval
336+
let SubscriptionMaintenance = chronos.seconds(30) # Subscription maintenance interval
336337
while true:
337338
info "maintaining subscription at", peer = constructMultiaddrStr(actualFilterPeer)
338339
# First use filter-ping to check if we have an active subscription
339340
let pingErr = (await wakuNode.wakuFilterClient.ping(actualFilterPeer)).errorOr:
340-
await sleepAsync(SubscriptionMaintenanceMs)
341+
await sleepAsync(SubscriptionMaintenance)
341342
info "subscription is live."
342343
continue
343344

@@ -350,7 +351,7 @@ proc maintainSubscription(
350351
some(filterPubsubTopic), filterContentTopic, actualFilterPeer
351352
)
352353
).errorOr:
353-
await sleepAsync(SubscriptionMaintenanceMs)
354+
await sleepAsync(SubscriptionMaintenance)
354355
if noFailedSubscribes > 0:
355356
noFailedSubscribes -= 1
356357
notice "subscribe request successful."
@@ -365,7 +366,7 @@ proc maintainSubscription(
365366
# wakunode.peerManager.peerStore.delete(actualFilterPeer)
366367

367368
if noFailedSubscribes < maxFailedSubscribes:
368-
await sleepAsync(RetryWaitMs) # Wait a bit before retrying
369+
await sleepAsync(RetryWait) # Wait a bit before retrying
369370
elif not preventPeerSwitch:
370371
# try again with new peer without delay
371372
let actualFilterPeer = selectRandomServicePeer(
@@ -380,7 +381,7 @@ proc maintainSubscription(
380381

381382
noFailedSubscribes = 0
382383
else:
383-
await sleepAsync(SubscriptionMaintenanceMs)
384+
await sleepAsync(SubscriptionMaintenance)
384385

385386
{.pop.}
386387
# @TODO confutils.nim(775, 17) Error: can raise an unlisted exception: ref IOError
@@ -450,6 +451,8 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
450451
(await node.mountMix(conf.clusterId, mixPrivKey, conf.mixnodes)).isOkOr:
451452
error "failed to mount waku mix protocol: ", error = $error
452453
quit(QuitFailure)
454+
await node.mountRendezvousClient(conf.clusterId)
455+
453456
await node.start()
454457

455458
node.peerManager.start()
@@ -587,7 +590,6 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} =
587590
error "Couldn't find any service peer"
588591
quit(QuitFailure)
589592

590-
#await mountLegacyLightPush(node)
591593
node.peerManager.addServicePeer(servicePeerInfo, WakuLightpushCodec)
592594
node.peerManager.addServicePeer(servicePeerInfo, WakuPeerExchangeCodec)
593595

examples/lightpush_mix/lightpush_publisher_mix.nim

Lines changed: 32 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ proc splitPeerIdAndAddr(maddr: string): (string, string) =
5151
proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.} =
5252
# use notice to filter all waku messaging
5353
setupLog(logging.LogLevel.DEBUG, logging.LogFormat.TEXT)
54-
5554
notice "starting publisher", wakuPort = conf.port
5655

5756
let
@@ -114,17 +113,8 @@ proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.}
114113
let dPeerId = PeerId.init(destPeerId).valueOr:
115114
error "Failed to initialize PeerId", error = error
116115
return
117-
var conn: Connection
118-
if not conf.mixDisabled:
119-
conn = node.wakuMix.toConnection(
120-
MixDestination.init(dPeerId, pxPeerInfo.addrs[0]), # destination lightpush peer
121-
WakuLightPushCodec, # protocol codec which will be used over the mix connection
122-
MixParameters(expectReply: Opt.some(true), numSurbs: Opt.some(byte(1))),
123-
# mix parameters indicating we expect a single reply
124-
).valueOr:
125-
error "failed to create mix connection", error = error
126-
return
127116

117+
await node.mountRendezvousClient(clusterId)
128118
await node.start()
129119
node.peerManager.start()
130120
node.startPeerExchangeLoop()
@@ -145,20 +135,26 @@ proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.}
145135

146136
var i = 0
147137
while i < conf.numMsgs:
138+
var conn: Connection
148139
if conf.mixDisabled:
149140
let connOpt = await node.peerManager.dialPeer(dPeerId, WakuLightPushCodec)
150141
if connOpt.isNone():
151142
error "failed to dial peer with WakuLightPushCodec", target_peer_id = dPeerId
152143
return
153144
conn = connOpt.get()
145+
else:
146+
conn = node.wakuMix.toConnection(
147+
MixDestination.init(dPeerId, pxPeerInfo.addrs[0]), # destination lightpush peer
148+
WakuLightPushCodec, # protocol codec which will be used over the mix connection
149+
MixParameters(expectReply: Opt.some(true), numSurbs: Opt.some(byte(1))),
150+
# mix parameters indicating we expect a single reply
151+
).valueOr:
152+
error "failed to create mix connection", error = error
153+
return
154154
i = i + 1
155155
let text =
156156
"""Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam venenatis magna ut tortor faucibus, in vestibulum nibh commodo. Aenean eget vestibulum augue. Nullam suscipit urna non nunc efficitur, at iaculis nisl consequat. Mauris quis ultrices elit. Suspendisse lobortis odio vitae laoreet facilisis. Cras ornare sem felis, at vulputate magna aliquam ac. Duis quis est ultricies, euismod nulla ac, interdum dui. Maecenas sit amet est vitae enim commodo gravida. Proin vitae elit nulla. Donec tempor dolor lectus, in faucibus velit elementum quis. Donec non mauris eu nibh faucibus cursus ut egestas dolor. Aliquam venenatis ligula id velit pulvinar malesuada. Vestibulum scelerisque, justo non porta gravida, nulla justo tempor purus, at sollicitudin erat erat vel libero.
157-
Fusce nec eros eu metus tristique aliquet. Sed ut magna sagittis, vulputate diam sit amet, aliquam magna. Aenean sollicitudin velit lacus, eu ultrices magna semper at. Integer vitae felis ligula. In a eros nec risus condimentum tincidunt fermentum sit amet ex. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Nullam vitae justo maximus, fringilla tellus nec, rutrum purus. Etiam efficitur nisi dapibus euismod vestibulum. Phasellus at felis elementum, tristique nulla ac, consectetur neque.
158-
Maecenas hendrerit nibh eget velit rutrum, in ornare mauris molestie. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia curae; Praesent dignissim efficitur eros, sit amet rutrum justo mattis a. Fusce mollis neque at erat placerat bibendum. Ut fringilla fringilla orci, ut fringilla metus fermentum vel. In hac habitasse platea dictumst. Donec hendrerit porttitor odio. Suspendisse ornare sollicitudin mauris, sodales pulvinar velit finibus vel. Fusce id pulvinar neque. Suspendisse eget tincidunt sapien, ac accumsan turpis.
159-
Curabitur cursus tincidunt leo at aliquet. Nunc dapibus quam id venenatis varius. Aenean eget augue vel velit dapibus aliquam. Nulla facilisi. Curabitur cursus, turpis vel congue volutpat, tellus eros cursus lacus, eu fringilla turpis orci non ipsum. In hac habitasse platea dictumst. Nulla aliquam nisl a nunc placerat, eget dignissim felis pulvinar. Fusce sed porta mauris. Donec sodales arcu in nisl sodales, quis posuere massa ultricies. Nam feugiat massa eget felis ultricies finibus. Nunc magna nulla, interdum a elit vel, egestas efficitur urna. Ut posuere tincidunt odio in maximus. Sed at dignissim est.
160-
Morbi accumsan elementum ligula ut fringilla. Praesent in ex metus. Phasellus urna est, tempus sit amet elementum vitae, sollicitudin vel ipsum. Fusce hendrerit eleifend dignissim. Maecenas tempor dapibus dui quis laoreet. Cras tincidunt sed ipsum sed pellentesque. Proin ut tellus nec ipsum varius interdum. Curabitur id velit ligula. Etiam sapien nulla, cursus sodales orci eu, porta lobortis nunc. Nunc at dapibus velit. Nulla et nunc vehicula, condimentum erat quis, elementum dolor. Quisque eu metus fermentum, vestibulum tellus at, sollicitudin odio. Ut vel neque justo.
161-
Praesent porta porta velit, vel porttitor sem. Donec sagittis at nulla venenatis iaculis. Nullam vel eleifend felis. Nullam a pellentesque lectus. Aliquam tincidunt semper dui sed bibendum. Donec hendrerit, urna et cursus dictum, neque neque convallis magna, id condimentum sem urna quis massa. Fusce non quam vulputate, fermentum mauris at, malesuada ipsum. Mauris id pellentesque libero. Donec vel erat ullamcorper, dapibus quam id, imperdiet urna. Praesent sed ligula ut est pellentesque pharetra quis et diam. Ut placerat lorem eget mi fermentum aliquet.
157+
Fusce nec eros eu metus tristique aliquet.
162158
This is message #""" &
163159
$i & """ sent from a publisher using mix. End of transmission."""
164160
let message = WakuMessage(
@@ -168,25 +164,31 @@ proc setupAndPublish(rng: ref HmacDrbgContext, conf: LightPushMixConf) {.async.}
168164
timestamp: getNowInNanosecondTime(),
169165
) # current timestamp
170166

171-
let res = await node.wakuLightpushClient.publishWithConn(
172-
LightpushPubsubTopic, message, conn, dPeerId
173-
)
174-
175-
if res.isOk():
176-
lp_mix_success.inc()
177-
notice "published message",
178-
text = text,
179-
timestamp = message.timestamp,
180-
psTopic = LightpushPubsubTopic,
181-
contentTopic = LightpushContentTopic
182-
else:
183-
error "failed to publish message", error = $res.error
167+
let startTime = getNowInNanosecondTime()
168+
169+
(
170+
await node.wakuLightpushClient.publishWithConn(
171+
LightpushPubsubTopic, message, conn, dPeerId
172+
)
173+
).isOkOr:
174+
error "failed to publish message via mix", error = error.desc
184175
lp_mix_failed.inc(labelValues = ["publish_error"])
176+
return
177+
178+
let latency = float64(getNowInNanosecondTime() - startTime) / 1_000_000.0
179+
lp_mix_latency.observe(latency)
180+
lp_mix_success.inc()
181+
notice "published message",
182+
text = text,
183+
timestamp = message.timestamp,
184+
latency = latency,
185+
psTopic = LightpushPubsubTopic,
186+
contentTopic = LightpushContentTopic
185187

186188
if conf.mixDisabled:
187189
await conn.close()
188190
await sleepAsync(conf.msgIntervalMilliseconds)
189-
info "###########Sent all messages via mix"
191+
info "Sent all messages via mix"
190192
quit(0)
191193

192194
when isMainModule:

examples/lightpush_mix/lightpush_publisher_mix_metrics.nim

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,6 @@ declarePublicCounter lp_mix_success, "number of lightpush messages sent via mix"
66

77
declarePublicCounter lp_mix_failed,
88
"number of lightpush messages failed via mix", labels = ["error"]
9+
10+
declarePublicHistogram lp_mix_latency,
11+
"lightpush publish latency via mix in milliseconds"

simulations/mixnet/run_chat_mix.sh

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
../../build/chat2mix --cluster-id=2 --num-shards-in-network=1 --shard=0 --servicenode="/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o" --log-level=TRACE --mixnode="/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF:9231e86da6432502900a84f867004ce78632ab52cd8e30b1ec322cd795710c2a" --mixnode="/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA:275cd6889e1f29ca48e5b9edb800d1a94f49f13d393a0ecf1a07af753506de6c" --mixnode="/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f:e0ed594a8d506681be075e8e23723478388fb182477f7a469309a25e7076fc18" --mixnode="/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu:8fd7a1a7c19b403d231452a9b1ea40eb1cc76f455d918ef8980e7685f9eeeb1f"
1+
../../build/chat2mix --cluster-id=2 --num-shards-in-network=1 --shard=0 --servicenode="/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o" --log-level=TRACE
2+
#--mixnode="/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF:9231e86da6432502900a84f867004ce78632ab52cd8e30b1ec322cd795710c2a" --mixnode="/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA:275cd6889e1f29ca48e5b9edb800d1a94f49f13d393a0ecf1a07af753506de6c" --mixnode="/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f:e0ed594a8d506681be075e8e23723478388fb182477f7a469309a25e7076fc18" --mixnode="/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu:8fd7a1a7c19b403d231452a9b1ea40eb1cc76f455d918ef8980e7685f9eeeb1f"
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1-
../../build/chat2mix --cluster-id=2 --num-shards-in-network=1 --shard=0 --servicenode="/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o" --log-level=TRACE --mixnode="/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF:9231e86da6432502900a84f867004ce78632ab52cd8e30b1ec322cd795710c2a" --mixnode="/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA:275cd6889e1f29ca48e5b9edb800d1a94f49f13d393a0ecf1a07af753506de6c" --mixnode="/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f:e0ed594a8d506681be075e8e23723478388fb182477f7a469309a25e7076fc18" --mixnode="/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu:8fd7a1a7c19b403d231452a9b1ea40eb1cc76f455d918ef8980e7685f9eeeb1f"
1+
../../build/chat2mix --cluster-id=2 --num-shards-in-network=1 --shard=0 --servicenode="/ip4/127.0.0.1/tcp/60001/p2p/16Uiu2HAmPiEs2ozjjJF2iN2Pe2FYeMC9w4caRHKYdLdAfjgbWM6o" --log-level=TRACE
2+
#--mixnode="/ip4/127.0.0.1/tcp/60002/p2p/16Uiu2HAmLtKaFaSWDohToWhWUZFLtqzYZGPFuXwKrojFVF6az5UF:9231e86da6432502900a84f867004ce78632ab52cd8e30b1ec322cd795710c2a" --mixnode="/ip4/127.0.0.1/tcp/60003/p2p/16Uiu2HAmTEDHwAziWUSz6ZE23h5vxG2o4Nn7GazhMor4bVuMXTrA:275cd6889e1f29ca48e5b9edb800d1a94f49f13d393a0ecf1a07af753506de6c" --mixnode="/ip4/127.0.0.1/tcp/60004/p2p/16Uiu2HAmPwRKZajXtfb1Qsv45VVfRZgK3ENdfmnqzSrVm3BczF6f:e0ed594a8d506681be075e8e23723478388fb182477f7a469309a25e7076fc18" --mixnode="/ip4/127.0.0.1/tcp/60005/p2p/16Uiu2HAmRhxmCHBYdXt1RibXrjAUNJbduAhzaTHwFCZT4qWnqZAu:8fd7a1a7c19b403d231452a9b1ea40eb1cc76f455d918ef8980e7685f9eeeb1f"

tests/test_waku_rendezvous.nim

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,20 @@
11
{.used.}
22

3-
import std/options, chronos, testutils/unittests, libp2p/builders
3+
import
4+
std/options,
5+
chronos,
6+
testutils/unittests,
7+
libp2p/builders,
8+
libp2p/protocols/rendezvous
49

510
import
611
waku/waku_core/peers,
12+
waku/waku_core/codecs,
713
waku/node/waku_node,
814
waku/node/peer_manager/peer_manager,
915
waku/waku_rendezvous/protocol,
16+
waku/waku_rendezvous/common,
17+
waku/waku_rendezvous/waku_peer_record,
1018
./testlib/[wakucore, wakunode]
1119

1220
procSuite "Waku Rendezvous":
@@ -50,18 +58,26 @@ procSuite "Waku Rendezvous":
5058
node2.peerManager.addPeer(peerInfo3)
5159
node3.peerManager.addPeer(peerInfo2)
5260

53-
let namespace = "test/name/space"
54-
55-
let res = await node1.wakuRendezvous.batchAdvertise(
56-
namespace, 60.seconds, @[peerInfo2.peerId]
57-
)
61+
let res = await node1.wakuRendezvous.advertiseAll()
5862
assert res.isOk(), $res.error
63+
# Rendezvous Request API requires dialing first
64+
let connOpt =
65+
await node3.peerManager.dialPeer(peerInfo2.peerId, WakuRendezVousCodec)
66+
require:
67+
connOpt.isSome
5968

60-
let response =
61-
await node3.wakuRendezvous.batchRequest(namespace, 1, @[peerInfo2.peerId])
62-
assert response.isOk(), $response.error
63-
let records = response.get()
69+
var records: seq[WakuPeerRecord]
70+
try:
71+
records = await rendezvous.request[WakuPeerRecord](
72+
node3.wakuRendezvous,
73+
Opt.some(computeMixNamespace(clusterId)),
74+
Opt.some(1),
75+
Opt.some(@[peerInfo2.peerId]),
76+
)
77+
except CatchableError as e:
78+
assert false, "Request failed with exception: " & e.msg
6479

6580
check:
6681
records.len == 1
6782
records[0].peerId == peerInfo1.peerId
83+
#records[0].mixPubKey == $node1.wakuMix.pubKey

tests/waku_discv5/test_waku_discv5.nim

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ suite "Waku Discovery v5":
426426
confBuilder.withNodeKey(libp2p_keys.PrivateKey.random(Secp256k1, myRng[])[])
427427
confBuilder.discv5Conf.withEnabled(true)
428428
confBuilder.discv5Conf.withUdpPort(9000.Port)
429-
430429
let conf = confBuilder.build().valueOr:
431430
raiseAssert error
432431

@@ -468,6 +467,9 @@ suite "Waku Discovery v5":
468467
# leave some time for discv5 to act
469468
await sleepAsync(chronos.seconds(10))
470469

470+
# Connect peers via peer manager to ensure identify happens
471+
discard await waku0.node.peerManager.connectPeer(waku1.node.switch.peerInfo)
472+
471473
var r = waku0.node.peerManager.selectPeer(WakuPeerExchangeCodec)
472474
assert r.isSome(), "could not retrieve peer mounting WakuPeerExchangeCodec"
473475

@@ -480,7 +482,7 @@ suite "Waku Discovery v5":
480482
r = waku2.node.peerManager.selectPeer(WakuPeerExchangeCodec)
481483
assert r.isSome(), "could not retrieve peer mounting WakuPeerExchangeCodec"
482484

483-
r = waku2.node.peerManager.selectPeer(RendezVousCodec)
485+
r = waku2.node.peerManager.selectPeer(WakuRendezVousCodec)
484486
assert r.isSome(), "could not retrieve peer mounting RendezVousCodec"
485487

486488
asyncTest "Discv5 bootstrap nodes should be added to the peer store":

waku.nimble

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ requires "nim >= 2.2.4",
2424
"stew",
2525
"stint",
2626
"metrics",
27-
"libp2p >= 1.14.2",
27+
"libp2p >= 1.14.3",
2828
"web3",
2929
"presto",
3030
"regex",

0 commit comments

Comments
 (0)