Skip to content

Commit

Permalink
Add EIP: Read BLOCKHASH from storage and update cost
Browse files Browse the repository at this point in the history
Merged by EIP-Bot.
  • Loading branch information
gabrocheleau authored May 29, 2024
1 parent f20b164 commit 0e03197
Showing 1 changed file with 101 additions and 0 deletions.
101 changes: 101 additions & 0 deletions EIPS/eip-7709.md
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).

0 comments on commit 0e03197

Please sign in to comment.