Meter Contract Code Size
Adds gas metering to contract code loading beyond 24KB
Abstract
This EIP adds gas metering for excess code loading, introducing a gas cost of 2 gas per (32 byte) word for contract code exceeding 24KB (24576 bytes). It builds on EIP-7954, which raises the contract code size limit to 64KB (65536 bytes) and the initcode size limit to 128KB (131072 bytes), without changing either limit.
Motivation
EIP-170 introduced a 24KB contract code size limit to prevent potential DoS attacks, as large contract code requires O(n) resource cost in terms of disk reads, VM preprocessing, and Merkle proof sizes, all of which are not directly compensated by gas fees. EIP-7954 raises this limit to 64KB, allowing larger contracts to be deployed.
This EIP ensures that users loading large contracts pay gas proportional to the additional resources they consume. This approach aligns with Ethereum's gas model philosophy of paying for the resources consumed.
Specification
Definitions
| Name | Value | Description |
|---|---|---|
COLD_SLOAD_COST | 2100 | The cost charged for cold loading storage as defined by EIP-2929. |
WARM_STORAGE_READ_COST | 100 | The cost charged for loading warm storage as defined by EIP-2929. |
COLD_ACCOUNT_ACCESS_COST | 2600 | The cost charged for loading a cold account as defined by EIP-2929. |
GAS_PER_CODE_WORD | 2 | The cost charged per word of code loaded beyond the initial 24KB amount. |
FORK_BLKNUM | TBD | The block number of the hard fork that this EIP is activated. |
The MAX_CODE_SIZE and MAX_INITCODE_SIZE limits remain as specified in EIP-7954.
Helpers
def ceil32(n: int) -> int:
return ((n + 31) // 32) * 32
def excess_code_size(n: int) -> int:
return max(0, n - 0x6000)Behavior
- Introduces a new cold/warm state for contract code. Specifically, change the gas schedule of operations that load code, e.g. the opcodes
CALL,STATICCALL,DELEGATECALL,CALLCODEandEXTCODECOPYare modified so that dynamicEXCESS_CODE_COST= ceil32(excess_code_size(len(code))) * GAS_PER_CODE_WORD // 32gas are added to the access cost if the code is cold. When the code is an EIP-7702 delegation to another account, if target account code is cold add additional gas should be accounted. Warming of the contract code is subjected to the journaling and can be reverted similar to other state warming in EIP-2930. - If a large contract is the entry point of a transaction, the cost calculated in (1) is charged before the execution and contract code is marked as warm. This fee is not calculated towards the initial gas fee. In case of out-of-gas halt, execution will stop and the balance will not be transferred.
- Empty code ( with
keccak("") = "0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470") is always considered warm.
| Contract | Gas changes (only opcodes that load code) | How? |
|---|---|---|
| Cold account and code | Add COLD_SLOAD_COST=2100, EXCESS_CODE_COST, and COLD_ACCOUNT_ACCESS_COST=2600 | Contract not in access list nor accessed prior in the txn |
| Warm account and cold code | Add COLD_SLOAD_COST=2100, EXCESS_CODE_COST, and WARM_STORAGE_READ_COST=100 | Already accessed balance, storage, or included in access list (EIP-2930) |
| Warm account and code | WARM_STORAGE_READ_COST=100 | Already accessed account code |
COLD_ACCOUNT_ACCESS_COST, COLD_SLOAD_COST, and WARM_STORAGE_READ_COST are defined in EIP-2929.
Migration
This EIP adds a new field to the account tuple, codesize. That is, the account tuple goes from having the following four fields, (nonce, balance, storage_root, code_hash) to (nonce, balance, storage_root, code_hash, codesize). The reason for this is that most key-value databases in use by production clients do not allow peeking at the size of a value pointed to by a given key without actually loading the full contents of the value.
To avoid forcing a full migration, the following rules are followed:
- Any account created or updated on or after
FORK_BLKNUMshould additionally have its codesize written into the account tuple. - For any account which does not have the
codesizefield, the code size is determined from the length of its bytecode when needed for gas metering. Such accounts may contain code exceeding 24KB deployed after EIP-7954 activation.
Rationale
The gas cost of 2 per word was chosen to account for:
- The additional disk I/O for retrieving larger contract code
- The increased computational resources for preprocessing larger code for execution (a.k.a. "JUMPDEST analysis").
- The growth in Merkle proof sizes for blocks containing larger contracts
This EIP introduces the gas cost as an additional cost for contracts exceeding 24KB. It could have been specified as a simpler ceil32(contract_size) * GAS_PER_CODE_WORD // 32, without hardcoding the original EIP-170 contract size limit. However, for the sake of being conservative and avoiding lowering the cost of loading existing contracts (which could be small, under the 24KB limit), the 24KB floor was added to the formula.
The EXTCODECOPY opcode could theoretically be exempt from this, since clients could just load the parts of the bytecode which are actually requested. However, this might require a change at the protocol level, since the full code is required for the block witness. For this reason, EXTCODECOPY is included in the pricing scheme, and a carveout could be considered at a later date.
Backwards Compatibility
This EIP introduces additional gas costs for certain operations. Specifically, CALL, STATICCALL, DELEGATECALL, CALLCODE, EXTCODESIZE, and EXTCODECOPY may now require extra gas when accessing cold contract code.
Test Cases
Reference Implementation
Security Considerations
Copyright
Copyright and related rights waived via CC0.