Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 48 additions & 13 deletions docs/ev-reth/engine-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,22 +25,22 @@ Configure both sides:
```text
ev-node ev-reth
│ │
│ 1. engine_forkchoiceUpdatedV3
│ 1. engine_forkchoiceUpdatedV3/V4
│ (headBlockHash, payloadAttributes) │
│─────────────────────────────────────────►│
│ │
│ 2. {payloadId} │
│◄─────────────────────────────────────────│
│ │
│ 3. engine_getPayloadV3(payloadId)
│ 3. engine_getPayloadV4/V5/V6(payloadId) │
│─────────────────────────────────────────►│
│ │
│ 4. {executionPayload, blockValue} │
│◄─────────────────────────────────────────│
│ │
│ [ev-node broadcasts to P2P, submits DA] │
│ │
│ 5. engine_newPayloadV3(executionPayload)
│ 5. engine_newPayloadV4/V5(payload)
│─────────────────────────────────────────►│
│ │
│ 6. {status: VALID} │
Expand All @@ -54,15 +54,28 @@ ev-node ev-reth

## Methods

### engine_forkchoiceUpdatedV3
| Fork family | Forkchoice | Get payload | New payload |
|-------------|------------|-------------|-------------|
| Prague | `engine_forkchoiceUpdatedV3` | `engine_getPayloadV4` | `engine_newPayloadV4` |
| Osaka/Fusaka | `engine_forkchoiceUpdatedV3` | `engine_getPayloadV5` | `engine_newPayloadV4` |
| Amsterdam | `engine_forkchoiceUpdatedV4` | `engine_getPayloadV6` | `engine_newPayloadV5` |

Amsterdam support is more than a method rename: payload attributes include
`slotNumber`, and built payloads include `executionPayload.blockAccessList`.
ev-node preserves the raw Amsterdam `executionPayload` returned by ev-reth and
submits it unchanged to `engine_newPayloadV5`.
ev-node detects Amsterdam by retrying `engine_forkchoiceUpdatedV4` after an
unsupported-fork response from `engine_forkchoiceUpdatedV3`, then caches V4.

### engine_forkchoiceUpdatedV3 / V4

Update the fork choice and optionally start building a new block.

**Request:**

```json
{
"method": "engine_forkchoiceUpdatedV3",
"method": "engine_forkchoiceUpdatedV4",
"params": [
{
"headBlockHash": "0x...",
Expand All @@ -74,7 +87,8 @@ Update the fork choice and optionally start building a new block.
"prevRandao": "0x...",
"suggestedFeeRecipient": "0x...",
"withdrawals": [],
"parentBeaconBlockRoot": "0x..."
"parentBeaconBlockRoot": "0x...",
"slotNumber": "0x..."
}
]
}
Expand All @@ -92,15 +106,15 @@ Update the fork choice and optionally start building a new block.
}
```

### engine_getPayloadV3
### engine_getPayloadV4 / V5 / V6

Retrieve a built payload.

**Request:**

```json
{
"method": "engine_getPayloadV3",
"method": "engine_getPayloadV6",
"params": ["0x...payloadId"]
}
```
Expand All @@ -123,25 +137,33 @@ Retrieve a built payload.
"extraData": "0x",
"baseFeePerGas": "0x...",
"blockHash": "0x...",
"transactions": ["0x..."]
"transactions": ["0x..."],
"slotNumber": "0x...",
"blockAccessList": []
},
"blockValue": "0x..."
}
```

### engine_newPayloadV3
### engine_newPayloadV4 / V5

Validate and execute a payload.

**Request:**

```json
{
"method": "engine_newPayloadV3",
"method": "engine_newPayloadV5",
"params": [
{ "executionPayload": "..." },
{
"parentHash": "0x...",
"blockHash": "0x...",
"slotNumber": "0x...",
"blockAccessList": []
},
["0x...versionedHashes"],
"0x...parentBeaconBlockRoot"
"0x...parentBeaconBlockRoot",
[]
]
}
```
Expand All @@ -155,6 +177,19 @@ Validate and execute a payload.
}
```

## Amsterdam Enablement Checklist

Before setting `amsterdamTime` in an ev-reth chainspec, verify:

- [ ] ev-node can call `engine_forkchoiceUpdatedV4`.
- [ ] ev-node sends `slotNumber` in Amsterdam payload attributes.
- [ ] ev-node can call `engine_getPayloadV6`.
- [ ] ev-node preserves `executionPayload.blockAccessList`.
- [ ] ev-node can call `engine_newPayloadV5`.
- [ ] Tracing and logs report the selected Engine API version.
- [ ] Unit tests cover V4/V5/V6 version selection and `blockAccessList` passthrough.
- [ ] E2E tests pass against an Amsterdam-enabled ev-reth chainspec.

## Status Codes

| Status | Meaning |
Expand Down
47 changes: 37 additions & 10 deletions docs/reference/api/engine-api.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,29 @@ openssl rand -hex 32 > jwt.hex

## Methods

### engine_forkchoiceUpdatedV3
ev-node selects Engine API methods by fork:

| Fork family | Forkchoice | Get payload | New payload |
|-------------|------------|-------------|-------------|
| Prague | `engine_forkchoiceUpdatedV3` | `engine_getPayloadV4` | `engine_newPayloadV4` |
| Osaka/Fusaka | `engine_forkchoiceUpdatedV3` | `engine_getPayloadV5` | `engine_newPayloadV4` |
| Amsterdam | `engine_forkchoiceUpdatedV4` | `engine_getPayloadV6` | `engine_newPayloadV5` |

### engine_forkchoiceUpdatedV3 / V4

Update fork choice and optionally build a new block.

Payload builds start with `engine_forkchoiceUpdatedV3`. If the execution layer
returns unsupported fork, ev-node retries `engine_forkchoiceUpdatedV4` with
`slotNumber` in the payload attributes and caches V4 for future calls.
`slotNumber` is derived deterministically from rollup block height.

**Request:**

```json
{
"jsonrpc": "2.0",
"method": "engine_forkchoiceUpdatedV3",
"method": "engine_forkchoiceUpdatedV4",
"params": [
{
"headBlockHash": "0x...",
Expand All @@ -39,7 +52,8 @@ Update fork choice and optionally build a new block.
"prevRandao": "0x...",
"suggestedFeeRecipient": "0x...",
"withdrawals": [],
"parentBeaconBlockRoot": "0x..."
"parentBeaconBlockRoot": "0x...",
"slotNumber": "0x..."
}
],
"id": 1
Expand All @@ -62,16 +76,20 @@ Update fork choice and optionally build a new block.
}
```

### engine_getPayloadV3
### engine_getPayloadV4 / V5 / V6

Get a built payload.

ev-node starts with `engine_getPayloadV4`, caches `engine_getPayloadV5` or
`engine_getPayloadV6` after successful unsupported-fork fallback, and switches
directly to V6 after an Amsterdam `forkchoiceUpdatedV4` build request.

**Request:**

```json
{
"jsonrpc": "2.0",
"method": "engine_getPayloadV3",
"method": "engine_getPayloadV6",
"params": ["0x...payloadId"],
"id": 1
}
Expand Down Expand Up @@ -100,7 +118,9 @@ Get a built payload.
"transactions": ["0x..."],
"withdrawals": [],
"blobGasUsed": "0x0",
"excessBlobGas": "0x0"
"excessBlobGas": "0x0",
"slotNumber": "0x...",
"blockAccessList": []
Comment on lines +121 to +123

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

set -euo pipefail

printf '\n## File sizes\n'
wc -l docs/reference/api/engine-api.md docs/ev-reth/engine-api.md execution/evm/README.md

printf '\n## Relevant excerpts: docs/reference/api/engine-api.md\n'
sed -n '100,190p' docs/reference/api/engine-api.md

printf '\n## Relevant excerpts: docs/ev-reth/engine-api.md\n'
sed -n '120,170p' docs/ev-reth/engine-api.md

printf '\n## Relevant excerpts: execution/evm/README.md\n'
sed -n '40,90p' execution/evm/README.md

printf '\n## Search executionRequests across docs\n'
rg -n "executionRequests|blockAccessList|slotNumber|engine_forkchoiceUpdatedV4|engine_newPayloadV5" docs execution -S

Repository: evstack/ev-node

Length of output: 13672


🌐 Web query:

Ethereum executionRequests Engine API Prague newPayloadV5 forkchoiceUpdatedV4 executionRequests docs

💡 Result:

In the Ethereum Prague upgrade, the Engine API introduced support for execution requests, a mechanism defined by EIP-7685 that allows the execution layer to trigger protocol-level operations [1][2]. These requests are communicated between the execution layer and consensus layer through updated Engine API methods [1]. Key Engine API changes for Prague include: 1. New Method Versions: The Prague upgrade introduced engine_newPayloadV4 and engine_getPayloadV4 to support the inclusion and validation of execution requests [1][3][2]. 2. Execution Requests Parameter: In engine_newPayloadV4, an executionRequests parameter was added [1][2]. This parameter is an array of byte arrays, where each element represents a request [1][2]. Each request is formatted as a byte array beginning with a single-byte request type, followed by the specific request data [2]. 3. Validation and Ordering: Requests must be ordered by their request type in ascending order [2]. The execution layer computes a commitment to these requests (the requestsRoot), which is included in the block header and validated against the data provided via the Engine API [1][4][2]. Regarding the specific methods mentioned in your query: - newPayloadV5 and forkchoiceUpdatedV4: These represent later versions of the Engine API methods introduced in subsequent upgrades (e.g., the Amsterdam fork) to support additional features like block access lists and further protocol evolutions [5][6]. They are not the methods used for the initial Prague execution requests implementation, which utilized V4 versions [1][2]. - Documentation: Official specifications for these changes are maintained in the ethereum/execution-apis repository, specifically within the prague.md and related specification documents [7][8][6]. In summary, while Prague established the foundation for execution requests using V4 engine methods, V5 (newPayloadV5) and V4 (forkchoiceUpdatedV4) methods represent subsequent API evolutions required for later network upgrades [5][6].

Citations:


🏁 Script executed:

set -euo pipefail

printf 'docs/reference/api/engine-api.md\n'
grep -n "executionRequests\|blockAccessList\|slotNumber" -n docs/reference/api/engine-api.md || true

printf '\ndocs/ev-reth/engine-api.md\n'
grep -n "executionRequests\|blockAccessList\|slotNumber" -n docs/ev-reth/engine-api.md || true

printf '\nexecution/evm/README.md\n'
grep -n "executionRequests\|executionPayload" -n execution/evm/README.md || true

Repository: evstack/ev-node

Length of output: 1320


Document executionRequests in the Engine API docs

engine_getPayloadV6 responses omit executionRequests, and the engine_newPayloadV5 examples leave the last array unlabeled. Add the field/label in both Engine API docs and note in execution/evm/README.md that ev-node forwards both executionPayload and executionRequests.

📍 Affects 3 files
  • docs/reference/api/engine-api.md#L121-L123 (this comment)
  • docs/reference/api/engine-api.md#L169-L175
  • docs/ev-reth/engine-api.md#L140-L144
  • execution/evm/README.md#L62-L64
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docs/reference/api/engine-api.md` around lines 121 - 123, Update
engine_getPayloadV6 response examples to include the executionRequests field,
label the final array in engine_newPayloadV5 examples, and mirror the
documentation changes in docs/reference/api/engine-api.md (121-123 and 169-175)
and docs/ev-reth/engine-api.md (140-144). In execution/evm/README.md (62-64),
note that ev-node forwards both executionPayload and executionRequests.

Source: MCP tools

},
"blockValue": "0x...",
"blobsBundle": {
Expand All @@ -114,16 +134,20 @@ Get a built payload.
}
```

### engine_newPayloadV3
### engine_newPayloadV4 / V5

Validate and execute a payload.

Amsterdam payloads use `engine_newPayloadV5`. ev-node passes through the raw
`executionPayload` object returned by `engine_getPayloadV6` so
`blockAccessList` is preserved.

**Request:**

```json
{
"jsonrpc": "2.0",
"method": "engine_newPayloadV3",
"method": "engine_newPayloadV5",
"params": [
{
"parentHash": "0x...",
Expand All @@ -142,10 +166,13 @@ Validate and execute a payload.
"transactions": ["0x..."],
"withdrawals": [],
"blobGasUsed": "0x0",
"excessBlobGas": "0x0"
"excessBlobGas": "0x0",
"slotNumber": "0x...",
"blockAccessList": []
},
["0x...expectedBlobVersionedHashes"],
"0x...parentBeaconBlockRoot"
"0x...parentBeaconBlockRoot",
[]
],
"id": 1
}
Expand Down
21 changes: 17 additions & 4 deletions execution/evm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ Since the `PureEngineClient` relies on the Engine API, the genesis configuration
1. The genesis file must include post-merge hardfork configurations
2. `terminalTotalDifficulty` must be set to 0
3. `terminalTotalDifficultyPassed` must be set to true
4. Hardforks like `mergeNetsplitBlock`, `shanghaiTime`, `cancunTime` and `pragueTime` should be properly configured
4. Hardforks like `mergeNetsplitBlock`, `shanghaiTime`, `cancunTime`, `pragueTime`, and optionally `amsterdamTime` should be properly configured

Example of required genesis configuration:

Expand All @@ -43,18 +43,31 @@ Example of required genesis configuration:
"terminalTotalDifficultyPassed": true,
"shanghaiTime": 0,
"cancunTime": 0,
"pragueTime": 0
"pragueTime": 0,
"amsterdamTime": 0
}
}
```

Without these settings, the Engine API will not be available, and the `PureEngineClient` will not function correctly.

### Engine API Versions

ev-node uses fork-aware Engine API methods:

- Prague payloads use `engine_forkchoiceUpdatedV3`, `engine_getPayloadV4`, and `engine_newPayloadV4`.
- Osaka/Fusaka payloads fall forward from `engine_getPayloadV4` to `engine_getPayloadV5` on unsupported-fork responses.
- Amsterdam payloads use `engine_forkchoiceUpdatedV4`, `engine_getPayloadV6`, and `engine_newPayloadV5`.

ev-node auto-detects Engine API versions by retrying on unsupported-fork responses. For payload builds, it first tries `engine_forkchoiceUpdatedV3`; if the execution layer rejects that method for Amsterdam, ev-node retries `engine_forkchoiceUpdatedV4` with a deterministic `slotNumber` derived from rollup block height and caches V4 for future calls.

Amsterdam adds `slotNumber` to payload attributes and `executionPayload.blockAccessList` to built payloads. ev-node does not compute the block access list; it preserves the raw `executionPayload` returned by ev-reth and submits that object unchanged to `engine_newPayloadV5`.

### PayloadID Storage

The `PureEngineClient` maintains the `payloadID` between calls:

1. During `InitChain`, a payload ID is obtained from the Engine API via `engine_forkchoiceUpdatedV3`
1. During `InitChain`, the genesis forkchoice is acknowledged through the Engine API
2. This payload ID is stored in the client instance as `c.payloadID`
3. The stored payload ID is used in subsequent calls to `GetTxs` to retrieve the current execution payload
4. After each `ExecuteTxs` call, a new payload ID is obtained and stored for the next block
Expand All @@ -66,7 +79,7 @@ The `PureEngineClient` implements a unique approach to transaction execution:
1. In `GetTxs`, the entire execution payload is serialized to JSON and returned as the first transaction
2. In `ExecuteTxs`, this first transaction is deserialized back into an execution payload
3. The remaining transactions are added to the payload's transaction list
4. The complete payload is then submitted to the execution client via `engine_newPayloadV4`
4. The complete payload is then submitted to the execution client via the fork-appropriate `engine_newPayload` method

This approach ensures that:

Expand Down
Loading
Loading