diff --git a/Makefile b/Makefile index c62688aed..f50bed98c 100644 --- a/Makefile +++ b/Makefile @@ -172,15 +172,10 @@ deps: | nimble ################## ## RLN ## ################## -.PHONY: librln mix-librln +.PHONY: librln LIBRLN_BUILDDIR := $(CURDIR)/vendor/zerokit LIBRLN_VERSION := v2.0.2 -MIX_LIBRLN_VERSION ?= v2.0.0 -MIX_LIBRLN_REPO ?= https://github.com/vacp2p/zerokit.git -MIX_LIBRLN_SRCDIR ?= $(CURDIR)/build/zerokit_$(MIX_LIBRLN_VERSION) -MIX_LIBRLN_FILE ?= $(CURDIR)/build/librln_mix_$(MIX_LIBRLN_VERSION).a -MIX_LIBRLN_NIM_PARAMS := --passL:$(MIX_LIBRLN_FILE) --passL:-lm ifeq ($(detected_OS),Windows) LIBRLN_FILE ?= rln.lib @@ -193,20 +188,16 @@ $(LIBRLN_FILE): echo -e $(BUILD_MSG) "$@" && \ bash scripts/build_rln.sh $(LIBRLN_BUILDDIR) $(LIBRLN_VERSION) $(LIBRLN_FILE) -$(MIX_LIBRLN_FILE): - echo -e $(BUILD_MSG) "$@" && \ - ./scripts/build_rln_mix.sh $(MIX_LIBRLN_SRCDIR) $(MIX_LIBRLN_VERSION) $(MIX_LIBRLN_FILE) $(MIX_LIBRLN_REPO) - +# Single zerokit archive (stateless features) for both relay and mix plugin. +# Plugin keeps its Merkle tree Nim-side, so it does not need the pmtree FFIs +# the default features would expose -- and including a second archive built +# with different features causes duplicate-symbol link errors. librln: | $(LIBRLN_FILE) $(eval NIM_PARAMS += --passL:$(LIBRLN_FILE) --passL:-lm) -mix-librln: | $(MIX_LIBRLN_FILE) - $(eval NIM_PARAMS += --passL:$(MIX_LIBRLN_FILE) --passL:-lm) - clean-librln: cargo clean --manifest-path vendor/zerokit/rln/Cargo.toml rm -f $(LIBRLN_FILE) - rm -f $(MIX_LIBRLN_FILE) clean: | clean-librln @@ -228,7 +219,7 @@ testwaku: | build-deps build rln-deps librln echo -e $(BUILD_MSG) "build/$@" && \ nimble test -wakunode2: | build-deps build deps librln mix-librln +wakunode2: | build-deps build deps librln echo -e $(BUILD_MSG) "build/$@" && \ nimble wakunode2 @@ -248,7 +239,7 @@ chat2: | build-deps build deps librln echo -e $(BUILD_MSG) "build/$@" && \ nimble chat2 -chat2mix: | build-deps build deps librln mix-librln +chat2mix: | build-deps build deps librln echo -e $(BUILD_MSG) "build/$@" && \ nimble chat2mix diff --git a/apps/chat2mix/chat2mix.nim b/apps/chat2mix/chat2mix.nim index ea3cbd376..6a43476bd 100644 --- a/apps/chat2mix/chat2mix.nim +++ b/apps/chat2mix/chat2mix.nim @@ -18,6 +18,7 @@ import metrics, metrics/chronos_httpserver import + libp2p/crypto/rng as libp2p_rng, libp2p/[ switch, # manage transports, a single entry point for dialing and listening crypto/crypto, # cryptographic functions @@ -29,9 +30,9 @@ import peerid, # Implement how peers interact protobuf/minprotobuf, # message serialisation/deserialisation from and to protobufs nameresolving/dnsresolver, - protocols/mix/curve25519, - protocols/mix/mix_protocol, ] # define DNS resolution +# libp2p_mix has been extracted into its own package; import from there. +import libp2p_mix/curve25519, libp2p_mix/mix_protocol import waku/[ waku_core, @@ -60,7 +61,6 @@ import ../../waku/waku_rln_relay logScope: topics = "chat2 mix" - ######################### ## Mix Spam Protection ## ######################### @@ -160,8 +160,7 @@ proc maintainSpamProtectionSubscription( noFailedSubscribes = 0 await sleepAsync(SubscriptionMaintenance) -const Help = - """ +const Help = """ Commands: /[?|help|connect|nick|exit] help: Prints this help connect: dials a remote peer @@ -501,7 +500,7 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} = if conf.nodekey.isSome(): conf.nodekey.get() else: - PrivateKey.random(Secp256k1, rng[]).tryGet() + PrivateKey.random(Secp256k1, libp2p_rng.newBearSslRng(rng)).tryGet() # set log level if conf.logLevel != LogLevel.NONE: @@ -576,12 +575,13 @@ proc processInput(rfd: AsyncFD, rng: ref HmacDrbgContext) {.async.} = if kadBootstrapPeers.len > 0: node.wakuKademlia = WakuKademlia.new( node.switch, - ExtendedKademliaDiscoveryParams( + ExtendedServiceDiscoveryParams( bootstrapNodes: kadBootstrapPeers, mixPubKey: some(mixPubKey), advertiseMix: false, ), node.peerManager, + rng = libp2p_rng.newBearSslRng(node.rng), getMixNodePoolSize = proc(): int {.gcsafe, raises: [].} = if node.wakuMix.isNil(): 0 @@ -788,7 +788,7 @@ proc main(rng: ref HmacDrbgContext) {.async.} = raise e when isMainModule: # isMainModule = true when the module is compiled as the main file - let rng = crypto.newRng() + let rng = HmacDrbgContext.new() try: waitFor(main(rng)) except CatchableError as e: diff --git a/config.nims b/config.nims index ebe501db8..5b2f2e90a 100644 --- a/config.nims +++ b/config.nims @@ -90,6 +90,14 @@ if not defined(macosx) and not defined(android): nimStackTraceOverride switch("import", "libbacktrace") +# Auto-import the Option[T] valueOr/withValue shim for every compilation +# unit (libp2p 1.15.3 dropped the Option overloads previously provided by +# libp2p/utility). Per-file imports follow cover-traffic's pattern for +# the 15 files touched there, but our branch has additional downstream +# call sites that need the shim too -- auto-import covers them without +# requiring every file to remember the explicit import. +switch("import", "waku/common/option_shims") + --define: nimOldCaseObjects # https://github.com/status-im/nim-confutils/issues/9 diff --git a/examples/lightpush_mix/lightpush_publisher_mix.nim b/examples/lightpush_mix/lightpush_publisher_mix.nim index 104de8552..893b15368 100644 --- a/examples/lightpush_mix/lightpush_publisher_mix.nim +++ b/examples/lightpush_mix/lightpush_publisher_mix.nim @@ -7,8 +7,8 @@ import confutils, libp2p/crypto/crypto, libp2p/crypto/curve25519, - libp2p/protocols/mix, - libp2p/protocols/mix/curve25519, + libp2p_mix, + libp2p_mix/curve25519, libp2p/multiaddress, eth/keys, eth/p2p/discoveryv5/enr, diff --git a/scripts/build_rln_mix.sh b/scripts/build_rln_mix.sh deleted file mode 100755 index 786ef76f5..000000000 --- a/scripts/build_rln_mix.sh +++ /dev/null @@ -1,43 +0,0 @@ -#!/usr/bin/env bash - -# Build a separate, pinned RLN library for mix spam-protection usage. -# This keeps the main nwaku RLN dependency flow unchanged. - -set -euo pipefail - -source_dir="${1:-}" -version="${2:-}" -output_file="${3:-}" -repo_url="${4:-https://github.com/vacp2p/zerokit.git}" - -if [[ -z "${source_dir}" || -z "${version}" || -z "${output_file}" ]]; then - echo "Usage: $0 [repo_url]" - exit 1 -fi - -mkdir -p "$(dirname "${source_dir}")" -mkdir -p "$(dirname "${output_file}")" - -if [[ ! -d "${source_dir}/.git" ]]; then - echo "Cloning zerokit ${version} from ${repo_url}..." - if [[ -e "${source_dir}" ]]; then - echo "Path exists but is not a git repository: ${source_dir}" - echo "Please remove it and retry." - exit 1 - fi - git clone --depth 1 --branch "${version}" "${repo_url}" "${source_dir}" -else - echo "Using existing zerokit checkout in ${source_dir}" - current_tag="$(git -C "${source_dir}" describe --tags --exact-match 2>/dev/null || true)" - if [[ "${current_tag}" != "${version}" ]]; then - echo "Updating zerokit checkout to ${version}..." - git -C "${source_dir}" fetch --tags origin "${version}" - git -C "${source_dir}" checkout --detach "${version}" - fi -fi - -echo "Building mix RLN library from source (version ${version})..." -cargo build --release -p rln --manifest-path "${source_dir}/rln/Cargo.toml" - -cp "${source_dir}/target/release/librln.a" "${output_file}" -echo "Successfully built ${output_file}" diff --git a/simulations/mixnet/build_setup.sh b/simulations/mixnet/build_setup.sh index 809f3d0de..81af9d16f 100755 --- a/simulations/mixnet/build_setup.sh +++ b/simulations/mixnet/build_setup.sh @@ -5,8 +5,8 @@ cd ../.. ROOT_DIR=$(pwd) source "$ROOT_DIR/env.sh" -# Prefer explicitly provided RLN library path, otherwise use the one built by `make mix-librln`. -LIBRLN_PATH=${LIBRLN_PATH:-"$ROOT_DIR/build/librln_mix_v2.0.0.a"} +# Prefer explicitly provided RLN library path, otherwise use the one built by `make librln`. +LIBRLN_PATH=${LIBRLN_PATH:-"$ROOT_DIR/librln_v2.0.2.a"} # Clean up old files first rm -f "$MIXNET_DIR/rln_tree.db" "$MIXNET_DIR"/rln_keystore_*.json diff --git a/waku.nimble b/waku.nimble index d02226108..d439fe2fe 100644 --- a/waku.nimble +++ b/waku.nimble @@ -27,19 +27,23 @@ requires "nim >= 2.2.4", "toml_serialization", "faststreams", # Networking & P2P - "https://github.com/vacp2p/nim-libp2p.git#ff8d51857b4b79a68468e7bcc27b2026cca02996", + # nim-libp2p: release/v2.0.0 tip (c43199378). SHA-pinned because vacp2p + # hasn't published a v2.0.0 git tag yet. + "https://github.com/vacp2p/nim-libp2p.git#c43199378f46d0aaf61be1cad1ee1d63e8f665d6", "eth", "nat_traversal", "dnsdisc", "dnsclient", "httputils >= 0.4.1", - "websock >= 0.3.0", + "https://github.com/status-im/nim-websock >= 0.4.0", # Cryptography "nimcrypto == 0.6.4", # 0.6.4 used in libp2p. Version 0.7.3 makes test to crash on Ubuntu. "secp256k1", "bearssl", # RPC & APIs - "https://github.com/status-im/nim-json-rpc.git#43bbf499143eb45046c83ac9794c9e3280a2b8e7", + # TODO: revert to status-im/nim-json-rpc once + # https://github.com/status-im/nim-json-rpc/pull/277 merges + tag cut. + "https://github.com/chaitanyaprem/nim-json-rpc.git#f05fad251a1ceb845db963902b54295e7f37fb99", "presto", "web3", # Database @@ -53,20 +57,28 @@ requires "nim >= 2.2.4", "unicodedb", "results", "minilru", - "zlib < 0.2", + "zlib", # Debug & Testing "testutils", "unittest2" # Packages not on nimble (use git URLs) requires "https://github.com/logos-messaging/nim-ffi#v0.1.3" -requires "https://github.com/logos-co/mix-rln-spam-protection-plugin.git#037f8e100bfedffdbad1c4442e760d10a2437428" +requires "https://github.com/logos-co/mix-rln-spam-protection-plugin.git#23b278b4ab21193ad4e9ce76015f008db7332a6f" + +# nim-libp2p-mix: extracted mix protocol used by the plugin and by waku's +# mix integration layer. Tip of experiment/drop-nimble-lock (PR #14, stacked +# on chore/bump-libp2p-v2.0.0). Carries the v2.0.0 bump + sink overrides + +# AddressConfidence.Infinite + deeper move-semantics propagation + the +# lockfile-as-build-artefact cleanup. Re-bump to master SHA once #14 lands. +# The plugin pins the same SHA — keeps the diamond dep collapsed. +requires "https://github.com/logos-co/nim-libp2p-mix.git#50c4ab4fa788a33eb12a0a2cecaa708873352b58" requires "https://github.com/logos-messaging/nim-sds.git#abdd40cc645f1b024c3ee99cced7e287c4e4c441" requires "https://github.com/NagyZoltanPeter/nim-brokers.git#v3.1.1" -requires "https://github.com/vacp2p/nim-lsquic" +requires "lsquic >= 0.4.1" requires "https://github.com/vacp2p/nim-jwt.git#057ec95eb5af0eea9c49bfe9025b3312c95dc5f2" proc getMyCPU(): string = diff --git a/waku/common/option_shims.nim b/waku/common/option_shims.nim new file mode 100644 index 000000000..18e433574 --- /dev/null +++ b/waku/common/option_shims.nim @@ -0,0 +1,31 @@ +# Compatibility shims for std/options. +# libp2p 1.15.2 (and earlier) exposed `valueOr` / `withValue` for std `Option[T]` +# via `libp2p/utility`. libp2p 1.15.3 dropped those overloads (only `Opt[T]` and +# `Result[T, E]` remain), which breaks existing waku code that still uses +# std `Option`. Restore the templates locally so the codebase keeps compiling +# while the upstream API gap is resolved. + +{.push raises: [].} + +import std/options + +template valueOr*[T](self: Option[T], def: untyped): T = + let tmp = self + if tmp.isSome(): + tmp.get() + else: + def + +template withValue*[T](self: Option[T], value, body: untyped): untyped = + let tmp = self + if tmp.isSome(): + let value {.inject.} = tmp.get() + body + +template withValue*[T](self: Option[T], value, body, elseBody: untyped): untyped = + let tmp = self + if tmp.isSome(): + let value {.inject.} = tmp.get() + body + else: + elseBody diff --git a/waku/common/rate_limit/request_limiter.nim b/waku/common/rate_limit/request_limiter.nim index bc318e151..8db84f833 100644 --- a/waku/common/rate_limit/request_limiter.nim +++ b/waku/common/rate_limit/request_limiter.nim @@ -24,6 +24,7 @@ import import std/times except TimeInterval, Duration, seconds, minutes +import ../option_shims import ./[single_token_limiter, service_metrics, timed_map] export token_bucket, setting, service_metrics diff --git a/waku/discovery/autonat_service.nim b/waku/discovery/autonat_service.nim index fb1f7dbc3..abe01eb6e 100644 --- a/waku/discovery/autonat_service.nim +++ b/waku/discovery/autonat_service.nim @@ -2,6 +2,7 @@ import chronos, chronicles, bearssl/rand, + libp2p/crypto/rng as libp2p_rng, libp2p/protocols/connectivity/autonat/client, libp2p/protocols/connectivity/autonat/service @@ -15,7 +16,8 @@ proc getAutonatService*(rng: ref HmacDrbgContext): AutonatService = ## in the calculation. let autonatService = AutonatService.new( autonatClient = AutonatClient.new(), - rng = rng, + # libp2p 1.15.3: AutonatService.new now takes libp2p `Rng`. + rng = libp2p_rng.newBearSslRng(rng), scheduleInterval = AutonatCheckInterval, askNewConnectedPeers = false, numPeersToAsk = 3, diff --git a/waku/discovery/waku_discv5.nim b/waku/discovery/waku_discv5.nim index c1b253c8c..d5567f44a 100644 --- a/waku/discovery/waku_discv5.nim +++ b/waku/discovery/waku_discv5.nim @@ -10,6 +10,7 @@ import eth/keys as eth_keys, eth/p2p/discoveryv5/node, eth/p2p/discoveryv5/protocol +import ../common/option_shims import waku/[net/auto_port, node/peer_manager/peer_manager, waku_core, waku_enr] export protocol, waku_enr diff --git a/waku/discovery/waku_kademlia.nim b/waku/discovery/waku_kademlia.nim index aab3a9819..2ffa4fac0 100644 --- a/waku/discovery/waku_kademlia.nim +++ b/waku/discovery/waku_kademlia.nim @@ -9,9 +9,10 @@ import libp2p/[peerid, multiaddress, switch], libp2p/extended_peer_record, libp2p/crypto/curve25519, - libp2p/protocols/[kademlia, kad_disco], - libp2p/protocols/kademlia_discovery/types as kad_types, - libp2p/protocols/mix/mix_protocol + libp2p/protocols/[kademlia, service_discovery], + libp2p/protocols/service_discovery/types as kad_types, + libp2p/crypto/rng as libp2p_rng, + libp2p_mix/mix_protocol import waku/waku_core, waku/node/peer_manager @@ -19,20 +20,20 @@ logScope: topics = "waku extended kademlia discovery" const - DefaultExtendedKademliaDiscoveryInterval* = chronos.seconds(5) - ExtendedKademliaDiscoveryStartupDelay* = chronos.seconds(5) + DefaultExtendedServiceDiscoveryInterval* = chronos.seconds(5) + ExtendedServiceDiscoveryStartupDelay* = chronos.seconds(5) type MixNodePoolSizeProvider* = proc(): int {.gcsafe, raises: [].} NodeStartedProvider* = proc(): bool {.gcsafe, raises: [].} - ExtendedKademliaDiscoveryParams* = object + ExtendedServiceDiscoveryParams* = object bootstrapNodes*: seq[(PeerId, seq[MultiAddress])] mixPubKey*: Option[Curve25519Key] advertiseMix*: bool = false WakuKademlia* = ref object - protocol*: KademliaDiscovery + protocol*: ServiceDiscovery peerManager: PeerManager discoveryLoop: Future[void] running*: bool @@ -42,21 +43,24 @@ type proc new*( T: type WakuKademlia, switch: Switch, - params: ExtendedKademliaDiscoveryParams, + params: ExtendedServiceDiscoveryParams, peerManager: PeerManager, + rng: libp2p_rng.Rng, getMixNodePoolSize: MixNodePoolSizeProvider = nil, isNodeStarted: NodeStartedProvider = nil, ): Result[T, string] = if params.bootstrapNodes.len == 0: info "creating kademlia discovery as seed node (no bootstrap nodes)" - let kademlia = KademliaDiscovery.new( + # libp2p 1.15.3: ServiceDiscovery.new requires `rng: Rng` (libp2p type). + let kademlia = ServiceDiscovery.new( switch, bootstrapNodes = params.bootstrapNodes, config = KadDHTConfig.new( validator = kad_types.ExtEntryValidator(), selector = kad_types.ExtEntrySelector() ), - codec = ExtendedKademliaDiscoveryCodec, + rng = rng, + codec = ExtendedServiceDiscoveryCodec, ) try: @@ -68,11 +72,9 @@ proc new*( # initial self-signed peer record published to the DHT if params.advertiseMix: if params.mixPubKey.isSome(): - let alreadyAdvertising = kademlia.startAdvertising( + kademlia.startAdvertising( ServiceInfo(id: MixProtocolID, data: @(params.mixPubKey.get())) ) - if alreadyAdvertising: - warn "mix service was already being advertised" debug "extended kademlia advertising mix service", keyHex = byteutils.toHex(params.mixPubKey.get()), bootstrapNodes = params.bootstrapNodes.len @@ -162,17 +164,18 @@ proc lookupMixPeers*( return err("cannot lookup mix peers: kademlia not mounted") let mixService = ServiceInfo(id: MixProtocolID, data: @[]) - var records: seq[ExtendedPeerRecord] - try: - records = await wk.protocol.lookup(mixService) - except CatchableError: - return err("mix peer lookup failed: " & getCurrentExceptionMsg()) + let advertisements = + try: + (await wk.protocol.lookup(mixService)).valueOr: + return err("mix peer lookup failed: " & error) + except CatchableError: + return err("mix peer lookup failed: " & getCurrentExceptionMsg()) - debug "mix peer lookup returned records", numRecords = records.len + debug "mix peer lookup returned records", numRecords = advertisements.len var added = 0 - for record in records: - let peerOpt = remotePeerInfoFrom(record) + for ad in advertisements: + let peerOpt = remotePeerInfoFrom(ad.data) if peerOpt.isNone(): continue @@ -197,12 +200,12 @@ proc runDiscoveryLoop( while wk.running: # Wait for node to be started if not wk.isNodeStarted.isNil() and not wk.isNodeStarted(): - await sleepAsync(ExtendedKademliaDiscoveryStartupDelay) + await sleepAsync(ExtendedServiceDiscoveryStartupDelay) continue var records: seq[ExtendedPeerRecord] try: - records = await wk.protocol.randomRecords() + records = await wk.protocol.lookupRandom() except CatchableError as e: warn "extended kademlia discovery failed", error = e.msg await sleepAsync(interval) @@ -247,7 +250,7 @@ proc runDiscoveryLoop( proc start*( wk: WakuKademlia, - interval: Duration = DefaultExtendedKademliaDiscoveryInterval, + interval: Duration = DefaultExtendedServiceDiscoveryInterval, minMixPeers: int = 0, ): Future[Result[void, string]] {.async: (raises: []).} = if wk.running: diff --git a/waku/factory/builder.nim b/waku/factory/builder.nim index 4212cb92d..cc190b193 100644 --- a/waku/factory/builder.nim +++ b/waku/factory/builder.nim @@ -5,6 +5,8 @@ import results, chronicles, libp2p/crypto/crypto, + libp2p/crypto/rng as libp2p_rng, + bearssl/rand, libp2p/builders, libp2p/nameresolving/nameresolver, libp2p/transports/wstransport, @@ -15,13 +17,14 @@ import ../waku_enr, ../discovery/waku_discv5, ../waku_node, + ../node/waku_switch, ../node/peer_manager, ../common/rate_limit/setting, ../common/utils/parse_size_units type WakuNodeBuilder* = object # General - nodeRng: Option[ref crypto.HmacDrbgContext] + nodeRng: Option[ref HmacDrbgContext] nodeKey: Option[crypto.PrivateKey] netConfig: Option[NetConfig] record: Option[enr.Record] @@ -57,7 +60,7 @@ proc init*(T: type WakuNodeBuilder): WakuNodeBuilder = ## General -proc withRng*(builder: var WakuNodeBuilder, rng: ref crypto.HmacDrbgContext) = +proc withRng*(builder: var WakuNodeBuilder, rng: ref HmacDrbgContext) = builder.nodeRng = some(rng) proc withNodeKey*(builder: var WakuNodeBuilder, nodeKey: crypto.PrivateKey) = @@ -157,9 +160,9 @@ proc withSwitchConfiguration*( ## Build proc build*(builder: WakuNodeBuilder): Result[WakuNode, string] = - var rng: ref crypto.HmacDrbgContext + var rng: ref HmacDrbgContext if builder.nodeRng.isNone(): - rng = crypto.newRng() + rng = HmacDrbgContext.new() else: rng = builder.nodeRng.get() @@ -189,8 +192,9 @@ proc build*(builder: WakuNodeBuilder): Result[WakuNode, string] = address = builder.netConfig.get().hostAddress, wsAddress = builder.netConfig.get().wsHostAddress, transportFlags = {ServerFlags.ReuseAddr, ServerFlags.TcpNoDelay}, - rng = rng, - maxConnections = builder.switchMaxConnections.get(builders.MaxConnections), + # newWakuSwitch now expects libp2p `Rng`; wrap our BearSSL rng. + rng = libp2p_rng.newBearSslRng(rng), + maxConnections = builder.switchMaxConnections.get(waku_switch.MaxConnections), wssEnabled = builder.netConfig.get().wssEnabled, secureKeyPath = builder.switchSslSecureKey.get(""), secureCertPath = builder.switchSslSecureCert.get(""), @@ -210,7 +214,7 @@ proc build*(builder: WakuNodeBuilder): Result[WakuNode, string] = maxServicePeers = some(builder.maxServicePeers), colocationLimit = builder.colocationLimit, shardedPeerManagement = builder.shardAware, - maxConnections = builder.switchMaxConnections.get(builders.MaxConnections), + maxConnections = builder.switchMaxConnections.get(waku_switch.MaxConnections), ) var node: WakuNode diff --git a/waku/factory/conf_builder/mix_conf_builder.nim b/waku/factory/conf_builder/mix_conf_builder.nim index 145ccb76e..c04378884 100644 --- a/waku/factory/conf_builder/mix_conf_builder.nim +++ b/waku/factory/conf_builder/mix_conf_builder.nim @@ -1,5 +1,5 @@ import chronicles, std/options, results -import libp2p/crypto/crypto, libp2p/crypto/curve25519, libp2p/protocols/mix/curve25519 +import libp2p/crypto/crypto, libp2p/crypto/curve25519, libp2p_mix/curve25519 import ../waku_conf, waku/waku_mix logScope: diff --git a/waku/factory/conf_builder/waku_conf_builder.nim b/waku/factory/conf_builder/waku_conf_builder.nim index 96e34eeed..e610df830 100644 --- a/waku/factory/conf_builder/waku_conf_builder.nim +++ b/waku/factory/conf_builder/waku_conf_builder.nim @@ -1,6 +1,8 @@ import libp2p/crypto/crypto, + libp2p/crypto/rng as libp2p_rng, libp2p/multiaddress, + bearssl/rand, std/[net, options, sequtils], stint, chronicles, @@ -299,7 +301,9 @@ proc nodeKey( return ok(builder.nodeKey.get()) else: warn "missing node key, generating new set" - let nodeKey = crypto.PrivateKey.random(Secp256k1, rng[]).valueOr: + # libp2p 1.15.3: PrivateKey.random now expects the libp2p `Rng` (ref + # object wrapping a ref HmacDrbgContext). Wrap the BearSSL rng. + let nodeKey = crypto.PrivateKey.random(Secp256k1, libp2p_rng.newBearSslRng(rng)).valueOr: error "Failed to generate key", error = error return err("Failed to generate key: " & $error) return ok(nodeKey) @@ -443,7 +447,7 @@ proc applyNetworkConf(builder: var WakuConfBuilder) = warn "Failed to process entry nodes from network conf", error = processed.error() proc build*( - builder: var WakuConfBuilder, rng: ref HmacDrbgContext = crypto.newRng() + builder: var WakuConfBuilder, rng: ref HmacDrbgContext = HmacDrbgContext.new() ): Result[WakuConf, string] = ## Return a WakuConf that contains all mandatory parameters ## Applies some sane defaults that are applicable across any usage diff --git a/waku/factory/node_factory.nim b/waku/factory/node_factory.nim index 52b719b8f..5f99f7e17 100644 --- a/waku/factory/node_factory.nim +++ b/waku/factory/node_factory.nim @@ -7,7 +7,9 @@ import libp2p/protocols/connectivity/relay/relay, libp2p/nameresolving/dnsresolver, libp2p/crypto/crypto, - libp2p/crypto/curve25519 + libp2p/crypto/curve25519, + libp2p/crypto/rng as libp2p_rng, + bearssl/rand import ./internal_config, @@ -175,12 +177,13 @@ proc setupProtocols( node.wakuKademlia = WakuKademlia.new( node.switch, - ExtendedKademliaDiscoveryParams( + ExtendedServiceDiscoveryParams( bootstrapNodes: conf.kademliaDiscoveryConf.get().bootstrapNodes, mixPubKey: mixPubKey, advertiseMix: conf.mixConf.isSome(), ), node.peerManager, + rng = libp2p_rng.newBearSslRng(node.rng), getMixNodePoolSize = proc(): int {.gcsafe, raises: [].} = if node.wakuMix.isNil(): 0 @@ -458,7 +461,7 @@ proc startNode*( return ok() proc setupNode*( - wakuConf: WakuConf, rng: ref HmacDrbgContext = crypto.newRng(), relay: Relay + wakuConf: WakuConf, rng: ref HmacDrbgContext = HmacDrbgContext.new(), relay: Relay ): Future[Result[WakuNode, string]] {.async.} = let netConfig = ( await networkConfiguration( diff --git a/waku/factory/waku.nim b/waku/factory/waku.nim index 6a5567f8c..bff24a611 100644 --- a/waku/factory/waku.nim +++ b/waku/factory/waku.nim @@ -9,6 +9,8 @@ import libp2p/protocols/connectivity/relay/client, libp2p/wire, libp2p/crypto/crypto, + libp2p/crypto/rng as libp2p_rng, + bearssl/rand, libp2p/protocols/pubsub/gossipsub, libp2p/services/autorelayservice, libp2p/services/hpservice, @@ -102,12 +104,29 @@ proc setupSwitchServices( ## 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 + # libp2p 1.15.3: AutoRelayService.new now expects libp2p `Rng`. let autoRelayService = AutoRelayService.new( - MaxNumRelayServers, RelayClient(circuitRelay), onReservation, rng + MaxNumRelayServers, + RelayClient(circuitRelay), + onReservation, + libp2p_rng.newBearSslRng(rng), ) let holePunchService = HPService.new(autonatService, autoRelayService) + # libp2p v2.0.0: switch.start() no longer auto-calls service.setup() (part + # of the Service lifecycle refactor in libp2p#2462). Without setup, + # HPService's wrapped Autonat/AutoRelay leave their addressMapper field + # nil, which makes peerInfo.expandAddrs SIGSEGV during start(). + try: + holePunchService.setup(waku.node.switch) + except ServiceSetupError as e: + error "HPService setup failed", description = e.msg waku.node.switch.services = @[Service(holePunchService)] else: + # Same reason as above: AutonatService.setup() initializes addressMapper. + try: + autonatService.setup(waku.node.switch) + except ServiceSetupError as e: + error "AutonatService setup failed", description = e.msg waku.node.switch.services = @[Service(autonatService)] ## Initialisation @@ -175,7 +194,7 @@ proc setupAppCallbacks( proc new*( T: type Waku, wakuConf: WakuConf, appCallbacks: AppCallbacks = nil ): Future[Result[Waku, string]] {.async.} = - let rng = crypto.newRng() + let rng = HmacDrbgContext.new() let brokerCtx = globalBrokerContext() logging.setupLog(wakuConf.logLevel, wakuConf.logFormat) diff --git a/waku/node/delivery_service/send_service/lightpush_processor.nim b/waku/node/delivery_service/send_service/lightpush_processor.nim index 7a9f65c71..c47487c2d 100644 --- a/waku/node/delivery_service/send_service/lightpush_processor.nim +++ b/waku/node/delivery_service/send_service/lightpush_processor.nim @@ -1,7 +1,11 @@ import chronicles, chronos, results import std/options import brokers/broker_context -import waku/node/peer_manager, waku/waku_core, waku/waku_lightpush/[common, client, rpc] +import + waku/common/option_shims, + waku/node/peer_manager, + waku/waku_core, + waku/waku_lightpush/[common, client, rpc] import ./[delivery_task, send_processor] diff --git a/waku/node/kernel_api/lightpush.nim b/waku/node/kernel_api/lightpush.nim index ffe2afdac..658de7696 100644 --- a/waku/node/kernel_api/lightpush.nim +++ b/waku/node/kernel_api/lightpush.nim @@ -17,7 +17,7 @@ import libp2p/transports/tcptransport, libp2p/transports/wstransport, libp2p/utility, - libp2p/protocols/mix + libp2p_mix import ../waku_node, @@ -28,6 +28,7 @@ import ../../waku_lightpush/client as lightpush_client, ../../waku_lightpush as lightpush_protocol, ../peer_manager, + ../../common/option_shims, ../../common/rate_limit/setting, ../../waku_rln_relay diff --git a/waku/node/kernel_api/ping.nim b/waku/node/kernel_api/ping.nim index 9dc649fd8..f9da3980e 100644 --- a/waku/node/kernel_api/ping.nim +++ b/waku/node/kernel_api/ping.nim @@ -12,6 +12,7 @@ import libp2p/utility import ../waku_node, ../peer_manager +import libp2p/crypto/rng as libp2p_rng logScope: topics = "waku node ping api" @@ -20,7 +21,9 @@ proc mountLibp2pPing*(node: WakuNode) {.async: (raises: []).} = info "mounting libp2p ping protocol" try: - node.libp2pPing = Ping.new(rng = node.rng) + # libp2p 1.15.3: Ping.new now expects libp2p's `Rng` (ref object + # wrapping a ref HmacDrbgContext). Wrap the node's BearSSL rng. + node.libp2pPing = Ping.new(rng = libp2p_rng.newBearSslRng(node.rng)) except Exception as e: error "failed to create ping", error = getCurrentExceptionMsg() diff --git a/waku/node/kernel_api/relay.nim b/waku/node/kernel_api/relay.nim index 16aa8f3ff..124a70903 100644 --- a/waku/node/kernel_api/relay.nim +++ b/waku/node/kernel_api/relay.nim @@ -31,6 +31,7 @@ import waku_mix, node/waku_node, node/peer_manager, + common/option_shims, events/message_events, ] diff --git a/waku/node/peer_manager/peer_manager.nim b/waku/node/peer_manager/peer_manager.nim index 6602c049b..16de8fd61 100644 --- a/waku/node/peer_manager/peer_manager.nim +++ b/waku/node/peer_manager/peer_manager.nim @@ -20,12 +20,14 @@ import waku_enr/sharding, waku_enr/capabilities, events/peer_events, + common/option_shims, common/nimchronos, common/enr, common/callbacks, common/utils/parse_size_units, node/health_monitor/online_monitor, ], + ../waku_switch, ./peer_store/peer_storage, ./waku_peer_store diff --git a/waku/node/peer_manager/waku_peer_store.nim b/waku/node/peer_manager/waku_peer_store.nim index 93ac9ad2e..9c4201190 100644 --- a/waku/node/peer_manager/waku_peer_store.nim +++ b/waku/node/peer_manager/waku_peer_store.nim @@ -7,9 +7,11 @@ import eth/p2p/discoveryv5/enr, libp2p/builders, libp2p/peerstore, - libp2p/crypto/curve25519 + libp2p/crypto/curve25519, + libp2p_mix/pool import + ../../common/option_shims, ../../waku_core, ../../waku_enr/sharding, ../../waku_enr/capabilities, diff --git a/waku/node/waku_node.nim b/waku/node/waku_node.nim index 6dd24fb47..70581e3d9 100644 --- a/waku/node/waku_node.nim +++ b/waku/node/waku_node.nim @@ -23,8 +23,8 @@ import libp2p/transports/wstransport, libp2p/utility, libp2p/utils/offsettedseq, - libp2p/protocols/mix, - libp2p/protocols/mix/mix_protocol, + libp2p_mix, + libp2p_mix/mix_protocol, brokers/broker_context, brokers/request_broker @@ -52,6 +52,7 @@ import waku_enr, waku_peer_exchange, waku_rln_relay, + common/option_shims, common/rate_limit/setting, common/callbacks, common/nimchronos, @@ -219,7 +220,7 @@ proc new*( peerManager: PeerManager, rateLimitSettings: ProtocolRateLimitSettings = DefaultProtocolRateLimit, # TODO: make this argument required after tests are updated - rng: ref HmacDrbgContext = crypto.newRng(), + rng: ref HmacDrbgContext = HmacDrbgContext.new(), ): T {.raises: [Defect, LPError, IOError, TLSStreamProtocolError].} = ## Creates a Waku Node instance. diff --git a/waku/node/waku_switch.nim b/waku/node/waku_switch.nim index d1af77662..60ba3eb44 100644 --- a/waku/node/waku_switch.nim +++ b/waku/node/waku_switch.nim @@ -7,6 +7,7 @@ import chronicles, eth/keys, libp2p/crypto/crypto, + libp2p/crypto/rng as libp2p_rng, libp2p/protocols/pubsub/gossipsub, libp2p/protocols/rendezvous, libp2p/protocols/connectivity/relay/relay, @@ -18,11 +19,15 @@ import # override nim-libp2p default value (which is also 1) const MaxConnectionsPerPeer* = 1 -proc withWsTransport*(b: SwitchBuilder): SwitchBuilder = - b.withTransport( - proc(upgr: Upgrade, privateKey: crypto.PrivateKey): Transport = - WsTransport.new(upgr) - ) +# libp2p 1.15.3 ships a built-in `withWsTransport` matching this name, so +# the plain-WS wrapper that used to live here is now redundant. Callers +# that did `b.withWsTransport()` resolve to libp2p's overload (zero args = +# no TLS, no flags). Callers passing `tlsPrivateKey=`/`tlsCertificate=` +# also use libp2p's built-in. + +# nim-libp2p#2329 made libp2p's MaxConnections const private (renamed to +# DefaultMaxConnections); redeclare here to keep waku's cap explicit. +const MaxConnections* = 50 proc getSecureKey(path: string): TLSPrivateKey {.raises: [Defect, IOError].} = trace "Key path is.", path = path @@ -59,7 +64,7 @@ proc newWakuSwitch*( wsAddress = none(MultiAddress), secureManagers: openarray[SecureProtocol] = [SecureProtocol.Noise], transportFlags: set[ServerFlags] = {}, - rng: ref HmacDrbgContext, + rng: libp2p_rng.Rng, inTimeout: Duration = 5.minutes, outTimeout: Duration = 5.minutes, maxConnections = MaxConnections, @@ -73,15 +78,16 @@ proc newWakuSwitch*( secureCertPath: string = "", agentString = none(string), # defaults to nim-libp2p version peerStoreCapacity = none(int), # defaults to 1.25 maxConnections - rendezvous: RendezVous = nil, + rendezvous: Opt[RendezVousConfig] = Opt.none(RendezVousConfig), circuitRelay: Relay, ): Switch {.raises: [Defect, IOError, LPError].} = - var b = SwitchBuilder - .new() - .withRng(rng) - .withMaxConnections(maxConnections) - .withMaxIn(maxIn) - .withMaxOut(maxOut) + var b = SwitchBuilder.new().withRng(rng).withMaxConnections(maxConnections) + # libp2p 1.15.3 asserts both maxIn and maxOut > 0; only opt into independent + # in/out caps when the caller actually supplied them. Otherwise the single + # `withMaxConnections` cap from above remains in effect. + if maxIn > 0 and maxOut > 0: + b = b.withMaxInOut(maxIn, maxOut) + b = b .withMaxConnsPerPeer(maxConnsPerPeer) .withYamux() .withMplex(inTimeout, outTimeout) @@ -111,7 +117,7 @@ proc newWakuSwitch*( else: b = b.withAddress(address) - if not rendezvous.isNil(): - b = b.withRendezVous(rendezvous) + if rendezvous.isSome(): + b = b.withRendezVous(rendezvous.get()) b.build() diff --git a/waku/rest_api/endpoint/filter/handlers.nim b/waku/rest_api/endpoint/filter/handlers.nim index 61d7eb96f..363b9bd1f 100644 --- a/waku/rest_api/endpoint/filter/handlers.nim +++ b/waku/rest_api/endpoint/filter/handlers.nim @@ -10,6 +10,7 @@ import presto/route, presto/common import + ../../../common/option_shims, ../../../waku_core, ../../../waku_node, ../../../node/peer_manager, diff --git a/waku/rest_api/endpoint/legacy_lightpush/handlers.nim b/waku/rest_api/endpoint/legacy_lightpush/handlers.nim index 7a3c5b1ed..a2ca0f79b 100644 --- a/waku/rest_api/endpoint/legacy_lightpush/handlers.nim +++ b/waku/rest_api/endpoint/legacy_lightpush/handlers.nim @@ -10,6 +10,7 @@ import presto/common import + waku/common/option_shims, waku/node/peer_manager, waku/waku_lightpush_legacy/common, ../../../waku_node, diff --git a/waku/rest_api/endpoint/lightpush/handlers.nim b/waku/rest_api/endpoint/lightpush/handlers.nim index 342053e72..e334b3420 100644 --- a/waku/rest_api/endpoint/lightpush/handlers.nim +++ b/waku/rest_api/endpoint/lightpush/handlers.nim @@ -10,6 +10,7 @@ import presto/common import + waku/common/option_shims, waku/node/peer_manager, waku/waku_lightpush/common, ../../../waku_node, diff --git a/waku/rest_api/endpoint/store/handlers.nim b/waku/rest_api/endpoint/store/handlers.nim index 7d37191fb..fc07c8fc8 100644 --- a/waku/rest_api/endpoint/store/handlers.nim +++ b/waku/rest_api/endpoint/store/handlers.nim @@ -3,6 +3,7 @@ import std/[strformat, sugar], results, chronicles, uri, json_serialization, presto/route import + ../../../common/option_shims, ../../../waku_core, ../../../waku_store/common, ../../../waku_store/self_req_handler, diff --git a/waku/waku_enr/capabilities.nim b/waku/waku_enr/capabilities.nim index 26899fbb4..6a5b5338f 100644 --- a/waku/waku_enr/capabilities.nim +++ b/waku/waku_enr/capabilities.nim @@ -3,7 +3,7 @@ import std/[options, bitops, sequtils, net, tables], results, eth/keys, libp2p/crypto/crypto import ../common/enr, ../waku_core/codecs -import libp2p/protocols/mix +import libp2p_mix const CapabilitiesEnrField* = "waku2" diff --git a/waku/waku_enr/sharding.nim b/waku/waku_enr/sharding.nim index 2aeb96a9d..f35bca275 100644 --- a/waku/waku_enr/sharding.nim +++ b/waku/waku_enr/sharding.nim @@ -8,7 +8,7 @@ import eth/keys, libp2p/[multiaddress, multicodec], libp2p/crypto/crypto -import ../common/enr, ../waku_core/topics/pubsub_topic +import ../common/enr, ../common/option_shims, ../waku_core/topics/pubsub_topic logScope: topics = "waku enr sharding" diff --git a/waku/waku_lightpush/client.nim b/waku/waku_lightpush/client.nim index fd12c49d2..c76aaa680 100644 --- a/waku/waku_lightpush/client.nim +++ b/waku/waku_lightpush/client.nim @@ -3,6 +3,7 @@ import std/options, results, chronicles, chronos, metrics, bearssl/rand, stew/byteutils import libp2p/peerid, libp2p/stream/connection import + ../common/option_shims, ../waku_core/peers, ../node/peer_manager, ../utils/requests, diff --git a/waku/waku_mix/protocol.nim b/waku/waku_mix/protocol.nim index 8a12250a3..a504f94f4 100644 --- a/waku/waku_mix/protocol.nim +++ b/waku/waku_mix/protocol.nim @@ -5,12 +5,12 @@ import chronicles, std/[options, sequtils], chronos, results, metrics import libp2p/crypto/curve25519, libp2p/crypto/crypto, - libp2p/protocols/mix, - libp2p/protocols/mix/mix_node, - libp2p/protocols/mix/mix_protocol, - libp2p/protocols/mix/mix_metrics, - libp2p/protocols/mix/delay_strategy, - libp2p/protocols/mix/spam_protection, + libp2p_mix, + libp2p_mix/mix_node, + libp2p_mix/mix_protocol, + libp2p_mix/mix_metrics, + libp2p_mix/delay_strategy, + libp2p_mix/spam_protection, libp2p/[multiaddress, multicodec, peerid, peerinfo], eth/common/keys @@ -126,8 +126,11 @@ proc new*( localMixNodeInfo, peermgr.switch, spamProtection = Opt.some(SpamProtection(spamProtection)), - delayStrategy = - ExponentialDelayStrategy.new(meanDelayMs = 100, rng = crypto.newRng()), + delayStrategy = Opt.some( + DelayStrategy( + ExponentialDelayStrategy.new(meanDelay = 100, rng = crypto.newRng()) + ) + ), ) processBootNodes(bootnodes, peermgr, m) @@ -300,8 +303,7 @@ proc dosRegistrationRetryLoop(mix: WakuMix) {.async.} = try: let registerRes = await mix.mixRlnSpamProtection.registerSelf() if registerRes.isOk(): - debug "DoS-protection self-registration succeeded", - index = registerRes.get() + debug "DoS-protection self-registration succeeded", index = registerRes.get() # Persist tree only after a successful register — for fresh nodes this # captures the new index; for keystore nodes it's a harmless no-op. let saveRes = mix.mixRlnSpamProtection.saveTree() diff --git a/waku/waku_relay/protocol.nim b/waku/waku_relay/protocol.nim index d0b1ddb48..82298875d 100644 --- a/waku/waku_relay/protocol.nim +++ b/waku/waku_relay/protocol.nim @@ -13,6 +13,7 @@ import chronicles, metrics, libp2p/multihash, + libp2p/crypto/rng, libp2p/protocols/pubsub/gossipsub, libp2p/protocols/pubsub/rpc/messages, libp2p/stream/connection, @@ -366,6 +367,8 @@ proc new*( triggerSelf = true, msgIdProvider = defaultMessageIdProvider, maxMessageSize = maxMessageSize, + # libp2p 1.15.3 made `rng` a required parameter of PubSub.init. + rng = newRng(), parameters = GossipsubParameters, ) w.brokerCtx = globalBrokerContext() diff --git a/waku/waku_rendezvous/client.nim b/waku/waku_rendezvous/client.nim index 09e789774..0b42f61d3 100644 --- a/waku/waku_rendezvous/client.nim +++ b/waku/waku_rendezvous/client.nim @@ -7,8 +7,7 @@ import chronicles, libp2p/protocols/rendezvous, libp2p/crypto/curve25519, - libp2p/switch, - libp2p/utils/semaphore + libp2p/switch import metrics except collect @@ -107,10 +106,14 @@ proc new*( switch: switch, rng: rng, sema: newAsyncSemaphore(MaxSimultanesousAdvertisements), - minDuration: rendezvous.MinimumAcceptedDuration, - maxDuration: rendezvous.MaximumDuration, - minTTL: rendezvous.MinimumAcceptedDuration.seconds.uint64, - maxTTL: rendezvous.MaximumDuration.seconds.uint64, + # libp2p 1.15.3 moved minDuration/maxDuration/minTTL/maxTTL onto + # GenericRendezVous.config (RendezVousConfig). + config: RendezVousConfig( + minDuration: rendezvous.MinimumAcceptedDuration, + maxDuration: rendezvous.MaximumDuration, + minTTL: rendezvous.MinimumAcceptedDuration.seconds.uint64, + maxTTL: rendezvous.MaximumDuration.seconds.uint64, + ), peers: @[], # Will be populated from selectPeer calls cookiesSaved: initTable[PeerId, Table[string, seq[byte]]](), peerRecordValidator: checkWakuPeerRecord, diff --git a/waku/waku_rendezvous/protocol.nim b/waku/waku_rendezvous/protocol.nim index 89433f533..01f0778cd 100644 --- a/waku/waku_rendezvous/protocol.nim +++ b/waku/waku_rendezvous/protocol.nim @@ -8,7 +8,7 @@ import stew/byteutils, libp2p/protocols/rendezvous, libp2p/protocols/rendezvous/protobuf, - libp2p/utils/semaphore, + libp2p/crypto/rng, libp2p/utils/offsettedseq, libp2p/crypto/curve25519, libp2p/switch, @@ -51,7 +51,7 @@ proc advertise*( self: WakuRendezVous, namespace: string, peers: seq[PeerId], - ttl: timer.Duration = self.minDuration, + ttl: timer.Duration = self.config.minDuration, ): Future[Result[void, string]] {.async: (raises: []).} = trace "advertising via waku rendezvous", namespace = namespace, ttl = ttl, peers = $peers, peerRecord = $self.getPeerRecord() @@ -154,14 +154,20 @@ proc new*( let rng = newRng() let wrv = T( rng: rng, - salt: string.fromBytes(generateBytes(rng[], 8)), + # libp2p 1.15.3: generateBytes now takes the libp2p Rng directly + # (used to take the underlying ref HmacDrbgContext via `rng[]`). + salt: string.fromBytes(generateBytes(rng, 8)), registered: initOffsettedSeq[RegisteredData](), expiredDT: Moment.now() - 1.days, sema: newAsyncSemaphore(SemaphoreDefaultSize), - minDuration: rendezvous.MinimumAcceptedDuration, - maxDuration: rendezvous.MaximumDuration, - minTTL: rendezvous.MinimumAcceptedDuration.seconds.uint64, - maxTTL: rendezvous.MaximumDuration.seconds.uint64, + # libp2p 1.15.3 moved minDuration/maxDuration/minTTL/maxTTL onto + # GenericRendezVous.config (RendezVousConfig). + config: RendezVousConfig( + minDuration: rendezvous.MinimumAcceptedDuration, + maxDuration: rendezvous.MaximumDuration, + minTTL: rendezvous.MinimumAcceptedDuration.seconds.uint64, + maxTTL: rendezvous.MaximumDuration.seconds.uint64, + ), peerRecordValidator: checkWakuPeerRecord, ) diff --git a/waku/waku_store/client.nim b/waku/waku_store/client.nim index b49662811..fab1e4abc 100644 --- a/waku/waku_store/client.nim +++ b/waku/waku_store/client.nim @@ -8,7 +8,12 @@ import metrics, bearssl/rand import - ../node/peer_manager, ../utils/requests, ./protocol_metrics, ./common, ./rpc_codec + ../common/option_shims, + ../node/peer_manager, + ../utils/requests, + ./protocol_metrics, + ./common, + ./rpc_codec logScope: topics = "waku store client"