Phase 19b: Governance & BFT

Status: HARDENED 2026-09-20 — the initial PBFT review found safety and liveness gaps (see "Review findings fixed" below); this is the protocol as now implemented, with signed vote certificates, all-to-all vote relay, sealed-batch verification, buffered commits, view change, and cluster policy.

Deployment policy

Nodes Mode Quorum Behavior
1 Single-server 1 Governance works locally; server signs its own votes; seals execute immediately
2–3 Refused — No BFT possible (needs 3f+1=4); propose returns None with a logged reason
4 BFT (f=1) 3 Minimum viable
5+ BFT (f=1+) 2f+1 5 recommended operationally (f=1 + one crash for liveness)

Review findings fixed (2026-09-20 hardening)

Castro-Liskov conformance

Mechanism Status Notes
Pre-prepare (leader proposal, view+seq) ✅ Leader-checked, fork-checked
Prepare phase, 2f+1 quorum ✅ Signature + digest bound
Commit phase, 2f+1 quorum ✅ Buffered early votes
Sealed execution, deterministic order ✅ Only after certificates
Signed messages (per-member keys) ✅ Ed25519, verify_strict
View change + new-view ✅ Simplified: highest-prepared certificate transfer
Checkpoints / log GC ◐ Retention-window pruning; no stable-checkpoint protocol
Client request authentication ✅ Admin-gated propose; votes server-to-server only
State transfer for lagging replicas ◐ Sealed-batch ingestion; no bulk catch-up
Watermarks on sequence numbers ◐ Implicit via prepared watermark

Test coverage

Bugs the harness caught (2026-09-20, all fixed)

  1. Early prepare votes were dropped — a replica whose pre-prepare was delayed lost early prepare votes and stalled at quorum-1 forever under simple message reordering. Now buffered and replayed on round creation (mirrors the buffered-commit fix).
  2. Commit votes were broadcast but never self-counted — the emitter's own round missed its own vote; rounds stalled at commit-quorum-1 on the origin node.
  3. The NewView assembler never applied its own NewView — the new leader broadcast the view change but stayed in the old view.
  4. Digest covered the proposal envelope (view/proposer/timestamp) — re-proposing the same value in a new view changed the digest, breaking prepared-certificate carry-over. Digests now bind only (sequence, transactions), matching PBFT's request digest.
  5. Cluster size not synced in view-change paths — quorum computed from the default cluster_size 1 on fresh nodes.
  6. View-change election had no timeout (review finding #2) — a wedged election (new leader also down) never retried. Stall detection now covers: stalled rounds, view-changes-in-flight without a NewView, and entered-view-without-a-proposal; targets escalate only after a full timeout collecting (no scattering).
  7. NewView verification gaps (review finding #4) — assembler must be the leader of the announced view with a valid signature; certificates must target exactly that view with distinct senders.

PBFT/BFT testing tooling survey (2026-09-20)

Performance envelope (3–5 nodes)

Governance ops are rare (admissions, key rotations, royalties): a round costs 1 pre-prepare + (n−1) prepares + n commits ≈ 3n frames, each ~200 bytes + one Ed25519 signature (~50µs sign, ~80µs verify). Verification of a sealed batch (2 × 2f+1 sigs) ≈ 0.5ms. The timeout poll runs every 5s per connection; negligible. Single pending round at a time — pipelining deliberately omitted (governance tx volume does not justify it; revisit if royalty recording becomes high-volume).

Wire Operations (0x1Bxx range)

Opcode Operation Auth Required
0x1B01 GovernancePropose Admin
0x1B02 GovernancePrepare (casts SELF vote) Login
0x1B03 GovernanceCommit (casts SELF vote) Login
0x1B04 GovernanceSeal Admin
0x1B05 GovernanceLog Login
0x1B06 GovernanceStatus Login

Server-to-Server Federation Frames

Frame Purpose
GovernancePrePrepare Leader proposes a governance batch
GovernancePrepareVote Signed prepare vote (broadcast all-to-all)
GovernanceCommitVote Signed commit vote (broadcast all-to-all)
GovernanceSealed Sealed batch + certificates (broadcast on seal)
GovernanceViewChange Signed view-change with prepared certificate
GovernanceNewView Leader's 2f+1 view-change assembly

Governance Transactions

Admit / Expel / KeyRegister / RoyaltyRecord (unchanged from the original design — see git history for details).

Key Types

Follow-ups closed (2026-09-20, second hardening round)

  1. ✅ State transfer: GovernanceLogRequest/Result frames — a lagging replica requests the sealed tail, each batch is certificate-verified and executed in order; a pruned-past gap is detected and refused loudly (full rejoin required). Mesh test covers catch-up + no-fork-via-transfer + gap refusal.
  2. ✅ Randomized mesh fuzz: 25-seed delivery-order shuffling (every message arrives, in randomized order) — liveness (always seals) + safety (identical digests, no fork). This is the ordering class that hid three real bugs; Shuttle-style thread randomization doesn't apply to the single-threaded event mesh, so event-order randomization is the tool (18/18 mesh scenarios stable).
  3. ✅ deny.toml licenses: proper OSS allow-list; the gate caught a REAL issue — epub-2.x is GPL-3.0 and was linked into the Apache-2.0 server. EPUB import is now isolated behind the non-default epub-import feature (operators opting in accept GPL terms for their build); core/server builds are GPL-free and any new GPL dependency fails the gate. NCSA (libfuzzer) and CDLA-Permissive-2.0 (webpki-roots) allow-listed as permissive.
  4. ✅ Transport DOS: per-IP federation connection cap (8 live sockets) enforced at the federation ws entry, slot released on close; unattributable connections uncapped; capped refusals logged as SECURITY events.
  5. ✅ TLA+ safety spec (spec/xudanu-pbft/): formal model of the quorum mechanics (signed digest-bound votes, one byzantine node with unrestricted equivocation, arbitrary message reordering). TLC-checked at N=4/Q=3/2 digests/1 sequence: 337,761 states, no violations of Agreement, TypeOK, or Validity — the protocol cannot fork. Single-sequence scope: the cross-sequence fork protection (prepared digests) is enforced in code and covered by mesh tests, not re-proven here.
  6. cargo-audit clean (6 allowed unmaintained-crate warnings, pre-existing transitive deps).

Remaining gaps

  1. Full stable-checkpoint protocol (sequence watermarks beyond the retention prune) if governance volume ever grows.
  2. Client retry semantics: unprepared requests lost on view change are the client's responsibility to resubmit (mesh tests model this); a durable client-side retry queue would smooth it.
  3. Multi-sequence TLA+ model (state-explosion-bound; needs symmetry reduction or abstraction refinement to check S={1,2}).