S08 — Gossip & State Roots

Lazy push/pull protocol for event propagation between nodes.

IHAVE/IWANT

  1. Node sends IHAVE: event_ids + state_root_pre + rule_version_hash + fork_id
  2. Receiver validates: rule version matches, state root is continuous from known checkpoint, fork ID matches
  3. If valid, receiver sends IWANT for events it doesn’t have
  4. Sender delivers requested events

Mismatch on any of the three validation checks → reject entire gossip batch.

Triple-Anchor validation

Every IHAVE message is validated with three independent checks before any events are requested:

Anchor What is checked Failure consequence
rule_version_hash Hash of the sender’s active rule set must match the receiver’s Entire gossip batch rejected; receiver may trigger fork if rule divergence is persistent
state_root continuity The sender’s state_root_pre must be reachable from the receiver’s last known checkpoint (chain of verified state roots, no gaps > 1 epoch) Batch rejected; receiver requests a full checkpoint sync instead
fork_id Both nodes must be operating on the same fork (identical fork_id) Batch rejected; sender is on a different fork; events are not shared across fork boundaries

All three anchors must pass for IWANT to be issued. A single failure causes the entire batch to be discarded — partial acceptance would allow inconsistent state to enter the local event log.

Deduplication

Bloom filter per gossip round. Prevents requesting events already in local storage. False positive rate tuned to <1%.

Bloom filter algorithm

A Bloom filter is a probabilistic data structure that answers “have I seen this event ID before?” in O(1) time without storing the actual event IDs.

Filter sizing formula:

m = -n * ln(p) / (ln(2))^2

Where:

  • m = number of bits in the filter
  • n = expected number of unique event IDs per gossip round
  • p = target false positive rate (0.01 = 1%)

For a typical round of n = 1000 events at p = 0.01:

m = -1000 * ln(0.01) / (ln(2))^2  ≈  9585 bits  (~1.2 KB)

Number of hash functions:

k = (m / n) * ln(2)  ≈  7 hash functions

Insertion: Hash the event ID with k independent hash functions; set k bits.
Query: Check all k bit positions; if any is 0, the event is definitely new.
False positives: All k bits set by coincidence (different event IDs); rate ≤ p when filter is not over-full.

Each gossip round allocates a fresh filter. Filters are not persisted — they exist only for the duration of a single IHAVE exchange.

Adaptive fanout

  • Well-connected nodes gossip to fewer peers
  • Isolated nodes gossip more aggressively
  • Fanout adjusts based on network topology and propagation delay metrics

Adaptive fanout formula:

fanout = max(3, min(10, 15 - connectivity_score))

Where connectivity_score is the number of live peers in the node’s routing table, clamped to [0, 12].

connectivity_score fanout
0 (isolated) 10
3 10
5 10
7 8
10 5
12 3 (minimum)

The minimum fanout of 3 ensures gossip always propagates even in well-connected topologies. The maximum of 10 bounds bandwidth on isolated nodes. connectivity_score is recomputed every 5 epochs based on successful IHAVE/IWANT exchanges.

Signed Time Anchors (STA)

High-reputation arbiters broadcast (timestamp, epoch, signature) periodically. Nodes compute: peer_time = STA_median + local_offset. If node drift >30s from STA median, its proposals are deprioritized.

Fork Transition Events

EVT-FORK-TRANSITION contains: source fork_id, target fork_id, divergence point, transition path, reason code, Merkle proof from common ancestor. Both forks must share a genesis_id — no cross-genesis jumps.


Implementation Status

Verified against source: 2026-04-06

Claim Status Notes
IHAVE/IWANT lazy push/pull protocol Spec-only No gossip protocol code in src/. Roadmap item exists at data/roadmaps/peer-to-peer/content/todo@gossip-sync-liveness.md.
Bloom filter deduplication Spec-only No bloom filter implementation found in source.
Adaptive fanout Spec-only No fanout or topology-aware propagation logic in source.
Signed Time Anchors (STA) Spec-only No STA broadcast or time-drift deprioritization in source.
Fork Transition Events (EVT-FORK-TRANSITION) Spec-only No fork transition event type or cross-fork Merkle proof logic in source.

Back to top

Colibri — documentation-first MCP runtime. Apache 2.0 + Commons Clause.

This site uses Just the Docs, a documentation theme for Jekyll.