-
Notifications
You must be signed in to change notification settings - Fork 220
Update Beacon API for parity with Builder API and KeyManager API #630
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 16 commits
5daf8a7
21750d8
f8d2943
0ea8a06
adc1ae1
1028934
657d390
727f6b3
23b5555
3f886eb
979d038
ea9bafb
bb1e790
bd99f03
91db6c8
97c1cd9
f71b1b8
eb752a1
1dda02d
71c7315
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -43,6 +43,20 @@ post: | |
| required: true | ||
| name: Eth-Consensus-Version | ||
| description: "The active consensus version to which the block being submitted belongs." | ||
| - name: Eth-Builder-Url | ||
| in: header | ||
| required: false | ||
| description: | | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. it's required false but maybe we should specify that we must echo this and eth-builder-proxy when available if returned by produceBlockv4 just to be explicit |
||
| The `url` of the winning builder, as returned by `POST /eth/v4/validator/blocks/{slot}`. | ||
| When that endpoint returns this header the validator client MUST echo it here, so the beacon | ||
| node can forward the signed block to the same builder and the builder can release the | ||
| payload without waiting for gossip. The echo is what lets a beacon node that did not serve | ||
| the block-production request still forward it. Omitted for a self-built block or a block won | ||
| by a p2p bid. | ||
| schema: | ||
| type: string | ||
| format: uri | ||
| example: "https://builder.example.com" | ||
| requestBody: | ||
| description: "The `SignedBeaconBlock` object composed of `BeaconBlock` object (produced by beacon node) and validator signature." | ||
| required: true | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -1,25 +1,35 @@ | ||||||
| get: | ||||||
| post: | ||||||
| tags: | ||||||
| - Validator | ||||||
| - ValidatorRequiredApi | ||||||
| operationId: "produceBlockV4" | ||||||
| summary: "Produce a new block, without signature." | ||||||
| description: | | ||||||
| Requests a beacon node to produce a valid block, which can then be signed by a validator. | ||||||
| Requests a beacon node to produce a valid block, which the validator then signs. | ||||||
|
|
||||||
| Post-Gloas, proposers submit execution payload bids rather than full execution payloads, | ||||||
| so there is no longer a concept of blinded or unblinded blocks. Builders release the | ||||||
| payload later. This endpoint is specific to the post-Gloas forks and is not backwards compatible | ||||||
| with previous forks. | ||||||
| The beacon node always builds a local payload and MAY consider a p2p bid, so a block is returned | ||||||
| even when no bid is available. The validator client optionally supplies a `BuilderConfig` in the | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: there are several places where we mention bid (i.e. here "no bid is available"). in the local build case a bid is still constructed. It might be useful instead to specify builder bid, for example
Suggested change
there are multiple places in the PR where "bid" is assumed to be a builder bid. it might make things a bit clearer if we just explicitly say builder bid in those cases
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. not disagreeing with adding "builder" here as suggested but referring to local payload as "local bid" or similar is really confusing, during block proposal you either use a bid from a builder or you commit to a local payload, the fact that the
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yeah i totally agree with not using the term local bid |
||||||
| request body: a list of `BuilderEntry` objects in its `builders` field, one per bid request, | ||||||
| plus a top-level `min_bid` and `builder_boost_factor` that apply to p2p bids. Each entry | ||||||
| requests a bid from its `url`, and the entry applies to the bid that request returns; when the | ||||||
| entry also contains a `builder_pubkey`, that bid MUST NOT be accepted unless signed by it. | ||||||
|
|
||||||
| When self-building (local execution payload), the response includes the full block contents | ||||||
| (beacon block, execution payload envelope, blobs, and KZG proofs) if `include_payload` is | ||||||
| set to `true`, otherwise only the `BeaconBlock` is returned. | ||||||
| When using an external builder bid, only the `BeaconBlock` is returned as the beacon node | ||||||
| does not have access to the builder's execution payload. | ||||||
| A bid is rejected if its total payment falls below the `min_bid` that applies to it. Every | ||||||
| surviving bid is then boosted by the `builder_boost_factor` that applies to it, and the highest | ||||||
| boosted bid competes with the local build in Gwei. The local build wins a tie. | ||||||
|
|
||||||
| The `Eth-Execution-Payload-Included` header and `execution_payload_included` response field | ||||||
| indicate which response type was returned. | ||||||
| The response carries the full block contents only when the beacon node self-built the block and | ||||||
| `include_payload` is `true`; in every other case, including any bid win, it carries only the | ||||||
| `BeaconBlock`. | ||||||
|
|
||||||
| Every block is published via `POST /eth/v2/beacon/blocks`. A self-built block carries | ||||||
| `BUILDER_INDEX_SELF_BUILD` as its `builder_index`, and the validator client publishes its | ||||||
| execution payload envelope via `POST /eth/v1/beacon/execution_payload_envelopes`. When a bid | ||||||
| won, the winning builder releases the envelope instead, and the validator client echoes | ||||||
| `Eth-Builder-Url` if one was returned. | ||||||
|
|
||||||
| This endpoint is specific to the post-Gloas forks and is not backwards compatible with previous | ||||||
| forks. | ||||||
| parameters: | ||||||
| - name: slot | ||||||
| in: path | ||||||
|
|
@@ -58,46 +68,30 @@ get: | |||||
| bandwidth but requires the validator client to publish via the same beacon node that | ||||||
| produced the block (stateful operation). | ||||||
|
|
||||||
| This parameter only affects self-building scenarios. When using an external builder's bid, | ||||||
| only the beacon block is returned regardless of this parameter (the beacon node does not | ||||||
| have access to the builder's execution payload). | ||||||
| This parameter affects the self-built case only. When a bid wins, the beacon node does not | ||||||
| hold that payload, so it returns only the beacon block regardless of this parameter. | ||||||
| schema: | ||||||
| type: boolean | ||||||
| - name: builder_boost_factor | ||||||
| in: query | ||||||
| required: false | ||||||
| description: | | ||||||
| Percentage multiplier to apply to the builder's bid value when choosing between a | ||||||
| builder bid and payload from the paired execution node. This parameter is only relevant | ||||||
| if the beacon node has at least one viable builder `ExecutionPayloadBid` available and | ||||||
| receives a valid response from the paired execution node. When these preconditions are | ||||||
| met, the server MUST act as follows: | ||||||
|
|
||||||
| * if `exec_node_payload_value >= builder_boost_factor * (builder_bid_value // 100)` | ||||||
| for the highest builder bid known to the beacon node, then return a block committing | ||||||
| to the local execution node payload (with the payload itself included if | ||||||
| `include_payload` is set to true). | ||||||
| * otherwise, return a block committing to the builder bid (without execution payload, | ||||||
| as it is not yet available). | ||||||
|
|
||||||
| Servers must support the following values of the boost factor which encode common | ||||||
| preferences: | ||||||
|
|
||||||
| * `builder_boost_factor=0`: prefer the local execution node payload unless an error makes | ||||||
| it unviable. | ||||||
| * `builder_boost_factor=100`: profit maximization mode; choose whichever of the local | ||||||
| execution node payload and the builder bid pays more. | ||||||
| * `builder_boost_factor=2**64 - 1`: prefer the builder bid unless an error or beacon node | ||||||
| health check makes it unviable. | ||||||
|
|
||||||
| Servers should use saturating arithmetic or another technique to ensure that large values | ||||||
| of the `builder_boost_factor` do not trigger overflows or errors. If this parameter is | ||||||
| provided and no builder bid is available, the beacon node MUST respond with a block | ||||||
| committing to the local execution node payload, which the caller can choose to reject if | ||||||
| it wishes. If the value is provided but out of range for a 64-bit unsigned integer, then | ||||||
| an error response with status code 400 MUST be returned. | ||||||
| schema: | ||||||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/Uint64" | ||||||
| requestBody: | ||||||
| required: false | ||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. while this request body is not required, we should make the arguably it's only needed if also worth considering making passing |
||||||
| description: | | ||||||
| A `BuilderConfig` for this request: the builder entries to solicit bids from, plus the | ||||||
| top-level `min_bid` and `builder_boost_factor` that apply to p2p bids. | ||||||
| Each entry's `auth.message.slot` is the `slot` this request is for; | ||||||
| the builder rejects a mismatch, so an entry naming a different slot is one the beacon node | ||||||
| does not use for a bid request. A body that cannot be decoded is invalid and MUST fail with a | ||||||
| 400. Every other failure is per entry: an entry the beacon node rejects, or whose builder does | ||||||
| not answer, yields no bid and MUST NOT fail the request, so one bad entry never costs the | ||||||
| proposer its slot. When the body is omitted the validator client has supplied no | ||||||
| builder config, so the beacon node requests no bids and returns its locally built block. A | ||||||
| client that wants a bid considered, over the builder API or p2p, supplies a `BuilderConfig`. | ||||||
| content: | ||||||
| application/json: | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. wait we should also allow ssz |
||||||
| schema: | ||||||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/Gloas.BuilderConfig" | ||||||
| application/octet-stream: | ||||||
| schema: | ||||||
| description: "SSZ serialized `BuilderConfig` bytes (see the `BuilderConfig` type description for the container and constants). Use Content-Type header to indicate that SSZ data is contained in the request body." | ||||||
| responses: | ||||||
| "200": | ||||||
| description: Success response | ||||||
|
|
@@ -110,6 +104,18 @@ get: | |||||
| $ref: '../../beacon-node-oapi.yaml#/components/headers/Eth-Execution-Payload-Value' | ||||||
| Eth-Execution-Payload-Included: | ||||||
| $ref: '../../beacon-node-oapi.yaml#/components/headers/Eth-Execution-Payload-Included' | ||||||
| Eth-Builder-Url: | ||||||
| description: | | ||||||
| When the winning bid came through the builder-API channel, the `url` of that builder. | ||||||
| The validator echoes this value in the `Eth-Builder-Url` request header when publishing | ||||||
| the signed block, so the beacon node can forward the block to the same builder via the | ||||||
| builder-API `submitSignedBeaconBlock`. Absent when the block was self-built or the | ||||||
| winning bid came from the p2p network. | ||||||
| required: false | ||||||
| schema: | ||||||
| type: string | ||||||
| format: uri | ||||||
| example: "https://builder.example.com" | ||||||
| content: | ||||||
| application/json: | ||||||
| schema: | ||||||
|
|
@@ -159,6 +165,8 @@ get: | |||||
| message: "Invalid request to produce a block" | ||||||
| "406": | ||||||
| $ref: "../../beacon-node-oapi.yaml#/components/responses/NotAcceptable" | ||||||
| "415": | ||||||
| $ref: "../../beacon-node-oapi.yaml#/components/responses/UnsupportedMediaType" | ||||||
| "500": | ||||||
| $ref: '../../beacon-node-oapi.yaml#/components/responses/InternalError' | ||||||
| "503": | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| post: | ||
| operationId: "submitBuilderPreferences" | ||
| summary: Submit builder preferences | ||
| description: | | ||
| Submits per-builder preferences for one or more proposers. The request body is a flat list of | ||
| `BuilderPreferencesEntry` objects, each naming the proposer in `proposer_pubkey`; the beacon | ||
| node submits each to the builder-API `submitBuilderPreferences` endpoint at the entry's `url`. | ||
| Applicable from the Gloas fork onwards. | ||
|
|
||
| Notes: | ||
| - Each entry targets one builder `url`, to which the beacon node makes one submission. | ||
| - Entries are identified by `proposer_pubkey`, so several proposers MAY submit to the same `url`. | ||
| - The beacon node routes each entry by its `url` and submits to that builder's | ||
| `submitBuilderPreferences` for the entry's `proposer_pubkey`, forwarding the `auth` and | ||
| `max_execution_payment`. | ||
| - Validators MAY submit in the epoch prior to proposing (from `state.proposer_lookahead`), so | ||
| builders hold the preferences before the bid request arrives. | ||
| parameters: | ||
| - in: header | ||
| schema: | ||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/ConsensusVersion" | ||
| required: true | ||
| name: Eth-Consensus-Version | ||
| description: "The active consensus version to which the submitted builder preferences belong." | ||
| tags: | ||
| - Validator | ||
| requestBody: | ||
| required: true | ||
| description: "Array of `BuilderPreferencesEntry` objects to submit, one per builder per proposer." | ||
| content: | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. this api is missing fork versioning, wouldn't it be good to keep the door open to easily update how to deal with this on the builder-api side can be different, but I would just add a fork version to leave the door open to add a new container in heze, there isn't much harm to add this metadata
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
@JasonVranek let's discussion the versioning here, so from my experience, using a in my opinion and this has worked quite nicely so far is to use the
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
yes I believe I'm doing this exactly, just to verify:
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes sounds good to me, having |
||
| application/json: | ||
| schema: | ||
| type: array | ||
| maxItems: 4096 # MAX_BUILDER_ENTRIES * (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH | ||
| items: | ||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/Gloas.BuilderPreferencesEntry" | ||
| application/octet-stream: | ||
| schema: | ||
| description: "SSZ serialized `List[BuilderPreferencesEntry, MAX_BUILDER_ENTRIES * (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]` bytes. Use Content-Type header to indicate that SSZ data is contained in the request body." | ||
| responses: | ||
| "200": | ||
| description: "Every entry was submitted and its builder accepted it" | ||
| "400": | ||
| description: | | ||
| One or more entries failed; the others were still submitted. Each failure is reported by the | ||
| entry's index via `IndexedErrorMessage`, proxying the builder's error for that entry. | ||
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/IndexedErrorMessage" | ||
| "415": | ||
| $ref: "../../beacon-node-oapi.yaml#/components/responses/UnsupportedMediaType" | ||
| "500": | ||
| $ref: "../../beacon-node-oapi.yaml#/components/responses/InternalError" | ||
| "503": | ||
| $ref: "../../beacon-node-oapi.yaml#/components/responses/CurrentlySyncing" | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we really need this header? if I understand correctly the sole purpose of this is so that the beacon node knows where to submit it via
submitSignedBeaconBlockbut the beacon node should know this anyways, since it got the bid from that builder via apithe only case where the beacon node doesn't know this is if it's a different node (eg. in a multi-node setup) if the primary node that sourced the bid from the builder via api went offline during the proposal flow but this seems like an edge case and even then, publishing only via p2p is a fine fallback behavior that is sufficient anyways most of the time
that said, we can keep the header if people wanna have it, just questionable to me if it's useful enough
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this was solely for the multi-node support, not opinionated on it but it seemed like DVT teams wanted. Will leave for now and address most of the fat trimming comments
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not feel strongly about removing it, also I think when I commented there was in addition a
Eth-Proxy-Urlheader which is now gone, so this single header, if useful for DVT teams, might be worth keeping