This document specifies the Engine API methods that the Consensus Layer uses to interact with the Execution Layer.
- Underlying protocol
- Versioning
- Message ordering
- Load-balancing and advanced configurations
- Errors
- Structures
- Core
This specification is based on Ethereum JSON-RPC API and inherits the following properties of this standard:
- Supported communication protocols (HTTP and WebSocket)
- Message format and encoding notation
- Error codes improvement proposal
Client software MUST expose Engine API at a port independent from JSON-RPC API.
The default port for the Engine API is 8550 for HTTP and 8551 for WebSocket.
The Engine API is exposed under the engine
namespace.
To facilitate an Engine API consumer to access state and logs (e.g. proof-of-stake deposits) through the same connection,
the client MUST also expose the eth
namespace.
The versioning of the Engine API is defined as follows:
- The version of each method and structure is independent from versions of other methods and structures.
- The
VX
, where theX
is the number of the version, is suffixed to the name of each method and structure. - The version of a method or a structure MUST be incremented by one if any of the following is changed:
- a set of method parameters
- a method response value
- a method behavior
- a set of structure fields
- The specification MAY reference a method or a structure without the version suffix e.g.
engine_executePayload
. These statements should be read as related to all versions of the referenced method or structure.
Consensus Layer client software MUST utilize JSON-RPC request IDs that are strictly increasing.
Execution Layer client software MUST execute calls strictly in the order of request IDs to avoid degenerate race conditions.
The Engine API supports a one-to-many Consensus Layer to Execution Layer configuration. Intuitively this is because the Consensus Layer drives the Execution Layer and thus can drive many of them independently.
On the other hand, generic many-to-one Consensus Layer to Execution Layer configurations are not supported out-of-the-box.
The Execution Layer, by default, only supports one chain head at a time and thus has undefined behavior when multiple Consensus Layers simultaneously control the head.
The Engine API does work properly, if in such a many-to-one configuration, only one Consensus Layer instantiation is able to write to the Execution Layer's chain head and initiate the payload build process (i.e. call engine_forkchoiceUpdated
),
while other Consensus Layers can only safely insert payloads (i.e. engine_executePayload
) and read from the Execution Layer.
The list of error codes introduced by this specification can be found below.
Code | Message | Meaning |
---|---|---|
-32700 | Parse error | Invalid JSON was received by the server. |
-32600 | Invalid Request | The JSON sent is not a valid Request object. |
-32601 | Method not found | The method does not exist / is not available. |
-32602 | Invalid params | Invalid method parameter(s). |
-32603 | Internal error | Internal JSON-RPC error. |
-32000 | Server error | Generic client error while processing request. |
-32001 | Unknown payload | Payload does not exist / is not available. |
Each error returns a null
data
value, except -32000
which returns the data
object with a err
member that explains the error encountered.
For example:
$ curl https://localhost:8550 \
-X POST \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","method":"engine_getPayloadV1","params": ["0x1"],"id":1}'
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32000,
"message": "Server error",
"data": {
"err": "Database corrupted"
}
}
}
Fields having DATA
and QUANTITY
types MUST be encoded according to the HEX value encoding section of Ethereum JSON-RPC API.
Note: Byte order of encoded value having QUANTITY
type is big-endian.
This structure maps on the ExecutionPayload
structure of the beacon chain spec. The fields are encoded as follows:
parentHash
:DATA
, 32 Bytescoinbase
:DATA
, 20 BytesstateRoot
:DATA
, 32 BytesreceiptRoot
:DATA
, 32 ByteslogsBloom
:DATA
, 256 Bytesrandom
:DATA
, 32 BytesblockNumber
:QUANTITY
, 64 BitsgasLimit
:QUANTITY
, 64 BitsgasUsed
:QUANTITY
, 64 Bitstimestamp
:QUANTITY
, 64 BitsextraData
:DATA
, 0 to 32 BytesbaseFeePerGas
:QUANTITY
, 256 BitsblockHash
:DATA
, 32 Bytestransactions
:Array of DATA
- Array of transaction objects, each object is a byte list (DATA
) representingTransactionType || TransactionPayload
orLegacyTransaction
as defined in EIP-2718
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 chainsafeBlockHash
: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 ofheadBlockHash
finalizedBlockHash
:DATA
, 32 Bytes - block hash of the most recent finalized block
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:
timestamp
:QUANTITY
, 64 Bits - value for thetimestamp
field of the new payloadrandom
:DATA
, 32 Bytes - value for therandom
field of the new payloadfeeRecipient
:DATA
, 20 Bytes - suggested value for thecoinbase
field of the new payload
- method:
engine_executePayloadV1
- params:
- 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 ancestorsmessage
: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 while executing the payload.
-
Client software MUST validate the payload according to the execution environment rule set with modifications to this rule set defined in the Block Validity section of EIP-3675 and return the validation result.
- If validation succeeds, return
{status: VALID, lastestValidHash: payload.blockHash}
- If validation fails, return
{status: INVALID, lastestValidHash: validHash}
wherevalidHash
is the block hash of the most recent valid ancestor of the invalid payload. That is, the valid ancestor of the payload with the highestblockNumber
.
- If validation succeeds, return
-
Client software MUST discard the payload if it's deemed invalid.
-
Client software MUST return
{status: SYNCING, lastestValidHash: null}
if the sync process is already in progress or if requisite data for payload validation is missing. In the event that requisite data to validate the payload is missing (e.g. does not have payload identified byparentHash
), the client software SHOULD initiate the sync process. -
Client software MAY provide additional details on the payload validation by utilizing
message
field in the response object. For example, particular error message occurred during the payload execution may accompany a response withINVALID
status.
- method: "engine_forkchoiceUpdatedV1"
- params:
forkchoiceState
:Object
- instance ofForkchoiceStateV1
payloadAttributes
:Object|null
- instance ofPayloadAttributesV1
ornull
- result:
object
status
:enum
-"SUCCESS" | "SYNCING"
payloadId
:DATA|null
, 8 Bytes - identifier of the payload build process ornull
- error: code and message set in case an exception happens while updating the forkchoice or initiating the payload build process.
-
The values
(forkchoiceState.headBlockHash, forkchoiceState.finalizedBlockHash)
of this method call map on thePOS_FORKCHOICE_UPDATED
event of EIP-3675 and MUST be processed according to the specification defined in the EIP. -
All updates to the forkchoice state resulting from this call MUST be made atomically.
-
Client software MUST return
{status: SUCCESS, payloadId: null}
ifpayloadAttributes
isnull
and the client is notSYNCING
. -
Client software MUST return
{status: SYNCING, payloadId: null}
if the payload identified by either theforkchoiceState.headBlockHash
or theforkchoiceState.finalizedBlockHash
is unknown or if the sync process is in progress. In the event that either theforkchoiceState.headBlockHash
or theforkchoiceState.finalizedBlockHash
is unknown, the client software SHOULD initiate the sync process. -
Client software MUST return
{status: SUCCESS, payloadId: buildProcessId}
ifpayloadAttributes
is notnull
and the client is notSYNCING
, and MUST begin a payload build process building on top offorkchoiceState.headBlockHash
and identified viabuildProcessId
value. The build process is specified in the Payload build process section. -
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.
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 builtExecutionPayload
MAY deviate thecoinbase
field value from what is specified by thefeeRecipient
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'spayloadId
is made orSECONDS_PER_SLOT
(12s in the Mainnet configuration) have passed since the point in time identified by thetimestamp
parameter.
- method:
engine_getPayloadV1
- params:
payloadId
:DATA
, 8 Bytes - Identifier of the payload build process
- result:
ExecutionPayloadV1
- error: code and message set in case an exception happens while getting the payload.
-
Given the
payloadId
client software MUST return the most recent version of the payload that is available in the corresponding build process at the time of receiving the call. -
The call MUST return
-32001: Unknown payload
error if the build process identified by thepayloadId
does not exist. -
Client software MAY stop the corresponding build process after serving this call.