Skip to content

The Serialization Ceiling

The overview framed the book’s one question: how do you build a single global state machine that runs at hardware speed without falling apart? Before we can talk about Solana’s answer, we have to be precise about the problem. Bitcoin does roughly seven transactions per second. Ethereum’s base layer does a few dozen. These are not the numbers of chains that are badly written — Bitcoin Core and the Ethereum clients are some of the most carefully engineered software on Earth. The slowness is chosen. It falls straight out of a single safe default that almost every blockchain reaches for.

This page names that default and shows why it caps throughput. We’ll call the cap the serialization ceiling. Everything the rest of the book builds — the clock, the account model, the parallel scheduler — exists to remove it.

A blockchain is a state machine. There is one global state — every account balance, every piece of contract storage — and transactions are functions that read some of that state and write some of it back. Run a transaction and the state moves from one valid snapshot to the next. Every node in the network must land on the exact same final state, or the network has forked and the whole point is lost.

Now ask the question that decides everything: can you run two transactions at the same time?

Sometimes, obviously, yes. If Alice pays Bob and, on the other side of the world, Carol pays Dave, those two transfers touch four completely separate accounts. Their order does not matter and they could run on two different CPU cores simultaneously. No conflict, no problem.

But sometimes, just as obviously, no. If two transactions both spend from Alice’s account, the order is everything:

start: Alice = 100
tx1: Alice pays Bob 80 tx2: Alice pays Carol 50
run tx1 then tx2: after tx1 Alice=20 → tx2 needs 50 → FAILS final: Alice=20, Bob=80
run tx2 then tx1: after tx2 Alice=50 → tx1 needs 80 → FAILS final: Alice=50, Carol=50
run BOTH at once: both read Alice=100, both think they can pay → Alice= -30 ← double-spend

The last line is the disaster. Two transactions that both read Alice = 100 before either writes will both believe the money is there. That is a race condition — the classic shared-mutable-state bug — and on a blockchain it is a double-spend: money created from nothing. Every node that scheduled the two transactions in a slightly different order would also compute a different final balance, so the network can’t even agree on what happened.

So the rule is simple and hard: two transactions can run in parallel only if they touch disjoint state. Overlapping state forces an order.

Why “just run them serially” wins by default

Section titled “Why “just run them serially” wins by default”

Here is the pivotal detail, and it is the whole reason the ceiling exists.

On most chains you cannot tell, before running a transaction, which state it will touch. On Ethereum a transaction is a call into a smart contract. That contract can read another contract’s storage, which can call a third contract, which can decide — at runtime, based on the current state — to write to an account nobody named in the original transaction. The set of accounts a call reads and writes (its state footprint) is only fully known after you execute it.

That leaves a chain designer with two options:

  1. Run transactions in parallel and hope none collide. But you can’t know they don’t collide until you’ve already run them. If two happen to touch the same account, you’ve corrupted state or have to detect the conflict, throw the work away, and redo it in order. In the worst case you’ve built a slower system with a correctness hazard bolted on.
  2. Run them one at a time, in a fixed order. Boring. Uses one CPU core out of the sixty-four the machine has. But it is unconditionally correct: a single well-defined order means every node computes the identical final state, every time, with zero coordination about who touched what.

Faced with “provably correct and simple” versus “maybe faster but possibly wrong,” a system securing billions of dollars picks correct. Serial execution is the conservative default, and it is the right call given the constraint. Low throughput is the price of that default, not a defect in the code.

The footprint problem, in one line:
unknown state footprint ──► can't prove two txs are disjoint
──► the only safe schedule is "one at a time"
──► throughput is capped at one core's worth of execution

That cap — one-transaction-at-a-time because the footprint is unknown until runtime — is the serialization ceiling.

Under the hood — where Bitcoin’s ~7 and Ethereum’s ~15–30 come from

Section titled “Under the hood — where Bitcoin’s ~7 and Ethereum’s ~15–30 come from”

The two base layers hit the ceiling for related but different reasons, and it’s worth seeing that the number is a budget, not a speed limit of the hardware.

Bitcoin produces a block roughly every ten minutes (a difficulty-adjusted target, not a fixed clock) and caps each block’s size (~1 MB of base data, up to ~4 MB weight with SegWit). A simple payment is a few hundred bytes. Divide the byte budget per block by the bytes per transaction, divide again by ~600 seconds, and you land near seven transactions per second. The limit is a deliberately small, fixed blockspace budget per unit time — kept small so a hobbyist on cheap hardware can still verify the whole chain.

Ethereum replaces “bytes per block” with a gas limit per block: every operation a transaction performs costs gas, and a block can only spend so much (~30 million gas as of ~2024, targeting ~15 million). A plain transfer costs 21,000 gas, so a block holds on the order of a thousand of them; at a ~12-second block time that’s on the order of tens of transfers per second (real-world blocks carry a mix of heavier operations, so the practical figure lands lower, in the ~15–30 range). But note why the gas limit stays where it is — push it higher and blocks take longer to execute and propagate, and because execution is serial, that execution time is a hard wall. Ethereum can’t just parallelize its way to a bigger budget, because — as we just saw — it can’t know transaction footprints ahead of time. The serialization ceiling is baked into how high the gas limit can safely go.

Two chains, two budgets (bytes, gas), one underlying reason the budget stays modest: keep verification cheap, and — for Ethereum especially — keep the serial execution stage from becoming the bottleneck.

The second, separate bottleneck: agreeing on order

Section titled “The second, separate bottleneck: agreeing on order”

Suppose you did solve execution — you found a way to run every transaction in parallel with no correctness risk. You would still not have a fast blockchain, because execution is only half the job. The other half is that thousands of independent, mutually-distrusting validators must agree on the order transactions happened in the first place. And ordering is its own bottleneck.

Why is agreeing on order hard? Because there is no trusted global clock. Two validators on opposite sides of the planet each receive transactions in a slightly different order thanks to network latency. Before they can execute anything, they have to reconcile those views into one canonical sequence that everyone accepts — and none of them trusts the others’ claim about “what time it is” or “what came first.” Traditionally that reconciliation is done with rounds of messaging: proposers broadcast blocks, validators vote, votes are gathered, a fork-choice rule breaks ties. Every round is a network round-trip, and round-trips across the globe cost real milliseconds that multiply as the validator set grows.

Two independent costs, stacked:
[ 1. ORDERING ] who touched the ledger, and in what sequence?
── validators message back and forth to agree ──► costs round-trips
[ 2. EXECUTION ] given that order, compute the new state
── run the transactions ──► serial by default ──► costs one core
A chain is only as fast as the SLOWER of these two stages.

This matters enormously for the rest of the book, so hold it clearly: execution and ordering are two different problems with two different bottlenecks. You can make one arbitrarily fast and still be throttled by the other. A chain that parallelizes execution but still spends a round of global voting to agree on order per batch has just moved the wall, not removed it. Any serious attempt to smash the ceiling has to attack both.

We flagged only execution when we defined the serialization ceiling. The honest, fuller statement is: low throughput on base-layer chains comes from a conservative default on execution (serial, because footprints are unknown) sitting on top of a chatty default on ordering (agree by messaging, because there’s no shared clock). Two safe defaults, two ceilings, stacked.

Reframing the problem, not calling it a bug

Section titled “Reframing the problem, not calling it a bug”

It is tempting to read “seven transactions per second” as a failure. First-principles thinking corrects that instinct. Bitcoin and Ethereum’s throughput is the logical consequence of choices that are correct for their goals:

  • Keep the state footprint of a transaction implicit, so contracts can be maximally expressive and call each other freely → you lose the ability to prove disjointness → execution must be serial.
  • Keep verification cheap enough that anyone can run a node on modest hardware → keep the per-block budget small → throughput stays low.
  • Assume no trusted clock and reconcile order by messaging → ordering costs round-trips → adding validators for decentralization can slow agreement.

Each of those is a defensible, even admirable, decision. Together they define a ceiling. The ceiling is not a bug to be patched; it is a design point to be moved — and moving it means revisiting the very defaults that produced it.

That reframing is the pivot of the whole book. Solana did not find a magic constant to multiply Bitcoin’s seven by. It went back to each conservative default and asked “what if we changed the assumption that forces this?”:

Default that creates the ceiling Solana's move (later in the book)
───────────────────────────────────── ──────────────────────────────────────────────
footprint unknown until runtime → make every tx DECLARE its accounts up front
→ so execution must be serial → → so the runtime can run disjoint txs in PARALLEL
no shared clock, so order costs → build a verifiable clock everyone checks alone
round-trips of messaging → → so agreeing on order stops costing round-trips
small budget for cheap verification → spend more on validator hardware to raise the budget

You don’t need to understand how those moves work yet — that’s the rest of the Foundations part and the chapters after it. What matters here is the shape of the strategy: identify each safe default that caps throughput, and replace it with a mechanism that keeps the safety while lifting the cap.

The serialization ceiling is the target. State it in one sentence and carry it forward: base-layer chains process transactions one at a time because a transaction’s state footprint is unknown until it runs, so serial execution is the only unconditionally safe schedule — and, separately, agreeing on the order of transactions costs rounds of global messaging. Two conservative defaults, two ceilings.

Solana’s thesis is that both defaults can be replaced without giving up correctness — that you can make footprints knowable and make a clock verifiable, and thereby run at hardware speed instead of at the speed of the most conservative safe assumption. Whether that bet is worth its costs is the honest thread we’ll keep pulling.

The next page turns the diagnosis into a strategy: rather than pushing work off the chain onto extra layers, Solana bets on making the single chain faster — Scale Up, Not Out — Solana’s Thesis. From there we’ll enumerate the concrete mechanisms in The Eight Core Innovations at a Glance and pin down what “runs at hardware speed” actually means in What ‘Hardware Speed’ Means.

  1. Why does shared mutable state force sequential execution? Give the concrete failure that happens if you run two transactions that both spend from the same account in parallel.
  2. On a chain like Ethereum, why can’t you know a transaction’s state footprint before running it — and why does that single fact push the safe default all the way to serial execution?
  3. Ordering is described as a second, separate bottleneck from execution. What makes agreeing on order expensive, and why isn’t solving execution alone enough to make a chain fast?
  4. The page insists that ~7 TPS is “a design consequence, not a bug.” Name two of the deliberate design choices whose logical consequence is low throughput.
  5. Define “the serialization ceiling” in one sentence, and describe in general terms the strategy Solana uses to remove it.
Show answers
  1. Because a blockchain has one global state and every node must compute the identical result. If two transactions both spend from Alice (who has 100) run at the same time, both read Alice = 100 before either writes, both conclude the funds are there, and both spend — a race condition that on a blockchain is a double-spend (money created from nothing). Two transactions can safely run in parallel only if they touch disjoint state; overlapping state forces a defined order.
  2. An Ethereum transaction is a call into a contract that can call other contracts and decide at runtime, based on current state, which accounts to read and write — so its full state footprint is known only after it executes. If you can’t know the footprint in advance, you can’t prove two transactions are disjoint, so you can’t safely run them in parallel. The only unconditionally correct schedule left is one-at-a-time in a fixed order.
  3. There is no trusted global clock: validators receive transactions in different orders due to network latency and don’t trust each other’s timestamps, so they reconcile into one canonical sequence with rounds of messaging (round-trips), which get slower as the validator set grows. A chain is only as fast as the slower of ordering and execution, so parallelizing execution while still voting per batch just moves the wall — you must attack both.
  4. Any two of: (a) leaving the transaction footprint implicit so contracts can be maximally expressive and call each other freely — which forfeits the ability to prove disjointness, forcing serial execution; (b) keeping verification cheap enough to run a node on modest hardware — which keeps the per-block budget (bytes/gas) small; (c) assuming no trusted clock and reconciling order by messaging — which makes ordering cost round-trips and can slow agreement as validators are added.
  5. The serialization ceiling is the low-throughput cap that arises because a transaction’s state footprint is unknown until it runs, making serial execution the only safe schedule (with agreeing on order a second, messaging-bound bottleneck). Solana removes it by going back to each conservative default and replacing it with a safety-preserving mechanism: make every transaction declare its accounts so disjoint ones run in parallel, and build a verifiable clock so agreeing on order no longer costs round-trips.