libp2p v2.0.0's `random(T, scheme, rng)` overload takes `Rng` (the new
wrapper type). Pre-existing call sites in tests/wakunode_rest and
tests/waku_discv5 still passed `rng[]` (dereferenced HmacDrbgContext).
- tests/wakunode_rest/test_rest_{health,cors,debug}.nim: wrap
`common.rng()` (ref HmacDrbgContext) via newBearSslRng to get an Rng.
- tests/waku_discv5/test_waku_discv5.nim: `myRng` is already an Rng
(from `libp2p_keys.newRng()`), so drop the `[]` deref and pass it
directly to `random(Secp256k1, myRng)`.
The nix flake's `liblogosdelivery` derivation was pinning libp2p to the
old master SHA ff8d51857, which still exports `valueOr` for `Option[T]`
in `libp2p/utility`. Combined with this PR's `waku/common/option_shims.nim`
(which also defines `valueOr` for `Option[T]` to cover libp2p 1.15.3+
where it was removed), the nix x86_64-linux build fails with:
identify.nim(180, 25) Error: ambiguous call; both option_shims.valueOr
and utility.valueOr match for: (Option[crypto.PublicKey], )
Regenerate `nix/deps.nix` via `tools/gen-nix-deps.sh nimble.lock nix/deps.nix`
so the nix build picks up the same libp2p v2.0.0 (c43199378) + transitive
deps that the nimble.lock-driven build uses. With libp2p v2.0.0, only
option_shims defines `valueOr` for `Option[T]` -- no ambiguity.
libp2p v2.0.0's 3-arg `random(T, scheme, rng)` overload now takes the
`Rng` wrapper type instead of `var HmacDrbgContext`. My prior
`common.rng()[]` (deref) attempt resolves to `HmacDrbgContext` which
no longer matches.
Wrap our existing `ref HmacDrbgContext` (from `common.rng`) via
`newBearSslRng` to get an `Rng` value, satisfying the new signature
without re-seeding a fresh PRNG on every key generation.
nimble.lock:
Stale lockfile (inherited from master at rebase time) pinned libp2p
to ff8d51857, jwt to 18f8378de, json_rpc to status-im 43bbf499, etc.
— all incompatible with this PR's waku.nimble pin set, and nimble's
vnext SAT solver was falling back to the global packages.json
registry (which still maps `jwt` → yglukhov/nim-jwt) when the
lockfile/active-pin conflict couldn't be reconciled. That registry
lookup tried to clone yglukhov/nim-jwt at SHA 057ec95… which only
exists on the vacp2p fork, so the build aborted.
Regenerated via `nimble lock`. Resulting pins now reflect what
waku.nimble + libp2p v2.0.0 actually require: libp2p c43199378,
jwt 057ec95, websock 387a8eb7, json_rpc f05fad25 (chaitanyaprem
fork), lsquic 3813b849, libp2p_mix 50c4ab4f, mix_rln_spam_protection
23b278b4.
Hand-fixed one nimble vnext bug: mix_rln_spam_protection's
`vcsRevision` was generated as the local logos-delivery HEAD SHA
instead of the plugin's HEAD; replaced with 23b278b4… (matches
`version` field's URL+SHA spec and the cached package).
tests/testlib/wakucore.nim:
libp2p v2.0.0 also exports a `rng` symbol (the new `Rng` wrapper
type), making the unqualified `rng[]` calls here ambiguous against
the local `common.rng` template (returns `ref HmacDrbgContext`).
Qualify the three call sites as `common.rng()[]` so we keep the
`ref HmacDrbgContext` value that `libp2p_keys.PrivateKey.random` /
`KeyPair.random` expect.
libp2p v2.0.0's `crypto.newRng()` returns the new `Rng` wrapper type,
which can't be assigned to a `ref HmacDrbgContext` field. The two test
helper modules (tests/testlib/common.nim and tests/test_helpers.nim)
both fall in this pattern; rest of the codebase migrated in the prior
sweep but these two test-only files were missed because they don't
compile during the wakunode2 / chat2mix builds — only when the test
target is built (which CI does, locally we didn't until this PR).
Same fix pattern as the other newRng → HmacDrbgContext.new() migrations.
Combines five dep-and-build changes that all flow from the libp2p v2.0.0
upgrade and the move to the extracted libp2p_mix / mix-rln plugin stack:
waku.nimble:
* libp2p: ff8d51857 -> c43199378 (release/v2.0.0 tip; sha-pinned until
vacp2p cuts a v2.0.0 tag).
* Drop the bare `zlib < 0.2` cap — no longer needed by the upgraded
libp2p.
* websock: bare ">= 0.4.0" — replaces the d4cd68b URL+SHA workaround
that pinned through a libp2p commit-specific websock SHA.
* nim-json-rpc: switch to chaitanyaprem/nim-json-rpc#f05fad25 — relaxes
websock cap to allow >=0.4.0. TODO: revert to status-im/nim-json-rpc
once status-im/nim-json-rpc#277 merges and a tag is cut.
* lsquic: bare ">= 0.4.1" (drops URL form).
* Add mix-rln-spam-protection-plugin pin (23b278b4) and nim-libp2p-mix
pin (50c4ab4f — PR #14 HEAD); the plugin pins the same libp2p_mix
SHA so the diamond dep collapses to a single source.
waku/factory/waku.nim:
* Explicit HPService.setup(switch) / AutonatService.setup(switch)
calls. libp2p v2.0.0's Service lifecycle refactor (libp2p#2462)
removed switch.start's auto-setup loop, so any caller that assigns
directly to switch.services (we do) is responsible for calling
setup() themselves. Without it, AutonatService.addressMapper stays
nil and peerInfo.expandAddrs SIGSEGVs during start(). Wrapped in
try/except for ServiceSetupError so a setup failure surfaces as a
logged error rather than a crash.
Build / scripts:
* scripts/build_rln_mix.sh removed and Makefile simplified — librln
is now a single shared archive built from zerokit's `stateless`
features (no separate librln_mix archive).
* simulations/mixnet/build_setup.sh + setup_credentials.nim updated
to use librln_v2.0.2.a directly and run RLN keystore setup before
nodes start.
Validated:
* Cold local-cache nimble setup --localdeps -y.
* wakunode2 and chat2mix link cleanly.
* Mixnet roundtrip sim: [PASS] bob received message from alice.
* RLN proof generation + verification on every in-path mix node:
5 gen_called == 5 verified, 0 SPAM_PROOF_* errors.
WakuMix.start() previously ran a single sequential pipeline that ended
with mixRlnSpamProtection.registerSelf() — which publishes the new
member's idCommitment to other mix nodes via relay. With master's flow
(switch.start() then reconnectRelayPeers() then ...), running registerSelf
inline would either:
- block startup for ~62s when reconnectRelayPeers backs off, or
- run before relay peers exist and silently no-op.
Split the start() proc into:
- method start*(WakuMix): local-only init (cred load, tree restore,
plugin start). Safe to await before peers are connected.
- proc registerDoSProtectionWithNetwork*(WakuMix): kick off a background
task that retries registerSelf + saveTree indefinitely until the
broadcast lands. Cancelled when WakuMix.stop() is invoked.
waku_node.start() now wires these in order:
switch.start()
wakuMix.start() # local init, errors propagate
reconnectRelayPeers() # may back off; no longer blocks mix
wakuMix.registerDoSProtectionWithNetwork() # fire-and-forget retry
node.started = true
Re-call safety: registerDoSProtectionWithNetwork no-ops if a prior task
is still running. Lifecycle: WakuMix.stop() cancelAndWait()s the task
before calling plugin.stop().
For keystore-loaded nodes the first attempt early-returns successfully
(membershipIndex already set); the retry path only exercises for fresh
joins where the initial broadcast hits a not-yet-subscribed network.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* persistency: follow nim-sds 0.3.0 snapshot persistence contract
nim-sds 0.3.0 replaced the ~14 fine-grained per-row Persistence callbacks
with a 5-proc snapshot model (saveChannelMeta / updateHistory / loadChannel
/ dropChannel / setRetrievalHint), all returning Future[Result[...]].
Rewrite waku/persistency/sds_persistency.nim accordingly:
- ChannelMeta is stored as one blob per channel; the message log as
append/evict rows. Categories collapse from 7 to 2 (sds.meta, sds.log).
- Blob transform uses nim-sds' own codecs: snapshot_codec (schema-versioned
protobuf) for ChannelMeta, the SDS wire codec for SdsMessage log rows. The
generic payload_codec/BlobCodec path is retired (removed payload_codec.nim
and test_blob_codec.nim).
- setRetrievalHint is a deliberate no-op: persisted hints are never read back
(loadChannel/ChannelMeta carry none; hints are supplied live via the
onRetrievalHint provider). The closure stays because the field is required.
- Fix the module import spelling (srcDir="sds" => bare module paths), which
the previous adapter got wrong and never compiled against the locked deps.
Add tests/persistency/test_sds_persistency.nim (round-trip, empty-load,
evict, drop) replacing test_blob_codec in test_all. Full persistency suite
passes 74/74 under both refc and ORC.
* Bump to latest nim-sds and nim-brokers 3.1.1
* Update with latest nim-sds changes - removal of setRetrievalHints - not needed
Adds a portable (macOS bash 3.2 / Linux) helper that detects git-URL pinned
`requires` in waku.nimble which changed vs a git base ref (default HEAD) and
updates ONLY those nimble.lock entries — version, vcsRevision and the sha1
checksum — leaving every other entry byte-for-byte untouched.
It does not run `nimble lock` (which rewrites the whole file). The sha1 is
computed directly, reproducing nimble's algorithm from
src/nimblepkg/checksums.nim (git ls-files -> sort -> SHA1 over path +
symlink-target/file-bytes). Resolves tags to commits via git rev-parse and
guards against invalid commit hashes (e.g. a stray leading character).
Dry-run by default (exit 1 on drift); --apply writes; --base REF to compare
against another ref. Requires git + python3; nimble not required.
Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
* Remove makefile target update
* fix: set execute permission on install_nimble.sh
* improve install_nim script
* skip second nim install on Windows
* fix path check in install-nim
* Makefile workfile reordering
* chore: pin confutils to merged upstream commit
status-im/nim-confutils#146 is merged; move the confutils pin from the
PR fork back to status-im/nim-confutils master (36f3115). Content is
identical to the fork commit, so nimble sha1 and nix sha256 are unchanged.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
PR #3899 fixes zerokit v2.0.2's stale cargoHash, but only via an internal
`let` binding consumed by liblogosdelivery. Downstream consumers (e.g.
logos-delivery-module) that need librln still pull zerokit's rln package
directly and hit the stale hash.
Expose that corrected derivation as `packages.<system>.rln` so consumers can
bundle the exact same librln this build links, instead of overriding the
cargoHash themselves.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(node-info): real Version + new Commit in Nix/lgpm builds
getNodeInfo Version returned "n/a" on Nix-built libs (and lgpm
releases built from the flake) because nix/default.nix never passed
-d:git_version. A flake sandbox has no .git, so git describe is
impossible; derive the semver from waku.nimble's version field plus
the flake short commit, and expose the full commit SHA via a new
Commit node info id.
- waku_state_info: add Commit to NodeInfoId + dispatch git_commit
- waku_node: add git_commit {.strdefine.} (default "n/a")
- node start logs ("Starting Waku node" / "Running nwaku node") now
print commit = git_commit alongside version
- Makefile: inject -d:git_commit (full SHA), mirrors docker label
- nix/default.nix: accept gitVersion/gitCommit, pass as nim defines
- flake.nix: gitVersion = <nimble version>-g<shortRev>, gitCommit = rev
- CI version-check (PR only): ancestor-aware `git describe --tags
--abbrev=0` vs PR HEAD, base-version compare, so waku.nimble is kept
current early and a new tag never breaks in-flight PRs
- release-assets.yml: gate build/upload on a verify-version job
asserting tag base == waku.nimble (RC tags allowed), so a mismatched
tag publishes no artifacts
- docs: prepare_release.md explains the bump-before-tag requirement
Refs: status-im/infra-logos#4Closes: logos-messaging/logos-delivery#3884
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* docs: simplify
* chore: update version in waku.nimble
* fix(node-info): remove Commit node info field
Drop the newly added Commit (full SHA) node info id and its
git_commit compile-time define plumbing across Makefile, flake.nix
and nix/default.nix; revert the start/run log lines to version only.
The PR now solely fixes the getNodeInfo Version regression.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore(nix): align git_version format closer to Makefile
Adds the `v` prefix and uses a 6-char SHA so Nix-built nodes report
e.g. `v0.38.1-g52e980`, matching the shape of `git describe --abbrev=6
--always --tags` aside from the unreachable commit-count segment (tag
metadata isn't exposed through the flake input protocol).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds NodeInfoId.MyMixPubKey, returning the node's mix public key as
0x-prefixed hex via the existing debug API. Returns an empty string
when the mix protocol is not mounted.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* persistency: per-job SQLite-backed storage layer (singleton, brokered)
Adds a backend-neutral CRUD library at waku/persistency/, plus the
nim-brokers dependency swap that enables it.
Architecture (ports-and-adapters):
* Persistency: process-wide singleton, one root directory.
* Job: one tenant, one DB file, one worker thread, one BrokerContext.
* Backend: SQLite via waku/common/databases/db_sqlite. Uniform schema
kv(category BLOB, key BLOB, payload BLOB) PRIMARY KEY (category, key)
WITHOUT ROWID, WAL mode.
* Writes are fire-and-forget via EventBroker(mt) PersistEvent.
* Reads are async via five RequestBroker(mt) shapes (KvGet, KvExists,
KvScan, KvCount, KvDelete). Reads return Result[T, PersistencyError].
* One storage thread per job; tenants isolated by BrokerContext.
Public surface (waku/persistency/persistency.nim):
Persistency.instance(rootDir) / Persistency.instance() / Persistency.reset()
p.openJob(id) / p.closeJob(id) / p.dropJob(id) / p.close()
p.job(id) / p[id] / p.hasJob(id)
Writes (Job form & string-id form, fire-and-forget):
persist / persistPut / persistDelete / persistEncoded
Reads (Job form & string-id form, async Result):
get / exists / scan / scanPrefix / count / deleteAcked
Key & payload encoding (keys.nim, payload.nim):
* encodePart family + variadic key(...) / payload(...) macros +
single-value toKey / toPayload.
* Primitives: string and openArray[byte] are 2-byte BE length + bytes;
int{8..64} are sign-flipped 8-byte BE; uint{16..64} are 8-byte BE;
bool/byte/char are 1 byte; enums are int64(ord(v)).
* Generic encodePart[T: tuple | object] recurses through fields() so
any composite Nim type is encodable without ceremony.
* Stable across Nim/C compiler upgrades: no sizeof, no memcpy, no
cast on pointers, no host-endianness dependency.
* `rawKey(bytes)` + `persistPut(..., openArray[byte])` let callers
bypass the built-in encoder with their own format (CBOR, protobuf...).
Lifecycle:
* Persistency.new is private; Persistency.instance is the only public
constructor. Same rootDir is idempotent; conflicting rootDir is
peInvalidArgument. Persistency.reset for test/restart paths.
* openJob opens-or-creates the per-job SQLite file; an existing file
is reused with its data preserved.
* Teardown integration: Persistency.instance registers a Teardown
MultiRequestBroker provider that closes all jobs and clears the
singleton slot when Waku.stop() issues Teardown.request.
Internal layering:
types.nim pure value types (Key, KeyRange, KvRow, TxOp,
PersistencyError)
keys.nim encodePart primitives + key(...) macro
payload.nim toPayload + payload(...) macro
schema.nim CREATE TABLE + connection pragmas + user_version
backend_sqlite.nim KvBackend, applyOps (single source of write SQL),
getOne/existsOne/deleteOne, scanRange (asc/desc,
half-open ranges, open-ended stop), countRange
backend_comm.nim EventBroker(mt) PersistEvent + 5 RequestBroker(mt)
declarations; encodeErr/decodeErr boundary helpers
backend_thread.nim startStorageThread / stopStorageThread (shared
allocShared0 arg, cstring dbPath, atomic
ready/shutdown flags); per-thread provider
registration
persistency.nim Persistency + Job types, singleton state, public
facade
../requests/lifecycle_requests.nim
Teardown MultiRequestBroker
Tests (69 cases, all passing):
test_keys.nim sort-order invariants (length-prefix strings,
sign-flipped ints, composite tuples, prefix
range)
test_backend.nim round-trip / replace / delete-return-value /
batched atomicity / asc-desc-half-open-open-
ended scans / category isolation / batch
txDelete
test_lifecycle.nim open-or-create rootDir / non-dir collision /
reopen across sessions / idempotent openJob /
two-tenant parallel isolation / closeJob joins
worker / dropJob removes file / acked delete
test_facade.nim put-then-get / atomic batch / scanPrefix
asc/desc / deleteAcked hit-miss /
fire-and-forget delete / two-tenant facade
isolation
test_encoding.nim tuple/named-tuple/object keys, embedded Key,
enum encoding, field-major composite sort,
payload struct encoding, end-to-end struct
round-trip through SQLite
test_string_lookup.nim peJobNotFound semantics / hasJob / subscript /
persistPut+get via id / reads short-circuit /
writes drop+warn / persistEncoded via id /
scan parity Job-ref vs id
test_singleton.nim idempotent same-rootDir / different-rootDir
rejection / no-arg instance lifecycle / reset
retargets / reset idempotence / Teardown.request
end-to-end
Prerequisite delivered in the same series: replace the in-tree broker
implementation with the external nim-brokers package; update all
broker call-sites (waku_filter_v2, waku_relay, waku_rln_relay,
delivery_service, peer_manager, requests/*, factory/*, api tests, etc.)
to the new package API; chat2 made to compile again.
Note: SDS adapter (Phase 5 of the design) is deferred -- nim-sds is
still developed side-by-side and the persistency layer is intentionally
SDS-agnostic.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* persistency: pin nim-brokers by URL+commit (workaround for stale registry)
The bare `brokers >= 2.0.1` form cannot resolve on machines where the
local nimble SAT solver enumerates only the registry-recorded 0.1.0 for
brokers. The nim-lang/packages entry for `brokers` carries no per-tag
metadata (only the URL), so until that registry entry is refreshed the
SAT solver clamps the available-versions list to 0.1.0 and rejects the
>= 2.0.1 constraint -- even though pkgs2 and pkgcache both have v2.0.1
cloned locally.
Pinning by URL+commit bypasses the registry path entirely. Inline
comment in waku.nimble documents the situation and the path back to
the bare form once nim-lang/packages is updated.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* persistency: nph format pass
Run `nph` on all 57 Nim files touched by this PR. Pure formatting:
17 files re-styled, no semantic change. Suite still 69/69.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* Fix build, add local-storage-path config, lazy init of Persistency from Waku start
* fix: fix nix deps
* fixes for nix build, regenerate deps
* reverting accidental dependency changes
* Fixing deps
* Apply suggestions from code review
Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
* persistency tests: migrate to suite / asyncTest / await
Match the in-tree test convention (procSuite -> suite, sync test +
waitFor -> asyncTest + await):
- procSuite "X": -> suite "X":
- For tests doing async work: test -> asyncTest, waitFor -> await.
- Poll helpers (proc waitFor(t: Job, ...) in test_lifecycle.nim,
proc waitUntilExists(...) in test_facade.nim and
test_string_lookup.nim) -> Future[bool] {.async.}, internal
`waitFor X` -> `await X`, internal `sleep(N)` ->
`await sleepAsync(chronos.milliseconds(N))`.
- Renamed test_lifecycle.nim's helper proc from `waitFor(t: Job, ...)`
-> `pollExists(t: Job, ...)`; the previous name shadowed
chronos.waitFor in the chronos macro expansion.
- `chronos.milliseconds(N)` explicitly qualified because `std/times`
also exports `milliseconds` (returning TimeInterval, not Duration).
- `check await x` -> `let okN = await x; check okN` to dodge chronos's
"yield in expr not lowered" with await-as-macro-argument.
- `(await x).foo()` -> `let awN = await x; ... awN.foo() ...` for the
same reason.
waku/persistency/persistency.nim: nph also pulled the proc signatures
across multiple lines; restored explicit `Future[void] {.async.}`
return types after the colon (an intermediate nph pass had elided them).
Suite: 71 / 71 OK against the new async write surface.
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
* use idiomatic valueOr instead of ifs
* Reworked persistency shutdown, remove not necessary teardown mechanism
* Use const for DefaultStoragePath
* format to follow coding guidelines - no use of result and explicit returns - no functional change
---------
Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Ivan FB <128452529+Ivansete-status@users.noreply.github.com>
* any port set to 0 on conf results in a random port bound
* Debug API MyBoundPorts reports actually bound ports for all services, reports 0 if disabled
* write back bound values to both WakuConf and WakuNode.ports
* setupDiscoveryV5 returns Result and errors out on port 0
* rename setupAndStartDiscv5WithAutoPort to setupAndStartDiscv5
* updateWaku ENR rebuild now runs after discv5 startup
* Add DefaultP2pTcpPort, DefaultDiscv5UdpPort, DefaultWebSocketPort, DefaultRestPort, DefaultMetricsHttpPort
* add tests
* nix: parameterize build flags with named args
Expose `enablePostgres`, `enableNimDebugDlOpen`, and `chroniclesLogLevel`
as arguments on `nix/default.nix`. Defaults preserve today's hardcoded
behavior, so `nix build .#liblogosdelivery` with no overrides is a
no-op change.
Consume the package via `callPackage` in `flake.nix` so consumers can
use `.override { ... }` without extra wrapping.
* nix: link libstdc++ on Linux so consumers don't need patchelf
Append `stdenv.cc.cc.lib` to `buildInputs` on Linux and add `-lstdc++`
to the Nim `--passL` flags. Nix stdenv's fixupPhase will auto-inject
`${stdenv.cc.cc.lib}/lib` into the output's RUNPATH, so downstream
consumers can drop their patchelf step.
macOS resolves the C++ stdlib via dyld/libc++ and is unaffected.
* nix: bundle librln into the output for a self-contained package
Copy the librln shared library (`librln.so` / `librln.dylib`) from the
zerokit input into `$out/lib` and rewrite the internal reference in
`liblogosdelivery`:
- Darwin: set librln's install name to `@rpath/librln.dylib`, change the
consumer's reference to match, and add `@loader_path` as an rpath.
- Linux: add `$ORIGIN` to the rpath so `librln.so` resolves from the
sibling directory, preserving the gcc-lib entry injected by the stdenv
fixupPhase for libstdc++.
The installed `liblogosdelivery` no longer carries a `/nix/store/...`
absolute path to zerokit, so downstream consumers can ship the bundle
as-is.