|
1 | | -# Version 0.1 (current, milestone 1, running on [Kiln testnet](https://kiln.themerge.dev/)) |
| 1 | +# Version 0.2 |
2 | 2 |
|
3 | | -This initial milestone provides simple sidecar logic with minimal consensus client changes, simple networking, no validator authentication, and manual safety mechanism. |
4 | | - |
5 | | -1. _mev-boost_ is initialized with a list of `RelayURI`s from trusted relays. |
6 | | - |
7 | | -2. _mev-boost_ receives a [`engine_forkchoiceUpdatedV1`](#engine_forkchoiceupdatedv1) call from a beacon node and forwards it to all connected relays to communicate `feeRecipient`. |
8 | | - |
9 | | -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`. |
10 | | - |
11 | | -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). |
12 | | - |
13 | | -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. |
14 | | - |
15 | | -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_. |
| 3 | +This document specifies the Builder API methods that the Consensus Layer uses to interact with external block builders. |
16 | 4 |
|
17 | 5 | ```mermaid |
18 | 6 | sequenceDiagram |
| 7 | + participant consensus |
| 8 | + participant mev_boost |
| 9 | + participant relays |
19 | 10 | Title: Block Proposal |
20 | | - consensus-->+mev_boost: engine_forkchoiceUpdatedV1 |
21 | | - mev_boost->>-relays: engine_forkchoiceUpdatedV1 |
| 11 | + Note over consensus: sign fee recipient announcement |
| 12 | + consensus->>mev_boost: builder_setFeeRecipient |
| 13 | + mev_boost->>relays: builder_setFeeRecipient |
22 | 14 | Note over consensus: wait for allocated slot |
23 | | - consensus->>+mev_boost: builder_getPayloadHeaderV1 |
24 | | - mev_boost->>relays: relay_getPayloadHeaderV1 |
25 | | - Note over mev_boost: select most valuable payload |
26 | | - mev_boost-->>-consensus: builder_getPayloadHeaderV1 response |
| 15 | + consensus->>mev_boost: builder_getHeader |
| 16 | + mev_boost->>relays: builder_getHeader |
| 17 | + relays-->>mev_boost: builder_getHeader response |
| 18 | + Note over mev_boost: verify response matches expected |
| 19 | + Note over mev_boost: select best payload |
| 20 | + mev_boost-->>consensus: builder_getHeader response |
27 | 21 | Note over consensus: sign the block |
28 | | - consensus->>+mev_boost: builder_proposeBlindedBlockV1 |
| 22 | + consensus->>mev_boost: builder_getPayload |
29 | 23 | Note over mev_boost: identify payload source |
30 | | - mev_boost->>relays: relay_proposeBlindedBlockV1 |
| 24 | + mev_boost->>relays: builder_getPayload |
31 | 25 | Note over relays: validate signature |
32 | | - relays-->>mev_boost: relay_proposeBlindedBlockV1 response |
33 | | - mev_boost-->>-consensus: builder_proposeBlindedBlockV1 response |
| 26 | + relays-->>mev_boost: builder_getPayload response |
| 27 | + Note over mev_boost: verify response matches expected |
| 28 | + mev_boost-->>consensus: builder_getPayload response |
34 | 29 | ``` |
35 | 30 |
|
36 | | -## Required client modifications |
| 31 | +## Structures |
37 | 32 |
|
38 | | -- consensus client must implement [blind transaction signing](https://hackmd.io/@paulhauner/H1XifIQ_t#Change-1-Blind-Transaction-Signing) |
| 33 | +### `ExecutionPayloadV1` |
39 | 34 |
|
40 | | -## API |
| 35 | +Mirror of [`ExecutionPayloadV1`][execution-payload]. |
41 | 36 |
|
42 | | -Methods are prefixed using the following convention: |
| 37 | +### `ExecutionPayloadHeaderV1` |
43 | 38 |
|
44 | | -- `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). |
45 | | -- `builder` prefix indicates calls made to the mev-boost sidecar. |
46 | | -- `relay` prefix indicates calls made to a relay. |
| 39 | +Equivalent to `ExecutionPayloadV1`, except `transactions` is replaced with `transactionsRoot`. |
| 40 | +- `parentHash`: `DATA`, 32 Bytes |
| 41 | +- `feeRecipient`: `DATA`, 20 Bytes |
| 42 | +- `stateRoot`: `DATA`, 32 Bytes |
| 43 | +- `receiptsRoot`: `DATA`, 32 Bytes |
| 44 | +- `logsBloom`: `DATA`, 256 Bytes |
| 45 | +- `prevRandao`: `DATA`, 32 Bytes |
| 46 | +- `blockNumber`: `QUANTITY`, 64 Bits |
| 47 | +- `gasLimit`: `QUANTITY`, 64 Bits |
| 48 | +- `gasUsed`: `QUANTITY`, 64 Bits |
| 49 | +- `timestamp`: `QUANTITY`, 64 Bits |
| 50 | +- `extraData`: `DATA`, 0 to 32 Bytes |
| 51 | +- `baseFeePerGas`: `QUANTITY`, 256 Bits |
| 52 | +- `blockHash`: `DATA`, 32 Bytes |
| 53 | +- `transactionsRoot`: `DATA`, 32 Bytes |
47 | 54 |
|
48 | | -### engine_forkchoiceUpdatedV1 |
| 55 | +#### SSZ Objects |
49 | 56 |
|
50 | | -See [engine_forkchoiceUpdatedV1](https://github.com/ethereum/execution-apis/blob/v1.0.0-alpha.8/src/engine/specification.md#engine_forkchoiceupdatedv1). |
| 57 | +Consider the following definitions supplementary to the definitions in [`consensus-specs`][consensus-specs]. |
51 | 58 |
|
52 | | -### builder_proposeBlindedBlockV1 |
| 59 | +##### `builder_setFeeRecipientV1` Request |
53 | 60 |
|
54 | | -#### Request |
| 61 | +```python |
| 62 | +class Request(Container): |
| 63 | + feeRecipient: Bytes20 |
| 64 | + timestamp: uint64 |
| 65 | +``` |
55 | 66 |
|
56 | | -- method: `builder_proposeBlindedBlockV1` |
57 | | -- params: |
58 | | - 1. [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) |
| 67 | +##### `builder_getPayloadV1` Response |
59 | 68 |
|
60 | | -#### Response |
| 69 | +```python |
| 70 | +class Response(Container): |
| 71 | + payload: ExecutionPayloadHeader |
| 72 | + value: uint256 |
| 73 | +``` |
61 | 74 |
|
62 | | -- result: [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayload). |
63 | | -- error: code and message set in case an exception happens while proposing the payload. |
| 75 | +##### `builder_getPayloadV1` Request |
64 | 76 |
|
65 | | -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. |
| 77 | +###### `BlindBeaconBlock` |
66 | 78 |
|
67 | | -### builder_getPayloadHeaderV1 |
| 79 | +```python |
| 80 | +class BlindBeaconBlock(Container): |
| 81 | + slot: Slot |
| 82 | + proposer_index: ValidatorIndex |
| 83 | + parent_root: Root |
| 84 | + state_root: Root |
| 85 | + body: BlindBeaconBlockBody |
| 86 | +``` |
68 | 87 |
|
69 | | -#### Request |
| 88 | +###### `BlindBeaconBlockBody` |
| 89 | + |
| 90 | +```python |
| 91 | +class BlindBeaconBlockBody(Container): |
| 92 | + randao_reveal: BLSSignature |
| 93 | + eth1_data: Eth1Data |
| 94 | + graffiti: Bytes32 |
| 95 | + proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] |
| 96 | + attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] |
| 97 | + attestations: List[Attestation, MAX_ATTESTATIONS] |
| 98 | + deposits: List[Deposit, MAX_DEPOSITS] |
| 99 | + voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] |
| 100 | + sync_aggregate: SyncAggregate |
| 101 | + execution_payload: ExecutionPayloadHeader |
| 102 | +``` |
70 | 103 |
|
71 | | -- method: `builder_getPayloadHeaderV1` |
72 | | -- params: |
73 | | - 1. `payloadId`: `DATA`, 8 Bytes - Identifier of the payload build process |
| 104 | +## Errors |
74 | 105 |
|
75 | | -#### Response |
| 106 | +The list of error codes introduced by this specification can be found below. |
76 | 107 |
|
77 | | -- result: [`ExecutionPayloadHeaderV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayloadheader) |
78 | | -- error: code and message set in case an exception happens while getting the payload. |
| 108 | +| Code | Message | Meaning | |
| 109 | +| - | - | - | |
| 110 | +| -32000 | Server error | Generic client error while processing request. | |
| 111 | +| -32001 | Unknown hash | No block with the provided hash is known. | |
| 112 | +| -32002 | Unknown validator | No known mapping between validator and feeRecipient. | |
| 113 | +| -32003 | Invalid SSZ | Unable to decode SSZ. | |
| 114 | +| -32004 | Unknown block | Block does not match the provided header. | |
| 115 | +| -32005 | Invalid signature | Provided signature is invalid. | |
| 116 | +| -32006 | Invalid timestamp | Provided timestamp was invalid. | |
| 117 | +| -32600 | Invalid request | The JSON sent is not a valid Request object. | |
| 118 | +| -32601 | Method not found | The method does not exist / is not available. | |
| 119 | +| -32602 | Invalid params | Invalid method parameter(s). | |
| 120 | +| -32603 | Internal error | Internal JSON-RPC error. | |
| 121 | +| -32700 | Parse error | Invalid JSON was received by the server. | |
79 | 122 |
|
80 | | -### relay_getPayloadHeaderV1 |
| 123 | +## Routines |
81 | 124 |
|
82 | | -#### Request |
| 125 | +### Signing |
83 | 126 |
|
84 | | -- method: `relay_getPayloadHeaderV1` |
85 | | -- params: |
86 | | - 1. `payloadId`: `DATA`, 8 Bytes - Identifier of the payload build process |
| 127 | +All signature operations should follow the [standard BLS operations][bls] interface defined in `consensus-specs`. |
87 | 128 |
|
88 | | -#### Response |
| 129 | +There are two types of data to sign over in the Builder API: |
| 130 | +* 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. |
| 131 | +* 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). |
89 | 132 |
|
90 | | -- result: [`SignedMEVPayloadHeader`](#signedmevpayloadheader) |
91 | | -- error: code and message set in case an exception happens while getting the payload. |
| 133 | +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). |
| 134 | + |
| 135 | +## Methods |
92 | 136 |
|
93 | | -### relay_proposeBlindedBlockV1 |
| 137 | +### `builder_setFeeRecipientV1` |
94 | 138 |
|
95 | 139 | #### Request |
96 | 140 |
|
97 | | -- method: `relay_proposeBlindedBlockV1` |
| 141 | +- method: `builder_setFeeRecipientV1` |
98 | 142 | - params: |
99 | | - 1. [`SignedBlindedBeaconBlock`](#signedblindedbeaconblock) |
100 | | - 2. [`SignedMEVPayloadHeader`](#signedmevpayloadheader) |
| 143 | + 1. `feeRecipient`: `DATA`, 20 Bytes - Address of account which should receive fees. |
| 144 | + 2. `timestamp`: `QUANTITY`, uint64 - Unix timestamp of announcement. |
| 145 | + 2. `publicKey`: `DATA`, 48 Bytes - Public key of validator. |
| 146 | + 3. `signature`: `DATA`, 96 Bytes - Signature over `feeRecipient` and `timestamp`. |
101 | 147 |
|
102 | 148 | #### Response |
103 | 149 |
|
104 | | -- result: [`ExecutionPayloadV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayload) |
105 | | -- error: code and message set in case an exception happens while proposing the payload. |
106 | | - |
107 | | -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. |
108 | | - |
109 | | -### Types |
110 | | - |
111 | | -#### SignedMEVPayloadHeader |
| 150 | +- result: `null` |
| 151 | +- error: code and message set in case an exception happens while getting the payload. |
112 | 152 |
|
113 | | -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` |
| 153 | +#### Specification |
| 154 | +1. Builder software **MUST** verify `signature` is valid under `publicKey`. |
| 155 | +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`. |
| 156 | +3. Builder software **MUST** store `feeRecipient` in a map keyed by `publicKey`. |
114 | 157 |
|
115 | | -- message: [MEVPayloadHeader](#mevpayloadheader) |
116 | | -- signature: BLSSignature |
| 158 | +### `builder_getHeaderV1` |
117 | 159 |
|
118 | | -#### MEVPayloadHeader |
| 160 | +#### Request |
119 | 161 |
|
120 | | -- payloadHeader: [`ExecutionPayloadHeaderV1`](https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/bellatrix/beacon-chain.md#executionpayloadheader) |
121 | | -- feeRecipientDiff: Quantity, 256 Bits - the change in balance of the feeRecipient address |
| 162 | +- method: `builder_getHeaderV1` |
| 163 | +- params: |
| 164 | + 1. `hash`: `DATA`, 32 Bytes - Hash of block which the validator intends to use as the parent for its proposal. |
122 | 165 |
|
123 | | -#### SignedBlindedBeaconBlock |
| 166 | +#### Response |
124 | 167 |
|
125 | | -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` |
| 168 | +- result: `object` |
| 169 | + - `header`: [`ExecutionPayloadHeaderV1`](#executionpayloadheaderv1). |
| 170 | + - `value`: `DATA`, 32 Bytes - the change in wei balance of the `feeRecipient` account. |
| 171 | + - `publicKey`: `DATA`, 48 Bytes - the public key associated with the builder. |
| 172 | + - `signature`: `DATA`, 96 Bytes - BLS signature of the builder over `payload` and `value`. |
| 173 | +- error: code and message set in case an exception happens while getting the payload. |
126 | 174 |
|
127 | | -- message: [BlindedBeaconBlock](#blindedbeaconblock) |
128 | | -- signature: BLSSignature |
| 175 | +#### Specification |
| 176 | +1. Builder software **SHOULD** respond immediately with the `header` that increases the `feeRecipient`'s balance by the most. |
| 177 | +2. Builder software **MUST** return `-32001: Unknown hash` if the block identified by `hash` does not exist. |
| 178 | +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`. |
129 | 179 |
|
130 | | -#### BlindedBeaconBlock |
| 180 | +### `builder_getPayloadV1` |
131 | 181 |
|
132 | | -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` |
| 182 | +#### Request |
133 | 183 |
|
134 | | -- slot: Slot |
135 | | -- proposer_index: ValidatorIndex |
136 | | -- parent_root: Root |
137 | | -- state_root: Root |
138 | | -- body: BlindedBeaconBlockBody |
| 184 | +- method: `builder_getPayloadV1` |
| 185 | +- params: |
| 186 | + 1. `block`: `DATA`, arbitray length - SSZ encoded [`BlindBeaconBlock`](#blindbeaconblock). |
| 187 | + 2. `signature`: `DATA`, 96 Bytes - BLS signature of the validator over `block`. |
139 | 188 |
|
140 | | -#### BlindedBeaconBlockBody |
| 189 | +#### Response |
141 | 190 |
|
142 | | -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) |
| 191 | +- result: [`ExecutionPayloadV1`](#executionpayloadv1). |
| 192 | +- error: code and message set in case an exception happens while proposing the payload. |
143 | 193 |
|
144 | | -- randao_reveal: BLSSignature |
145 | | -- eth1_data: Eth1Data |
146 | | -- graffiti: Bytes32 |
147 | | -- proposer_slashings: List[ProposerSlashing, MAX_PROPOSER_SLASHINGS] |
148 | | -- attester_slashings: List[AttesterSlashing, MAX_ATTESTER_SLASHINGS] |
149 | | -- attestations: List[Attestation, MAX_ATTESTATIONS] |
150 | | -- deposits: List[Deposit, MAX_DEPOSITS] |
151 | | -- voluntary_exits: List[SignedVoluntaryExit, MAX_VOLUNTARY_EXITS] |
152 | | -- sync_aggregate: SyncAggregate |
153 | | -- execution_payload_header: ExecutionPayloadHeader |
| 194 | +#### Specification |
| 195 | +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. |
| 196 | +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`. |
| 197 | + |
| 198 | +[consensus-specs]: https://github.com/ethereum/consensus-specs |
| 199 | +[bls]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#bls-signatures |
| 200 | +[compute-signing-root]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#compute_signing_root |
| 201 | +[bytes20]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#aliases |
| 202 | +[uint256]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#basic-types |
| 203 | +[execution-payload-header]: https://github.com/ethereum/consensus-specs/blob/dev/specs/bellatrix/beacon-chain.md#executionpayloadheader |
| 204 | +[execution-payload]: https://github.com/ethereum/execution-apis/blob/main/src/engine/specification.md#executionpayloadv1 |
| 205 | +[hash-tree-root]: https://github.com/ethereum/consensus-specs/blob/dev/ssz/simple-serialize.md#merkleization |
| 206 | +[beacon-block]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beaconblock |
| 207 | +[verify-block-signature]: https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/beacon-chain.md#beacon-chain-state-transition-function |
0 commit comments