ethereum / ethereum/execution-apis
eth_simulateV1: simulated block identity is undefined after Amsterdam
- 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
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