ethereum / ethereum/execution-apis

eth_simulateV1: simulated block identity is undefined after Amsterdam

Open
#868 5 comments 2 reactions 0 assignees View on GitHub
Dominant language
Io
Stars
1.1k
Forks
530
Avg merge
5d 8h
Merged PRs (30d)
9

Description

With the Amsterdam test chain from #867, most cross-client rpc-compat failures land in `eth_simulateV1`. The cause is not client bugs. The spec does not say what a simulated block looks like after Amsterdam, and every client answers differently. Real blocks are fine: all clients that import the chain agree with each other on `slotNumber` and `blockAccessListHash` there.

Data below is from hive rpc-compat runs on 2026-08-26 against the #867 fixtures: geth/nethermind/besu master builds, erigon/reth `glamsterdam-devnet-8` images. Between 44 and 54 tests per client fail on these questions.

### 1. Which header fields does a simulated block have?

| client | slotNumber | blockAccessListHash |
|---|---|---|
| real blocks (all clients) | present | present |
| geth, nethermind, besu, erigon | absent | present |
| reth | present | absent |

### 2. What is `blockAccessListHash` when present?

| client | value |
|---|---|
| besu | `keccak(rlp([]))` (`0x1dcc4de8...`), every block |
| geth | computed BAL |
| nethermind | computed BAL, different contents than geth |
| erigon | computed BAL, a third value |

nethermind's simulated `transactionsRoot` also differs from geth's in 12 tests, so the identity disagreement is wider than the BAL alone.

Since the block hash and the parentHash chain derive from these fields, every downstream assertion diverges too, including block properties read back by contracts (`BLOCKHASH`).

### 3. `traceTransfers` collides with EIP-7708

EIP-7708 emits a protocol transfer log from `0xffff...fffe`. `traceTransfers` predates it and synthesizes one from `0xeeee...eeee`. For one plain value transfer post-Amsterdam:

| client | logs |
|---|---|
| geth, reth, erigon | both: `0xeeee...` at index 0, `0xffff...` at index 1 |
| nethermind | protocol log only |
| besu | synthetic log only |

A consumer of the flag double-counts transfers on three clients and loses the protocol log on besu.

### Possible resolutions

For 1 and 2, pick one:
- a. Simulated blocks carry both Amsterdam header fields, with a computed BAL, as if the block were real. Most faithful, but the three computed BALs disagree today, so this also needs an answer to what the BAL of a simulated block contains (system calls, fee credits, overridden state).
- b. `blockAccessListHash` is the hash of the empty list and `slotNumber` derives from the parent. Cheap and deterministic, but simulated blocks stop being self-consistent with EIP-7928.
- c. Omit both fields in simulated blocks. Simplest, but the object shape then differs from real blocks.

For 3, pick one:
- a. Suppress the synthetic `0xeeee...` log when the fork already emits a protocol transfer log for the same transfer.
- b. Keep both, in a specified order.
- c. Deprecate `traceTransfers` once EIP-7708 is active.

#851 specified BAL getter semantics for real blocks only and does not cover simulation. Refs: [EIP-7928](https://eips.ethereum.org/EIPS/eip-7928), [EIP-7708](https://eips.ethereum.org/EIPS/eip-7708), [EIP-7843](https://eips.ethereum.org/EIPS/eip-7843), #867.

Contributor guide

Open the contributing guide

Research direction

Start by reading EIP-7928, EIP-7708, EIP-7843, issue #851, and the Amsterdam fixtures from #867, then compare the reported client behavior for eth_simulateV1 and traceTransfers. Done means the specification records an agreed semantic for simulated block identity, BAL contents, and transfer-log handling, with the listed compatibility cases resolved.

Written by the indexing model from the issue text.

Assessment

Tech stack
blockchain
Domain
api, blockchain
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.