EIP-161 State trie empty account clearing (State trie clearing (invariant-preserving alternative))
Final · EVM & execution · EIP status Final · created 2016-10-24
Changes the account creation and gas charging rules so that 'empty accounts' with no code, nonce, or balance are deleted from state at the end of a transaction, and so that new empty accounts can no longer be created.
Why it is needed
Ethereum keeps all account information in a data structure called the state trie, which every node stores. However, an 'empty account' with no code and with both nonce and balance at 0 could remain in state. Such an account serves no function while still taking up storage space. The security advisory cited in the source text notes that once the state cleanup is complete, empty accounts will no longer be a general concern, which shows that empty accounts were a real operational burden. EIP-158 was proposed earlier for the same purpose, but it had edge cases that broke existing invariants, such as a newly created account being deletable before it was even deployed. EIP-161 is an alternative that achieves the same cleanup while preserving those invariants. It deletes empty accounts at the end of a transaction and introduces four rules to prevent new empty accounts from being created in the first place. This EIP was included in the Spurious Dragon hard fork (block 2,675,000) and applied to mainnet.
What changes
Today
- Empty accounts with code, nonce, and balance all at 0 remain in the state trie
- 25,000 gas is charged when the target account of CALL or SUICIDE does not exist, even if no value is transferred
- A previously nonexistent account can be newly created in an empty state
- Contract accounts are also created with nonce 0
After EIP-161
- An account touched by a transaction is deleted from state if it is empty at the end of the transaction
- The 25,000 gas charge is applied only when a value greater than 0 is transferred and the target is a dead account
- No operation can move an account from nonexistent to 'existing but empty'
- An account created via CREATE starts with its nonce already incremented by 1 before the initialization code runs
Who is affected
- Node operators: Empty accounts that serve no purpose are removed from the state trie, cleaning up the state that every node must store.
- Client teams: Definitions such as touched, empty, and dead, along with the timing of deletion and handling during state rollback, must all be implemented identically across the four rules. A consensus bug actually occurred in 2016 due to implementation differences.
- Contract developer: A contract account deployed via CREATE starts its nonce at 1 instead of 0. A transfer of value 0 alone does not incur the cost of creating a new account.
In depth
Rule a: Start the nonce at 1 upon CREATE
Account creation transactions and the CREATE operation set the new account's nonce to 1 more than the default starting value before executing the initialization code. On the main network this simply becomes 1, while on test networks with a nonstandard default starting nonce the value differs. The rationale explains that the reason for not leaving the nonce at 0 is to avoid the odd situation where an account being created via CREATE is classified as empty and becomes subject to deletion during its own creation.
Rule b: Narrow the condition for charging 25,000 gas
Previously, 25,000 gas was charged whenever the target of CALL or SUICIDE was a nonexistent account. Now it is charged only when the operation transfers a value greater than 0 and the target account is dead. Dead means an account that is either nonexistent or empty. Therefore this cost is not incurred for a zero-value transfer.
Rule c: Prohibit transitioning from nonexistent to empty
No operation can move an account from a nonexistent state to an 'existing but empty' state. If an operation would otherwise produce that result, the account remains nonexistent instead. While rule d is responsible for removing existing empty accounts, this rule is responsible for preventing new empty accounts from arising in the first place.
Rule d: Delete touched empty accounts at the end of a transaction
An account touched by transaction execution is moved to a nonexistent state, i.e. deleted, if it is empty at the end of the transaction. Touched refers to involvement in an operation that could potentially change state, including being the recipient of a zero-value transfer. Empty means an account with no code, nonce 0, and balance 0. Cases where an account is considered to have 'changed state' include being the target or refund recipient of a SUICIDE for a value of 0 or more, being the source or destination of a CALL or message-call transaction, being the source or creation target of a CREATE or contract-creation transaction, and receiving block rewards or fees as the block's producer. The 'end of the transaction' is right after the suicide list is executed and before the state trie root to be placed in the receipt is determined.
Four contexts implementations must track
According to the Notes in the source text, under the current protocol there are not many paths by which an empty account can remain after transaction execution, so implementations need to track only four situations: an empty account receiving a zero value via CALL, via SUICIDE, via a message-call transaction, or via a fee transfer when the gas price is 0.
Difference from EIP-158: preserving invariants
The Rationale explains that this proposal is equivalent to EIP-158 but avoids several edge cases because it does not break invariants. Specifically, the invariant that a newly created account cannot be deleted before it is deployed is preserved. Starting the nonce at a nonzero value on CREATE is also a safeguard to eliminate the possibility of an account being mistakenly treated as subject to deletion while it is still being created.
The 2016-11-24 consensus bug and the specification patch
On November 24, 2016, a consensus bug occurred because two implementations behaved differently during a state rollback. Geth failed to roll back an empty-account deletion when the transaction that caused it ended in an out-of-gas exception, and Parity made the same mistake in a more limited context involving out-of-gas calls to precompiled contracts. Geth was subsequently fixed to match Parity's behavior, and on August 15, 2017 the specification was updated to state explicitly that empty-account deletions are rolled back along with state rollbacks. This EIP was included in the Spurious Dragon hard fork (block 2,675,000, mainnet CHAIN_ID 1) and its status is Final.