From 0875361e0c3b718ddefb7351512156c5bad38d00 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 4 Nov 2021 13:20:40 +0600 Subject: [PATCH 1/6] Engine API: implement ForkchoiceStateV1 structure --- src/engine/specification.md | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/engine/specification.md b/src/engine/specification.md index ed0011c3..61666031 100644 --- a/src/engine/specification.md +++ b/src/engine/specification.md @@ -14,6 +14,7 @@ This document specifies the Engine API methods that the Consensus Layer uses to - [Errors](#errors) - [Structures](#structures) - [ExecutionPayloadV1](#executionpayloadv1) + - [ForkchoiceStateV1](#forkchoicestatev1) - [PayloadAttributesV1](#payloadattributesv1) - [Core](#core) - [engine_executePayloadV1](#engine_executepayloadv1) @@ -135,6 +136,13 @@ This structure maps on the [`ExecutionPayload`](https://github.com/ethereum/cons - `blockHash`: `DATA`, 32 Bytes - `transactions`: `Array of DATA` - Array of transaction objects, each object is a byte list (`DATA`) representing `TransactionType || TransactionPayload` or `LegacyTransaction` as defined in [EIP-2718](https://eips.ethereum.org/EIPS/eip-2718) +### ForkchoiceStateV1 + +This structure renders the fork choice state. The fields are encoded as follows: +- `headBlockHash`: `DATA`, 32 Bytes - block hash of the head of the canonical chain +- `safeBlockHash`: `DATA`, 32 Bytes - the "safe" block hash of the canonical chain under certain synchrony and honesty assumptions. This value **MUST** be either equal to or an ancestor of `headBlockHash` +- `finalizedBlockHash`: `DATA`, 32 Bytes - block hash of the most recent finalized block + ### PayloadAttributesV1 This structure contains the attributes required to initiate a payload build process in the context of an `engine_forkchoiceUpdated` call. The fields are encoded as follows: @@ -178,10 +186,8 @@ This structure contains the attributes required to initiate a payload build proc * method: "engine_forkchoiceUpdatedV1" * params: - 1. `headBlockHash`: `DATA`, 32 Bytes - block hash of the head of the canonical chain - 2. `safeBlockHash`: `DATA`, 32 Bytes - the "safe" block hash of the canonical chain under certain synchrony and honesty assumptions. This value **MUST** be either equal to or an ancestor of `headBlockHash` - 3. `finalizedBlockHash`: `DATA`, 32 Bytes - block hash of the most recent finalized block - 4. `payloadAttributes`: `Object|null` - instance of [`PayloadAttributesV1`](#PayloadAttributesV1) or `null` + 1. `forkchoiceState`: `Object` - instance of [`ForkchoiceStateV1`](#ForkchoiceStateV1) + 2. `payloadAttributes`: `Object|null` - instance of [`PayloadAttributesV1`](#PayloadAttributesV1) or `null` #### Response @@ -190,13 +196,13 @@ This structure contains the attributes required to initiate a payload build proc #### Specification -1. The values `(headBlockHash, finalizedBlockHash)` of this method call map on the `POS_FORKCHOICE_UPDATED` event of [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#specification) and **MUST** be processed according to the specification defined in the EIP. +1. The values `(forkchoiceState.headBlockHash, forkchoiceState.finalizedBlockHash)` of this method call map on the `POS_FORKCHOICE_UPDATED` event of [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#specification) and **MUST** be processed according to the specification defined in the EIP. 2. All updates to the forkchoice resulting from this call **MUST** be made atomically. -3. Client software **MUST** return `SYNCING` status if the payload identified by either the `headBlockHash` or the `finalizedBlockHash` is unknown or if the sync process is in progress. In the event that either the `headBlockHash` or the `finalizedBlockHash` is unknown, the client software **SHOULD** initiate the sync process. +3. Client software **MUST** return `SYNCING` status if the payload identified by either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown or if the sync process is in progress. In the event that either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown, the client software **SHOULD** initiate the sync process. -4. Client software **MUST** begin a payload build process building on top of `headBlockHash` if `payloadAttributes` is not `null` and the client is not `SYNCING`. The build process is specified as: +4. Client software **MUST** begin a payload build process building on top of `forkchoiceState.headBlockHash` if `payloadAttributes` is not `null` and the client is not `SYNCING`. The build process is specified as: * The payload build process **MUST** be identified via `payloadId` where `payloadId` is defined as the hash of the block-production inputs, see [Hashing to `payloadId`](#hashing-to-payloadid). * Client software **MUST** set the payload field values according to the set of parameters passed into this method with exception of the `feeRecipient`. The prepared `ExecutionPayload` **MAY** deviate the `coinbase` field value from what is specified by the `feeRecipient` parameter. * Client software **SHOULD** build the initial version of the payload which has an empty transaction set. From 37c885292ad0f14391cf98bc2593014a74308ab4 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 4 Nov 2021 15:06:17 +0600 Subject: [PATCH 2/6] Engine API: remove payloadId computation, refine forkchoiceUpdated --- src/engine/specification.md | 44 ++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 25 deletions(-) diff --git a/src/engine/specification.md b/src/engine/specification.md index 61666031..30b02540 100644 --- a/src/engine/specification.md +++ b/src/engine/specification.md @@ -25,6 +25,7 @@ This document specifies the Engine API methods that the Consensus Layer uses to - [Request](#request-1) - [Response](#response-1) - [Specification](#specification-1) + - [Payload build process](#payload-build-process) - [engine_getPayloadV1](#engine_getpayloadv1) - [Request](#request-2) - [Response](#response-2) @@ -164,9 +165,9 @@ This structure contains the attributes required to initiate a payload build proc * result: `object` - `status`: `enum` - `"VALID" | "INVALID" | "SYNCING"` - - `latestValidHash`: `DATA|null`, 32 bytes - the hash of the most recent *valid* block in the branch defined by payload and its ancestors + - `latestValidHash`: `DATA|null`, 32 Bytes - the hash of the most recent *valid* block in the branch defined by payload and its ancestors - `message`: `STRING|null` - the message providing additional details on the response to the method call if needed -* error: code and message set in case an exception happens during showing a message. +* error: code and message set in case an exception happens while executing the payload. #### Specification @@ -191,38 +192,31 @@ This structure contains the attributes required to initiate a payload build proc #### Response -* result: `enum`, `"SUCCESS" | "SYNCING"` -* error: code and message set in case an exception happens while updating the forkchoice or preparing the payload. +* result: `object` + - `status`: `enum` - `"SUCCESS" | "SYNCING"` + - `payloadId`: `QUANTITY|null`, 64 Bits - identifier of the payload build process or `null` +* error: code and message set in case an exception happens while updating the forkchoice or initiating the payload build process. #### Specification 1. The values `(forkchoiceState.headBlockHash, forkchoiceState.finalizedBlockHash)` of this method call map on the `POS_FORKCHOICE_UPDATED` event of [EIP-3675](https://eips.ethereum.org/EIPS/eip-3675#specification) and **MUST** be processed according to the specification defined in the EIP. -2. All updates to the forkchoice resulting from this call **MUST** be made atomically. - -3. Client software **MUST** return `SYNCING` status if the payload identified by either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown or if the sync process is in progress. In the event that either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown, the client software **SHOULD** initiate the sync process. +2. All updates to the forkchoice state resulting from this call **MUST** be made atomically. -4. Client software **MUST** begin a payload build process building on top of `forkchoiceState.headBlockHash` if `payloadAttributes` is not `null` and the client is not `SYNCING`. The build process is specified as: - * The payload build process **MUST** be identified via `payloadId` where `payloadId` is defined as the hash of the block-production inputs, see [Hashing to `payloadId`](#hashing-to-payloadid). - * Client software **MUST** set the payload field values according to the set of parameters passed into this method with exception of the `feeRecipient`. The prepared `ExecutionPayload` **MAY** deviate the `coinbase` field value from what is specified by the `feeRecipient` parameter. - * Client software **SHOULD** build the initial version of the payload which has an empty transaction set. - * Client software **SHOULD** start the process of updating the payload. The strategy of this process is implementation dependent. The default strategy is to keep the transaction set up-to-date with the state of local mempool. - * Client software **SHOULD** stop the updating process when either a call to `engine_getPayload` with the build process's `payloadId` is made or [`SECONDS_PER_SLOT`](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1) (currently set to 12 in the Mainnet configuration) seconds have passed since the point in time identified by the `timestamp` parameter. +3. Client software **MUST** return `{status: SUCCESS, payloadId: null}` if `payloadAttributes` is `null` and the client is not `SYNCING`. -5. If any of the above fails due to errors unrelated to the client software's normal `SYNCING` status, the client software **MUST** return an error. +4. Client software **MUST** return `{status: SYNCING, payloadId: null}` if the payload identified by either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown or if the sync process is in progress. In the event that either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown, the client software **SHOULD** initiate the sync process. -##### Hashing to `payloadId` +5. Client software **MUST** return `{status: SUCCESS, payloadId: buildProcessId}` if `payloadAttributes` is not `null` and the client is not `SYNCING`, and begin a payload build process building on top of `forkchoiceState.headBlockHash` and identified via `buildProcessId` value. The build process is specified in the [Payload build process](#payload-build-process) section. -The `payloadId` is the `sha256` hash of the concatenation of version byte and inputs: -```python -PAYLOAD_ID_VERSION_BYTE = b"\x00" -sha256(PAYLOAD_ID_VERSION_BYTE + headBlockHash + payloadAttributes.timestamp.to_bytes(8, "big") + payloadAttributes.random + payloadAttributes.feeRecipient) -``` -Note that the timestamp is encoded as big-endian and padded fully to 8 bytes. +6. If any of the above fails due to errors unrelated to the client software's normal `SYNCING` status, the client software **MUST** return an error. -This ID-computation is versioned and may change over time, opaque to the engine API user, and **MUST** always be consistent between `engine_forkchoiceUpdated` and `engine_getPayload`. -The `PAYLOAD_ID_VERSION_BYTE` **SHOULD** be updated if the intent or typing of the payload production inputs changes, -such that a payload cache can be safely shared between current and later versions of `engine_forkchoiceUpdated`. +##### Payload build process +The payload build process is specified as follows: +* Client software **MUST** set the payload field values according to the set of parameters passed into this method with exception of the `feeRecipient`. The built `ExecutionPayload` **MAY** deviate the `coinbase` field value from what is specified by the `feeRecipient` parameter. +* Client software **SHOULD** build the initial version of the payload which has an empty transaction set. +* Client software **SHOULD** start the process of updating the payload. The strategy of this process is implementation dependent. The default strategy is to keep the transaction set up-to-date with the state of local mempool. +* Client software **SHOULD** stop the updating process when either a call to `engine_getPayload` with the build process's `payloadId` is made or [`SECONDS_PER_SLOT`](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1) (currently set to 12 in the Mainnet configuration) seconds have passed since the point in time identified by the `timestamp` parameter. ### engine_getPayloadV1 @@ -230,7 +224,7 @@ such that a payload cache can be safely shared between current and later version * method: `engine_getPayloadV1` * params: - 1. `payloadId`: `DATA`, 32 bytes - Identifier of the payload build process + 1. `payloadId`: `QUANTITY`, 64 Bits - Identifier of the payload build process #### Response From ad7c36d5a1ace57d9411ab8e044070667fc2018d Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 4 Nov 2021 15:49:37 +0600 Subject: [PATCH 3/6] Engine API: set payloadId type back to DATA --- src/engine/specification.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/engine/specification.md b/src/engine/specification.md index 30b02540..d7214b2a 100644 --- a/src/engine/specification.md +++ b/src/engine/specification.md @@ -194,7 +194,7 @@ This structure contains the attributes required to initiate a payload build proc * result: `object` - `status`: `enum` - `"SUCCESS" | "SYNCING"` - - `payloadId`: `QUANTITY|null`, 64 Bits - identifier of the payload build process or `null` + - `payloadId`: `DATA|null`, 8 Bytes - identifier of the payload build process or `null` * error: code and message set in case an exception happens while updating the forkchoice or initiating the payload build process. #### Specification @@ -224,7 +224,7 @@ The payload build process is specified as follows: * method: `engine_getPayloadV1` * params: - 1. `payloadId`: `QUANTITY`, 64 Bits - Identifier of the payload build process + 1. `payloadId`: `DATA`, 8 Bytes - Identifier of the payload build process #### Response From b63ef88a410d21e324db7d532374226189bb3731 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 4 Nov 2021 16:24:38 +0600 Subject: [PATCH 4/6] Fix spell check --- wordlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wordlist.txt b/wordlist.txt index 42862ce3..d372d313 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -20,6 +20,7 @@ rlp rpc schemas secp +statev sha uint updatedv From 1fc3738195cfc6095f8b451bc2f3e42def72a7e2 Mon Sep 17 00:00:00 2001 From: Mikhail Kalinin Date: Thu, 4 Nov 2021 19:26:30 +0600 Subject: [PATCH 5/6] Engine API: Apply suggestions from code review Co-authored-by: Danny Ryan Co-authored-by: lightclient <14004106+lightclient@users.noreply.github.com> --- src/engine/specification.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/engine/specification.md b/src/engine/specification.md index d7214b2a..635a106c 100644 --- a/src/engine/specification.md +++ b/src/engine/specification.md @@ -139,7 +139,7 @@ This structure maps on the [`ExecutionPayload`](https://github.com/ethereum/cons ### ForkchoiceStateV1 -This structure renders the fork choice state. The fields are encoded as follows: +This structure encapsulates the fork choice state. The fields are encoded as follows: - `headBlockHash`: `DATA`, 32 Bytes - block hash of the head of the canonical chain - `safeBlockHash`: `DATA`, 32 Bytes - the "safe" block hash of the canonical chain under certain synchrony and honesty assumptions. This value **MUST** be either equal to or an ancestor of `headBlockHash` - `finalizedBlockHash`: `DATA`, 32 Bytes - block hash of the most recent finalized block @@ -207,7 +207,7 @@ This structure contains the attributes required to initiate a payload build proc 4. Client software **MUST** return `{status: SYNCING, payloadId: null}` if the payload identified by either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown or if the sync process is in progress. In the event that either the `forkchoiceState.headBlockHash` or the `forkchoiceState.finalizedBlockHash` is unknown, the client software **SHOULD** initiate the sync process. -5. Client software **MUST** return `{status: SUCCESS, payloadId: buildProcessId}` if `payloadAttributes` is not `null` and the client is not `SYNCING`, and begin a payload build process building on top of `forkchoiceState.headBlockHash` and identified via `buildProcessId` value. The build process is specified in the [Payload build process](#payload-build-process) section. +5. Client software **MUST** return `{status: SUCCESS, payloadId: buildProcessId}` if `payloadAttributes` is not `null` and the client is not `SYNCING`, and **MUST** begin a payload build process building on top of `forkchoiceState.headBlockHash` and identified via `buildProcessId` value. The build process is specified in the [Payload build process](#payload-build-process) section. 6. If any of the above fails due to errors unrelated to the client software's normal `SYNCING` status, the client software **MUST** return an error. @@ -216,7 +216,7 @@ The payload build process is specified as follows: * Client software **MUST** set the payload field values according to the set of parameters passed into this method with exception of the `feeRecipient`. The built `ExecutionPayload` **MAY** deviate the `coinbase` field value from what is specified by the `feeRecipient` parameter. * Client software **SHOULD** build the initial version of the payload which has an empty transaction set. * Client software **SHOULD** start the process of updating the payload. The strategy of this process is implementation dependent. The default strategy is to keep the transaction set up-to-date with the state of local mempool. -* Client software **SHOULD** stop the updating process when either a call to `engine_getPayload` with the build process's `payloadId` is made or [`SECONDS_PER_SLOT`](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1) (currently set to 12 in the Mainnet configuration) seconds have passed since the point in time identified by the `timestamp` parameter. +* Client software **SHOULD** stop the updating process when either a call to `engine_getPayload` with the build process's `payloadId` is made or [`SECONDS_PER_SLOT`](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1) (12 in the Mainnet configuration) have passed since the point in time identified by the `timestamp` parameter. ### engine_getPayloadV1 From 00883ad0df04b908f736fb45b69f3689a8a98bf6 Mon Sep 17 00:00:00 2001 From: lightclient <14004106+lightclient@users.noreply.github.com> Date: Thu, 4 Nov 2021 07:30:47 -0600 Subject: [PATCH 6/6] Update src/engine/specification.md --- src/engine/specification.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/specification.md b/src/engine/specification.md index 635a106c..c1afdf4d 100644 --- a/src/engine/specification.md +++ b/src/engine/specification.md @@ -216,7 +216,7 @@ The payload build process is specified as follows: * Client software **MUST** set the payload field values according to the set of parameters passed into this method with exception of the `feeRecipient`. The built `ExecutionPayload` **MAY** deviate the `coinbase` field value from what is specified by the `feeRecipient` parameter. * Client software **SHOULD** build the initial version of the payload which has an empty transaction set. * Client software **SHOULD** start the process of updating the payload. The strategy of this process is implementation dependent. The default strategy is to keep the transaction set up-to-date with the state of local mempool. -* Client software **SHOULD** stop the updating process when either a call to `engine_getPayload` with the build process's `payloadId` is made or [`SECONDS_PER_SLOT`](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1) (12 in the Mainnet configuration) have passed since the point in time identified by the `timestamp` parameter. +* Client software **SHOULD** stop the updating process when either a call to `engine_getPayload` with the build process's `payloadId` is made or [`SECONDS_PER_SLOT`](https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#time-parameters-1) (12s in the Mainnet configuration) have passed since the point in time identified by the `timestamp` parameter. ### engine_getPayloadV1