From aa563a36a0aba406a6800b346071d9dd5d037002 Mon Sep 17 00:00:00 2001 From: Alex Stokes Date: Thu, 1 Jun 2023 12:57:13 -0600 Subject: [PATCH] bound state growth of beacon root contract --- EIPS/eip-4788.md | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/EIPS/eip-4788.md b/EIPS/eip-4788.md index 74521bc1d2dba..d960a41eca3cd 100644 --- a/EIPS/eip-4788.md +++ b/EIPS/eip-4788.md @@ -30,6 +30,7 @@ restaking constructions, smart contract bridges, MEV mitigations and more. | `FORK_TIMESTAMP` | TBD | | `HISTORY_STORAGE_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffd` | | `G_beacon_root` | 2100 | gas +| `HISTORY_ACCUMULATOR_LENGTH` | 98304 | ### Background @@ -53,37 +54,39 @@ Beginning at the execution timestamp `FORK_TIMESTAMP`, execution clients **MUST* 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 from the header is used as a key into the contract's storage. +The timestamp (a 64-bit unsigned integer value) is encoded as 32 bytes in big-endian format when used as this key into the storage. In Python pseudocode: ```python +timestamp_key = block_header.timestamp % HISTORY_ACCUMULATOR_LENGTH +key = to_uint256_be(timestamp_key) 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. -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. 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 root of the corresponding 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_data = evm.calldata[:32] +timestamp = to_uint64_be(timestamp_data) % HISTORY_ACCUMULATOR_LENGTH +key = to_uint256_be(timestamp) +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 root stored at the given timestamp, the opcode follows the existing EVM semantics of `sload` returning `0`. ## Rationale