-
Notifications
You must be signed in to change notification settings - Fork 221
Produce block v4 with payload #580
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
Changes from all commits
e902e3b
56be573
e74fde6
5c28168
6ee20eb
25de51f
0c45859
8bf9080
b9b6fc6
f78aaef
5413e57
6a64ee1
45f142a
3fed1ee
b613dde
7c1c6b1
72b9ba2
4114350
7c9fa88
cb1244b
947f91d
b92bc94
e69b73e
7dcfcc4
76ea0ba
bed49d9
eaf5eec
19dc4db
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 |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| post: | ||
| operationId: publishExecutionPayloadEnvelope | ||
| summary: Publish signed execution payload envelope | ||
| description: | | ||
| Instructs the beacon node to broadcast a signed execution payload envelope to the network, | ||
| to be gossiped for payload validation. A success response (20x) indicates | ||
| that the envelope passed gossip validation and was successfully broadcast onto the network. | ||
| The beacon node is also expected to integrate the envelope into the state, but may broadcast it | ||
| before doing so, so as to aid timely delivery of the envelope. Should the envelope fail full | ||
| validation, a separate success response code (202) is used to indicate that the envelope was | ||
| successfully broadcast but failed integration. The broadcast behaviour may be adjusted via | ||
| the `broadcast_validation` query parameter. | ||
|
|
||
| The request body can be either form, distinguished by the `Eth-Execution-Payload-Blinded` | ||
| header: | ||
| - A `SignedExecutionPayloadEnvelopeContents` object (header `false`) containing the signed | ||
| envelope along with blobs and KZG proofs. This is used in stateless operation (multi-BN | ||
| setups, distributed validators, failover) where the receiving beacon node does not have | ||
| the blobs cached. | ||
| - A `SignedBlindedExecutionPayloadEnvelope` object (header `true`) containing the signed | ||
| blinded envelope (transactions omitted). This is used in stateful operation where the | ||
| beacon node already has the full envelope and blobs cached from block production. The | ||
| beacon node reconstructs the full envelope from its cache before broadcasting; the | ||
| signature is valid over both forms by construction. | ||
| tags: | ||
| - Beacon | ||
| - ValidatorRequiredApi | ||
| parameters: | ||
| - name: broadcast_validation | ||
| in: query | ||
| required: false | ||
| description: | | ||
| Level of validation that must be applied to an envelope before it is broadcast. | ||
|
|
||
| Possible values: | ||
| - **`gossip`** (default): lightweight gossip checks only | ||
| - **`consensus`**: full consensus checks, including validation of all signatures and | ||
| envelope fields. | ||
| - **`consensus_and_equivocation`**: the same as `consensus`, with an extra check that | ||
| the envelope's beacon block is not an equivocation. If the block is found to be an | ||
| equivocation, validation fails. This is recommended for builders to protect against | ||
| unbundling attacks where a malicious proposer publishes equivocating blocks to extract | ||
| payload contents from honest builders. | ||
|
|
||
| If the envelope fails the requested level of validation, a 400 status MUST be returned | ||
| immediately and the envelope MUST NOT be broadcast to the network. | ||
|
|
||
| If validation succeeds, the envelope must still be fully verified before it is | ||
| incorporated into the state and a 20x status is returned to the caller. | ||
| schema: | ||
| $ref: '../../../beacon-node-oapi.yaml#/components/schemas/BroadcastValidation' | ||
| - 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 execution payload envelope being submitted belongs." | ||
| - in: header | ||
| name: Eth-Execution-Payload-Blinded | ||
| required: true | ||
| schema: | ||
| type: boolean | ||
| description: | | ||
| Indicates which body schema is submitted (see the | ||
| [`Eth-Execution-Payload-Blinded`](#/components/headers/Eth-Execution-Payload-Blinded) | ||
| header). When `false`, the body is a `SignedExecutionPayloadEnvelopeContents` (full | ||
| envelope plus blobs and KZG proofs, stateless flow). When `true`, the body is a | ||
| `SignedBlindedExecutionPayloadEnvelope` (blinded envelope only, stateful flow; the | ||
| beacon node must have cached the full envelope and blobs from block production). | ||
| requestBody: | ||
| description: "The `SignedExecutionPayloadEnvelopeContents` or `SignedBlindedExecutionPayloadEnvelope` object to be broadcast, selected via the `Eth-Execution-Payload-Blinded` header." | ||
| required: true | ||
| content: | ||
| application/json: | ||
| schema: | ||
| anyOf: | ||
| - $ref: "../../../beacon-node-oapi.yaml#/components/schemas/Gloas.SignedExecutionPayloadEnvelopeContents" | ||
| - $ref: "../../../beacon-node-oapi.yaml#/components/schemas/Gloas.SignedBlindedExecutionPayloadEnvelope" | ||
| application/octet-stream: | ||
| schema: | ||
| description: "SSZ serialized `SignedExecutionPayloadEnvelopeContents` or `SignedBlindedExecutionPayloadEnvelope` bytes. Use the `Eth-Execution-Payload-Blinded` header to select the schema." | ||
| responses: | ||
| "200": | ||
| description: "The envelope was validated successfully and has been broadcast. It has also been integrated into the beacon node's database." | ||
| "202": | ||
| description: "The envelope could not be integrated into the beacon node's database as it failed validation, but was successfully broadcast." | ||
| "400": | ||
| description: | | ||
| The signed envelope object is invalid, broadcast validation failed, or a blinded | ||
| envelope was submitted but the beacon node has no cached full envelope to reconstruct | ||
| from (e.g. because block production happened on a different beacon node). | ||
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "../../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage" | ||
| example: | ||
| code: 400 | ||
| message: "Invalid signed execution payload envelope" | ||
| "415": | ||
| $ref: "../../../beacon-node-oapi.yaml#/components/responses/UnsupportedMediaType" | ||
| "500": | ||
| $ref: "../../../beacon-node-oapi.yaml#/components/responses/InternalError" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,157 @@ | ||
| get: | ||
| 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. | ||
|
|
||
| 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. | ||
|
|
||
| When self-building (local execution payload), the response will include the full block contents | ||
| including the beacon block, execution payload envelope, blobs, and KZG proofs. | ||
| 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. | ||
|
|
||
| The `Eth-Execution-Payload-Included` header and `execution_payload_included` response field | ||
| indicate which response type was returned. | ||
| parameters: | ||
| - name: slot | ||
| in: path | ||
| required: true | ||
| description: "The slot for which the block should be proposed." | ||
| schema: | ||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/Uint64" | ||
| - name: randao_reveal | ||
| in: query | ||
| required: true | ||
| description: "The validator's randao reveal value." | ||
| schema: | ||
| $ref: '../../beacon-node-oapi.yaml#/components/schemas/Signature' | ||
| - name: graffiti | ||
| in: query | ||
| required: false | ||
| description: "Arbitrary data validator wants to include in block." | ||
| schema: | ||
| $ref: '../../beacon-node-oapi.yaml#/components/schemas/Graffiti' | ||
| - name: skip_randao_verification | ||
| $ref: '../../beacon-node-oapi.yaml#/components/parameters/SkipRandaoVerification' | ||
| - name: include_payload | ||
| in: query | ||
| required: false | ||
| description: | | ||
| Controls whether the execution payload envelope and blobs are included in the response | ||
| when self-building (using local execution payload). | ||
|
|
||
| When `true` (default), the response includes the full block contents: beacon block, | ||
| execution payload envelope, blobs, and KZG proofs. This enables stateless operation | ||
| where the validator client can use multiple beacon nodes (multi-BN setups, distributed validators, failover). | ||
|
|
||
| When `false`, only the beacon block is returned and the beacon node caches the execution | ||
| payload envelope and blobs internally. The validator client must then fetch them separately | ||
| via `GET /eth/v1/validator/execution_payload_envelopes/{slot}/{beacon_block_root}`. This saves | ||
| 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). | ||
| schema: | ||
| type: boolean | ||
| default: true | ||
| - name: builder_boost_factor | ||
|
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. @bharath-123 if a client doesn't have builders configured via api, we don't wanna submit builder preferences at all, so moving boost factor and other parameters there seem wrong to me, we need a way for the validator to signal this to the beacon node. And I don't think the beacon api should be concerned about off protocol builders or per builder configs |
||
| 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_payload_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 payload 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" | ||
| responses: | ||
| "200": | ||
| description: Success response | ||
| headers: | ||
| Eth-Consensus-Version: | ||
| $ref: '../../beacon-node-oapi.yaml#/components/headers/Eth-Consensus-Version' | ||
| Eth-Consensus-Block-Value: | ||
| $ref: '../../beacon-node-oapi.yaml#/components/headers/Eth-Consensus-Block-Value' | ||
| Eth-Execution-Payload-Included: | ||
| $ref: '../../beacon-node-oapi.yaml#/components/headers/Eth-Execution-Payload-Included' | ||
| content: | ||
| application/json: | ||
| schema: | ||
| title: "ProduceBlockV4Response" | ||
| type: object | ||
| required: [version, consensus_block_value, execution_payload_included, data] | ||
| properties: | ||
| version: | ||
| type: string | ||
| enum: [gloas] | ||
| example: "gloas" | ||
| consensus_block_value: | ||
| type: string | ||
| example: "12345" | ||
| description: "Consensus rewards for this block in Wei" | ||
| execution_payload_included: | ||
| type: boolean | ||
| description: | | ||
| Indicates whether the execution payload envelope is included in the response. | ||
| When `true`, the `data` field contains the full | ||
| execution payload envelope, blobs, and KZG proofs. When `false`, the `data` | ||
| field contains only a `BeaconBlock`. | ||
| example: false | ||
| data: | ||
| anyOf: | ||
| - $ref: "../../beacon-node-oapi.yaml#/components/schemas/Gloas.BeaconBlock" | ||
| - $ref: "../../beacon-node-oapi.yaml#/components/schemas/Gloas.BlockContents" | ||
| application/octet-stream: | ||
| schema: | ||
| description: "SSZ serialized `BeaconBlock` or `BlockContents` bytes. Use Accept header to choose this response type, version string is sent in header `Eth-Consensus-Version` and payload inclusion indicated by `Eth-Execution-Payload-Included` header." | ||
| "400": | ||
| description: "Invalid block production request" | ||
| content: | ||
| application/json: | ||
| schema: | ||
| $ref: "../../beacon-node-oapi.yaml#/components/schemas/ErrorMessage" | ||
| examples: | ||
| InvalidRequest: | ||
| value: | ||
| code: 400 | ||
| message: "Invalid request to produce a block" | ||
| "406": | ||
| $ref: "../../beacon-node-oapi.yaml#/components/responses/NotAcceptable" | ||
| "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.
In
publishBlockV2we return 202 if block passed gossip validation but failed integration.Are we doing something similar for
publishExecutionPayloadEnvelope?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 guess from another angle to think about this is we broadcast the payload regardless the result of the payload integration, or we integrate first, if it goes well, we then gossip?
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.
We probably want to propagate the envelope as quickly as possible, so ideally:
process_execution_payloadand import to DBIf (1) fails, we 400. If (3) fails we should probably 202 just like for blocks.
I was hoping we could avoid the nastiness of
broadcast_validationfor envelopes, but I think there might actually be an unbundling attack (background) for envelopes now:I think there is an unbundling attack something like:
Aat slotNcommitting tobidAandpayloadA, wherebidAcomes from an external builder (could be P2P or otherwise).B(slashable) at slotNcommitting tobidBand payloadpayloadB. They will be slashed at the next slot.bidAstarts to publishpayloadA. Even on beacon nodes that have seen the equivocating block, the payload will PASS gossip validation as long as block A was imported.payloadBfor blockB. Envelope gossip validation passes forpayloadBbecause it is signed by a different builder frompayloadA.Proposed fixes:
broadcast_validation=equivocationflag (like we have for pre-Gloas blocks) to check that the envelope's block is not an equivocation. This flag would likely be used by all builders when interacting with their BNs.broadcast_validation=equivocationfrom fix 3, but no flag required and no ability to opt-out).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.
based off the discord convo, seems like a
broadcast_validationflag is warranted. I built it out in b9b6fc6 to use sameBroadcastValidationschema asproduceBlocksV2since all the possible values seem to make sense for envelopes as well, but lmk if have some other thoughts on itThere 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'm just catching up on the discussions here, but I think the
broadcast_validationflag and its values make sense to me.If im understanding correctly, the
broadcast_validation =consensus_and_equivocationvalue on the publish_block endpoint will no longer be useful for unbundling protection? Probably no harm to keep it though.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.
no, it's not needed for this anymore, we could discuss if we wanna deprecate
broadcast_validationonpublishBlockV2, but might still be useful to have basic checks before publishing the block