Part III · Chapter 39 of 43 · Prague · Electra

EIP-2935: keeping block hashes in state

The BLOCKHASH opcode can only see the last 256 blocks — about 51 minutes. Older than that, it returns zero. But L2s, provers, and light clients need to reach further back, and stateless clients need those hashes in the state itself, not in a special header cache. EIP-2935 puts them in a ring buffer inside a system contract.

Updated Jul 2, 2026 · 8 min
Assumed
  • BLOCKHASH & block headers
  • stateless Ethereum (witnesses)

Prague / Electra, May 2025. The EVM has always let a contract ask for a past block’s hash: BLOCKHASH(n). It’s how a contract can pin a fact to a specific block, or seed a bit of pseudo-randomness. But there’s a catch that has quietly shaped a decade of on-chain design: it only reaches back 256 blocks — roughly 51 minutes. Ask for anything older and it returns zero. As rollups, cross-chain provers, and light clients grew up around Ethereum, that short, hard window became a real constraint — and the way it was implemented became an obstacle to stateless Ethereum. EIP-2935 rebuilds block-hash lookup on a better foundation. Let’s derive it.

1 step A 256-block window

The problem: BLOCKHASH sees only the recent past, from a side cache

BLOCKHASH(n) returns the hash of block n — but only if n is one of the last 256 blocks; otherwise it yields zero. Two things about this hurt. First, the window is tiny: many applications — a rollup verifying an older state, a cross-chain prover A contract or system that proves a fact about one chain to another (or to a rollup) by checking block hashes and Merkle proofs. It often needs hashes of blocks far older than 256, which BLOCKHASH cannot provide. checking historical inclusion, a light client catching up — need hashes from far further back than 51 minutes. Second, and more subtly, the opcode was served from a client-side header cache: each node kept the recent headers around in its own memory to answer BLOCKHASH. That’s fine for a full node, but it’s exactly the kind of out-of-band state that stateless Ethereum A future where a node can validate a block using only the block plus a cryptographic 'witness' of the state it touches, without storing the full state. Anything the EVM reads must therefore be part of the witnessed state — a side cache of headers doesn't fit. is trying to eliminate: a stateless client validating a block from a witness has no header cache to consult.

BLOCKHASH(n): the hash of a past block last 256 older blocks → returns 0 head → but L2s, provers & light clients need older hashes and stateless clients need them in state, not client memory 256 blocks ≈ 51 minutes — a hard, out-of-band limit
BLOCKHASH can only read the last 256 block hashes (~51 min); older blocks return zero. Rollups, provers, and light clients need to reach much further back — and the opcode is served from a client-side header cache, not from state, which stateless clients can't rely on.

→ Step 2: put the hashes into state, in a ring buffer.

2 step A ring buffer in state

EIP-2935: a system contract records each parent hash

The fix reuses a pattern this book has seen before. A designated system contract A contract at a fixed, protocol-reserved address whose storage the protocol itself writes each block. EIP-2935's history contract and EIP-4788's beacon-root contract both work this way — the ring buffer lives in ordinary contract storage, so the EVM reads it with a normal SLOAD. holds the recent block hashes, and the protocol updates it automatically: at the start of processing block n, it writes the parent block’s hash into the contract’s storage at slot (n − 1) mod 8191. Because the index wraps, the contract is a fixed-size ring buffer A fixed-length array addressed by index-modulo-length, so new entries overwrite the oldest. Here it holds the last 8191 block hashes in 8191 storage slots, in constant space — the same structure EIP-4788 uses for beacon roots. holding the last 8191 hashes (~27 hours). Now a contract reads a historical hash with an ordinary SLOAD against that address — no special opcode path, no header cache — and, decisively, the hashes are part of the state and therefore of any witness.

each block: write parent hash into a ring buffer in state block n → store hash at slot (n−1) mod 8191 8191 slots in state readable with a plain SLOAD same pattern as EIP-4788's beacon root
EIP-2935 has the protocol write each block's parent hash into a ring buffer in a system contract's storage — slot (n−1) mod 8191. The last 8191 hashes become readable with a plain SLOAD, and live in state. It's the exact same ring-buffer-in-a-system-contract design as EIP-4788's beacon root.

→ Step 3: a longer reach, and a piece of the stateless future.

3 step Reach, and statelessness

The payoff: further back, and witnessable

Two wins fall out at once. The reach jumps from 256 to 8191 blocks — a 32× longer window that rollups and provers can lean on for historical proofs. And because the hashes now live in state, a stateless client can access them straight from a block’s witness, with no header cache to keep — removing one of the awkward out-of-band pieces standing between today’s Ethereum and a fully stateless, Verkle-ready one. It also makes trust-minimized cross-chain and historical proofs cheaper and simpler, since a contract just reads storage. And it’s a satisfying repeat of a now-familiar idea: like EIP-4788’s beacon root, the protocol maintains a small ring buffer in a system contract, turning a special data need into ordinary, readable state.

256 → 8191 blocks, and now part of state before 256 blocks after 8191 blocks hashes live in witnessed state — no special header cache a building block for stateless Ethereum and cheaper cross-chain proofs the ring-buffer-in-a-contract pattern, again
The lookback grows from 256 to 8191 blocks (32×), and the hashes now live in witnessed state — so stateless clients read them without a header cache, and cross-chain/historical proofs get cheaper. The same ring-buffer-in-a-contract pattern as EIP-4788, in service of statelessness.
04 Go Deeper Where to take it from here