This note summarizes the ev-node changes needed before enabling Amsterdam in an ev-reth 2.3 chainspec.
Current ev-node main has Prague/Osaka/Fusaka-style Engine API support:
engine_forkchoiceUpdatedV3engine_getPayloadV4with fallback/cache toengine_getPayloadV5engine_newPayloadV4
That is enough while the execution chain remains pre-Amsterdam. It is not enough for Amsterdam payloads.
The checked-in ev-node EVM genesis currently has pragueTime: 0 and no
amsterdamTime, so this is not an immediate break for that default config.
Amsterdam introduces an Engine payload shape that ev-node must preserve:
PayloadAttributesrequireslotNumber.- Built execution payloads include
executionPayload.blockAccessList. - Reth 2.3 expects Amsterdam payloads through:
engine_forkchoiceUpdatedV4engine_getPayloadV6engine_newPayloadV5
The most important gap is blockAccessList passthrough. ev-node currently
decodes getPayload responses into go-ethereum's engine.ExecutionPayloadEnvelope.
In go-ethereum v1.17.2, engine.ExecutableData includes slotNumber, but the
Engine API envelope does not expose executionPayload.blockAccessList. Decoding
an Amsterdam payload into that type will lose the BAL before ev-node submits the
payload back with newPayload.
Update execution/evm/engine_rpc_client.go:
- Add
engine_forkchoiceUpdatedV4. - Add
engine_getPayloadV6. - Add
engine_newPayloadV5. - Track the selected payload version beyond the current V4/V5 boolean.
Recommended shape:
- Replace
useV5 atomic.Boolwith a small enum or atomic version value. - Keep unsupported-fork fallback for
getPayload, but include V6. - Select
newPayloadV5whenever the payload has Amsterdam fields. - Select
forkchoiceUpdatedV4whenever payload attributes are Amsterdam.
Update the payload attributes map in execution/evm/execution.go.
Current map includes:
timestampprevRandaosuggestedFeeRecipientwithdrawalsparentBeaconBlockRoot- evolve-specific
transactions - evolve-specific
gasLimit
For Amsterdam-active timestamps, add:
"slotNumber": "<deterministic slot number>"The slot number should come from an explicit chain rule. A reasonable default is to derive it from rollup block height, but this should be agreed with the ev-node/ev-reth chain semantics before enabling the fork.
Do not try to compute the block access list in ev-node. ev-reth builds it.
Add a local Amsterdam-capable payload wrapper that can decode and re-encode the
full executionPayload object, including:
- all fields currently in
engine.ExecutableData slotNumberblockAccessList
Implementation options:
- Use a custom struct embedding or mirroring
engine.ExecutableDataand addingBlockAccessList hexutil.Bytes. - Or keep the raw
json.RawMessageforexecutionPayload, decode only the fields ev-node needs forblockNumber,timestamp,blockHash, andstateRoot, then submit the raw payload object unchanged tonewPayloadV5.
The raw-object approach is safest for Engine API compatibility because it avoids dropping future EL payload fields.
ev-node currently does not have an EVM fork schedule option. It receives:
- ETH RPC URL
- Engine RPC URL
- JWT secret
- genesis hash
- fee recipient
Amsterdam selection needs one of:
- a new flag such as
--evm.amsterdam-time, kept in sync with ev-reth genesis; - parsing the ev-reth genesis/chainspec from a configured path;
- an Engine API capability probe plus explicit local state that knows when
slotNumbermust be present.
Do not rely only on getPayload unsupported-fork fallback. forkchoiceUpdatedV4
requires slotNumber when starting an Amsterdam build, so ev-node must know the
fork state before asking ev-reth to build a payload.
Update execution/evm/engine_rpc_tracing.go so spans record the actual selected
method:
engine_forkchoiceUpdatedV3orengine_forkchoiceUpdatedV4engine_getPayloadV4,engine_getPayloadV5, orengine_getPayloadV6engine_newPayloadV4orengine_newPayloadV5
Also update hard-coded log messages in execution/evm/execution.go that still
name V3/V4 methods.
Add or extend tests in execution/evm/engine_rpc_client_test.go:
- Prague path uses
getPayloadV4andnewPayloadV4. - Osaka/Fusaka path falls back to and caches
getPayloadV5. - Amsterdam path uses
forkchoiceUpdatedV4withslotNumber. - Amsterdam path uses
getPayloadV6. - Amsterdam path submits with
newPayloadV5. blockAccessListreturned bygetPayloadV6is present in the submittednewPayloadV5execution payload.- Unsupported-fork errors still switch only to valid alternate methods.
Update integration test helpers:
execution/evm/test/test_helpers.gocurrently hard-codesengine_forkchoiceUpdatedV3for readiness.- Any E2E config that enables
amsterdamTimemust use the updated method path.
Update ev-node docs that currently describe only older Engine API versions:
execution/evm/README.mddocs/reference/api/engine-api.mddocs/ev-reth/engine-api.md
Document that Prague/Osaka/Fusaka support is insufficient for Amsterdam because
Amsterdam adds slotNumber, blockAccessList, and newer Engine API methods.
Before setting amsterdamTime in an ev-reth chainspec:
- ev-node can call
engine_forkchoiceUpdatedV4. - ev-node sends
slotNumberin Amsterdam payload attributes. - ev-node can call
engine_getPayloadV6. - ev-node preserves
executionPayload.blockAccessList. - ev-node can call
engine_newPayloadV5. - tracing/logs report the selected Engine API version.
- unit tests cover V4/V5/V6 version selection and BAL passthrough.
- E2E tests pass against an Amsterdam-enabled ev-reth chainspec.