← Bitcoin Core v31

BitDevs Perth · Worked Example

One Cluster, Three Approaches

A step-by-step walkthrough of 8 transactions through the old mempool, cluster mempool with CSS, and cluster mempool with SFL — showing where the approaches align and where their policy/computation behavior differs.

1
Meet the Cluster

Here are 8 unconfirmed transactions that form a single connected cluster. The sizes and fees are intentionally stylized to make the policy differences easy to see.

Presenter takeaway: Start by grounding the audience in the graph and the totals: 8 txs, 21,550 vB, 33,400 sats.

TxFee (sats)Size (vB)Feerate (s/vB)Spends fromRole
A5002502.0Root parent, low fee
B4002002.0Independent root
C6,00020030.0AHigh-fee child of A
D10,00020050.0AVery high-fee child of A
E20010,0000.02AHuge low-fee child (bloat)
F30010,0000.03EAnother huge low-fee tx
G15,00020075.0B, DPremium tx, spends B and D
H1,0005002.0CModest child of C
Transaction dependency graph
A 500 sats · 250 vB 2.0 s/vB B 400 sats · 200 vB 2.0 s/vB C 6,000 sats · 200 vB 30.0 s/vB E 200 sats · 10,000 vB 0.02 s/vB D 10,000 sats · 200 vB 50.0 s/vB G 15,000 sats · 200 vB 75.0 s/vB H 1,000 sats · 500 vB 2.0 s/vB F 300 sats · 10,000 vB 0.03 s/vB ← E + F: 20,000 vB of bloat at ~0.025 sat/vB average Value path: A → D → G (+B → G) 25,900 sats / 850 vB = 30.5 s/vB combined This is the most profitable set for a miner KEY Normal tx Bloat tx Premium tx Dependency Bloat dependency
The scenario

Transaction G is a premium 75 sat/vB tx, but it depends on two parents — B (independent root) and D (which depends on A). Meanwhile, someone has attached massive low-fee txs E and F as children of A, dragging down A's descendant feerate. This is a realistic pattern: a value path (A→D→G) polluted by a bloat path (A→E→F). How does each approach handle it?

Total cluster: 8 txs, 21,550 vB, 33,400 sats. Let's assume there's only space for about 1,250 vB in the next block (to force interesting choices). Which transactions get included?

2
Old Mempool: Ancestor & Descendant Feerate

The pre-v31 mempool uses two separate orderings. Let's compute both and see where they diverge.

Presenter takeaway: Mining and eviction both look reasonable locally, but they optimize different metrics and can send conflicting signals.

Ancestor feerate computation
3
Cluster Mempool with CSS (Candidate-Set Search)

Now let's see what cluster mempool does. First, it identifies the connected component as a single cluster and attempts to find the optimal linearization using the CSS/LIMO algorithm.

Presenter takeaway: CSS can find the right ordering here, but does so with search that can become expensive on harder clusters.

Cluster identification
4
Cluster Mempool with SFL (Spanning-Forest Linearization)

SFL starts from a different place. Instead of searching through candidate subsets, it maintains a spanning forest of active dependency edges and iteratively merges or splits chunks.

Presenter takeaway: SFL reaches the same ordering here via local updates, which is why it scales better as clusters evolve.

SFL: Initial state — every tx is its own chunk
5
Side-by-Side Verdict

Given a block with only ~1,250 vB of space, all three approaches include the same template here; the differences are in ranking coherence and computation:

Presenter takeaway: In this toy case, throughput is equal (31,900 sats), but cluster mempool provides one consistent policy view for mining and eviction.

OLD MEMPOOL

Mines (anc FR): G+B+D+A, then C
Evicts first: E (which also removes F)
Evict order: E+F, then recompute
Problem: dual metrics can
send mixed signals
Template (1250 vB):
G+B+D+A 850 vB
+ C 1050 vB
+ H not possible (would exceed 1250 vB)
Revenue: ~31,900 sats
Missed: single coherent ranking

CSS LINEARIZATION

Finds chunk 1: {A,B,D,G}
Chunk 1 FR: 30.5 s/vB
Finds chunk 2: {C}
Chunk 2 FR: 30.0 s/vB
Search work: moderate
Template (1250 vB):
Chunk 1: A,B,D,G 850 vB
Chunk 2: C 1050 vB
Chunk 3: H not included (size limit)
Revenue: ~31,900 sats
Result: Optimal under 1,250 vB cap

SFL LINEARIZATION

Finds chunk 1: {A,B,D,G}
Chunk 1 FR: 30.5 s/vB
Finds chunk 2: {C}
Chunk 2 FR: 30.0 s/vB
Merge/split ops: ~6 steps
Template (1250 vB):
Chunk 1: A,B,D,G 850 vB
Chunk 2: C 1050 vB
Chunk 3: H not included (size limit)
Revenue: ~31,900 sats
Result: Optimal under 1,250 vB cap
Old mempool tension

The old mempool's eviction logic scores A using all descendants, including 20kvB of low-fee bloat (E+F): (500+6000+10000+200+300+15000+1000) / (250+200+200+10000+10000+200+500) = 1.55 sat/vB. In this exact graph, eviction still removes E+F first (0.025 sat/vB), which is sensible. But the key issue remains: mining and eviction evaluate value differently, so transaction importance can look contradictory depending on direction.

CSS — correct but costly in hard cases

CSS finds the same optimal answer as SFL for this cluster. The difference shows up in the computational path. CSS's branch-and-bound search explores candidate subsets exponentially. For this 8-tx cluster it's fine — but with clusters up to 64 txs, especially those with many cross-dependencies, CSS can hit its iteration limit and return a suboptimal linearization. In 2023 simulations, some clusters caused 9ms of CPU per incoming transaction.

SFL — correct and graceful

SFL arrives at the optimal answer through a series of simple, local merge/split operations on the spanning forest. Each step is O(cluster-size) work. It's incremental: if a new transaction arrives and changes the cluster, SFL starts from the previous (nearly-optimal) state and typically needs only a few operations to re-optimise. CSS would need to re-search from scratch. This is why SFL is replacing CSS in PR #32545.

The optimal chunking for this cluster

Chunk 1: A + B + D + G → 850 vB, 25,900 sats = 30.5 s/vB
Chunk 2: C → 200 vB, 6,000 sats = 30.0 s/vB
Chunk 3: H → 500 vB, 1,000 sats = 2.0 s/vB
Chunk 4: E + F → 20,000 vB, 500 sats = 0.025 s/vB
Monotonically decreasing feerate ✓ — low-fee bloat ends up in the final chunk