Ethereum addresses are currently only 160 bits long. This means it is possible to create a collision between a contract account and an Externally Owned Account (EOA) using an estimated
2**80 computing operations, which is feasible now given a large budget (ca. 10 billion USD). The fix in this EIP prevents the worst possible attack, where a safe looking contract (e.g. a token wrapper or an AMM-type contract) is deployed to attract user funds, which can then be spent using the EOA key for the same address. The fix is to never allow to use an address that already has code deployed as an EOA address.
# Generating address collisions
By creating keys for
2**80 EOAs and simulating the deployment of
2**80 contracts from these EOAs (one each), one expects to find about one collision where an EOA has the same address as one contract.
This very simple form of the attack requires the storage of
2**80 addresses, which is a practical barrier: It would require
2.4*10**25 bytes of memory (24 Yottabyte). However, there are cycle finding algorithms that can perform the collision search without requiring large amounts of storage. An estimate for the complexity has been made here (opens new window). We estimate that a collision between a contract and an EOA could be found in about one year with an investment of ca. US$10 billion in hardware and electricity.
There is currently a discussion to move to 256-bit addresses on Ethereum, which would increase collision resistance to a complexity of
2**128 which is currently thought infeasible for the foreseeable future. However, with 160 bit addresses, the collision problem can be effectively solved now, as demonstrated above.
Most attacks that can occur via address collisions are quite impractical: They involve users sending funds to an address before a contract is deployed. This is a very rare application in practice and users can easily circumvent the attack by never sending funds to a contract until it has been safely deployed with enough confirmations.
However, the yellow paper does not explicitly specify how a client should handle the case where a transaction is sent from an account that already has contract code deployed; presumably because this was considered infeasible at the time. The assumption is that most client would allow this transaction in their current state.
This EIP is to specify this behaviour to always forbid such transactions. This fixes most realistic or serious attacks due to address collisions.
Any transaction where
tx.sender has a
CODEHASH != EMPTYCODEHASH MUST be rejected as invalid, where
EMPTYCODEHASH = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470.
The invalid transaction MUST be rejected by the client and not be included in a block.
A block containing such a transaction MUST be considered invalid.
We note that it was always the expected that a contract account's behaviour is constrainted by the code in that contract -- which means that the account's funds should not suddenly be spendable by some private key. It was just implicitly assumed in the past that a 160 bit address length is enough to provide collision resistance, and thus that this case could never occur. In that sense, this EIP should be seen as a clarification of protocol behaviour in a previously undefined case rather than an explicit upgrade of consensus rules.
This does not exclude all possible attack vectors, only the most serious one. Further possible attack vectors via address collisions between contracts and EOAs are:
- An attacker can convince a user to send funds to an account before it is deployed. Some applications require this behaviour (e.g. state channels).
- A chain reorg can happen after a contract is deployed. If the reorg removes the contract deployment transaction the funds can still be accessed using the private key.
- A contract can self desctruct, with the stated intention that ERC20s (or other tokens) in the contract would be burned. However, they can now be accessed by a key for that address.
All these scenarios are much harder to exploit for an attacker, and likely have much lower yield making the attacks unlikely to be economically viable.
# Backwards Compatibility
It is unlikely that an attack like this has already occurred on the Ethereum mainnet, or we would very likely have heard of it. It is inconceivable that someone would use this as a "feature" to make a contract an EOA at the same time, when they could simply do this by adding some methods to the contract instead of spending billions on building hardware to find hash collisions.
Private networks may have deployed contracts which also work as EOAs at genesis and should check that this upgrade does not impact their workflows.
Clients might choose to disable this rule for RPC calls like
eth_estimateGas as some Multi-Sig contracts use these calls to create transactions as if they originated from the multisig contract itself.
# Test Cases
Given a genesis allocation of
Address: 0x71562b71999873DB5b286dF957af199Ec94617F7 Balance: 1000000000000000000 // 1 ether Nonce: 0, Code: 0xB0B0FACE",
Every transaction sent by the private key corresponding to
b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291) should be rejected.
These transaction must be rejected and not included in a block.
# Reference Implementation
The following check must be added to the state transition checks after checking that the nonce of the sender is correct. The sender is the address recovered from the signature of the transaction.
// Make sure the sender is an EOA Set ch to the CodeHash of the sender account if ch is not equal to EmptyCodeHash then return ErrSenderNoEOA end if
A diff to implement EIP-3607 in go-ethereum can be found here
# Security Considerations
This EIP is a strict security upgrade: It simply makes some transactions that were formerly valid now invalid. There is no legitimate use for such transactions, so there should be no security downsides.
This EIP can be implemented as a soft fork because the new validity rules are a strict superset of the previous validity rules.
Copyright and related rights waived via CC0 (opens new window).