← docs

M0 — block reader, schema, reorg rollback

Status: complete. 18 tests passing.

What was built

Module Purpose
ribbit/config.py Chain params for main/test/regtest; RPC credential loading (conf, then cookie)
ribbit/rpc.py JSON-RPC client with batching, session reuse, id-based result reordering
ribbit/db.py SQLite schema, WAL, and the undo journalStateDB records a reversal for every mutation
ribbit/chain.py ChainFollower — connects blocks, detects forks, rolls back reorgs
ribbit/zmq_listener.py ZMQ subscriber for hashblock/rawblock/rawtx, with gap detection
ribbit/regtest.py Throwaway regtest node, run as the current user, cookie auth, no root

Design decisions made during M0

  1. Mutations are illegal outside a block context. A mutation with no height cannot be rolled back, so it would survive a reorg and corrupt state silently. StateDB raises rather than allowing it.
  2. Tables must be explicitly registered for journalling. An unregistered table cannot be mutated through StateDB. This makes adding protocol state in M2 a conscious act rather than something that quietly escapes the journal.
  3. PRAGMA synchronous=FULL, not NORMAL. A torn write after a crash means silently wrong protocol state, which is far worse than a slower indexer.
  4. Reorgs are fully resolved before any new block is connected, so the database is never a mixture of two chains.
  5. max_reorg_depth (default 500) raises rather than unwinding forever. A disagreement that deep means a wrong network, a corrupt database, or something genuinely catastrophic — all three deserve a human, not a retry loop.
  6. ZMQ is a wake-up, never a source of truth. Pepecoin v1.1.0 has no zmqpubsequence (Bitcoin 0.19+), so ZMQ cannot report a disconnected block. Reorg detection stays with ChainFollower, comparing hashes over RPC.

Tests

File Covers
tests/test_undo.py (9) insert/update/delete reversal, reverse-order replay, multi-block rollback, atomic failure, misuse guards
tests/test_chain.py (6) connect from activation, idempotency, batching limit, a real reorg on a live node, journal hygiene, depth limit
tests/test_zmq.py (3) hashblock delivery, rawblock body, sequence monotonicity

The reorg test is deliberately run against a real pepecoind, not a mock: it mines 20 blocks, invalidateblocks three below the tip, mines a longer competing chain, re-syncs, and asserts that state from the orphaned blocks is gone — not merely superseded — and that every height we hold matches the node.

Known gaps, carried into M1