Overclocking Blocks with Gas Refunds
TL;DR: Storage‐clearing refunds are valuable but can inflate block gas figures - keep them for users, but don’t count them against block gas used. EIP-7778 restores accurate on-chain gas accounting.
Ethereum’s gas mechanism aims to reflect computational resource consumption accurately. To encourage users to keep the state clean and manageable, Ethereum grants gas refunds when storage slots are reset to zero. While effective in reducing state bloat, these refunds currently complicate gas accounting, making it appear that blocks consume fewer resources than they actually do.
How Gas Refunds Work Today
Transactions that clear storage slots via SSTORE
operations, resetting a slot to zero, qualify for gas refunds (see EIP-3529). For instance, a transaction consuming 45 million gas with a 20% refund effectively costs the user:
tx.gas_used = 45,000,000 - (0.20 × 45,000,000) = 36,000,000 gas
Similarly, another transaction consuming 9 million gas with a 20% refund results in:
tx.gas_used = 9,000,000 - (0.20 × 9,000,000) = 7,200,000 gas
Importantly, the gas refund of one transaction can be consumed by another transaction.
What’s Problematic About the Current Mechanism?
While gas refunds effectively incentivize storage cleanup, their current implementation reduces the total gas usage counted against the block gas limit. As a result, the block’s gas usage understates the actual computational effort performed. Crucially, long-term incentives against state bloat should not distort short-term feedback controller mechanisms such as EIP-1559’s basefee.
To clearly understand the impact of gas refunds on block gas accounting, let’s formalize this more systematically.
Formal Model of Gas Smuggling
Definitions
- Block Gas Limit: G_0G0
- Refund Ratio: r = 0.2r=0.2 (20%)
- Minimum Gas Required per Transaction: G_{\text{min}} = 21,000Gmin=21,000
Gas Refund at Step ii
The gas refund at each iterative step ii (starting from i=1i=1) is given by:
For example:
- Step 1: R_1 = G_0 \times rR1=G0×r
- Step 2: R_2 = G_0 \times r^2R2=G0×r2, etc.
Stopping Condition
We continue generating transactions that trigger more refunds until the refund at step nn falls below the minimum required gas:
Isolating nn:
Solving for nn:
Thus, the stopping step number is:
(\lfloor x \rfloor⌊x⌋ denotes the floor function, giving the largest integer ≤ x.)
Total Computational Gas
Summing all computational gas used up to step n-1n−1:
Factoring out G_0G0:
Using the geometric series formula:
We get:
Substituting our values:
- G_0 = 45,000,000G0=45,000,000
- r = 0.2r=0.2
- G_{\text{min}} = 21,000Gmin=21,000
Compute nn:
Compute Total Gas:
This demonstrates a ~25% increase from the initial gas limit, highlighting how significantly current refunds distort block gas accounting.
Example Contract
This is how such contracts might look like:
// SPDX-License-Identifier: MITpragma solidity ^0.8.0;contract Refundooor {mapping(uint256 => uint256) private storageSlots;/// @notice Pre‑fill `maxSlots` keys starting at `startKey`function chargeStorage(uint256 startKey, uint256 maxSlots) external {for (uint256 i = 0; i < maxSlots; i++) {storageSlots[startKey + i] = startKey + i + 1;}}/// @notice Clears exactly MAX_LOOPS slots unconditionally (no checks)fallback() external {assembly {let base := storageSlots.slotmstore(0x20, base)// MAX_LOOPS * ~5,109 gas/iter ≈ 45 000 000 gaslet MAX_LOOPS := 8805for { let i := 0 } lt(i, MAX_LOOPS) { i := add(i, 1) } {// compute storage slot for key = imstore(0x0, i)let s := keccak256(0x0, 0x40)// unconditionally write zerosstore(s, 0)}}}}
- We first charge the contract by writing to empty storage slots.
- Second, we call the contract’s fallback, setting 8805 storage slots to zero.
Check out this sample transaction on Holesky which maxes out the number of
SSTORE
operations.
Eventually, the “smuggled” gas scales linearly with the block gas limit. At 100M gas, a block can come with 125M gas of actual work.
Proposed Change: Separate Transaction Refunds from Block Gas Accounting
EIP-7778 proposes retaining user-level refunds to incentivize efficient storage management but removing these refunds from block-level gas accounting. This ensures block gas usage accurately reflects actual resource consumption.
The benefits of implementing the EIP are:
- Improved Predictability: Actual work for blocks stays below the intended limit.
- Increased Network Stability: Reduced DoS risks regardless of the worst-case scenario.
- Preserved User Incentives: Users maintain their motivation for state cleanup.
EIP-7778 cleanly separates user incentives from block-wide resource constraints, aligning block gas usage more closely with the actual work performed.