diff --git a/docs/specification.md b/docs/specification.md index a9c294a8..5fbe3c94 100644 --- a/docs/specification.md +++ b/docs/specification.md @@ -1,153 +1,207 @@ -# Version 0.1 (current, milestone 1, running on [Kiln testnet](https://kiln.themerge.dev/)) +# Version 0.2 -This initial milestone provides simple sidecar logic with minimal consensus client changes, simple networking, no validator authentication, and manual safety mechanism. - -1. _mev-boost_ is initialized with a list of `RelayURI`s from trusted relays. - -2. _mev-boost_ receives a [`engine_forkchoiceUpdatedV1`](#engine_forkchoiceupdatedv1) call from a beacon node and forwards it to all connected relays to communicate `feeRecipient`. - -3. _mev_boost_ receives [`builder_getPayloadHeaderV1`](#builder_getpayloadheaderv1) request from the beacon node, and forwards it to all relays as `relay_getPayloadHeaderV1`. _mev-boost_ must return the [`ExecutionPayloadHeaderV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayloadheader) with the highest associated `feeRecipientDiff`. - -4. The _beacon node_ must use the [`ExecutionPayloadHeaderV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/merge/beacon-chain.md#executionpayloadheader) received to assemble and sign a [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) and return it to _mev-boost_ using [`builder_proposeBlindedBlockV1`](#builder_proposeblindedblockv1). - -5. _mev-boost_ must forward the [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) to all connected relays and attach the matching [`SignedMEVPayloadHeader`](#signedmevpayloadheader) using [`relay_proposeBlindedBlockV1`](#relay_proposeblindedblockv1) to inform the network of which relay created this payload. - -6. If an [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.6/specs/merge/beacon-chain.md#executionpayload) is returned, _mev-boost_ must verify that the root of the transaction list matches the expected transaction root from the [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) before returning it to the _beacon node_. +This document specifies the Builder API methods that the Consensus Layer uses to interact with external block builders. ```mermaid sequenceDiagram + participant consensus + participant mev_boost + participant relays Title: Block Proposal - consensus-->+mev_boost: engine_forkchoiceUpdatedV1 - mev_boost->>-relays: engine_forkchoiceUpdatedV1 + Note over consensus: sign fee recipient announcement + consensus->>mev_boost: builder_setFeeRecipient + mev_boost->>relays: builder_setFeeRecipient Note over consensus: wait for allocated slot - consensus->>+mev_boost: builder_getPayloadHeaderV1 - mev_boost->>relays: relay_getPayloadHeaderV1 - Note over mev_boost: select most valuable payload - mev_boost-->>-consensus: builder_getPayloadHeaderV1 response + consensus->>mev_boost: builder_getHeader + mev_boost->>relays: builder_getHeader + relays-->>mev_boost: builder_getHeader response + Note over mev_boost: verify response matches expected + Note over mev_boost: select best payload + mev_boost-->>consensus: builder_getHeader response Note over consensus: sign the block - consensus->>+mev_boost: builder_proposeBlindedBlockV1 + consensus->>mev_boost: builder_getPayload Note over mev_boost: identify payload source - mev_boost->>relays: relay_proposeBlindedBlockV1 + mev_boost->>relays: builder_getPayload Note over relays: validate signature - relays-->>mev_boost: relay_proposeBlindedBlockV1 response - mev_boost-->>-consensus: builder_proposeBlindedBlockV1 response + relays-->>mev_boost: builder_getPayload response + Note over mev_boost: verify response matches expected + mev_boost-->>consensus: builder_getPayload response ``` -## Required client modifications +## Structures -- consensus client must implement [blind transaction signing](https://hackmd.io/@paulhauner/H1XifIQ_t#Change-1-Blind-Transaction-Signing) +### `ExecutionPayloadV1` -## API +Mirror of [`ExecutionPayloadV1`][execution-payload]. -Methods are prefixed using the following convention: +### `ExecutionPayloadHeaderV1` -- `engine` prefix indicates calls made to the execution client. These methods are specified in the [execution engine APIs](https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.8/src/engine/specification.md). -- `builder` prefix indicates calls made to the mev-boost sidecar. -- `relay` prefix indicates calls made to a relay. +Equivalent to `ExecutionPayloadV1`, except `transactions` is replaced with `transactionsRoot`. +- `parentHash`: `DATA`, 32 Bytes +- `feeRecipient`: `DATA`, 20 Bytes +- `stateRoot`: `DATA`, 32 Bytes +- `receiptsRoot`: `DATA`, 32 Bytes +- `logsBloom`: `DATA`, 256 Bytes +- `prevRandao`: `DATA`, 32 Bytes +- `blockNumber`: `QUANTITY`, 64 Bits +- `gasLimit`: `QUANTITY`, 64 Bits +- `gasUsed`: `QUANTITY`, 64 Bits +- `timestamp`: `QUANTITY`, 64 Bits +- `extraData`: `DATA`, 0 to 32 Bytes +- `baseFeePerGas`: `QUANTITY`, 256 Bits +- `blockHash`: `DATA`, 32 Bytes +- `transactionsRoot`: `DATA`, 32 Bytes -### engine_forkchoiceUpdatedV1 +#### SSZ Objects -See [engine_forkchoiceUpdatedV1](https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.8/src/engine/specification.md#engine_forkchoiceupdatedv1). +Consider the following definitions supplementary to the definitions in [`consensus-specs`][consensus-specs]. -### builder_proposeBlindedBlockV1 +##### `builder_setFeeRecipientV1` Request -#### Request +```python +class Request(Container): + feeRecipient: Bytes20 + timestamp: uint64 +``` -- method: `builder_proposeBlindedBlockV1` -- params: - 1. [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) +##### `builder_getPayloadV1` Response -#### Response +```python +class Response(Container): + payload: ExecutionPayloadHeader + value: uint256 +``` -- result: [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayload). -- error: code and message set in case an exception happens while proposing the payload. +##### `builder_getPayloadV1` Request -Technically, this call only needs to return the `transactions` field of [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayload), but we return the full payload for simplicity. +###### `BlindBeaconBlock` -### builder_getPayloadHeaderV1 +```python +class BlindBeaconBlock(Container): + slot: Slot + proposer_index: ValidatorIndex + parent_root: Root + state_root: Root + body: BlindBeaconBlockBody +``` -#### Request +###### `BlindBeaconBlockBody` + +```python +class BlindBeaconBlockBody(Container): + randao_reveal: BLSSignature + eth1_data: Eth1Data + graffiti: Bytes32 + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] + attestations: List[Attestation, MAX_ATTESTATIONS] + deposits: List[Deposit, MAX_DEPOSITS] + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] + sync_aggregate: SyncAggregate + execution_payload: ExecutionPayloadHeader +``` -- method: `builder_getPayloadHeaderV1` -- params: - 1. `payloadId`: `DATA`, 8 Bytes - Identifier of the payload build process +## Errors -#### Response +The list of error codes introduced by this specification can be found below. -- result: [`ExecutionPayloadHeaderV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayloadheader) -- error: code and message set in case an exception happens while getting the payload. +| Code | Message | Meaning | +| - | - | - | +| -32000 | Server error | Generic client error while processing request. | +| -32001 | Unknown hash | No block with the provided hash is known. | +| -32002 | Unknown validator | No known mapping between validator and feeRecipient. | +| -32003 | Invalid SSZ | Unable to decode SSZ. | +| -32004 | Unknown block | Block does not match the provided header. | +| -32005 | Invalid signature | Provided signature is invalid. | +| -32006 | Invalid timestamp | Provided timestamp was invalid. | +| -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. | +| -32700 | Parse error | Invalid JSON was received by the server. | -### relay_getPayloadHeaderV1 +## Routines -#### Request +### Signing -- method: `relay_getPayloadHeaderV1` -- params: - 1. `payloadId`: `DATA`, 8 Bytes - Identifier of the payload build process +All signature operations should follow the [standard BLS operations][bls] interface defined in `consensus-specs`. -#### Response +There are two types of data to sign over in the Builder API: +* In-protocol messages, e.g. [`BlindBeaconBlock`](#blindbeaconblock), which should compute the signing root using [`computer_signing_root`][compute-signing-root] and use the domain specified for beacon block proposals. +* Builder API messages, e.g. [`builder_setFeeRecipientV1`](#builder_setFeeRecipientV1) and the response to [`builder_getHeader`](#response-2), which should compute the signing root using [`compute_signing_root`][compute-signing-root] and the domain `DomainType('0xXXXXXXXX')` (TODO: get a proper domain). -- result: [`SignedMEVPayloadHeader`](#signedmevpayloadheader) -- error: code and message set in case an exception happens while getting the payload. +As `compute_signing_root` takes `SSZObject` as input, client software should convert in-protocol messages to their SSZ representation to compute the signing root and Builder API messages to the SSZ representations defined [above](#sszobjects). + +## Methods -### relay_proposeBlindedBlockV1 +### `builder_setFeeRecipientV1` #### Request -- method: `relay_proposeBlindedBlockV1` +- method: `builder_setFeeRecipientV1` - params: - 1. [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) - 2. [`SignedMEVPayloadHeader`](#signedmevpayloadheader) + 1. `feeRecipient`: `DATA`, 20 Bytes - Address of account which should receive fees. + 2. `timestamp`: `QUANTITY`, uint64 - Unix timestamp of announcement. + 2. `publicKey`: `DATA`, 48 Bytes - Public key of validator. + 3. `signature`: `DATA`, 96 Bytes - Signature over `feeRecipient` and `timestamp`. #### Response -- result: [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayload) -- error: code and message set in case an exception happens while proposing the payload. - -Technically, this call only needs to return the `transactions` field of [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayload), but we return the full payload for simplicity. - -### Types - -#### SignedMEVPayloadHeader +- result: `null` +- error: code and message set in case an exception happens while getting the payload. -See [here](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/beacon-chain.md#custom-types) for the definition of fields like `BLSSignature` +#### Specification +1. Builder software **MUST** verify `signature` is valid under `publicKey`. +2. Builder software **MUST** respond to requests where `timestamp` is before the latest announcement from the validator or more than +/- 10 seconds from the current time with `-32006: Invalid timestamp`. +3. Builder software **MUST** store `feeRecipient` in a map keyed by `publicKey`. -- message: [MEVPayloadHeader](#mevpayloadheader) -- signature: BLSSignature +### `builder_getHeaderV1` -#### MEVPayloadHeader +#### Request -- payloadHeader: [`ExecutionPayloadHeaderV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayloadheader) -- feeRecipientDiff: Quantity, 256 Bits - the change in balance of the feeRecipient address +- method: `builder_getHeaderV1` +- params: + 1. `hash`: `DATA`, 32 Bytes - Hash of block which the validator intends to use as the parent for its proposal. -#### SignedBlindedBeaconBlock +#### Response -See [here](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/beacon-chain.md#custom-types) for the definition of fields like `BLSSignature` +- result: `object` + - `header`: [`ExecutionPayloadHeaderV1`](#executionpayloadheaderv1). + - `value`: `DATA`, 32 Bytes - the change in wei balance of the `feeRecipient` account. + - `publicKey`: `DATA`, 48 Bytes - the public key associated with the builder. + - `signature`: `DATA`, 96 Bytes - BLS signature of the builder over `payload` and `value`. +- error: code and message set in case an exception happens while getting the payload. -- message: [BlindedBeaconBlock](#blindedbeaconblock) -- signature: BLSSignature +#### Specification +1. Builder software **SHOULD** respond immediately with the `header` that increases the `feeRecipient`'s balance by the most. +2. Builder software **MUST** return `-32001: Unknown hash` if the block identified by `hash` does not exist. +3. Builder software **MUST** return `-32002: Unknown validator` if the validator the builder expects to propose in the current slot has not been mapped to a `feeRecipient`. -#### BlindedBeaconBlock +### `builder_getPayloadV1` -This is forked from [here](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/beacon-chain.md#beaconblock) with `body` replaced with `BlindedBeaconBlockBody` +#### Request -- slot: Slot -- proposer_index: ValidatorIndex -- parent_root: Root -- state_root: Root -- body: BlindedBeaconBlockBody +- method: `builder_getPayloadV1` +- params: + 1. `block`: `DATA`, arbitray length - SSZ encoded [`BlindBeaconBlock`](#blindbeaconblock). + 2. `signature`: `DATA`, 96 Bytes - BLS signature of the validator over `block`. -#### BlindedBeaconBlockBody +#### Response -This is forked from [here](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/merge/beacon-chain.md#beaconblockbody) with `execution_payload` replaced with [execution_payload_header](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayloadheader) +- result: [`ExecutionPayloadV1`](#executionpayloadv1). +- error: code and message set in case an exception happens while proposing the payload. -- randao_reveal: BLSSignature -- eth1_data: Eth1Data -- graffiti: Bytes32 -- proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] -- attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] -- attestations: List[Attestation, MAX_ATTESTATIONS] -- deposits: List[Deposit, MAX_DEPOSITS] -- voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] -- sync_aggregate: SyncAggregate -- execution_payload_header: ExecutionPayloadHeader +#### Specification +1. Builder software **MUST** verify that `block` is an SSZ encoded [`BlindBeaconBlock`](#blindbeaconblock). If the block is encoded incorrectly, the builder **MUST** return `-32003: Invalid SSZ`. If the block is encoded correctly, but does not match the `ExecutionPayloadHeaderV1` provided in `builder_getExecutionPayloadHeaderV1`, the builder **SHOULD** return `-32004: Unknown block`. If the CL modifies the payload in such a way that it is still valid and the builder is able to unblind it, the builder **MAY** update the payload on it's end to reflect the CL's changes before returning it. +2. Builder software **MUST** verify that `signature` is a BLS signature over `block`, verifiable using [`verify_block_signature`][verify-block-signature] and the validator public key that is expected to propose in the given slot. If the signature is determined to be invalid or from a different validator than expected, the builder **MUST** return `-32005: Invalid signature`. + +[consensus-specs]: https://github.com/ethereum/consensus-specs +[bls]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#bls-signatures +[compute-signing-root]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_signing_root +[bytes20]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#aliases +[uint256]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#basic-types +[execution-payload-header]: https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#executionpayloadheader +[execution-payload]: https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#executionpayloadv1 +[hash-tree-root]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization +[beacon-block]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblock +[verify-block-signature]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function