- 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.
78 lines
3.4 KiB
Markdown
78 lines
3.4 KiB
Markdown
# 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 ]
|
||
```
|
||
|
||
1. The round's proposer offers its latest head.
|
||
2. Validators **prevote** for the proposed head (or nothing).
|
||
3. On a quorum prevote for X, each validator **precommits** X.
|
||
4. 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.
|