feat(indexer): BFT multi-node consensus protocol with state roots and gossip (#536)#578
feat(indexer): BFT multi-node consensus protocol with state roots and gossip (#536)#578MarcusDavidG wants to merge 5 commits into
Conversation
…#536) - docs/ADR-003-indexer-consensus.md: evaluates Raft, PBFT/Tendermint and optimistic replication; selects state-root gossip approach given Soroban events are already totally ordered and deterministic - migrations/006_indexer_state.sql: indexer_state(ledger_sequence, state_root) - src/stateRoot.ts: deterministic Merkle state root over posts/follows/ profiles/pools; saveStateRoot persists per ledger; getStateRoot retrieves - src/gossip.ts: HTTP gossip loop broadcasting latest (ledger, state_root) to INDEXER_PEERS; emits DIVERGENCE_DETECTED on mismatch; self-fences (SELF_FENCED) when >= DIVERGENCE_THRESHOLD peers disagree - src/api/routes/stateRoot.ts: GET /api/state-root?ledger=N - src/api/index.ts: mounts state-root route; blocks all /api traffic with 503 SELF_FENCED when node is fenced - src/index.ts: saves state root after each new ledger; starts gossip loop - src/cli/verify-state.ts: re-derives state root and compares to --trusted-root or --peer; exits 1 on mismatch - src/__tests__/stateRoot.test.ts: determinism tests for merkleRoot and computeStateRoot - src/__tests__/gossip.test.ts: divergence detection, self-fencing, and 503 API response tests All 66 tests pass.
|
Solid implementation @MarcusDavidG |
|
cl checks error fixed @devJaja we're good to go |
devJaja
left a comment
There was a problem hiding this comment.
Nice work @MarcusDavidG
The architecture and overall design are correct. The ADR reasoning is sound. The self-fencing mechanism, 503 middleware, and saveStateRoot idempotency are all good. But the reconciliation stub is the one thing that could mislead an operator into thinking their node recovered when it hasn't — that needs to be either implemented or explicitly surfaced as a known limitation with a tracking issue. The md5/sha256 mismatch also needs fixing before the state root can be considered trustworthy for its stated purpose.
Request changes on the reconciliation stub and md5 issue. All other notes are non-blocking.
|
@MarcusDavidG is attempting to deploy a commit to the Jaja's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
thanks @devJaja ...requested changes have been addressed, please review |
Summary
Closes #536
Implements a Byzantine-fault-tolerant multi-node indexer consensus protocol using optimistic replication with cryptographic state roots.
Changes
Phase 1 — ADR
docs/ADR-003-indexer-consensus.md: evaluates Raft, PBFT/Tendermint, and optimistic replication; selects the state-root gossip approach, justified by Soroban events being deterministically totally ordered. Includes CAP trade-off analysis and failure mode coverage table.Phase 2 — Cryptographic State Root
migrations/006_indexer_state.sql:indexer_state(ledger_sequence, state_root)tablesrc/stateRoot.ts: deterministic Merkle tree over sorted row hashes for posts/follows/profiles/pools;computeStateRoot,saveStateRoot,getStateRootsrc/api/routes/stateRoot.ts:GET /api/state-root?ledger=Nsrc/cli/verify-state.ts: re-derives root from DB and compares to--trusted-rootor--peer; exits 1 on mismatchPhase 3 — Gossip & Divergence Detection
src/gossip.ts: HTTP gossip loop broadcasting(ledger, state_root)toINDEXER_PEERS; emitsDIVERGENCE_DETECTEDstructured log; binary-search reconciliation; self-fences withSELF_FENCEDalert when>= DIVERGENCE_THRESHOLDpeers disagreesrc/api/index.ts: 503SELF_FENCEDmiddleware blocks all/apitraffic when fencedsrc/index.ts: saves state root after each new ledger; starts gossip background loopTests
src/__tests__/stateRoot.test.ts: determinism (same data → same root twice), different data → different root,merkleRootedge casessrc/__tests__/gossip.test.ts: divergence detection logsDIVERGENCE_DETECTED, self-fencing setsisFenced()and logsSELF_FENCED, fenced node returns 503Test Results
All 66 tests pass (8 suites).