diff --git a/EIPS/eip-7709.md b/EIPS/eip-7709.md new file mode 100644 index 0000000000000..6f69c9abd491b --- /dev/null +++ b/EIPS/eip-7709.md @@ -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).