Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
141 changes: 141 additions & 0 deletions solutions/LP-0017.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
# Solution: LP-0017 — Whistleblower

**Submitted by:** Thompsonmina

## Summary

Whistleblower is a Logos Basecamp app for censorship-resistant document
publication. A user picks a file, attaches metadata, and submits; the
app uploads to Logos Storage, gets back a content identifier (CID),
broadcasts the CID + metadata over Logos Delivery, and either the
publisher or any permissionless third party anchors the CID on-chain via
the `chronicle-registry` SPEL program on LEZ.

The submission includes `logos-chronicle`, a standalone reusable
document-indexing module any Basecamp app can depend on, and
`batch-anchor`, a permissionless CLI that subscribes to the Chronicle
Delivery topic and batch-anchors accumulated CIDs (up to 50 per tx)
without coordination with the original publisher.

## Repository

- **Repo:** https://github.com/Thompsonmina/WhistleBlower-Logos-
- **Demo video:** https://github.com/Thompsonmina/WhistleBlower-Logos-/releases/download/demo-v1/demo.mp4

## Approach

The pipeline splits cleanly into a **publish path** and an **anchor
path**, with one shared on-chain registry.

**Publish path — `logos-chronicle` (Basecamp module).** A Logos Core
module in C++/Qt exposing JSON-in / JSON-out methods. `publishFileJson`
chains: (1) upload to Logos Storage with exponential-backoff retries,
(2) build + sign a metadata envelope (`cid`, `title`, `description`,
`content_type`, `size_bytes`, `timestamp`, optional `tags`,
deterministic `metadata_hash`), (3) broadcast on the Chronicle Waku
topic `/chronicle/1/document-index/json`. Re-broadcasting the same CID
is deduped locally. Optional `anchorBatchJson` /
`anchorStatusJson` / `lookupAnchorJson` for publisher-initiated
on-chain anchoring, wired via a generated FFI cdylib.

**Anchor path — `chronicle-registry` (SPEL program) + `batch-anchor`
(CLI).** The registry is a permissionless PDA at
`[program_id, "registry"]` holding a Borsh `HashMap<CID, CidRecord>`.
Two instructions: `init_registry(anchorer)` and
`index_batch(anchorer, cids, metadata_hashes, anchor_timestamps)` up to
`MAX_BATCH = 50`. Idempotency is in-program (`contains_key`), which is
what lets the permissionless `batch-anchor` CLI replay any batch after
a restart without coordination.

`batch-anchor` is a tokio daemon that seeds an in-memory dedup set from
on-chain state at startup, catches up over Waku's store protocol for
messages broadcast while it was offline, subscribes to the live relay,
and flushes the buffer on either size (50) or time (30 s) — whichever
comes first.

**Why LEZ over zone-SDK.** The zone-SDK path "requires a single designated actor to perform consensus
inscription" concentrating anchor authority and undermining
the censorship-resistance premise of the problem. A SPEL program on LEZ is
permissionless — anyone with a wallet can submit `index_batch`, which
is exactly the property the `batch-anchor` CLI relies on. SPEL also
ships IDL generation, scaffolding, an auto-generated CLI, and the
`#[lez_program]` macro — strictly less code than rolling the inscription
format by hand.

## Success Criteria Checklist

- [x] **Upload**: app uploads to Logos Storage and obtains a CID (chronicle module, `publishFileJson`).
- [x] **Broadcast**: chronicle publishes a versioned metadata envelope on `/chronicle/1/document-index/json` immediately after upload.
- [x] **On-chain anchoring (UI)**: chronicle exposes `anchorBatchJson` / `anchorStatusJson` / `lookupAnchorJson`; whistleblower UI wires a per-row "anchor" button.
- [x] **Batch anchor tool**: `batch-anchor` CLI subscribes to the topic, batches up to 50 CIDs per tx, permissionless, idempotent (in-program `contains_key` + on-chain dedup seed at startup).
- [x] **On-chain registry**: `chronicle-registry` SPEL program on LEZ stores `(CID, metadata_hash, anchor_timestamp)` keyed on CID; queryable via `batch-anchor lookup <cid>`; ≥10 CIDs per tx (50).
- [x] **Document-indexing module**: `logos-chronicle` is a standalone Logos Core module with documented JSON API; any Basecamp app can depend on it.
- [x] **Basecamp app GUI**: `logos-whistleblower` builds via the repo's nix flake and loads into Basecamp.
- [x] **Module SDK README**: `logos-chronicle/README.md` + `logos-chronicle/docs/api.md`.
- [x] **IDL for LEZ program**: `chronicle-registry-idl.json` at repo root; regenerated via `make idl`.
- [x] **Upload retries with exponential backoff**: chronicle storage layer, documented in `logos-chronicle/docs/api.md`.
- [x] **Broadcast dedup**: chronicle keeps a per-CID publish ledger; subscribers (incl. `batch-anchor`) skip duplicates.
- [x] **Batch tool resume after interruption**: seeded from chain at startup + Waku store-protocol catch-up over a configurable lookback window.
- [x] **CU benchmarks (1 + 50 CID)**: documented in `README_CHRONICLE_REGISTRY.md` § Compute units (cold n=1 = 2,240 cycles; cold n=50 = 178,646 cycles).
- [x] **Local LEZ deployment**: chronicle-registry deploys to a local LEZ devnet via `make deploy`; `scripts/setup.sh` does so end-to-end.
- [ ] **E2E integration tests in CI**: IT contract sketched in `integration-test.toml`; chronicle smoke test on the IT topic; that runs against a real local sequencer; `RISC0_DEV_MODE` left unset so the prover runs in production mode CI runner that runs lez and logoscore environment pending.
- [x] **Top-level README** with build, addresses, app, tool, query: `whistleblower/README.md`.
- [x] **Reproducible E2E demo script**: `scripts/run-app.sh` + .
- [x] **Narrated video demo**: linked above;.
- [x] **Dual licensed MIT + Apache-2.0**: `LICENSE-MIT`, `LICENSE-APACHE`.

## FURPS Self-Assessment

### Functionality

Upload → broadcast → optional publisher anchor → batch anchor → on-chain
lookup, end-to-end. Two independent anchor consumers
(`chronicle::anchorBatchJson` for publisher-initiated, `batch-anchor`
for permissionless third-party) sharing one registry program. Borsh
serialisation gives deterministic on-chain bytes (required for risc0
proof determinism). Idempotency is enforced in-program so callers can
replay batches freely.

### Usability

- Whistleblower Basecamp app: file picker + metadata fields + submit; per-row "anchor on-chain" action.
- One-shot evaluator path: `git clone && cd whistleblower && ./scripts/run-app.sh`. Idempotent.
- `logos-chronicle` module: JSON-in / JSON-out methods; SDK README + `docs/api.md`.
- IDL JSON for the LEZ program shipped at repo root.

### Reliability

- Upload: exponential-backoff retry on transient storage failures, structured error after exhaust.
- Broadcast: chronicle keeps a per-CID publish ledger so re-broadcasts are silent no-ops to subscribers.
- Batch anchor: dedup set seeded from on-chain state on every startup (no local-state drift); Waku store-protocol catch-up recovers messages broadcast while the anchor was offline.

### Performance

LP-17 R8 — CU costs instrumented via `risc0_zkvm::guest::env::cycle_count()` around each instruction body, logged to sequencer stdout.

| Instruction | n | Cycles | Cycles / CID |
|------------------|----|---------|--------------|
| `init_registry` | — | 414 | — |
| `index_batch` | 1 | 2,240 | 2,240 |
| `index_batch` | 50 | 178,646 | 3,573 |

Worst-case (n=50 near the 100 KiB account-data cap) is ~288k cycles — well under 1 Mi, ~3 % of the NSSA 32 Mi per-tx budget.

### Supportability

- Top-level + per-component READMEs, with an LP-17 requirement → file map.
- `scripts/setup.sh` (idempotent bootstrap) and `scripts/run-app.sh` (one-shot launcher).
- Project-local `--user-dir` for basecamp means re-runs never touch the user's regular `~/.local/share/Logos`.
- Pending: CI config + automated E2E test in CI.

## Supporting Materials

- Top-level README: https://github.com/Thompsonmina/WhistleBlower-Logos-/blob/master/README.md
- Chronicle-registry deep-dive: https://github.com/Thompsonmina/WhistleBlower-Logos-/blob/master/README_CHRONICLE_REGISTRY.md
- Chronicle module API: https://github.com/Thompsonmina/WhistleBlower-Logos-/blob/master/logos-chronicle/docs/api.md
- Demo script (off-camera reading copy): https://github.com/Thompsonmina/WhistleBlower-Logos-/blob/master/docs/demo-script.md
- Demo video: https://github.com/Thompsonmina/WhistleBlower-Logos-/releases/download/demo-v1/demo.mp4

## Terms & Conditions

By submitting this solution, I confirm that I have read and agree to the [Terms & Conditions](../TERMS.md).
Loading