EIP-1884 Rebalancing gas costs for state size dependent instructions (Repricing for trie-size-dependent opcodes)

Final · Fees & gas · EIP status Final · created 2019-03-28

Raises the gas cost of the state reading instructions SLOAD, BALANCE, and EXTCODEHASH, and adds a new instruction, SELFBALANCE, that reads the caller's own balance for 5 gas.

Why it is needed

As Ethereum's state has grown, some state reading instructions now consume far more resources (CPU time, memory, and so on) in practice than their priced cost reflects. When price and resource consumption diverge, two problems arise. First, an attacker can fill a block with underpriced instructions to excessively inflate block processing time. Second, blocks that use the same amount of gas end up finishing at very different speeds, making processing time inconsistent. In fact, measurements taken while fully syncing blocks with Geth showed that storage reads (storage_reads) and account reads (account_reads) accounted for the largest share of block processing time. When instruction prices are balanced with resource consumption, block processing time can stay stable even while using the full block gas limit.

What changes

Today

After EIP-1884

Who is affected

In depth

Measurement basis: SLOAD execution time rose again during a Geth full sync

Execution time for each opcode was aggregated in 10K block increments during a Geth full sync. In the 5 to 7 million block range, SLOAD climbed into the top ranks of heavy opcodes, and storage_reads and account_reads were the two largest contributors to overall block processing time. SLOAD's cost had been raised from 50 to 200 in EIP-150, dropping its execution time metric from about 67 to about 23, but it returned to pre-EIP-150 levels around block 5 million and by block 7 million averaged about 150, more than double its pre-increase level. Raising the cost fourfold (from 200 to 800) is expected to bring this down to around 40, but the source notes that without state clearing it could rise again, requiring further rebalancing. GASPRICE (0x3a) also ranks high, but unlike SLOAD and BALANCE, it can be eliminated through client side internal optimization.

BALANCE and EXTCODEHASH are aligned at 700 gas

BALANCE is an operation that fetches data from the state trie, and was raised from 20 to 400 gas in EIP-150. Among the account lookup instructions EXTCODESIZE and EXTCODEHASH, EXTCODESIZE is already 700, so BALANCE is raised to match at 700. EXTCODEHASH was priced at 400 when it was introduced in Constantinople via EIP-1052, on the grounds that it 'requires an account lookup like BALANCE', so raising BALANCE requires raising EXTCODEHASH together with it. Meanwhile, BALANCE mixes inherently cheap uses, such as looking up one's own (this) balance, with uses that require trie (disk) access, such as looking up an arbitrary account, resulting in a large spread in cost. The source notes that, in hindsight, it would have been better to split this into two opcodes with different prices: EXTBALANCE(address) and SELFBALANCE.

Specification of the new instruction SELFBALANCE (0x47)

SELFBALANCE pops 0 arguments from the stack and pushes the balance of the current address onto the stack. Its price is GasFastStep, 5 gas. The reason it costs 5 gas rather than the GasQuickStep (2 gas) used by similar lookup instructions is that the EVM execution engine still needs to perform one lookup against the cached trie, and balance, unlike gasPrice or timeStamp, can change during execution, adding its own extra overhead. The opcode number falls in the 0x4X range because the 0x3X range, where balance lookup type opcodes are clustered, is already full. Defining SELFBALANCE as 'BALANCE that uses its own address instead of popping an address from the stack' introduces no special edge cases, since BALANCE is already well defined.

Backwards compatibility: requires a hard fork and may break some contracts

This change requires a hard fork and has three consequences. First, certain calls become more expensive. Second, a default receive function that accesses storage within the 2,300 gas minimum always guaranteed on a call may run out of gas. Third, contracts that assume a fixed gas cost for calls or internal sections may stop working. ERC-165's supportsInterface returns a bool and is capped at a fixed 30,000 gas, and uses the affected opcodes, but the two example implementations at the time of writing used 586 gas (independent of input) and 236 gas (increasing proportionally with the number of supported interfaces) respectively, so exceeding the cap under the second approach would require supporting around thirty interfaces, making it unlikely. It is also noted that these operations have already been rebalanced before, so assuming a fixed gas cost for them should have been avoided in the first place.

Security considerations: the pattern of logging after receiving ether can fail

A recipient of ether via CALL commonly tries to record a LOG. LOG costs 375 gas plus 375 gas per topic. Combined with an SLOAD (800 gas), this can exceed 2,300 gas, causing some ether transfers to fail. The source also notes that it should be investigated whether Solidity has any hardcoded expectations about the gas costs of these operations. In terms of development patterns, the source's author expects a shift toward merging multiple modifiers that SLOAD the same value into one, or toward not logging SLOAD values that are not strictly necessary.

Status and tests: Final, and SELFBALANCE is invalid before Istanbul

This EIP's status is Final. The original text requires five tests: whether selfbalance returns the same value as balance(address), whether the cost of balance(this) is charged the same way as before, whether selfbalance does not pop a value off the stack, whether the gas costs of SLOAD, EXTCODEHASH, and SELFBALANCE match the specification, and whether SELFBALANCE is an invalid instruction on blocks before Istanbul. Some tests are implemented as state tests at github.com/holiman/IstanbulTests. The original text also includes example implementation code for SELFBALANCE in go-ethereum.

Original EIP · ← EIPs