Skip to content

Commit 3f0f14c

Browse files
committed
feat(mix): adaptive service-peer discovery top-up via broker
Add a generic runServicePeerTopUp loop in waku_node that, while a service's provider count is below target, pulls more peers through the ServicePeersRequest broker; wired for mix in WakuNode.start(). Move the ServicePeersRequest provider registration into the startProvidersAndListeners/stopProvidersAndListeners lifecycle (gated on kademlia) so chat2mix gets it too, keeping WakuKademlia generic. Also fix pre-existing chat2mix build errors (toHashSet, valueOr, std/sets import).
1 parent 0f3eb30 commit 3f0f14c

4 files changed

Lines changed: 56 additions & 15 deletions

File tree

apps/chat2mix/chat2mix.nim

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ when not (compileOption("threads")):
66

77
{.push raises: [].}
88

9-
import std/[strformat, strutils, times, options, random, sequtils]
9+
import std/[strformat, strutils, times, options, random, sequtils, sets]
1010
import
1111
confutils,
1212
chronicles,
@@ -563,7 +563,7 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} =
563563
var kadBootstrapPeers: seq[(PeerId, seq[MultiAddress])]
564564
for nodeStr in conf.kadBootstrapNodes:
565565
let (peerId, ma) = block:
566-
parseFullAddress(nodeStr).isOkOr:
566+
parseFullAddress(nodeStr).valueOr:
567567
error "Failed to parse kademlia bootstrap node", node = nodeStr, error
568568
continue
569569

@@ -573,7 +573,7 @@ proc processInput(rfd: AsyncFD, rng: crypto.Rng) {.async.} =
573573
node.mountKademlia(
574574
KademliaDiscoveryConf(
575575
bootstrapNodes: kadBootstrapPeers,
576-
servicesToDiscover: @[MixProtocolID],
576+
servicesToDiscover: toHashSet(@[MixProtocolID]),
577577
randomLookupInterval: chronos.seconds(60),
578578
serviceLookupInterval: chronos.seconds(60),
579579
kadDhtConfig: KadDHTConfig.new(),

logos_delivery/waku/factory/node_factory.nim

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -183,17 +183,6 @@ proc setupProtocols(
183183
node.mountKademlia(kadConf).isOkOr:
184184
return err("failed to setup service discovery: " & error)
185185

186-
# Register ServicePeersRequest provider
187-
ServicePeersRequest.setProvider(
188-
node.brokerCtx,
189-
proc(serviceId: string): Future[Result[ServicePeersRequest, string]] {.async.} =
190-
let peers = (await node.wakuKademlia.lookupServicePeers(serviceId)).valueOr:
191-
return err("failed call to lookupServicePeers: " & error)
192-
return ok(ServicePeersRequest(serviceId: serviceId, peers: peers)),
193-
).isOkOr:
194-
error "Can't set provider for ServicePeersRequest", error = error
195-
return err("Can't set provider for ServicePeersRequest: " & error)
196-
197186
if conf.storeServiceConf.isSome():
198187
let storeServiceConf = conf.storeServiceConf.get()
199188

logos_delivery/waku/node/waku_node.nim

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@ import
6262
events/health_events,
6363
events/message_events,
6464
events/peer_events,
65+
events/discovery_events,
6566
],
6667
logos_delivery/waku/discovery/waku_kademlia,
6768
logos_delivery/waku/net/[bound_ports, net_config],
@@ -123,6 +124,7 @@ type
123124
libp2pPing*: Ping
124125
rng*: crypto.Rng
125126
brokerCtx*: BrokerContext
127+
mixTopUpLoop: Future[void]
126128
wakuRendezvous*: WakuRendezVous
127129
wakuRendezvousClient*: rendezvous_client.WakuRendezVousClient
128130
announcedAddresses*: seq[MultiAddress]
@@ -394,6 +396,26 @@ proc mountKademlia*(
394396

395397
return ok()
396398

399+
proc runServicePeerTopUp(
400+
node: WakuNode,
401+
serviceId: string,
402+
target: int,
403+
currentCount: proc(): int {.gcsafe, raises: [].},
404+
interval: Duration,
405+
) {.async.} =
406+
## Adaptive service-peer discovery: while the number of usable providers for
407+
## `serviceId` is below `target`, pull more through the broker. The registered
408+
## ServicePeersRequest provider (kademlia) performs the lookup and fills the
409+
## pool. Generic — the caller supplies the service id, target and count getter.
410+
debug "service peer top-up loop started", serviceId, target, interval = $interval
411+
while true:
412+
await sleepAsync(interval)
413+
if currentCount() >= target:
414+
continue
415+
let res = await ServicePeersRequest.request(node.brokerCtx, serviceId)
416+
if res.isErr:
417+
debug "service peer top-up request failed", serviceId, error = res.error
418+
397419
## Waku Sync
398420

399421
proc mountStoreSync*(
@@ -620,10 +642,22 @@ proc startProvidersAndListeners*(node: WakuNode) =
620642
).isOkOr:
621643
error "Can't set provider for RequestContentTopicsHealth", error = error
622644

645+
# Service-peer lookups are answered by kademlia; register only when it's mounted.
646+
if not node.wakuKademlia.isNil():
647+
ServicePeersRequest.setProvider(
648+
node.brokerCtx,
649+
proc(serviceId: string): Future[Result[ServicePeersRequest, string]] {.async.} =
650+
let peers = (await node.wakuKademlia.lookupServicePeers(serviceId)).valueOr:
651+
return err("failed call to lookupServicePeers: " & error)
652+
return ok(ServicePeersRequest(serviceId: serviceId, peers: peers)),
653+
).isOkOr:
654+
error "Can't set provider for ServicePeersRequest", error = error
655+
623656
proc stopProvidersAndListeners*(node: WakuNode) =
624657
RequestRelayShard.clearProvider(node.brokerCtx)
625658
RequestContentTopicsHealth.clearProvider(node.brokerCtx)
626659
RequestShardTopicsHealth.clearProvider(node.brokerCtx)
660+
ServicePeersRequest.clearProvider(node.brokerCtx)
627661

628662
proc start*(node: WakuNode) {.async.} =
629663
## Starts a created Waku Node and
@@ -672,6 +706,20 @@ proc start*(node: WakuNode) {.async.} =
672706
if not node.wakuKademlia.isNil():
673707
await node.wakuKademlia.start()
674708

709+
# Keep the mix pool filled: the generic service-peer top-up wired with
710+
# mix's service id, target pool size and current pool-size getter.
711+
if not node.wakuMix.isNil():
712+
node.mixTopUpLoop = node.runServicePeerTopUp(
713+
MixProtocolID,
714+
minMixPoolSize,
715+
proc(): int {.gcsafe, raises: [].} =
716+
if node.wakuMix.isNil():
717+
0
718+
else:
719+
node.getMixNodePoolSize(),
720+
chronos.seconds(5),
721+
)
722+
675723
if not node.wakuFilterClient.isNil():
676724
node.wakuFilterClient.registerPushHandler(
677725
proc(pubsubTopic: PubsubTopic, msg: WakuMessage) {.async, gcsafe.} =
@@ -698,6 +746,10 @@ proc stop*(node: WakuNode) {.async.} =
698746

699747
node.stopProvidersAndListeners()
700748

749+
if not node.mixTopUpLoop.isNil():
750+
await node.mixTopUpLoop.cancelAndWait()
751+
node.mixTopUpLoop = nil
752+
701753
if not node.wakuKademlia.isNil():
702754
await node.wakuKademlia.stop()
703755

logos_delivery/waku/waku_mix/protocol.nim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import
2727
logScope:
2828
topics = "waku mix"
2929

30-
const minMixPoolSize = 4
30+
const minMixPoolSize* = 4
3131

3232
type
3333
PublishMessage* = proc(message: WakuMessage): Future[Result[void, string]] {.

0 commit comments

Comments
 (0)