Skip to content

Commit

Permalink
write roots into ring buffer
Browse files Browse the repository at this point in the history
  • Loading branch information
ralexstokes committed Jun 16, 2023
1 parent a9e7891 commit 2cafd5e
Showing 1 changed file with 23 additions and 12 deletions.
35 changes: 23 additions & 12 deletions EIPS/eip-4788.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ restaking constructions, smart contract bridges, MEV mitigations and more.
| `FORK_TIMESTAMP` | TBD |
| `HISTORY_STORAGE_ADDRESS` | `Bytes20(0xB)` |
| `G_beacon_root` | 2100 | gas
| `HISTORICAL_ROOTS_LENGTH` | 98304 |

### Background

Expand All @@ -52,37 +53,47 @@ Validity is guaranteed from the consensus layer, much like how withdrawals are h
At the start of processing any execution block where `block.timestamp >= FORK_TIMESTAMP` (i.e. before processing any transactions),
write the parent beacon root provided in the block header into the storage of the contract at `HISTORY_STORAGE_ADDRESS`.

The root itself is used as a key into the contract's storage and the timestamp of the header is written as the key's value.
The timestamp (a 64-bit unsigned integer value) is encoded as 32 bytes in big-endian format.
The timestamp (a 64-bit unsigned integer value) of the header is used as a key into the contract's storage.
To map the timestamp to the correct key, the timestamp as a number is reduced modulo `HISTORICAL_ROOTS_LENGTH` and
this resulting 64-bit unsigned integer should be encoded as 32 bytes in big-endian format when writing to the storage.

The 32 bytes of the `parent_beacon_block_root` (as provided) are the
value to write in the contract's storage.

In Python pseudocode:

```python
timestamp_reduced = block_header.timestamp % HISTORICAL_ROOTS_LENGTH
key = to_uint256_be(timestamp_reduced)

parent_beacon_block_root = block_header.parent_beacon_block_root
timestamp = to_uint256_be(block_header.timestamp)

sstore(HISTORY_STORAGE_ADDRESS, parent_beacon_block_root, timestamp)
sstore(HISTORY_STORAGE_ADDRESS, key, parent_beacon_block_root)
```

#### New stateful precompile

Beginning at the execution timestamp `FORK_TIMESTAMP`, the code and storage at `HISTORY_STORAGE_ADDRESS` constitute a "stateful" precompile.
Beginning at the execution timestamp `FORK_TIMESTAMP`, a "stateful" precompile is deployed at `HISTORY_STORAGE_ADDRESS`.

Callers of the precompile should provide the `root` they are querying encoded as 32 bytes.
Callers of the precompile should provide the `timestamp` they are querying encoded as 32 bytes in big-endian format.
This `timestamp` is reduced in the same way to point to a unique storage location into the ring buffer from any given block.

Alongside the existing gas for calling the precompile, there is an additional gas cost of `G_beacon_root` cost to reflect the implicit `SLOAD` from
the precompile's state. The timestamp of the corresponding root is returned as 32 bytes in the caller's provided return buffer and represents the
64-bit unsigned integer from the header in big-endian format.
the precompile's state.

The parent beacon block root for the given timestamp is returned as 32 bytes in the caller's provided return buffer.

In pseudocode:

```python
root = evm.calldata[:32]
timestamp = sload(HISTORY_STORAGE_ADDRESS, root)
evm.returndata[:32].set(timestamp)
timestamp = evm.calldata[:32]
timestamp_reduced = to_uint64_be(timestamp) % HISTORICAL_ROOTS_LENGTH
key = to_uint32_be(timestamp_reduced)
root = sload(HISTORY_STORAGE_ADDRESS, key)
evm.returndata[:32].set(root)
```

If there is no timestamp stored at the given root, the opcode follows the existing EVM semantics of `sload` returning `0`.
If there is no timestamp stored at the given root, the opcode follows the existing EVM semantics of `SLOAD` returning `0`.

## Rationale

Expand Down

0 comments on commit 2cafd5e

Please sign in to comment.