Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

EIP: Reject transactions from senders with deployed code #3607

Merged
merged 10 commits into from
Jun 11, 2021
94 changes: 94 additions & 0 deletions EIPS/eip-3607.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
---
eip: 3607
title: Reject transactions from senders with deployed code
author: Dankrad Feist (@dankrad), Dmitry Khovratovich (@khovratovich), Marius van der Wijden (@MariusVanDerWijden)
discussions-to: https://github.com/ethereum/EIPs/issues/3608
status: Draft
type: Standards Track
category: Core
created: 2021-06-10
---

## Simple Summary

Do not allow transactions for which `tx.sender` has any code deployed, i.e. `tx.sender` has `CODESIZE != 0`

## 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](https://hackmd.io/Vzhp5YJyTT-LhWm_s0JQpA). 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 `CODESIZE != 0` MUST be rejected as invalid.

## Rationale

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:
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 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.
Copy link

@3sGgpQ8H 3sGgpQ8H Jun 15, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proposed solution doesn't solve the problem for those token contracts, that do implement EIP-2612, as well as for other contracts that rely on the ecrecover function. A very dirty way to fix this would be to modify the behavior of the ecrecover function to never return an address where any code is deployed.

Another attack scenario, the proposed solution doesn't prevent, is when an attacker approves token transfer from an address before deploying a contract at this address. However, preparation to such attack could be detected, as the attack requires a contract to be deployed at an address, that already has some outgoing transactions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please leave comments in the discussions-to link at the top of the EIP. Messages left here are unlikely to be seen.


## Backwards Compatibility

It is unlikely that an attack like this has already occured 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.
dankrad marked this conversation as resolved.
Show resolved Hide resolved

Private networks may have deployed contracts which also work as EOAs at genesis and should check that this upgrade does not impact their workflows.

## Test Cases

Given a genesis allocation of
```
Address: 0x71562b71999873DB5b286dF957af199Ec94617F7
Balance: 1000000000000000000 // 1 ether
Nonce: 0,
Code: 0xB0B0FACE",
```
Every transaction send by the private key corresponding to `0x715656...` (
`b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291`) fails.

A set of test cases can be found [here](https://github.com/ethereum/tests/pull/879)

## Reference Implementation

The following check must be added to the state transition checks after checking that the nonce of the sender is correct.
```go
// Make sure the sender is an EOA
if codesize := st.state.GetCodeSize(st.msg.From()); codesize != 0 {
return ErrSenderNoEOA
}
```
Comment on lines +77 to +82
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider writing this in pseudocode or a more well known/easier to read language than Go. Also, consider extracting the assignment out of the conditional for a bit more clarity/readability.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.


An implementation in go-ethereum can be found [here](https://github.com/ethereum/go-ethereum/pull/23002)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though we are no longer blocking PRs that include external links to transient things, I still recommend keeping these out of the EIP (same for similar links above).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This link in particular would not be transient -- however the links to Hackmd would. What is the preferred format of these references? We could add them as an appendix? Or push them to a blog with a permalink?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the most preferable method is to add a PDF or markdown to this repository to the text. Here is the format for doing that: https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1.md#auxiliary-files

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Text, JSON, PDF, code, etc. are all fine as assets, we just prefer they live permanently within the EIPs repository rather than living externally since organizations change names, repositories change names, GitHub may change its addressing format, etc. Also, someone should be able to read and understand this EIP in isolation without having context about go-ethereum, Go, etc.


## Security Considerations

This EIP is a strict security upgrade: It simply makes some transactions that were formely valid now invalid. There is no legitimate use for such transactions, so there should be no security downsides.
dankrad marked this conversation as resolved.
Show resolved Hide resolved

This EIP can be implemented as a soft fork because the new validity rules are a strict superset of the previous validity rules.


## Copyright
Copyright and related rights waived via [CC0](https://creativecommons.org/publicdomain/zero/1.0/).