2024-06-28 16:04:57 +05:30
|
|
|
|
{.push raises: [].}
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
|
|
|
|
|
import
|
2025-10-08 20:06:46 +05:30
|
|
|
|
std/[options, tables, strutils, sequtils, os, net, random],
|
2024-03-16 00:08:47 +01:00
|
|
|
|
chronos,
|
|
|
|
|
|
chronicles,
|
|
|
|
|
|
metrics,
|
2024-07-09 13:14:28 +02:00
|
|
|
|
results,
|
2022-10-18 09:05:53 -05:00
|
|
|
|
eth/keys,
|
|
|
|
|
|
nimcrypto,
|
|
|
|
|
|
bearssl/rand,
|
2025-10-08 20:06:46 +05:30
|
|
|
|
stew/byteutils,
|
2022-10-18 09:05:53 -05:00
|
|
|
|
eth/p2p/discoveryv5/enr,
|
|
|
|
|
|
libp2p/crypto/crypto,
|
2025-09-11 20:40:01 +05:30
|
|
|
|
libp2p/crypto/curve25519,
|
|
|
|
|
|
libp2p/[multiaddress, multicodec],
|
2022-10-18 09:05:53 -05:00
|
|
|
|
libp2p/protocols/ping,
|
2022-11-04 10:52:08 +01:00
|
|
|
|
libp2p/protocols/pubsub/gossipsub,
|
|
|
|
|
|
libp2p/protocols/pubsub/rpc/messages,
|
|
|
|
|
|
libp2p/builders,
|
2023-11-16 18:15:27 +02:00
|
|
|
|
libp2p/transports/transport,
|
2022-11-04 10:52:08 +01:00
|
|
|
|
libp2p/transports/tcptransport,
|
2025-03-05 12:07:56 +01:00
|
|
|
|
libp2p/transports/wstransport,
|
2025-09-11 20:40:01 +05:30
|
|
|
|
libp2p/utility,
|
2025-10-23 10:00:11 +05:30
|
|
|
|
libp2p/protocols/mix,
|
|
|
|
|
|
libp2p/protocols/mix/mix_protocol
|
2025-09-11 20:40:01 +05:30
|
|
|
|
|
2022-10-18 09:05:53 -05:00
|
|
|
|
import
|
2023-04-19 13:29:23 +02:00
|
|
|
|
../waku_core,
|
2023-09-26 07:33:52 -04:00
|
|
|
|
../waku_core/topics/sharding,
|
2023-04-18 15:22:10 +02:00
|
|
|
|
../waku_relay,
|
|
|
|
|
|
../waku_archive,
|
2024-07-12 12:19:12 -04:00
|
|
|
|
../waku_archive_legacy,
|
2024-04-25 09:09:52 -04:00
|
|
|
|
../waku_store_legacy/protocol as legacy_store,
|
|
|
|
|
|
../waku_store_legacy/client as legacy_store_client,
|
|
|
|
|
|
../waku_store_legacy/common as legacy_store_common,
|
|
|
|
|
|
../waku_store/protocol as store,
|
2023-04-18 15:22:10 +02:00
|
|
|
|
../waku_store/client as store_client,
|
2024-04-25 09:09:52 -04:00
|
|
|
|
../waku_store/common as store_common,
|
2024-07-30 07:23:39 -04:00
|
|
|
|
../waku_store/resume,
|
2025-01-24 11:46:11 -05:00
|
|
|
|
../waku_store_sync,
|
2023-04-18 15:22:10 +02:00
|
|
|
|
../waku_filter_v2,
|
2023-09-14 21:28:57 +02:00
|
|
|
|
../waku_filter_v2/client as filter_client,
|
2023-10-11 08:58:45 +02:00
|
|
|
|
../waku_metadata,
|
2024-12-09 15:22:36 -05:00
|
|
|
|
../waku_rendezvous/protocol,
|
2025-03-05 12:07:56 +01:00
|
|
|
|
../waku_lightpush_legacy/client as legacy_ligntpuhs_client,
|
|
|
|
|
|
../waku_lightpush_legacy as legacy_lightpush_protocol,
|
|
|
|
|
|
../waku_lightpush/client as ligntpuhs_client,
|
|
|
|
|
|
../waku_lightpush as lightpush_protocol,
|
2023-04-18 15:22:10 +02:00
|
|
|
|
../waku_enr,
|
|
|
|
|
|
../waku_peer_exchange,
|
2023-09-11 12:02:31 +05:30
|
|
|
|
../waku_rln_relay,
|
2025-05-08 07:05:35 +10:00
|
|
|
|
./net_config,
|
2024-04-15 15:28:35 +02:00
|
|
|
|
./peer_manager,
|
2025-08-29 18:43:29 +05:30
|
|
|
|
../common/rate_limit/setting,
|
2025-09-11 20:40:01 +05:30
|
|
|
|
../common/callbacks,
|
|
|
|
|
|
../common/nimchronos,
|
|
|
|
|
|
../waku_mix
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
|
|
|
|
|
declarePublicCounter waku_node_messages, "number of messages received", ["type"]
|
2023-04-20 13:45:29 +02:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
declarePublicGauge waku_version,
|
|
|
|
|
|
"Waku version info (in git describe format)", ["version"]
|
2025-08-01 16:11:32 +05:30
|
|
|
|
declarePublicCounter waku_node_errors, "number of wakunode errors", ["type"]
|
2022-10-28 16:30:01 +02:00
|
|
|
|
declarePublicGauge waku_lightpush_peers, "number of lightpush peers"
|
2022-11-02 11:59:58 +01:00
|
|
|
|
declarePublicGauge waku_filter_peers, "number of filter peers"
|
2022-10-28 20:11:28 +02:00
|
|
|
|
declarePublicGauge waku_store_peers, "number of store peers"
|
2024-03-16 00:08:47 +01:00
|
|
|
|
declarePublicGauge waku_px_peers,
|
|
|
|
|
|
"number of peers (in the node's peerManager) supporting the peer exchange protocol"
|
2022-10-28 16:30:01 +02:00
|
|
|
|
|
2022-10-18 09:05:53 -05:00
|
|
|
|
logScope:
|
2022-11-03 16:36:24 +01:00
|
|
|
|
topics = "waku node"
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2025-06-27 11:16:00 +02:00
|
|
|
|
# randomize initializes sdt/random's random number generator
|
|
|
|
|
|
# if not called, the outcome of randomization procedures will be the same in every run
|
|
|
|
|
|
randomize()
|
|
|
|
|
|
|
2023-04-05 09:46:13 +02:00
|
|
|
|
# TODO: Move to application instance (e.g., `WakuNode2`)
|
2022-10-18 09:05:53 -05:00
|
|
|
|
# Git version in git describe format (defined compile time)
|
|
|
|
|
|
const git_version* {.strdefine.} = "n/a"
|
|
|
|
|
|
|
|
|
|
|
|
# Default clientId
|
|
|
|
|
|
const clientId* = "Nimbus Waku v2 node"
|
|
|
|
|
|
|
2023-05-12 18:08:41 +02:00
|
|
|
|
const WakuNodeVersionString* = "version / git commit hash: " & git_version
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
|
|
|
|
|
# key and crypto modules different
|
|
|
|
|
|
type
|
2023-04-05 09:46:13 +02:00
|
|
|
|
# TODO: Move to application instance (e.g., `WakuNode2`)
|
2024-03-16 00:08:47 +01:00
|
|
|
|
WakuInfo* = object # NOTE One for simplicity, can extend later as needed
|
2022-10-18 09:05:53 -05:00
|
|
|
|
listenAddresses*: seq[string]
|
2024-03-16 00:08:47 +01:00
|
|
|
|
enrUri*: string #multiaddrStrings*: seq[string]
|
2025-10-08 10:18:54 +05:30
|
|
|
|
mixPubKey*: Option[string]
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
|
|
|
|
|
# NOTE based on Eth2Node in NBC eth2_network.nim
|
2022-10-27 17:29:09 +02:00
|
|
|
|
WakuNode* = ref object
|
2022-10-18 09:05:53 -05:00
|
|
|
|
peerManager*: PeerManager
|
|
|
|
|
|
switch*: Switch
|
|
|
|
|
|
wakuRelay*: WakuRelay
|
2024-07-12 12:19:12 -04:00
|
|
|
|
wakuArchive*: waku_archive.WakuArchive
|
|
|
|
|
|
wakuLegacyArchive*: waku_archive_legacy.WakuArchive
|
2024-04-25 09:09:52 -04:00
|
|
|
|
wakuLegacyStore*: legacy_store.WakuStore
|
|
|
|
|
|
wakuLegacyStoreClient*: legacy_store_client.WakuStoreClient
|
|
|
|
|
|
wakuStore*: store.WakuStore
|
|
|
|
|
|
wakuStoreClient*: store_client.WakuStoreClient
|
2024-07-30 07:23:39 -04:00
|
|
|
|
wakuStoreResume*: StoreResume
|
2025-01-24 11:46:11 -05:00
|
|
|
|
wakuStoreReconciliation*: SyncReconciliation
|
|
|
|
|
|
wakuStoreTransfer*: SyncTransfer
|
2023-04-11 10:12:54 +02:00
|
|
|
|
wakuFilter*: waku_filter_v2.WakuFilter
|
2023-09-14 21:28:57 +02:00
|
|
|
|
wakuFilterClient*: filter_client.WakuFilterClient
|
2023-09-11 12:02:31 +05:30
|
|
|
|
wakuRlnRelay*: WakuRLNRelay
|
2025-03-05 12:07:56 +01:00
|
|
|
|
wakuLegacyLightPush*: WakuLegacyLightPush
|
|
|
|
|
|
wakuLegacyLightpushClient*: WakuLegacyLightPushClient
|
2022-10-18 09:05:53 -05:00
|
|
|
|
wakuLightPush*: WakuLightPush
|
2022-10-28 16:30:01 +02:00
|
|
|
|
wakuLightpushClient*: WakuLightPushClient
|
2022-10-18 09:05:53 -05:00
|
|
|
|
wakuPeerExchange*: WakuPeerExchange
|
2025-08-13 12:04:01 +05:30
|
|
|
|
wakuPeerExchangeClient*: WakuPeerExchangeClient
|
2023-10-11 08:58:45 +02:00
|
|
|
|
wakuMetadata*: WakuMetadata
|
2025-07-04 17:10:53 +10:00
|
|
|
|
wakuAutoSharding*: Option[Sharding]
|
2022-10-18 09:05:53 -05:00
|
|
|
|
enr*: enr.Record
|
|
|
|
|
|
libp2pPing*: Ping
|
|
|
|
|
|
rng*: ref rand.HmacDrbgContext
|
2024-12-09 15:22:36 -05:00
|
|
|
|
wakuRendezvous*: WakuRendezVous
|
2024-03-16 00:08:47 +01:00
|
|
|
|
announcedAddresses*: seq[MultiAddress]
|
2022-10-18 09:05:53 -05:00
|
|
|
|
started*: bool # Indicates that node has started listening
|
2023-08-23 09:53:17 -04:00
|
|
|
|
topicSubscriptionQueue*: AsyncEventQueue[SubscriptionEvent]
|
2024-09-18 15:58:07 +02:00
|
|
|
|
rateLimitSettings*: ProtocolRateLimitSettings
|
2025-09-11 20:40:01 +05:30
|
|
|
|
wakuMix*: WakuMix
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2025-08-29 18:43:29 +05:30
|
|
|
|
proc getShardsGetter(node: WakuNode): GetShards =
|
|
|
|
|
|
return proc(): seq[uint16] {.closure, gcsafe, raises: [].} =
|
|
|
|
|
|
# fetch pubsubTopics subscribed to relay and convert them to shards
|
|
|
|
|
|
if node.wakuRelay.isNil():
|
|
|
|
|
|
return @[]
|
2025-09-09 14:04:10 +02:00
|
|
|
|
let subscribedTopics = node.wakuRelay.subscribedTopics()
|
|
|
|
|
|
let relayShards = topicsToRelayShards(subscribedTopics).valueOr:
|
|
|
|
|
|
error "could not convert relay topics to shards",
|
|
|
|
|
|
error = $error, topics = subscribedTopics
|
2025-08-29 18:43:29 +05:30
|
|
|
|
return @[]
|
|
|
|
|
|
if relayShards.isSome():
|
|
|
|
|
|
let shards = relayShards.get().shardIds
|
|
|
|
|
|
return shards
|
|
|
|
|
|
return @[]
|
|
|
|
|
|
|
2025-09-11 22:40:13 +05:30
|
|
|
|
proc getCapabilitiesGetter(node: WakuNode): GetCapabilities =
|
|
|
|
|
|
return proc(): seq[Capabilities] {.closure, gcsafe, raises: [].} =
|
|
|
|
|
|
if node.wakuRelay.isNil():
|
|
|
|
|
|
return @[]
|
|
|
|
|
|
return node.enr.getCapabilities()
|
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
proc new*(
|
|
|
|
|
|
T: type WakuNode,
|
|
|
|
|
|
netConfig: NetConfig,
|
|
|
|
|
|
enr: enr.Record,
|
|
|
|
|
|
switch: Switch,
|
|
|
|
|
|
peerManager: PeerManager,
|
2025-07-09 15:57:38 +10:00
|
|
|
|
rateLimitSettings: ProtocolRateLimitSettings = DefaultProtocolRateLimit,
|
2024-03-16 00:08:47 +01:00
|
|
|
|
# TODO: make this argument required after tests are updated
|
|
|
|
|
|
rng: ref HmacDrbgContext = crypto.newRng(),
|
|
|
|
|
|
): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} =
|
2023-02-07 18:36:50 +05:30
|
|
|
|
## Creates a Waku Node instance.
|
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
info "Initializing networking", addrs = $netConfig.announcedAddresses
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2024-03-25 10:33:01 -04:00
|
|
|
|
let queue = newAsyncEventQueue[SubscriptionEvent](0)
|
2023-10-11 08:58:45 +02:00
|
|
|
|
let node = WakuNode(
|
2023-06-23 15:30:28 +02:00
|
|
|
|
peerManager: peerManager,
|
2022-10-18 09:05:53 -05:00
|
|
|
|
switch: switch,
|
|
|
|
|
|
rng: rng,
|
2023-06-22 16:58:14 -04:00
|
|
|
|
enr: enr,
|
2023-02-07 18:36:50 +05:30
|
|
|
|
announcedAddresses: netConfig.announcedAddresses,
|
2024-03-16 00:08:47 +01:00
|
|
|
|
topicSubscriptionQueue: queue,
|
2025-07-09 15:57:38 +10:00
|
|
|
|
rateLimitSettings: rateLimitSettings,
|
2022-10-18 09:05:53 -05:00
|
|
|
|
)
|
|
|
|
|
|
|
2025-08-29 18:43:29 +05:30
|
|
|
|
peerManager.setShardGetter(node.getShardsGetter())
|
|
|
|
|
|
|
2023-10-11 08:58:45 +02:00
|
|
|
|
return node
|
|
|
|
|
|
|
2022-11-21 09:36:41 +01:00
|
|
|
|
proc peerInfo*(node: WakuNode): PeerInfo =
|
2022-10-18 09:05:53 -05:00
|
|
|
|
node.switch.peerInfo
|
|
|
|
|
|
|
2023-02-27 17:36:24 +02:00
|
|
|
|
proc peerId*(node: WakuNode): PeerId =
|
|
|
|
|
|
node.peerInfo.peerId
|
|
|
|
|
|
|
2023-04-05 09:46:13 +02:00
|
|
|
|
# TODO: Move to application instance (e.g., `WakuNode2`)
|
2022-10-27 17:29:09 +02:00
|
|
|
|
# TODO: Extend with more relevant info: topics, peers, memory usage, online time, etc
|
|
|
|
|
|
proc info*(node: WakuNode): WakuInfo =
|
|
|
|
|
|
## Returns information about the Node, such as what multiaddress it can be reached at.
|
|
|
|
|
|
|
|
|
|
|
|
let peerInfo = node.switch.peerInfo
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
var listenStr: seq[string]
|
2022-10-27 17:29:09 +02:00
|
|
|
|
for address in node.announcedAddresses:
|
|
|
|
|
|
var fulladdr = $address & "/p2p/" & $peerInfo.peerId
|
|
|
|
|
|
listenStr &= fulladdr
|
|
|
|
|
|
let enrUri = node.enr.toUri()
|
2025-10-08 10:18:54 +05:30
|
|
|
|
var wakuInfo = WakuInfo(listenAddresses: listenStr, enrUri: enrUri)
|
|
|
|
|
|
if not node.wakuMix.isNil():
|
|
|
|
|
|
let keyStr = node.wakuMix.pubKey.to0xHex()
|
|
|
|
|
|
wakuInfo.mixPubKey = some(keyStr)
|
|
|
|
|
|
info "node info", wakuInfo
|
2022-10-27 17:29:09 +02:00
|
|
|
|
return wakuInfo
|
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
proc connectToNodes*(
|
|
|
|
|
|
node: WakuNode, nodes: seq[RemotePeerInfo] | seq[string], source = "api"
|
|
|
|
|
|
) {.async.} =
|
2022-10-27 17:29:09 +02:00
|
|
|
|
## `source` indicates source of node addrs (static config, api call, discovery, etc)
|
2023-03-28 13:29:48 +02:00
|
|
|
|
# NOTE Connects to the node without a give protocol, which automatically creates streams for relay
|
2024-03-16 00:08:47 +01:00
|
|
|
|
await peer_manager.connectToNodes(node.peerManager, nodes, source = source)
|
2022-10-27 17:29:09 +02:00
|
|
|
|
|
2024-09-24 18:20:29 +02:00
|
|
|
|
proc disconnectNode*(node: WakuNode, remotePeer: RemotePeerInfo) {.async.} =
|
|
|
|
|
|
await peer_manager.disconnectNode(node.peerManager, remotePeer)
|
|
|
|
|
|
|
2025-08-13 10:48:56 +05:30
|
|
|
|
proc mountMetadata*(
|
|
|
|
|
|
node: WakuNode, clusterId: uint32, shards: seq[uint16]
|
|
|
|
|
|
): Result[void, string] =
|
2023-11-21 15:15:39 -05:00
|
|
|
|
if not node.wakuMetadata.isNil():
|
|
|
|
|
|
return err("Waku metadata already mounted, skipping")
|
2025-08-29 18:43:29 +05:30
|
|
|
|
|
|
|
|
|
|
let metadata = WakuMetadata.new(clusterId, node.getShardsGetter())
|
2023-11-21 15:15:39 -05:00
|
|
|
|
|
|
|
|
|
|
node.wakuMetadata = metadata
|
|
|
|
|
|
node.peerManager.wakuMetadata = metadata
|
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let catchRes = catch:
|
|
|
|
|
|
node.switch.mount(node.wakuMetadata, protocolMatcher(WakuMetadataCodec))
|
2025-10-27 14:07:06 -03:00
|
|
|
|
catchRes.isOkOr:
|
|
|
|
|
|
return err(error.msg)
|
2023-11-21 15:15:39 -05:00
|
|
|
|
|
|
|
|
|
|
return ok()
|
2022-10-27 17:29:09 +02:00
|
|
|
|
|
2025-07-04 17:10:53 +10:00
|
|
|
|
## Waku AutoSharding
|
|
|
|
|
|
proc mountAutoSharding*(
|
2024-06-05 15:32:35 +02:00
|
|
|
|
node: WakuNode, clusterId: uint16, shardCount: uint32
|
2024-03-16 00:08:47 +01:00
|
|
|
|
): Result[void, string] =
|
2025-07-04 17:10:53 +10:00
|
|
|
|
info "mounting auto sharding", clusterId = clusterId, shardCount = shardCount
|
|
|
|
|
|
node.wakuAutoSharding =
|
|
|
|
|
|
some(Sharding(clusterId: clusterId, shardCountGenZero: shardCount))
|
2024-03-13 10:58:13 +01:00
|
|
|
|
return ok()
|
|
|
|
|
|
|
2025-09-11 20:40:01 +05:30
|
|
|
|
proc getMixNodePoolSize*(node: WakuNode): int =
|
|
|
|
|
|
return node.wakuMix.getNodePoolSize()
|
|
|
|
|
|
|
|
|
|
|
|
proc mountMix*(
|
2025-10-08 10:18:54 +05:30
|
|
|
|
node: WakuNode,
|
|
|
|
|
|
clusterId: uint16,
|
|
|
|
|
|
mixPrivKey: Curve25519Key,
|
|
|
|
|
|
mixnodes: seq[MixNodePubInfo],
|
2025-09-11 20:40:01 +05:30
|
|
|
|
): Future[Result[void, string]] {.async.} =
|
|
|
|
|
|
info "mounting mix protocol", nodeId = node.info #TODO log the config used
|
|
|
|
|
|
|
|
|
|
|
|
if node.announcedAddresses.len == 0:
|
|
|
|
|
|
return err("Trying to mount mix without having announced addresses")
|
|
|
|
|
|
|
|
|
|
|
|
let localaddrStr = node.announcedAddresses[0].toString().valueOr:
|
|
|
|
|
|
return err("Failed to convert multiaddress to string.")
|
|
|
|
|
|
info "local addr", localaddr = localaddrStr
|
|
|
|
|
|
|
|
|
|
|
|
let nodeAddr = localaddrStr & "/p2p/" & $node.peerId
|
2025-10-08 10:18:54 +05:30
|
|
|
|
node.wakuMix = WakuMix.new(
|
|
|
|
|
|
nodeAddr, node.peerManager, clusterId, mixPrivKey, mixnodes
|
|
|
|
|
|
).valueOr:
|
2025-09-11 20:40:01 +05:30
|
|
|
|
error "Waku Mix protocol initialization failed", err = error
|
|
|
|
|
|
return
|
|
|
|
|
|
node.wakuMix.registerDestReadBehavior(WakuLightPushCodec, readLp(int(-1)))
|
|
|
|
|
|
let catchRes = catch:
|
|
|
|
|
|
node.switch.mount(node.wakuMix)
|
2025-10-27 14:07:06 -03:00
|
|
|
|
catchRes.isOkOr:
|
|
|
|
|
|
return err(error.msg)
|
2025-09-11 20:40:01 +05:30
|
|
|
|
return ok()
|
|
|
|
|
|
|
2025-01-24 11:46:11 -05:00
|
|
|
|
## Waku Sync
|
|
|
|
|
|
|
|
|
|
|
|
proc mountStoreSync*(
|
|
|
|
|
|
node: WakuNode,
|
2025-09-12 08:12:35 -04:00
|
|
|
|
cluster: uint16,
|
|
|
|
|
|
shards: seq[uint16],
|
|
|
|
|
|
contentTopics: seq[string],
|
|
|
|
|
|
storeSyncRange: uint32,
|
|
|
|
|
|
storeSyncInterval: uint32,
|
|
|
|
|
|
storeSyncRelayJitter: uint32,
|
2025-01-24 11:46:11 -05:00
|
|
|
|
): Future[Result[void, string]] {.async.} =
|
2025-09-12 08:12:35 -04:00
|
|
|
|
let idsChannel = newAsyncQueue[(SyncID, PubsubTopic, ContentTopic)](0)
|
|
|
|
|
|
let wantsChannel = newAsyncQueue[(PeerId)](0)
|
2025-03-24 08:36:19 -04:00
|
|
|
|
let needsChannel = newAsyncQueue[(PeerId, WakuMessageHash)](0)
|
2025-01-24 11:46:11 -05:00
|
|
|
|
|
2025-09-12 08:12:35 -04:00
|
|
|
|
let pubsubTopics = shards.mapIt($RelayShard(clusterId: cluster, shardId: it))
|
2025-01-30 08:46:34 -05:00
|
|
|
|
|
2025-01-24 11:46:11 -05:00
|
|
|
|
let recon =
|
|
|
|
|
|
?await SyncReconciliation.new(
|
2025-09-12 08:12:35 -04:00
|
|
|
|
pubsubTopics, contentTopics, node.peerManager, node.wakuArchive,
|
|
|
|
|
|
storeSyncRange.seconds, storeSyncInterval.seconds, storeSyncRelayJitter.seconds,
|
|
|
|
|
|
idsChannel, wantsChannel, needsChannel,
|
2025-01-24 11:46:11 -05:00
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
node.wakuStoreReconciliation = recon
|
|
|
|
|
|
|
2025-03-12 08:47:49 -04:00
|
|
|
|
let reconMountRes = catch:
|
|
|
|
|
|
node.switch.mount(
|
|
|
|
|
|
node.wakuStoreReconciliation, protocolMatcher(WakuReconciliationCodec)
|
|
|
|
|
|
)
|
2025-10-27 14:07:06 -03:00
|
|
|
|
reconMountRes.isOkOr:
|
|
|
|
|
|
return err(error.msg)
|
2025-03-12 08:47:49 -04:00
|
|
|
|
|
2025-01-24 11:46:11 -05:00
|
|
|
|
let transfer = SyncTransfer.new(
|
|
|
|
|
|
node.peerManager, node.wakuArchive, idsChannel, wantsChannel, needsChannel
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
node.wakuStoreTransfer = transfer
|
|
|
|
|
|
|
2025-03-12 08:47:49 -04:00
|
|
|
|
let transMountRes = catch:
|
|
|
|
|
|
node.switch.mount(node.wakuStoreTransfer, protocolMatcher(WakuTransferCodec))
|
2025-10-27 14:07:06 -03:00
|
|
|
|
transMountRes.isOkOr:
|
|
|
|
|
|
return err(error.msg)
|
2025-03-12 08:47:49 -04:00
|
|
|
|
|
2025-01-24 11:46:11 -05:00
|
|
|
|
return ok()
|
|
|
|
|
|
|
2022-10-27 17:29:09 +02:00
|
|
|
|
proc startRelay*(node: WakuNode) {.async.} =
|
2022-11-18 14:50:56 +01:00
|
|
|
|
## Setup and start relay protocol
|
|
|
|
|
|
info "starting relay protocol"
|
|
|
|
|
|
|
2022-10-27 17:29:09 +02:00
|
|
|
|
if node.wakuRelay.isNil():
|
2023-02-08 16:09:59 +01:00
|
|
|
|
error "Failed to start relay. Not mounted."
|
2022-10-27 17:29:09 +02:00
|
|
|
|
return
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2022-11-18 14:50:56 +01:00
|
|
|
|
## Setup relay protocol
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2022-10-27 17:29:09 +02:00
|
|
|
|
# Resume previous relay connections
|
2025-04-07 12:24:03 +02:00
|
|
|
|
if node.peerManager.switch.peerStore.hasPeers(protocolMatcher(WakuRelayCodec)):
|
2022-10-27 17:29:09 +02:00
|
|
|
|
info "Found previous WakuRelay peers. Reconnecting."
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2022-10-27 17:29:09 +02:00
|
|
|
|
# Reconnect to previous relay peers. This will respect a backoff period, if necessary
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let backoffPeriod =
|
|
|
|
|
|
node.wakuRelay.parameters.pruneBackoff + chronos.seconds(BackoffSlackTime)
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
await node.peerManager.reconnectPeers(WakuRelayCodec, backoffPeriod)
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2022-10-27 17:29:09 +02:00
|
|
|
|
# Start the WakuRelay protocol
|
|
|
|
|
|
await node.wakuRelay.start()
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2022-10-27 17:29:09 +02:00
|
|
|
|
info "relay started successfully"
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2025-06-27 11:16:00 +02:00
|
|
|
|
proc selectRandomPeers*(peers: seq[PeerId], numRandomPeers: int): seq[PeerId] =
|
|
|
|
|
|
var randomPeers = peers
|
|
|
|
|
|
shuffle(randomPeers)
|
|
|
|
|
|
return randomPeers[0 ..< min(len(randomPeers), numRandomPeers)]
|
|
|
|
|
|
|
2025-09-11 22:40:13 +05:30
|
|
|
|
proc mountRendezvous*(node: WakuNode, clusterId: uint16) {.async: (raises: []).} =
|
2023-06-01 21:43:10 +02:00
|
|
|
|
info "mounting rendezvous discovery protocol"
|
|
|
|
|
|
|
2025-09-11 22:40:13 +05:30
|
|
|
|
node.wakuRendezvous = WakuRendezVous.new(
|
|
|
|
|
|
node.switch,
|
|
|
|
|
|
node.peerManager,
|
|
|
|
|
|
clusterId,
|
|
|
|
|
|
node.getShardsGetter(),
|
|
|
|
|
|
node.getCapabilitiesGetter(),
|
|
|
|
|
|
).valueOr:
|
2024-12-09 15:22:36 -05:00
|
|
|
|
error "initializing waku rendezvous failed", error = error
|
2024-11-10 09:27:04 +01:00
|
|
|
|
return
|
2023-06-01 21:43:10 +02:00
|
|
|
|
|
2024-12-09 15:22:36 -05:00
|
|
|
|
if node.started:
|
|
|
|
|
|
await node.wakuRendezvous.start()
|
2023-06-01 21:43:10 +02:00
|
|
|
|
|
2023-10-27 10:11:47 +03:00
|
|
|
|
proc isBindIpWithZeroPort(inputMultiAdd: MultiAddress): bool =
|
|
|
|
|
|
let inputStr = $inputMultiAdd
|
|
|
|
|
|
if inputStr.contains("0.0.0.0/tcp/0") or inputStr.contains("127.0.0.1/tcp/0"):
|
|
|
|
|
|
return true
|
2022-10-27 17:29:09 +02:00
|
|
|
|
|
2023-10-27 10:11:47 +03:00
|
|
|
|
return false
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2024-10-28 09:17:46 +01:00
|
|
|
|
proc updateAnnouncedAddrWithPrimaryIpAddr*(node: WakuNode): Result[void, string] =
|
2022-10-18 09:05:53 -05:00
|
|
|
|
let peerInfo = node.switch.peerInfo
|
2023-11-16 18:15:27 +02:00
|
|
|
|
var announcedStr = ""
|
2022-10-18 09:05:53 -05:00
|
|
|
|
var listenStr = ""
|
2024-10-28 09:17:46 +01:00
|
|
|
|
var localIp = "0.0.0.0"
|
2023-11-16 18:15:27 +02:00
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
localIp = $getPrimaryIPAddr()
|
|
|
|
|
|
except Exception as e:
|
2024-03-16 00:08:47 +01:00
|
|
|
|
warn "Could not retrieve localIp", msg = e.msg
|
2023-10-27 10:11:47 +03:00
|
|
|
|
|
|
|
|
|
|
info "PeerInfo", peerId = peerInfo.peerId, addrs = peerInfo.addrs
|
|
|
|
|
|
|
2024-10-28 09:17:46 +01:00
|
|
|
|
## Update the WakuNode addresses
|
|
|
|
|
|
var newAnnouncedAddresses = newSeq[MultiAddress](0)
|
2022-10-18 09:05:53 -05:00
|
|
|
|
for address in node.announcedAddresses:
|
2024-10-28 09:17:46 +01:00
|
|
|
|
## Replace "0.0.0.0" or "127.0.0.1" with the localIp
|
|
|
|
|
|
let newAddr = ($address).replace("0.0.0.0", localIp).replace("127.0.0.1", localIp)
|
|
|
|
|
|
let fulladdr = "[" & $newAddr & "/p2p/" & $peerInfo.peerId & "]"
|
2023-11-16 18:15:27 +02:00
|
|
|
|
announcedStr &= fulladdr
|
2024-10-28 09:17:46 +01:00
|
|
|
|
let newMultiAddr = MultiAddress.init(newAddr).valueOr:
|
|
|
|
|
|
return err("error in updateAnnouncedAddrWithPrimaryIpAddr: " & $error)
|
|
|
|
|
|
newAnnouncedAddresses.add(newMultiAddr)
|
|
|
|
|
|
|
|
|
|
|
|
node.announcedAddresses = newAnnouncedAddresses
|
|
|
|
|
|
|
|
|
|
|
|
## Update the Switch addresses
|
|
|
|
|
|
node.switch.peerInfo.addrs = newAnnouncedAddresses
|
2023-11-16 18:15:27 +02:00
|
|
|
|
|
|
|
|
|
|
for transport in node.switch.transports:
|
|
|
|
|
|
for address in transport.addrs:
|
2024-10-28 09:17:46 +01:00
|
|
|
|
let fulladdr = "[" & $address & "/p2p/" & $peerInfo.peerId & "]"
|
2023-11-16 18:15:27 +02:00
|
|
|
|
listenStr &= fulladdr
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2024-10-28 09:17:46 +01:00
|
|
|
|
info "Listening on",
|
|
|
|
|
|
full = listenStr, localIp = localIp, switchAddress = $(node.switch.peerInfo.addrs)
|
2023-11-16 18:15:27 +02:00
|
|
|
|
info "Announcing addresses", full = announcedStr
|
2022-10-18 09:05:53 -05:00
|
|
|
|
info "DNS: discoverable ENR ", enr = node.enr.toUri()
|
|
|
|
|
|
|
2024-10-28 09:17:46 +01:00
|
|
|
|
return ok()
|
|
|
|
|
|
|
2023-10-27 10:11:47 +03:00
|
|
|
|
proc start*(node: WakuNode) {.async.} =
|
|
|
|
|
|
## Starts a created Waku Node and
|
|
|
|
|
|
## all its mounted protocols.
|
|
|
|
|
|
|
2024-03-16 00:08:47 +01:00
|
|
|
|
waku_version.set(1, labelValues = [git_version])
|
|
|
|
|
|
info "Starting Waku node", version = git_version
|
2023-10-27 10:11:47 +03:00
|
|
|
|
|
|
|
|
|
|
var zeroPortPresent = false
|
|
|
|
|
|
for address in node.announcedAddresses:
|
|
|
|
|
|
if isBindIpWithZeroPort(address):
|
|
|
|
|
|
zeroPortPresent = true
|
|
|
|
|
|
|
2022-10-18 09:05:53 -05:00
|
|
|
|
# Perform relay-specific startup tasks TODO: this should be rethought
|
2022-10-27 17:29:09 +02:00
|
|
|
|
if not node.wakuRelay.isNil():
|
2022-10-18 09:05:53 -05:00
|
|
|
|
await node.startRelay()
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2025-09-11 20:40:01 +05:30
|
|
|
|
if not node.wakuMix.isNil():
|
|
|
|
|
|
node.wakuMix.start()
|
|
|
|
|
|
|
2023-11-21 15:15:39 -05:00
|
|
|
|
if not node.wakuMetadata.isNil():
|
|
|
|
|
|
node.wakuMetadata.start()
|
|
|
|
|
|
|
2024-07-30 07:23:39 -04:00
|
|
|
|
if not node.wakuStoreResume.isNil():
|
|
|
|
|
|
await node.wakuStoreResume.start()
|
|
|
|
|
|
|
2024-12-09 15:22:36 -05:00
|
|
|
|
if not node.wakuRendezvous.isNil():
|
|
|
|
|
|
await node.wakuRendezvous.start()
|
|
|
|
|
|
|
2025-01-24 11:46:11 -05:00
|
|
|
|
if not node.wakuStoreReconciliation.isNil():
|
|
|
|
|
|
node.wakuStoreReconciliation.start()
|
|
|
|
|
|
|
|
|
|
|
|
if not node.wakuStoreTransfer.isNil():
|
|
|
|
|
|
node.wakuStoreTransfer.start()
|
|
|
|
|
|
|
2022-10-28 12:51:46 +03:00
|
|
|
|
## The switch uses this mapper to update peer info addrs
|
|
|
|
|
|
## with announced addrs after start
|
2024-03-16 00:08:47 +01:00
|
|
|
|
let addressMapper = proc(
|
|
|
|
|
|
listenAddrs: seq[MultiAddress]
|
2025-05-26 21:58:02 +02:00
|
|
|
|
): Future[seq[MultiAddress]] {.gcsafe, async: (raises: [CancelledError]).} =
|
2024-03-16 00:08:47 +01:00
|
|
|
|
return node.announcedAddresses
|
2022-10-28 12:51:46 +03:00
|
|
|
|
node.switch.peerInfo.addressMappers.add(addressMapper)
|
|
|
|
|
|
|
|
|
|
|
|
## The switch will update addresses after start using the addressMapper
|
|
|
|
|
|
await node.switch.start()
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
|
|
|
|
|
node.started = true
|
2022-11-21 09:36:41 +01:00
|
|
|
|
|
2023-11-16 18:15:27 +02:00
|
|
|
|
if not zeroPortPresent:
|
2024-10-28 09:17:46 +01:00
|
|
|
|
updateAnnouncedAddrWithPrimaryIpAddr(node).isOkOr:
|
|
|
|
|
|
error "failed update announced addr", error = $error
|
2023-11-16 18:15:27 +02:00
|
|
|
|
else:
|
|
|
|
|
|
info "Listening port is dynamically allocated, address and ENR generation postponed"
|
|
|
|
|
|
|
2022-10-18 09:05:53 -05:00
|
|
|
|
info "Node started successfully"
|
|
|
|
|
|
|
|
|
|
|
|
proc stop*(node: WakuNode) {.async.} =
|
2024-04-30 12:52:11 +02:00
|
|
|
|
## By stopping the switch we are stopping all the underlying mounted protocols
|
|
|
|
|
|
await node.switch.stop()
|
|
|
|
|
|
|
2023-01-26 10:20:20 +01:00
|
|
|
|
node.peerManager.stop()
|
2022-10-18 09:05:53 -05:00
|
|
|
|
|
2023-09-11 12:02:31 +05:30
|
|
|
|
if not node.wakuRlnRelay.isNil():
|
2023-12-14 07:16:39 +01:00
|
|
|
|
try:
|
|
|
|
|
|
await node.wakuRlnRelay.stop() ## this can raise an exception
|
|
|
|
|
|
except Exception:
|
2024-03-16 00:08:47 +01:00
|
|
|
|
error "exception stopping the node", error = getCurrentExceptionMsg()
|
2023-07-27 17:21:21 +05:30
|
|
|
|
|
2023-12-11 08:50:40 +01:00
|
|
|
|
if not node.wakuArchive.isNil():
|
2024-03-12 07:51:03 -04:00
|
|
|
|
await node.wakuArchive.stopWait()
|
2023-12-11 08:50:40 +01:00
|
|
|
|
|
2024-07-30 07:23:39 -04:00
|
|
|
|
if not node.wakuStoreResume.isNil():
|
|
|
|
|
|
await node.wakuStoreResume.stopWait()
|
|
|
|
|
|
|
2025-01-24 11:46:11 -05:00
|
|
|
|
if not node.wakuStoreReconciliation.isNil():
|
|
|
|
|
|
node.wakuStoreReconciliation.stop()
|
|
|
|
|
|
|
|
|
|
|
|
if not node.wakuStoreTransfer.isNil():
|
|
|
|
|
|
node.wakuStoreTransfer.stop()
|
|
|
|
|
|
|
2024-10-30 12:51:04 +02:00
|
|
|
|
if not node.wakuPeerExchange.isNil() and not node.wakuPeerExchange.pxLoopHandle.isNil():
|
|
|
|
|
|
await node.wakuPeerExchange.pxLoopHandle.cancelAndWait()
|
|
|
|
|
|
|
2025-08-13 12:04:01 +05:30
|
|
|
|
if not node.wakuPeerExchangeClient.isNil() and
|
|
|
|
|
|
not node.wakuPeerExchangeClient.pxLoopHandle.isNil():
|
|
|
|
|
|
await node.wakuPeerExchangeClient.pxLoopHandle.cancelAndWait()
|
|
|
|
|
|
|
2024-12-09 15:22:36 -05:00
|
|
|
|
if not node.wakuRendezvous.isNil():
|
|
|
|
|
|
await node.wakuRendezvous.stopWait()
|
|
|
|
|
|
|
2022-11-21 09:36:41 +01:00
|
|
|
|
node.started = false
|
2023-09-06 14:16:19 +05:30
|
|
|
|
|
2023-12-14 07:16:39 +01:00
|
|
|
|
proc isReady*(node: WakuNode): Future[bool] {.async: (raises: [Exception]).} =
|
2023-09-11 12:02:31 +05:30
|
|
|
|
if node.wakuRlnRelay == nil:
|
|
|
|
|
|
return true
|
|
|
|
|
|
return await node.wakuRlnRelay.isReady()
|
2023-09-06 14:16:19 +05:30
|
|
|
|
## TODO: add other protocol `isReady` checks
|