diff --git a/EIPS/eip-4788.md b/EIPS/eip-4788.md index e0678e4ca276ed..0b01d2ac90d88c 100644 --- a/EIPS/eip-4788.md +++ b/EIPS/eip-4788.md @@ -29,7 +29,7 @@ restaking constructions, smart contract bridges, MEV mitigations and more. | constants | value | |--- |--- | | `FORK_TIMESTAMP` | TBD | -| `HISTORICAL_ROOTS_MODULUS` | `98304` | +| `HISTORY_BUFFER_LENGTH` | `98304` | | `SYSTEM_ADDRESS` | `0xfffffffffffffffffffffffffffffffffffffffe` | | `BEACON_ROOTS_ADDRESS` | `0xbEac00dDB15f3B6d645C48263dC93862413A222D` | @@ -87,15 +87,15 @@ 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. -* Given `timestamp`, the contract computes the storage index in which the timestamp is stored by computing the modulo `timestamp % HISTORICAL_ROOTS_MODULUS` and reads the value. +* 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 % HISTORICAL_ROOTS_MODULUS + HISTORICAL_ROOTS_MODULUS`. +* Finally, the beacon root associated with the timestamp is returned to the user. It is stored at `timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH`. ##### `set` * Caller provides the parent beacon block root as calldata to the contract. -* Set the storage value at `header.timestamp % HISTORICAL_ROOTS_MODULUS` to be `header.timestamp` -* Set the storage value at `header.timestamp % HISTORICAL_ROOTS_MODULUS + HISTORICAL_ROOTS_MODULUS` to be `calldata[0:32]` +* Set the storage value at `header.timestamp % HISTORY_BUFFER_LENGTH` to be `header.timestamp` +* Set the storage value at `header.timestamp % HISTORY_BUFFER_LENGTH + HISTORY_BUFFER_LENGTH` to be `calldata[0:32]` ##### Pseudocode @@ -109,20 +109,20 @@ def get(): if len(evm.calldata) != 32: evm.revert() - timestamp_idx = to_uint256_be(evm.calldata) % HISTORICAL_ROOTS_MODULUS + timestamp_idx = to_uint256_be(evm.calldata) % HISTORY_BUFFER_LENGTH timestamp = storage.get(timestamp_idx) if timestamp != evm.calldata: evm.revert() - root_idx = timestamp_idx + HISTORICAL_ROOTS_MODULUS + root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH root = storage.get(root_idx) evm.return(root) def set(): - timestamp_idx = to_uint256_be(evm.timestamp) % HISTORICAL_ROOTS_MODULUS - root_idx = timestamp_idx + HISTORICAL_ROOTS_MODULUS + timestamp_idx = to_uint256_be(evm.timestamp) % HISTORY_BUFFER_LENGTH + root_idx = timestamp_idx + HISTORY_BUFFER_LENGTH storage.set(timestamp_idx, evm.timestamp) storage.set(root_idx, evm.calldata) @@ -260,7 +260,7 @@ e.g. with a singleton state root contract that caches the proof per slot). ### Why two ring buffers? -The first ring buffer only tracks `HISTORICAL_ROOTS_MODULUS` worth of roots and so for all possible timestamp values would consume a constant amount of storage. +The first ring buffer only tracks `HISTORY_BUFFER_LENGTH` worth of roots and so for all possible timestamp values would consume a constant amount of storage. However, this design opens the precompile to an attack where a skipped slot that has the same value modulo the ring buffer length would return an old root value, rather than the most recent one.