This proposal introduces renewal-age pricing for Ethereum state writes. It builds on the last_written_block write-age metadata defined in EIP-8188, deriving a coarse period from each item's last-write block number. The gas cost of state-writing operations depends on whether the target state is in the Active or Inactive tier, determined by how many periods have elapsed since its last write. Writing to Inactive state is more expensive than writing to Active state. Read costs are unchanged.
This creates an economic incentive for state hygiene without mandating deletion, complementing the storage-tiering signal that EIP-8188 already provides to clients.
State access costs are not uniform in practice, yet the gas schedule prices all writes the same regardless of how recently the target was mutated:
Renewal age is unpriced: Writing to state that has not been mutated in years costs the same as writing to state mutated recently, despite different resource profiles. Recently mutated state is more likely to stay in the performance-critical mutable working set, while older state more often falls onto slower paths with deeper database lookups and higher write overhead. A flat write cost overcharges for the active set and undercharges mutations of long-unmodified state.
Abandoned state imposes uncompensated costs: Once state is written, it persists indefinitely. The ongoing storage, indexing, and lookup costs fall on node operators with no continuing contribution from the party that created it. A renewal-age-based surcharge introduces a continuing cost signal for long-unmutated state without requiring explicit in-protocol expiry or deletion.
A client-local signal cannot be priced: Clients could track write-age locally, but without a consensus price an attacker can cheaply mutate deeply write-inactive state to inflate every node's commit and storage costs. Pricing the surcharge in consensus closes this, and the EIP-8188 metadata it reads is canonically verified and syncable, unlike a local heuristic that each client would recompute and could not trust from peers.
EIP-8188 records when each piece of state was last written but does not change gas costs. This proposal turns that metadata into a price signal, charging more to mutate state that has been write-inactive for a long time.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
This proposal requires the last_written_block field defined in EIP-8188. EIP-8188 owns the encoding and the rules that update last_written_block. This proposal only reads that field to determine write pricing.
| Name | Value | Description |
|---|---|---|
PERIOD_LENGTH |
TBD | Blocks per period |
PERIOD_START_BLOCK |
derived | Number of the fork activation block at which this EIP takes effect |
INACTIVE_MIN_AGE |
TBD | Periods of write-inactivity before state enters the Inactive tier |
| Constant | Description |
|---|---|
INACTIVE_ACCOUNT_WRITE_SURCHARGE |
Additional gas charged when mutating an Inactive account |
INACTIVE_STORAGE_WRITE_SURCHARGE |
Additional gas charged when mutating an Inactive storage slot |
Each surcharge is added on top of the normal gas for the operation, not a replacement for it (see Tiered write costs). Active mutations are not repriced. Both surcharges MUST be greater than zero.
A period is a coarse bucket of consecutive block numbers, PERIOD_LENGTH blocks wide. The global current_period and an item's last_written_period are derived from a block number the same way:
current_period = max(0, (block_number - PERIOD_START_BLOCK) // PERIOD_LENGTH)
last_written_period = max(0, (last_written_block - PERIOD_START_BLOCK) // PERIOD_LENGTH)
last_written_block is the field defined in EIP-8188.
Given a state item's last_written_period, the renewal-age tier is determined by how many periods have elapsed since the last write:
period_age = current_period - last_written_period
if period_age < INACTIVE_MIN_AGE:
tier = ACTIVE
else:
tier = INACTIVE
The surcharge is charged per Inactive leaf that an operation writes. It is in addition to the normal gas for the operation, which is defined by EIP-8038 and EIP-8037. Reads are unaffected.
The general rule is:
SSTORE recomputes storageRoot, charge INACTIVE_ACCOUNT_WRITE_SURCHARGE if that account is in the Inactive tier.INACTIVE_STORAGE_WRITE_SURCHARGE if that slot is in the Inactive tier.last_written_block as it stands at the start of the operation, before EIP-8188 updates it. The write then sets last_written_block to the current block, so period_age becomes 0 and the leaf is Active. Each leaf is therefore surcharged at most once per block.The table below lists, for each state-changing operation, the leaves it can surcharge.
| Operation | Inactive leaves surcharged |
|---|---|
SSTORE, existing slot changed |
the slot (storage), and the containing account via the storageRoot cascade (account) |
SSTORE, new slot (0 to nonzero) |
the containing account via the cascade (account) only. The new slot is creation and pays no storage surcharge |
SSTORE, slot cleared (nonzero to 0) |
the containing account via the cascade (account) only |
CALL / CALLCODE with value |
the sender and the receiver (account), each if Inactive. A newly created receiver is exempt |
| Value-transfer transaction | the sender and the receiver (account), charged in intrinsic gas |
| nonce increment | the account whose nonce changes (account) |
CREATE / CREATE2 |
the creator account (account). The new contract account, its code, and constructor-set slots are creation and exempt |
SELFDESTRUCT |
each Inactive side whose balance changes, per the EIP-8188 rules. A contract created and destroyed in the same transaction has no leaf |
| EIP-7702 authorization | the authority account (account), charged in intrinsic gas |
reads (SLOAD, BALANCE, EXT*, value-less calls) |
none |
The surcharge is regular-gas, not state-gas, because reviving Inactive state is I/O work rather than state growth. It is therefore subject to EIP-7825's TX_MAX_GAS_LIMIT like any other regular-gas, and it counts toward the block's regular-gas under EIP-8037's two-dimensional accounting. Intrinsic surcharges are folded into intrinsic gas and evaluated at transaction validation.
The surcharge is consumed like ordinary regular-gas:
last_written_block update made by EIP-8188 reverts with the rest of that frame's state. The surcharge stays consumed, but the leaf remains Inactive, so a later write to it is surcharged again.State creation is never classified as Inactive and never pays the surcharge. The exemption applies to the created leaf only: a new account, a new storage slot, or deployed code. An operation that creates one leaf while writing another existing Inactive leaf still surcharges that existing leaf. For example, SSTORE 0 -> x in a dormant contract creates the slot, which pays no storage surcharge, but revives the existing account leaf through the storageRoot cascade, which pays the account surcharge.
State creation is priced by EIP-8037. The inactive surcharge SHOULD be calibrated so that mutating existing Inactive state is not cheaper, in effective block-resource terms, than creating comparable new state under EIP-8037 (see "Relation with state creation cost" in the Rationale). Because creation is priced independently of the tier mechanism, there is no economic cliff at INACTIVE_MIN_AGE: the cost of creating new state does not jump when newly created state would otherwise age into the Inactive tier.
Active and Inactive are renewal-age tiers determined by last_written_block. They affect write costs only. EIP-2929's warm/cold distinction, which is a within-transaction first-touch concept, continues to apply to reads as before. For writes, first determine the item's renewal-age tier, then apply the corresponding tiered write cost.
Access lists (EIP-2930) pre-warm addresses and storage keys into the EIP-2929 accessed sets, removing transaction-local first-touch read overhead. Since read costs are not tiered, access-list read pricing is unaffected by this proposal.
However, access-list pre-warming MUST NOT erase the item's renewal-age tier for write purposes. If a transaction pre-warms a storage slot via an access list and later writes to it via SSTORE, the write MUST still pay the tiered write cost based on the slot's last_written_block.
A tier-based model with fixed gas constants per tier is used instead of a multiplier-based model.
Discrete tiers reflect the coarse resolution of the data, which is that state is either recently mutated or not recently mutated. Fixed constants are also easier for gas estimators to work with, such that an estimator only needs to determine whether the state falls into the Active or Inactive tier.
EIP-8188 records the raw block number, which is finer-grained than pricing needs. Bucketing it into fixed-length periods serves two purposes. First, it matches the coarse resolution of the pricing decision: only the Active/Inactive boundary matters, not the exact block of the last write. Second, it makes the tier stable and predictable for gas estimators, since every block within a period shares the same current_period and an item's tier changes only at period boundaries rather than every block.
PERIOD_LENGTH is denominated in blocks rather than wall-clock time. If slot timing changes materially, the number of blocks corresponding to the target period duration (~6 months) shifts, and PERIOD_LENGTH can be re-derived in a later EIP, in the same way EIP-8037 allows cost per state byte (CPSB) to be re-derived. Deriving the period from a block number also keeps it consistent with the field EIP-8188 actually stores, avoiding the need to store a separate timestamp per entry.
The Active tier is not strictly bounded by protocol, but is limited by gas over the renewal window.
For a tier window of W blocks, any Active item must have been written within that window, and each such refresh consumes gas. Therefore the maximum Active cardinality is bounded above by the total gas available in the window divided by the minimum marginal gas needed to refresh one additional item.
This is a worst-case upper bound. It assumes the protocol allows arbitrary refresh of any accounts or storage slots by any party. In practice, this bound is more natural for accounts than for storage slots, because not all storage slots can be refreshed independently by arbitrary actors.
The relevant claim is not that the Active set is strictly bounded, but that it is economically rate-limited and therefore can remain much smaller than the total state under write-renewal semantics.
There is an incentive to periodically rewrite state purely to keep it in the Active tier. This is by design: the proposal intends to make state maintenance an ongoing cost borne by the parties who benefit from cheap future writes.
The size of the surcharge should be chosen with this in mind. It must be large enough that letting state go write-inactive carries a real cost, but not so large that it pays to issue mass speculative refresh writes purely to keep state in the Active tier, which would inflate the very set this proposal aims to keep small.
The gas cost of state creation should be at least equal to the cost of mutating Inactive state, which is the normal write cost plus the inactive surcharge, and may be higher.
Creating new state performs no less work than writing to Inactive state. Both operations require traversing and updating the state trie, including recomputing hashes along the modified path. State creation in the worst case can also touch intermediate nodes that belong to existing Inactive state.
For this reason, mutating Inactive state must not be cheaper than creating comparable new state. Otherwise the gas schedule would create an inconsistency where reviving old Inactive state is a cheaper way to consume the same node resources than allocating fresh state.
This gas relation is distinct from EIP-8037's interaction with EIP-8188, which concerns the per-byte state-size parameters rather than write-tier pricing.
This is a backwards-incompatible gas repricing that requires a scheduled network upgrade. It depends on the EIP-8188 metadata and must activate at or after the same fork.
Wallets and RPC providers must update eth_estimateGas to reflect the surcharge. Estimators must determine each written item's renewal-age tier from its last_written_block and add the inactive surcharge when the item is Inactive.
This proposal prices write-age only. A storage slot can be read on every block yet never rewritten, leaving it in the Inactive tier. The tier signal therefore must not be read as "cold" for access purposes. This proposal does not move any state. Only client storage policy does. Clients that relocate Inactive state to slower or denser storage should account for read frequency separately, since placing frequently read Inactive state on a slow path could become a denial-of-service vector. Read frequency is orthogonal to write-age, and reconciling the two is left to client storage policy, which is out of scope for this proposal.
Copyright and related rights waived via CC0.