From b25a07ca9ac71a0a25c049cdce047c723e359ae7 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 10:48:21 +0200 Subject: [PATCH 01/17] Move waku.nim from waku/factory to under waku/ --- library/kernel_api/ping_api.nim | 4 +++- logos_delivery/logos_delivery.nim | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/library/kernel_api/ping_api.nim b/library/kernel_api/ping_api.nim index e6ed69dd1..14db0eb53 100644 --- a/library/kernel_api/ping_api.nim +++ b/library/kernel_api/ping_api.nim @@ -1,7 +1,9 @@ import std/[json, strutils] import chronos, results, ffi import libp2p/[protocols/ping, switch, multiaddress, multicodec] -import logos_delivery/waku/[waku, waku_core/peers, node/waku_node], library/declare_lib +import + logos_delivery/waku/[waku, waku_core/peers, node/waku_node], + library/declare_lib proc waku_ping_peer( ctx: ptr FFIContext[LogosDelivery], diff --git a/logos_delivery/logos_delivery.nim b/logos_delivery/logos_delivery.nim index f61202b9a..45f742cf5 100644 --- a/logos_delivery/logos_delivery.nim +++ b/logos_delivery/logos_delivery.nim @@ -11,6 +11,8 @@ import results, chronos, chronicles +import logos_delivery/waku/api +export api import logos_delivery/waku/waku export waku import logos_delivery/messaging/messaging_client From c93294c638c9e69b41107b111b10ee10cdc9cae7 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 11:19:16 +0200 Subject: [PATCH 02/17] remove unused --- logos_delivery/waku/waku.nim | 414 ----------------------------------- 1 file changed, 414 deletions(-) diff --git a/logos_delivery/waku/waku.nim b/logos_delivery/waku/waku.nim index 2c18c5f63..963d3fcb7 100644 --- a/logos_delivery/waku/waku.nim +++ b/logos_delivery/waku/waku.nim @@ -574,418 +574,4 @@ proc stop*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = return ok() -## Kernel API realization -## -# --- topic construction --- -proc buildContentTopic*( - self: Waku, appName: string, appVersion: uint32, name: string, encoding: string -): Future[Result[ContentTopic, string]] {.async.} = - try: - return ok(ContentTopic(fmt"/{appName}/{appVersion}/{name}/{encoding}")) - except CatchableError as e: - return err(e.msg) - -proc buildPubsubTopic*( - self: Waku, topicName: string -): Future[Result[PubsubTopic, string]] {.async.} = - try: - return ok(PubsubTopic(fmt"/waku/2/{topicName}")) - except CatchableError as e: - return err(e.msg) - -proc defaultPubsubTopic*(self: Waku): Future[Result[PubsubTopic, string]] {.async.} = - return ok(DefaultPubsubTopic) - -# --- relay --- -proc relayPublish*( - self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, timeoutMs: uint32 -): Future[Result[int, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayPublish: WakuRelay not mounted") - - let numPeers = (await self.node.wakuRelay.publish(pubsubTopic, message)).valueOr: - return err($error) - - return ok(numPeers) - except CatchableError as e: - return err(e.msg) - -proc relaySubscribe*( - self: Waku, pubsubTopic: PubsubTopic -): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relaySubscribe: WakuRelay not mounted") - - self.node.subscribe( - (kind: SubscriptionKind.PubsubSub, topic: pubsubTopic), WakuRelayHandler(nil) - ).isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc relayUnsubscribe*( - self: Waku, pubsubTopic: PubsubTopic -): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayUnsubscribe: WakuRelay not mounted") - - self.node.unsubscribe((kind: SubscriptionKind.PubsubSub, topic: pubsubTopic)).isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc relayAddProtectedShard*( - self: Waku, clusterId: uint16, shardId: uint16, publicKey: string -): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayAddProtectedShard: WakuRelay not mounted") - - let pubKey = SkPublicKey.fromHex(publicKey).valueOr: - return err("relayAddProtectedShard: invalid public key: " & $error) - - let protectedShard = ProtectedShard(shard: shardId, key: pubKey) - self.node.wakuRelay.addSignedShardsValidator(@[protectedShard], clusterId) - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc relayConnectedPeers*( - self: Waku, pubsubTopic: PubsubTopic -): Future[Result[seq[string], string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayConnectedPeers: WakuRelay not mounted") - - let connPeers = self.node.wakuRelay.getConnectedPeers(pubsubTopic).valueOr: - return err($error) - - return ok(connPeers.mapIt($it)) - except CatchableError as e: - return err(e.msg) - -proc relayPeersInMesh*( - self: Waku, pubsubTopic: PubsubTopic -): Future[Result[seq[string], string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayPeersInMesh: WakuRelay not mounted") - - let meshPeers = self.node.wakuRelay.getPeersInMesh(pubsubTopic).valueOr: - return err($error) - - return ok(meshPeers.mapIt($it)) - except CatchableError as e: - return err(e.msg) - -# --- filter --- -proc filterSubscribe*( - self: Waku, - pubsubTopic: Option[PubsubTopic], - contentTopics: seq[ContentTopic], - peer: string, -): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuFilterClient.isNil(): - return err("wakuFilterClient is not mounted") - - let subFut = self.node.filterSubscribe(pubsubTopic, contentTopics, peer) - if not await subFut.withTimeout(FilterOpTimeout): - return err("filter subscription timed out") - subFut.read().isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc filterUnsubscribe*( - self: Waku, - pubsubTopic: Option[PubsubTopic], - contentTopics: seq[ContentTopic], - peer: string, -): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuFilterClient.isNil(): - return err("wakuFilterClient is not mounted") - - let unsubFut = self.node.filterUnsubscribe(pubsubTopic, contentTopics, peer) - if not await unsubFut.withTimeout(FilterOpTimeout): - return err("filter un-subscription timed out") - unsubFut.read().isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc filterUnsubscribeAll*( - self: Waku, peer: string -): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuFilterClient.isNil(): - return err("wakuFilterClient is not mounted") - - let unsubFut = self.node.filterUnsubscribeAll(peer) - if not await unsubFut.withTimeout(FilterOpTimeout): - return err("filter un-subscription all timed out") - unsubFut.read().isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - -# --- lightpush --- -proc lightpushPublish*( - self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, peer: string -): Future[Result[string, string]] {.async.} = - try: - if self.node.wakuLegacyLightpushClient.isNil(): - return err("wakuLegacyLightpushClient is not mounted") - - let remotePeer = parsePeerInfo(peer).valueOr: - return err("lightpushPublish failed to parse peer addr: " & $error) - - let msgHashHex = ( - await self.node.wakuLegacyLightpushClient.publish( - pubsubTopic, message, remotePeer - ) - ).valueOr: - return err($error) - - return ok(msgHashHex) - except CatchableError as e: - return err(e.msg) - -# --- store --- -proc storeQuery*( - self: Waku, request: StoreQueryRequest, peer: string, timeoutMs: int -): Future[Result[StoreQueryResponse, string]] {.async.} = - try: - if self.node.wakuStoreClient.isNil(): - return err("wakuStoreClient is not mounted") - - let remotePeer = parsePeerInfo(peer).valueOr: - return err("storeQuery failed to parse peer addr: " & $error) - - let queryFut = self.node.wakuStoreClient.query(request, remotePeer) - if not await queryFut.withTimeout(timeoutMs.milliseconds): - return err("storeQuery timed out") - - let queryResponse = queryFut.read().valueOr: - return err("storeQuery failed: " & $error) - - return ok(queryResponse) - except CatchableError as e: - return err(e.msg) - -# --- peer management --- -proc connect*( - self: Waku, peers: seq[string], timeoutMs: uint32 -): Future[Result[bool, string]] {.async.} = - try: - await self.node.connectToNodes(peers.mapIt(strip(it)), source = "static") - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc disconnectPeerById*( - self: Waku, peerId: string -): Future[Result[bool, string]] {.async.} = - try: - let pId = PeerId.init(peerId).valueOr: - return err($error) - await self.node.peerManager.disconnectNode(pId) - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc disconnectAllPeers*(self: Waku): Future[Result[bool, string]] {.async.} = - try: - await self.node.peerManager.disconnectAllPeers() - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc dialPeer*( - self: Waku, peerAddr: string, protocol: string, timeoutMs: int -): Future[Result[bool, string]] {.async.} = - try: - let remotePeerInfo = parsePeerInfo(peerAddr).valueOr: - return err($error) - let conn = await self.node.peerManager.dialPeer(remotePeerInfo, protocol) - if conn.isNone(): - return err("failed dialing peer") - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc dialPeerById*( - self: Waku, peerId: string, protocol: string, timeoutMs: int -): Future[Result[bool, string]] {.async.} = - try: - let pId = PeerId.init(peerId).valueOr: - return err($error) - let conn = await self.node.peerManager.dialPeer(pId, protocol) - if conn.isNone(): - return err("failed dialing peer") - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc peerIdsFromPeerstore*(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - return ok(self.node.peerManager.switch.peerStore.peers().mapIt($it.peerId)) - except CatchableError as e: - return err(e.msg) - -proc connectedPeersInfo*(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - return ok( - self.node.peerManager.switch.peerStore - .peers() - .filterIt(it.connectedness == Connected) - .mapIt($it.peerId) - ) - except CatchableError as e: - return err(e.msg) - -proc connectedPeers*(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - let (inPeerIds, outPeerIds) = self.node.peerManager.connectedPeers() - return ok(concat(inPeerIds, outPeerIds).mapIt($it)) - except CatchableError as e: - return err(e.msg) - -proc peerIdsByProtocol*( - self: Waku, protocol: string -): Future[Result[seq[string], string]] {.async.} = - try: - return ok( - self.node.peerManager.switch.peerStore - .peers(protocol) - .filterIt(it.connectedness == Connected) - .mapIt($it.peerId) - ) - except CatchableError as e: - return err(e.msg) - -# --- discovery --- -proc dnsDiscovery*( - self: Waku, enrTreeUrl: string, nameServer: string, timeoutMs: int -): Future[Result[seq[string], string]] {.async.} = - try: - let dnsNameServers = @[parseIpAddress(nameServer)] - let discoveredPeers = ( - await retrieveDynamicBootstrapNodes(enrTreeUrl, dnsNameServers) - ).valueOr: - return err("failed discovering peers from DNS: " & $error) - - var multiAddresses = newSeq[string]() - for discPeer in discoveredPeers: - for address in discPeer.addrs: - multiAddresses.add($address & "/p2p/" & $discPeer) - - return ok(multiAddresses) - except CatchableError as e: - return err(e.msg) - -proc discv5UpdateBootnodes*( - self: Waku, bootnodes: seq[string] -): Future[Result[bool, string]] {.async.} = - try: - if self.wakuDiscv5.isNil(): - return err("discv5 not started") - let jsonArray = "[" & bootnodes.mapIt("\"" & it & "\"").join(",") & "]" - self.wakuDiscv5.updateBootstrapRecords(jsonArray).isOkOr: - return err("error in discv5UpdateBootnodes: " & $error) - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc startDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = - try: - if self.wakuDiscv5.isNil(): - return err("discv5 not started") - (await self.wakuDiscv5.start()).isOkOr: - return err("error starting discv5: " & $error) - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc stopDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = - try: - if self.wakuDiscv5.isNil(): - return err("discv5 not started") - await self.wakuDiscv5.stop() - return ok(true) - except CatchableError as e: - return err(e.msg) - -proc peerExchangeRequest*( - self: Waku, numPeers: uint64 -): Future[Result[int, string]] {.async.} = - try: - let numPeersRecv = (await self.node.fetchPeerExchangePeers(numPeers)).valueOr: - return err("failed peer exchange: " & $error) - return ok(numPeersRecv) - except CatchableError as e: - return err(e.msg) - -# --- debug / info --- -proc version*(self: Waku): Future[Result[string, string]] {.async.} = - return ok(WakuNodeVersionString) - -proc listenAddresses*(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - return ok(self.node.info().listenAddresses) - except CatchableError as e: - return err(e.msg) - -proc myEnr*(self: Waku): Future[Result[string, string]] {.async.} = - try: - return ok(self.node.enr.toURI()) - except CatchableError as e: - return err(e.msg) - -proc myPeerId*(self: Waku): Future[Result[string, string]] {.async.} = - try: - return ok($self.node.peerId()) - except CatchableError as e: - return err(e.msg) - -proc metrics*(self: Waku): Future[Result[string, string]] {.async.} = - {.gcsafe.}: - try: - return ok(defaultRegistry.toText()) - except CatchableError as e: - return err(e.msg) - -proc pingPeer*( - self: Waku, peerAddr: string, timeoutMs: int -): Future[Result[int64, string]] {.async.} = - try: - let peerInfo = parsePeerInfo(peerAddr).valueOr: - return err("pingPeer failed to parse peer addr: " & $error) - - let conn = await self.node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec) - defer: - await conn.close() - let pingRTT = await self.node.libp2pPing.ping(conn) - - if pingRTT == 0.nanos: - return err("could not ping peer: rtt-0") - - return ok(pingRTT.nanos) - except CatchableError as e: - return err(e.msg) - {.pop.} From 10634f8a05ba59a63f792c532ea7882de6a78068 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 11:24:11 +0200 Subject: [PATCH 03/17] Realize Kernel API in scope of Waku class --- logos_delivery/waku/waku.nim | 424 +++++++++++++++++++++++++++++++++++ 1 file changed, 424 insertions(+) diff --git a/logos_delivery/waku/waku.nim b/logos_delivery/waku/waku.nim index 963d3fcb7..0112d15d7 100644 --- a/logos_delivery/waku/waku.nim +++ b/logos_delivery/waku/waku.nim @@ -574,4 +574,428 @@ proc stop*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = return ok() +## Kernel API realization +## +# --- topic construction --- +proc buildContentTopic*( + self: Waku, appName: string, appVersion: uint32, name: string, encoding: string +): Future[Result[ContentTopic, string]] {.async.} = + try: + return ok(ContentTopic(fmt"/{appName}/{appVersion}/{name}/{encoding}")) + except CatchableError as e: + return err(e.msg) + +proc buildPubsubTopic*( + self: Waku, topicName: string +): Future[Result[PubsubTopic, string]] {.async.} = + try: + return ok(PubsubTopic(fmt"/waku/2/{topicName}")) + except CatchableError as e: + return err(e.msg) + +proc defaultPubsubTopic*(self: Waku): Future[Result[PubsubTopic, string]] {.async.} = + return ok(DefaultPubsubTopic) + +# --- relay --- +proc relayPublish*( + self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, timeoutMs: uint32 +): Future[Result[int, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayPublish: WakuRelay not mounted") + + let numPeers = (await self.node.wakuRelay.publish(pubsubTopic, message)).valueOr: + return err($error) + + return ok(numPeers) + except CatchableError as e: + return err(e.msg) + +proc relaySubscribe*( + self: Waku, pubsubTopic: PubsubTopic +): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relaySubscribe: WakuRelay not mounted") + + let handler = proc(topic: PubsubTopic, msg: WakuMessage) {.async.} = + ## Bridge inbound relay traffic to the `ReceivedMessage` kernel event + ## (replaces libwaku's set_event_callback message path). + ReceivedMessage.emit( + self.brokerCtx, ReceivedMessage(pubsubTopic: topic, message: msg) + ) + + self.node.subscribe( + (kind: SubscriptionKind.PubsubSub, topic: pubsubTopic), WakuRelayHandler(handler) + ).isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc relayUnsubscribe*( + self: Waku, pubsubTopic: PubsubTopic +): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayUnsubscribe: WakuRelay not mounted") + + self.node.unsubscribe((kind: SubscriptionKind.PubsubSub, topic: pubsubTopic)).isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc relayAddProtectedShard*( + self: Waku, clusterId: uint16, shardId: uint16, publicKey: string +): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayAddProtectedShard: WakuRelay not mounted") + + let pubKey = SkPublicKey.fromHex(publicKey).valueOr: + return err("relayAddProtectedShard: invalid public key: " & $error) + + let protectedShard = ProtectedShard(shard: shardId, key: pubKey) + self.node.wakuRelay.addSignedShardsValidator(@[protectedShard], clusterId) + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc relayConnectedPeers*( + self: Waku, pubsubTopic: PubsubTopic +): Future[Result[seq[string], string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayConnectedPeers: WakuRelay not mounted") + + let connPeers = self.node.wakuRelay.getConnectedPeers(pubsubTopic).valueOr: + return err($error) + + return ok(connPeers.mapIt($it)) + except CatchableError as e: + return err(e.msg) + +proc relayPeersInMesh*( + self: Waku, pubsubTopic: PubsubTopic +): Future[Result[seq[string], string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayPeersInMesh: WakuRelay not mounted") + + let meshPeers = self.node.wakuRelay.getPeersInMesh(pubsubTopic).valueOr: + return err($error) + + return ok(meshPeers.mapIt($it)) + except CatchableError as e: + return err(e.msg) + +# --- filter --- +proc filterSubscribe*( + self: Waku, + pubsubTopic: Option[PubsubTopic], + contentTopics: seq[ContentTopic], + peer: string, +): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuFilterClient.isNil(): + return err("wakuFilterClient is not mounted") + + let subFut = self.node.filterSubscribe(pubsubTopic, contentTopics, peer) + if not await subFut.withTimeout(FilterOpTimeout): + return err("filter subscription timed out") + subFut.read().isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc filterUnsubscribe*( + self: Waku, + pubsubTopic: Option[PubsubTopic], + contentTopics: seq[ContentTopic], + peer: string, +): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuFilterClient.isNil(): + return err("wakuFilterClient is not mounted") + + let unsubFut = self.node.filterUnsubscribe(pubsubTopic, contentTopics, peer) + if not await unsubFut.withTimeout(FilterOpTimeout): + return err("filter un-subscription timed out") + unsubFut.read().isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc filterUnsubscribeAll*( + self: Waku, peer: string +): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuFilterClient.isNil(): + return err("wakuFilterClient is not mounted") + + let unsubFut = self.node.filterUnsubscribeAll(peer) + if not await unsubFut.withTimeout(FilterOpTimeout): + return err("filter un-subscription all timed out") + unsubFut.read().isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + +# --- lightpush --- +proc lightpushPublish*( + self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, peer: string +): Future[Result[string, string]] {.async.} = + try: + if self.node.wakuLegacyLightpushClient.isNil(): + return err("wakuLegacyLightpushClient is not mounted") + + let remotePeer = parsePeerInfo(peer).valueOr: + return err("lightpushPublish failed to parse peer addr: " & $error) + + let msgHashHex = ( + await self.node.wakuLegacyLightpushClient.publish( + pubsubTopic, message, remotePeer + ) + ).valueOr: + return err($error) + + return ok(msgHashHex) + except CatchableError as e: + return err(e.msg) + +# --- store --- +proc storeQuery*( + self: Waku, request: StoreQueryRequest, peer: string, timeoutMs: int +): Future[Result[StoreQueryResponse, string]] {.async.} = + try: + if self.node.wakuStoreClient.isNil(): + return err("wakuStoreClient is not mounted") + + let remotePeer = parsePeerInfo(peer).valueOr: + return err("storeQuery failed to parse peer addr: " & $error) + + let queryFut = self.node.wakuStoreClient.query(request, remotePeer) + if not await queryFut.withTimeout(timeoutMs.milliseconds): + return err("storeQuery timed out") + + let queryResponse = queryFut.read().valueOr: + return err("storeQuery failed: " & $error) + + return ok(queryResponse) + except CatchableError as e: + return err(e.msg) + +# --- peer management --- +proc connect*( + self: Waku, peers: seq[string], timeoutMs: uint32 +): Future[Result[bool, string]] {.async.} = + try: + await self.node.connectToNodes(peers.mapIt(strip(it)), source = "static") + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc disconnectPeerById*( + self: Waku, peerId: string +): Future[Result[bool, string]] {.async.} = + try: + let pId = PeerId.init(peerId).valueOr: + return err($error) + await self.node.peerManager.disconnectNode(pId) + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc disconnectAllPeers*(self: Waku): Future[Result[bool, string]] {.async.} = + try: + await self.node.peerManager.disconnectAllPeers() + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc dialPeer*( + self: Waku, peerAddr: string, protocol: string, timeoutMs: int +): Future[Result[bool, string]] {.async.} = + try: + let remotePeerInfo = parsePeerInfo(peerAddr).valueOr: + return err($error) + let conn = await self.node.peerManager.dialPeer(remotePeerInfo, protocol) + if conn.isNone(): + return err("failed dialing peer") + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc dialPeerById*( + self: Waku, peerId: string, protocol: string, timeoutMs: int +): Future[Result[bool, string]] {.async.} = + try: + let pId = PeerId.init(peerId).valueOr: + return err($error) + let conn = await self.node.peerManager.dialPeer(pId, protocol) + if conn.isNone(): + return err("failed dialing peer") + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc peerIdsFromPeerstore*(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + return ok(self.node.peerManager.switch.peerStore.peers().mapIt($it.peerId)) + except CatchableError as e: + return err(e.msg) + +proc connectedPeersInfo*(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + return ok( + self.node.peerManager.switch.peerStore + .peers() + .filterIt(it.connectedness == Connected) + .mapIt($it.peerId) + ) + except CatchableError as e: + return err(e.msg) + +proc connectedPeers*(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + let (inPeerIds, outPeerIds) = self.node.peerManager.connectedPeers() + return ok(concat(inPeerIds, outPeerIds).mapIt($it)) + except CatchableError as e: + return err(e.msg) + +proc peerIdsByProtocol*( + self: Waku, protocol: string +): Future[Result[seq[string], string]] {.async.} = + try: + return ok( + self.node.peerManager.switch.peerStore + .peers(protocol) + .filterIt(it.connectedness == Connected) + .mapIt($it.peerId) + ) + except CatchableError as e: + return err(e.msg) + +# --- discovery --- +proc dnsDiscovery*( + self: Waku, enrTreeUrl: string, nameServer: string, timeoutMs: int +): Future[Result[seq[string], string]] {.async.} = + try: + let dnsNameServers = @[parseIpAddress(nameServer)] + let discoveredPeers = ( + await retrieveDynamicBootstrapNodes(enrTreeUrl, dnsNameServers) + ).valueOr: + return err("failed discovering peers from DNS: " & $error) + + var multiAddresses = newSeq[string]() + for discPeer in discoveredPeers: + for address in discPeer.addrs: + multiAddresses.add($address & "/p2p/" & $discPeer) + + return ok(multiAddresses) + except CatchableError as e: + return err(e.msg) + +proc discv5UpdateBootnodes*( + self: Waku, bootnodes: seq[string] +): Future[Result[bool, string]] {.async.} = + try: + if self.wakuDiscv5.isNil(): + return err("discv5 not started") + let jsonArray = "[" & bootnodes.mapIt("\"" & it & "\"").join(",") & "]" + self.wakuDiscv5.updateBootstrapRecords(jsonArray).isOkOr: + return err("error in discv5UpdateBootnodes: " & $error) + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc startDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = + try: + if self.wakuDiscv5.isNil(): + return err("discv5 not started") + (await self.wakuDiscv5.start()).isOkOr: + return err("error starting discv5: " & $error) + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc stopDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = + try: + if self.wakuDiscv5.isNil(): + return err("discv5 not started") + await self.wakuDiscv5.stop() + return ok(true) + except CatchableError as e: + return err(e.msg) + +proc peerExchangeRequest*( + self: Waku, numPeers: uint64 +): Future[Result[int, string]] {.async.} = + try: + let numPeersRecv = (await self.node.fetchPeerExchangePeers(numPeers)).valueOr: + return err("failed peer exchange: " & $error) + return ok(numPeersRecv) + except CatchableError as e: + return err(e.msg) + +# --- debug / info --- +proc version*(self: Waku): Future[Result[string, string]] {.async.} = + return ok(WakuNodeVersionString) + +proc listenAddresses*(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + return ok(self.node.info().listenAddresses) + except CatchableError as e: + return err(e.msg) + +proc myEnr*(self: Waku): Future[Result[string, string]] {.async.} = + try: + return ok(self.node.enr.toURI()) + except CatchableError as e: + return err(e.msg) + +proc myPeerId*(self: Waku): Future[Result[string, string]] {.async.} = + try: + return ok($self.node.peerId()) + except CatchableError as e: + return err(e.msg) + +proc metrics*(self: Waku): Future[Result[string, string]] {.async.} = + {.gcsafe.}: + try: + return ok(defaultRegistry.toText()) + except CatchableError as e: + return err(e.msg) + +proc isOnline*(self: Waku): Future[Result[bool, string]] {.async.} = + return ok(self.healthMonitor.onlineMonitor.amIOnline()) + +proc pingPeer*( + self: Waku, peerAddr: string, timeoutMs: int +): Future[Result[int64, string]] {.async.} = + try: + let peerInfo = parsePeerInfo(peerAddr).valueOr: + return err("pingPeer failed to parse peer addr: " & $error) + + let conn = await self.node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec) + defer: + await conn.close() + let pingRTT = await self.node.libp2pPing.ping(conn) + + if pingRTT == 0.nanos: + return err("could not ping peer: rtt-0") + + return ok(pingRTT.nanos) + except CatchableError as e: + return err(e.msg) + {.pop.} From 341556e96422815a8b84187d57b053836832ed4f Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 13:55:23 +0200 Subject: [PATCH 04/17] Refactor waku/api into messaging_client, waku/api/types and api_conf into logos_delivery/api --- logos_delivery/logos_delivery.nim | 2 - logos_delivery/messaging/messaging_client.nim | 16 +- logos_delivery/waku/factory/waku.nim | 1034 +++++++++++++++++ .../node/health_monitor/connection_status.nim | 2 +- logos_delivery/waku/waku.nim | 15 +- 5 files changed, 1044 insertions(+), 25 deletions(-) create mode 100644 logos_delivery/waku/factory/waku.nim diff --git a/logos_delivery/logos_delivery.nim b/logos_delivery/logos_delivery.nim index 45f742cf5..1c2682f76 100644 --- a/logos_delivery/logos_delivery.nim +++ b/logos_delivery/logos_delivery.nim @@ -22,8 +22,6 @@ export reliable_channel_manager import logos_delivery/waku/factory/waku_conf import logos_delivery/waku/factory/app_callbacks -import tools/confutils/cli_args -import logos_delivery/waku/node/health_monitor/online_monitor logScope: topics = "logosdelivery" diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index 96cd13eb1..a05c94377 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -43,25 +43,25 @@ proc stop*(self: MessagingClient) {.async.} = await self.recvService.stopRecvService() self.started = false -proc checkApiAvailability(self: MessagingClient): Result[void, string] = - if self.isNil(): +proc checkApiAvailability(mc: MessagingClient): Result[void, string] = + if mc.isNil(): return err("MessagingClient is not initialized") return ok() proc subscribe*( - self: MessagingClient, contentTopic: ContentTopic + mc: MessagingClient, contentTopic: ContentTopic ): Future[Result[void, string]] {.async.} = - ?checkApiAvailability(self) + ?checkApiAvailability(mc) - return self.node.subscriptionManager.subscribe(contentTopic) + return mc.node.subscriptionManager.subscribe(contentTopic) proc unsubscribe*( - self: MessagingClient, contentTopic: ContentTopic + mc: MessagingClient, contentTopic: ContentTopic ): Result[void, string] = - ?checkApiAvailability(self) + ?checkApiAvailability(mc) - return self.node.subscriptionManager.unsubscribe(contentTopic) + return mc.node.subscriptionManager.unsubscribe(contentTopic) proc send*( self: MessagingClient, envelope: MessageEnvelope diff --git a/logos_delivery/waku/factory/waku.nim b/logos_delivery/waku/factory/waku.nim new file mode 100644 index 000000000..a9a649ca8 --- /dev/null +++ b/logos_delivery/waku/factory/waku.nim @@ -0,0 +1,1034 @@ +import logos_delivery/waku/compat/option_valueor +{.push raises: [].} + +import + std/[options, sequtils, strformat, net, strutils], + results, + chronicles, + chronos, + secp256k1, + libp2p/protocols/ping, + libp2p/protocols/connectivity/relay/relay, + libp2p/protocols/connectivity/relay/client, + libp2p/wire, + libp2p/crypto/crypto, + libp2p/protocols/pubsub/gossipsub, + libp2p/services/autorelayservice, + libp2p/services/hpservice, + libp2p/peerid, + eth/keys, + eth/p2p/discoveryv5/enr, + presto, + metrics, + metrics/chronos_httpserver, + brokers/broker_context, + brokers/broker_implement, + logos_delivery/api/types, + logos_delivery/waku/[ + waku_core, + waku_node, + waku_archive, + waku_rln_relay, + waku_store, + waku_filter_v2, + waku_relay/protocol, + waku_enr/sharding, + waku_enr/multiaddr, + common/logging, + node/peer_manager, + node/health_monitor, + net/net_config, + node/waku_metrics, + node/subscription_manager, + rest_api/message_cache, + rest_api/endpoint/server, + rest_api/endpoint/builder as rest_server_builder, + discovery/waku_dnsdisc, + discovery/waku_discv5, + discovery/autonat_service, + requests/health_requests, + factory/node_factory, + factory/internal_config, + factory/app_callbacks, + persistency/persistency, + waku_lightpush_legacy/client, + waku_store/client as waku_store_client, + factory/validator_signed, + ], + logos_delivery/api/kernel_interface, + logos_delivery/channels/reliable_channel_manager, + logos_delivery/messaging/messaging_client, + ./waku_conf, + ./waku_state_info + +logScope: + topics = "wakunode waku" + +# Git version in git describe format (defined at compile time) +const git_version* {.strdefine.} = "n/a" + +type Waku* = ref object of KernelInterface + stateInfo*: WakuStateInfo + conf*: WakuConf + rng*: crypto.Rng + + key: crypto.PrivateKey + + wakuDiscv5*: WakuDiscoveryV5 + dynamicBootstrapNodes*: seq[RemotePeerInfo] + dnsRetryLoopHandle: Future[void] + networkConnLoopHandle: Future[void] + + node*: WakuNode + + # TODO: remove this indirection. Now kept for legacy. + healthMonitor*: NodeHealthMonitor + messagingClient*: MessagingClient + + reliableChannelManager*: ReliableChannelManager + + restServer*: WakuRestServerRef + metricsServer*: MetricsHttpServerRef + appCallbacks*: AppCallbacks + ## `brokerCtx` is inherited from the `KernelInterface` broker base. + +proc setupSwitchServices( + waku: Waku, conf: WakuConf, circuitRelay: Relay, rng: crypto.Rng +) = + proc onReservation(addresses: seq[MultiAddress]) {.gcsafe, raises: [].} = + info "circuit relay handler new reserve event", + addrs_before = $(waku.node.announcedAddresses), addrs = $addresses + + waku.node.announcedAddresses.setLen(0) ## remove previous addresses + waku.node.announcedAddresses.add(addresses) + info "waku node announced addresses updated", + announcedAddresses = waku.node.announcedAddresses + + if not isNil(waku.wakuDiscv5): + waku.wakuDiscv5.updateAnnouncedMultiAddress(addresses).isOkOr: + error "failed to update announced multiaddress", error = $error + + let autonatService = getAutonatService(rng) + if conf.circuitRelayClient: + ## The node is considered to be behind a NAT or firewall and then it + ## should struggle to be reachable and establish connections to other nodes + const MaxNumRelayServers = 2 + let autoRelayService = AutoRelayService.new( + MaxNumRelayServers, RelayClient(circuitRelay), onReservation, rng + ) + let holePunchService = HPService.new(autonatService, autoRelayService) + waku.node.switch.services = @[Service(holePunchService)] + else: + waku.node.switch.services = @[Service(autonatService)] + + # libp2p 2.0.0 split Service.setup out of Service.start: the switch runs setup + # only at build time (SwitchBuilder.setupServices), while switch.start calls + # just start. These services are created and attached post-build, so setup must + # be invoked explicitly here -- otherwise AutonatService.addressMapper stays nil + # and the peerInfo.update() inside start dereferences it (SIGSEGV). + for service in waku.node.switch.services: + try: + service.setup(waku.node.switch) + except ServiceSetupError as e: + error "failed to set up libp2p switch service", error = e.msg + +## Initialisation + +proc newCircuitRelay(isRelayClient: bool): Relay = + # TODO: Does it mean it's a circuit-relay server when it's false? + if isRelayClient: + return RelayClient.new() + return Relay.new() + +proc setupAppCallbacks( + node: WakuNode, + conf: WakuConf, + appCallbacks: AppCallbacks, + healthMonitor: NodeHealthMonitor, +): Result[void, string] = + if appCallbacks.isNil(): + info "No external callbacks to be set" + return ok() + + if not appCallbacks.relayHandler.isNil(): + if node.wakuRelay.isNil(): + return err("Cannot configure relayHandler callback without Relay mounted") + + let autoShards = + if node.wakuAutoSharding.isSome(): + node.getAutoshards(conf.contentTopics).valueOr: + return err("Could not get autoshards: " & error) + else: + @[] + + let confShards = conf.subscribeShards.mapIt( + RelayShard(clusterId: conf.clusterId, shardId: uint16(it)) + ) + let shards = confShards & autoShards + + let uniqueShards = deduplicate(shards) + + for shard in uniqueShards: + let topic = $shard + node.subscribe((kind: PubsubSub, topic: topic), appCallbacks.relayHandler).isOkOr: + return err(fmt"Could not subscribe {topic}: " & $error) + + if not appCallbacks.topicHealthChangeHandler.isNil(): + if node.wakuRelay.isNil(): + return + err("Cannot configure topicHealthChangeHandler callback without Relay mounted") + node.wakuRelay.onTopicHealthChange = appCallbacks.topicHealthChangeHandler + + if not appCallbacks.connectionChangeHandler.isNil(): + if node.peerManager.isNil(): + return + err("Cannot configure connectionChangeHandler callback with empty peer manager") + node.peerManager.onConnectionChange = appCallbacks.connectionChangeHandler + + if not appCallbacks.connectionStatusChangeHandler.isNil(): + if healthMonitor.isNil(): + return + err("Cannot configure connectionStatusChangeHandler with empty health monitor") + + healthMonitor.onConnectionStatusChange = appCallbacks.connectionStatusChangeHandler + + return ok() + +proc getPorts( + listenAddrs: seq[MultiAddress] +): Result[tuple[tcpPort, websocketPort, quicPort: Option[Port]], string] = + var tcpPort, websocketPort, quicPort = none(Port) + + for a in listenAddrs: + if a.isWsAddress(): + if websocketPort.isNone(): + let wsAddress = initTAddress(a).valueOr: + return err("getPorts wsAddr error:" & $error) + websocketPort = some(wsAddress.port) + elif a.isQuicAddress(): + if quicPort.isNone(): + let quicAddress = initTAddress(a).valueOr: + return err("getPorts quicAddr error:" & $error) + quicPort = some(quicAddress.port) + elif tcpPort.isNone(): + let tcpAddress = initTAddress(a).valueOr: + return err("getPorts tcpAddr error:" & $error) + tcpPort = some(tcpAddress.port) + + return ok((tcpPort: tcpPort, websocketPort: websocketPort, quicPort: quicPort)) + +proc getRunningNetConfig(waku: Waku): Future[Result[NetConfig, string]] {.async.} = + let conf = waku.conf + let (tcpPort, websocketPort, quicPort) = getPorts( + waku.node.switch.peerInfo.listenAddrs + ).valueOr: + return err("Could not retrieve ports: " & error) + + if tcpPort.isSome(): + conf.endpointConf.p2pTcpPort = tcpPort.get() + + if websocketPort.isSome() and conf.webSocketConf.isSome(): + conf.webSocketConf.get().port = websocketPort.get() + + if quicPort.isSome() and conf.quicConf.isSome(): + conf.quicConf.get().port = quicPort.get() + + # Rebuild NetConfig with bound port values + let netConf = ( + await networkConfiguration( + conf.clusterId, conf.endpointConf, conf.discv5Conf, conf.webSocketConf, + conf.quicConf, conf.wakuFlags, conf.dnsAddrsNameServers, conf.portsShift, clientId, + ) + ).valueOr: + return err("Could not update NetConfig: " & error) + + return ok(netConf) + +proc updateEnr(waku: Waku): Future[Result[void, string]] {.async.} = + let netConf: NetConfig = (await getRunningNetConfig(waku)).valueOr: + return err("error calling updateNetConfig: " & $error) + let record = enrConfiguration(waku.conf, netConf).valueOr: + return err("ENR setup failed: " & error) + + if isClusterMismatched(record, waku.conf.clusterId): + return err("cluster-id mismatch configured shards") + + waku.node.enr = record + + # If TCP/WS was configured with port 0, node.announcedAddresses was built + # pre-bind with a port value of 0. In any case, the resync is harmless. + waku.node.announcedAddresses = netConf.announcedAddresses + + return ok() + +proc updateAddressInENR(waku: Waku): Result[void, string] = + let addresses: seq[MultiAddress] = waku.node.announcedAddresses + let encodedAddrs = multiaddr.encodeMultiaddrs(addresses) + + ## First update the enr info contained in WakuNode + let keyBytes = waku.key.getRawBytes().valueOr: + return err("failed to retrieve raw bytes from waku key: " & $error) + + let parsedPk = keys.PrivateKey.fromHex(keyBytes.toHex()).valueOr: + return err("failed to parse the private key: " & $error) + + let enrFields = @[toFieldPair(MultiaddrEnrField, encodedAddrs)] + waku.node.enr.update(parsedPk, extraFields = enrFields).isOkOr: + return err("failed to update multiaddress in ENR updateAddressInENR: " & $error) + + info "Waku node ENR updated successfully with new multiaddress", + enr = waku.node.enr.toUri(), record = $(waku.node.enr) + + ## Now update the ENR infor in discv5 + if not waku.wakuDiscv5.isNil(): + waku.wakuDiscv5.protocol.localNode.record = waku.node.enr + let enr = waku.wakuDiscv5.protocol.localNode.record + + info "Waku discv5 ENR updated successfully with new multiaddress", + enr = enr.toUri(), record = $(enr) + + return ok() + +proc updateWaku(waku: Waku): Future[Result[void, string]] {.async.} = + (await updateEnr(waku)).isOkOr: + return err("error calling updateEnr: " & $error) + + ?updateAnnouncedAddrWithPrimaryIpAddr(waku.node) + + ?updateAddressInENR(waku) + + return ok() + +proc startDnsDiscoveryRetryLoop(waku: Waku): Future[void] {.async.} = + while true: + await sleepAsync(30.seconds) + if waku.conf.dnsDiscoveryConf.isSome(): + let dnsDiscoveryConf = waku.conf.dnsDiscoveryConf.get() + waku.dynamicBootstrapNodes = ( + await waku_dnsdisc.retrieveDynamicBootstrapNodes( + dnsDiscoveryConf.enrTreeUrl, dnsDiscoveryConf.nameServers + ) + ).valueOr: + error "Retrieving dynamic bootstrap nodes failed", error = error + continue + + if not waku.wakuDiscv5.isNil(): + let dynamicBootstrapEnrs = + waku.dynamicBootstrapNodes.filterIt(it.hasUdpPort()).mapIt(it.enr.get().toUri()) + var discv5BootstrapEnrs: seq[enr.Record] + # parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq + for enrUri in dynamicBootstrapEnrs: + addBootstrapNode(enrUri, discv5BootstrapEnrs) + + waku.wakuDiscv5.updateBootstrapRecords( + waku.wakuDiscv5.protocol.bootstrapRecords & discv5BootstrapEnrs + ) + + info "Connecting to dynamic bootstrap peers" + try: + await connectToNodes(waku.node, waku.dynamicBootstrapNodes, "dynamic bootstrap") + except CatchableError: + error "failed to connect to dynamic bootstrap nodes: " & getCurrentExceptionMsg() + return + +# Notice this interface to be used only from LogosDelivery, hence not in the interface level. +proc start*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = + if waku.node.started: + warn "start: waku node already started" + return ok() + + info "Retrieve dynamic bootstrap nodes" + let conf = waku.conf + + if conf.dnsDiscoveryConf.isSome(): + let dnsDiscoveryConf = waku.conf.dnsDiscoveryConf.get() + let dynamicBootstrapNodesRes = + try: + await waku_dnsdisc.retrieveDynamicBootstrapNodes( + dnsDiscoveryConf.enrTreeUrl, dnsDiscoveryConf.nameServers + ) + except CatchableError as exc: + Result[seq[RemotePeerInfo], string].err( + "Retrieving dynamic bootstrap nodes failed: " & exc.msg + ) + + if dynamicBootstrapNodesRes.isErr(): + error "Retrieving dynamic bootstrap nodes failed", + error = dynamicBootstrapNodesRes.error + # Start Dns Discovery retry loop + waku.dnsRetryLoopHandle = waku.startDnsDiscoveryRetryLoop() + else: + waku.dynamicBootstrapNodes = dynamicBootstrapNodesRes.get() + + ## Initialize persistency singleton instance - we don't need the instance itself here, + ## but this ensures it's initialized before any store job starts. + discard Persistency.instance(conf.localStoragePath).valueOr: + error "Failed to initialize persistency instance", error = $error + return err("Failed to initialize persistency instance: " & $error) + + (await startNode(waku.node, waku.conf, waku.dynamicBootstrapNodes)).isOkOr: + return err("error while calling startNode: " & $error) + + let bound = getPorts(waku.node.switch.peerInfo.listenAddrs).valueOr: + return err("failed to read bound ports from switch: " & $error) + waku.node.ports.tcp = bound.tcpPort.get(Port(0)).uint16 + waku.node.ports.webSocket = bound.websocketPort.get(Port(0)).uint16 + waku.node.ports.quic = bound.quicPort.get(Port(0)).uint16 + + ## Discv5 + if conf.discv5Conf.isSome(): + waku.wakuDiscV5 = ( + await waku_discv5.setupAndStartDiscv5( + waku.node.enr, + waku.node.peerManager, + waku.node.topicSubscriptionQueue, + conf.discv5Conf.get(), + waku.dynamicBootstrapNodes, + waku.rng, + conf.nodeKey, + conf.endpointConf.p2pListenAddress, + conf.portsShift, + ) + ).valueOr: + return err("failed to start waku discovery v5: " & error) + + waku.node.ports.discv5Udp = waku.wakuDiscV5.udpPort.uint16 + waku.conf.discv5Conf.get().udpPort = waku.wakuDiscV5.udpPort + + ## Update waku data that is set dynamically on node start + try: + (await updateWaku(waku)).isOkOr: + return err("Error in start: " & $error) + except CatchableError: + return err("Caught exception in start: " & getCurrentExceptionMsg()) + + waku.node.subscriptionManager.subscribeAllAutoshards().isOkOr: + return err("failed to auto-subscribe autosharding shards: " & $error) + + ## Health Monitor + waku.healthMonitor.startHealthMonitor().isOkOr: + return err("failed to start health monitor: " & $error) + + ## Setup RequestConnectionStatus provider + + RequestConnectionStatus.setProvider( + globalBrokerContext(), + proc(): Result[RequestConnectionStatus, string] = + try: + let healthReport = waku.healthMonitor.getSyncNodeHealthReport() + return + ok(RequestConnectionStatus(connectionStatus: healthReport.connectionStatus)) + except CatchableError: + err("Failed to read health report: " & getCurrentExceptionMsg()), + ).isOkOr: + error "Failed to set RequestConnectionStatus provider", error = error + + ## Setup RequestProtocolHealth provider + + RequestProtocolHealth.setProvider( + globalBrokerContext(), + proc( + protocol: WakuProtocol + ): Future[Result[RequestProtocolHealth, string]] {.async.} = + try: + let protocolHealthStatus = + await waku.healthMonitor.getProtocolHealthInfo(protocol) + return ok(RequestProtocolHealth(healthStatus: protocolHealthStatus)) + except CatchableError: + return err("Failed to get protocol health: " & getCurrentExceptionMsg()), + ).isOkOr: + error "Failed to set RequestProtocolHealth provider", error = error + + ## Setup RequestHealthReport provider + + RequestHealthReport.setProvider( + globalBrokerContext(), + proc(): Future[Result[RequestHealthReport, string]] {.async.} = + try: + let report = await waku.healthMonitor.getNodeHealthReport() + return ok(RequestHealthReport(healthReport: report)) + except CatchableError: + return err("Failed to get health report: " & getCurrentExceptionMsg()), + ).isOkOr: + error "Failed to set RequestHealthReport provider", error = error + + if conf.restServerConf.isSome(): + rest_server_builder.startRestServerProtocolSupport( + waku.restServer, + waku.node, + waku.wakuDiscv5, + conf.restServerConf.get(), + conf.relay, + conf.lightPush, + conf.clusterId, + conf.subscribeShards, + conf.contentTopics, + ).isOkOr: + return err ("Starting protocols support REST server failed: " & $error) + + if conf.metricsServerConf.isSome(): + try: + let (server, port) = ( + await waku_metrics.startMetricsServerAndLogging( + conf.metricsServerConf.get(), conf.portsShift + ) + ).valueOr: + return err("Starting monitoring and external interfaces failed: " & error) + waku.metricsServer = server + waku.node.ports.metrics = port.uint16 + waku.conf.metricsServerConf.get().httpPort = port + except CatchableError: + return err( + "Caught exception starting monitoring and external interfaces failed: " & + getCurrentExceptionMsg() + ) + waku.healthMonitor.setOverallHealth(HealthStatus.READY) + + if not waku.messagingClient.isNil(): + waku.messagingClient.start().isOkOr: + return err("failed to start messaging client: " & $error) + + if not waku.reliableChannelManager.isNil(): + waku.reliableChannelManager.start().isOkOr: + return err("failed to start reliable channel manager: " & $error) + + return ok() + +# Notice this interface to be used only from LogosDelivery, hence not in the interface level. +proc stop*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = + if not waku.node.started: + warn "stop: attempting to stop node that isn't running" + + try: + waku.healthMonitor.setOverallHealth(HealthStatus.SHUTTING_DOWN) + + Persistency.reset() + + if not waku.metricsServer.isNil(): + await waku.metricsServer.stop() + + if not waku.wakuDiscv5.isNil(): + await waku.wakuDiscv5.stop() + + if not waku.reliableChannelManager.isNil(): + await waku.reliableChannelManager.stop() + + if not waku.messagingClient.isNil(): + await waku.messagingClient.stop() + + if not waku.node.isNil(): + await waku.node.stop() + + if not waku.dnsRetryLoopHandle.isNil(): + await waku.dnsRetryLoopHandle.cancelAndWait() + + if not waku.healthMonitor.isNil(): + await waku.healthMonitor.stopHealthMonitor() + + ## Clear RequestConnectionStatus provider + RequestConnectionStatus.clearProvider(waku.brokerCtx) + + if not waku.restServer.isNil(): + await waku.restServer.stop() + except Exception: + error "waku stop failed: " & getCurrentExceptionMsg() + return err("waku stop failed: " & getCurrentExceptionMsg()) + + return ok() + +{.pop.} + # end of `{.push raises: [].}` — kernel impl methods may propagate + # CatchableError (the BrokerImplement provider wrappers catch them). + +const FilterOpTimeout = 5.seconds + +BrokerImplement Waku of KernelInterface: + ## `new` is the BARE constructor (no ctx, no providers). Legacy callers keep + ## using `Waku.new(...)` unchanged — it is re-emitted verbatim by the macro + ## and returns a `globalBrokerContext`-bound node exactly as before, with the + ## kernel request-broker providers left unwired. `Waku.create(...)` / + ## `Waku.createUnderContext(...)` are additionally generated (async `Result` + ## shape) to wire the kernel under a fresh per-instance ctx when needed. + proc new*( + T: type Waku, wakuConf: WakuConf, appCallbacks: AppCallbacks = nil + ): Future[Result[Waku, string]] {.async.} = + let rng = crypto.newRng() + let brokerCtx = globalBrokerContext() + + logging.setupLog(wakuConf.logLevel, wakuConf.logFormat) + + ?wakuConf.validate() + wakuConf.logConf() + + let relay = newCircuitRelay(wakuConf.circuitRelayClient) + + let node = (await setupNode(wakuConf, rng, relay)).valueOr: + error "Failed setting up node", error = $error + return err("Failed setting up node: " & $error) + + let healthMonitor = NodeHealthMonitor.new(node, wakuConf.dnsAddrsNameServers) + + let restServer: WakuRestServerRef = + if wakuConf.restServerConf.isSome(): + let restServer = startRestServerEssentials( + healthMonitor, wakuConf.restServerConf.get(), wakuConf.portsShift + ).valueOr: + error "Starting essential REST server failed", error = $error + return err("Failed to start essential REST server in Waku.new: " & $error) + + restServer + else: + nil + + if not restServer.isNil(): + let boundRestPort = restServer.httpServer.address.port + node.ports.rest = boundRestPort.uint16 + wakuConf.restServerConf.get().port = boundRestPort + + # Set the extMultiAddrsOnly flag so the node knows not to replace explicit addresses + node.extMultiAddrsOnly = wakuConf.endpointConf.extMultiAddrsOnly + + node.setupAppCallbacks(wakuConf, appCallbacks, healthMonitor).isOkOr: + error "Failed setting up app callbacks", error = error + return err("Failed setting up app callbacks: " & $error) + + var waku = Waku( + stateInfo: WakuStateInfo.init(node), + conf: wakuConf, + rng: rng, + key: wakuConf.nodeKey, + node: node, + healthMonitor: healthMonitor, + appCallbacks: appCallbacks, + restServer: restServer, + brokerCtx: brokerCtx, + ) + + waku.setupSwitchServices(wakuConf, relay, rng) + + ok(waku) + + # --- topic construction --- + method buildContentTopic( + self: Waku, appName: string, appVersion: uint32, name: string, encoding: string + ): Future[Result[ContentTopic, string]] {.async.} = + try: + return ok(ContentTopic(fmt"/{appName}/{appVersion}/{name}/{encoding}")) + except CatchableError as e: + return err(e.msg) + + method buildPubsubTopic( + self: Waku, topicName: string + ): Future[Result[PubsubTopic, string]] {.async.} = + try: + return ok(PubsubTopic(fmt"/waku/2/{topicName}")) + except CatchableError as e: + return err(e.msg) + + method defaultPubsubTopic(self: Waku): Future[Result[PubsubTopic, string]] {.async.} = + return ok(DefaultPubsubTopic) + + # --- relay --- + method relayPublish( + self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, timeoutMs: uint32 + ): Future[Result[int, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayPublish: WakuRelay not mounted") + + let numPeers = (await self.node.wakuRelay.publish(pubsubTopic, message)).valueOr: + return err($error) + + return ok(numPeers) + except CatchableError as e: + return err(e.msg) + + method relaySubscribe( + self: Waku, pubsubTopic: PubsubTopic + ): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relaySubscribe: WakuRelay not mounted") + + let handler = proc(topic: PubsubTopic, msg: WakuMessage) {.async.} = + ## Bridge inbound relay traffic to the `ReceivedMessage` kernel event + ## (replaces libwaku's set_event_callback message path). + ReceivedMessage.emit( + self.brokerCtx, ReceivedMessage(pubsubTopic: topic, message: msg) + ) + + self.node.subscribe( + (kind: SubscriptionKind.PubsubSub, topic: pubsubTopic), + WakuRelayHandler(handler), + ).isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + + method relayUnsubscribe( + self: Waku, pubsubTopic: PubsubTopic + ): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayUnsubscribe: WakuRelay not mounted") + + self.node.unsubscribe((kind: SubscriptionKind.PubsubSub, topic: pubsubTopic)).isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + + method relayAddProtectedShard( + self: Waku, clusterId: uint16, shardId: uint16, publicKey: string + ): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayAddProtectedShard: WakuRelay not mounted") + + let pubKey = SkPublicKey.fromHex(publicKey).valueOr: + return err("relayAddProtectedShard: invalid public key: " & $error) + + let protectedShard = ProtectedShard(shard: shardId, key: pubKey) + self.node.wakuRelay.addSignedShardsValidator(@[protectedShard], clusterId) + return ok(true) + except CatchableError as e: + return err(e.msg) + + method relayConnectedPeers( + self: Waku, pubsubTopic: PubsubTopic + ): Future[Result[seq[string], string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayConnectedPeers: WakuRelay not mounted") + + let connPeers = self.node.wakuRelay.getConnectedPeers(pubsubTopic).valueOr: + return err($error) + + return ok(connPeers.mapIt($it)) + except CatchableError as e: + return err(e.msg) + + method relayPeersInMesh( + self: Waku, pubsubTopic: PubsubTopic + ): Future[Result[seq[string], string]] {.async.} = + try: + if self.node.wakuRelay.isNil(): + return err("relayPeersInMesh: WakuRelay not mounted") + + let meshPeers = self.node.wakuRelay.getPeersInMesh(pubsubTopic).valueOr: + return err($error) + + return ok(meshPeers.mapIt($it)) + except CatchableError as e: + return err(e.msg) + + # --- filter --- + method filterSubscribe( + self: Waku, + pubsubTopic: Option[PubsubTopic], + contentTopics: seq[ContentTopic], + peer: string, + ): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuFilterClient.isNil(): + return err("wakuFilterClient is not mounted") + + let subFut = self.node.filterSubscribe(pubsubTopic, contentTopics, peer) + if not await subFut.withTimeout(FilterOpTimeout): + return err("filter subscription timed out") + subFut.read().isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + + method filterUnsubscribe( + self: Waku, + pubsubTopic: Option[PubsubTopic], + contentTopics: seq[ContentTopic], + peer: string, + ): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuFilterClient.isNil(): + return err("wakuFilterClient is not mounted") + + let unsubFut = self.node.filterUnsubscribe(pubsubTopic, contentTopics, peer) + if not await unsubFut.withTimeout(FilterOpTimeout): + return err("filter un-subscription timed out") + unsubFut.read().isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + + method filterUnsubscribeAll( + self: Waku, peer: string + ): Future[Result[bool, string]] {.async.} = + try: + if self.node.wakuFilterClient.isNil(): + return err("wakuFilterClient is not mounted") + + let unsubFut = self.node.filterUnsubscribeAll(peer) + if not await unsubFut.withTimeout(FilterOpTimeout): + return err("filter un-subscription all timed out") + unsubFut.read().isOkOr: + return err($error) + + return ok(true) + except CatchableError as e: + return err(e.msg) + + # --- lightpush --- + method lightpushPublish( + self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, peer: string + ): Future[Result[string, string]] {.async.} = + try: + if self.node.wakuLegacyLightpushClient.isNil(): + return err("wakuLegacyLightpushClient is not mounted") + + let remotePeer = parsePeerInfo(peer).valueOr: + return err("lightpushPublish failed to parse peer addr: " & $error) + + let msgHashHex = ( + await self.node.wakuLegacyLightpushClient.publish( + pubsubTopic, message, remotePeer + ) + ).valueOr: + return err($error) + + return ok(msgHashHex) + except CatchableError as e: + return err(e.msg) + + # --- store --- + method storeQuery( + self: Waku, request: StoreQueryRequest, peer: string, timeoutMs: int + ): Future[Result[StoreQueryResponse, string]] {.async.} = + try: + if self.node.wakuStoreClient.isNil(): + return err("wakuStoreClient is not mounted") + + let remotePeer = parsePeerInfo(peer).valueOr: + return err("storeQuery failed to parse peer addr: " & $error) + + let queryFut = self.node.wakuStoreClient.query(request, remotePeer) + if not await queryFut.withTimeout(timeoutMs.milliseconds): + return err("storeQuery timed out") + + let queryResponse = queryFut.read().valueOr: + return err("storeQuery failed: " & $error) + + return ok(queryResponse) + except CatchableError as e: + return err(e.msg) + + # --- peer management --- + method connect( + self: Waku, peers: seq[string], timeoutMs: uint32 + ): Future[Result[bool, string]] {.async.} = + try: + await self.node.connectToNodes(peers.mapIt(strip(it)), source = "static") + return ok(true) + except CatchableError as e: + return err(e.msg) + + method disconnectPeerById( + self: Waku, peerId: string + ): Future[Result[bool, string]] {.async.} = + try: + let pId = PeerId.init(peerId).valueOr: + return err($error) + await self.node.peerManager.disconnectNode(pId) + return ok(true) + except CatchableError as e: + return err(e.msg) + + method disconnectAllPeers(self: Waku): Future[Result[bool, string]] {.async.} = + try: + await self.node.peerManager.disconnectAllPeers() + return ok(true) + except CatchableError as e: + return err(e.msg) + + method dialPeer( + self: Waku, peerAddr: string, protocol: string, timeoutMs: int + ): Future[Result[bool, string]] {.async.} = + try: + let remotePeerInfo = parsePeerInfo(peerAddr).valueOr: + return err($error) + let conn = await self.node.peerManager.dialPeer(remotePeerInfo, protocol) + if conn.isNone(): + return err("failed dialing peer") + return ok(true) + except CatchableError as e: + return err(e.msg) + + method dialPeerById( + self: Waku, peerId: string, protocol: string, timeoutMs: int + ): Future[Result[bool, string]] {.async.} = + try: + let pId = PeerId.init(peerId).valueOr: + return err($error) + let conn = await self.node.peerManager.dialPeer(pId, protocol) + if conn.isNone(): + return err("failed dialing peer") + return ok(true) + except CatchableError as e: + return err(e.msg) + + method peerIdsFromPeerstore( + self: Waku + ): Future[Result[seq[string], string]] {.async.} = + try: + return ok(self.node.peerManager.switch.peerStore.peers().mapIt($it.peerId)) + except CatchableError as e: + return err(e.msg) + + method connectedPeersInfo(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + return ok( + self.node.peerManager.switch.peerStore + .peers() + .filterIt(it.connectedness == Connected) + .mapIt($it.peerId) + ) + except CatchableError as e: + return err(e.msg) + + method connectedPeers(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + let (inPeerIds, outPeerIds) = self.node.peerManager.connectedPeers() + return ok(concat(inPeerIds, outPeerIds).mapIt($it)) + except CatchableError as e: + return err(e.msg) + + method peerIdsByProtocol( + self: Waku, protocol: string + ): Future[Result[seq[string], string]] {.async.} = + try: + return ok( + self.node.peerManager.switch.peerStore + .peers(protocol) + .filterIt(it.connectedness == Connected) + .mapIt($it.peerId) + ) + except CatchableError as e: + return err(e.msg) + + # --- discovery --- + method dnsDiscovery( + self: Waku, enrTreeUrl: string, nameServer: string, timeoutMs: int + ): Future[Result[seq[string], string]] {.async.} = + try: + let dnsNameServers = @[parseIpAddress(nameServer)] + let discoveredPeers = ( + await retrieveDynamicBootstrapNodes(enrTreeUrl, dnsNameServers) + ).valueOr: + return err("failed discovering peers from DNS: " & $error) + + var multiAddresses = newSeq[string]() + for discPeer in discoveredPeers: + for address in discPeer.addrs: + multiAddresses.add($address & "/p2p/" & $discPeer) + + return ok(multiAddresses) + except CatchableError as e: + return err(e.msg) + + method discv5UpdateBootnodes( + self: Waku, bootnodes: seq[string] + ): Future[Result[bool, string]] {.async.} = + try: + if self.wakuDiscv5.isNil(): + return err("discv5 not started") + let jsonArray = "[" & bootnodes.mapIt("\"" & it & "\"").join(",") & "]" + self.wakuDiscv5.updateBootstrapRecords(jsonArray).isOkOr: + return err("error in discv5UpdateBootnodes: " & $error) + return ok(true) + except CatchableError as e: + return err(e.msg) + + method startDiscv5(self: Waku): Future[Result[bool, string]] {.async.} = + try: + if self.wakuDiscv5.isNil(): + return err("discv5 not started") + (await self.wakuDiscv5.start()).isOkOr: + return err("error starting discv5: " & $error) + return ok(true) + except CatchableError as e: + return err(e.msg) + + method stopDiscv5(self: Waku): Future[Result[bool, string]] {.async.} = + try: + if self.wakuDiscv5.isNil(): + return err("discv5 not started") + await self.wakuDiscv5.stop() + return ok(true) + except CatchableError as e: + return err(e.msg) + + method peerExchangeRequest( + self: Waku, numPeers: uint64 + ): Future[Result[int, string]] {.async.} = + try: + let numPeersRecv = (await self.node.fetchPeerExchangePeers(numPeers)).valueOr: + return err("failed peer exchange: " & $error) + return ok(numPeersRecv) + except CatchableError as e: + return err(e.msg) + + # --- debug / info --- + method version(self: Waku): Future[Result[string, string]] {.async.} = + return ok(WakuNodeVersionString) + + method listenAddresses(self: Waku): Future[Result[seq[string], string]] {.async.} = + try: + return ok(self.node.info().listenAddresses) + except CatchableError as e: + return err(e.msg) + + method myEnr(self: Waku): Future[Result[string, string]] {.async.} = + try: + return ok(self.node.enr.toURI()) + except CatchableError as e: + return err(e.msg) + + method myPeerId(self: Waku): Future[Result[string, string]] {.async.} = + try: + return ok($self.node.peerId()) + except CatchableError as e: + return err(e.msg) + + method metrics(self: Waku): Future[Result[string, string]] {.async.} = + {.gcsafe.}: + try: + return ok(defaultRegistry.toText()) + except CatchableError as e: + return err(e.msg) + + method isOnline(self: Waku): Future[Result[bool, string]] {.async.} = + return ok(self.healthMonitor.onlineMonitor.amIOnline()) + + method pingPeer( + self: Waku, peerAddr: string, timeoutMs: int + ): Future[Result[int64, string]] {.async.} = + try: + let peerInfo = parsePeerInfo(peerAddr).valueOr: + return err("pingPeer failed to parse peer addr: " & $error) + + let conn = await self.node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec) + defer: + await conn.close() + let pingRTT = await self.node.libp2pPing.ping(conn) + + if pingRTT == 0.nanos: + return err("could not ping peer: rtt-0") + + return ok(pingRTT.nanos) + except CatchableError as e: + return err(e.msg) diff --git a/logos_delivery/waku/node/health_monitor/connection_status.nim b/logos_delivery/waku/node/health_monitor/connection_status.nim index fd0328fb7..3c1c5cf0f 100644 --- a/logos_delivery/waku/node/health_monitor/connection_status.nim +++ b/logos_delivery/waku/node/health_monitor/connection_status.nim @@ -1,5 +1,5 @@ import chronos, results, std/strutils -from logos_delivery/api/types import ConnectionStatus +import logos_delivery/api/types export ConnectionStatus diff --git a/logos_delivery/waku/waku.nim b/logos_delivery/waku/waku.nim index 0112d15d7..19a580fba 100644 --- a/logos_delivery/waku/waku.nim +++ b/logos_delivery/waku/waku.nim @@ -50,9 +50,6 @@ import factory/app_callbacks, persistency/persistency, factory/validator_signed, - waku_lightpush/client, - waku_lightpush_legacy/client, - waku_store/client, ], ./factory/waku_conf, ./factory/waku_state_info @@ -618,15 +615,8 @@ proc relaySubscribe*( if self.node.wakuRelay.isNil(): return err("relaySubscribe: WakuRelay not mounted") - let handler = proc(topic: PubsubTopic, msg: WakuMessage) {.async.} = - ## Bridge inbound relay traffic to the `ReceivedMessage` kernel event - ## (replaces libwaku's set_event_callback message path). - ReceivedMessage.emit( - self.brokerCtx, ReceivedMessage(pubsubTopic: topic, message: msg) - ) - self.node.subscribe( - (kind: SubscriptionKind.PubsubSub, topic: pubsubTopic), WakuRelayHandler(handler) + (kind: SubscriptionKind.PubsubSub, topic: pubsubTopic), WakuRelayHandler(nil) ).isOkOr: return err($error) @@ -976,9 +966,6 @@ proc metrics*(self: Waku): Future[Result[string, string]] {.async.} = except CatchableError as e: return err(e.msg) -proc isOnline*(self: Waku): Future[Result[bool, string]] {.async.} = - return ok(self.healthMonitor.onlineMonitor.amIOnline()) - proc pingPeer*( self: Waku, peerAddr: string, timeoutMs: int ): Future[Result[int64, string]] {.async.} = From 43b88cf8e7eb353d87cf6ba386836d36da2ed526 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 17:00:28 +0200 Subject: [PATCH 05/17] Make liblogosdelivery and wakunode2 compile, remove waku/api.nim as it was just a import orchestrator --- logos_delivery/api/types.nim | 2 + logos_delivery/logos_delivery.nim | 4 +- logos_delivery/waku/factory/waku.nim | 1034 -------------------------- logos_delivery/waku/waku.nim | 3 + 4 files changed, 7 insertions(+), 1036 deletions(-) delete mode 100644 logos_delivery/waku/factory/waku.nim diff --git a/logos_delivery/api/types.nim b/logos_delivery/api/types.nim index 5757a8e82..eef47557a 100644 --- a/logos_delivery/api/types.nim +++ b/logos_delivery/api/types.nim @@ -9,6 +9,8 @@ import logos_delivery/waku/waku_core/[topics/content_topic, message/message, tim export content_topic, message +export content_topic, message + type MessageEnvelope* = object contentTopic*: ContentTopic diff --git a/logos_delivery/logos_delivery.nim b/logos_delivery/logos_delivery.nim index 1c2682f76..f61202b9a 100644 --- a/logos_delivery/logos_delivery.nim +++ b/logos_delivery/logos_delivery.nim @@ -11,8 +11,6 @@ import results, chronos, chronicles -import logos_delivery/waku/api -export api import logos_delivery/waku/waku export waku import logos_delivery/messaging/messaging_client @@ -22,6 +20,8 @@ export reliable_channel_manager import logos_delivery/waku/factory/waku_conf import logos_delivery/waku/factory/app_callbacks +import tools/confutils/cli_args +import logos_delivery/waku/node/health_monitor/online_monitor logScope: topics = "logosdelivery" diff --git a/logos_delivery/waku/factory/waku.nim b/logos_delivery/waku/factory/waku.nim deleted file mode 100644 index a9a649ca8..000000000 --- a/logos_delivery/waku/factory/waku.nim +++ /dev/null @@ -1,1034 +0,0 @@ -import logos_delivery/waku/compat/option_valueor -{.push raises: [].} - -import - std/[options, sequtils, strformat, net, strutils], - results, - chronicles, - chronos, - secp256k1, - libp2p/protocols/ping, - libp2p/protocols/connectivity/relay/relay, - libp2p/protocols/connectivity/relay/client, - libp2p/wire, - libp2p/crypto/crypto, - libp2p/protocols/pubsub/gossipsub, - libp2p/services/autorelayservice, - libp2p/services/hpservice, - libp2p/peerid, - eth/keys, - eth/p2p/discoveryv5/enr, - presto, - metrics, - metrics/chronos_httpserver, - brokers/broker_context, - brokers/broker_implement, - logos_delivery/api/types, - logos_delivery/waku/[ - waku_core, - waku_node, - waku_archive, - waku_rln_relay, - waku_store, - waku_filter_v2, - waku_relay/protocol, - waku_enr/sharding, - waku_enr/multiaddr, - common/logging, - node/peer_manager, - node/health_monitor, - net/net_config, - node/waku_metrics, - node/subscription_manager, - rest_api/message_cache, - rest_api/endpoint/server, - rest_api/endpoint/builder as rest_server_builder, - discovery/waku_dnsdisc, - discovery/waku_discv5, - discovery/autonat_service, - requests/health_requests, - factory/node_factory, - factory/internal_config, - factory/app_callbacks, - persistency/persistency, - waku_lightpush_legacy/client, - waku_store/client as waku_store_client, - factory/validator_signed, - ], - logos_delivery/api/kernel_interface, - logos_delivery/channels/reliable_channel_manager, - logos_delivery/messaging/messaging_client, - ./waku_conf, - ./waku_state_info - -logScope: - topics = "wakunode waku" - -# Git version in git describe format (defined at compile time) -const git_version* {.strdefine.} = "n/a" - -type Waku* = ref object of KernelInterface - stateInfo*: WakuStateInfo - conf*: WakuConf - rng*: crypto.Rng - - key: crypto.PrivateKey - - wakuDiscv5*: WakuDiscoveryV5 - dynamicBootstrapNodes*: seq[RemotePeerInfo] - dnsRetryLoopHandle: Future[void] - networkConnLoopHandle: Future[void] - - node*: WakuNode - - # TODO: remove this indirection. Now kept for legacy. - healthMonitor*: NodeHealthMonitor - messagingClient*: MessagingClient - - reliableChannelManager*: ReliableChannelManager - - restServer*: WakuRestServerRef - metricsServer*: MetricsHttpServerRef - appCallbacks*: AppCallbacks - ## `brokerCtx` is inherited from the `KernelInterface` broker base. - -proc setupSwitchServices( - waku: Waku, conf: WakuConf, circuitRelay: Relay, rng: crypto.Rng -) = - proc onReservation(addresses: seq[MultiAddress]) {.gcsafe, raises: [].} = - info "circuit relay handler new reserve event", - addrs_before = $(waku.node.announcedAddresses), addrs = $addresses - - waku.node.announcedAddresses.setLen(0) ## remove previous addresses - waku.node.announcedAddresses.add(addresses) - info "waku node announced addresses updated", - announcedAddresses = waku.node.announcedAddresses - - if not isNil(waku.wakuDiscv5): - waku.wakuDiscv5.updateAnnouncedMultiAddress(addresses).isOkOr: - error "failed to update announced multiaddress", error = $error - - let autonatService = getAutonatService(rng) - if conf.circuitRelayClient: - ## The node is considered to be behind a NAT or firewall and then it - ## should struggle to be reachable and establish connections to other nodes - const MaxNumRelayServers = 2 - let autoRelayService = AutoRelayService.new( - MaxNumRelayServers, RelayClient(circuitRelay), onReservation, rng - ) - let holePunchService = HPService.new(autonatService, autoRelayService) - waku.node.switch.services = @[Service(holePunchService)] - else: - waku.node.switch.services = @[Service(autonatService)] - - # libp2p 2.0.0 split Service.setup out of Service.start: the switch runs setup - # only at build time (SwitchBuilder.setupServices), while switch.start calls - # just start. These services are created and attached post-build, so setup must - # be invoked explicitly here -- otherwise AutonatService.addressMapper stays nil - # and the peerInfo.update() inside start dereferences it (SIGSEGV). - for service in waku.node.switch.services: - try: - service.setup(waku.node.switch) - except ServiceSetupError as e: - error "failed to set up libp2p switch service", error = e.msg - -## Initialisation - -proc newCircuitRelay(isRelayClient: bool): Relay = - # TODO: Does it mean it's a circuit-relay server when it's false? - if isRelayClient: - return RelayClient.new() - return Relay.new() - -proc setupAppCallbacks( - node: WakuNode, - conf: WakuConf, - appCallbacks: AppCallbacks, - healthMonitor: NodeHealthMonitor, -): Result[void, string] = - if appCallbacks.isNil(): - info "No external callbacks to be set" - return ok() - - if not appCallbacks.relayHandler.isNil(): - if node.wakuRelay.isNil(): - return err("Cannot configure relayHandler callback without Relay mounted") - - let autoShards = - if node.wakuAutoSharding.isSome(): - node.getAutoshards(conf.contentTopics).valueOr: - return err("Could not get autoshards: " & error) - else: - @[] - - let confShards = conf.subscribeShards.mapIt( - RelayShard(clusterId: conf.clusterId, shardId: uint16(it)) - ) - let shards = confShards & autoShards - - let uniqueShards = deduplicate(shards) - - for shard in uniqueShards: - let topic = $shard - node.subscribe((kind: PubsubSub, topic: topic), appCallbacks.relayHandler).isOkOr: - return err(fmt"Could not subscribe {topic}: " & $error) - - if not appCallbacks.topicHealthChangeHandler.isNil(): - if node.wakuRelay.isNil(): - return - err("Cannot configure topicHealthChangeHandler callback without Relay mounted") - node.wakuRelay.onTopicHealthChange = appCallbacks.topicHealthChangeHandler - - if not appCallbacks.connectionChangeHandler.isNil(): - if node.peerManager.isNil(): - return - err("Cannot configure connectionChangeHandler callback with empty peer manager") - node.peerManager.onConnectionChange = appCallbacks.connectionChangeHandler - - if not appCallbacks.connectionStatusChangeHandler.isNil(): - if healthMonitor.isNil(): - return - err("Cannot configure connectionStatusChangeHandler with empty health monitor") - - healthMonitor.onConnectionStatusChange = appCallbacks.connectionStatusChangeHandler - - return ok() - -proc getPorts( - listenAddrs: seq[MultiAddress] -): Result[tuple[tcpPort, websocketPort, quicPort: Option[Port]], string] = - var tcpPort, websocketPort, quicPort = none(Port) - - for a in listenAddrs: - if a.isWsAddress(): - if websocketPort.isNone(): - let wsAddress = initTAddress(a).valueOr: - return err("getPorts wsAddr error:" & $error) - websocketPort = some(wsAddress.port) - elif a.isQuicAddress(): - if quicPort.isNone(): - let quicAddress = initTAddress(a).valueOr: - return err("getPorts quicAddr error:" & $error) - quicPort = some(quicAddress.port) - elif tcpPort.isNone(): - let tcpAddress = initTAddress(a).valueOr: - return err("getPorts tcpAddr error:" & $error) - tcpPort = some(tcpAddress.port) - - return ok((tcpPort: tcpPort, websocketPort: websocketPort, quicPort: quicPort)) - -proc getRunningNetConfig(waku: Waku): Future[Result[NetConfig, string]] {.async.} = - let conf = waku.conf - let (tcpPort, websocketPort, quicPort) = getPorts( - waku.node.switch.peerInfo.listenAddrs - ).valueOr: - return err("Could not retrieve ports: " & error) - - if tcpPort.isSome(): - conf.endpointConf.p2pTcpPort = tcpPort.get() - - if websocketPort.isSome() and conf.webSocketConf.isSome(): - conf.webSocketConf.get().port = websocketPort.get() - - if quicPort.isSome() and conf.quicConf.isSome(): - conf.quicConf.get().port = quicPort.get() - - # Rebuild NetConfig with bound port values - let netConf = ( - await networkConfiguration( - conf.clusterId, conf.endpointConf, conf.discv5Conf, conf.webSocketConf, - conf.quicConf, conf.wakuFlags, conf.dnsAddrsNameServers, conf.portsShift, clientId, - ) - ).valueOr: - return err("Could not update NetConfig: " & error) - - return ok(netConf) - -proc updateEnr(waku: Waku): Future[Result[void, string]] {.async.} = - let netConf: NetConfig = (await getRunningNetConfig(waku)).valueOr: - return err("error calling updateNetConfig: " & $error) - let record = enrConfiguration(waku.conf, netConf).valueOr: - return err("ENR setup failed: " & error) - - if isClusterMismatched(record, waku.conf.clusterId): - return err("cluster-id mismatch configured shards") - - waku.node.enr = record - - # If TCP/WS was configured with port 0, node.announcedAddresses was built - # pre-bind with a port value of 0. In any case, the resync is harmless. - waku.node.announcedAddresses = netConf.announcedAddresses - - return ok() - -proc updateAddressInENR(waku: Waku): Result[void, string] = - let addresses: seq[MultiAddress] = waku.node.announcedAddresses - let encodedAddrs = multiaddr.encodeMultiaddrs(addresses) - - ## First update the enr info contained in WakuNode - let keyBytes = waku.key.getRawBytes().valueOr: - return err("failed to retrieve raw bytes from waku key: " & $error) - - let parsedPk = keys.PrivateKey.fromHex(keyBytes.toHex()).valueOr: - return err("failed to parse the private key: " & $error) - - let enrFields = @[toFieldPair(MultiaddrEnrField, encodedAddrs)] - waku.node.enr.update(parsedPk, extraFields = enrFields).isOkOr: - return err("failed to update multiaddress in ENR updateAddressInENR: " & $error) - - info "Waku node ENR updated successfully with new multiaddress", - enr = waku.node.enr.toUri(), record = $(waku.node.enr) - - ## Now update the ENR infor in discv5 - if not waku.wakuDiscv5.isNil(): - waku.wakuDiscv5.protocol.localNode.record = waku.node.enr - let enr = waku.wakuDiscv5.protocol.localNode.record - - info "Waku discv5 ENR updated successfully with new multiaddress", - enr = enr.toUri(), record = $(enr) - - return ok() - -proc updateWaku(waku: Waku): Future[Result[void, string]] {.async.} = - (await updateEnr(waku)).isOkOr: - return err("error calling updateEnr: " & $error) - - ?updateAnnouncedAddrWithPrimaryIpAddr(waku.node) - - ?updateAddressInENR(waku) - - return ok() - -proc startDnsDiscoveryRetryLoop(waku: Waku): Future[void] {.async.} = - while true: - await sleepAsync(30.seconds) - if waku.conf.dnsDiscoveryConf.isSome(): - let dnsDiscoveryConf = waku.conf.dnsDiscoveryConf.get() - waku.dynamicBootstrapNodes = ( - await waku_dnsdisc.retrieveDynamicBootstrapNodes( - dnsDiscoveryConf.enrTreeUrl, dnsDiscoveryConf.nameServers - ) - ).valueOr: - error "Retrieving dynamic bootstrap nodes failed", error = error - continue - - if not waku.wakuDiscv5.isNil(): - let dynamicBootstrapEnrs = - waku.dynamicBootstrapNodes.filterIt(it.hasUdpPort()).mapIt(it.enr.get().toUri()) - var discv5BootstrapEnrs: seq[enr.Record] - # parse enrURIs from the configuration and add the resulting ENRs to the discv5BootstrapEnrs seq - for enrUri in dynamicBootstrapEnrs: - addBootstrapNode(enrUri, discv5BootstrapEnrs) - - waku.wakuDiscv5.updateBootstrapRecords( - waku.wakuDiscv5.protocol.bootstrapRecords & discv5BootstrapEnrs - ) - - info "Connecting to dynamic bootstrap peers" - try: - await connectToNodes(waku.node, waku.dynamicBootstrapNodes, "dynamic bootstrap") - except CatchableError: - error "failed to connect to dynamic bootstrap nodes: " & getCurrentExceptionMsg() - return - -# Notice this interface to be used only from LogosDelivery, hence not in the interface level. -proc start*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = - if waku.node.started: - warn "start: waku node already started" - return ok() - - info "Retrieve dynamic bootstrap nodes" - let conf = waku.conf - - if conf.dnsDiscoveryConf.isSome(): - let dnsDiscoveryConf = waku.conf.dnsDiscoveryConf.get() - let dynamicBootstrapNodesRes = - try: - await waku_dnsdisc.retrieveDynamicBootstrapNodes( - dnsDiscoveryConf.enrTreeUrl, dnsDiscoveryConf.nameServers - ) - except CatchableError as exc: - Result[seq[RemotePeerInfo], string].err( - "Retrieving dynamic bootstrap nodes failed: " & exc.msg - ) - - if dynamicBootstrapNodesRes.isErr(): - error "Retrieving dynamic bootstrap nodes failed", - error = dynamicBootstrapNodesRes.error - # Start Dns Discovery retry loop - waku.dnsRetryLoopHandle = waku.startDnsDiscoveryRetryLoop() - else: - waku.dynamicBootstrapNodes = dynamicBootstrapNodesRes.get() - - ## Initialize persistency singleton instance - we don't need the instance itself here, - ## but this ensures it's initialized before any store job starts. - discard Persistency.instance(conf.localStoragePath).valueOr: - error "Failed to initialize persistency instance", error = $error - return err("Failed to initialize persistency instance: " & $error) - - (await startNode(waku.node, waku.conf, waku.dynamicBootstrapNodes)).isOkOr: - return err("error while calling startNode: " & $error) - - let bound = getPorts(waku.node.switch.peerInfo.listenAddrs).valueOr: - return err("failed to read bound ports from switch: " & $error) - waku.node.ports.tcp = bound.tcpPort.get(Port(0)).uint16 - waku.node.ports.webSocket = bound.websocketPort.get(Port(0)).uint16 - waku.node.ports.quic = bound.quicPort.get(Port(0)).uint16 - - ## Discv5 - if conf.discv5Conf.isSome(): - waku.wakuDiscV5 = ( - await waku_discv5.setupAndStartDiscv5( - waku.node.enr, - waku.node.peerManager, - waku.node.topicSubscriptionQueue, - conf.discv5Conf.get(), - waku.dynamicBootstrapNodes, - waku.rng, - conf.nodeKey, - conf.endpointConf.p2pListenAddress, - conf.portsShift, - ) - ).valueOr: - return err("failed to start waku discovery v5: " & error) - - waku.node.ports.discv5Udp = waku.wakuDiscV5.udpPort.uint16 - waku.conf.discv5Conf.get().udpPort = waku.wakuDiscV5.udpPort - - ## Update waku data that is set dynamically on node start - try: - (await updateWaku(waku)).isOkOr: - return err("Error in start: " & $error) - except CatchableError: - return err("Caught exception in start: " & getCurrentExceptionMsg()) - - waku.node.subscriptionManager.subscribeAllAutoshards().isOkOr: - return err("failed to auto-subscribe autosharding shards: " & $error) - - ## Health Monitor - waku.healthMonitor.startHealthMonitor().isOkOr: - return err("failed to start health monitor: " & $error) - - ## Setup RequestConnectionStatus provider - - RequestConnectionStatus.setProvider( - globalBrokerContext(), - proc(): Result[RequestConnectionStatus, string] = - try: - let healthReport = waku.healthMonitor.getSyncNodeHealthReport() - return - ok(RequestConnectionStatus(connectionStatus: healthReport.connectionStatus)) - except CatchableError: - err("Failed to read health report: " & getCurrentExceptionMsg()), - ).isOkOr: - error "Failed to set RequestConnectionStatus provider", error = error - - ## Setup RequestProtocolHealth provider - - RequestProtocolHealth.setProvider( - globalBrokerContext(), - proc( - protocol: WakuProtocol - ): Future[Result[RequestProtocolHealth, string]] {.async.} = - try: - let protocolHealthStatus = - await waku.healthMonitor.getProtocolHealthInfo(protocol) - return ok(RequestProtocolHealth(healthStatus: protocolHealthStatus)) - except CatchableError: - return err("Failed to get protocol health: " & getCurrentExceptionMsg()), - ).isOkOr: - error "Failed to set RequestProtocolHealth provider", error = error - - ## Setup RequestHealthReport provider - - RequestHealthReport.setProvider( - globalBrokerContext(), - proc(): Future[Result[RequestHealthReport, string]] {.async.} = - try: - let report = await waku.healthMonitor.getNodeHealthReport() - return ok(RequestHealthReport(healthReport: report)) - except CatchableError: - return err("Failed to get health report: " & getCurrentExceptionMsg()), - ).isOkOr: - error "Failed to set RequestHealthReport provider", error = error - - if conf.restServerConf.isSome(): - rest_server_builder.startRestServerProtocolSupport( - waku.restServer, - waku.node, - waku.wakuDiscv5, - conf.restServerConf.get(), - conf.relay, - conf.lightPush, - conf.clusterId, - conf.subscribeShards, - conf.contentTopics, - ).isOkOr: - return err ("Starting protocols support REST server failed: " & $error) - - if conf.metricsServerConf.isSome(): - try: - let (server, port) = ( - await waku_metrics.startMetricsServerAndLogging( - conf.metricsServerConf.get(), conf.portsShift - ) - ).valueOr: - return err("Starting monitoring and external interfaces failed: " & error) - waku.metricsServer = server - waku.node.ports.metrics = port.uint16 - waku.conf.metricsServerConf.get().httpPort = port - except CatchableError: - return err( - "Caught exception starting monitoring and external interfaces failed: " & - getCurrentExceptionMsg() - ) - waku.healthMonitor.setOverallHealth(HealthStatus.READY) - - if not waku.messagingClient.isNil(): - waku.messagingClient.start().isOkOr: - return err("failed to start messaging client: " & $error) - - if not waku.reliableChannelManager.isNil(): - waku.reliableChannelManager.start().isOkOr: - return err("failed to start reliable channel manager: " & $error) - - return ok() - -# Notice this interface to be used only from LogosDelivery, hence not in the interface level. -proc stop*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = - if not waku.node.started: - warn "stop: attempting to stop node that isn't running" - - try: - waku.healthMonitor.setOverallHealth(HealthStatus.SHUTTING_DOWN) - - Persistency.reset() - - if not waku.metricsServer.isNil(): - await waku.metricsServer.stop() - - if not waku.wakuDiscv5.isNil(): - await waku.wakuDiscv5.stop() - - if not waku.reliableChannelManager.isNil(): - await waku.reliableChannelManager.stop() - - if not waku.messagingClient.isNil(): - await waku.messagingClient.stop() - - if not waku.node.isNil(): - await waku.node.stop() - - if not waku.dnsRetryLoopHandle.isNil(): - await waku.dnsRetryLoopHandle.cancelAndWait() - - if not waku.healthMonitor.isNil(): - await waku.healthMonitor.stopHealthMonitor() - - ## Clear RequestConnectionStatus provider - RequestConnectionStatus.clearProvider(waku.brokerCtx) - - if not waku.restServer.isNil(): - await waku.restServer.stop() - except Exception: - error "waku stop failed: " & getCurrentExceptionMsg() - return err("waku stop failed: " & getCurrentExceptionMsg()) - - return ok() - -{.pop.} - # end of `{.push raises: [].}` — kernel impl methods may propagate - # CatchableError (the BrokerImplement provider wrappers catch them). - -const FilterOpTimeout = 5.seconds - -BrokerImplement Waku of KernelInterface: - ## `new` is the BARE constructor (no ctx, no providers). Legacy callers keep - ## using `Waku.new(...)` unchanged — it is re-emitted verbatim by the macro - ## and returns a `globalBrokerContext`-bound node exactly as before, with the - ## kernel request-broker providers left unwired. `Waku.create(...)` / - ## `Waku.createUnderContext(...)` are additionally generated (async `Result` - ## shape) to wire the kernel under a fresh per-instance ctx when needed. - proc new*( - T: type Waku, wakuConf: WakuConf, appCallbacks: AppCallbacks = nil - ): Future[Result[Waku, string]] {.async.} = - let rng = crypto.newRng() - let brokerCtx = globalBrokerContext() - - logging.setupLog(wakuConf.logLevel, wakuConf.logFormat) - - ?wakuConf.validate() - wakuConf.logConf() - - let relay = newCircuitRelay(wakuConf.circuitRelayClient) - - let node = (await setupNode(wakuConf, rng, relay)).valueOr: - error "Failed setting up node", error = $error - return err("Failed setting up node: " & $error) - - let healthMonitor = NodeHealthMonitor.new(node, wakuConf.dnsAddrsNameServers) - - let restServer: WakuRestServerRef = - if wakuConf.restServerConf.isSome(): - let restServer = startRestServerEssentials( - healthMonitor, wakuConf.restServerConf.get(), wakuConf.portsShift - ).valueOr: - error "Starting essential REST server failed", error = $error - return err("Failed to start essential REST server in Waku.new: " & $error) - - restServer - else: - nil - - if not restServer.isNil(): - let boundRestPort = restServer.httpServer.address.port - node.ports.rest = boundRestPort.uint16 - wakuConf.restServerConf.get().port = boundRestPort - - # Set the extMultiAddrsOnly flag so the node knows not to replace explicit addresses - node.extMultiAddrsOnly = wakuConf.endpointConf.extMultiAddrsOnly - - node.setupAppCallbacks(wakuConf, appCallbacks, healthMonitor).isOkOr: - error "Failed setting up app callbacks", error = error - return err("Failed setting up app callbacks: " & $error) - - var waku = Waku( - stateInfo: WakuStateInfo.init(node), - conf: wakuConf, - rng: rng, - key: wakuConf.nodeKey, - node: node, - healthMonitor: healthMonitor, - appCallbacks: appCallbacks, - restServer: restServer, - brokerCtx: brokerCtx, - ) - - waku.setupSwitchServices(wakuConf, relay, rng) - - ok(waku) - - # --- topic construction --- - method buildContentTopic( - self: Waku, appName: string, appVersion: uint32, name: string, encoding: string - ): Future[Result[ContentTopic, string]] {.async.} = - try: - return ok(ContentTopic(fmt"/{appName}/{appVersion}/{name}/{encoding}")) - except CatchableError as e: - return err(e.msg) - - method buildPubsubTopic( - self: Waku, topicName: string - ): Future[Result[PubsubTopic, string]] {.async.} = - try: - return ok(PubsubTopic(fmt"/waku/2/{topicName}")) - except CatchableError as e: - return err(e.msg) - - method defaultPubsubTopic(self: Waku): Future[Result[PubsubTopic, string]] {.async.} = - return ok(DefaultPubsubTopic) - - # --- relay --- - method relayPublish( - self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, timeoutMs: uint32 - ): Future[Result[int, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayPublish: WakuRelay not mounted") - - let numPeers = (await self.node.wakuRelay.publish(pubsubTopic, message)).valueOr: - return err($error) - - return ok(numPeers) - except CatchableError as e: - return err(e.msg) - - method relaySubscribe( - self: Waku, pubsubTopic: PubsubTopic - ): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relaySubscribe: WakuRelay not mounted") - - let handler = proc(topic: PubsubTopic, msg: WakuMessage) {.async.} = - ## Bridge inbound relay traffic to the `ReceivedMessage` kernel event - ## (replaces libwaku's set_event_callback message path). - ReceivedMessage.emit( - self.brokerCtx, ReceivedMessage(pubsubTopic: topic, message: msg) - ) - - self.node.subscribe( - (kind: SubscriptionKind.PubsubSub, topic: pubsubTopic), - WakuRelayHandler(handler), - ).isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - - method relayUnsubscribe( - self: Waku, pubsubTopic: PubsubTopic - ): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayUnsubscribe: WakuRelay not mounted") - - self.node.unsubscribe((kind: SubscriptionKind.PubsubSub, topic: pubsubTopic)).isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - - method relayAddProtectedShard( - self: Waku, clusterId: uint16, shardId: uint16, publicKey: string - ): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayAddProtectedShard: WakuRelay not mounted") - - let pubKey = SkPublicKey.fromHex(publicKey).valueOr: - return err("relayAddProtectedShard: invalid public key: " & $error) - - let protectedShard = ProtectedShard(shard: shardId, key: pubKey) - self.node.wakuRelay.addSignedShardsValidator(@[protectedShard], clusterId) - return ok(true) - except CatchableError as e: - return err(e.msg) - - method relayConnectedPeers( - self: Waku, pubsubTopic: PubsubTopic - ): Future[Result[seq[string], string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayConnectedPeers: WakuRelay not mounted") - - let connPeers = self.node.wakuRelay.getConnectedPeers(pubsubTopic).valueOr: - return err($error) - - return ok(connPeers.mapIt($it)) - except CatchableError as e: - return err(e.msg) - - method relayPeersInMesh( - self: Waku, pubsubTopic: PubsubTopic - ): Future[Result[seq[string], string]] {.async.} = - try: - if self.node.wakuRelay.isNil(): - return err("relayPeersInMesh: WakuRelay not mounted") - - let meshPeers = self.node.wakuRelay.getPeersInMesh(pubsubTopic).valueOr: - return err($error) - - return ok(meshPeers.mapIt($it)) - except CatchableError as e: - return err(e.msg) - - # --- filter --- - method filterSubscribe( - self: Waku, - pubsubTopic: Option[PubsubTopic], - contentTopics: seq[ContentTopic], - peer: string, - ): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuFilterClient.isNil(): - return err("wakuFilterClient is not mounted") - - let subFut = self.node.filterSubscribe(pubsubTopic, contentTopics, peer) - if not await subFut.withTimeout(FilterOpTimeout): - return err("filter subscription timed out") - subFut.read().isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - - method filterUnsubscribe( - self: Waku, - pubsubTopic: Option[PubsubTopic], - contentTopics: seq[ContentTopic], - peer: string, - ): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuFilterClient.isNil(): - return err("wakuFilterClient is not mounted") - - let unsubFut = self.node.filterUnsubscribe(pubsubTopic, contentTopics, peer) - if not await unsubFut.withTimeout(FilterOpTimeout): - return err("filter un-subscription timed out") - unsubFut.read().isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - - method filterUnsubscribeAll( - self: Waku, peer: string - ): Future[Result[bool, string]] {.async.} = - try: - if self.node.wakuFilterClient.isNil(): - return err("wakuFilterClient is not mounted") - - let unsubFut = self.node.filterUnsubscribeAll(peer) - if not await unsubFut.withTimeout(FilterOpTimeout): - return err("filter un-subscription all timed out") - unsubFut.read().isOkOr: - return err($error) - - return ok(true) - except CatchableError as e: - return err(e.msg) - - # --- lightpush --- - method lightpushPublish( - self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, peer: string - ): Future[Result[string, string]] {.async.} = - try: - if self.node.wakuLegacyLightpushClient.isNil(): - return err("wakuLegacyLightpushClient is not mounted") - - let remotePeer = parsePeerInfo(peer).valueOr: - return err("lightpushPublish failed to parse peer addr: " & $error) - - let msgHashHex = ( - await self.node.wakuLegacyLightpushClient.publish( - pubsubTopic, message, remotePeer - ) - ).valueOr: - return err($error) - - return ok(msgHashHex) - except CatchableError as e: - return err(e.msg) - - # --- store --- - method storeQuery( - self: Waku, request: StoreQueryRequest, peer: string, timeoutMs: int - ): Future[Result[StoreQueryResponse, string]] {.async.} = - try: - if self.node.wakuStoreClient.isNil(): - return err("wakuStoreClient is not mounted") - - let remotePeer = parsePeerInfo(peer).valueOr: - return err("storeQuery failed to parse peer addr: " & $error) - - let queryFut = self.node.wakuStoreClient.query(request, remotePeer) - if not await queryFut.withTimeout(timeoutMs.milliseconds): - return err("storeQuery timed out") - - let queryResponse = queryFut.read().valueOr: - return err("storeQuery failed: " & $error) - - return ok(queryResponse) - except CatchableError as e: - return err(e.msg) - - # --- peer management --- - method connect( - self: Waku, peers: seq[string], timeoutMs: uint32 - ): Future[Result[bool, string]] {.async.} = - try: - await self.node.connectToNodes(peers.mapIt(strip(it)), source = "static") - return ok(true) - except CatchableError as e: - return err(e.msg) - - method disconnectPeerById( - self: Waku, peerId: string - ): Future[Result[bool, string]] {.async.} = - try: - let pId = PeerId.init(peerId).valueOr: - return err($error) - await self.node.peerManager.disconnectNode(pId) - return ok(true) - except CatchableError as e: - return err(e.msg) - - method disconnectAllPeers(self: Waku): Future[Result[bool, string]] {.async.} = - try: - await self.node.peerManager.disconnectAllPeers() - return ok(true) - except CatchableError as e: - return err(e.msg) - - method dialPeer( - self: Waku, peerAddr: string, protocol: string, timeoutMs: int - ): Future[Result[bool, string]] {.async.} = - try: - let remotePeerInfo = parsePeerInfo(peerAddr).valueOr: - return err($error) - let conn = await self.node.peerManager.dialPeer(remotePeerInfo, protocol) - if conn.isNone(): - return err("failed dialing peer") - return ok(true) - except CatchableError as e: - return err(e.msg) - - method dialPeerById( - self: Waku, peerId: string, protocol: string, timeoutMs: int - ): Future[Result[bool, string]] {.async.} = - try: - let pId = PeerId.init(peerId).valueOr: - return err($error) - let conn = await self.node.peerManager.dialPeer(pId, protocol) - if conn.isNone(): - return err("failed dialing peer") - return ok(true) - except CatchableError as e: - return err(e.msg) - - method peerIdsFromPeerstore( - self: Waku - ): Future[Result[seq[string], string]] {.async.} = - try: - return ok(self.node.peerManager.switch.peerStore.peers().mapIt($it.peerId)) - except CatchableError as e: - return err(e.msg) - - method connectedPeersInfo(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - return ok( - self.node.peerManager.switch.peerStore - .peers() - .filterIt(it.connectedness == Connected) - .mapIt($it.peerId) - ) - except CatchableError as e: - return err(e.msg) - - method connectedPeers(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - let (inPeerIds, outPeerIds) = self.node.peerManager.connectedPeers() - return ok(concat(inPeerIds, outPeerIds).mapIt($it)) - except CatchableError as e: - return err(e.msg) - - method peerIdsByProtocol( - self: Waku, protocol: string - ): Future[Result[seq[string], string]] {.async.} = - try: - return ok( - self.node.peerManager.switch.peerStore - .peers(protocol) - .filterIt(it.connectedness == Connected) - .mapIt($it.peerId) - ) - except CatchableError as e: - return err(e.msg) - - # --- discovery --- - method dnsDiscovery( - self: Waku, enrTreeUrl: string, nameServer: string, timeoutMs: int - ): Future[Result[seq[string], string]] {.async.} = - try: - let dnsNameServers = @[parseIpAddress(nameServer)] - let discoveredPeers = ( - await retrieveDynamicBootstrapNodes(enrTreeUrl, dnsNameServers) - ).valueOr: - return err("failed discovering peers from DNS: " & $error) - - var multiAddresses = newSeq[string]() - for discPeer in discoveredPeers: - for address in discPeer.addrs: - multiAddresses.add($address & "/p2p/" & $discPeer) - - return ok(multiAddresses) - except CatchableError as e: - return err(e.msg) - - method discv5UpdateBootnodes( - self: Waku, bootnodes: seq[string] - ): Future[Result[bool, string]] {.async.} = - try: - if self.wakuDiscv5.isNil(): - return err("discv5 not started") - let jsonArray = "[" & bootnodes.mapIt("\"" & it & "\"").join(",") & "]" - self.wakuDiscv5.updateBootstrapRecords(jsonArray).isOkOr: - return err("error in discv5UpdateBootnodes: " & $error) - return ok(true) - except CatchableError as e: - return err(e.msg) - - method startDiscv5(self: Waku): Future[Result[bool, string]] {.async.} = - try: - if self.wakuDiscv5.isNil(): - return err("discv5 not started") - (await self.wakuDiscv5.start()).isOkOr: - return err("error starting discv5: " & $error) - return ok(true) - except CatchableError as e: - return err(e.msg) - - method stopDiscv5(self: Waku): Future[Result[bool, string]] {.async.} = - try: - if self.wakuDiscv5.isNil(): - return err("discv5 not started") - await self.wakuDiscv5.stop() - return ok(true) - except CatchableError as e: - return err(e.msg) - - method peerExchangeRequest( - self: Waku, numPeers: uint64 - ): Future[Result[int, string]] {.async.} = - try: - let numPeersRecv = (await self.node.fetchPeerExchangePeers(numPeers)).valueOr: - return err("failed peer exchange: " & $error) - return ok(numPeersRecv) - except CatchableError as e: - return err(e.msg) - - # --- debug / info --- - method version(self: Waku): Future[Result[string, string]] {.async.} = - return ok(WakuNodeVersionString) - - method listenAddresses(self: Waku): Future[Result[seq[string], string]] {.async.} = - try: - return ok(self.node.info().listenAddresses) - except CatchableError as e: - return err(e.msg) - - method myEnr(self: Waku): Future[Result[string, string]] {.async.} = - try: - return ok(self.node.enr.toURI()) - except CatchableError as e: - return err(e.msg) - - method myPeerId(self: Waku): Future[Result[string, string]] {.async.} = - try: - return ok($self.node.peerId()) - except CatchableError as e: - return err(e.msg) - - method metrics(self: Waku): Future[Result[string, string]] {.async.} = - {.gcsafe.}: - try: - return ok(defaultRegistry.toText()) - except CatchableError as e: - return err(e.msg) - - method isOnline(self: Waku): Future[Result[bool, string]] {.async.} = - return ok(self.healthMonitor.onlineMonitor.amIOnline()) - - method pingPeer( - self: Waku, peerAddr: string, timeoutMs: int - ): Future[Result[int64, string]] {.async.} = - try: - let peerInfo = parsePeerInfo(peerAddr).valueOr: - return err("pingPeer failed to parse peer addr: " & $error) - - let conn = await self.node.switch.dial(peerInfo.peerId, peerInfo.addrs, PingCodec) - defer: - await conn.close() - let pingRTT = await self.node.libp2pPing.ping(conn) - - if pingRTT == 0.nanos: - return err("could not ping peer: rtt-0") - - return ok(pingRTT.nanos) - except CatchableError as e: - return err(e.msg) diff --git a/logos_delivery/waku/waku.nim b/logos_delivery/waku/waku.nim index 19a580fba..2c18c5f63 100644 --- a/logos_delivery/waku/waku.nim +++ b/logos_delivery/waku/waku.nim @@ -50,6 +50,9 @@ import factory/app_callbacks, persistency/persistency, factory/validator_signed, + waku_lightpush/client, + waku_lightpush_legacy/client, + waku_store/client, ], ./factory/waku_conf, ./factory/waku_state_info From 59c3a366893497bb208025b39061677d490613fb Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 18:20:45 +0200 Subject: [PATCH 06/17] make test compile and run --- logos_delivery/api/types.nim | 2 - .../node/health_monitor/connection_status.nim | 2 +- tests/api/test_api_subscription.nim | 52 +++++-------------- 3 files changed, 14 insertions(+), 42 deletions(-) diff --git a/logos_delivery/api/types.nim b/logos_delivery/api/types.nim index eef47557a..5757a8e82 100644 --- a/logos_delivery/api/types.nim +++ b/logos_delivery/api/types.nim @@ -9,8 +9,6 @@ import logos_delivery/waku/waku_core/[topics/content_topic, message/message, tim export content_topic, message -export content_topic, message - type MessageEnvelope* = object contentTopic*: ContentTopic diff --git a/logos_delivery/waku/node/health_monitor/connection_status.nim b/logos_delivery/waku/node/health_monitor/connection_status.nim index 3c1c5cf0f..fd0328fb7 100644 --- a/logos_delivery/waku/node/health_monitor/connection_status.nim +++ b/logos_delivery/waku/node/health_monitor/connection_status.nim @@ -1,5 +1,5 @@ import chronos, results, std/strutils -import logos_delivery/api/types +from logos_delivery/api/types import ConnectionStatus export ConnectionStatus diff --git a/tests/api/test_api_subscription.nim b/tests/api/test_api_subscription.nim index bf2851b02..d6a9c6c60 100644 --- a/tests/api/test_api_subscription.nim +++ b/tests/api/test_api_subscription.nim @@ -248,9 +248,7 @@ suite "Messaging API, SubscriptionManager": let subbedTopic = ContentTopic("/waku/2/subbed-topic/proto") let ignoredTopic = ContentTopic("/waku/2/ignored-topic/proto") - (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect( - "failed to subscribe" - ) + (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect("failed to subscribe") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -270,12 +268,8 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/unsub-test/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect( - "failed to subscribe" - ) - net.subscriber.messagingClient.unsubscribe(testTopic).expect( - "failed to unsubscribe" - ) + (await net.subscriber.messagingClient.subscribe(testTopic)).expect("failed to subscribe") + net.subscriber.messagingClient.unsubscribe(testTopic).expect("failed to unsubscribe") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -321,12 +315,8 @@ suite "Messaging API, SubscriptionManager": let glitchTopic = ContentTopic("/waku/2/glitch/proto") - (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect( - "failed to sub" - ) - (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect( - "failed to double sub" - ) + (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect("failed to sub") + (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect("failed to double sub") net.subscriber.messagingClient.unsubscribe(glitchTopic).expect("failed to unsub") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) @@ -348,9 +338,7 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/resub-test/proto") # Subscribe - (await net.subscriber.messagingClient.subscribe(testTopic)).expect( - "Initial sub failed" - ) + (await net.subscriber.messagingClient.subscribe(testTopic)).expect("Initial sub failed") var eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) discard @@ -482,9 +470,7 @@ suite "Messaging API, SubscriptionManager": await net.teardown() let testTopic = ContentTopic("/waku/2/test-content/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect( - "failed to subscribe" - ) + (await net.subscriber.messagingClient.subscribe(testTopic)).expect("failed to subscribe") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -505,9 +491,7 @@ suite "Messaging API, SubscriptionManager": let subbedTopic = ContentTopic("/waku/2/subbed-topic/proto") let ignoredTopic = ContentTopic("/waku/2/ignored-topic/proto") - (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect( - "failed to subscribe" - ) + (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect("failed to subscribe") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -527,12 +511,8 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/unsub-test/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect( - "failed to subscribe" - ) - net.subscriber.messagingClient.unsubscribe(testTopic).expect( - "failed to unsubscribe" - ) + (await net.subscriber.messagingClient.subscribe(testTopic)).expect("failed to subscribe") + net.subscriber.messagingClient.unsubscribe(testTopic).expect("failed to unsubscribe") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -581,9 +561,7 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/resub-test/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect( - "Initial sub failed" - ) + (await net.subscriber.messagingClient.subscribe(testTopic)).expect("Initial sub failed") var eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) discard (await net.publishToMeshAfterEdgeReady(testTopic, "Msg 1".toBytes())).expect( @@ -675,9 +653,7 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/failover-test/proto") let shard = subscriber.waku.node.getRelayShard(testTopic) - (await subscriber.messagingClient.subscribe(testTopic)).expect( - "Failed to subscribe" - ) + (await subscriber.messagingClient.subscribe(testTopic)).expect("Failed to subscribe") # Wait for dialing both filter servers (HealthyThreshold = 2) check await edgePeersReached(subscriber, shard, 2) @@ -807,9 +783,7 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/replacement-test/proto") let shard = subscriber.waku.node.getRelayShard(testTopic) - (await subscriber.messagingClient.subscribe(testTopic)).expect( - "Failed to subscribe" - ) + (await subscriber.messagingClient.subscribe(testTopic)).expect("Failed to subscribe") # Wait for 2 confirmed peers (HealthyThreshold). The 3rd is available but not dialed. check await edgePeersReached(subscriber, shard, 2) From 9e58cfa139d13ac2d2c6faa76a565434b1e3dba6 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 22:38:19 +0200 Subject: [PATCH 07/17] nph fix --- library/kernel_api/ping_api.nim | 4 +-- tests/api/test_api_subscription.nim | 52 +++++++++++++++++++++-------- 2 files changed, 40 insertions(+), 16 deletions(-) diff --git a/library/kernel_api/ping_api.nim b/library/kernel_api/ping_api.nim index 14db0eb53..e6ed69dd1 100644 --- a/library/kernel_api/ping_api.nim +++ b/library/kernel_api/ping_api.nim @@ -1,9 +1,7 @@ import std/[json, strutils] import chronos, results, ffi import libp2p/[protocols/ping, switch, multiaddress, multicodec] -import - logos_delivery/waku/[waku, waku_core/peers, node/waku_node], - library/declare_lib +import logos_delivery/waku/[waku, waku_core/peers, node/waku_node], library/declare_lib proc waku_ping_peer( ctx: ptr FFIContext[LogosDelivery], diff --git a/tests/api/test_api_subscription.nim b/tests/api/test_api_subscription.nim index d6a9c6c60..bf2851b02 100644 --- a/tests/api/test_api_subscription.nim +++ b/tests/api/test_api_subscription.nim @@ -248,7 +248,9 @@ suite "Messaging API, SubscriptionManager": let subbedTopic = ContentTopic("/waku/2/subbed-topic/proto") let ignoredTopic = ContentTopic("/waku/2/ignored-topic/proto") - (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect("failed to subscribe") + (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect( + "failed to subscribe" + ) let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -268,8 +270,12 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/unsub-test/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect("failed to subscribe") - net.subscriber.messagingClient.unsubscribe(testTopic).expect("failed to unsubscribe") + (await net.subscriber.messagingClient.subscribe(testTopic)).expect( + "failed to subscribe" + ) + net.subscriber.messagingClient.unsubscribe(testTopic).expect( + "failed to unsubscribe" + ) let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -315,8 +321,12 @@ suite "Messaging API, SubscriptionManager": let glitchTopic = ContentTopic("/waku/2/glitch/proto") - (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect("failed to sub") - (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect("failed to double sub") + (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect( + "failed to sub" + ) + (await net.subscriber.messagingClient.subscribe(glitchTopic)).expect( + "failed to double sub" + ) net.subscriber.messagingClient.unsubscribe(glitchTopic).expect("failed to unsub") let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) @@ -338,7 +348,9 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/resub-test/proto") # Subscribe - (await net.subscriber.messagingClient.subscribe(testTopic)).expect("Initial sub failed") + (await net.subscriber.messagingClient.subscribe(testTopic)).expect( + "Initial sub failed" + ) var eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) discard @@ -470,7 +482,9 @@ suite "Messaging API, SubscriptionManager": await net.teardown() let testTopic = ContentTopic("/waku/2/test-content/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect("failed to subscribe") + (await net.subscriber.messagingClient.subscribe(testTopic)).expect( + "failed to subscribe" + ) let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -491,7 +505,9 @@ suite "Messaging API, SubscriptionManager": let subbedTopic = ContentTopic("/waku/2/subbed-topic/proto") let ignoredTopic = ContentTopic("/waku/2/ignored-topic/proto") - (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect("failed to subscribe") + (await net.subscriber.messagingClient.subscribe(subbedTopic)).expect( + "failed to subscribe" + ) let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -511,8 +527,12 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/unsub-test/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect("failed to subscribe") - net.subscriber.messagingClient.unsubscribe(testTopic).expect("failed to unsubscribe") + (await net.subscriber.messagingClient.subscribe(testTopic)).expect( + "failed to subscribe" + ) + net.subscriber.messagingClient.unsubscribe(testTopic).expect( + "failed to unsubscribe" + ) let eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) defer: @@ -561,7 +581,9 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/resub-test/proto") - (await net.subscriber.messagingClient.subscribe(testTopic)).expect("Initial sub failed") + (await net.subscriber.messagingClient.subscribe(testTopic)).expect( + "Initial sub failed" + ) var eventManager = newReceiveEventListenerManager(net.subscriber.waku.brokerCtx, 1) discard (await net.publishToMeshAfterEdgeReady(testTopic, "Msg 1".toBytes())).expect( @@ -653,7 +675,9 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/failover-test/proto") let shard = subscriber.waku.node.getRelayShard(testTopic) - (await subscriber.messagingClient.subscribe(testTopic)).expect("Failed to subscribe") + (await subscriber.messagingClient.subscribe(testTopic)).expect( + "Failed to subscribe" + ) # Wait for dialing both filter servers (HealthyThreshold = 2) check await edgePeersReached(subscriber, shard, 2) @@ -783,7 +807,9 @@ suite "Messaging API, SubscriptionManager": let testTopic = ContentTopic("/waku/2/replacement-test/proto") let shard = subscriber.waku.node.getRelayShard(testTopic) - (await subscriber.messagingClient.subscribe(testTopic)).expect("Failed to subscribe") + (await subscriber.messagingClient.subscribe(testTopic)).expect( + "Failed to subscribe" + ) # Wait for 2 confirmed peers (HealthyThreshold). The 3rd is available but not dialed. check await edgePeersReached(subscriber, shard, 2) From eb5b82de2bbc9f7c8667e82c3a6b8f6e54429680 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Tue, 23 Jun 2026 22:37:05 +0200 Subject: [PATCH 08/17] Initial add of api layers interface classes --- logos_delivery/api/kernel_api.nim | 195 ++++++++++++++++++ logos_delivery/api/messaging_client_api.nim | 19 ++ .../api/reliable_cannel_manager_api.nim | 28 +++ .../channels/reliable_channel_manager.nim | 13 +- logos_delivery/messaging/messaging_client.nim | 31 +-- logos_delivery/waku/waku.nim | 127 +++++++----- 6 files changed, 335 insertions(+), 78 deletions(-) create mode 100644 logos_delivery/api/kernel_api.nim create mode 100644 logos_delivery/api/messaging_client_api.nim create mode 100644 logos_delivery/api/reliable_cannel_manager_api.nim diff --git a/logos_delivery/api/kernel_api.nim b/logos_delivery/api/kernel_api.nim new file mode 100644 index 000000000..4c1a838bb --- /dev/null +++ b/logos_delivery/api/kernel_api.nim @@ -0,0 +1,195 @@ +import std/options +import chronos, results +import logos_delivery/api/types +import logos_delivery/waku/waku_core/topics/pubsub_topic +import logos_delivery/waku/waku_store/common + +type IKernel* = ref object of RootObj + +# --- topic construction --- +method buildContentTopic*( + self: IKernel, + appName: string, + appVersion: uint32, + name: string, + encoding: string, +): Future[Result[ContentTopic, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.buildContentTopic not implemented") + +method buildPubsubTopic*( + self: IKernel, topicName: string +): Future[Result[PubsubTopic, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.buildPubsubTopic not implemented") + +method defaultPubsubTopic*( + self: IKernel +): Future[Result[PubsubTopic, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.defaultPubsubTopic not implemented") + +# --- relay --- +method relayPublish*( + self: IKernel, pubsubTopic: PubsubTopic, message: WakuMessage, timeoutMs: uint32 +): Future[Result[int, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.relayPublish not implemented") + +method relaySubscribe*( + self: IKernel, pubsubTopic: PubsubTopic +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.relaySubscribe not implemented") + +method relayUnsubscribe*( + self: IKernel, pubsubTopic: PubsubTopic +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.relayUnsubscribe not implemented") + +method relayAddProtectedShard*( + self: IKernel, clusterId: uint16, shardId: uint16, publicKey: string +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.relayAddProtectedShard not implemented") + +method relayConnectedPeers*( + self: IKernel, pubsubTopic: PubsubTopic +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.relayConnectedPeers not implemented") + +method relayPeersInMesh*( + self: IKernel, pubsubTopic: PubsubTopic +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.relayPeersInMesh not implemented") + +# --- filter --- +method filterSubscribe*( + self: IKernel, + pubsubTopic: Option[PubsubTopic], + contentTopics: seq[ContentTopic], + peer: string, +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.filterSubscribe not implemented") + +method filterUnsubscribe*( + self: IKernel, + pubsubTopic: Option[PubsubTopic], + contentTopics: seq[ContentTopic], + peer: string, +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.filterUnsubscribe not implemented") + +method filterUnsubscribeAll*( + self: IKernel, peer: string +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.filterUnsubscribeAll not implemented") + +# --- lightpush --- +method lightpushPublish*( + self: IKernel, pubsubTopic: PubsubTopic, message: WakuMessage, peer: string +): Future[Result[string, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.lightpushPublish not implemented") + +# --- store --- +method storeQuery*( + self: IKernel, request: StoreQueryRequest, peer: string, timeoutMs: int +): Future[Result[StoreQueryResponse, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.storeQuery not implemented") + +# --- peer management --- +method connect*( + self: IKernel, peers: seq[string], timeoutMs: uint32 +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.connect not implemented") + +method disconnectPeerById*( + self: IKernel, peerId: string +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.disconnectPeerById not implemented") + +method disconnectAllPeers*( + self: IKernel +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.disconnectAllPeers not implemented") + +method dialPeer*( + self: IKernel, peerAddr: string, protocol: string, timeoutMs: int +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.dialPeer not implemented") + +method dialPeerById*( + self: IKernel, peerId: string, protocol: string, timeoutMs: int +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.dialPeerById not implemented") + +method peerIdsFromPeerstore*( + self: IKernel +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.peerIdsFromPeerstore not implemented") + +method connectedPeersInfo*( + self: IKernel +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.connectedPeersInfo not implemented") + +method connectedPeers*( + self: IKernel +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.connectedPeers not implemented") + +method peerIdsByProtocol*( + self: IKernel, protocol: string +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.peerIdsByProtocol not implemented") + +# --- discovery --- +method dnsDiscovery*( + self: IKernel, enrTreeUrl: string, nameServer: string, timeoutMs: int +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.dnsDiscovery not implemented") + +method discv5UpdateBootnodes*( + self: IKernel, bootnodes: seq[string] +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.discv5UpdateBootnodes not implemented") + +method startDiscv5*( + self: IKernel +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.startDiscv5 not implemented") + +method stopDiscv5*( + self: IKernel +): Future[Result[bool, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.stopDiscv5 not implemented") + +method peerExchangeRequest*( + self: IKernel, numPeers: uint64 +): Future[Result[int, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.peerExchangeRequest not implemented") + +# --- debug / info --- +method version*( + self: IKernel +): Future[Result[string, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.version not implemented") + +method listenAddresses*( + self: IKernel +): Future[Result[seq[string], string]] {.async: (raises: []), base.} = + return err("Interface IKernel.listenAddresses not implemented") + +method myEnr*( + self: IKernel +): Future[Result[string, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.myEnr not implemented") + +method myPeerId*( + self: IKernel +): Future[Result[string, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.myPeerId not implemented") + +method metrics*( + self: IKernel +): Future[Result[string, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.metrics not implemented") + +method pingPeer*( + self: IKernel, peerAddr: string, timeoutMs: int +): Future[Result[int64, string]] {.async: (raises: []), base.} = + return err("Interface IKernel.pingPeer not implemented") diff --git a/logos_delivery/api/messaging_client_api.nim b/logos_delivery/api/messaging_client_api.nim new file mode 100644 index 000000000..227a7620b --- /dev/null +++ b/logos_delivery/api/messaging_client_api.nim @@ -0,0 +1,19 @@ +import chronos, results +import logos_delivery/api/types + +type IMessagingClient* = ref object of RootObj + +method subscribe*( + self: IMessagingClient, contentTopic: ContentTopic +): Future[Result[void, string]] {.async: (raises: []), base.} = + return err("Interface IMessagingClient.subscribe not implemented") + +method unsubscribe*( + self: IMessagingClient, contentTopic: ContentTopic +): Result[void, string] {.base, raises: [].} = + return err("Interface IMessagingClient.unsubscribe not implemented") + +method send*( + self: IMessagingClient, envelope: MessageEnvelope +): Future[Result[RequestId, string]] {.async: (raises: []), base.} = + return err("Interface IMessagingClient.send not implemented") diff --git a/logos_delivery/api/reliable_cannel_manager_api.nim b/logos_delivery/api/reliable_cannel_manager_api.nim new file mode 100644 index 000000000..c93146a77 --- /dev/null +++ b/logos_delivery/api/reliable_cannel_manager_api.nim @@ -0,0 +1,28 @@ +import chronos, results +import logos_delivery/api/types +import logos_delivery/channels/types +import logos_delivery/channels/reliable_channel + +type IReliableChannelManager* = ref object of RootObj + +method createReliableChannel*( + self: IReliableChannelManager, + channelId: ChannelId, + contentTopic: ContentTopic, + senderId: SdsParticipantID, + sendHandler: SendHandler = nil, +): Result[ChannelId, string] {.base.} = + return err("Interface IReliableChannelManager.createReliableChannel not implemented") + +method closeChannel*( + self: IReliableChannelManager, channelId: ChannelId +): Future[Result[void, string]] {.async: (raises: []), base.} = + return err("Interface IReliableChannelManager.closeChannel not implemented") + +method send*( + self: IReliableChannelManager, + channelId: ChannelId, + appPayload: seq[byte], + ephemeral: bool = false, +): Future[Result[RequestId, string]] {.async: (raises: []), base.} = + return err("Interface IReliableChannelManager.send not implemented") diff --git a/logos_delivery/channels/reliable_channel_manager.nim b/logos_delivery/channels/reliable_channel_manager.nim index 29feab0b9..52abba765 100644 --- a/logos_delivery/channels/reliable_channel_manager.nim +++ b/logos_delivery/channels/reliable_channel_manager.nim @@ -13,9 +13,10 @@ import stew/byteutils import brokers/broker_context +import logos_delivery/api/types +import logos_delivery/api/reliable_cannel_manager_api import logos_delivery/waku/events/message_events as waku_message_events import logos_delivery/messaging/messaging_client -import logos_delivery/api/types import logos_delivery/waku/waku_core/topics import logos_delivery/waku/persistency/sds_persistency @@ -34,7 +35,7 @@ type ## channel API. Placeholder for now (segmentation / SDS / rate-limit defaults ## will move here in a follow-up PR); kept so each layer owns its own config. - ReliableChannelManager* = ref object + ReliableChannelManager* = ref object of IReliableChannelManager channels: Table[ChannelId, ReliableChannel] messagingClient: MessagingClient ## The channel layer chains onto messaging. sendHandler: SendHandler @@ -94,13 +95,13 @@ proc sdsPersistence(): Option[Persistence] = return none(Persistence) return some(newSdsPersistence(job)) -proc createReliableChannel*( +method createReliableChannel*( self: ReliableChannelManager, channelId: ChannelId, contentTopic: ContentTopic, senderId: SdsParticipantID, sendHandler: SendHandler = nil, -): Result[ChannelId, string] = +): Result[ChannelId, string] {.raises: [].} = ## Spec entry point. The `sendHandler` and `rng` the channel needs are ## sourced from the owning `ReliableChannelManager` rather than passed ## per call. Encryption is wired up through the `Encrypt`/`Decrypt` @@ -146,7 +147,7 @@ proc createReliableChannel*( self.channels[channelId] = chn return ok(channelId) -proc closeChannel*( +method closeChannel*( self: ReliableChannelManager, channelId: ChannelId ): Future[Result[void, string]] {.async: (raises: []).} = ## Stops the channel's SDS loops and releases the channel. Persisted SDS @@ -158,7 +159,7 @@ proc closeChannel*( await chn.stop() return ok() -proc send*( +method send*( self: ReliableChannelManager, channelId: ChannelId, appPayload: seq[byte], diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index a05c94377..3f93ca689 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -2,6 +2,7 @@ import results, chronos import chronicles import logos_delivery/api/types, + logos_delivery/api/messaging_client_api, logos_delivery/waku/node/[waku_node, subscription_manager], logos_delivery/messaging/delivery_service/[recv_service, send_service], logos_delivery/messaging/delivery_service/send_service/delivery_task @@ -13,7 +14,7 @@ type ## follow-up PR. Today it only carries the p2p reliability toggle. useP2PReliability*: bool - MessagingClient* = ref object + MessagingClient* = ref object of IMessagingClient node: WakuNode sendService*: SendService recvService*: RecvService @@ -43,29 +44,29 @@ proc stop*(self: MessagingClient) {.async.} = await self.recvService.stopRecvService() self.started = false -proc checkApiAvailability(mc: MessagingClient): Result[void, string] = - if mc.isNil(): +proc checkApiAvailability(self: MessagingClient): Result[void, string] = + if self.isNil(): return err("MessagingClient is not initialized") return ok() -proc subscribe*( - mc: MessagingClient, contentTopic: ContentTopic -): Future[Result[void, string]] {.async.} = - ?checkApiAvailability(mc) +method subscribe*( + self: MessagingClient, contentTopic: ContentTopic +): Future[Result[void, string]] {.async: (raises: []).} = + ?checkApiAvailability(self) - return mc.node.subscriptionManager.subscribe(contentTopic) + return self.node.subscriptionManager.subscribe(contentTopic) -proc unsubscribe*( - mc: MessagingClient, contentTopic: ContentTopic -): Result[void, string] = - ?checkApiAvailability(mc) +method unsubscribe*( + self: MessagingClient, contentTopic: ContentTopic +): Result[void, string] {.raises: [].} = + ?checkApiAvailability(self) - return mc.node.subscriptionManager.unsubscribe(contentTopic) + return self.node.subscriptionManager.unsubscribe(contentTopic) -proc send*( +method send*( self: MessagingClient, envelope: MessageEnvelope -): Future[Result[RequestId, string]] {.async.} = +): Future[Result[RequestId, string]] {.async: (raises: []).} = ## High-level messaging API send. Auto-subscribes to the content topic ## (so the local node sees its own gossipsub broadcast), builds a ## `DeliveryTask`, and hands it to the send service. Returns the request diff --git a/logos_delivery/waku/waku.nim b/logos_delivery/waku/waku.nim index 2c18c5f63..b9c8ff21b 100644 --- a/logos_delivery/waku/waku.nim +++ b/logos_delivery/waku/waku.nim @@ -22,6 +22,7 @@ import metrics/chronos_httpserver, brokers/broker_context, logos_delivery/api/types, + logos_delivery/api/kernel_api, logos_delivery/waku/[ waku_core, waku_node, @@ -65,7 +66,7 @@ const git_version* {.strdefine.} = "n/a" const FilterOpTimeout = 5.seconds -type Waku* = ref object +type Waku* = ref object of IKernel stateInfo*: WakuStateInfo conf*: WakuConf rng*: crypto.Rng @@ -577,29 +578,31 @@ proc stop*(waku: Waku): Future[Result[void, string]] {.async: (raises: []).} = ## Kernel API realization ## # --- topic construction --- -proc buildContentTopic*( +method buildContentTopic*( self: Waku, appName: string, appVersion: uint32, name: string, encoding: string -): Future[Result[ContentTopic, string]] {.async.} = +): Future[Result[ContentTopic, string]] {.async: (raises: []).} = try: return ok(ContentTopic(fmt"/{appName}/{appVersion}/{name}/{encoding}")) except CatchableError as e: return err(e.msg) -proc buildPubsubTopic*( +method buildPubsubTopic*( self: Waku, topicName: string -): Future[Result[PubsubTopic, string]] {.async.} = +): Future[Result[PubsubTopic, string]] {.async: (raises: []).} = try: return ok(PubsubTopic(fmt"/waku/2/{topicName}")) except CatchableError as e: return err(e.msg) -proc defaultPubsubTopic*(self: Waku): Future[Result[PubsubTopic, string]] {.async.} = +method defaultPubsubTopic*( + self: Waku +): Future[Result[PubsubTopic, string]] {.async: (raises: []).} = return ok(DefaultPubsubTopic) # --- relay --- -proc relayPublish*( +method relayPublish*( self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, timeoutMs: uint32 -): Future[Result[int, string]] {.async.} = +): Future[Result[int, string]] {.async: (raises: []).} = try: if self.node.wakuRelay.isNil(): return err("relayPublish: WakuRelay not mounted") @@ -611,9 +614,9 @@ proc relayPublish*( except CatchableError as e: return err(e.msg) -proc relaySubscribe*( +method relaySubscribe*( self: Waku, pubsubTopic: PubsubTopic -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.node.wakuRelay.isNil(): return err("relaySubscribe: WakuRelay not mounted") @@ -627,9 +630,9 @@ proc relaySubscribe*( except CatchableError as e: return err(e.msg) -proc relayUnsubscribe*( +method relayUnsubscribe*( self: Waku, pubsubTopic: PubsubTopic -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.node.wakuRelay.isNil(): return err("relayUnsubscribe: WakuRelay not mounted") @@ -641,9 +644,9 @@ proc relayUnsubscribe*( except CatchableError as e: return err(e.msg) -proc relayAddProtectedShard*( +method relayAddProtectedShard*( self: Waku, clusterId: uint16, shardId: uint16, publicKey: string -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.node.wakuRelay.isNil(): return err("relayAddProtectedShard: WakuRelay not mounted") @@ -657,9 +660,9 @@ proc relayAddProtectedShard*( except CatchableError as e: return err(e.msg) -proc relayConnectedPeers*( +method relayConnectedPeers*( self: Waku, pubsubTopic: PubsubTopic -): Future[Result[seq[string], string]] {.async.} = +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: if self.node.wakuRelay.isNil(): return err("relayConnectedPeers: WakuRelay not mounted") @@ -671,9 +674,9 @@ proc relayConnectedPeers*( except CatchableError as e: return err(e.msg) -proc relayPeersInMesh*( +method relayPeersInMesh*( self: Waku, pubsubTopic: PubsubTopic -): Future[Result[seq[string], string]] {.async.} = +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: if self.node.wakuRelay.isNil(): return err("relayPeersInMesh: WakuRelay not mounted") @@ -686,12 +689,12 @@ proc relayPeersInMesh*( return err(e.msg) # --- filter --- -proc filterSubscribe*( +method filterSubscribe*( self: Waku, pubsubTopic: Option[PubsubTopic], contentTopics: seq[ContentTopic], peer: string, -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.node.wakuFilterClient.isNil(): return err("wakuFilterClient is not mounted") @@ -706,12 +709,12 @@ proc filterSubscribe*( except CatchableError as e: return err(e.msg) -proc filterUnsubscribe*( +method filterUnsubscribe*( self: Waku, pubsubTopic: Option[PubsubTopic], contentTopics: seq[ContentTopic], peer: string, -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.node.wakuFilterClient.isNil(): return err("wakuFilterClient is not mounted") @@ -726,9 +729,9 @@ proc filterUnsubscribe*( except CatchableError as e: return err(e.msg) -proc filterUnsubscribeAll*( +method filterUnsubscribeAll*( self: Waku, peer: string -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.node.wakuFilterClient.isNil(): return err("wakuFilterClient is not mounted") @@ -744,9 +747,9 @@ proc filterUnsubscribeAll*( return err(e.msg) # --- lightpush --- -proc lightpushPublish*( +method lightpushPublish*( self: Waku, pubsubTopic: PubsubTopic, message: WakuMessage, peer: string -): Future[Result[string, string]] {.async.} = +): Future[Result[string, string]] {.async: (raises: []).} = try: if self.node.wakuLegacyLightpushClient.isNil(): return err("wakuLegacyLightpushClient is not mounted") @@ -766,9 +769,9 @@ proc lightpushPublish*( return err(e.msg) # --- store --- -proc storeQuery*( +method storeQuery*( self: Waku, request: StoreQueryRequest, peer: string, timeoutMs: int -): Future[Result[StoreQueryResponse, string]] {.async.} = +): Future[Result[StoreQueryResponse, string]] {.async: (raises: []).} = try: if self.node.wakuStoreClient.isNil(): return err("wakuStoreClient is not mounted") @@ -788,18 +791,18 @@ proc storeQuery*( return err(e.msg) # --- peer management --- -proc connect*( +method connect*( self: Waku, peers: seq[string], timeoutMs: uint32 -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: await self.node.connectToNodes(peers.mapIt(strip(it)), source = "static") return ok(true) except CatchableError as e: return err(e.msg) -proc disconnectPeerById*( +method disconnectPeerById*( self: Waku, peerId: string -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: let pId = PeerId.init(peerId).valueOr: return err($error) @@ -808,16 +811,18 @@ proc disconnectPeerById*( except CatchableError as e: return err(e.msg) -proc disconnectAllPeers*(self: Waku): Future[Result[bool, string]] {.async.} = +method disconnectAllPeers*( + self: Waku +): Future[Result[bool, string]] {.async: (raises: []).} = try: await self.node.peerManager.disconnectAllPeers() return ok(true) except CatchableError as e: return err(e.msg) -proc dialPeer*( +method dialPeer*( self: Waku, peerAddr: string, protocol: string, timeoutMs: int -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: let remotePeerInfo = parsePeerInfo(peerAddr).valueOr: return err($error) @@ -828,9 +833,9 @@ proc dialPeer*( except CatchableError as e: return err(e.msg) -proc dialPeerById*( +method dialPeerById*( self: Waku, peerId: string, protocol: string, timeoutMs: int -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: let pId = PeerId.init(peerId).valueOr: return err($error) @@ -841,13 +846,17 @@ proc dialPeerById*( except CatchableError as e: return err(e.msg) -proc peerIdsFromPeerstore*(self: Waku): Future[Result[seq[string], string]] {.async.} = +method peerIdsFromPeerstore*( + self: Waku +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: return ok(self.node.peerManager.switch.peerStore.peers().mapIt($it.peerId)) except CatchableError as e: return err(e.msg) -proc connectedPeersInfo*(self: Waku): Future[Result[seq[string], string]] {.async.} = +method connectedPeersInfo*( + self: Waku +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: return ok( self.node.peerManager.switch.peerStore @@ -858,16 +867,18 @@ proc connectedPeersInfo*(self: Waku): Future[Result[seq[string], string]] {.asyn except CatchableError as e: return err(e.msg) -proc connectedPeers*(self: Waku): Future[Result[seq[string], string]] {.async.} = +method connectedPeers*( + self: Waku +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: let (inPeerIds, outPeerIds) = self.node.peerManager.connectedPeers() return ok(concat(inPeerIds, outPeerIds).mapIt($it)) except CatchableError as e: return err(e.msg) -proc peerIdsByProtocol*( +method peerIdsByProtocol*( self: Waku, protocol: string -): Future[Result[seq[string], string]] {.async.} = +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: return ok( self.node.peerManager.switch.peerStore @@ -879,9 +890,9 @@ proc peerIdsByProtocol*( return err(e.msg) # --- discovery --- -proc dnsDiscovery*( +method dnsDiscovery*( self: Waku, enrTreeUrl: string, nameServer: string, timeoutMs: int -): Future[Result[seq[string], string]] {.async.} = +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: let dnsNameServers = @[parseIpAddress(nameServer)] let discoveredPeers = ( @@ -898,9 +909,9 @@ proc dnsDiscovery*( except CatchableError as e: return err(e.msg) -proc discv5UpdateBootnodes*( +method discv5UpdateBootnodes*( self: Waku, bootnodes: seq[string] -): Future[Result[bool, string]] {.async.} = +): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.wakuDiscv5.isNil(): return err("discv5 not started") @@ -911,7 +922,7 @@ proc discv5UpdateBootnodes*( except CatchableError as e: return err(e.msg) -proc startDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = +method startDiscv5*(self: Waku): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.wakuDiscv5.isNil(): return err("discv5 not started") @@ -921,7 +932,7 @@ proc startDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = except CatchableError as e: return err(e.msg) -proc stopDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = +method stopDiscv5*(self: Waku): Future[Result[bool, string]] {.async: (raises: []).} = try: if self.wakuDiscv5.isNil(): return err("discv5 not started") @@ -930,9 +941,9 @@ proc stopDiscv5*(self: Waku): Future[Result[bool, string]] {.async.} = except CatchableError as e: return err(e.msg) -proc peerExchangeRequest*( +method peerExchangeRequest*( self: Waku, numPeers: uint64 -): Future[Result[int, string]] {.async.} = +): Future[Result[int, string]] {.async: (raises: []).} = try: let numPeersRecv = (await self.node.fetchPeerExchangePeers(numPeers)).valueOr: return err("failed peer exchange: " & $error) @@ -941,37 +952,39 @@ proc peerExchangeRequest*( return err(e.msg) # --- debug / info --- -proc version*(self: Waku): Future[Result[string, string]] {.async.} = +method version*(self: Waku): Future[Result[string, string]] {.async: (raises: []).} = return ok(WakuNodeVersionString) -proc listenAddresses*(self: Waku): Future[Result[seq[string], string]] {.async.} = +method listenAddresses*( + self: Waku +): Future[Result[seq[string], string]] {.async: (raises: []).} = try: return ok(self.node.info().listenAddresses) except CatchableError as e: return err(e.msg) -proc myEnr*(self: Waku): Future[Result[string, string]] {.async.} = +method myEnr*(self: Waku): Future[Result[string, string]] {.async: (raises: []).} = try: return ok(self.node.enr.toURI()) except CatchableError as e: return err(e.msg) -proc myPeerId*(self: Waku): Future[Result[string, string]] {.async.} = +method myPeerId*(self: Waku): Future[Result[string, string]] {.async: (raises: []).} = try: return ok($self.node.peerId()) except CatchableError as e: return err(e.msg) -proc metrics*(self: Waku): Future[Result[string, string]] {.async.} = +method metrics*(self: Waku): Future[Result[string, string]] {.async: (raises: []).} = {.gcsafe.}: try: return ok(defaultRegistry.toText()) except CatchableError as e: return err(e.msg) -proc pingPeer*( +method pingPeer*( self: Waku, peerAddr: string, timeoutMs: int -): Future[Result[int64, string]] {.async.} = +): Future[Result[int64, string]] {.async: (raises: []).} = try: let peerInfo = parsePeerInfo(peerAddr).valueOr: return err("pingPeer failed to parse peer addr: " & $error) From 019937a79b8256dec591a66f5c70174bb1185976 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 06:36:36 +0200 Subject: [PATCH 09/17] Typo in file name --- ..._cannel_manager_api.nim => reliable_channel_manager_api.nim} | 0 logos_delivery/channels/reliable_channel_manager.nim | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename logos_delivery/api/{reliable_cannel_manager_api.nim => reliable_channel_manager_api.nim} (100%) diff --git a/logos_delivery/api/reliable_cannel_manager_api.nim b/logos_delivery/api/reliable_channel_manager_api.nim similarity index 100% rename from logos_delivery/api/reliable_cannel_manager_api.nim rename to logos_delivery/api/reliable_channel_manager_api.nim diff --git a/logos_delivery/channels/reliable_channel_manager.nim b/logos_delivery/channels/reliable_channel_manager.nim index 52abba765..1e0f35f7c 100644 --- a/logos_delivery/channels/reliable_channel_manager.nim +++ b/logos_delivery/channels/reliable_channel_manager.nim @@ -14,7 +14,7 @@ import stew/byteutils import brokers/broker_context import logos_delivery/api/types -import logos_delivery/api/reliable_cannel_manager_api +import logos_delivery/api/reliable_channel_manager_api import logos_delivery/waku/events/message_events as waku_message_events import logos_delivery/messaging/messaging_client import logos_delivery/waku/waku_core/topics From 2322dafd706bdd143310d458b2c533c7a9b75ecd Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:24:49 +0200 Subject: [PATCH 10/17] Add events to interface level --- library/logos_delivery_api/node_api.nim | 6 +-- logos_delivery/api/kernel_api.nim | 21 ++++++---- logos_delivery/api/logos_delivery_api.nim | 33 +++++++++++++++ logos_delivery/api/messaging_client_api.nim | 31 +++++++++++++- .../api/reliable_channel_manager_api.nim | 42 +++++++++++++++++-- logos_delivery/api/types.nim | 27 +++++++++--- logos_delivery/channels/events.nim | 39 ----------------- logos_delivery/channels/reliable_channel.nim | 15 ++----- .../channels/reliable_channel_manager.nim | 1 - logos_delivery/channels/types.nim | 15 ------- logos_delivery/logos_delivery.nim | 11 +++-- .../recv_service/recv_service.nim | 2 +- .../send_service/send_service.nim | 2 +- logos_delivery/waku/events/events.nim | 8 +--- logos_delivery/waku/events/health_events.nim | 13 ++---- logos_delivery/waku/events/message_events.nim | 35 ---------------- .../health_monitor/node_health_monitor.nim | 1 + .../waku/node/health_monitor/topic_health.nim | 2 +- .../waku/node/subscription_manager.nim | 2 +- logos_delivery/waku/node/waku_node.nim | 2 +- logos_delivery/waku/node/waku_node/relay.nim | 1 - logos_delivery/waku/utils/requests.nim | 10 ----- logos_delivery/waku/waku_lightpush/client.nim | 2 +- .../waku/waku_lightpush/self_req_handler.nim | 4 +- .../waku/waku_lightpush_legacy/client.nim | 2 +- .../self_req_handler.nim | 10 +---- logos_delivery/waku/waku_store/client.nim | 4 +- 27 files changed, 171 insertions(+), 170 deletions(-) create mode 100644 logos_delivery/api/logos_delivery_api.nim delete mode 100644 logos_delivery/channels/events.nim delete mode 100644 logos_delivery/channels/types.nim delete mode 100644 logos_delivery/waku/events/message_events.nim delete mode 100644 logos_delivery/waku/utils/requests.nim diff --git a/library/logos_delivery_api/node_api.nim b/library/logos_delivery_api/node_api.nim index 354ab3a98..8f0ee3921 100644 --- a/library/logos_delivery_api/node_api.nim +++ b/library/logos_delivery_api/node_api.nim @@ -3,9 +3,9 @@ import chronos, chronicles, results, ffi import logos_delivery, logos_delivery/waku/node/waku_node, - logos_delivery/waku/events/message_events, + logos_delivery/api/messaging_client_api, logos_delivery/api/types, - logos_delivery/waku/events/[message_events, health_events], + logos_delivery/waku/events/health_events, tools/confutils/conf_from_json, ../declare_lib, ../json_event @@ -116,7 +116,7 @@ proc logosdelivery_start_node( chronicles.error "MessageReceivedEvent.listen failed", err = $error return err("MessageReceivedEvent.listen failed: " & $error) - let ConnectionStatusChangeListener = EventConnectionStatusChange.listen( + discard EventConnectionStatusChange.listen( ctx.myLib[].waku.brokerCtx, proc(event: EventConnectionStatusChange) {.async: (raises: []).} = callEventCallback(ctx, "onConnectionStatusChange"): diff --git a/logos_delivery/api/kernel_api.nim b/logos_delivery/api/kernel_api.nim index 4c1a838bb..ea64eab22 100644 --- a/logos_delivery/api/kernel_api.nim +++ b/logos_delivery/api/kernel_api.nim @@ -1,18 +1,25 @@ import std/options import chronos, results -import logos_delivery/api/types +import brokers/event_broker + +import logos_delivery/api/types as api_types import logos_delivery/waku/waku_core/topics/pubsub_topic -import logos_delivery/waku/waku_store/common +import logos_delivery/waku/waku_store/common as store_types + +export event_broker +export api_types, pubsub_topic, store_types type IKernel* = ref object of RootObj +EventBroker: + # Internal event emitted when a message arrives from the network via any protocol + type MessageSeenEvent* = object + topic*: PubsubTopic + message*: WakuMessage + # --- topic construction --- method buildContentTopic*( - self: IKernel, - appName: string, - appVersion: uint32, - name: string, - encoding: string, + self: IKernel, appName: string, appVersion: uint32, name: string, encoding: string ): Future[Result[ContentTopic, string]] {.async: (raises: []), base.} = return err("Interface IKernel.buildContentTopic not implemented") diff --git a/logos_delivery/api/logos_delivery_api.nim b/logos_delivery/api/logos_delivery_api.nim new file mode 100644 index 000000000..162159d8e --- /dev/null +++ b/logos_delivery/api/logos_delivery_api.nim @@ -0,0 +1,33 @@ +## `LogosDelivery` is the project entry point. It is a pure concentrator: it +## owns exactly one instance of each API layer +## +## Waku <- MessagingClient <- ReliableChannelManager +## +## and chains them together (each layer drives the one below it). Every layer +## keeps its own, separate public API — `LogosDelivery` only wires them up and +## drives the shared `new` / `start` / `stop` lifecycle. + +{.push raises: [].} + +import results, chronos +import brokers/event_broker +import types as api_types + +export api_types, event_broker + +type + ## Entry point. Holds one instance of each API layer. + ILogosDelivery* = ref object of RootObj + +EventBroker: + type EventConnectionStatusChange* = object + connectionStatus*: ConnectionStatus + +method start*(self: ILogosDelivery): Future[Result[void, string]] {.async, base.} = + return err("ILogosDelivery.start not implemented") + +method stop*(self: ILogosDelivery): Future[Result[void, string]] {.async, base.} = + return err("ILogosDelivery.stop not implemented") + +method isOnline*(self: ILogosDelivery): Future[Result[bool, string]] {.async, base.} = + return err("ILogosDelivery.isOnline not implemented") diff --git a/logos_delivery/api/messaging_client_api.nim b/logos_delivery/api/messaging_client_api.nim index 227a7620b..46acec3bc 100644 --- a/logos_delivery/api/messaging_client_api.nim +++ b/logos_delivery/api/messaging_client_api.nim @@ -1,8 +1,37 @@ import chronos, results -import logos_delivery/api/types +import brokers/event_broker + +import logos_delivery/api/types as api_types + +export event_broker, api_types type IMessagingClient* = ref object of RootObj +EventBroker: + # Event emitted when a message is sent to the network + type MessageSentEvent* = object + requestId*: RequestId + messageHash*: string + +EventBroker: + # Event emitted when a message send operation fails + type MessageErrorEvent* = object + requestId*: RequestId + messageHash*: string + error*: string + +EventBroker: + # Confirmation that a message has been correctly delivered to some neighbouring nodes. + type MessagePropagatedEvent* = object + requestId*: RequestId + messageHash*: string + +EventBroker: + # Event emitted when a message is received via Waku + type MessageReceivedEvent* = object + messageHash*: string + message*: WakuMessage + method subscribe*( self: IMessagingClient, contentTopic: ContentTopic ): Future[Result[void, string]] {.async: (raises: []), base.} = diff --git a/logos_delivery/api/reliable_channel_manager_api.nim b/logos_delivery/api/reliable_channel_manager_api.nim index c93146a77..206ef0df7 100644 --- a/logos_delivery/api/reliable_channel_manager_api.nim +++ b/logos_delivery/api/reliable_channel_manager_api.nim @@ -1,9 +1,43 @@ import chronos, results -import logos_delivery/api/types -import logos_delivery/channels/types -import logos_delivery/channels/reliable_channel -type IReliableChannelManager* = ref object of RootObj +import brokers/event_broker + +import logos_delivery/api/types as api_types + +export event_broker, api_types + +type + IReliableChannelManager* = ref object of RootObj + + SendHandler* = proc(envelope: MessageEnvelope): Future[Result[RequestId, string]] {. + async: (raises: [CatchableError]), gcsafe + .} + ## Egress dispatch boundary. Typically wraps `MessagingClient.send`; + ## tests inject a fake that records calls and returns canned + ## `RequestId`s so the send state machine can be exercised end-to-end + ## without a network. + +EventBroker: + type ChannelMessageReceivedEvent* = object + channelId*: ChannelId + senderId*: SdsParticipantID + payload*: seq[byte] + +EventBroker: + ## Emitted when every segment of a channel-level `send()` reached + ## `Confirmed`. Channel-level analogue of `MessageSentEvent`; the + ## `requestId` is the channel-layer parent returned by `send()`. + type ChannelMessageSentEvent* = object + channelId*: ChannelId + requestId*: RequestId + +EventBroker: + ## Emitted when a channel-level `send()` finalises with at least one + ## segment in `Failed`. Channel-level analogue of `MessageErrorEvent`. + type ChannelMessageErrorEvent* = object + channelId*: ChannelId + requestId*: RequestId + error*: string method createReliableChannel*( self: IReliableChannelManager, diff --git a/logos_delivery/api/types.nim b/logos_delivery/api/types.nim index 5757a8e82..c73b98e38 100644 --- a/logos_delivery/api/types.nim +++ b/logos_delivery/api/types.nim @@ -1,14 +1,19 @@ -import logos_delivery/waku/compat/option_valueor -import libp2p/crypto/crypto {.push raises: [].} - +import std/hashes import bearssl/rand, std/times, chronos import stew/byteutils -import logos_delivery/waku/utils/requests as request_utils +import libp2p/crypto/crypto + +import logos_delivery/waku/compat/option_valueor + import logos_delivery/waku/waku_core/[topics/content_topic, message/message, time] export content_topic, message +import types/sds_message_id + +export sds_message_id + type MessageEnvelope* = object contentTopic*: ContentTopic @@ -26,9 +31,16 @@ type PartiallyConnected Connected + ChannelId* = SdsChannelID + +proc generateRequestId*(rng: crypto.Rng): string = + var bytes: array[10, byte] + rng.generate(bytes) + return byteutils.toHex(bytes) + proc new*(T: typedesc[RequestId], rng: crypto.Rng): T = ## Generate a new RequestId using the provided RNG. - RequestId(request_utils.generateRequestId(rng)) + RequestId(generateRequestId(rng)) proc `$`*(r: RequestId): string {.inline.} = string(r) @@ -36,6 +48,11 @@ proc `$`*(r: RequestId): string {.inline.} = proc `==`*(a, b: RequestId): bool {.inline.} = string(a) == string(b) +proc hash*(r: RequestId): Hash = + ## Allows `RequestId` to be used as a `Table` key. + hash(string(r)) + + proc init*( T: type MessageEnvelope, contentTopic: ContentTopic, diff --git a/logos_delivery/channels/events.nim b/logos_delivery/channels/events.nim deleted file mode 100644 index 5f69095e4..000000000 --- a/logos_delivery/channels/events.nim +++ /dev/null @@ -1,39 +0,0 @@ -## Reliable Channel event types emitted to API consumers. -## -## Lifecycle events for individual segments (sent / propagated / errored) -## are the same as the network-level ones the MessagingClient already -## emits — `requestId` is shared across layers — so we just re-export -## `waku/events/message_events` and avoid declaring duplicates. -## -## Only the channel-level `MessageReceivedEvent` carries data that has -## no analogue in the lower layer (reassembled application payload, -## senderId, channelId), so it lives here. - -import logos_delivery/waku/events/message_events as waku_message_events -import brokers/event_broker - -import ./types as channel_types - -export waku_message_events, channel_types, event_broker - -EventBroker: - type ChannelMessageReceivedEvent* = object - channelId*: ChannelId - senderId*: SdsParticipantID - payload*: seq[byte] - -EventBroker: - ## Emitted when every segment of a channel-level `send()` reached - ## `Confirmed`. Channel-level analogue of `MessageSentEvent`; the - ## `requestId` is the channel-layer parent returned by `send()`. - type ChannelMessageSentEvent* = object - channelId*: ChannelId - requestId*: RequestId - -EventBroker: - ## Emitted when a channel-level `send()` finalises with at least one - ## segment in `Failed`. Channel-level analogue of `MessageErrorEvent`. - type ChannelMessageErrorEvent* = object - channelId*: ChannelId - requestId*: RequestId - error*: string diff --git a/logos_delivery/channels/reliable_channel.nim b/logos_delivery/channels/reliable_channel.nim index 307dc17a4..c52d25653 100644 --- a/logos_delivery/channels/reliable_channel.nim +++ b/logos_delivery/channels/reliable_channel.nim @@ -24,16 +24,17 @@ import libp2p/crypto/crypto as libp2p_crypto import logos_delivery/api/types import logos_delivery/messaging/delivery_service/send_service import logos_delivery/waku/waku_core/topics +import logos_delivery/api/reliable_channel_manager_api +import logos_delivery/api/messaging_client_api -import ./events import ./segmentation/segmentation import ./scalable_data_sync/scalable_data_sync import ./rate_limit_manager/rate_limit_manager import ./encryption/encryption export - types, send_service, events, segmentation, scalable_data_sync, rate_limit_manager, - encryption + types, send_service, reliable_channel_manager_api, segmentation, scalable_data_sync, + rate_limit_manager, encryption const LipWireReliableChannelVersion* = "RELIABLE-CHANNEL-API/1" ## Wire-format spec marker for the Reliable Channel layer, as defined @@ -44,14 +45,6 @@ const LipWireReliableChannelVersion* = "RELIABLE-CHANNEL-API/1" ## on breaking on-the-wire changes; implementations pin one version. type - SendHandler* = proc(envelope: MessageEnvelope): Future[Result[RequestId, string]] {. - async: (raises: [CatchableError]), gcsafe - .} - ## Egress dispatch boundary. Typically wraps `MessagingClient.send`; - ## tests inject a fake that records calls and returns canned - ## `RequestId`s so the send state machine can be exercised end-to-end - ## without a network. - MessagePersistence {.pure.} = enum Persistent Ephemeral diff --git a/logos_delivery/channels/reliable_channel_manager.nim b/logos_delivery/channels/reliable_channel_manager.nim index 1e0f35f7c..88d1d1787 100644 --- a/logos_delivery/channels/reliable_channel_manager.nim +++ b/logos_delivery/channels/reliable_channel_manager.nim @@ -15,7 +15,6 @@ import brokers/broker_context import logos_delivery/api/types import logos_delivery/api/reliable_channel_manager_api -import logos_delivery/waku/events/message_events as waku_message_events import logos_delivery/messaging/messaging_client import logos_delivery/waku/waku_core/topics import logos_delivery/waku/persistency/sds_persistency diff --git a/logos_delivery/channels/types.nim b/logos_delivery/channels/types.nim deleted file mode 100644 index 7730c5c58..000000000 --- a/logos_delivery/channels/types.nim +++ /dev/null @@ -1,15 +0,0 @@ -## Core identifier types for the Reliable Channel API. - -import std/hashes -import logos_delivery/api/types as api_types - -import ./scalable_data_sync/scalable_data_sync - -export scalable_data_sync -export api_types - -type ChannelId* = SdsChannelID - -proc hash*(r: RequestId): Hash = - ## Allows `RequestId` to be used as a `Table` key. - hash(string(r)) diff --git a/logos_delivery/logos_delivery.nim b/logos_delivery/logos_delivery.nim index f61202b9a..f739851e7 100644 --- a/logos_delivery/logos_delivery.nim +++ b/logos_delivery/logos_delivery.nim @@ -11,6 +11,8 @@ import results, chronos, chronicles +import logos_delivery/api/logos_delivery_api +export logos_delivery_api import logos_delivery/waku/waku export waku import logos_delivery/messaging/messaging_client @@ -35,7 +37,8 @@ type messaging*: MessagingClientConf reliableChannel*: ReliableChannelManagerConf - LogosDelivery* = ref object ## Entry point. Holds one instance of each API layer. + LogosDelivery* = ref object of ILogosDelivery + ## Entry point. Holds one instance of each API layer. waku*: Waku messagingClient*: MessagingClient reliableChannelManager*: ReliableChannelManager @@ -79,7 +82,7 @@ proc new*( ) ) -proc start*(self: LogosDelivery): Future[Result[void, string]] {.async.} = +method start*(self: LogosDelivery): Future[Result[void, string]] {.async.} = ## Starts each layer bottom-up: transport first, then messaging, then channels. if self.waku.isNil(): return err("Waku node is not initialized") @@ -99,7 +102,7 @@ proc start*(self: LogosDelivery): Future[Result[void, string]] {.async.} = return ok() -proc stop*(self: LogosDelivery): Future[Result[void, string]] {.async.} = +method stop*(self: LogosDelivery): Future[Result[void, string]] {.async.} = ## Stops in reverse order so higher layers drain before their dependencies. await self.reliableChannelManager.stop() await self.messagingClient.stop() @@ -109,7 +112,7 @@ proc stop*(self: LogosDelivery): Future[Result[void, string]] {.async.} = return ok() -proc isOnline*(self: LogosDelivery): Future[Result[bool, string]] {.async.} = +method isOnline*(self: LogosDelivery): Future[Result[bool, string]] {.async.} = if self.waku.isNil(): return err("Waku node is not initialized") return ok(self.waku.healthMonitor.onlineMonitor.amIOnline()) diff --git a/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim b/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim index 90bdb0839..9840d5a20 100644 --- a/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim +++ b/logos_delivery/messaging/delivery_service/recv_service/recv_service.nim @@ -6,6 +6,7 @@ import logos_delivery/waku/compat/option_valueor import std/[tables, sequtils, options, sets] import chronos, chronicles, libp2p/utility import brokers/broker_context +import logos_delivery/api/[types, logos_delivery_api, kernel_api, messaging_client_api] import logos_delivery/waku/[ waku_core, @@ -13,7 +14,6 @@ import waku_store/client, waku_store/common, waku_filter_v2/client, - events/message_events, events/health_events, waku_node, node/subscription_manager, diff --git a/logos_delivery/messaging/delivery_service/send_service/send_service.nim b/logos_delivery/messaging/delivery_service/send_service/send_service.nim index 00f2ff672..c6086b797 100644 --- a/logos_delivery/messaging/delivery_service/send_service/send_service.nim +++ b/logos_delivery/messaging/delivery_service/send_service/send_service.nim @@ -5,6 +5,7 @@ import logos_delivery/waku/compat/option_valueor import std/[sequtils, tables, options, typetraits] import chronos, chronicles, libp2p/utility import brokers/broker_context +import logos_delivery/api/messaging_client_api import ./[send_processor, relay_processor, lightpush_processor, delivery_task], logos_delivery/waku/[ @@ -18,7 +19,6 @@ import waku_rln_relay/rln_relay, waku_lightpush/client, waku_lightpush/callbacks, - events/message_events, ] logScope: diff --git a/logos_delivery/waku/events/events.nim b/logos_delivery/waku/events/events.nim index 130d7c018..b087cfb8e 100644 --- a/logos_delivery/waku/events/events.nim +++ b/logos_delivery/waku/events/events.nim @@ -1,9 +1,5 @@ import - ./[ - message_events, delivery_events, health_events, peer_events, lifecycle_events, - discovery_events, - ] + ./[delivery_events, health_events, peer_events, discovery_events] export - message_events, delivery_events, health_events, peer_events, lifecycle_events, - discovery_events + delivery_events, health_events, peer_events, discovery_events diff --git a/logos_delivery/waku/events/health_events.nim b/logos_delivery/waku/events/health_events.nim index d19de776b..9dc70ae63 100644 --- a/logos_delivery/waku/events/health_events.nim +++ b/logos_delivery/waku/events/health_events.nim @@ -1,15 +1,10 @@ import brokers/event_broker -import logos_delivery/api/types -import logos_delivery/waku/node/health_monitor/[protocol_health, topic_health] -import logos_delivery/waku/waku_core/topics +from logos_delivery/api/logos_delivery_api import EventConnectionStatusChange +import logos_delivery/waku/node/health_monitor/topic_health +from logos_delivery/waku/waku_core/topics import ContentTopic, PubsubTopic -export protocol_health, topic_health - -# Notify health changes to node connectivity -EventBroker: - type EventConnectionStatusChange* = object - connectionStatus*: ConnectionStatus +export topic_health, EventConnectionStatusChange # Notify health changes to a subscribed topic # TODO: emit content topic health change events when subscribe/unsubscribe diff --git a/logos_delivery/waku/events/message_events.nim b/logos_delivery/waku/events/message_events.nim deleted file mode 100644 index 2e4bece80..000000000 --- a/logos_delivery/waku/events/message_events.nim +++ /dev/null @@ -1,35 +0,0 @@ -import brokers/event_broker -import logos_delivery/api/types -import logos_delivery/waku/[waku_core/message, waku_core/topics] -export types - -EventBroker: - # Event emitted when a message is sent to the network - type MessageSentEvent* = object - requestId*: RequestId - messageHash*: string - -EventBroker: - # Event emitted when a message send operation fails - type MessageErrorEvent* = object - requestId*: RequestId - messageHash*: string - error*: string - -EventBroker: - # Confirmation that a message has been correctly delivered to some neighbouring nodes. - type MessagePropagatedEvent* = object - requestId*: RequestId - messageHash*: string - -EventBroker: - # Event emitted when a message is received via Waku - type MessageReceivedEvent* = object - messageHash*: string - message*: WakuMessage - -EventBroker: - # Internal event emitted when a message arrives from the network via any protocol - type MessageSeenEvent* = object - topic*: PubsubTopic - message*: WakuMessage diff --git a/logos_delivery/waku/node/health_monitor/node_health_monitor.nim b/logos_delivery/waku/node/health_monitor/node_health_monitor.nim index 465598794..deedaa6cc 100644 --- a/logos_delivery/waku/node/health_monitor/node_health_monitor.nim +++ b/logos_delivery/waku/node/health_monitor/node_health_monitor.nim @@ -9,6 +9,7 @@ import libp2p/protocols/pubsub, libp2p/protocols/pubsub/rpc/messages, logos_delivery/api/types, + logos_delivery/api/logos_delivery_api, logos_delivery/waku/[ waku_relay, waku_rln_relay, diff --git a/logos_delivery/waku/node/health_monitor/topic_health.nim b/logos_delivery/waku/node/health_monitor/topic_health.nim index 9273f4835..a08a3c3a9 100644 --- a/logos_delivery/waku/node/health_monitor/topic_health.nim +++ b/logos_delivery/waku/node/health_monitor/topic_health.nim @@ -1,6 +1,6 @@ import chronos -import logos_delivery/waku/waku_core +from logos_delivery/waku/waku_core/topics import PubsubTopic type TopicHealth* = enum UNHEALTHY diff --git a/logos_delivery/waku/node/subscription_manager.nim b/logos_delivery/waku/node/subscription_manager.nim index 15b582ea6..2eadd2009 100644 --- a/logos_delivery/waku/node/subscription_manager.nim +++ b/logos_delivery/waku/node/subscription_manager.nim @@ -2,6 +2,7 @@ import logos_delivery/waku/compat/option_valueor import std/[sequtils, sets, tables, options], chronos, chronicles, metrics, results import libp2p/[peerid, peerinfo] import brokers/broker_context +import logos_delivery/api/kernel_api import logos_delivery/waku/[ @@ -16,7 +17,6 @@ import waku_filter_v2/client as filter_client, waku_filter_v2/protocol as filter_protocol, events/health_events, - events/message_events, events/peer_events, requests/health_requests, node/peer_manager, diff --git a/logos_delivery/waku/node/waku_node.nim b/logos_delivery/waku/node/waku_node.nim index 2ad7dc601..7a9813b98 100644 --- a/logos_delivery/waku/node/waku_node.nim +++ b/logos_delivery/waku/node/waku_node.nim @@ -60,9 +60,9 @@ import requests/node_requests, requests/health_requests, events/health_events, - events/message_events, events/peer_events, ], + logos_delivery/api/kernel_api, logos_delivery/waku/discovery/waku_kademlia, logos_delivery/waku/net/[bound_ports, net_config], ./peer_manager, diff --git a/logos_delivery/waku/node/waku_node/relay.nim b/logos_delivery/waku/node/waku_node/relay.nim index 57904dc94..a2d1751ef 100644 --- a/logos_delivery/waku/node/waku_node/relay.nim +++ b/logos_delivery/waku/node/waku_node/relay.nim @@ -32,7 +32,6 @@ import node/waku_node, node/subscription_manager, node/peer_manager, - events/message_events, ] export waku_relay.WakuRelayHandler diff --git a/logos_delivery/waku/utils/requests.nim b/logos_delivery/waku/utils/requests.nim deleted file mode 100644 index a7fd9a2a9..000000000 --- a/logos_delivery/waku/utils/requests.nim +++ /dev/null @@ -1,10 +0,0 @@ -# Request utils. - -{.push raises: [].} - -import libp2p/crypto/crypto, stew/byteutils - -proc generateRequestId*(rng: crypto.Rng): string = - var bytes: array[10, byte] - rng.generate(bytes) - return byteutils.toHex(bytes) diff --git a/logos_delivery/waku/waku_lightpush/client.nim b/logos_delivery/waku/waku_lightpush/client.nim index 680970a51..e33b2875c 100644 --- a/logos_delivery/waku/waku_lightpush/client.nim +++ b/logos_delivery/waku/waku_lightpush/client.nim @@ -4,10 +4,10 @@ import logos_delivery/waku/compat/option_valueor import std/options, results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils import libp2p/peerid, libp2p/stream/connection +import logos_delivery/api/types import ../waku_core/peers, ../node/peer_manager, - ../utils/requests, ../waku_core, ./common, ./protocol_metrics, diff --git a/logos_delivery/waku/waku_lightpush/self_req_handler.nim b/logos_delivery/waku/waku_lightpush/self_req_handler.nim index 06a0d3715..dcf8ba895 100644 --- a/logos_delivery/waku/waku_lightpush/self_req_handler.nim +++ b/logos_delivery/waku/waku_lightpush/self_req_handler.nim @@ -10,8 +10,8 @@ ## that could be used also as a lightpush client, helping testing and development. import results, chronos, std/options, metrics -import ../waku_core, ./protocol, ./common, ./rpc, ./rpc_codec, ../utils/requests - +import logos_delivery/api/types +import ../waku_core, ./protocol, ./common, ./rpc, ./rpc_codec proc handleSelfLightPushRequest*( self: WakuLightPush, pubSubTopic: Option[PubsubTopic], message: WakuMessage ): Future[WakuLightPushResult] {.async.} = diff --git a/logos_delivery/waku/waku_lightpush_legacy/client.nim b/logos_delivery/waku/waku_lightpush_legacy/client.nim index 511c3f543..ff7e694d3 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/client.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/client.nim @@ -4,10 +4,10 @@ import logos_delivery/waku/compat/option_valueor import std/options, results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils import libp2p/peerid +import logos_delivery/api/types import ../waku_core/peers, ../node/peer_manager, - ../utils/requests, ../waku_core, ./common, ./protocol_metrics, diff --git a/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim b/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim index 3c5d09a9c..466d14f7c 100644 --- a/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim +++ b/logos_delivery/waku/waku_lightpush_legacy/self_req_handler.nim @@ -10,14 +10,8 @@ ## that could be used also as a lightpush client, helping testing and development. import results, chronos, chronicles, std/options, metrics, stew/byteutils -import - ../waku_core, - ./protocol, - ./common, - ./rpc, - ./rpc_codec, - ./protocol_metrics, - ../utils/requests +import logos_delivery/api/types +import ../waku_core, ./protocol, ./common, ./rpc, ./rpc_codec, ./protocol_metrics proc handleSelfLightPushRequest*( self: WakuLegacyLightPush, pubSubTopic: PubsubTopic, message: WakuMessage diff --git a/logos_delivery/waku/waku_store/client.nim b/logos_delivery/waku/waku_store/client.nim index 21e2699e3..c93fad6a4 100644 --- a/logos_delivery/waku/waku_store/client.nim +++ b/logos_delivery/waku/waku_store/client.nim @@ -9,8 +9,8 @@ import chronos, metrics, bearssl/rand -import - ../node/peer_manager, ../utils/requests, ./protocol_metrics, ./common, ./rpc_codec +import logos_delivery/api/types +import ../node/peer_manager, ./protocol_metrics, ./common, ./rpc_codec logScope: topics = "waku store client" From 6dd5ea0cc4cdd3a772bab0f62fc406dc926c30e6 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 14:29:48 +0200 Subject: [PATCH 11/17] liteprotocoltester build --- apps/liteprotocoltester/statistics.nim | 1 + 1 file changed, 1 insertion(+) diff --git a/apps/liteprotocoltester/statistics.nim b/apps/liteprotocoltester/statistics.nim index 7feebd4cf..ed9a6c214 100644 --- a/apps/liteprotocoltester/statistics.nim +++ b/apps/liteprotocoltester/statistics.nim @@ -10,6 +10,7 @@ import from std/sugar import `=>` +import logos_delivery/waku/compat/option_valueor import ./tester_message, ./lpt_metrics type From 358fad8db75cfca178b1285e22d37a688473ccc5 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 15:20:48 +0200 Subject: [PATCH 12/17] Fix test imports --- tests/api/test_api_receive.nim | 2 +- tests/api/test_api_send.nim | 1 + tests/api/test_api_subscription.nim | 2 +- .../test_reliable_channel_send_receive.nim | 95 +++++++++---------- 4 files changed, 47 insertions(+), 53 deletions(-) diff --git a/tests/api/test_api_receive.nim b/tests/api/test_api_receive.nim index 41c0f0477..ae8d6fcc2 100644 --- a/tests/api/test_api_receive.nim +++ b/tests/api/test_api_receive.nim @@ -5,6 +5,7 @@ import chronos, testutils/unittests, stew/byteutils import libp2p/[peerid, peerinfo, crypto/crypto] import brokers/broker_context import ../testlib/[common, wakucore, wakunode, testasync] +import logos_delivery/api/[types, logos_delivery_api, kernel_api, messaging_client_api] import ../waku_archive/archive_utils import logos_delivery/messaging/messaging_client import logos_delivery/messaging/delivery_service/recv_service @@ -14,7 +15,6 @@ import logos_delivery/waku/[ waku_node, waku_core, - events/message_events, events/health_events, waku_relay/protocol, waku_archive, diff --git a/tests/api/test_api_send.nim b/tests/api/test_api_send.nim index f64715592..ff8708dcc 100644 --- a/tests/api/test_api_send.nim +++ b/tests/api/test_api_send.nim @@ -4,6 +4,7 @@ import std/strutils import chronos, testutils/unittests, stew/byteutils, libp2p/[switch, peerinfo] import brokers/broker_context import ../testlib/[common, wakucore, wakunode, testasync] +import logos_delivery/api/[types, logos_delivery_api, kernel_api, messaging_client_api] import ../waku_archive/archive_utils import logos_delivery, logos_delivery/waku/[waku_node, waku_core, waku_relay/protocol] import logos_delivery/waku/factory/waku_conf diff --git a/tests/api/test_api_subscription.nim b/tests/api/test_api_subscription.nim index bf2851b02..50653108e 100644 --- a/tests/api/test_api_subscription.nim +++ b/tests/api/test_api_subscription.nim @@ -5,6 +5,7 @@ import chronos, testutils/unittests, stew/byteutils import libp2p/[peerid, peerinfo, multiaddress, crypto/crypto] import brokers/broker_context import ../testlib/[common, wakucore, wakunode, testasync] +import logos_delivery/api/[types, logos_delivery_api, kernel_api, messaging_client_api] import logos_delivery/messaging/messaging_client import @@ -12,7 +13,6 @@ import logos_delivery/waku/[ waku_node, waku_core, - events/message_events, waku_relay/protocol, node/waku_node/filter, node/subscription_manager, diff --git a/tests/channels/test_reliable_channel_send_receive.nim b/tests/channels/test_reliable_channel_send_receive.nim index b3d9a8f00..719ed857c 100644 --- a/tests/channels/test_reliable_channel_send_receive.nim +++ b/tests/channels/test_reliable_channel_send_receive.nim @@ -7,10 +7,11 @@ import brokers/broker_context import ../testlib/[common, wakucore, wakunode, testasync] +import logos_delivery/api/[types, logos_delivery_api, kernel_api, messaging_client_api] + import logos_delivery import logos_delivery/waku/[waku_node, waku_core] import logos_delivery/waku/factory/waku_conf -import logos_delivery/waku/events/message_events as waku_message_events import tools/confutils/cli_args import logos_delivery/channels/reliable_channel_manager @@ -99,9 +100,8 @@ suite "Reliable Channel - ingress": meta: LipWireReliableChannelVersion.toBytes(), ) - waku_message_events.MessageReceivedEvent.emit( - brokerCtx, - waku_message_events.MessageReceivedEvent(messageHash: "", message: inboundMsg), + MessageReceivedEvent.emit( + brokerCtx, MessageReceivedEvent(messageHash: "", message: inboundMsg) ) let arrived = await received.withTimeout(TestTimeout) @@ -151,9 +151,8 @@ suite "Reliable Channel - ingress": meta: @[], ## no Reliable Channel spec marker ) - waku_message_events.MessageReceivedEvent.emit( - brokerCtx, - waku_message_events.MessageReceivedEvent(messageHash: "", message: inboundMsg), + MessageReceivedEvent.emit( + brokerCtx, MessageReceivedEvent(messageHash: "", message: inboundMsg) ) ## Give the event broker a chance to fan out. @@ -217,9 +216,8 @@ suite "Reliable Channel - send state machine": await sleepAsync(5.milliseconds) check sendCalls == 1 - waku_message_events.MessageSentEvent.emit( - brokerCtx, - waku_message_events.MessageSentEvent(requestId: fakeMsgReqId, messageHash: ""), + MessageSentEvent.emit( + brokerCtx, MessageSentEvent(requestId: fakeMsgReqId, messageHash: "") ) let finalised = await sentFut.withTimeout(1.seconds) @@ -296,9 +294,8 @@ suite "Reliable Channel - send state machine": await sleepAsync(5.milliseconds) check msgReqIds.len == 2 - waku_message_events.MessageSentEvent.emit( - brokerCtx, - waku_message_events.MessageSentEvent(requestId: msgReqIds[0], messageHash: ""), + MessageSentEvent.emit( + brokerCtx, MessageSentEvent(requestId: msgReqIds[0], messageHash: "") ) let sentArrived = await sentFut.withTimeout(1.seconds) check sentArrived @@ -308,11 +305,9 @@ suite "Reliable Channel - send state machine": ## segment is still `InFlight`. check not erroredFut.finished() - waku_message_events.MessageErrorEvent.emit( + MessageErrorEvent.emit( brokerCtx, - waku_message_events.MessageErrorEvent( - requestId: msgReqIds[1], messageHash: "", error: "synthetic" - ), + MessageErrorEvent(requestId: msgReqIds[1], messageHash: "", error: "synthetic"), ) let erroredArrived = await erroredFut.withTimeout(1.seconds) check erroredArrived @@ -364,9 +359,8 @@ suite "Reliable Channel - send state machine": let id = RequestId("race-msg-req-" & $(msgReqIds.len + 1)) msgReqIds.add(id) if msgReqIds.len == 2: - waku_message_events.MessageSentEvent.emit( - brokerCtx, - waku_message_events.MessageSentEvent(requestId: msgReqIds[0], messageHash: ""), + MessageSentEvent.emit( + brokerCtx, MessageSentEvent(requestId: msgReqIds[0], messageHash: "") ) await sleepAsync(50.milliseconds) sendsReturned.inc() @@ -419,9 +413,8 @@ suite "Reliable Channel - send state machine": ## Finalise the second segment from the outside. If the race ## corrupted state, `channelReqId2`'s entry would never reach ## `inflightMessagingIds` and this event would silently miss. - waku_message_events.MessageSentEvent.emit( - brokerCtx, - waku_message_events.MessageSentEvent(requestId: msgReqIds[1], messageHash: ""), + MessageSentEvent.emit( + brokerCtx, MessageSentEvent(requestId: msgReqIds[1], messageHash: "") ) let arrived = await bothFinalised.withTimeout(2.seconds) @@ -556,9 +549,9 @@ suite "Reliable Channel - SDS lifecycle": ).expect("wrap m2") ## m2 first: missing dependency m1 -> parked, nothing delivered. - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "hash-m2", message: sdsWakuMessage(contentTopic, wire2) ), ) @@ -566,9 +559,9 @@ suite "Reliable Channel - SDS lifecycle": check deliveries.len == 0 ## m1 arrives: m1 delivered, then the parked m2 released after it. - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "hash-m1", message: sdsWakuMessage(contentTopic, wire1) ), ) @@ -622,15 +615,15 @@ suite "Reliable Channel - SDS lifecycle": ).expect("wrap") ## Same envelope twice (different hashes) — the second must be suppressed. - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "dup-hash-1", message: sdsWakuMessage(contentTopic, wire) ), ) - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "dup-hash-2", message: sdsWakuMessage(contentTopic, wire) ), ) @@ -678,9 +671,9 @@ suite "Reliable Channel - SDS lifecycle": ) ).expect("wrap") - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "foreign-hash", message: sdsWakuMessage(contentTopic, wire) ), ) @@ -738,9 +731,9 @@ suite "Reliable Channel - SDS lifecycle": ) ).expect("wrap") - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "restore-hash-1", message: sdsWakuMessage(contentTopic, wire) ), ) @@ -768,9 +761,9 @@ suite "Reliable Channel - SDS lifecycle": .expect("re-createReliableChannel") ## Replay the same envelope. Only a restored history suppresses it. - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "restore-hash-2", message: sdsWakuMessage(contentTopic, wire) ), ) @@ -820,9 +813,9 @@ suite "Reliable Channel - SDS protocol semantics": ).expect("wrap m1") let m1 = deserializeMessage(wire1).expect("deserialize m1") - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "semantics-hash-1", message: sdsWakuMessage(contentTopic, wire1) ), ) @@ -916,9 +909,9 @@ suite "Reliable Channel - SDS protocol semantics": ) ).expect("wrap ack carrier") - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "ack-hash-1", message: sdsWakuMessage(contentTopic, ackCarrier) ), ) @@ -982,9 +975,9 @@ suite "Reliable Channel - SDS protocol semantics": ## Deepest first: m3, then m2 — both must be parked. for i in [2, 1]: - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "chain-hash-" & $(i + 1), message: sdsWakuMessage(contentTopic, wires[i]), ), @@ -993,9 +986,9 @@ suite "Reliable Channel - SDS protocol semantics": check deliveries.len == 0 ## The root arrives: everything drains in causal order. - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "chain-hash-1", message: sdsWakuMessage(contentTopic, wires[0]) ), ) @@ -1054,9 +1047,9 @@ suite "Reliable Channel - SDS protocol semantics": ) let syncWire = serializeMessage(syncMsg).expect("serialize sync") - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "sync-hash-1", message: sdsWakuMessage(contentTopic, syncWire) ), ) @@ -1070,9 +1063,9 @@ suite "Reliable Channel - SDS protocol semantics": appPayload, "sync-m1", SdsChannelID(channelId) ) ).expect("wrap") - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "sync-hash-2", message: sdsWakuMessage(contentTopic, wire) ), ) @@ -1145,9 +1138,9 @@ suite "Reliable Channel - SDS protocol semantics": appPayload, "unique-m" & $i, SdsChannelID(channelId) ) ).expect("wrap " & $i) - waku_message_events.MessageReceivedEvent.emit( + MessageReceivedEvent.emit( brokerCtx, - waku_message_events.MessageReceivedEvent( + MessageReceivedEvent( messageHash: "unique-hash-" & $i, message: sdsWakuMessage(contentTopic, wire) ), ) From f3cb30903c3b7f4f567f0b29ffb06d5408e6a32f Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 16:15:39 +0200 Subject: [PATCH 13/17] nph --- logos_delivery/api/types.nim | 1 - logos_delivery/waku/events/events.nim | 6 ++---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/logos_delivery/api/types.nim b/logos_delivery/api/types.nim index c73b98e38..415e4bf0b 100644 --- a/logos_delivery/api/types.nim +++ b/logos_delivery/api/types.nim @@ -52,7 +52,6 @@ proc hash*(r: RequestId): Hash = ## Allows `RequestId` to be used as a `Table` key. hash(string(r)) - proc init*( T: type MessageEnvelope, contentTopic: ContentTopic, diff --git a/logos_delivery/waku/events/events.nim b/logos_delivery/waku/events/events.nim index b087cfb8e..56d8eee7f 100644 --- a/logos_delivery/waku/events/events.nim +++ b/logos_delivery/waku/events/events.nim @@ -1,5 +1,3 @@ -import - ./[delivery_events, health_events, peer_events, discovery_events] +import ./[delivery_events, health_events, peer_events, discovery_events] -export - delivery_events, health_events, peer_events, discovery_events +export delivery_events, health_events, peer_events, discovery_events From 7d45e64753042dcf649a0014558ccc4823a1cbd1 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 21:16:01 +0200 Subject: [PATCH 14/17] Remove unnecessary line in checkApiAvailability --- logos_delivery/messaging/messaging_client.nim | 1 - 1 file changed, 1 deletion(-) diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index 3f93ca689..6db970a72 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -47,7 +47,6 @@ proc stop*(self: MessagingClient) {.async.} = proc checkApiAvailability(self: MessagingClient): Result[void, string] = if self.isNil(): return err("MessagingClient is not initialized") - return ok() method subscribe*( From f357ffbe536b1222b18422fe3e43fe8a27f550b0 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Wed, 24 Jun 2026 17:45:24 +0200 Subject: [PATCH 15/17] fixing namaings, tyoe --- logos_delivery/messaging/messaging_client.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index 6db970a72..275da8431 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -49,16 +49,16 @@ proc checkApiAvailability(self: MessagingClient): Result[void, string] = return err("MessagingClient is not initialized") return ok() -method subscribe*( +proc subscribe*( self: MessagingClient, contentTopic: ContentTopic -): Future[Result[void, string]] {.async: (raises: []).} = +): Future[Result[void, string]] {.async.} = ?checkApiAvailability(self) return self.node.subscriptionManager.subscribe(contentTopic) -method unsubscribe*( +proc unsubscribe*( self: MessagingClient, contentTopic: ContentTopic -): Result[void, string] {.raises: [].} = +): Result[void, string] = ?checkApiAvailability(self) return self.node.subscriptionManager.unsubscribe(contentTopic) From f3f1bb2481a92e0ab0b90dd0e845582a90599481 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:00:08 +0200 Subject: [PATCH 16/17] Fixing rebase bad merge --- logos_delivery/messaging/messaging_client.nim | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index 275da8431..879a8d77f 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -49,16 +49,16 @@ proc checkApiAvailability(self: MessagingClient): Result[void, string] = return err("MessagingClient is not initialized") return ok() -proc subscribe*( +method subscribe*( self: MessagingClient, contentTopic: ContentTopic -): Future[Result[void, string]] {.async.} = +): Future[Result[void, string]] {.async: (raises: []).} = ?checkApiAvailability(self) return self.node.subscriptionManager.subscribe(contentTopic) -proc unsubscribe*( +method unsubscribe*( self: MessagingClient, contentTopic: ContentTopic -): Result[void, string] = +): Result[void, string] {.raises[].} = ?checkApiAvailability(self) return self.node.subscriptionManager.unsubscribe(contentTopic) From 8f9ddc80cec1719de64fffd245df6e17612a41f6 Mon Sep 17 00:00:00 2001 From: NagyZoltanPeter <113987313+NagyZoltanPeter@users.noreply.github.com> Date: Thu, 25 Jun 2026 10:04:39 +0200 Subject: [PATCH 17/17] typo fix --- logos_delivery/messaging/messaging_client.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/logos_delivery/messaging/messaging_client.nim b/logos_delivery/messaging/messaging_client.nim index 879a8d77f..6db970a72 100644 --- a/logos_delivery/messaging/messaging_client.nim +++ b/logos_delivery/messaging/messaging_client.nim @@ -58,7 +58,7 @@ method subscribe*( method unsubscribe*( self: MessagingClient, contentTopic: ContentTopic -): Result[void, string] {.raises[].} = +): Result[void, string] {.raises: [].} = ?checkApiAvailability(self) return self.node.subscriptionManager.unsubscribe(contentTopic)