- BLAKE3 keyed proof-of-work on object storage and auth challenges, with frozen vectors cross-checked against an independent Python reference implementing the single-block hash it needs. - Sparse Merkle trie over object IDs: order-independent roots, inclusion and absence proofs (internal/smt). - Signed checkpoint chain per relay: transport key amendment to INV-1, /v1/checkpoint/* and inclusion/absence proof endpoints, restart-safe epoch continuity (internal/checkpoint). - Head gossip with TOFU pinning and equivocation detection; light node (cmd/lightnode) that stores no history: quorum of pinned relays, every served object proven against the agreed root, LRU disk cache. - WebSocket streaming on relay and light node (coder/websocket): scoped channels mirroring REST, raw envelopes verified client-side; light node marks streamed objects unproven until checkpoint coverage. - Protocol v1 additions: DelegationClaim tag 0x07 with deterministic chain resolution in verify.Graph, KeyRotationRequest/Confirm tags 0x08/0x09 with hash-bound two-sided consent and Policy.RotationMaxAge; spec sections, frozen vectors appended byte-identically, Python reference extended. - Optional permissioned BFT finality over gossip (internal/bft): prevote/precommit with quorum certificates verifiable offline. - Quick wins: Policy.TrustedIssuers, per-type stored metrics, batch fetch, lexicographic lists with stable cursor pagination. - Security review of the network layer (docs/SECURITY-REVIEW.md) with findings F-01..F-09; hub send/close race and unstable pagination fixed under review. 12 packages green, vet/gofmt clean, protocol fuzzing stable.
3.4 KiB
BFT finality over checkpoint gossip
Optional permissioned finality layered on the checkpoint chain. Gossip alone detects divergence after the fact; a validator set prevents it from being presented as truth in the first place: a height commits to exactly one head, and everyone can check that commitment offline.
1. Roles
- Validators are relays whose transport key doubles as their validator
key. One key, one role, no new secrets. The set is fixed in configuration
(
-bft-validators,-bft-urls) — membership changes are an operational ceremony, not a protocol event. - Everyone else (relays, light nodes, verifiers) needs only the public validator list to check a certificate.
2. Protocol
Per height h (aligned with checkpoint epochs), deterministic leader:
proposer(h, r) = validators[ SHA-256(height‖round)[0] mod n ]
- The round's proposer offers its latest head.
- Validators prevote for the proposed head (or nothing).
- On a quorum prevote for X, each validator precommits X.
- On a quorum precommit for X the height finalizes with a certificate: the collected precommit signatures. Height advances; the finalized head becomes the anchor every future proposal must chain onto.
Quorum is 2f+1 of n with tolerated Byzantine validators f = ⌊(n−1)/3⌋.
A stalled or equivocating proposer costs one round timeout, then leadership
rotates. All messages are canonical bytes signed with Ed25519; phases live
in the signing domain, so a prevote can never be replayed as a precommit.
3. Guarantees and simplifications
Safety: two certificates for one height require ≥⅓ Byzantine validators. Liveness: finality proceeds while ≥ quorum validators are online and honest; a minority outage stalls that height until they return (fail-stop, never fork).
Documented v1 simplifications, none safety-relevant:
- Single in-flight round per height on the driver; rotation happens through timeouts rather than full Tendermint lock-rules.
- Validators accept a proposal whose head they have already verified via gossip; head-body re-fetch before prevoting is future work.
- Validator-set changes are manual: update config, restart.
4. Endpoints
| Method | Path | Purpose |
|---|---|---|
| POST | /v1/bft/proposal |
validator fan-out: signed proposal |
| POST | /v1/bft/vote |
validator fan-out: signed prevote/precommit |
| GET | /v1/bft/state |
{enabled, height, last_finalized} |
| GET | /v1/bft/certificate/{h} |
finality certificate for a height |
Light nodes pin the validator keys (BFTValidators); /v1/bft/certificate
then serves only certificates that verify against exactly those keys, so a
light node can demand "quorum-agreed root" instead of trusting any single
mirror's checkpoint.
5. Composition
relays ──gossip──▶ heads ──▶ validators vote ──▶ certificate
│
light nodes ◀── verify offline ──────────────┘
Gossip remains the data plane; BFT is a thin consensus overlay on which head counts as canon per height. Disabling it returns the system to plain checkpoint-gossip with split-view detection by comparison.