niko_trust/docs/BFT.md
Niko Marmeladkov 20cc52c3a5 feat: network layer — PoW, checkpoint chain, gossip, light node, WS, delegation, rotation, BFT
- 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.
2026-08-25 20:38:40 +03:00

78 lines
3.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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 = ⌊(n1)/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.