Alert Source Discuss
Standards Track: Core

EIP-3607: Reject transactions from senders with deployed code

Do not allow transactions for which `tx.sender` has any code deployed.

Authors Dankrad Feist (@dankrad), Dmitry Khovratovich (@khovratovich), Marius van der Wijden (@MariusVanDerWijden)
Created 2021-06-10

Abstract

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.

Motivation

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. 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.

Background

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.

Specification

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.

Rationale

We note that it was always the expected that a contract account’s behaviour is constrained 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:

  1. 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).
  2. 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.
  3. A contract can self destruct, 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_call and 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 0x715656... ( 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.

Citation

Please cite this document as:

Dankrad Feist (@dankrad), Dmitry Khovratovich (@khovratovich), Marius van der Wijden (@MariusVanDerWijden), "EIP-3607: Reject transactions from senders with deployed code," Ethereum Improvement Proposals, no. 3607, June 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3607.