# EIP-7709 for Hegota ## Summary [EIP-7709](https://eips.ethereum.org/EIPS/eip-7709) ([refresh under review](https://github.com/ethereum/EIPs/pull/11587)) updates `BLOCKHASH` so that in-window lookups are treated as reads from EIP-2935 block-hash history storage and charged with cold/warm `SLOAD` semantics. It does not change return-value semantics. EIP-7709 is narrow, [implementation-ready](https://github.com/ethereum/execution-specs/pull/2619), and removes a protocol special case that adds unnecessary complexity to stateless execution. ## Why include it in Hegota? The case for EIP-7709 is not new functionality; it is removing a mismatch between protocol semantics, gas accounting, and implementation reality. Today, `BLOCKHASH` is unusual: - it depends on historical chain data, - it is cheap in a way that assumes stateful local access, - but it is not modeled like other state-dependent reads. That works for fully stateful clients that already keep recent block history in memory or a local database. It is less clean for stateless execution, where all required data must be supplied explicitly and verified. In other words, `BLOCKHASH` is a protocol special case. EIP-7709 removes that special case by aligning recent blockhash access with Ethereum's normal state-access machinery (i.e. MPT proofs). ## The problem with the status quo Consider a transaction that executes: ```text BLOCKHASH(current_block_number - 10) ``` Stateful clients can resolve this from local history or cache; stateless executors need both the value and a verification path. There are two broad ways to support this. ### Option 1: prove the value through EIP-2935 storage Since [EIP-2935](https://eips.ethereum.org/EIPS/eip-2935) is active, recent blockhash history exists in the block-hash history contract storage. A stateless executor can verify the relevant storage proof the same way it verifies other state-dependent operations. **Pros** - Uses the same proof machinery as other stateful accesses. - Fits naturally into a witness model that already carries state proofs. - Gives a single coherent model: recent blockhash access is just another state read. **Cons in today's protocol model** - Stateful clients constructing execution witnesses (i.e the input for a stateless client) do not currently observe `BLOCKHASH` as a normal `SLOAD`-like access. - Witness construction may therefore require special-case logic instead of relying solely on existing state tracking. - The current gas cost of `BLOCKHASH` is not aligned with the resource being verified. ### Option 2: provide a chain of parent headers A stateless executor can also receive the relevant parent headers and verify the chain by hashing them and checking consistency against `current_block.parent_hash`. For example, resolving `BLOCKHASH(current_block_number - 10)` requires 10 parent headers to connect (i.e. `parent_hash` chaining) the current block to the requested ancestor. **Pros** - Can use fewer `keccak`s than proving a storage slot per accessed blockhash. **Cons** - Requires a separate header component in the witness, in addition to the existing state-proof path. - Adds bespoke logic to witness design and construction. - Still leaves `BLOCKHASH` underpriced relative to required verification work, although this may matter less because the in-window size is small and values can be shared across transactions. This is the [current approach](https://github.com/ethereum/execution-specs/blob/713d1eed0d3b730b7d3c72c961fc4d7ed0b8d656/src/ethereum/forks/amsterdam/stateless.py#L43-L47) in the `execution-specs` stateless zkEVM work, where header-chain verification is used as a practical workaround for the current protocol shape. ## Why EIP-7709 is cleaner EIP-7709 makes the protocol model explicit and consistent: in-range `BLOCKHASH` queries are treated as reads from EIP-2935 history storage, with the same cold/warm behavior as storage reads. That has several benefits. ### 1. It removes `BLOCKHASH` as a protocol special case Instead of treating recent blockhash access as something magical that clients happen to serve locally, the protocol recognizes it as access to recent-history state. This is cleaner whether a client is stateful or stateless. ### 2. It aligns gas accounting with the accessed resource Under EIP-7709, `BLOCKHASH` is charged like the storage-backed access it effectively is. That matters because today's cost does not reflect either: - the cost of verifying a storage-proof-based witness, or - the cost of verifying an explicitly supplied header chain. If recent blockhash access is conceptually backed by state, then storage-style pricing is the most principled model, even if the exact marginal witness cost can sometimes be amortized at block scope. ### 3. It simplifies witness construction If clients resolve `BLOCKHASH` through the EIP-2935-backed access model, the access can flow through the same state-tracking machinery used for other stateful reads. That reduces custom witness-construction logic needed only because `BLOCKHASH` is specified differently from similar state-dependent operations. ### 4. It improves future compatibility If Ethereum's state model evolves further, `BLOCKHASH` should evolve alongside other state-reading opcodes rather than remain a historical exception. EIP-7709 puts it in the right category. ## Anticipated concerns ### Concern 1: "This is not urgent" Fair, but it cuts both ways. Because EIP-7709 is narrow and self-contained, it is exactly the kind of cleanup that is easiest to adopt in a fork with room for non-headliner improvements. Deferring it leaves the `BLOCKHASH` special case in place longer. Note that [EIP-8025](https://eips.ethereum.org/EIPS/eip-8025) is also proposed for Hegota, so EIP-7709's benefits could be realized immediately by simplifying execution witness construction and validation. ### Concern 2: "Will this break contracts that rely on cheap `BLOCKHASH`?" Repricing creates compatibility risk for contracts that rely on today's low `BLOCKHASH` cost. This is probably the main concern to analyze. That analysis will clarify the ROI of the change. If few users are impacted, we gain protocol simplification at low cost. If many users are impacted, the cleanup value may not justify the change. User-impact analysis is underway. ### Concern 3: "Is this pricing too harsh?" The main counterarguments are: - `BLOCKHASH` only serves a 256-block window. That bounds the opcode's semantic scope, but it does not change the modeling point: in-range values are recent-history state already maintained by EIP-2935. A bounded scope does not by itself justify a bespoke gas rule. - `SLOAD`-style cold pricing may seem too harsh because execution witnesses are block-scoped while warming is transaction-scoped. But this is not unique to `BLOCKHASH`: other state accesses can also benefit from block-level witness amortization while still using normal transaction-scoped cold/warm rules. Block-level warming only for `BLOCKHASH` would add another exception rather than apply an existing principle. - `BLOCKHASH(block.number - 1)` may seem effectively warm or free because EIP-2935 inserted the parent hash during block processing. But that insertion happens outside user transaction execution. Under the current access-list model, warming is transaction-scoped, so pre-warming that slot for users would also require a special rule. This leaves three plausible pricing directions: - Keep the current EIP-7709 design: normal `SLOAD`-like cold/warm semantics for in-range lookups. This is the cleanest and most internally consistent option. It matches EIP-2935's storage-backed model, even though `BLOCKHASH` intentionally does not charge the full cost of literally calling the history contract. - Always charge the warm `SLOAD` read cost. This would reduce compatibility risk and create a more amortized user-facing charge, but would knowingly underprice blocks with few `BLOCKHASH` lookups and introduce a `BLOCKHASH`-specific exception. - Introduce a custom middle-ground price. This could approximate average cost, but would give up much of the proposal's simplification value and likely invite bikeshedding over a new constant with no natural home in the gas schedule. Our view is that the first option remains the strongest default because EIP-7709 is meant to simplify the protocol and remove special cases, not just reprice an opcode. The other options lose more of the benefit, but we can reevaluate after the user-impact analysis is done. ### Concern 4: "Why not solve this entirely in the witness layer?" Because witness-layer special handling is still protocol debt and increases bug risk. If `BLOCKHASH` is conceptually a recent-history state read, the protocol should model it that way. Otherwise, every stateless or proving-oriented implementation must preserve an exception path for a single opcode whose behavior does not fit the general model. ## Specs and test status There is already a full specs-and-tests implementation for EIP-7709 in `execution-specs`: - [EIP-7709](https://eips.ethereum.org/EIPS/eip-7709) ([refresh under review](https://github.com/ethereum/EIPs/pull/11587)) - [execution-specs PR #2619](https://github.com/ethereum/execution-specs/pull/2619) contains full specs and tests.