Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 31 additions & 17 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` | `93600` |
| `SYSTEM_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffe` |
| `BEACON_ROOTS_ADDRESS` | `0xbEac00dDB15f3B6d645C48263dC93862413A222D` |
| `BEACON_ROOTS_ADDRESS` | `0xbEaC02f20e05eDcfcB49E623683E08dcbA550Ea3` |

### 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 @@ -133,7 +137,7 @@ def set():
The exact initcode to deploy is shared below.

```asm
push1 0x58
push1 0x61
dup1
push1 0x09
push0
Expand All @@ -144,7 +148,7 @@ return
caller
push20 0xfffffffffffffffffffffffffffffffffffffffe
eq
push1 0x44
push1 0x4d
jumpi

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

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

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

push0
push0
revert

jumpdest
push3 0x018000
push3 0x016da0
add
sload
push0
Expand All @@ -185,7 +194,12 @@ push0
return

jumpdest
push3 0x018000
push0
push0
revert

jumpdest
push3 0x016da0
timestamp
mod
timestamp
Expand All @@ -194,7 +208,7 @@ sstore
push0
calldataload
swap1
push3 0x018000
push3 0x016da0
add
sstore
stop
Expand All @@ -210,20 +224,20 @@ 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": "0x60618060095f395ff33373fffffffffffffffffffffffffffffffffffffffe14604d57602036146024575f5ffd5b5f35801560495762016da0810690815414603c575f5ffd5b62016da001545f5260205ff35b5f5ffd5b62016da042064281555f359062016da0015500",
"v": "0x1b",
"r": "0x539",
"s": "0x133700f3a77843802897db",
"hash": "0x14789a20c0508b81ab7a0287a12a3a41ca960aa18244af8e98689e37ed569f07"
"s": "0x133700018971c643803096",
Copy link
Contributor

Choose a reason for hiding this comment

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

Do the r and s values have any particular meaning? I'm more curious as to why they s value had to change. Was it searched to find the first valid signature of any address from "zero" or is there some other meaning?

Copy link
Member Author

Choose a reason for hiding this comment

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

The s value is like the "nonce" for our address generator. We keep trying new s values until we get a deploy address with beac02 prefix.

Copy link
Contributor

Choose a reason for hiding this comment

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

Got it.

Is there a canonical definition of what a synthetic address is and best practices to grind out and S value?

In this particular case (r being 1337 in decimal, and s being 0x1337 left shifted 72 bytes, and then search upwards from there) it is obvious it should not have a known public key. But I think the industry would benefit from a best practice for showing a transaction is a synthetic address transaction with a know r producing a corresponding s.

Copy link
Member Author

Choose a reason for hiding this comment

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

I think this post is the pinnacle of our knowledge on the subject and it does not give any explicit instructions: https://weka.medium.com/how-to-send-ether-to-11-440-people-187e332566b7

Copy link
Contributor

Choose a reason for hiding this comment

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

Are you talking about Nothing-up-my-sleeve numbers?

"hash": "0xe51c1d6c56467add9ab579bcda47a3057280dfdf1f8174a2b9b05a4e7346cf0d"
}
```

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).
The sender of the transaction can be calculated as `0x54049C55437B1a0b82C090655D4A45296641cAF4`. The address of the first contract deployed from the account is `rlp([sender, 0])` which equals `0xbEaC02f20e05eDcfcB49E623683E08dcbA550Ea3`. 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