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

3.4 KiB
Raw Blame History

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.