S08 — Gossip & State Roots
Lazy push/pull protocol for event propagation between nodes.
IHAVE/IWANT
- Node sends IHAVE:
event_ids + state_root_pre + rule_version_hash + fork_id - Receiver validates: rule version matches, state root is continuous from known checkpoint, fork ID matches
- If valid, receiver sends IWANT for events it doesn’t have
- 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 filtern= expected number of unique event IDs per gossip roundp= 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. |