-
Notifications
You must be signed in to change notification settings - Fork 5.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add EIP: Read BLOCKHASH from storage and update cost
Merged by EIP-Bot.
- Loading branch information
1 parent
f20b164
commit 0e03197
Showing
1 changed file
with
101 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
--- | ||
eip: 7709 | ||
title: Read BLOCKHASH from storage and update cost | ||
description: Read the `BLOCKHASH (0x40)` opcode from the EIP-2935 system contract storage and adjust its gas cost to reflect storage access. | ||
author: Vitalik Buterin (@vbuterin), Tomasz Stanczak (@tkstanczak), Guillaume Ballet (@gballet), Gajinder Singh (@g11tech), Tanishq Jasoria (@tanishqjasoria), Ignacio Hagopian (@jsign), Jochem Brouwer (@jochem-brouwer), Gabriel Rocheleau (@gabrocheleau) | ||
discussions-to: https://ethereum-magicians.org/t/eip-7709-read-blockhash-opcode-from-storage-and-adjust-gas-cost/20052 | ||
status: Draft | ||
type: Standards Track | ||
category: Core | ||
created: 2024-05-18 | ||
requires: 2935 | ||
--- | ||
|
||
## Abstract | ||
|
||
Update the `BLOCKHASH (0x40)` opcode to read and serve from the system contract storage and charge the **additional** (cold or warm) storage costs. | ||
|
||
## Motivation | ||
|
||
The `BLOCKHASH (0x40)` opcode currently assumes that the client has knowledge of the previous blocks, which in Verkle [EIP-6800](./eip-6800.md) would prevent stateless execution. However with [EIP-2935](./eip-2935.md) blockhashes can be retrieved and served from its system contract storage which allows Verkle blocks to include a storage access witness for stateless execution. | ||
|
||
## Specification | ||
|
||
| Parameter | Value | | ||
| ------------------------- | ------ | | ||
| `FORK_TIMESTAMP` | TBD | | ||
| `HISTORY_STORAGE_ADDRESS` | TBD | | ||
| `BLOCKHASH_SERVE_WINDOW` | `256` | | ||
|
||
The `BLOCKHASH` opcode semantics remains the same as before. From the `fork_block` (defined as `fork_block.timestamp >= FORK_TIMESTAMP and fork_block.parent.timestamp < FORK_TIMESTAMP`), the `BLOCKHASH` instruction should be updated to resolve block hash in the following manner: | ||
|
||
```python | ||
def resolve_blockhash(block: Block, state: State, arg: uint64): | ||
# note that outside the BLOCKHASH_SERVE_WINDOW we continue to return 0 | ||
# despite the 2935 history contract being able to serve more hashes | ||
if arg >= block.number or (arg + BLOCKHASH_SERVE_WINDOW) < block.number | ||
return 0 | ||
|
||
# performs an sload on arg % HISTORY_SERVE_WINDOW including gas charges, | ||
# warming effects as well as execution accesses | ||
# | ||
# note that the `BLOCKHASH_SERVE_WINDOW` and the 2935 ring buffer window | ||
# `HISTORY_SERVE_WINDOW` for slot calculation are different | ||
return state.load_slot(HISTORY_STORAGE_ADDRESS, arg % HISTORY_SERVE_WINDOW) | ||
``` | ||
|
||
ONLY if the `arg` is within the correct `BLOCKHASH` window, clients can choose to either | ||
|
||
* do a direct `SLOAD` from state, or | ||
* do a system call to [EIP-2935](./eip-2935.md) contract via its `get` mechanism (caller other than `SYSTEM_ADDRESS`) or | ||
* serve from memory or as per current designs if maintaining requisite history (full clients for e.g.) | ||
|
||
However the entire semantics and after effects of the `SLOAD` operation needs to be applied as per the current fork if the `arg` is within the correct `BLOCKHASH` window: | ||
|
||
* `SLOAD` gas costs (cold or warm) for the `arg % HISTORY_SERVE_WINDOW` slot. | ||
* `SLOAD` after effects on the slot (warming the slot) | ||
* `SLOAD` accesses added to execution witnesses if Verkle ([EIP-6800](./eip-6800.md) and [EIP-4762](./eip-4762.md)) is activated | ||
|
||
### Activation | ||
|
||
This EIP specifies the transition to the new logic assuming that [EIP-2935](./eip-2935.md) has been activated: | ||
|
||
* sufficiently ahead of this EIP's activation (>= `BLOCKHASH_SERVE_WINDOW`) or | ||
* at genesis for testnets/devnets where this EIP could also be activated at genesis | ||
|
||
The current proposal is to activate this EIP with Verkle to allow for stateless execution of the block. | ||
|
||
### Gas costs | ||
|
||
As described above, if the `arg` to be resolved is within the correct window, the corresponding `SLOAD` charges and accesses are to be applied for the slot `arg % HISTORY_SERVE_WINDOW`. Note that the `HISTORY_SERVE_WINDOW` and `BLOCKHASH_SERVE_WINDOW` are different. | ||
|
||
### Reading from the System contract | ||
|
||
Even if the clients choose to resolve `BLOCKHASH` through system call to [EIP-2935](./eip-2935.md) contract, the gas cost for the system code execution (and also the code witnesses if Verkle activated) is not applied. Only the effect of `SLOAD` is applied as described above. | ||
|
||
## Rationale | ||
|
||
* The reason behind the updated gas cost is to match the real operation, which is equivalent to an `SLOAD`. | ||
* The [EIP-2935](./eip-2935.md) system contract execution charges (and accesses) are not applied to keep the gas low and to keep things simple for clients which choose to resolve `BLOCKHASH` in other ways (directly or though memory/maintained history) | ||
|
||
Note that `BLOCKHASH` opcode only serves a limited `BLOCKHASH_SERVE_WINDOW` to be backward compatible (and to not extend the above exemptions). For deeper accesses one will need to directly call [EIP-2935](./eip-2935.md) system contract which will lead to a normal contract execution (as well as charges and accesses) | ||
|
||
## Backwards Compatibility | ||
|
||
This EIP introduces a significant increase in the cost of `BLOCKHASH`, which could break use-cases that rely on the previous gas cost. Also, this EIP introduces a breaking change in the case where less than `BLOCKHASH_SERVE_WINDOW` elapse between the [EIP-2935](./eip-2935.md) fork and this EIP's fork (unless [EIP-2935](./eip-2935.md) is activated in genesis for e.g. in testnets/devnets) as the [EIP-2935](./eip-2935.md) system contract would not have saved the required history. | ||
|
||
## Test Cases | ||
|
||
* If `BLOCKHASH` is not called or there is no [EIP-2935](./eip-2935.md) contract call by any transaction, only the [EIP-2935](./eip-2935.md) system update of the parent hash shows up in witnesses if Verkle is activated. | ||
* If `BLOCKHASH` is called, there MUST be a storage access gas charge (and corresponding access witness if Verkle is activated) for the storage slot but ONLY if the `BLOCKHASH` query is for the last `BLOCKHASH_SERVE_WINDOW` ancestors. This is irrespective of how the client chooses to resolve the `BLOCKHASH` (directly, via system contract or via memory) | ||
* The gas cost for each `BLOCKHASH` operation should still be charged, in addition to the `SLOAD` cost of each lookup (if performed) | ||
* If the [EIP-2935](./eip-2935.md) contract is called directly (i.e. not through `BLOCKHASH`), then the witness and gas costs (including those related to contract code) are applied as per normal contract execution of the current fork. | ||
* `BLOCKHASH` should be consistently resolved if this EIP is activated correctly `>= BLOCKHASH_SERVE_WINDOW` after [EIP-2935](./eip-2935.md) | ||
|
||
## Security Considerations | ||
|
||
No security considerations other than the ones contained in [EIP-2935](./eip-2935.md) are determined as of now. | ||
|
||
## Copyright | ||
|
||
Copyright and related rights waived via [CC0](../LICENSE.md). |