Rapidblocks, take two: a pipelined consensus for independent blocks

Last year, rapidblocks proposed building blocks that don’t depend on their immediate predecessor. Block i+1 builds on i−1’s state, and respects i’s BMF, a Bloom filter of the keys i modified. A block can then be skipped without a reorg, and slots can get much shorter. That post’s design part ended with a promissory note: “I think we can create a consensus mechanism that is pipelined and can selectively ‘merge’ independent sub-chains into a virtual safe chain horizon.” This post is an attempt to pay it. It is still a discussion starter, but now with a concrete design, a safety sketch, a simulation, a first model check and a mainnet measurement behind it.

The chain: what has to be agreed

A block has two kinds of edges:

  • Hist (state edges): the blocks whose state it executes on;
  • refs (filter edges): the concurrent blocks in a window of L slots whose filters it respects.

State keys are per account field (balance, nonce, code) and per storage slot. A(b) is what block b reads or writes, except balance credits that nothing in b reads, such as fee payments. M(b) is everything b modifies, credits included. A block must be compatible with every earlier block in its window that it doesn’t build on: A(b) ∩ M(c) = ∅.

Given that, the canonical set is a fixed function of one value per slot: for slot j, either a header hash or ⊥. Slots are settled in order. b_j is in iff its slot’s value is b_j, everything in its Hist is in, every block already in from before its window is in its Hist, and it is compatible with the concurrent blocks already in. So earlier slots win conflicts, and only the last L slots are ever open. Everything older is fixed by every canonical block, the way a parent hash fixes the past today: that is the block’s horizon, the “safe chain horizon” of the original post. If b_5 is voted out, b_6, built on b_4 and respecting b_5’s filter, stays; only blocks with b_5 in their Hist go with it. Consensus never has to order blocks, only decide a value per slot.

Each block builds on the slot before last and respects the filter of the last. Round A voted b4 out: only b5 referenced it, through its filter, and no block built on its state, so nothing else was lost. b8 needs two parents because b6 reached b5 only through a ref. Slots 4–7 are b8’s window (L = 4); everything older is its horizon, the same for every canonical block.

The vote

parameter meaning working value
τ slot 2 s
Δ bound on headers, the producer’s view of the votes, and anything an honest node relays τ/4 = 0.5 s
a rounds from the header vote to the body vote 1
m vote cadence: a slot’s follow rounds come every m-th slot 1 (2 if votes are slow)
L window, a + m·(number of follow rounds) 4 (7 at m = 2)
T fast-confirmation threshold, of the committee’s stake 2/3

Every slot, a committee votes once. The vote carries an entry for each slot in the window, and slot j’s entry goes through rounds:

  1. Round 0 (slot j): was the header received by jτ + Δ? Otherwise a header released late could knock out, under earlier-slot-wins, a later honest block whose producer never saw it.
  2. Round A (slot j + a): was the body available and valid, and is the block feasible? That is, by the voter’s own values, is everything in its Hist in, and everything in from before its window in its Hist? And no second timely header is known: an equivocated slot is empty, and producers respect both filters. Otherwise the voter enters ⊥ explicitly.
  3. Follow rounds (every m-th slot after round A): copy the majority of the round m back, ties to ⊥, in the voter’s view merged with the producer’s view of the votes, as in 3SF and RLMD-GHOST. Feasibility is checked here too, so a block that committed to the losing side of a decision is voted out once that decision locks. If the round m back is thin, its view holding less than half as many votes as the fullest recent one, the voter follows the latest earlier round that isn’t, or with none its own observation (the thin-view rule): with late votes, a merged view can hold little more than the voter’s own vote.

Three more rules make this hold up when several decisions are open at once and votes are slow:

  • Own values. Between a slot’s decision rounds, a node’s value for the slot is the entry it cast, or would have cast, in the latest of them. Feasibility, producers and the fork choice all use it. A tally still in progress could change after a feasibility check or a producer has used it, and an adversary whose votes arrive first can steer it.
  • An explicit cadence. Votes slower than the next round’s freeze would make voters fall back to older rounds and interleave two chains of rounds, which an adversary can steer apart. So a slow network is absorbed by the cadence m, with the window grown to keep the same number of follow rounds.
  • Closure. A round’s votes fast-confirm a block only if the blocks of its Hist in the window were confirmed at least m rounds earlier. Otherwise a block built on a decision that isn’t locked yet could collect more than 2/3 from the honest voters who see that decision in, plus adversarial votes, and be voted out once the decision goes the other way, with everything built on it. For honest blocks closure costs nothing when m ≤ a + 1: what they build on was confirmed by their producer’s fix, at least m rounds before their round A.

The slot has 3SF’s four phases. Voters freeze their view and producer s fixes Hist at sτ − Δ; producer s sends its header and its view at sτ; the committee votes at sτ + Δ. A block is fast-confirmed when more than 2/3 of the committee’s stake entered it in one round r, counting only votes received by (r+m)τ − 2Δ, so that, relayed, they are in every honest view by the next freeze, whoever leads it; and subject to closure. Producers put every confirmed block into Hist, along with every block in from before their window. So in the typical case b_j is confirmed 6Δ after its slot starts (3 s), and producer j+2 builds on it while referencing only b_{j+1}: exactly the one-slot pipeline of the original post. The body has until round A, 5Δ = 2.5 s, to propagate and execute. A block that misses it is voted out like a missed slot today, except that nothing built later depends on it. The window L only matters when decisions are slow: a decision must settle by (L+1)τ − Δ = 9.5 s after its slot starts, when producer j+L+1 has to commit to it.

b_j is confirmed 3 s after its slot starts, and producer j+2 builds on it at 3.5 s. Only b_{j+1} is concurrent with it: the original post’s pipeline. The follow rounds and the 9.5 s deadline matter only when round A splits, which takes an adversarial producer of slot j, or asynchrony.

Inside the window, votes are counted per slot, not by GHOST over prefixes. b_6 doesn’t depend on b_5, so it shouldn’t lose weight over an unrelated disagreement about b_5. Independence is the point. Dependencies are handled by the feasibility check, not by vote weight. Finality is FFG over the confirmed prefix, 3SF-style, carried in the same vote (open question 4).

Properties, and the number that matters

The safety sketch argues the following under its assumptions: synchrony (headers, the producer’s view and anything an honest node relays within Δ; votes within ℓ, below), an honest majority of the voting stake in each round, honest votes in every round at least half of all votes in any recent round (the thin-view rule’s assumption), no vote equivocation, honest bodies executed before their round-A vote, and m ≤ a + 1. If, in addition, every decision settles by its deadline:

  • honest blocks are never dropped (but see the known gap below), and no proposer boost is needed, since honest blocks never compete;
  • a fast confirmation implies a lock that no later round undoes.

A known gap. Feasibility checks a block’s Hist, while the canonical set also requires compatibility with the concurrent blocks that are in. A block that conflicts with an earlier block it doesn’t reference can therefore be voted in and fast-confirmed while the canonical set leaves it out, and honest blocks that took it into Hist are dropped with it. One adversarial producer suffices. The fix I’m checking: feasibility also checks compatibility, against the voter’s own values, and closure also waits until every conflicting slot in the window is confirmed out.

For a block whose own commitments are settled, its decision misses the deadline only if the slot’s own producer split it and the adversary led every follow round in the window (the producer is the view-merge leader); a block that committed to a decision still open locks only after that decision does. With adversarial stake share β and independent, stake-proportional leader selection, a missed deadline has probability at most β^(1+⌊(L−a)/m⌋) per slot: 1.6·10⁻³ at β = 0.2 and L = 4, about one every 20 minutes at τ = 2 s against an adversary that attacks every slot it produces. Then the blocks that committed to the losing side are lost, honest ones included: in simulation, about one honest block per missed deadline, with no cascades. Those blocks committed after the deadline, outside their window, where closure doesn’t reach, so whether an adversary could get one of them confirmed and built on is open (below).

All of this needs vote latency ℓ ≤ mτ − 2Δ: 1.0 s at m = 1, 3.0 s at m = 2. Fast confirmation itself needs ℓ ≤ mτ − 3Δ, 0.5 s at m = 1 and 2.5 s at m = 2. While it works, ⌈(ℓ + 2Δ)/τ⌉ slots are concurrent: at m = 2, one up to ℓ = 1.0 s and two up to 2.5 s. Between the two bounds (0.5–1.0 s at m = 1, 2.5–3.0 s at m = 2) the design is still safe, but confirmations can stop and concurrency can grow to the whole window. In simulation the transition at the safety bound is sharp: at m = 2, a lock-undoing adversary took no honest blocks just inside it and 42% just outside. So the real question is networking: how fast can aggregated votes reach everyone? Within 0.5 s, m = 1 gives the one-slot pipeline. If it takes up to about 2.5 s, the design still works at m = 2 with L = 7, with one or two concurrent slots.

Split attack at β = 0.3, two runs of 6,000 slots each, with own values and closure. Each bar is when a round’s votes arrive: the extra lag, plus network delay up to Δ. Inside ℓ ≤ mτ − 2Δ the lock-undoing adversary gains nothing; just past it, it undoes locks (42% of honest blocks at m = 2); past mτ − Δ, most honest blocks are lost.

How it is checked

  • Simulation. An event-level simulator runs the rules against adversarial producers, leaders and voters: split decisions, late headers, withheld bodies, withheld and mistimed votes, and blocks built on decisions still open. With 30% adversarial stake, building on open decisions costs only what a plain split costs, 0.75% of honest blocks at m = 1 and 0.41% at m = 2, with no wrong confirmations. Without own values and closure it cost 4.8% and 28%. And at m = 2 with 0.9 s of extra vote lag, reading tallies still in progress let fast adversarial votes mislead producers into dropping 83% of honest blocks; with own values, none.
  • Model check. A small Quint model, checked with Apalache, explores every run of a small instance: three honest validators and one adversarial, two slots, four rounds (five at m = 2), with every delay and adversary choice within the sketch’s bounds. With own values and closure, all five checked properties hold at m = 1: agreement, confirmation implies a lock, locks persist, honest blocks stay in, no cascades. The m = 2 check is still running. Without the two rules, it finds by itself the case each rule prevents. At m = 1, in 11 minutes, a block confirmed and then voted out (closure). At m = 2, in 78 minutes, a confirmed block that an honest voter then votes against, because its feasibility check read a tally still in progress (own values). In a scripted run, a withholding leader undoes a lock at ℓ = 3Δ but not at 2Δ, the bound at m = 1. The model has no sleeping validators, no equivocation, no refs or filters, and no slots older than the window, so it checks the sketch’s lemmas on small instances, not the whole design.

Not covered yet: the known gap above, until its fix is checked; vote equivocation (the sketch, the simulation and the model all exclude it); a block that commits to a decision still open after its deadline, outside its window (closure covers the window only); recovery after asynchrony; and adaptive corruption.

Does mainnet traffic take the fast path?

I traced 501 consecutive mainnet blocks (12 October 2026, about 100 minutes) and cut each into six 2-second slices of equal gas. A transaction is blocked if it touches a key that the previous slice modified.

  • 87% of transactions and 69% of gas take the fast path. Between the method’s upper and lower bounds on conflicts, it is 83–90% and 59–74%. With four concurrent slots, the worst case at L = 4, it is still 78% of transactions.
  • Most blocked transactions wait a slot or two. Deferring each to the next slot where it fits adds 0.19–0.34 slots (0.4–0.7 s) on average over all transactions. Of the blocked ones, half to three quarters wait a single slot and 18–29% three or more; on average they wait about two.
  • The credit rule is essential. If fee credits counted as reads, only 9% would pass, because every transaction credits the fee recipient.
  • Conflicts must be per storage slot. USDT and USDC are modified in 98% of slices, so per-contract conflicts would block most traffic.
  • A 1 KB filter is enough for this sample. A slice modifies 244 keys at the median and 865 at most, and at one concurrent slot the filter’s false positives cost 0.1 points (86.9% → 86.8%). It has little headroom: against a 1,000-key slice, even a 1 KB filter tuned for 1,000 keys would wrongly block 18% of transactions that touch 10 keys (the measured filter, tuned for the 90th-percentile slice, about half), and false positives compound over the filters of several concurrent slots.

Share of transactions (left) and gas (right) on the fast path, against the number of concurrent slots c. “Field keys” is the estimate; “account keys” and “field keys, min” bound it, with more and fewer conflicts.

Caveats: builders order by fee and MEV, so the slices aren’t the blocks a rapidblocks chain would see; all six slices of a block share one builder; and traffic tuned to 12 s blocks would adapt.

Relation to decoupled consensus

The closest recent design is @fradamt’s decoupled consensus. There, a small sampled committee runs a Goldfish-style available chain in the critical path, while the full validator set runs finality and a stabilization gadget in parallel. The window vote is the same kind of protocol with a different object of agreement. It shares the four-phase slot, view merge and Goldfish’s pattern of vote expiry (one round back, at cadence m, with the thin-view fallback), and its threshold rule matches that post’s: e ≤ (2T−1)·|C| gives its 1/2 at T = 3/4 (open question 2). The main difference is that it decides one value per slot rather than a chain head. That is what lets independent blocks be skipped without reorgs, and also why fast confirmation needs closure: several decisions are open at once. Two more differences: it asks two questions per block, timeliness at Δ and validity a slot later, which gives the body 5Δ; and its thin-view rule needs participation to stay stable within the window, a weaker guarantee than Goldfish’s in the sleepy model. And as written, its finality is 3SF-style FFG inside the same committee vote, which puts it on exactly the trade-off that post dissolves.

I think the two fit together. The window vote could be the top pipeline of a decoupled design, run by a small committee, which also makes aggregation within about 1 s far more plausible. And like Goldfish, it is brittle under asynchrony. A stabilization gadget on the horizon checkpoints might bound the part that is vulnerable; whether it keeps that part within the window, and preserves the window vote’s guarantees, I haven’t checked.

Open questions

  1. Vote aggregation within about 0.5–1 s (m = 1) or about 2.5 s (m = 2) to every validator, with headers, the producer’s view and relays within Δ = 0.5 s. This decides everything else.
  2. The threshold. Without equivocation, any threshold above 1/2 is safe. With it, and nodes discarding both votes of a known equivocator, a confirmation is safe iff the equivocating stake e ≤ (2T−1)·|C|, with |C| the committee’s stake: e ≤ |C|/3 at T = 2/3. A lower threshold keeps fast confirmation alive at low participation: in simulation, with 64% of the stake honest and awake, T = 0.55 kept 99.7% of producers building on the block two slots back, against about 16% at 2/3, but it tolerates only 10% equivocating stake. Could equivocation be bounded some other way?
  3. Committees. A small committee sampled anew each round needs an honest majority in each round. With equivocation, T = 3/4 tolerates any committee adversary below 1/2, as in decoupled consensus; 2/3 needs it below 1/3, which small committees make fragile (by binomial tails, β ≲ 0.2 with committees of at least 256). Do the window vote’s guarantees survive a fresh committee every round?
  4. Finality and stabilization. What should the full set vote on? The horizon checkpoints form a chain of prefixes, so a Majorum-style stabilization rule looks like a candidate.
  5. EVM details. The exact conditions for a credit to be read-free (account existence), and the system-contract queues.

Comments, holes and counterexamples very welcome, above all on own values and closure, the newest and least reviewed part of the design.