EIP-8188

State Tiering by Write Age

Proposed for Inclusion in Hegotá

Wei Han Ng (@ngweihan_eth)

Ethereum Foundation (Stateless Consensus)

Not All State is Equal

359GB Full node state today 20% 80% ~81GB active Accessed within 1 year ~278GB inactive Unaccessed for over a year

Majority of the state is inactive

One protocol-level signal: last_written_period

1 · Period counter

period = (block - PERIOD_START) // PERIOD_LENGTH

~6 months per period. Derived from block number, no extra state.

2 · Add period metadata for accounts and storage slots

Account RLP gains a 5th field. Storage slots wrap their value in a list with the same field. Legacy entries decode as last_written_period = 0.

3 · Write cost changes

Writing to Inactive state costs more. Writing to Active state costs less.

What bumps the period

Bumps last_written_period SSTORE (value change) Balance transfer (nonzero value) Nonce increment (tx execution) CREATE / CREATE2 Storage mutation cascades Slot write also bumps the account (storageRoot changes) No period bump SLOAD, BALANCE, EXTCODE* CALL with 0 value SSTORE same value (no-op) Access list pre-warming STATICCALL No conflict: reads don't bump, writes can't happen

Reads are unchanged.
Only actual state mutations bump the period.

Architecture unlocks for EL clients

LSM clients Geth · Nethermind · Besu · Ethrex
Extract Inactive subtrees to an append-only flat file, leaving small stubs in the live LSM. Compaction sees fewer files, working set shrinks.
Erigon MDBX + segment domains
Fits very well with this EIP. Already has hot-cold storage separation where items are moved into immutable flat files periodically.
Reth MDBX + Nippy Jar
Split plain/hashed/trie state along the Active/Inactive axis.

Separate cold subtrees out of the live LSM

TODAY PebbleDB / RocksDB root inactive active inactive All nodes in one LSM LIVE LSM hot + stubs root stub stub INACTIVE BLOB flat file · append-only · immutable 0x00 0x4a EOF → subtree · 0x00 subtree · 0x4a

Geth prototype · 1 year of mainnet replay

Trie Nodes
148GB33GB
−78%
Live LSM after extracting Inactive trie nodes
Replay scope
2.6M blocks
head 19,999,256 → 22,627,956 (~1 year)
Stub durability
80% survived
Original stubs unchanged across the entire import

Performance benchmarks: TBD · Prototype: github.com/weiihann/go-ethereum · branch feat/eip-8188/inject

FAQ

Doesn't the metadata bloat the state?

Worst case ~3.4GB (0.36GB accounts + 3GB slots). Pre-fork untouched state pays zero. Geth prototype measured only +300MB.

Why not state expiry?

State expiry needs decentralized resurrection infrastructure. None of which exists yet. EIP-8188 has no such prerequisite — state stays accessible, writes just cost more.

Is it compatible with future tree migration?

Compatible. When the trie moves to a page-based layout (e.g. EIP-7864), the period aggregates to the page: page.period = max(slot.period).

Why Hegotá, not later

EIP-8188

Thank You