EIP-8295: State Tiering by Periods
EIP-8295 puts a price on the write-age signal that EIP-8188 records. Writing to state that has not been touched in roughly a year costs more than writing to recently-mutated state. Reads are unchanged. Nothing is removed or expired, rather just making inactive state writes more expensive.
What EIP-8295 does
It reads last_written_block from EIP-8188 and turns it into a tier:
-
A
periodis a coarse bucket of blocks,period = (block_number - PERIOD_START_BLOCK) // PERIOD_LENGTH. -
An item is Active if
current_period - last_written_period < INACTIVE_MIN_AGE, otherwise Inactive. With the default target that means written within the last year or so. -
Writing to Active state costs normal gas, exactly as today. Writing to Inactive state costs normal gas plus
INACTIVE_ACCOUNT_WRITE_SURCHARGEorINACTIVE_STORAGE_WRITE_SURCHARGE. The surcharge is additive, not a replacement. -
The tier is evaluated before the write. An Inactive item pays the surcharge once, and because the write refreshes its
last_written_block, it becomes Active for later writes. -
Reads are untouched, and this is independent of EIP-2929’s warm/cold cache distinction, which still governs read access.
The surcharge behaves like ordinary execution gas. It is not refundable, it is consumed even if the call frame later reverts, and if the write happened inside a reverted frame then the EIP-8188 field update reverts with the rest of state, so the item stays Inactive and a later write pays again.
State creation is not tiered. Creating new state is priced by EIP-8037, and the surcharge should be calibrated so that reviving Inactive state is never a cheaper way to consume the same node resources than allocating fresh state.
Why price it at all
EIP-8188 on its own is a storage hint. It lets clients tier their databases, but it does not change what anyone pays, so it leaves the core mispricing in place:
-
Renewal age is unpriced. Writing to state untouched for years costs the same as writing to state touched yesterday, even though the old write pulls deeper database paths and undoes a client’s hot-cold separation. A flat cost overcharges the active set and undercharges mutations to long-dead state.
-
Abandoned state imposes uncompensated cost. Once written, state persists forever, and the ongoing storage and lookup burden falls on node operators with no continuing contribution from whoever created it. A renewal-age surcharge is a continuing cost signal, without any in-protocol expiry or deletion.
-
A client-local signal cannot be priced. Clients could track write-age privately, but without a consensus price an attacker can cheaply mutate deeply cold state and inflate every node’s commit and storage cost. Pricing in consensus, against the canonically-verified EIP-8188 field, closes that.
Why periods rather than the raw block number
EIP-8188 stores the raw block number because it is the finest-grained, policy-free record. Pricing does not need that resolution. Bucketing into fixed-length periods matches the coarseness of the decision (only the Active/Inactive boundary matters) and keeps the tier stable for gas estimators, since an item’s tier only changes at period boundaries rather than every block. The period parameters live entirely in 8295, so the stored metadata stays free of pricing policy and the two proposals can move on different timelines.
FAQ
What about state that is read-only but actively accessed?
Reads cost the same as today. The tier only affects writes. A contract that is heavily read but never written sees no change, and its tier drifts to Inactive over time with no consequence. The only case that feels it is state read constantly and written rarely but not never, like a config value updated once a year. That yearly update pays the Inactive cost, or the owner keeps it Active by refreshing it.
Won’t users just keep rewriting state to keep it Active?
Yes, and that is the point. Renewal-age pricing makes state maintenance an ongoing cost paid by the parties who want cheap future writes. If you want a slot to stay Active, you pay to refresh it. If you don’t, your eventual write pays the Inactive cost. The Active set is not strictly bounded by protocol, but it is economically rate-limited by the gas available over the renewal window, and the cheapest refresh sets the upper bound on how much can be kept Active per period. On mainnet today that bound is far below total state.
What if a malicious actor tries to keep all state Active forever?
They can keep some of it Active by paying to refresh it. That is true by design. The question is not whether an attacker can keep state Active, but how much, and at what cost.
For accounts the answer is potentially a lot: an attacker can create many accounts and refresh them, or refresh existing ones, with minimal-value transfers. Parts of storage can be refreshed indirectly through ERC-20 balances or other publicly-writable contract state. So the worst case is not that all old state goes Inactive. The worst case is roughly today’s world, where a large amount of state stays Active. That is still strictly better than the status quo, because keeping it Active is now a recurring paid action.
Two limits hold. Refreshing consumes gas every cycle, so the kept-Active set is rate-limited by the gas in the renewal window. And not all state is equally refreshable: accounts are easy, arbitrary storage slots are not, because storage refresh depends on contract-specific write paths. The mechanism does not guarantee all old state becomes Inactive. It guarantees that keeping large amounts of state Active requires repeated spending, which is enough to discourage it when the attack causes no catastrophic loss to the protocol.
Why not just do state expiry?
The same answer as for 8188. State expiry needs a resurrection path, which needs decentralized infrastructure to serve old state on demand, which does not exist yet. 8295 needs none of it. State never leaves consensus. It only costs more to write. The surcharge supplies the cost pressure that expiry would eventually provide, available today.
Activation
8295 depends on EIP-8188 and must activate at or after the same fork. The metadata has to be accumulating before the pricing can read it. The pricing constants and the period length can be tuned, and re-derived in a later EIP if slot timing changes, without touching the stored field.
Closing
EIP-8188 gives the protocol a shared write-age boundary. EIP-8295 prices it. Together they stop treating every write as equally cheap and stop forcing the mutable path to scale with the whole state, all within today’s constraints and with no dependency on infrastructure that has not shipped. It is not a substitute for state expiry. It is the part of the problem we can solve now.