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-2935: Update EVM bytecode to add the system set update op #8596

Merged
merged 5 commits into from
Jun 9, 2024
Merged
Changes from all commits
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
49 changes: 35 additions & 14 deletions EIPS/eip-2935.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@ A side benefit of this approach could be that it allows building/validating proo
| Parameter | Value |
| - | - |
| `FORK_TIMESTAMP` | TBD |
| `HISTORY_STORAGE_ADDRESS` | `0x25a219378dad9b3503c8268c9ca836a52427a4fb`|
| `HISTORY_SERVE_WINDOW` | `8192` |
| `BLOCKHASH_OLD_WINDOW` | `256` |
| `SYSTEM_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffe` |
| `HISTORY_STORAGE_ADDRESS` | `0x0aae40965e6800cd9b1f4b05ff21581047e3f91e`|

This EIP specifies for storing last `HISTORY_SERVE_WINDOW` block hashes in a ring buffer storage of `HISTORY_SERVE_WINDOW` length.

Expand All @@ -50,14 +51,21 @@ The `BLOCKHASH` opcode semantics remains the same as before.
Exact evm assembly that can be used for the contract to resolve `BLOCKHASH`

```
// if system call then jump to the set operation
caller
push20 0xfffffffffffffffffffffffffffffffffffffffe
eq
push1 0x57
jumpi

// check if input > 8 byte value and revert if this isn't the case
// the check is performed by comparing the biggest 8 byte number with
// the call data, which is a right-padded 32 byte number.
push8 0xffffffffffffffff
push0
calldataload
gt
push1 0x39
push1 0x53
jumpi

// check if input > blocknumber-1 then return 0
Expand All @@ -67,7 +75,7 @@ sub
push0
calldataload
gt
push1 0x31
push1 0x4b
jumpi

// check if blocknumber > input + 8192 then return 0, no overflow expected for input of 8 bytes
Expand All @@ -77,11 +85,11 @@ push2 0x2000
add
number
gt
push1 0x31
push1 0x4b
jumpi

// mod 8192 and sload
push2 0x1FFF
push2 0x1fff
push0
calldataload
and
Expand All @@ -94,7 +102,7 @@ push1 0x20
push0
return

// return 0
// 0x4b: return 0
jumpdest
push0
push0
Expand All @@ -103,21 +111,34 @@ push1 0x20
push0
return

// revert
// 0x53: revert
jumpdest
push0
push0
revert

// 0x57: set op - sstore the input to number-1 mod 8192
jumpdest
push0
calldataload
push2 0x1fff
push1 0x1
number
sub
g11tech marked this conversation as resolved.
Show resolved Hide resolved
and
sstore

stop
```

Note that the input contract read `32` bytes input as `calldataload`. Users and clients doing EVM call to this contract should left pad the `arg` correctly.
Corresponding bytecode:
`0x3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500`

<!-- TODO: bytecode is based off on first version and will be updated once assembly is locked down as it changes contract sender and address -->
#### Contract `get` and `set` mechanism

Corresponding bytecode:
`60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00`
Similar to [EIP-4788](./eip-4788.md) above contract provides a `set` mechanism which clients can choose to update the block's parent hash in the ring buffer instead of direct state update. For this clients should call this contract with `SYSTEM_ADDRESS` as caller and provide `32` bytes parent block hash as input.
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
Similar to [EIP-4788](./eip-4788.md) above contract provides a `set` mechanism which clients can choose to update the block's parent hash in the ring buffer instead of direct state update. For this clients should call this contract with `SYSTEM_ADDRESS` as caller and provide `32` bytes parent block hash as input.
Similar to [EIP-4788](./eip-4788.md) above contract provides a `set` mechanism which clients can choose to update the block's parent hash in the ring buffer instead of direct state update. For this clients should call this contract with `SYSTEM_ADDRESS` as caller and provide `32` bytes parent block hash as input.
Note that the inputs to the `set` method are not sanitized and it is the caller's responsibility to ensure that the ring buffer isn't overrun. This choice was made to support a change in the ring buffer size without having to redeploy a new contract.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

we will also need to change the get method as well. but there is another consideration:

the contracts that would directly call the contract would break if we modify ring buffer length and expcted them to mod the input in a new way


If caller is not `SYSTEM_ADDRESS` the contract treats it as `get` with contract reading `32` bytes input via `calldataload` as the `arg` to resolve the block hash for. Users and clients doing `get` EVM call should left pad the `arg` correctly.

#### Deployment

Expand All @@ -133,17 +154,17 @@ A special synthetic address is generated by working backwards from the desired d
"maxPriorityFeePerGas": null,
"maxFeePerGas": null,
"value": "0x0",
"input": "0x60368060095f395ff360203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00",
"input": "0x60648060095f395ff33373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500",
"v": "0x1b",
"r": "0x539",
"s": "0x1b9b6eb1f0",
"hash": "7ba81426bfa88a2cf4ea5c9abbbe83619505acd1173bc8450f93cf17cde3784b",
"hash": "0x3c769a03d6e2212f1d26ab59ba797dce0900df29ffd23c1dd391fd6b217973ad",
}
```

Note, the input in the transaction has a simple constructor prefixing the desired runtime code.

The sender of the transaction can be calculated as `0xa4690f0ed0d089faa1e0ad94c8f1b4a2fd4b0734`. The address of the first contract deployed from the account is `rlp([sender, 0])` which equals `0x25a219378dad9b3503c8268c9ca836a52427a4fb`. This is how `HISTORY_STORAGE_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 `0xe473f7e92ba2490e9fcbbe8bb9c3be3adbb74efc`. The address of the first contract deployed from the account is `rlp([sender, 0])` which equals `0x0aae40965e6800cd9b1f4b05ff21581047e3f91e`. This is how `HISTORY_STORAGE_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).


Some activation scenarios:
Expand Down
Loading