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

Update EIP-4788: post audit tweaks #7672

Merged
merged 8 commits into from
Sep 26, 2023
58 changes: 33 additions & 25 deletions EIPS/eip-4788.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@ restaking constructions, smart contract bridges, MEV mitigations and more.
| constants | value |
|--- |--- |
| `FORK_TIMESTAMP` | TBD |
| `HISTORY_BUFFER_LENGTH` | `98304` |
| `HISTORY_BUFFER_LENGTH` | `8191` |
| `SYSTEM_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffe` |
| `BEACON_ROOTS_ADDRESS` | `0xbEac00dDB15f3B6d645C48263dC93862413A222D` |
| `BEACON_ROOTS_ADDRESS` | `0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02` |
Copy link
Member

Choose a reason for hiding this comment

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

Why was the address changed?


### Background

Expand Down Expand Up @@ -87,6 +87,7 @@ The beacon roots contract has two operations: `get` and `set`. The input itself

* Callers provide the `timestamp` they are querying encoded as 32 bytes in big-endian format.
* If the input is not exactly 32 bytes, the contract must revert.
* If the input is equal to 0, the contract must revert.
* Given `timestamp`, the contract computes the storage index in which the timestamp is stored by computing the modulo `timestamp % HISTORY_BUFFER_LENGTH` and reads the value.
* If the `timestamp` does not match, the contract must revert.
* Finally, the beacon root associated with the timestamp is returned to the user. It is stored at `timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH`.
Expand All @@ -109,6 +110,9 @@ def get():
if len(evm.calldata) != 32:
evm.revert()

if to_uint256_be(evm.calldata) == 0:
evm.revert()

timestamp_idx = to_uint256_be(evm.calldata) % HISTORY_BUFFER_LENGTH
timestamp = storage.get(timestamp_idx)

Expand All @@ -130,21 +134,13 @@ def set():

##### Bytecode

The exact initcode to deploy is shared below.
The exact contract bytecode is shared below.

```asm
push1 0x58
dup1
push1 0x09
push0
codecopy
push0
return

caller
push20 0xfffffffffffffffffffffffffffffffffffffffe
eq
push1 0x44
push1 0x4d
jumpi

push1 0x20
Expand All @@ -158,24 +154,29 @@ push0
revert

jumpdest
push3 0x018000
push0
calldataload
mod
dup1
iszero
push1 0x49
jumpi

push3 0x001fff
dup2
mod
swap1
dup2
sload
push0
calldataload
eq
push1 0x37
push1 0x3c
jumpi

push0
push0
revert

jumpdest
push3 0x018000
push3 0x001fff
Copy link
Member

Choose a reason for hiding this comment

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

This should be push2 now.

Copy link
Contributor

Choose a reason for hiding this comment

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

yeah, this was a miss. However, not worth fixing, the runtime execution gascost is identical, the only difference is that the code is one byte larger than it would have needed to be.

Copy link
Member

Choose a reason for hiding this comment

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

This repeats 4x so 4 bytes wasted. Forever :)

Copy link

@namiloh namiloh Sep 28, 2023

Choose a reason for hiding this comment

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

Yeah. Now there are 32 bits less left in the world.

🚻 ☮️

add
sload
push0
Expand All @@ -185,7 +186,12 @@ push0
return

jumpdest
push3 0x018000
push0
push0
revert

jumpdest
push3 0x001fff
timestamp
mod
timestamp
Expand All @@ -194,7 +200,7 @@ sstore
push0
calldataload
swap1
push3 0x018000
push3 0x001fff
add
sstore
stop
Expand All @@ -210,20 +216,22 @@ by working backwards from the desired deployment transaction:
"type": "0x0",
"nonce": "0x0",
"to": null,
"gas": "0x27eac",
"gas": "0x3d090",
"gasPrice": "0xe8d4a51000",
"maxPriorityFeePerGas": null,
"maxFeePerGas": null,
"value": "0x0",
"input": "0x60588060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604457602036146024575f5ffd5b620180005f350680545f35146037575f5ffd5b6201800001545f5260205ff35b6201800042064281555f359062018000015500",
"input": "0x60618060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762001fff810690815414603c575f5ffd5b62001fff01545f5260205ff35b5f5ffd5b62001fff42064281555f359062001fff015500",
"v": "0x1b",
"r": "0x539",
"s": "0x133700f3a77843802897db",
"hash": "0x14789a20c0508b81ab7a0287a12a3a41ca960aa18244af8e98689e37ed569f07"
"s": "0x1b9b6eb1f0",
"hash": "0xdf52c2d3bbe38820fff7b5eaab3db1b91f8e1412b56497d88388fb5d4ea1fde0"
}
```

The sender of the transaction can be calculated as `0x3e266d3c3a70c238bdddafef1ba06fbd58958d70`. The address of the first contract deployed from the account is `rlp([sender, 0])` which equals `0xbEac00dDB15f3B6d645C48263dC93862413A222D`. This is how `BEACON_ROOTS_ADDRESS` is determined. Although this style of contract creation is not tied to any specific initcode like create2 is, the synthetic address is cryptographically bound to the input data of the transaction (e.g. the initcode).
Note, the input in the transaction has a simple constructor prefixing the desired runtime code.

The sender of the transaction can be calculated as `0x0B799C86a49DEeb90402691F1041aa3AF2d3C875`. The address of the first contract deployed from the account is `rlp([sender, 0])` which equals `0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02`. This is how `BEACON_ROOTS_ADDRESS` is determined. Although this style of contract creation is not tied to any specific initcode like create2 is, the synthetic address is cryptographically bound to the input data of the transaction (e.g. the initcode).

### Block processing

Expand Down