--- eip: 8038 title: State-access gas cost update description: Increases the gas cost of state-access operations to reflect Ethereum’s larger state author: Maria Silva (@misilva73), Wei Han Ng (@weiihann), Ansgar Dietrichs (@adietrichs) discussions-to: https://ethereum-magicians.org/t/eip-8038-state-access-gas-cost-update/25693 status: Draft type: Standards Track category: Core created: 2025-10-03 requires: 7904, 8037 --- ## Abstract This EIP updates the gas cost of state-access operations to reflect Ethereum's larger state and the consequent slowdown of these operations. It raises the base costs for `STORAGE_WRITE`, `COLD_STORAGE_ACCESS`, and `COLD_ACCOUNT_ACCESS` and updates the access cost for `EXTCODESIZE` and `EXTCODECOPY`. ## Motivation The gas price of accessing state has not been updated for quite some time. [EIP-2929](./eip-2929.md) was included in the Berlin fork in March 2021 and raised the costs of state-accessing opcodes. Yet, since then, Ethereum's state has grown significantly, thus deteriorating the performance of these operations. This proposal further raises state access costs to better align them with the current performance of state access operations, in relation to other operations. Additionally, `EXTCODESIZE` and `EXTCODECOPY` have the same access cost as `BALANCE` and `EXTCODEHASH`. However, `EXTCODESIZE` and `EXTCODECOPY` require two database reads - first to load the account object (which includes the `nonce`, `balance`, `codeHash` and `storageRoot`), and second to collect the required information (the code size and bytecode respectively). Therefore, the access cost of `EXTCODESIZE` and `EXTCODECOPY` should be higher when compared with the other account read operations. ## Specification ### Parameters Upon activation of this EIP, the following parameters of the gas model are introduced/updated: | **Parameter** | **Description** | **Current value** | **New value** | **Increase** | **Operations affected** | | :---: | :---: | :---: | :---: | :---: | :---: | | `COLD_ACCOUNT_ACCESS` | Cold touch of an account | 2,600 | TBD | TBD | `*CALL` opcodes, `BALANCE`, `SELFDESTRUCT`, `EXT*` opcodes, EOA delegations, contract creation txs and ETH transfers | | `ACCOUNT_WRITE` | Surcharge for when writing to an account changes one account leaf value for the first time | 6,700¹ | TBD | TBD | `*CALL` opcodes, `SELFDESTRUCT`, EOA delegations and ETH transfers | | `COLD_STORAGE_ACCESS` | Cold touch of a storage slot | 2,100 | TBD | TBD | `SSTORE` and `SLOAD` | | `STORAGE_WRITE` | Surcharge for when writing to a storage slot changes its value for the first time | 2,800² | TBD | TBD | `SSTORE` | | `WARM_ACCESS` | Touch of an already-warm account or storage slot | 100 | TBD | TBD | `SSTORE`, `SLOAD`, `*CALL` opcodes, `BALANCE` and `EXT*` opcodes | | `STORAGE_CLEAR_REFUND` | Refund for clearing a storage slot | 4,800 | TBD | TBD | `SSTORE` | | `CREATE_ACCESS` | State access costs for contract deployment (include account cold access and account write) | 7,000³ | TBD | TBD | `CREATE`/ `CREATE2` | | `ACCESS_LIST_STORAGE_KEY_COST` | Gas charged per storage key included in a transaction's access list | 1,900 | TBD | TBD | `SSTORE` and `SLOAD` | | `ACCESS_LIST_ADDRESS_COST` | Gas charged per address included in a transaction's access list | 2,400 | TBD | TBD | `*CALL` opcodes, `BALANCE`, `SELFDESTRUCT` and `EXT*` opcodes | ¹: 6,700 = `CALL_VALUE` (9,000) - `CALL_STIPEND`(2,300) ²: 2,800 = `GAS_STORAGE_UPDATE` (5,000) - `GAS_COLD_SLOAD` (2,100) - `GAS_WARM_ACCESS` (100) ³: 7,000 = `GAS_CREATE` (32,000) - `GAS_NEW_ACCOUNT` (25,000) ### `SSTORE` pricing In addition, the `SSTORE` cost formula is updated to include the following independent costs: 1. Access costs: `COLD_STORAGE_ACCESS` or `WARM_ACCESS`, depending on whether the storage slot is cold or warm. 2. Write cost: additionally charge `STORAGE_WRITE` if the new value is different from the original value. 3. State creation cost: additionally charge `GAS_STORAGE_SET` (per [EIP-8037](./eip-8037.md)) if the original value is zero, the current value is zero, and the new value is non-zero. Refunds are also updated as follows: 1. `STORAGE_CLEAR_REFUND` is refunded if the original value is non-zero, the current value is non-zero and the new value is zero. 2. `STORAGE_WRITE` is refunded if the original value is the same as the new value. These refunds go to the transaction's refund counter and are capped to 20% of the total gas used by the transaction, as per the current refund mechanism. The rules for state creation cost charges and refills are addressed in [EIP-8037](./eip-8037.md). Cases and their corresponding costs are detailed in the table below: | Original value | Current value | New value | Access status | Description | Regular-gas charges/refunds | State-gas charges/refills | | :---: | :---: | :---: | :---: | :---: | :---: | :---: | | 0 | 0 | x | Cold | New slot | `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged | `GAS_STORAGE_SET` charged | | 0 | 0 | x | Warm | New slot | `WARM_ACCESS` + `STORAGE_WRITE` charged | `GAS_STORAGE_SET` charged | | 0 | x | 0 | Warm | Cleared slot, zero at transaction start | `WARM_ACCESS` charged, `STORAGE_WRITE` refunded | `GAS_STORAGE_SET` refilled | | x | x | 0 | Warm | Cleared slot, non-zero at transaction start | `WARM_ACCESS` charged, `STORAGE_CLEAR_REFUND` refunded | no state-gas adjustments | | x | x | y | Cold | Existing slot, updated to new value | `COLD_STORAGE_ACCESS` + `STORAGE_WRITE` charged | no state-gas adjustments | | x | x | y | Warm | Existing slot, updated to new value | `WARM_ACCESS` + `STORAGE_WRITE` charged | no state-gas adjustments | | x | y | z | Warm | Existing slot, written to again | `WARM_ACCESS` charged | no state-gas adjustments | | x | y | x | Warm | Existing slot, value reset | `WARM_ACCESS` charged, `STORAGE_WRITE` refunded | no state-gas adjustments | ### Account access pricing The rules that determine when `COLD_ACCOUNT_ACCESS` and `WARM_ACCESS` are charged for account-related operations are unchanged; only the parameter values themselves are updated. #### `CALL`/`CALLCODE` For `CALL` and `CALLCODE` operations, `CALL_VALUE` is set to `ACCOUNT_WRITE + CALL_STIPEND`, where `CALL_STIPEND` = 2,300. #### `CREATE`/`CREATE2` `CREATE` and `CREATE2` operations don't have explicit warm/cold pricing. Instead, they are charged `CREATE_ACCESS` in regular-gas and `GAS_NEW_ACCOUNT` in state-gas (per [EIP-8037](./eip-8037.md)). `CREATE_ACCESS` is defined as `ACCOUNT_WRITE` + `COLD_STORAGE_ACCESS`. Note: this definition does not exactly match the legacy decomposition shown in footnote ³ of the Parameters table (`GAS_CREATE` - `GAS_NEW_ACCOUNT` = 7,000). The pre-existing accounting in the protocol is not internally consistent here, and this EIP keeps the discrepancy rather than attempting to reconcile it. #### `SELFDESTRUCT` For `SELFDESTRUCT`, an additional charge of `ACCOUNT_WRITE` is added if a positive balance is sent to an empty account. #### `EXT*` family update Besides the current access costs, `EXTCODESIZE` and `EXTCODECOPY` are charged an additional `WARM_ACCESS`. ### [EIP-7702](./eip-7702.md) authorizations pricing [EIP-7702](./eip-7702.md) authorizations have two separate gas costs - intrinsic costs and access costs. Intrinsic costs are computed during transaction validation, while access costs are charged during code execution. The following table summarizes these costs: | Charge type | Regular-gas charges/refunds | State-gas charges/refills | | :---: | :---: | :---: | | Intrinsic costs (per authorization) | `ACCOUNT_WRITE` + `REGULAR_PER_AUTH_BASE_COST` charged | (`STATE_BYTES_PER_NEW_ACCOUNT` + `STATE_BYTES_PER_AUTH_BASE`) x `CPSB` charged | | Access costs (per warm authority) | `WARM_ACCESS` | no state-gas updates | | Access costs (per cold authority) | `COLD_ACCOUNT_ACCESS` | State-gas charges/refills | `REGULAR_PER_AUTH_BASE_COST` is defined in [EIP-8037](./eip-8037.md) as the sum of: - Calldata cost: 1,616 (101 bytes × 16) - Recovering authority address (ecRecover): `PRECOMPILE_ECRECOVER` (updated by [EIP-7904](./eip-7904.md)) - Reading nonce and code of authority (cold access): `COLD_ACCOUNT_ACCESS` (updated by this EIP) - Storing values in already warm account: 2 x `WARM_ACCESS` ## Rationale ### Empirical Estimation of Gas Costs #### Selecting which Operations to Reprice The parameters selected for repricing in this EIP were chosen based on the estimated million gas per second (Mgas/s) performance of their respective operations. For this EIP, a performance target of **100 million gas per second** is chosen. With this performance target, we will be able to increase the base throughput of the chain by 5x from our current 20Mgas/s performance. #### Data Collection The gas costs proposed in this EIP are based on the actual time each execution client takes to run a specific set of benchmarks. Similar to the methodology used in the Gas Cost Estimator project, we generate synthetic blocks that isolate and stress individual EVM operations and use them to derive the various gas parameters. Concretely, to benchmark a single operation/parameter, different blocks are created by varying the number of times the target operation is executed and by changing the parameter values to the operation. The EEST benchmark suite contains the tests used to generate these blocks. Then, the Benchmarkoor tool is used to collect the needed metrics. This tool returns the total execution time of the block and the number of times each operation was executed. Each test block is run multiple times on each client to account for variability in execution time. All benchmarks were run on top of a snapshot with the same size as mainnet in March 2026, so they reflect the current performance of state access operations. **What about differences between client implementations?** Ultimately, we require a single cost model that is independent of the client's implementation. Although the decision may be different in a specific situation, the general rule is to take the worst client result that cannot be optimized. This means that the worst-performing client on a given operation and resource combination will define the cost of that operation for the entire network. This is the safer and most conservative choice. #### Runtime Estimation To estimate the runtime of a single operation from the total execution time of the corresponding synthetic blocks, a **Non-Negative Least Squares (NNLS) Linear Regression** is used. This model enforces that all coefficients are non-negative, thus ensuring execution time cannot be negative. The model estimates runtime as a linear combination of: - **Constant term (intercept)**: Base overhead for executing the test, which includes setup and teardown time - **Operation count (slope)**: Number of times the operation is executed in the test. This parameter is the one that allows us to estimate the per-operation runtime. - **Operation-specific parameters (e.g., update)**: Extra per-operation runtime contributed by an additional, operation-specific binary or numeric input (e.g., whether a `CALL` is made with value, or whether the `SSTORE` writes a new value). The `update` coefficient gives the marginal runtime added per execution for storage writes. For simple operations (i.e., without additional parameters), the model estimates: `runtime = intercept + slope × operation_count` For variable operations, the model estimates: `runtime = intercept + slope × operation_count + param1_coef × operation_count × param1 + param2_coef × operation_count × param2 + ...` Independent models are created for each client, operations, and configuration. Only operations and parameters with good model fits (R² > 0.5 and p-value < 0.05) are included in the gas cost proposal to ensure the reliability of the estimates. **Glue opcode adjustment** Each benchmark test includes auxiliary "glue" opcodes that scale linearly with the main opcode count. The regression slope captures the combined runtime of both the target opcode and its glue opcodes, so we subtract the estimated glue opcode runtime to isolate the true per-execution cost: ``` adjusted_slope = slope - sum(ratio_i * glue_runtime_i) ``` Where, for each glue opcode `i`: - `ratio_i` is the number of executions of glue opcode `i` per execution of the target opcode in the benchmark test. - `glue_runtime_i` is the estimated per-execution runtime of glue opcode `i`, taken from its own regression model. Only glue opcodes with a statistically significant fit (p-value < 0.05) are included. The adjusted slope is clipped to a minimum of zero. **Parameter mapping** Each gas parameter is derived from one or more benchmark models by selecting a specific regression coefficient (`slope` or `update`) after applying the relevant filters (test name, cache strategy, account mode). For each parameter and client, the worst-case value across all matching model configurations is used. The final proposal takes the worst case across clients. The following table lists the directly estimated parameters and their mapping to the regression models: | Test name | Configuration | Model | Parameter mapping | | :---: | :---: | :---: | :---: | | `test_account_access` | CacheStrategy = NO_CACHE | runtime = intercept + slope × operation_count + update × value_sent x operation_count | `slope` → `COLD_ACCOUNT_ACCESS`; `update` → `ACCOUNT_WRITE` | | `test_sload_bloated` | CacheStrategy = NO_CACHE | runtime = intercept + slope × operation_count | `slope` → `COLD_STORAGE_ACCESS` | | `test_sstore_bloated` | CacheStrategy = NO_CACHE | runtime = intercept + slope × operation_count + update × write_new_value x operation_count | `slope` → `COLD_STORAGE_ACCESS`; `update` → `STORAGE_WRITE` | | `test_storage_sload_same_key_benchmark` | NA | runtime = intercept + slope × operation_count | `slope` → `WARM_ACCESS` | | `test_ext_account_query_warm` | NA | runtime = intercept + slope × operation_count | `slope` → `WARM_ACCESS` | `test_sstore_bloated` and `test_sload_bloated` targeted a bespoke contract with a storage size of 10GB, which is the size of the largest mainnet contract. #### Conversion to gas costs New gas costs are calculated using the same target performance of 100Mgas/s. The formula used is: ``` new_gas = (anchor_rate * runtime_ms) / 1000 ``` Where: - `anchor_rate` is the target performance expressed in gas per second (e.g., `100_000_000` for a 100Mgas/s target). - `runtime_ms` is the estimated runtime per operation, in milliseconds, taken from the regression models (the `adjusted_slope` defined above). - The factor `1000` converts `runtime_ms` from milliseconds to seconds, so that the product with `anchor_rate` (gas/second) yields a result in gas units. **Derived parameters** are computed from the directly estimated ones: ``` STORAGE_CLEAR_REFUND = (STORAGE_WRITE + COLD_STORAGE_ACCESS) * (4800/5000) ACCESS_LIST_STORAGE_KEY_COST = COLD_STORAGE_ACCESS ACCESS_LIST_ADDRESS_COST = COLD_ACCOUNT_ACCESS CREATE_ACCESS = ACCOUNT_WRITE + COLD_STORAGE_ACCESS ``` ### Interaction with [EIP-7928](./eip-7928.md) [EIP-7928](./eip-7928.md) introduces Block-Level Access Lists, which enable parallel disk reads, parallel transaction validation, and executionless state updates through client optimizations. Our benchmarks already consider these optimization gains by running on clients with the optimizations implemented. ### Special case for `EXTCODESIZE` and `EXTCODECOPY` Differently from other account read operations, `EXTCODESIZE` and `EXTCODECOPY` make two reads to the database. The first read is the same, where the object of the target account is loaded. This object includes the account's `nonce`, `balance`, `codeHash` and `storageRoot`. Then, these operations do another read to collect either the code size or the bytecode of the account. This second read is to an already warmed account, and thus we propose to price it as `WARM_ACCESS` for consistency. ### Interaction with [EIP-8032](./eip-8032.md) [EIP-8032](./eip-8032.md) proposes modifying the `SSTORE` cost formula to account for the storage size of a contract. This is a more accurate method for pricing storage writes. It allows writes to smaller contracts to be cheaper than writes to large contracts, which helps with scaling and is fairer to users. However, [EIP-8032](./eip-8032.md) is not yet scheduled for inclusion in a fork, and, as such, this proposal considers two cases for setting the values of `STORAGE_WRITE` and `COLD_STORAGE_ACCESS`: 1. Before [EIP-8032](./eip-8032.md). In this case, we set the parameters assuming a worst-case contract size, which makes state-accessing operations more expensive, independently of the contract size. 2. After [EIP-8032](./eip-8032.md). In this case, we set the parameters assuming the worst-case until `ACTIVATION_THRESHOLD`, which is the parameter in [EIP-8032](./eip-8032.md) that triggers the depth-based cost. This means that contract sizes below the threshold have the same access costs, while contracts above the threshold get exponentially more expensive with increasing size. ### Interaction with [EIP-2926](./eip-2926.md) [EIP-2926](./eip-2926.md) proposes to change how code is stored in the state trie. One of the changes of this proposal is to include the code size as a new field in the account object (`codeSize`). With this change, the code size can be directly accessed with a single read to the database and thus `EXTCODESIZE` should maintain its previous cost formula, without including the additional `WARM_ACCESS`. ## Backwards Compatibility This is a backwards-incompatible gas repricing that requires a scheduled network upgrade. Wallet developers and node operators MUST update gas estimation handling to accommodate the new state access cost rules. Specifically: - Wallets: Wallets using `eth_estimateGas` MUST be updated to ensure that they correctly account for the updated gas parameters. Failure to do so could result in underestimating gas, leading to failed transactions. - Node Software: RPC methods such as `eth_estimateGas` MUST incorporate the updated formula for gas calculation with the new state access cost values. Users can maintain their usual workflows without modification, as wallet and RPC updates will handle these changes. ## Security Considerations Changing the cost of state access operations could impact the usability of certain applications. More analysis is needed to understand the potential effects on various dApps and user behaviors. ## Copyright Copyright and related rights waived via [CC0](../LICENSE.md).