From e5431d589e5f113a82c0211fae048d39cf134a32 Mon Sep 17 00:00:00 2001 From: Tranquil-Flow Date: Wed, 20 May 2026 16:14:11 +0200 Subject: [PATCH 1/2] =?UTF-8?q?Solution:=20LP-0017=20=E2=80=94=20Whistlebl?= =?UTF-8?q?ower?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- solutions/LP-0017.md | 88 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 solutions/LP-0017.md diff --git a/solutions/LP-0017.md b/solutions/LP-0017.md new file mode 100644 index 0000000..730a75b --- /dev/null +++ b/solutions/LP-0017.md @@ -0,0 +1,88 @@ +# Solution: LP-0017 — Whistleblower + +Censorship-resistant document upload + indexing app on the Logos stack. + +**Repository:** + +**Narrated demo video:** + +## Summary + +Whistleblower is a Logos Basecamp app that lets a user pick a document, upload it to Logos Storage, broadcast the `(CID, metadata)` envelope over Logos Delivery, and (optionally) anchor the CID on the LEZ registry. A separate permissionless CLI tool batch-anchors accumulated CIDs from the Delivery topic without coordination with the publisher. + +The on-chain registry uses a **PDA-per-CID** layout — every anchored CID lives in its own program-derived account at `(program_id, sha256("lp0017:cid:v1\0" || cid))`. Anchor cost is O(1) per CID regardless of total registry size, capacity is unbounded, and idempotency falls out of the default-state check rather than needing a separate read-modify-write step. + +The reusable indexing module (`document-indexing` crate) is Qt-free Rust and exposes `Publisher`, `StorageClient`, `DeliveryClient`, `RegistryClient` traits. The Basecamp UI plugin and the batch CLI both consume it via the same trait surface. + +## Spec compliance map + +| Spec § | Requirement | Status | Where | +|---|---|---|---| +| Functionality 1 | Upload to Logos Storage | ✅ | `ui/src/WhistleblowerBackend.cpp::uploadToStorage` via `LogosAPIClient::invokeRemoteMethodAsync("storage_module", "uploadUrl", ...)` | +| Functionality 2 | Broadcast envelope to Logos Delivery topic | ✅ | `ui/src/WhistleblowerBackend.cpp::broadcastEnvelope` via `LogosAPIClient::invokeRemoteMethodAsync("delivery_module", "send", ...)`. Topic = `/lp0017-whistleblower/1/cids/json`. | +| Functionality 3 | Optional on-chain anchor | ✅ | `Publisher::anchor_published` (Rust) and `whistleblower_anchor_one` FFI exposed to QML's "Anchor" button. | +| Functionality 4 | Permissionless batch anchor CLI | ✅ | `batch/` produces `whistleblower-batch` binary. Sled-backed dedupe ledger, batch window, idempotent re-anchoring. | +| Functionality 4 idempotency | Re-submit registered CID = no-op | ✅ | `process_entry` in `methods/guest/src/bin/whistleblower_registry.rs` uses `AccountPostState::new_claimed_if_default` — rejects only if non-default state already exists for a different `(cid_hash, metadata_hash)` pair. | +| Functionality 5 | Registry stores `(CID, metadata_hash, anchor_timestamp)` per doc | ✅ | `AnchorEntry` borsh-encoded into one PDA per CID. | +| Functionality 5 | Registry queryable by CID | ✅ | `whistleblower_query_by_cid` FFI + `LezRegistryClient::query_by_cid_hash` derive PDA + read account state. | +| Functionality 5 | ≥10 CIDs per batch tx | ✅ | 50-CID batch confirmed in `lez_adapter_anchor_50_cids_in_one_tx` integration test (5x headroom). | +| Functionality 6 | Reusable indexing module | ✅ | `document-indexing` crate, no Qt deps, three `dyn`-safe trait boundaries. Mock + LEZ + (placeholder) Logos adapters in tree. | +| Usability | Basecamp app GUI | ✅ | `ui/` — Qt6/QML plugin packaged as `dist/whistleblower-plugin.lgx` (2.4MB darwin-arm64). Build via `nix build .#lgx`. | +| Usability | LEZ program IDL via SPEL | ✅ | `whistleblower-registry-idl.json` (hand-written; SPEL macros couldn't be used because they pull `bonsai-sdk` into the riscv32im build via `nssa_core/host` — see `ARCHITECTURE.md`). `spel inspect` consumes it. | +| Reliability | Storage retry with backoff | ✅ | `Publisher` wraps every adapter call in `with_retry` (5 retries, exponential, surfaces final error). | +| Reliability | Delivery dedup | ✅ | `DurableDedupeStore` (sled) in `batch::run_batch_loop`. | +| Reliability | Batch resumes from last anchored | ✅ | Sled ledger + registry idempotency = safe re-runs from any point. | +| Performance | CU benchmarks (single + 50-CID) | ✅ | [`BENCHMARKS.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/BENCHMARKS.md) under `risc0_dev_mode = false` + `RISC0_DEV_MODE=0`: ~120ms zkVM executor for 50-CID batch (~2.5ms/CID amortized), ~6-12ms for single-CID. Per Logos Discord (2026-05-11), the local sequencer **is** the LEZ devnet — these numbers are devnet numbers. | +| Supportability | Deployed on LEZ devnet | ✅ | Per Logos Discord (2026-05-11), local sequencer = LEZ devnet. Program deployed and exercised under `risc0_dev_mode = false`: idempotency, anchor, query, and 50-CID batch flows pass against the live registry. See [`DEPLOYMENT.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/DEPLOYMENT.md). | +| Supportability | E2E tests in CI | ✅ | `.github/workflows/ci.yml` runs the workspace test suite + ignored live-LEZ tests against a localnet sequencer. The risc0 zkVM guest, FFI, and LEZ adapter all build and exercise in CI. | +| Supportability | CI green on default branch | ✅ | 24 fast tests + 4 FFI unit tests + 3 ignored live-LEZ adapter tests + 2 ignored live-LEZ FFI smokes pass. | +| Supportability | README covers build, deploy, app, CLI, query | ✅ | [`README.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/README.md) has each section. | +| Supportability | Reproducible E2E demo script (`RISC0_DEV_MODE=0`) | ✅ | `scripts/demo.sh` against `lgs localnet start` with `risc0_dev_mode = false`. | +| Supportability | Narrated video demo | ✅ | | +| Submission | GitHub issues filed for upstream problems | ✅ | [`BUGS_FILED.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/BUGS_FILED.md) lists every issue raised + link. | + +## Architecture decisions + +1. **PDA-per-CID registry storage** — not single-root-PDA. O(1) anchor cost, idempotency-by-default-state-check, unbounded capacity. Trade: no on-chain enumeration (acceptable per spec — registry need only be queryable by CID). +2. **Raw `nssa_core` guest** (not `spel-framework`) — `spel-framework` pulls `bonsai-sdk` into the riscv32im build via `nssa_core/host`, which fails to cross-compile (`ring` Apple Metal). IDL hand-written. Filed upstream. +3. **LEZ program path** (vs zone SDK) — zone SDK requires a single designated consensus inscriber (decentralised sequencers not yet shipped). LEZ program is permissionless from day one. +4. **Adapter-based indexing module** — Qt-free Rust core, three `dyn`-safe trait boundaries. Real adapter for LEZ + mock adapter for tests. Real Logos Storage / Delivery integration lives in the UI plugin (uses in-process `LogosAPIClient`). +5. **Wallet-free upload + broadcast** — only on-chain anchoring needs a wallet, satisfying spec's "without identifying the uploader" line. +6. **Topic** = `/lp0017-whistleblower/1/cids/json` (LIP-23 shape). Constant in `whistleblower-core::DEFAULT_CONTENT_TOPIC`. + +## Reproduce the build + +```bash +git clone https://github.com/Tranquil-Flow/lp-0017-whistleblower wb && cd wb + +# 1. Local dev — Rust + Qt6 toolchain on PATH: +(cd ui/ffi && cargo build --release) +cmake -B build -GNinja ./ui -DWHISTLEBLOWER_FFI_LIB_DIR="$PWD/ui/ffi/target/release" +cmake --build build +QML_PATH=$PWD/ui/qml ./build/bin/whistleblower_app # standalone preview + +# 2. Production .lgx via nix: +nix build .#ffi +nix build .#plugin +nix build .#lgx +nix run .#install +lgs basecamp install + +# 3. Test suite: +cargo test --workspace --exclude whistleblower-methods --exclude whistleblower-programs --exclude anchor-spike --release +(cd ui/ffi && cargo test --release) + +# 4. Live LEZ integration tests (require localnet up): +lgs localnet start +NSSA_WALLET_HOME_DIR=$PWD/.scaffold/wallet \ + cargo test -p whistleblower-lez-adapter --release -- --ignored --nocapture +``` + +## Known limitations + +- No headless real-Delivery in the batch CLI (mock-only); real Delivery requires either a Rust QtRemoteObjects client against `logos_host` or restructuring the batch as a Basecamp plugin component. Tradeoffs in `adapters/logos/README.md`. The Basecamp UI plugin owns the real-Storage / real-Delivery integration. +- IDL is hand-written (not generated by SPEL macros) due to the `bonsai-sdk` cross-compile blocker. `spel inspect` consumes it. Filed upstream. + +## License + +Dual-licensed under MIT and Apache-2.0. From 68125cef49e157a7f990d4e1391ffc8c2581db42 Mon Sep 17 00:00:00 2001 From: Tranquil-Flow Date: Wed, 20 May 2026 16:21:50 +0200 Subject: [PATCH 2/2] LP-0017: conform to canonical solution template --- solutions/LP-0017.md | 167 ++++++++++++++++++++++--------------------- 1 file changed, 85 insertions(+), 82 deletions(-) diff --git a/solutions/LP-0017.md b/solutions/LP-0017.md index 730a75b..b8d95e6 100644 --- a/solutions/LP-0017.md +++ b/solutions/LP-0017.md @@ -1,88 +1,91 @@ # Solution: LP-0017 — Whistleblower -Censorship-resistant document upload + indexing app on the Logos stack. +**Submitted by:** Tranquil-Flow -**Repository:** +## Summary -**Narrated demo video:** +Whistleblower is a Logos Basecamp app that lets a user pick a document, upload it to Logos Storage, broadcast the `(CID, metadata)` envelope over Logos Delivery, and (optionally) anchor the CID on a LEZ registry. A separate permissionless CLI tool batch-anchors accumulated CIDs from the Delivery topic without coordination with the publisher. The on-chain registry uses a **PDA-per-CID** layout — every anchored CID lives in its own program-derived account, so anchor cost is O(1), capacity is unbounded, and idempotency falls out of the default-state check. -## Summary +## Repository + +- **Repo:** + +## Approach + +The system has four components built from a shared trait surface: + +1. **Logos Basecamp app** (`ui/`) — Qt6/QML plugin packaged as a portable `.lgx`. Drives upload → Storage, broadcast → Delivery, optional anchor → LEZ via FFI. +2. **Reusable indexing module** (`document-indexing`, Qt-free Rust) — exposes `Publisher`, `StorageClient`, `DeliveryClient`, `RegistryClient` traits. Mock adapter for tests, LEZ adapter for production. +3. **Permissionless batch CLI** (`batch/whistleblower-batch`) — subscribes to the Delivery topic, dedupe via sled-backed ledger, anchors in bounded batches. +4. **LEZ registry program** (`methods/guest/`) — PDA-per-CID storage, idempotent anchors, queryable without a transaction. + +### Key design decisions + +1. **PDA-per-CID registry storage** — not a single root PDA with a `HashMap`. We considered the single-PDA approach and rejected it: a single account's data field is capped at ~100 KiB, which bounds registry capacity by design. PDA-per-CID gives O(1) anchor cost regardless of registry size, unbounded capacity, and idempotency-by-default-state-check (no read-modify-write race). Tradeoff: no on-chain enumeration — acceptable because the spec only requires queryability by CID. +2. **Raw `nssa_core` guest** (not `spel-framework`). We tried `spel-framework` first; its `nssa_core/host` feature pulls `bonsai-sdk` into the `riscv32im` build, which fails to cross-compile on macOS arm64 (`ring` Apple Metal). IDL is hand-written; `spel inspect` still consumes it. Filed upstream as a portability bug — see `BUGS_FILED.md`. +3. **LEZ program path** (not zone SDK). The zone SDK currently requires a single designated consensus inscriber — decentralised sequencers haven't shipped. LEZ program is permissionless from day one, which the censorship-resistance brief demands. +4. **Adapter-based indexing module.** The Qt-free Rust core is `dyn`-safe at three trait boundaries (`StorageClient`, `DeliveryClient`, `RegistryClient`). The Basecamp UI plugin and the batch CLI consume it identically, so the batch path can be re-targeted (e.g. a headless Rust adapter against `logos_host`) without touching publishing logic. Tradeoff: real Storage / Delivery integration lives in the UI plugin (uses in-process `LogosAPIClient`); a future headless Rust adapter is sketched in `adapters/logos/README.md`. +5. **Wallet-free upload + broadcast.** Only on-chain anchoring needs a wallet. The publish path satisfies the spec's "without identifying the uploader" requirement. + +### Why the Logos stack + +The brief is censorship-resistant document publication. Storage gives content-addressed retrieval; Delivery gives broadcast without a central operator; LEZ gives a permissionless on-chain registry anyone can append to. Built on a centralized stack, the publisher's identity leaks through whichever single operator hosts upload + broadcast + indexing — the very property we're avoiding. Logos lets each component live in a different trust domain. + +## Success Criteria Checklist + +Mirrored from the LP-0017 spec. + +- [x] **Functionality 1 — Upload to Logos Storage.** `ui/src/WhistleblowerBackend.cpp::uploadToStorage` via `LogosAPIClient::invokeRemoteMethodAsync("storage_module", "uploadUrl", ...)`. +- [x] **Functionality 2 — Broadcast envelope to Logos Delivery topic.** `ui/src/WhistleblowerBackend.cpp::broadcastEnvelope` to `/lp0017-whistleblower/1/cids/json`. +- [x] **Functionality 3 — Optional on-chain anchor.** `Publisher::anchor_published` (Rust) and `whistleblower_anchor_one` (C FFI) — wired to QML's "Anchor" button. +- [x] **Functionality 4 — Permissionless batch anchor CLI.** `batch/` produces `whistleblower-batch`. Sled-backed dedupe ledger, batch window, idempotent re-anchoring. +- [x] **Functionality 4 idempotency — Re-submit registered CID = no-op.** `process_entry` in `methods/guest/src/bin/whistleblower_registry.rs` uses `AccountPostState::new_claimed_if_default`. +- [x] **Functionality 5 — Registry stores `(CID, metadata_hash, anchor_timestamp)` per doc.** `AnchorEntry` borsh-encoded into one PDA per CID. +- [x] **Functionality 5 — Registry queryable by CID.** `whistleblower_query_by_cid` FFI + `LezRegistryClient::query_by_cid_hash`. +- [x] **Functionality 5 — ≥10 CIDs per batch tx.** 50-CID batch confirmed in `lez_adapter_anchor_50_cids_in_one_tx` (5× headroom). +- [x] **Functionality 6 — Reusable indexing module.** `document-indexing` crate, no Qt deps, three `dyn`-safe trait boundaries. +- [x] **Usability — Basecamp app GUI.** `ui/` Qt6/QML plugin packaged as `dist/whistleblower-plugin.lgx`. +- [x] **Usability — LEZ program IDL via SPEL.** `whistleblower-registry.idl.json` consumed by `spel inspect`. +- [x] **Reliability — Storage retry with backoff.** `Publisher` wraps every adapter call in `with_retry` (5 retries, exponential). +- [x] **Reliability — Delivery dedup.** `DurableDedupeStore` (sled) in `batch::run_batch_loop`. +- [x] **Reliability — Batch resumes from last anchored.** Sled ledger + registry idempotency = safe re-runs from any point. +- [x] **Performance — CU benchmarks.** `BENCHMARKS.md` under `risc0_dev_mode = false`: 50-CID batch ~120ms zkVM executor (~2.5ms/CID amortized), single-CID ~6–12ms. +- [x] **Supportability — Deployed on LEZ devnet.** Per Logos Discord (2026-05-11), local sequencer = LEZ devnet; program exercised under `risc0_dev_mode = false`. +- [x] **Supportability — E2E tests in CI.** `.github/workflows/ci.yml` runs the full workspace + ignored live-LEZ tests against a localnet sequencer. +- [x] **Supportability — README + reproducible E2E demo + narrated video.** `README.md`; `scripts/demo.sh` against `lgs localnet start`; narrated demo at . +- [x] **Submission — GitHub issues filed for upstream problems.** `BUGS_FILED.md` lists every issue raised + link. + +## FURPS Self-Assessment + +### Functionality + +The submission delivers the full publish flow (upload → broadcast → optional anchor) inside a real Basecamp instance, plus the permissionless batch CLI for third-party anchoring. The on-chain registry is queryable by CID hash without submitting a transaction. The 50-CID batch confirms a single transaction handles 5× the spec's ≥10-per-batch requirement. Out of scope: tag-based search across the registry (no on-chain enumeration by design — single-CID lookup only), and a headless real-Delivery adapter for the batch CLI (only the in-process Basecamp path uses real Delivery; the batch CLI uses a mock Delivery client because real Delivery currently requires Qt remote objects against `logos_host`). + +### Usability + +End users install the `.lgx` via `lgs basecamp install` or via Basecamp's "Install plugin" → file picker. Onboarding is two steps: pick a document, hit "Publish". Anchoring is an opt-in second click. The reusable indexing module (`document-indexing`) is documented via rustdoc on `Publisher` + the three adapter traits; integrators implement one adapter trait per Logos service they want to back the publisher with. The batch CLI is a single binary with three flags (`--topic`, `--batch-size`, `--dedupe-store-path`). + +### Reliability + +`Publisher` wraps every adapter call in `with_retry` (5 retries, exponential backoff, surfaces the final error). The batch CLI's dedupe ledger is sled-backed so it survives process restarts; combined with the registry's default-state idempotency, the batch is safe to re-run from any point — re-submitting an already-anchored CID is a no-op at the program level. Failed anchors leave the registry unchanged because the LEZ program rejects transactions atomically before any PDA write. The known limitation is that real-Delivery in the headless batch CLI is mock-only; the UI plugin owns the real Storage / Delivery integration (in-process `LogosAPIClient`). + +### Performance + +Captured under `risc0_dev_mode = false` and `RISC0_DEV_MODE=0` on the local LEZ devnet (per Logos Discord 2026-05-11, the local sequencer is the LEZ devnet — no separate remote endpoint exists). 50-CID batch: ~120 ms total zkVM executor time, ~2.5 ms/CID amortized. Single-CID anchor: 6–12 ms. Anchor cost is constant per CID regardless of registry size — the PDA-per-CID layout means anchoring CID N+1 is independent of CIDs 1..N. Wall-clock latency is dominated by the 15-second block production interval, not by program compute cost. Full numbers in `BENCHMARKS.md`. Note: anchor transactions use the LEZ Public path which bypasses host-side proof generation; the prover does fire under `RISC0_DEV_MODE=0` for the faucet / wallet-bootstrap path shown in Scene 1 of the demo video. + +### Supportability + +CI is green on `main`: 24 fast tests + 4 FFI unit tests + 3 ignored live-LEZ adapter tests + 2 ignored live-LEZ FFI smokes. The CI workflow exercises the full workspace including the risc0 zkVM guest, the FFI cdylib, and the LEZ adapter against a localnet sequencer — not just the pure-Rust shared types. Deployment is documented in `DEPLOYMENT.md` with the exact `lgs basecamp install` + `lgs basecamp launch` commands used to verify the plugin in a real Basecamp instance on 2026-05-09. The codebase is split into eight crates plus the UI plugin so future maintainers can swap individual layers (registry program, indexing traits, batch CLI, UI) independently. + +## Supporting Materials + +- **Narrated demo video:** +- **CU benchmarks:** +- **Deployment instructions:** +- **Demo script (terminal walkthrough):** +- **Upstream bug reports filed during this build:** +- **Hand-written SPEL-compatible IDL:** + +## Terms & Conditions -Whistleblower is a Logos Basecamp app that lets a user pick a document, upload it to Logos Storage, broadcast the `(CID, metadata)` envelope over Logos Delivery, and (optionally) anchor the CID on the LEZ registry. A separate permissionless CLI tool batch-anchors accumulated CIDs from the Delivery topic without coordination with the publisher. - -The on-chain registry uses a **PDA-per-CID** layout — every anchored CID lives in its own program-derived account at `(program_id, sha256("lp0017:cid:v1\0" || cid))`. Anchor cost is O(1) per CID regardless of total registry size, capacity is unbounded, and idempotency falls out of the default-state check rather than needing a separate read-modify-write step. - -The reusable indexing module (`document-indexing` crate) is Qt-free Rust and exposes `Publisher`, `StorageClient`, `DeliveryClient`, `RegistryClient` traits. The Basecamp UI plugin and the batch CLI both consume it via the same trait surface. - -## Spec compliance map - -| Spec § | Requirement | Status | Where | -|---|---|---|---| -| Functionality 1 | Upload to Logos Storage | ✅ | `ui/src/WhistleblowerBackend.cpp::uploadToStorage` via `LogosAPIClient::invokeRemoteMethodAsync("storage_module", "uploadUrl", ...)` | -| Functionality 2 | Broadcast envelope to Logos Delivery topic | ✅ | `ui/src/WhistleblowerBackend.cpp::broadcastEnvelope` via `LogosAPIClient::invokeRemoteMethodAsync("delivery_module", "send", ...)`. Topic = `/lp0017-whistleblower/1/cids/json`. | -| Functionality 3 | Optional on-chain anchor | ✅ | `Publisher::anchor_published` (Rust) and `whistleblower_anchor_one` FFI exposed to QML's "Anchor" button. | -| Functionality 4 | Permissionless batch anchor CLI | ✅ | `batch/` produces `whistleblower-batch` binary. Sled-backed dedupe ledger, batch window, idempotent re-anchoring. | -| Functionality 4 idempotency | Re-submit registered CID = no-op | ✅ | `process_entry` in `methods/guest/src/bin/whistleblower_registry.rs` uses `AccountPostState::new_claimed_if_default` — rejects only if non-default state already exists for a different `(cid_hash, metadata_hash)` pair. | -| Functionality 5 | Registry stores `(CID, metadata_hash, anchor_timestamp)` per doc | ✅ | `AnchorEntry` borsh-encoded into one PDA per CID. | -| Functionality 5 | Registry queryable by CID | ✅ | `whistleblower_query_by_cid` FFI + `LezRegistryClient::query_by_cid_hash` derive PDA + read account state. | -| Functionality 5 | ≥10 CIDs per batch tx | ✅ | 50-CID batch confirmed in `lez_adapter_anchor_50_cids_in_one_tx` integration test (5x headroom). | -| Functionality 6 | Reusable indexing module | ✅ | `document-indexing` crate, no Qt deps, three `dyn`-safe trait boundaries. Mock + LEZ + (placeholder) Logos adapters in tree. | -| Usability | Basecamp app GUI | ✅ | `ui/` — Qt6/QML plugin packaged as `dist/whistleblower-plugin.lgx` (2.4MB darwin-arm64). Build via `nix build .#lgx`. | -| Usability | LEZ program IDL via SPEL | ✅ | `whistleblower-registry-idl.json` (hand-written; SPEL macros couldn't be used because they pull `bonsai-sdk` into the riscv32im build via `nssa_core/host` — see `ARCHITECTURE.md`). `spel inspect` consumes it. | -| Reliability | Storage retry with backoff | ✅ | `Publisher` wraps every adapter call in `with_retry` (5 retries, exponential, surfaces final error). | -| Reliability | Delivery dedup | ✅ | `DurableDedupeStore` (sled) in `batch::run_batch_loop`. | -| Reliability | Batch resumes from last anchored | ✅ | Sled ledger + registry idempotency = safe re-runs from any point. | -| Performance | CU benchmarks (single + 50-CID) | ✅ | [`BENCHMARKS.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/BENCHMARKS.md) under `risc0_dev_mode = false` + `RISC0_DEV_MODE=0`: ~120ms zkVM executor for 50-CID batch (~2.5ms/CID amortized), ~6-12ms for single-CID. Per Logos Discord (2026-05-11), the local sequencer **is** the LEZ devnet — these numbers are devnet numbers. | -| Supportability | Deployed on LEZ devnet | ✅ | Per Logos Discord (2026-05-11), local sequencer = LEZ devnet. Program deployed and exercised under `risc0_dev_mode = false`: idempotency, anchor, query, and 50-CID batch flows pass against the live registry. See [`DEPLOYMENT.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/DEPLOYMENT.md). | -| Supportability | E2E tests in CI | ✅ | `.github/workflows/ci.yml` runs the workspace test suite + ignored live-LEZ tests against a localnet sequencer. The risc0 zkVM guest, FFI, and LEZ adapter all build and exercise in CI. | -| Supportability | CI green on default branch | ✅ | 24 fast tests + 4 FFI unit tests + 3 ignored live-LEZ adapter tests + 2 ignored live-LEZ FFI smokes pass. | -| Supportability | README covers build, deploy, app, CLI, query | ✅ | [`README.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/README.md) has each section. | -| Supportability | Reproducible E2E demo script (`RISC0_DEV_MODE=0`) | ✅ | `scripts/demo.sh` against `lgs localnet start` with `risc0_dev_mode = false`. | -| Supportability | Narrated video demo | ✅ | | -| Submission | GitHub issues filed for upstream problems | ✅ | [`BUGS_FILED.md`](https://github.com/Tranquil-Flow/lp-0017-whistleblower/blob/main/BUGS_FILED.md) lists every issue raised + link. | - -## Architecture decisions - -1. **PDA-per-CID registry storage** — not single-root-PDA. O(1) anchor cost, idempotency-by-default-state-check, unbounded capacity. Trade: no on-chain enumeration (acceptable per spec — registry need only be queryable by CID). -2. **Raw `nssa_core` guest** (not `spel-framework`) — `spel-framework` pulls `bonsai-sdk` into the riscv32im build via `nssa_core/host`, which fails to cross-compile (`ring` Apple Metal). IDL hand-written. Filed upstream. -3. **LEZ program path** (vs zone SDK) — zone SDK requires a single designated consensus inscriber (decentralised sequencers not yet shipped). LEZ program is permissionless from day one. -4. **Adapter-based indexing module** — Qt-free Rust core, three `dyn`-safe trait boundaries. Real adapter for LEZ + mock adapter for tests. Real Logos Storage / Delivery integration lives in the UI plugin (uses in-process `LogosAPIClient`). -5. **Wallet-free upload + broadcast** — only on-chain anchoring needs a wallet, satisfying spec's "without identifying the uploader" line. -6. **Topic** = `/lp0017-whistleblower/1/cids/json` (LIP-23 shape). Constant in `whistleblower-core::DEFAULT_CONTENT_TOPIC`. - -## Reproduce the build - -```bash -git clone https://github.com/Tranquil-Flow/lp-0017-whistleblower wb && cd wb - -# 1. Local dev — Rust + Qt6 toolchain on PATH: -(cd ui/ffi && cargo build --release) -cmake -B build -GNinja ./ui -DWHISTLEBLOWER_FFI_LIB_DIR="$PWD/ui/ffi/target/release" -cmake --build build -QML_PATH=$PWD/ui/qml ./build/bin/whistleblower_app # standalone preview - -# 2. Production .lgx via nix: -nix build .#ffi -nix build .#plugin -nix build .#lgx -nix run .#install -lgs basecamp install - -# 3. Test suite: -cargo test --workspace --exclude whistleblower-methods --exclude whistleblower-programs --exclude anchor-spike --release -(cd ui/ffi && cargo test --release) - -# 4. Live LEZ integration tests (require localnet up): -lgs localnet start -NSSA_WALLET_HOME_DIR=$PWD/.scaffold/wallet \ - cargo test -p whistleblower-lez-adapter --release -- --ignored --nocapture -``` - -## Known limitations - -- No headless real-Delivery in the batch CLI (mock-only); real Delivery requires either a Rust QtRemoteObjects client against `logos_host` or restructuring the batch as a Basecamp plugin component. Tradeoffs in `adapters/logos/README.md`. The Basecamp UI plugin owns the real-Storage / real-Delivery integration. -- IDL is hand-written (not generated by SPEL macros) due to the `bonsai-sdk` cross-compile blocker. `spel inspect` consumes it. Filed upstream. - -## License - -Dual-licensed under MIT and Apache-2.0. +By submitting this solution, I confirm that I have read and agree to the [Terms & Conditions](../TERMS.md).