From d87aa1a5e6b673cb44d1e9e3c9c3291581346129 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 17 Dec 2025 19:11:47 +0530 Subject: [PATCH 01/31] initial builder-api for gloas --- apis/builder/beacon_block.yaml | 50 ++++++++++++++ apis/builder/execution_payload_bid.yaml | 89 +++++++++++++++++++++++++ builder-oapi.yaml | 6 +- specs/gloas/builder.md | 34 ++++++++++ specs/gloas/validator.md | 38 +++++++++++ 5 files changed, 216 insertions(+), 1 deletion(-) create mode 100644 apis/builder/beacon_block.yaml create mode 100644 apis/builder/execution_payload_bid.yaml create mode 100644 specs/gloas/builder.md create mode 100644 specs/gloas/validator.md diff --git a/apis/builder/beacon_block.yaml b/apis/builder/beacon_block.yaml new file mode 100644 index 0000000..1a86500 --- /dev/null +++ b/apis/builder/beacon_block.yaml @@ -0,0 +1,50 @@ +post: + operationId: "submitSignedBeaconBlock" + summary: Submit a signed beacon block with the execution payload bid. + description: | + Submits a `SignedBeaconBlock` to the builder, binding the proposer to the block. + + A success response (200) indicates that the signed beacon block was + valid. If the signed beacon block was invalid, then the builder + must return an error response (400) with a description of the validation + failure. + tags: + - Builder + parameters: + - in: header + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/ConsensusVersion" + required: false + name: Eth-Consensus-Version + description: "The active consensus version to which the block being submitted belongs. Required if request is SSZ encoded." + requestBody: + description: A `SignedBeaconBlock`. + required: true + content: + application/json: + schema: + type: object + required: [data] + properties: + data: + $ref: "../../beacon-apis/types/gloas/block.yaml#/Gloas/SignedBeaconBlock" + description: "The signed beacon block." + application/octet-stream: + schema: + description: "SSZ serialized `SignedBeaconBlock` bytes. Use content type header to indicate that SSZ data is contained in the request body." + responses: + "202": + description: Success response. + "400": + description: Error response. + content: + application/json: + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/ErrorMessage" + example: + code: 400 + message: "Invalid signed beacon block: missing signature" + "415": + $ref: "../../builder-oapi.yaml#/components/responses/UnsupportedMediaType" + "500": + $ref: "../../builder-oapi.yaml#/components/responses/InternalError" diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml new file mode 100644 index 0000000..cd24328 --- /dev/null +++ b/apis/builder/execution_payload_bid.yaml @@ -0,0 +1,89 @@ +get: + operationId: "getExecutionPayloadBid" + summary: Get an execution payload bid. + description: | + Requests a builder node to produce a valid execution payload bid, which + can be integrated into a blinded beacon block and signed. + + If the builder is unable to produce a valid execution payload bid, then + the builder MUST return a 204 response. If the request is invalid, then the + builder MUST return an error response (400) with a description of the + validation failure. + + This API is applicable from Glamsterdam fork onwards. + tags: + - Builder + parameters: + - name: Date-Milliseconds + in: header + required: false + description: | + Optional header containing a Unix timestamp in milliseconds representing + the point-in-time the request was sent. This header can be used to measure + latency. + schema: + type: integer + format: int64 + example: 1710338135000 + - name: X-Timeout-Ms + in: header + required: false + description: | + Optional header containing the proposer's timeout for the request in milliseconds. + Relays should use this header to adjust the amount of time by which they delay getBid + requests to maximise block rewards. Otherwise, getBid requests will timeout and the proposer + will not receive the header in time. + schema: + type: integer + format: int64 + example: 10000 + - name: X-Fee-Recipient + in: header + required: true + description: | + Required header containing the fee recipient address to which the proposer wants to receive + the payment for the bid. + schema: + type: string + format: address + example: "0x0000000000000000000000000000000000000000" + responses: + "200": + description: Success response. + headers: + Eth-Consensus-Version: + $ref: "../../builder-oapi.yaml#/components/headers/Eth-Consensus-Version" + required: false + content: + application/json: + schema: + title: GetExecutionPayloadBidResponse + type: object + required: [version, data] + properties: + version: + type: string + enum: [ gloas ] + example: "gloas" + data: + $ref: "../../beacon-apis/types/gloas/execution_payload_bid.yaml#/Gloas/ExecutionPayloadBid" + application/octet-stream: + schema: + description: "SSZ serialized `ExecutionPayloadBid` bytes. Use Accept header to choose this response type" + "204": + description: No header is available. + "400": + description: Error response. + content: + application/json: + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/ErrorMessage" + examples: + InvalidRequest: + value: + code: 400 + message: "Unknown hash: missing parent hash" + "406": + $ref: "../../builder-oapi.yaml#/components/responses/NotAcceptable" + "500": + $ref: "../../builder-oapi.yaml#/components/responses/InternalError" diff --git a/builder-oapi.yaml b/builder-oapi.yaml index a9c05f0..0962a15 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -53,6 +53,10 @@ paths: $ref: "./apis/builder/validators.yaml" /eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}: $ref: "./apis/builder/header.yaml" + /eth/v1/builder/execution_payload_bid: + $ref: "./apis/builder/execution_payload_bid.yaml" + /eth/v1/builder/beacon_block: + $ref: "./apis/builder/beacon_block.yaml" /eth/v1/builder/blinded_blocks: $ref: "./apis/builder/blinded_blocks.yaml" /eth/v2/builder/blinded_blocks: @@ -72,7 +76,7 @@ components: $ref: "./beacon-apis/types/http.yaml#/ErrorMessage" ConsensusVersion: $ref: "./beacon-apis/beacon-node-oapi.yaml#/components/schemas/ConsensusVersion" - enum: [bellatrix, capella, deneb, electra, fulu] + enum: [bellatrix, capella, deneb, electra, fulu, gloas] example: "bellatrix" Bellatrix.ExecutionPayload: $ref: "./beacon-apis/types/bellatrix/execution_payload.yaml#/Bellatrix/ExecutionPayload" diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md new file mode 100644 index 0000000..793f15c --- /dev/null +++ b/specs/gloas/builder.md @@ -0,0 +1,34 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Gloas - Builder Specification](#gloas---builder-specification) + - [Introduction](#introduction) + - [Constructing a `SignedExecutionPayloadBid`](#constructing-a-signedexecutionpayloadbid) + - [Constructing a `SignedExecutionPayloadEnvelope`](#constructing-a-signedexecutionpayloadenvelope) + + + +# Gloas - Builder Specification + +## Introduction + +This document documents the builder behaviour with the Builder-API. + +### `ValidatorRegistrationV1` are deprecated + +With Gloas, `ValidatorRegistrations` are deprecated. Pre-Gloas, Validators used `ValidatorRegistrationV1` to signal their +preferred `fee_receipient` and `gas_limit` to the builder. + +Now, A proposer can indicate the `fee_receipient` to which they want the builder to pay as a header while requesting the +`SignedExecutionPayloadBid`. + +### Constructing a `SignedExecutionPayloadBid` + +The specification for a block builder to construct a `SignedExecutionPayloadBid` is documented in the +gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. + +### Constructing a `SignedExecutionPayloadEnvelope` + +The specification for a block builder to construct a `SignedExecutionPayloadEnvelope` is documented in the +gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md new file mode 100644 index 0000000..a8d4810 --- /dev/null +++ b/specs/gloas/validator.md @@ -0,0 +1,38 @@ + + +**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +- [Gloas - Honest Validator](#gloas---honest-validator) + - [Introduction](#introduction) + - [Block proposal](#block-proposal) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayloadBid](#executionpayloadbid) + + + +# Gloas - Honest Validator + + +## Introduction + +This document explains how a beacon-chain validator can participate in the external block building market post ePBS. + +Validators request an `ExecutionPayloadBid` from the external builder network to put it in their `SignedBeaconBlock`. +The external builder network broadcasts the `SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC commitee. + +### Block proposal + +#### Constructing the `BeaconBlockBody` + +##### ExecutionPayloadBid + +To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take +the following actions: + +1. Call upstream builder software to get an `ExecutionPayloadBid`. +2. Assemble a `SignedBeaconBlock` according to the process outlined in the [Gloas specs][https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal] but with + the `ExecutionPayloadBid` from the prior step. +3. The proposer returns the `SignedBeaconBlock` back to the upstream block + building software. +5. The upstream block building software constructs the `SignedExecutionPayloadEnvelope` from the + `SignedBlindedExecutionPayloadEnvelope` and broadcasts it to the PTC commitee. \ No newline at end of file From f087efb4adf7ab0b440cbbace4173b4aad7f910b Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Fri, 12 Dec 2025 15:25:26 +0530 Subject: [PATCH 02/31] updates --- apis/builder/execution_payload_bid.yaml | 2 +- specs/gloas/builder.md | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index cd24328..c716ed6 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -30,7 +30,7 @@ get: required: false description: | Optional header containing the proposer's timeout for the request in milliseconds. - Relays should use this header to adjust the amount of time by which they delay getBid + Builders should use this header to adjust the amount of time by which they delay getBid requests to maximise block rewards. Otherwise, getBid requests will timeout and the proposer will not receive the header in time. schema: diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 793f15c..7c6f819 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -4,8 +4,10 @@ - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) + - [`ValidatorRegistrationV1` are deprecated](#validatorregistrationv1-are-deprecated) - [Constructing a `SignedExecutionPayloadBid`](#constructing-a-signedexecutionpayloadbid) - [Constructing a `SignedExecutionPayloadEnvelope`](#constructing-a-signedexecutionpayloadenvelope) + - [Sealing the Payload with `fee_recipient`](#sealing-the-payload-with-fee_recipient) @@ -18,9 +20,9 @@ This document documents the builder behaviour with the Builder-API. ### `ValidatorRegistrationV1` are deprecated With Gloas, `ValidatorRegistrations` are deprecated. Pre-Gloas, Validators used `ValidatorRegistrationV1` to signal their -preferred `fee_receipient` and `gas_limit` to the builder. +preferred `fee_recipient` and `gas_limit` to the builder. -Now, A proposer can indicate the `fee_receipient` to which they want the builder to pay as a header while requesting the +Now, A proposer can indicate the `fee_recipient` to which they want the builder to pay as a header while requesting the `SignedExecutionPayloadBid`. ### Constructing a `SignedExecutionPayloadBid` @@ -32,3 +34,9 @@ gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/ The specification for a block builder to construct a `SignedExecutionPayloadEnvelope` is documented in the gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. + +### Sealing the Payload with `fee_recipient` + +The builder receives the `fee_recipient` as a header to the call to get the `SignedExecutionPayloadBid`. The builder +is required to seal the block to be sent with the payment transaction to the `fee_recipient` with the amount specified in the +`execution_payment` field in the `ExecutionPayloadBid`. \ No newline at end of file From 85f6f8f6491c9d708c2a8bc424d2bc82e17db239 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Fri, 12 Dec 2025 15:45:12 +0530 Subject: [PATCH 03/31] pass in params while querying execution payload bid --- apis/builder/execution_payload_bid.yaml | 24 ++++++++++++++++++++++++ builder-oapi.yaml | 2 +- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index c716ed6..8f28ee4 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -14,6 +14,30 @@ get: tags: - Builder parameters: + - name: slot + in: path + required: true + description: The slot for which the block should be proposed. + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/Uint64" + - name: parent_hash + in: path + required: true + description: Hash of execution layer block the proposer will build on. + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/Root" + - name: parent_root + in: path + required: true + description: Root of the execution layer block the proposer will build on. + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/Root" + - name: proposer_index + in: path + required: true + description: Index of the proposer. + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/Uint64" - name: Date-Milliseconds in: header required: false diff --git a/builder-oapi.yaml b/builder-oapi.yaml index 0962a15..5938750 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -53,7 +53,7 @@ paths: $ref: "./apis/builder/validators.yaml" /eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}: $ref: "./apis/builder/header.yaml" - /eth/v1/builder/execution_payload_bid: + /eth/v1/builder/execution_payload_bid/{slot}/{parent_hash}/{parent_root}/{proposer_index}: $ref: "./apis/builder/execution_payload_bid.yaml" /eth/v1/builder/beacon_block: $ref: "./apis/builder/beacon_block.yaml" From 5ed1841f4f507dc99f44470cc474471b96ee28a2 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 16 Dec 2025 15:27:35 +0530 Subject: [PATCH 04/31] introduce validator registrations v2 --- apis/builder/validators_v2.yaml | 45 ++++++++++++++ builder-oapi.yaml | 2 + specs/gloas/builder.md | 102 +++++++++++++++++++++++++++----- specs/gloas/validator.md | 36 ++++++++++- 4 files changed, 170 insertions(+), 15 deletions(-) create mode 100644 apis/builder/validators_v2.yaml diff --git a/apis/builder/validators_v2.yaml b/apis/builder/validators_v2.yaml new file mode 100644 index 0000000..eeff67b --- /dev/null +++ b/apis/builder/validators_v2.yaml @@ -0,0 +1,45 @@ +post: + operationId: "registerValidatorV2" + summary: Register or update a validator's block building preferences for Gloas. + description: | + Registers a validator's preferred fee recipient, gas limit and preferences. + + A success response (200) indicates that the registration was valid. If the + registration passes validation, then the builder MUST integrate the + registration into its state, such that future blocks built for the + validator conform to the preferences expressed in the registration. If the + registration is invalid, then the builder MUST return an error response + (400) with a description of the validation failure. + tags: + - Builder + requestBody: + description: | + A signed declaration of a validator's block building preferences. + required: true + content: + application/json: + schema: + type: array + items: + $ref: "../../builder-oapi.yaml#/components/schemas/SignedValidatorRegistrationV2" + example: + $ref: "../../builder-oapi.yaml#/components/examples/SignedValidatorRegistrations/value" + application/octet-stream: + schema: + description: "SSZ serialized `List[SignedValidatorRegistrationV2, VALIDATOR_REGISTRY_LIMIT]` bytes. Use content type header to indicate that SSZ data is contained in the request body." + responses: + "200": + description: Success response. + "400": + description: Error response. + content: + application/json: + schema: + $ref: "../../builder-oapi.yaml#/components/schemas/ErrorMessage" + example: + code: 400 + message: "unknown validator" + "415": + $ref: "../../builder-oapi.yaml#/components/responses/UnsupportedMediaType" + "500": + $ref: "../../builder-oapi.yaml#/components/responses/InternalError" diff --git a/builder-oapi.yaml b/builder-oapi.yaml index 5938750..7a65c7c 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -98,6 +98,8 @@ components: $ref: "./types/deneb/execution_payload_and_blobs_bundle.yaml#/Deneb/ExecutionPayloadAndBlobsBundle" SignedValidatorRegistration: $ref: "./beacon-apis/types/registration.yaml#/SignedValidatorRegistration" + SignedValidatorRegistrationV2: + $ref: "./beacon-apis/types/registration.yaml#/SignedValidatorRegistrationV2" Electra.SignedBlindedBeaconBlock: $ref: "./beacon-apis/types/electra/block.yaml#/Electra/SignedBlindedBeaconBlock" Electra.SignedBuilderBid: diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 7c6f819..163ba32 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -17,26 +17,100 @@ This document documents the builder behaviour with the Builder-API. -### `ValidatorRegistrationV1` are deprecated +## Custom types -With Gloas, `ValidatorRegistrations` are deprecated. Pre-Gloas, Validators used `ValidatorRegistrationV1` to signal their -preferred `fee_recipient` and `gas_limit` to the builder. +| Name | SSZ equivalent | Description | +| -------------- | -------------- | ---------------------- | +| `BuilderIndex` | `uint64` | Builder registry index | -Now, A proposer can indicate the `fee_recipient` to which they want the builder to pay as a header while requesting the -`SignedExecutionPayloadBid`. +## Containers -### Constructing a `SignedExecutionPayloadBid` +### New Containers -The specification for a block builder to construct a `SignedExecutionPayloadBid` is documented in the -gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. +#### `ValidatorRegistrationV2` -### Constructing a `SignedExecutionPayloadEnvelope` +```python +class ValidatorRegistrationV2(Container): + builder_pubkey: BLSPubkey ## is this needed? + fee_recipient: ExecutionAddress + gas_limit: uint64 + timestamp: uint64 + pubkey: BLSPubkey + can_accept_trusted_payment: bool + proposal_epoch: Epoch +``` -The specification for a block builder to construct a `SignedExecutionPayloadEnvelope` is documented in the +#### `SignedValidatorRegistrationV2` + +```python +class SignedValidatorRegistrationV2(Container): + message: ValidatorRegistrationV2 + signature: BLSSignature +``` + +### `verify_registration_signature` + +```python +def verify_registration_signature(state: BeaconState, signed_registration: SignedValidatorRegistrationV2) -> bool: + pubkey = signed_registration.message.pubkey + domain = compute_domain(DOMAIN_APPLICATION_BUILDER) + signing_root = compute_signing_root(signed_registration.message, domain) + return bls.Verify(pubkey, signing_root, signed_registration.signature) +``` + +## Validator Registration V2 + +The second version of ValidatorRegistrations adds the following new fields: +* `builder_pubkey`: The pubkey of the builder to which this registration is being sent. +* `can_accept_trusted_payment`: This is a boolean which indicates that the validator is willing accept a trusted + execution layer payment from the builder to which it is sending the registrations. +* `proposal_epoch`: The epoch at which this validator is proposing. + +### `process_registration` + +```python +def process_registration(state: BeaconState, + registration: SignedValidatorRegistrationV2, + registrations: Dict[BLSPubkey, ValidatorRegistrationV2], + current_timestamp: uint64): + signature = registration.signature + registration = registration.message + pubkey = registration.pubkey + builder_pubkey = registration.builder_pubkey + + # Verify BLS public key corresponds to a registered validator + validator_pubkeys = [v.pubkey for v in state.validators] + assert pubkey in validator_pubkeys + + index = ValidatorIndex(validator_pubkeys.index(pubkey)) + validator = state.validators[index] + + # [New in Gloas] + builder_pubkeys = [b.pubkey for v in state.builders] + assert builder_pubkey in builder_pubkeys + + # Verify validator registration elibility + assert is_eligible_for_registration(state, validator) + + # Verify timestamp is not too far in the future + assert registration.timestamp <= current_timestamp + MAX_REGISTRATION_LOOKAHEAD + + # Verify timestamp is not less than the timestamp of the previous registration (if it exists) + if registration.pubkey in registrations: + prev_registration = registrations[registration.pubkey] + assert registration.timestamp >= prev_registration.timestamp + + # Verify registration signature + assert verify_registration_signature(state, registration) +``` + + +## Constructing a `SignedExecutionPayloadBid` + +The specification for a block builder to construct a `SignedExecutionPayloadBid` is documented in the gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. -### Sealing the Payload with `fee_recipient` +## Constructing a `SignedExecutionPayloadEnvelope` -The builder receives the `fee_recipient` as a header to the call to get the `SignedExecutionPayloadBid`. The builder -is required to seal the block to be sent with the payment transaction to the `fee_recipient` with the amount specified in the -`execution_payment` field in the `ExecutionPayloadBid`. \ No newline at end of file +The specification for a block builder to construct a `SignedExecutionPayloadEnvelope` is documented in the +gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. \ No newline at end of file diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index a8d4810..24a3bc0 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -20,7 +20,41 @@ This document explains how a beacon-chain validator can participate in the exter Validators request an `ExecutionPayloadBid` from the external builder network to put it in their `SignedBeaconBlock`. The external builder network broadcasts the `SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC commitee. -### Block proposal +## Validator Registrations + +### Constructing the `ValidatorRegistrationV2` + +To do this, the validator client assembles a [`ValidatorRegistrationV2`][validator-registration-v2] with the following +information: + +* `fee_recipient`: an execution layer address where fees for the validator should go. +* `builder_pubkey`: the pubkey of the builder to which this registration is being sent to. +* `gas_limit`: the value a validator prefers for the execution block gas limit. +* `timestamp`: a recent timestamp later than any previously constructed `ValidatorRegistrationV1`. + Builders use this timestamp as a form of anti-DoS and to sequence registrations. +* `pubkey`: the validator's public key. Used to identify the beacon chain validator and verify the wrapping signature. +* `can_accept_trusted_payment`: whether the proposer is willing to accept a trusted payment from the builder with pubkey + `builder_pubkey`. +* `proposal_epoch`: This is set to `get_current_epoch(state) + 1`. + + +### Validator Registration dissemination + +This specification suggests validators re-submit registrations only if they will be proposing in the upcoming epoch(E+1). +This is to avoid sending a lot of `ValidatorRegistrations` every epoch. This can potentially help reduce the load +Validators are expected to perform this check at every epoch boundary. Validators can send their registrations even though +they won't be proposing in the upcoming epoch. + +```python +def is_next_epoch_proposer(state: BeaconState, validator_index: ValidatorIndex) -> bool: + """ + Check if ``validator_index`` is scheduled to propose in the next epoch. + """ + next_epoch_proposers = state.proposer_lookahead[SLOTS_PER_EPOCH:] + return validator_index in next_epoch_proposers +``` + +## Block proposal #### Constructing the `BeaconBlockBody` From 503eee6741abdef1dd0ac19c1f7d3f8315c6f173 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 17 Dec 2025 19:12:07 +0530 Subject: [PATCH 05/31] run doctoc --- specs/gloas/builder.md | 14 ++++++++++---- specs/gloas/validator.md | 5 ++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 163ba32..018aa6f 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -4,10 +4,16 @@ - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) - - [`ValidatorRegistrationV1` are deprecated](#validatorregistrationv1-are-deprecated) - - [Constructing a `SignedExecutionPayloadBid`](#constructing-a-signedexecutionpayloadbid) - - [Constructing a `SignedExecutionPayloadEnvelope`](#constructing-a-signedexecutionpayloadenvelope) - - [Sealing the Payload with `fee_recipient`](#sealing-the-payload-with-fee_recipient) + - [Custom types](#custom-types) + - [Containers](#containers) + - [New Containers](#new-containers) + - [`ValidatorRegistrationV2`](#validatorregistrationv2) + - [`SignedValidatorRegistrationV2`](#signedvalidatorregistrationv2) + - [`verify_registration_signature`](#verify_registration_signature) + - [Validator Registration V2](#validator-registration-v2) + - [`process_registration`](#process_registration) + - [Constructing a `SignedExecutionPayloadBid`](#constructing-a-signedexecutionpayloadbid) + - [Constructing a `SignedExecutionPayloadEnvelope`](#constructing-a-signedexecutionpayloadenvelope) diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 24a3bc0..e9872df 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -4,7 +4,10 @@ - [Gloas - Honest Validator](#gloas---honest-validator) - [Introduction](#introduction) - - [Block proposal](#block-proposal) + - [Validator Registrations](#validator-registrations) + - [Constructing the `ValidatorRegistrationV2`](#constructing-the-validatorregistrationv2) + - [Validator Registration dissemination](#validator-registration-dissemination) + - [Block proposal](#block-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - [ExecutionPayloadBid](#executionpayloadbid) From 7dde2ec7b8a148cfaf53584bb15db67aacf7afc1 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 17 Dec 2025 15:05:25 +0530 Subject: [PATCH 06/31] update validator registration v2 --- specs/gloas/builder.md | 81 +++++++++++++++++++++++++++--------------- 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 018aa6f..75ee6da 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -29,6 +29,30 @@ This document documents the builder behaviour with the Builder-API. | -------------- | -------------- | ---------------------- | | `BuilderIndex` | `uint64` | Builder registry index | +## Predicates + +### `is_active_builder` + +```python +def is_active_builder(builder: Builder) -> bool: + """ + Check if ``builder`` is active. + """ + return builder.exit_epoch == FAR_FUTURE_EPOCH +``` + +## Helper Functions + +#### `compute_epoch_at_slot` + +```python +def compute_epoch_at_slot(slot: Slot) -> Epoch: + """ + Return the epoch number at ``slot``. + """ + return Epoch(slot // SLOTS_PER_EPOCH) +``` + ## Containers ### New Containers @@ -37,13 +61,12 @@ This document documents the builder behaviour with the Builder-API. ```python class ValidatorRegistrationV2(Container): - builder_pubkey: BLSPubkey ## is this needed? + builder_index: BuilderIndex + validator_index: ValidatorIndex fee_recipient: ExecutionAddress + proposal_slot: Slot gas_limit: uint64 - timestamp: uint64 - pubkey: BLSPubkey - can_accept_trusted_payment: bool - proposal_epoch: Epoch + execution_payment_accepted: boolean ``` #### `SignedValidatorRegistrationV2` @@ -58,7 +81,8 @@ class SignedValidatorRegistrationV2(Container): ```python def verify_registration_signature(state: BeaconState, signed_registration: SignedValidatorRegistrationV2) -> bool: - pubkey = signed_registration.message.pubkey + validator = state.validators[signed_registration.message.validator_index] + pubkey = validator.pubkey domain = compute_domain(DOMAIN_APPLICATION_BUILDER) signing_root = compute_signing_root(signed_registration.message, domain) return bls.Verify(pubkey, signing_root, signed_registration.signature) @@ -67,50 +91,51 @@ def verify_registration_signature(state: BeaconState, signed_registration: Signe ## Validator Registration V2 The second version of ValidatorRegistrations adds the following new fields: -* `builder_pubkey`: The pubkey of the builder to which this registration is being sent. -* `can_accept_trusted_payment`: This is a boolean which indicates that the validator is willing accept a trusted +* `builder_index`: The index of the builder to which this registration is being sent. +* `validator_index`: The index of the validator selected to propose a block at slot `proposal_slot` +* `execution_payment_accepted`: This is a boolean which indicates that the validator is willing accept a trusted execution layer payment from the builder to which it is sending the registrations. -* `proposal_epoch`: The epoch at which this validator is proposing. +* `proposal_slot`: The slot at which this validator is proposing. -### `process_registration` +The following fields are removed: +* `pubkey`: This is the pubkey of the validator which has now been replaced with `validator_index`. +* `timestamp`: A new validator registration will be sent by the validator to the builder in + the epoch prior to one where + +### `process_registration_v2` ```python -def process_registration(state: BeaconState, +def process_registration_v2(state: BeaconState, registration: SignedValidatorRegistrationV2, registrations: Dict[BLSPubkey, ValidatorRegistrationV2], current_timestamp: uint64): signature = registration.signature registration = registration.message - pubkey = registration.pubkey - builder_pubkey = registration.builder_pubkey + validator_index = registration.validator_index + builder_index = registration.builder_index + proposal_slot = registration.proposal_slot - # Verify BLS public key corresponds to a registered validator - validator_pubkeys = [v.pubkey for v in state.validators] - assert pubkey in validator_pubkeys + assert validator_index < len(state.validators) + assert builder_index < len(state.builders) - index = ValidatorIndex(validator_pubkeys.index(pubkey)) - validator = state.validators[index] + validator = state.validators[validator_index] + builder = state.builders[builder_index] - # [New in Gloas] - builder_pubkeys = [b.pubkey for v in state.builders] - assert builder_pubkey in builder_pubkeys + assert is_active_validator(validator, compute_epoch_at_slot(proposal_slot)) + assert is_active_builder(builder) # Verify validator registration elibility assert is_eligible_for_registration(state, validator) - # Verify timestamp is not too far in the future - assert registration.timestamp <= current_timestamp + MAX_REGISTRATION_LOOKAHEAD - - # Verify timestamp is not less than the timestamp of the previous registration (if it exists) + # Verify that the old registration's slot is earlier than the new registration's slot if registration.pubkey in registrations: - prev_registration = registrations[registration.pubkey] - assert registration.timestamp >= prev_registration.timestamp + prev_registration = registrations[validator_index] + assert registration.proposal_slot >= prev_registration.proposal_slot # Verify registration signature assert verify_registration_signature(state, registration) ``` - ## Constructing a `SignedExecutionPayloadBid` The specification for a block builder to construct a `SignedExecutionPayloadBid` is documented in the From 8011cd8e2bb8114d2e7cab8399bff2d1de78dab1 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 17 Dec 2025 19:03:46 +0530 Subject: [PATCH 07/31] add more specs --- builder-oapi.yaml | 2 ++ specs/gloas/validator.md | 64 +++++++++++++++++++++++++++++----------- 2 files changed, 49 insertions(+), 17 deletions(-) diff --git a/builder-oapi.yaml b/builder-oapi.yaml index 7a65c7c..ca26f88 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -51,6 +51,8 @@ tags: paths: /eth/v1/builder/validators: $ref: "./apis/builder/validators.yaml" + /eth/v2/builder/validators: + $ref: "./apis/builder/validators_2.yaml" /eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}: $ref: "./apis/builder/header.yaml" /eth/v1/builder/execution_payload_bid/{slot}/{parent_hash}/{parent_root}/{proposer_index}: diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index e9872df..d0eda58 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -23,6 +23,30 @@ This document explains how a beacon-chain validator can participate in the exter Validators request an `ExecutionPayloadBid` from the external builder network to put it in their `SignedBeaconBlock`. The external builder network broadcasts the `SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC commitee. +## Helper + +### `get_proposer_slots_in_upcoming_epoch` + +```python +def get_proposer_slots_in_upcoming_epoch( + state: BeaconState, + validator_index: ValidatorIndex +) -> List[Slot]: + """ + Return all slots where validator_index is the proposer within the lookahead window in the next epoch. + """ + proposer_slots = [] + current_epoch_start_slot = compute_start_slot_at_epoch(get_current_epoch(state)) + next_epoch_proposer_lookahead = state.proposer_lookahead[SLOTS_PER_EPOCH:] + + for i, proposer_index in enumerate(next_epoch_proposer_lookahead): + if proposer_index == validator_index: + slot = current_epoch_start_slot + SLOTS_PER_EPOCH + i + proposer_slots.append(slot) + + return proposer_slots +``` + ## Validator Registrations ### Constructing the `ValidatorRegistrationV2` @@ -31,32 +55,38 @@ To do this, the validator client assembles a [`ValidatorRegistrationV2`][validat information: * `fee_recipient`: an execution layer address where fees for the validator should go. -* `builder_pubkey`: the pubkey of the builder to which this registration is being sent to. +* `builder_index`: the index of the builder to which this registration is being sent to. * `gas_limit`: the value a validator prefers for the execution block gas limit. -* `timestamp`: a recent timestamp later than any previously constructed `ValidatorRegistrationV1`. - Builders use this timestamp as a form of anti-DoS and to sequence registrations. -* `pubkey`: the validator's public key. Used to identify the beacon chain validator and verify the wrapping signature. -* `can_accept_trusted_payment`: whether the proposer is willing to accept a trusted payment from the builder with pubkey - `builder_pubkey`. -* `proposal_epoch`: This is set to `get_current_epoch(state) + 1`. +* `validator_index`: the validator's index. Used to identify the beacon chain validator and verify the wrapping signature. +* `execution_payment_accepted`: whether the proposer is willing to accept a trusted payment from the builder with index + `builder_index`. +* `proposal_slot`: This is set to the slot in which the validator will be proposing. This can be looked up in the `proposal_lookahead`. ### Validator Registration dissemination This specification suggests validators re-submit registrations only if they will be proposing in the upcoming epoch(E+1). -This is to avoid sending a lot of `ValidatorRegistrations` every epoch. This can potentially help reduce the load -Validators are expected to perform this check at every epoch boundary. Validators can send their registrations even though -they won't be proposing in the upcoming epoch. +This is such that we don't send too many validator registrations all at once to builders. +Validators run `create_validator_registrations` at every epoch boundary to create validator registrations for all the slots +they will be proposing in the upcoming epoch. ```python -def is_next_epoch_proposer(state: BeaconState, validator_index: ValidatorIndex) -> bool: - """ - Check if ``validator_index`` is scheduled to propose in the next epoch. - """ - next_epoch_proposers = state.proposer_lookahead[SLOTS_PER_EPOCH:] - return validator_index in next_epoch_proposers +def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_index: BuilderIndex, execution_payment_accepted: bool) -> List[ValidatorRegistrationV2]: + slots = get_proposer_slots_in_lookahead(state, validator_index) + registrations: List[ValidatorRegistrationsV2] = [] + + for slot in slots: + registrations.append(ValidatorRegistrationV2( + fee_recipient=fee_recipient, + builder_index=builder_index, + gas_limit=gas_limit, + validator_index=validator_index + execution_payment_accepted=execution_payment_accepted, + proposal_slot=slot + )) + + return registrations ``` - ## Block proposal #### Constructing the `BeaconBlockBody` From 610bfaea06ca2c1691aa084087fcc85d70e84995 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 17 Dec 2025 19:18:49 +0530 Subject: [PATCH 08/31] run lint --- specs/gloas/builder.md | 40 ++++++++++++++--------- specs/gloas/validator.md | 68 ++++++++++++++++++++++++---------------- 2 files changed, 66 insertions(+), 42 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 75ee6da..e91f40f 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -1,6 +1,9 @@ + -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +**Table of Contents** *generated with +[DocToc](https://github.com/thlorenz/doctoc)* - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) @@ -25,9 +28,8 @@ This document documents the builder behaviour with the Builder-API. ## Custom types -| Name | SSZ equivalent | Description | -| -------------- | -------------- | ---------------------- | -| `BuilderIndex` | `uint64` | Builder registry index | +| Name | SSZ equivalent | Description | | -------------- | -------------- | +---------------------- | | `BuilderIndex` | `uint64` | Builder registry index | ## Predicates @@ -91,16 +93,22 @@ def verify_registration_signature(state: BeaconState, signed_registration: Signe ## Validator Registration V2 The second version of ValidatorRegistrations adds the following new fields: -* `builder_index`: The index of the builder to which this registration is being sent. -* `validator_index`: The index of the validator selected to propose a block at slot `proposal_slot` -* `execution_payment_accepted`: This is a boolean which indicates that the validator is willing accept a trusted - execution layer payment from the builder to which it is sending the registrations. -* `proposal_slot`: The slot at which this validator is proposing. + +- `builder_index`: The index of the builder to which this registration is being + sent. +- `validator_index`: The index of the validator selected to propose a block at + slot `proposal_slot` +- `execution_payment_accepted`: This is a boolean which indicates that the + validator is willing accept a trusted execution layer payment from the builder + to which it is sending the registrations. +- `proposal_slot`: The slot at which this validator is proposing. The following fields are removed: -* `pubkey`: This is the pubkey of the validator which has now been replaced with `validator_index`. -* `timestamp`: A new validator registration will be sent by the validator to the builder in - the epoch prior to one where + +- `pubkey`: This is the pubkey of the validator which has now been replaced with + `validator_index`. +- `timestamp`: A new validator registration will be sent by the validator to the + builder in the epoch prior to one where ### `process_registration_v2` @@ -138,10 +146,12 @@ def process_registration_v2(state: BeaconState, ## Constructing a `SignedExecutionPayloadBid` -The specification for a block builder to construct a `SignedExecutionPayloadBid` is documented in the +The specification for a block builder to construct a `SignedExecutionPayloadBid` +is documented in the gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. ## Constructing a `SignedExecutionPayloadEnvelope` -The specification for a block builder to construct a `SignedExecutionPayloadEnvelope` is documented in the -gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. \ No newline at end of file +The specification for a block builder to construct a +`SignedExecutionPayloadEnvelope` is documented in the +gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index d0eda58..1376e3c 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -1,6 +1,9 @@ + -**Table of Contents** *generated with [DocToc](https://github.com/thlorenz/doctoc)* + +**Table of Contents** *generated with +[DocToc](https://github.com/thlorenz/doctoc)* - [Gloas - Honest Validator](#gloas---honest-validator) - [Introduction](#introduction) @@ -8,20 +11,21 @@ - [Constructing the `ValidatorRegistrationV2`](#constructing-the-validatorregistrationv2) - [Validator Registration dissemination](#validator-registration-dissemination) - [Block proposal](#block-proposal) - - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [ExecutionPayloadBid](#executionpayloadbid) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayloadBid](#executionpayloadbid) # Gloas - Honest Validator - ## Introduction -This document explains how a beacon-chain validator can participate in the external block building market post ePBS. +This document explains how a beacon-chain validator can participate in the +external block building market post ePBS. -Validators request an `ExecutionPayloadBid` from the external builder network to put it in their `SignedBeaconBlock`. -The external builder network broadcasts the `SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC commitee. +Validators request an `ExecutionPayloadBid` from the external builder network to +put it in their `SignedBeaconBlock`. The external builder network broadcasts the +`SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC committee. ## Helper @@ -47,28 +51,33 @@ def get_proposer_slots_in_upcoming_epoch( return proposer_slots ``` -## Validator Registrations +## Validator Registrations ### Constructing the `ValidatorRegistrationV2` -To do this, the validator client assembles a [`ValidatorRegistrationV2`][validator-registration-v2] with the following +To do this, the validator client assembles a +\[`ValidatorRegistrationV2`\][validator-registration-v2] with the following information: -* `fee_recipient`: an execution layer address where fees for the validator should go. -* `builder_index`: the index of the builder to which this registration is being sent to. -* `gas_limit`: the value a validator prefers for the execution block gas limit. -* `validator_index`: the validator's index. Used to identify the beacon chain validator and verify the wrapping signature. -* `execution_payment_accepted`: whether the proposer is willing to accept a trusted payment from the builder with index - `builder_index`. -* `proposal_slot`: This is set to the slot in which the validator will be proposing. This can be looked up in the `proposal_lookahead`. - +- `fee_recipient`: an execution layer address where fees for the validator + should go. +- `builder_index`: the index of the builder to which this registration is being + sent to. +- `gas_limit`: the value a validator prefers for the execution block gas limit. +- `validator_index`: the validator's index. Used to identify the beacon chain + validator and verify the wrapping signature. +- `execution_payment_accepted`: whether the proposer is willing to accept a + trusted payment from the builder with index `builder_index`. +- `proposal_slot`: This is set to the slot in which the validator will be + proposing. This can be looked up in the `proposal_lookahead`. ### Validator Registration dissemination -This specification suggests validators re-submit registrations only if they will be proposing in the upcoming epoch(E+1). -This is such that we don't send too many validator registrations all at once to builders. -Validators run `create_validator_registrations` at every epoch boundary to create validator registrations for all the slots -they will be proposing in the upcoming epoch. +This specification suggests validators re-submit registrations only if they will +be proposing in the upcoming epoch(E+1). This is such that we don't send too +many validator registrations all at once to builders. Validators run +`create_validator_registrations` at every epoch boundary to create validator +registrations for all the slots they will be proposing in the upcoming epoch. ```python def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_index: BuilderIndex, execution_payment_accepted: bool) -> List[ValidatorRegistrationV2]: @@ -87,19 +96,24 @@ def create_validator_registrations(state: BeaconState, validator_index: Validato return registrations ``` + ## Block proposal #### Constructing the `BeaconBlockBody` ##### ExecutionPayloadBid -To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take -the following actions: +To obtain an execution payload, a block proposer building a block on top of a +beacon `state` in a given `slot` must take the following actions: 1. Call upstream builder software to get an `ExecutionPayloadBid`. -2. Assemble a `SignedBeaconBlock` according to the process outlined in the [Gloas specs][https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal] but with - the `ExecutionPayloadBid` from the prior step. +2. Assemble a `SignedBeaconBlock` according to the process outlined in the + \[Gloas + specs\][https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal] + but with the `ExecutionPayloadBid` from the prior step. 3. The proposer returns the `SignedBeaconBlock` back to the upstream block building software. -5. The upstream block building software constructs the `SignedExecutionPayloadEnvelope` from the - `SignedBlindedExecutionPayloadEnvelope` and broadcasts it to the PTC commitee. \ No newline at end of file +4. The upstream block building software constructs the + `SignedExecutionPayloadEnvelope` from the + `SignedBlindedExecutionPayloadEnvelope` and broadcasts it to the PTC + committee. From beef159aa184c6483028ec27de4c36fa6ed3a5b0 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 17 Dec 2025 22:24:09 +0530 Subject: [PATCH 09/31] updates --- specs/gloas/builder.md | 14 +++++++++----- specs/gloas/validator.md | 41 ++++++++++++++++++++++++++++++++-------- 2 files changed, 42 insertions(+), 13 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index e91f40f..57dea97 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -1,20 +1,21 @@ - - -**Table of Contents** *generated with -[DocToc](https://github.com/thlorenz/doctoc)* + - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) - [Custom types](#custom-types) + - [Predicates](#predicates) + - [`is_active_builder`](#is_active_builder) + - [Helper Functions](#helper-functions) + - [`compute_epoch_at_slot`](#compute_epoch_at_slot) - [Containers](#containers) - [New Containers](#new-containers) - [`ValidatorRegistrationV2`](#validatorregistrationv2) - [`SignedValidatorRegistrationV2`](#signedvalidatorregistrationv2) - [`verify_registration_signature`](#verify_registration_signature) - [Validator Registration V2](#validator-registration-v2) - - [`process_registration`](#process_registration) + - [`process_registration_v2`](#process_registration_v2) - [Constructing a `SignedExecutionPayloadBid`](#constructing-a-signedexecutionpayloadbid) - [Constructing a `SignedExecutionPayloadEnvelope`](#constructing-a-signedexecutionpayloadenvelope) @@ -112,6 +113,9 @@ The following fields are removed: ### `process_registration_v2` +A `validator_registration_v2` is considered valid if the following function +completes without raising any assertions: + ```python def process_registration_v2(state: BeaconState, registration: SignedValidatorRegistrationV2, diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 1376e3c..1a8ca1d 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -1,18 +1,18 @@ - - -**Table of Contents** *generated with -[DocToc](https://github.com/thlorenz/doctoc)* + - [Gloas - Honest Validator](#gloas---honest-validator) - [Introduction](#introduction) + - [Helper](#helper) + - [`get_proposer_slots_in_upcoming_epoch`](#get_proposer_slots_in_upcoming_epoch) - [Validator Registrations](#validator-registrations) - [Constructing the `ValidatorRegistrationV2`](#constructing-the-validatorregistrationv2) - [Validator Registration dissemination](#validator-registration-dissemination) + - [Validating a `SignedExecutionPayloadBid`](#validating-a-signedexecutionpayloadbid) - [Block proposal](#block-proposal) - - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [ExecutionPayloadBid](#executionpayloadbid) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayloadBid](#executionpayloadbid) @@ -97,11 +97,36 @@ def create_validator_registrations(state: BeaconState, validator_index: Validato return registrations ``` +## Validating a `SignedExecutionPayloadBid` + +When the proposer receives a `SignedExecutionPayloadBid` from a builder, it can +validate the bid using `validate_bid`. It can discard the bid if the conditions +are not satisfied. + +```python +def validate_bid( + state: BeaconState, signed_bid: SignedExecutionPayloadBid, fee_recipient: ExecutionAddress +) -> bool: + builder = state.builders[signed_bid.builder_index] + + assert signed_bid.slot == state.slot + assert signed_bid.fee_recipient == fee_recipient + assert signed_bid.parent_block_hash == state.latest_block_hash + assert signed_bid.parent_block_root == hash_tree_root(state.latest_block_header) + assert signed_bid.prev_randao == get_randao_mix(state, get_current_epoch(state)) + assert is_builder(state, builder.pubkey) + + if signed_bid.value > 0: + assert can_builder_cover_bid(state, signed_bid.builder_index, signed_bid.value) + + return verify_execution_payload_bid_signature(state, signed_bid) +``` + ## Block proposal -#### Constructing the `BeaconBlockBody` +### Constructing the `BeaconBlockBody` -##### ExecutionPayloadBid +#### Recieving ExecutionPayloadBid To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take the following actions: From 9a6eeb75e2f1da3783dd3e71840398bc7db5aeb4 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 18 Dec 2025 10:50:18 +0530 Subject: [PATCH 10/31] abstract execution_payment_accepted to a BuilderPreferences struct --- specs/gloas/builder.md | 27 ++++++++++++++++++++++----- specs/gloas/validator.md | 21 ++++++++++++++------- 2 files changed, 36 insertions(+), 12 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 57dea97..62f5e2b 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -1,5 +1,7 @@ + + - [Gloas - Builder Specification](#gloas---builder-specification) @@ -8,7 +10,7 @@ - [Predicates](#predicates) - [`is_active_builder`](#is_active_builder) - [Helper Functions](#helper-functions) - - [`compute_epoch_at_slot`](#compute_epoch_at_slot) + - [`compute_epoch_at_slot`](#compute_epoch_at_slot) - [Containers](#containers) - [New Containers](#new-containers) - [`ValidatorRegistrationV2`](#validatorregistrationv2) @@ -60,6 +62,13 @@ def compute_epoch_at_slot(slot: Slot) -> Epoch: ### New Containers +#### `BuilderPreferences` + +```python +class BuilderPreferences(Container): + execution_payment_accepted: boolean +``` + #### `ValidatorRegistrationV2` ```python @@ -69,7 +78,7 @@ class ValidatorRegistrationV2(Container): fee_recipient: ExecutionAddress proposal_slot: Slot gas_limit: uint64 - execution_payment_accepted: boolean + builder_preferences: BuilderPreferences ``` #### `SignedValidatorRegistrationV2` @@ -91,6 +100,15 @@ def verify_registration_signature(state: BeaconState, signed_registration: Signe return bls.Verify(pubkey, signing_root, signed_registration.signature) ``` +## Builder Preferences + +Using validator registrations, a proposer can express the preferences it has for +a builder. Currently, the only preference that is supported is: + +- `execution_payment_accepted`: This is a boolean which indicates that the + proposer is willing to accept a trusted execution layer payment from the + builder. + ## Validator Registration V2 The second version of ValidatorRegistrations adds the following new fields: @@ -99,9 +117,8 @@ The second version of ValidatorRegistrations adds the following new fields: sent. - `validator_index`: The index of the validator selected to propose a block at slot `proposal_slot` -- `execution_payment_accepted`: This is a boolean which indicates that the - validator is willing accept a trusted execution layer payment from the builder - to which it is sending the registrations. +- `builder_preferences`: This is a struct which contains the per builder + preferences the proposer has. - `proposal_slot`: The slot at which this validator is proposing. The following fields are removed: diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 1a8ca1d..02163f5 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -1,5 +1,7 @@ + + - [Gloas - Honest Validator](#gloas---honest-validator) @@ -11,8 +13,8 @@ - [Validator Registration dissemination](#validator-registration-dissemination) - [Validating a `SignedExecutionPayloadBid`](#validating-a-signedexecutionpayloadbid) - [Block proposal](#block-proposal) - - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [ExecutionPayloadBid](#executionpayloadbid) + - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) + - [ExecutionPayloadBid](#executionpayloadbid) @@ -43,9 +45,9 @@ def get_proposer_slots_in_upcoming_epoch( current_epoch_start_slot = compute_start_slot_at_epoch(get_current_epoch(state)) next_epoch_proposer_lookahead = state.proposer_lookahead[SLOTS_PER_EPOCH:] - for i, proposer_index in enumerate(next_epoch_proposer_lookahead): + for offset, proposer_index in enumerate(next_epoch_proposer_lookahead): if proposer_index == validator_index: - slot = current_epoch_start_slot + SLOTS_PER_EPOCH + i + slot = current_epoch_start_slot + SLOTS_PER_EPOCH + offset proposer_slots.append(slot) return proposer_slots @@ -80,17 +82,22 @@ many validator registrations all at once to builders. Validators run registrations for all the slots they will be proposing in the upcoming epoch. ```python -def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_index: BuilderIndex, execution_payment_accepted: bool) -> List[ValidatorRegistrationV2]: +def create_validator_registrations_for_builder(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_index: BuilderIndex, builder_preferences: BuilderPreferences) -> List[ValidatorRegistrationV2]: slots = get_proposer_slots_in_lookahead(state, validator_index) registrations: List[ValidatorRegistrationsV2] = [] + assert is_builder(state, builder_index) + + builder = state.builders[builder_index] + assert builder.exit_epoch == FAR_FUTURE_EPOCH + for slot in slots: registrations.append(ValidatorRegistrationV2( fee_recipient=fee_recipient, builder_index=builder_index, gas_limit=gas_limit, validator_index=validator_index - execution_payment_accepted=execution_payment_accepted, + builder_preferences=builder_preferences, proposal_slot=slot )) @@ -126,7 +133,7 @@ def validate_bid( ### Constructing the `BeaconBlockBody` -#### Recieving ExecutionPayloadBid +#### Receiving ExecutionPayloadBid To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take the following actions: From 36fdcd25cb18eb55911197d518b59ccda9d72af9 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 18 Dec 2025 11:39:31 +0530 Subject: [PATCH 11/31] minor fixes --- builder-oapi.yaml | 2 +- specs/gloas/builder.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/builder-oapi.yaml b/builder-oapi.yaml index ca26f88..26c9916 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -52,7 +52,7 @@ paths: /eth/v1/builder/validators: $ref: "./apis/builder/validators.yaml" /eth/v2/builder/validators: - $ref: "./apis/builder/validators_2.yaml" + $ref: "./apis/builder/validators_v2.yaml" /eth/v1/builder/header/{slot}/{parent_hash}/{pubkey}: $ref: "./apis/builder/header.yaml" /eth/v1/builder/execution_payload_bid/{slot}/{parent_hash}/{parent_root}/{proposer_index}: diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 62f5e2b..2c90255 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -126,7 +126,7 @@ The following fields are removed: - `pubkey`: This is the pubkey of the validator which has now been replaced with `validator_index`. - `timestamp`: A new validator registration will be sent by the validator to the - builder in the epoch prior to one where + builder in the epoch prior to one where they will be proposing. ### `process_registration_v2` From 75a99060fdae52579bf4f7c908ffbe3aefe50025 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 18 Dec 2025 11:42:41 +0530 Subject: [PATCH 12/31] run doctoc --- specs/gloas/builder.md | 6 +++--- specs/gloas/validator.md | 4 +--- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 2c90255..876fb36 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -1,7 +1,5 @@ - - - [Gloas - Builder Specification](#gloas---builder-specification) @@ -10,12 +8,14 @@ - [Predicates](#predicates) - [`is_active_builder`](#is_active_builder) - [Helper Functions](#helper-functions) - - [`compute_epoch_at_slot`](#compute_epoch_at_slot) + - [`compute_epoch_at_slot`](#compute_epoch_at_slot) - [Containers](#containers) - [New Containers](#new-containers) + - [`BuilderPreferences`](#builderpreferences) - [`ValidatorRegistrationV2`](#validatorregistrationv2) - [`SignedValidatorRegistrationV2`](#signedvalidatorregistrationv2) - [`verify_registration_signature`](#verify_registration_signature) + - [Builder Preferences](#builder-preferences) - [Validator Registration V2](#validator-registration-v2) - [`process_registration_v2`](#process_registration_v2) - [Constructing a `SignedExecutionPayloadBid`](#constructing-a-signedexecutionpayloadbid) diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 02163f5..a40cc19 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -1,7 +1,5 @@ - - - [Gloas - Honest Validator](#gloas---honest-validator) @@ -14,7 +12,7 @@ - [Validating a `SignedExecutionPayloadBid`](#validating-a-signedexecutionpayloadbid) - [Block proposal](#block-proposal) - [Constructing the `BeaconBlockBody`](#constructing-the-beaconblockbody) - - [ExecutionPayloadBid](#executionpayloadbid) + - [Receiving ExecutionPayloadBid](#receiving-executionpayloadbid) From b2b5974e527524d3109dc0cbdd5323454d08894e Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Fri, 19 Dec 2025 15:53:00 +0530 Subject: [PATCH 13/31] use correct method to check if builder is active --- specs/gloas/validator.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index a40cc19..737f629 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -84,10 +84,7 @@ def create_validator_registrations_for_builder(state: BeaconState, validator_ind slots = get_proposer_slots_in_lookahead(state, validator_index) registrations: List[ValidatorRegistrationsV2] = [] - assert is_builder(state, builder_index) - - builder = state.builders[builder_index] - assert builder.exit_epoch == FAR_FUTURE_EPOCH + assert is_active_builder(state, builder_index) for slot in slots: registrations.append(ValidatorRegistrationV2( From 6e8f58ae6cef71466b21b6eca31ee274f7fe2dc4 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 23 Dec 2025 19:39:08 +0530 Subject: [PATCH 14/31] save --- apis/builder/execution_payload_bid.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index 8f28ee4..6a5bdd6 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -29,7 +29,7 @@ get: - name: parent_root in: path required: true - description: Root of the execution layer block the proposer will build on. + description: Root of the beacon block the proposer will build on. schema: $ref: "../../builder-oapi.yaml#/components/schemas/Root" - name: proposer_index From 5f6763916d0dd7e55748ef01b1fd81c1d0c67a3d Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 23 Dec 2025 22:49:33 +0530 Subject: [PATCH 15/31] updates --- specs/gloas/builder.md | 30 ++++++++++++++++++++---------- specs/gloas/validator.md | 6 ++++-- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 876fb36..6f9f938 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -1,5 +1,7 @@ + + - [Gloas - Builder Specification](#gloas---builder-specification) @@ -8,7 +10,7 @@ - [Predicates](#predicates) - [`is_active_builder`](#is_active_builder) - [Helper Functions](#helper-functions) - - [`compute_epoch_at_slot`](#compute_epoch_at_slot) + - [`compute_epoch_at_slot`](#compute_epoch_at_slot) - [Containers](#containers) - [New Containers](#new-containers) - [`BuilderPreferences`](#builderpreferences) @@ -39,11 +41,17 @@ This document documents the builder behaviour with the Builder-API. ### `is_active_builder` ```python -def is_active_builder(builder: Builder) -> bool: +def is_active_builder(state: BeaconState, builder_index: BuilderIndex) -> bool: """ - Check if ``builder`` is active. + Check if the builder at ``builder_index`` is active for the given ``state``. """ - return builder.exit_epoch == FAR_FUTURE_EPOCH + builder = state.builders[builder_index] + return ( + # Placement in builder list is finalized + builder.deposit_epoch < state.finalized_checkpoint.epoch + # Has not initiated exit + and builder.withdrawable_epoch == FAR_FUTURE_EPOCH + ) ``` ## Helper Functions @@ -144,19 +152,15 @@ def process_registration_v2(state: BeaconState, builder_index = registration.builder_index proposal_slot = registration.proposal_slot - assert validator_index < len(state.validators) - assert builder_index < len(state.builders) - validator = state.validators[validator_index] builder = state.builders[builder_index] - assert is_active_validator(validator, compute_epoch_at_slot(proposal_slot)) - assert is_active_builder(builder) + assert is_active_builder(state, builder) # Verify validator registration elibility assert is_eligible_for_registration(state, validator) - # Verify that the old registration's slot is earlier than the new registration's slot + # Verify that the old registration's proposal slot is earlier than the new registration's proposal slot if registration.pubkey in registrations: prev_registration = registrations[validator_index] assert registration.proposal_slot >= prev_registration.proposal_slot @@ -173,6 +177,12 @@ gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/ ## Constructing a `SignedExecutionPayloadEnvelope` +If the builder's `SignedExecutionPayloadBid` has been accepted by the proposer +and it has been included in it's `SignedBeaconBlock`, then the builder has to +construct a `SignedExecutionPayloadEnvelope` corresponding to the +`SignedExecutionPayloadBid` and it has to broadcast it to the PTC committee via +the `execution_payload_envelope` gossip topic. + The specification for a block builder to construct a `SignedExecutionPayloadEnvelope` is documented in the gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 737f629..5b4eb32 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -1,5 +1,7 @@ + + - [Gloas - Honest Validator](#gloas---honest-validator) @@ -110,13 +112,13 @@ def validate_bid( state: BeaconState, signed_bid: SignedExecutionPayloadBid, fee_recipient: ExecutionAddress ) -> bool: builder = state.builders[signed_bid.builder_index] - + + assert is_active_builder(state, builder) assert signed_bid.slot == state.slot assert signed_bid.fee_recipient == fee_recipient assert signed_bid.parent_block_hash == state.latest_block_hash assert signed_bid.parent_block_root == hash_tree_root(state.latest_block_header) assert signed_bid.prev_randao == get_randao_mix(state, get_current_epoch(state)) - assert is_builder(state, builder.pubkey) if signed_bid.value > 0: assert can_builder_cover_bid(state, signed_bid.builder_index, signed_bid.value) From d5031933a55630c3f779ce9d4c068a36a0ebde58 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 23 Dec 2025 23:02:46 +0530 Subject: [PATCH 16/31] add information for bidding --- specs/gloas/builder.md | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 6f9f938..3ab317c 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -108,6 +108,48 @@ def verify_registration_signature(state: BeaconState, signed_registration: Signe return bls.Verify(pubkey, signing_root, signed_registration.signature) ``` +## Bidding + +In Gloas, Execution payloads are built for a specific `slot`, `parent_hash`, +`pubkey` along with the `parent_root` tuple corresponding to a unique beacon +block serving as the parent. + +This is because in Gloas with EIP-7732, the execution payload and beacon blocks +are decoupled. The `parent_hash` could refer to a beacon block which is an +ancestor of the parent beacon block corresponding to the current beacon block +for which we are building the execution payload. + +We update `is_eligible_for_bid` below: + +```python +def is_eligible_for_bid(state: BeaconState, + registrations: Dict[BLSPubkey, ValidatorRegistrationV2], + slot: Slot, + parent_hash: Hash32, + # [New in Gloas] + parent_root: Root, + pubkey: BLSPubkey): + # Verify slot + if slot != state.slot: + return False + + # Verify BLS public key corresponds to a registered validator + if pubkey not in registrations: + return False + + # Verify BLS public key corresponds to the proposer for the slot + proposer_index = get_beacon_proposer_index(state) + if pubkey != state.validators[proposer_index].pubkey: + return False + + # Verify parent hash + # [Modified in Gloas:EIP7732] + assert parent_hash == state.latest_block_hash + + # Verify parent root + assert parent_root == hash_tree_root(state.latest_block_header) +``` + ## Builder Preferences Using validator registrations, a proposer can express the preferences it has for From c78bccde36e696514626bcb9e9b7839194ef038b Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 23 Dec 2025 23:17:30 +0530 Subject: [PATCH 17/31] update --- apis/builder/execution_payload_bid.yaml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index 6a5bdd6..da04a93 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -61,16 +61,6 @@ get: type: integer format: int64 example: 10000 - - name: X-Fee-Recipient - in: header - required: true - description: | - Required header containing the fee recipient address to which the proposer wants to receive - the payment for the bid. - schema: - type: string - format: address - example: "0x0000000000000000000000000000000000000000" responses: "200": description: Success response. From 959babe5ae2b57862a5a173c9e8ce796940598b4 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 6 Jan 2026 22:18:35 +0530 Subject: [PATCH 18/31] add bid request auth --- apis/builder/execution_payload_bid.yaml | 34 ++++++++++--- builder-oapi.yaml | 5 ++ specs/gloas/builder.md | 39 ++------------- specs/gloas/validator.md | 65 ++++++++++++++++++++----- types/gloas/bid_request_auth.yaml | 22 +++++++++ 5 files changed, 114 insertions(+), 51 deletions(-) create mode 100644 types/gloas/bid_request_auth.yaml diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index da04a93..0578d64 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -1,14 +1,23 @@ -get: +post: operationId: "getExecutionPayloadBid" summary: Get an execution payload bid. description: | Requests a builder node to produce a valid execution payload bid, which - can be integrated into a blinded beacon block and signed. + can be integrated into a blinded beacon block and signed. + + The proposer sends a POST request to the builder with the following information: + - The slot for which the block should be proposed. + - The hash of the execution layer block the proposer will build on. + - The root of the beacon block the proposer will build on. + - The index of the proposer. + - A signed bid request auth to authenticate the request to a specific builder index. + + The builder responds with a 200 response containing an execution payload bid if it can provide one. If the builder is unable to produce a valid execution payload bid, then the builder MUST return a 204 response. If the request is invalid, then the builder MUST return an error response (400) with a description of the - validation failure. + validation failure. If the SignedBidRequestAuth is invalid, the builder MUST return a 400 response. This API is applicable from Glamsterdam fork onwards. tags: @@ -55,12 +64,21 @@ get: description: | Optional header containing the proposer's timeout for the request in milliseconds. Builders should use this header to adjust the amount of time by which they delay getBid - requests to maximise block rewards. Otherwise, getBid requests will timeout and the proposer + requests to maximise block rewards. Otherwise, getExecutionPayloadBid requests will timeout and the proposer will not receive the header in time. schema: type: integer format: int64 example: 10000 + requestBody: + required: true + content: + application/json: + schema: + $ref: "../../types/gloas/bid_request_auth.yaml#/Gloas/SignedBidRequestAuth" + application/octet-stream: + schema: + description: "SSZ serialized `SignedBidRequestAuth` bytes." responses: "200": description: Success response. @@ -85,7 +103,7 @@ get: schema: description: "SSZ serialized `ExecutionPayloadBid` bytes. Use Accept header to choose this response type" "204": - description: No header is available. + description: No bid is available. "400": description: Error response. content: @@ -93,10 +111,14 @@ get: schema: $ref: "../../builder-oapi.yaml#/components/schemas/ErrorMessage" examples: - InvalidRequest: + InvalidHash: value: code: 400 message: "Unknown hash: missing parent hash" + InvalidAuth: + value: + code: 400 + message: "Invalid SignedBidRequestAuth: signature verification failed" "406": $ref: "../../builder-oapi.yaml#/components/responses/NotAcceptable" "500": diff --git a/builder-oapi.yaml b/builder-oapi.yaml index 26c9916..3e3915e 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -110,6 +110,11 @@ components: $ref: "./types/fulu/blobs_bundle.yaml#/Fulu/BlobsBundle" Fulu.ExecutionPayloadAndBlobsBundle: $ref: "./types/fulu/execution_payload_and_blobs_bundle.yaml#/Fulu/ExecutionPayloadAndBlobsBundle" + Gloas.BidRequestAuth: + $ref: "./types/gloas/bid_request_auth.yaml#/Gloas/BidRequestAuth" + Gloas.SignedBidRequestAuth: + $ref: "./types/gloas/bid_request_auth.yaml#/Gloas/SignedBidRequestAuth" + responses: InternalError: diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 3ab317c..1bf14db 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -29,43 +29,13 @@ ## Introduction -This document documents the builder behaviour with the Builder-API. +This document documents the builder behaviour with the Builder-API post ePBS. ## Custom types | Name | SSZ equivalent | Description | | -------------- | -------------- | ---------------------- | | `BuilderIndex` | `uint64` | Builder registry index | -## Predicates - -### `is_active_builder` - -```python -def is_active_builder(state: BeaconState, builder_index: BuilderIndex) -> bool: - """ - Check if the builder at ``builder_index`` is active for the given ``state``. - """ - builder = state.builders[builder_index] - return ( - # Placement in builder list is finalized - builder.deposit_epoch < state.finalized_checkpoint.epoch - # Has not initiated exit - and builder.withdrawable_epoch == FAR_FUTURE_EPOCH - ) -``` - -## Helper Functions - -#### `compute_epoch_at_slot` - -```python -def compute_epoch_at_slot(slot: Slot) -> Epoch: - """ - Return the epoch number at ``slot``. - """ - return Epoch(slot // SLOTS_PER_EPOCH) -``` - ## Containers ### New Containers @@ -81,8 +51,8 @@ class BuilderPreferences(Container): ```python class ValidatorRegistrationV2(Container): - builder_index: BuilderIndex validator_index: ValidatorIndex + builder_index: BuilderIndex fee_recipient: ExecutionAddress proposal_slot: Slot gas_limit: uint64 @@ -147,6 +117,7 @@ def is_eligible_for_bid(state: BeaconState, assert parent_hash == state.latest_block_hash # Verify parent root + # [Modified in Gloas:EIP7732] assert parent_root == hash_tree_root(state.latest_block_header) ``` @@ -163,8 +134,8 @@ a builder. Currently, the only preference that is supported is: The second version of ValidatorRegistrations adds the following new fields: -- `builder_index`: The index of the builder to which this registration is being - sent. +- `builder_index`: The index of the builder to which the validator is sending + the registration. - `validator_index`: The index of the validator selected to propose a block at slot `proposal_slot` - `builder_preferences`: This is a struct which contains the per builder diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 5b4eb32..430174a 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -23,12 +23,37 @@ ## Introduction This document explains how a beacon-chain validator can participate in the -external block building market post ePBS. +external block building market with the Builder-API post ePBS. Validators request an `ExecutionPayloadBid` from the external builder network to put it in their `SignedBeaconBlock`. The external builder network broadcasts the `SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC committee. +## Containers + +### New Containers + +#### `BidRequestAuth` + +`BidRequestAuth` is used to authenticate requests to get the bid from a builder. +This is useful so that other builders don't DDOS the builder to get their latest +bid. + +```python +class BidRequestAuth(Container): + builder_index: BuilderIndex + validator_index: ValidatorIndex + proposer_slot: Slot +``` + +#### `SignedBidRequestAuth` + +```python +class SignedBidRequestAuth(Container): + message: BidRequestAuth + signature: BLSSignature +``` + ## Helper ### `get_proposer_slots_in_upcoming_epoch` @@ -53,6 +78,21 @@ def get_proposer_slots_in_upcoming_epoch( return proposer_slots ``` +## Bid Authentication + +### Constructing the `BidRequestAuth` + +To construct the `BidRequestAuth`, we need to fill the following information: + +- `builder_index`: This builder index for which the validator is sending a + request to get the bid. +- `validator_index`: The proposer's validator index. +- `proposal_slot`: The slot at which the proposer is building a block. + +The validator constructs the `SignedBidRequestAuth` by signing the +`BidRequestAuth`. It sends the `SignedBidRequestAuth` as a header along with the +request to get the bid. + ## Validator Registrations ### Constructing the `ValidatorRegistrationV2` @@ -61,17 +101,17 @@ To do this, the validator client assembles a \[`ValidatorRegistrationV2`\][validator-registration-v2] with the following information: -- `fee_recipient`: an execution layer address where fees for the validator +- `builder_index`: The index of the builder to which the validator is submitting + the registration. +- `fee_recipient`: An execution layer address where fees for the validator should go. -- `builder_index`: the index of the builder to which this registration is being - sent to. -- `gas_limit`: the value a validator prefers for the execution block gas limit. -- `validator_index`: the validator's index. Used to identify the beacon chain +- `gas_limit`: The value a validator prefers for the execution block gas limit. +- `validator_index`: The validator's index. Used to identify the beacon chain validator and verify the wrapping signature. -- `execution_payment_accepted`: whether the proposer is willing to accept a +- `execution_payment_accepted`: Whether the proposer is willing to accept a trusted payment from the builder with index `builder_index`. - `proposal_slot`: This is set to the slot in which the validator will be - proposing. This can be looked up in the `proposal_lookahead`. + proposing. This can be looked up in `state.proposal_lookahead`. ### Validator Registration dissemination @@ -91,8 +131,8 @@ def create_validator_registrations_for_builder(state: BeaconState, validator_ind for slot in slots: registrations.append(ValidatorRegistrationV2( fee_recipient=fee_recipient, - builder_index=builder_index, gas_limit=gas_limit, + builder_index=builder_index, validator_index=validator_index builder_preferences=builder_preferences, proposal_slot=slot @@ -135,11 +175,14 @@ def validate_bid( To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take the following actions: -1. Call upstream builder software to get an `ExecutionPayloadBid`. +1. Call upstream builder software to get an `ExecutionPayloadBid`. The validator + is required to send the `SignedBidRequestAuth` in the request body in order to + authenticate the request to the builder. If a builder has multiple builder indices associated with + them, the validator will have to call the upstream builder software each time for each builder index. 2. Assemble a `SignedBeaconBlock` according to the process outlined in the \[Gloas specs\][https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal] - but with the `ExecutionPayloadBid` from the prior step. + but with the best `ExecutionPayloadBid` from the prior step. 3. The proposer returns the `SignedBeaconBlock` back to the upstream block building software. 4. The upstream block building software constructs the diff --git a/types/gloas/bid_request_auth.yaml b/types/gloas/bid_request_auth.yaml new file mode 100644 index 0000000..6fa4c2d --- /dev/null +++ b/types/gloas/bid_request_auth.yaml @@ -0,0 +1,22 @@ +Gloas: + BidRequestAuth: + type: object + required: [builder_index, validator_index, proposal_slot] + properties: + builder_index: + $ref: "../../builder-oapi.yaml#/components/schemas/Uint64" + description: "The index of the builder to which the validator is sending the request." + validator_index: + $ref: "../../beacon-apis/types/primitive.yaml#/ValidatorIndex" + description: "The index of the validator that is sending the request." + proposal_slot: + $ref: "../../beacon-apis/types/primitive.yaml#/Slot" + description: "The slot at which the proposer is building a block." + SignedBidRequestAuth: + type: object + required: [message, signature] + properties: + message: + $ref: "#/Gloas/BidRequestAuth" + signature: + $ref: "../../beacon-apis/types/primitive.yaml#/BLSSignature" \ No newline at end of file From 61cc85e6deb2b6afdb590356db79b9bb27525492 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 6 Jan 2026 22:28:11 +0530 Subject: [PATCH 19/31] remove builder index from validator registration --- specs/gloas/builder.md | 7 ------- specs/gloas/validator.md | 14 +++++--------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 1bf14db..054e8d2 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -52,7 +52,6 @@ class BuilderPreferences(Container): ```python class ValidatorRegistrationV2(Container): validator_index: ValidatorIndex - builder_index: BuilderIndex fee_recipient: ExecutionAddress proposal_slot: Slot gas_limit: uint64 @@ -134,8 +133,6 @@ a builder. Currently, the only preference that is supported is: The second version of ValidatorRegistrations adds the following new fields: -- `builder_index`: The index of the builder to which the validator is sending - the registration. - `validator_index`: The index of the validator selected to propose a block at slot `proposal_slot` - `builder_preferences`: This is a struct which contains the per builder @@ -162,13 +159,9 @@ def process_registration_v2(state: BeaconState, signature = registration.signature registration = registration.message validator_index = registration.validator_index - builder_index = registration.builder_index proposal_slot = registration.proposal_slot validator = state.validators[validator_index] - builder = state.builders[builder_index] - - assert is_active_builder(state, builder) # Verify validator registration elibility assert is_eligible_for_registration(state, validator) diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 430174a..d7d4ad6 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -101,8 +101,6 @@ To do this, the validator client assembles a \[`ValidatorRegistrationV2`\][validator-registration-v2] with the following information: -- `builder_index`: The index of the builder to which the validator is submitting - the registration. - `fee_recipient`: An execution layer address where fees for the validator should go. - `gas_limit`: The value a validator prefers for the execution block gas limit. @@ -122,17 +120,14 @@ many validator registrations all at once to builders. Validators run registrations for all the slots they will be proposing in the upcoming epoch. ```python -def create_validator_registrations_for_builder(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_index: BuilderIndex, builder_preferences: BuilderPreferences) -> List[ValidatorRegistrationV2]: +def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_preferences: BuilderPreferences) -> List[ValidatorRegistrationV2]: slots = get_proposer_slots_in_lookahead(state, validator_index) registrations: List[ValidatorRegistrationsV2] = [] - assert is_active_builder(state, builder_index) - for slot in slots: registrations.append(ValidatorRegistrationV2( fee_recipient=fee_recipient, gas_limit=gas_limit, - builder_index=builder_index, validator_index=validator_index builder_preferences=builder_preferences, proposal_slot=slot @@ -176,9 +171,10 @@ To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take the following actions: 1. Call upstream builder software to get an `ExecutionPayloadBid`. The validator - is required to send the `SignedBidRequestAuth` in the request body in order to - authenticate the request to the builder. If a builder has multiple builder indices associated with - them, the validator will have to call the upstream builder software each time for each builder index. + is required to send the `SignedBidRequestAuth` in the request body in order + to authenticate the request to the builder. If a builder has multiple builder + indices associated with them, the validator will have to call the upstream + builder software each time for each builder index. 2. Assemble a `SignedBeaconBlock` according to the process outlined in the \[Gloas specs\][https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal] From a382dcc7a275629ebf58ef4178dcf25810cdeccc Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Tue, 6 Jan 2026 22:50:22 +0530 Subject: [PATCH 20/31] add validator registration type --- apis/builder/validators_v2.yaml | 2 +- beacon-apis | 2 +- builder-oapi.yaml | 11 +++++---- specs/gloas/validator.md | 2 +- types/gloas/bid_request_auth.yaml | 6 ++--- types/gloas/registration.yaml | 38 +++++++++++++++++++++++++++++++ 6 files changed, 51 insertions(+), 10 deletions(-) create mode 100644 types/gloas/registration.yaml diff --git a/apis/builder/validators_v2.yaml b/apis/builder/validators_v2.yaml index eeff67b..813ae98 100644 --- a/apis/builder/validators_v2.yaml +++ b/apis/builder/validators_v2.yaml @@ -21,7 +21,7 @@ post: schema: type: array items: - $ref: "../../builder-oapi.yaml#/components/schemas/SignedValidatorRegistrationV2" + $ref: "../../builder-oapi.yaml#/components/schemas/Gloas.SignedValidatorRegistrationV2" example: $ref: "../../builder-oapi.yaml#/components/examples/SignedValidatorRegistrations/value" application/octet-stream: diff --git a/beacon-apis b/beacon-apis index 339eea9..fe36269 160000 --- a/beacon-apis +++ b/beacon-apis @@ -1 +1 @@ -Subproject commit 339eea96b41c787dad47765fc781303fb40aa886 +Subproject commit fe362694bd70685fe7d24cc40ada99178a354d7d diff --git a/builder-oapi.yaml b/builder-oapi.yaml index 3e3915e..99e7545 100644 --- a/builder-oapi.yaml +++ b/builder-oapi.yaml @@ -100,8 +100,6 @@ components: $ref: "./types/deneb/execution_payload_and_blobs_bundle.yaml#/Deneb/ExecutionPayloadAndBlobsBundle" SignedValidatorRegistration: $ref: "./beacon-apis/types/registration.yaml#/SignedValidatorRegistration" - SignedValidatorRegistrationV2: - $ref: "./beacon-apis/types/registration.yaml#/SignedValidatorRegistrationV2" Electra.SignedBlindedBeaconBlock: $ref: "./beacon-apis/types/electra/block.yaml#/Electra/SignedBlindedBeaconBlock" Electra.SignedBuilderBid: @@ -114,8 +112,13 @@ components: $ref: "./types/gloas/bid_request_auth.yaml#/Gloas/BidRequestAuth" Gloas.SignedBidRequestAuth: $ref: "./types/gloas/bid_request_auth.yaml#/Gloas/SignedBidRequestAuth" - - + Gloas.BuilderPreferences: + $ref: "./types/gloas/registration.yaml#/Gloas/BuilderPreferences" + Gloas.ValidatorRegistrationV2: + $ref: "./types/gloas/registration.yaml#/Gloas/ValidatorRegistrationV2" + Gloas.SignedValidatorRegistrationV2: + $ref: "./types/gloas/registration.yaml#/Gloas/SignedValidatorRegistrationV2" + responses: InternalError: $ref: "./types/http.yaml#/InternalError" diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index d7d4ad6..323e0b8 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -121,7 +121,7 @@ registrations for all the slots they will be proposing in the upcoming epoch. ```python def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_preferences: BuilderPreferences) -> List[ValidatorRegistrationV2]: - slots = get_proposer_slots_in_lookahead(state, validator_index) + slots = get_proposer_slots_in_upcoming_epoch(state, validator_index) registrations: List[ValidatorRegistrationsV2] = [] for slot in slots: diff --git a/types/gloas/bid_request_auth.yaml b/types/gloas/bid_request_auth.yaml index 6fa4c2d..4053307 100644 --- a/types/gloas/bid_request_auth.yaml +++ b/types/gloas/bid_request_auth.yaml @@ -7,10 +7,10 @@ Gloas: $ref: "../../builder-oapi.yaml#/components/schemas/Uint64" description: "The index of the builder to which the validator is sending the request." validator_index: - $ref: "../../beacon-apis/types/primitive.yaml#/ValidatorIndex" + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" description: "The index of the validator that is sending the request." proposal_slot: - $ref: "../../beacon-apis/types/primitive.yaml#/Slot" + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" description: "The slot at which the proposer is building a block." SignedBidRequestAuth: type: object @@ -19,4 +19,4 @@ Gloas: message: $ref: "#/Gloas/BidRequestAuth" signature: - $ref: "../../beacon-apis/types/primitive.yaml#/BLSSignature" \ No newline at end of file + $ref: "../../beacon-apis/types/primitive.yaml#/Signature" \ No newline at end of file diff --git a/types/gloas/registration.yaml b/types/gloas/registration.yaml new file mode 100644 index 0000000..1135975 --- /dev/null +++ b/types/gloas/registration.yaml @@ -0,0 +1,38 @@ +Gloas: + BuilderPreferences: + type: object + description: "Per-builder preferences that a validator can express." + required: [execution_payment_accepted] + properties: + execution_payment_accepted: + type: boolean + description: "Indicates that the proposer is willing to accept a trusted execution layer payment from the builder." + ValidatorRegistrationV2: + type: object + description: "The `ValidatorRegistrationV2` object for Gloas fork, replacing pubkey and timestamp with validator_index, proposal_slot, and builder_preferences." + required: [validator_index, fee_recipient, proposal_slot, gas_limit, builder_preferences] + properties: + validator_index: + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" + description: "Validator index. Used to identify the beacon chain validator and verify the signature." + fee_recipient: + $ref: "../../beacon-apis/types/primitive.yaml#/ExecutionAddress" + description: "Address to receive fees from the block." + proposal_slot: + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" + description: "The slot at which this validator is proposing." + gas_limit: + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" + description: "Preferred gas limit of validator." + builder_preferences: + $ref: "#/Gloas/BuilderPreferences" + description: "Per-builder preferences." + SignedValidatorRegistrationV2: + type: object + description: "The `SignedValidatorRegistrationV2` object for Gloas fork." + required: [message, signature] + properties: + message: + $ref: "#/Gloas/ValidatorRegistrationV2" + signature: + $ref: "../../beacon-apis/types/primitive.yaml#/Signature" \ No newline at end of file From 29c1908043f2b2fe0928d9c68d28bfea7b7b28ca Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 7 Jan 2026 10:36:49 +0530 Subject: [PATCH 21/31] link to api calls --- specs/gloas/builder.md | 96 ++++++++++++++++++++++----------------- specs/gloas/validator.md | 97 +++++++++++++++++++++++++++------------- wordlist.txt | 7 ++- 3 files changed, 126 insertions(+), 74 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 054e8d2..0267d27 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -6,17 +6,13 @@ - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) - - [Custom types](#custom-types) - - [Predicates](#predicates) - - [`is_active_builder`](#is_active_builder) - - [Helper Functions](#helper-functions) - - [`compute_epoch_at_slot`](#compute_epoch_at_slot) - [Containers](#containers) - [New Containers](#new-containers) - [`BuilderPreferences`](#builderpreferences) - [`ValidatorRegistrationV2`](#validatorregistrationv2) - [`SignedValidatorRegistrationV2`](#signedvalidatorregistrationv2) - - [`verify_registration_signature`](#verify_registration_signature) + - [`verify_registration_v2_signature`](#verify_registration_v2_signature) + - [Bidding](#bidding) - [Builder Preferences](#builder-preferences) - [Validator Registration V2](#validator-registration-v2) - [`process_registration_v2`](#process_registration_v2) @@ -29,12 +25,11 @@ ## Introduction -This document documents the builder behaviour with the Builder-API post ePBS. - -## Custom types - -| Name | SSZ equivalent | Description | | -------------- | -------------- | ----------------------- | | `BuilderIndex` | `uint64` | Builder registry index | +This document documents the builder behaviour with the Builder-API post ePBS. It +describes how builders interact with validators through +[`ValidatorRegistrationV2`][validator-registration-v2] and construct +[`SignedExecutionPayloadBid`][signed-execution-payload-bid] and +[`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] objects. ## Containers @@ -66,10 +61,13 @@ class SignedValidatorRegistrationV2(Container): signature: BLSSignature ``` -### `verify_registration_signature` +### `verify_registration_v2_signature` + +*Note*: `compute_domain` and `compute_signing_root` are defined in the +[Gloas consensus specs][gloas-consensus-specs]. ```python -def verify_registration_signature(state: BeaconState, signed_registration: SignedValidatorRegistrationV2) -> bool: +def verify_registration_v2_signature(state: BeaconState, signed_registration: SignedValidatorRegistrationV2) -> bool: validator = state.validators[signed_registration.message.validator_index] pubkey = validator.pubkey domain = compute_domain(DOMAIN_APPLICATION_BUILDER) @@ -80,35 +78,34 @@ def verify_registration_signature(state: BeaconState, signed_registration: Signe ## Bidding In Gloas, Execution payloads are built for a specific `slot`, `parent_hash`, -`pubkey` along with the `parent_root` tuple corresponding to a unique beacon -block serving as the parent. +`validator_index` along with the `parent_root` tuple corresponding to a unique +beacon block serving as the parent. -This is because in Gloas with EIP-7732, the execution payload and beacon blocks -are decoupled. The `parent_hash` could refer to a beacon block which is an -ancestor of the parent beacon block corresponding to the current beacon block -for which we are building the execution payload. +This is because in Gloas with [EIP-7732][eip-7732], the execution payload and +beacon blocks are decoupled. The `parent_hash` could refer to a beacon block +which is an ancestor of the parent beacon block corresponding to the current +beacon block for which we are building the execution payload. -We update `is_eligible_for_bid` below: +We update `is_eligible_for_bid` below. *Note*: `hash_tree_root` is defined in +the [Gloas consensus specs][gloas-consensus-specs]. ```python def is_eligible_for_bid(state: BeaconState, - registrations: Dict[BLSPubkey, ValidatorRegistrationV2], + registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], slot: Slot, parent_hash: Hash32, # [New in Gloas] parent_root: Root, - pubkey: BLSPubkey): + # [New in Gloas] + validator_index: ValidatorIndex): # Verify slot if slot != state.slot: return False - # Verify BLS public key corresponds to a registered validator - if pubkey not in registrations: + if validator_index not in state.validators.keys(): return False - # Verify BLS public key corresponds to the proposer for the slot - proposer_index = get_beacon_proposer_index(state) - if pubkey != state.validators[proposer_index].pubkey: + if validator_index not in registrations: return False # Verify parent hash @@ -149,12 +146,16 @@ The following fields are removed: ### `process_registration_v2` A `validator_registration_v2` is considered valid if the following function -completes without raising any assertions: +completes without raising any assertions. + +*Note*: [`is_eligible_for_registration`][is-eligible-for-registration] and +[`verify_registration_signature`][verify-registration-signature] are defined in +the [Gloas consensus specs][gloas-consensus-specs]. ```python def process_registration_v2(state: BeaconState, registration: SignedValidatorRegistrationV2, - registrations: Dict[BLSPubkey, ValidatorRegistrationV2], + registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], current_timestamp: uint64): signature = registration.signature registration = registration.message @@ -163,11 +164,11 @@ def process_registration_v2(state: BeaconState, validator = state.validators[validator_index] - # Verify validator registration elibility + # Verify validator registration eligibility assert is_eligible_for_registration(state, validator) # Verify that the old registration's proposal slot is earlier than the new registration's proposal slot - if registration.pubkey in registrations: + if validator_index in registrations: prev_registration = registrations[validator_index] assert registration.proposal_slot >= prev_registration.proposal_slot @@ -177,18 +178,29 @@ def process_registration_v2(state: BeaconState, ## Constructing a `SignedExecutionPayloadBid` -The specification for a block builder to construct a `SignedExecutionPayloadBid` -is documented in the -gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. +The specification for a block builder to construct a +[`SignedExecutionPayloadBid`][signed-execution-payload-bid] is documented in the +[Gloas consensus specs][gloas-builder-specs]. ## Constructing a `SignedExecutionPayloadEnvelope` -If the builder's `SignedExecutionPayloadBid` has been accepted by the proposer -and it has been included in it's `SignedBeaconBlock`, then the builder has to -construct a `SignedExecutionPayloadEnvelope` corresponding to the -`SignedExecutionPayloadBid` and it has to broadcast it to the PTC committee via -the `execution_payload_envelope` gossip topic. +If the builder's [`SignedExecutionPayloadBid`][signed-execution-payload-bid] has +been accepted by the proposer and it has been included in it's +`SignedBeaconBlock`, then the builder has to construct a +[`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] +corresponding to the [`SignedExecutionPayloadBid`][signed-execution-payload-bid] +and it has to broadcast it to the PTC committee via the +`execution_payload_envelope` gossip topic. The specification for a block builder to construct a -`SignedExecutionPayloadEnvelope` is documented in the -gloas-specs[https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md]. +[`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] is +documented in the [Gloas consensus specs][gloas-builder-specs]. + +[eip-7732]: https://eips.ethereum.org/EIPS/eip-7732 +[gloas-builder-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md +[gloas-consensus-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas +[is-eligible-for-registration]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#is_eligible_for_registration +[signed-execution-payload-bid]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid +[signed-execution-payload-envelope]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadenvelope +[validator-registration-v2]: #validatorregistrationv2 +[verify-registration-signature]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#verify_registration_signature diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 323e0b8..7e41ece 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -6,8 +6,14 @@ - [Gloas - Honest Validator](#gloas---honest-validator) - [Introduction](#introduction) + - [Containers](#containers) + - [New Containers](#new-containers) + - [`BidRequestAuth`](#bidrequestauth) + - [`SignedBidRequestAuth`](#signedbidrequestauth) - [Helper](#helper) - [`get_proposer_slots_in_upcoming_epoch`](#get_proposer_slots_in_upcoming_epoch) + - [Bid Authentication](#bid-authentication) + - [Constructing the `BidRequestAuth`](#constructing-the-bidrequestauth) - [Validator Registrations](#validator-registrations) - [Constructing the `ValidatorRegistrationV2`](#constructing-the-validatorregistrationv2) - [Validator Registration dissemination](#validator-registration-dissemination) @@ -25,9 +31,11 @@ This document explains how a beacon-chain validator can participate in the external block building market with the Builder-API post ePBS. -Validators request an `ExecutionPayloadBid` from the external builder network to -put it in their `SignedBeaconBlock`. The external builder network broadcasts the -`SignedExecutionPayloadEnvelope` corresponding to the bid to the PTC committee. +Validators request a [`SignedExecutionPayloadBid`][signed-execution-payload-bid] +from the external builder network to put it in their `SignedBeaconBlock`. The +external builder network broadcasts the +[`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] +corresponding to the bid to the PTC committee. ## Containers @@ -58,6 +66,9 @@ class SignedBidRequestAuth(Container): ### `get_proposer_slots_in_upcoming_epoch` +*Note*: `compute_start_slot_at_epoch` and `get_current_epoch` are defined in the +[Gloas consensus specs][gloas-consensus-specs]. + ```python def get_proposer_slots_in_upcoming_epoch( state: BeaconState, @@ -90,15 +101,16 @@ To construct the `BidRequestAuth`, we need to fill the following information: - `proposal_slot`: The slot at which the proposer is building a block. The validator constructs the `SignedBidRequestAuth` by signing the -`BidRequestAuth`. It sends the `SignedBidRequestAuth` as a header along with the -request to get the bid. +`BidRequestAuth`. It sends the `SignedBidRequestAuth` in the request body along +with the request to get the bid in the +[`getExecutionPayloadBid`][get-execution-payload-bid-api] API call. ## Validator Registrations ### Constructing the `ValidatorRegistrationV2` To do this, the validator client assembles a -\[`ValidatorRegistrationV2`\][validator-registration-v2] with the following +[`ValidatorRegistrationV2`][validator-registration-v2] with the following information: - `fee_recipient`: An execution layer address where fees for the validator @@ -122,25 +134,33 @@ registrations for all the slots they will be proposing in the upcoming epoch. ```python def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_preferences: BuilderPreferences) -> List[ValidatorRegistrationV2]: slots = get_proposer_slots_in_upcoming_epoch(state, validator_index) - registrations: List[ValidatorRegistrationsV2] = [] + registrations: List[ValidatorRegistrationV2] = [] for slot in slots: - registrations.append(ValidatorRegistrationV2( - fee_recipient=fee_recipient, - gas_limit=gas_limit, - validator_index=validator_index - builder_preferences=builder_preferences, - proposal_slot=slot - )) - - return registrations + registrations.append(ValidatorRegistrationV2( + fee_recipient=fee_recipient, + gas_limit=gas_limit, + validator_index=validator_index, + builder_preferences=builder_preferences, + proposal_slot=slot + )) + + return registrations ``` ## Validating a `SignedExecutionPayloadBid` -When the proposer receives a `SignedExecutionPayloadBid` from a builder, it can -validate the bid using `validate_bid`. It can discard the bid if the conditions -are not satisfied. +When the proposer receives a +[`SignedExecutionPayloadBid`][signed-execution-payload-bid] from a builder, it +can validate the bid using `validate_bid`. It can discard the bid if the +conditions are not satisfied. + +*Note*: `hash_tree_root`, `get_randao_mix`, and `get_current_epoch` are defined +in the [Gloas consensus specs][gloas-consensus-specs]. The predicates +[`is_active_builder`][is-active-builder], +[`can_builder_cover_bid`][can-builder-cover-bid], and +[`verify_execution_payload_bid_signature`][verify-execution-payload-bid-signature] +are also defined in the consensus specs. ```python def validate_bid( @@ -170,18 +190,33 @@ def validate_bid( To obtain an execution payload, a block proposer building a block on top of a beacon `state` in a given `slot` must take the following actions: -1. Call upstream builder software to get an `ExecutionPayloadBid`. The validator - is required to send the `SignedBidRequestAuth` in the request body in order - to authenticate the request to the builder. If a builder has multiple builder - indices associated with them, the validator will have to call the upstream - builder software each time for each builder index. +1. Call upstream builder software to get a + [`SignedExecutionPayloadBid`][signed-execution-payload-bid] using the + [`getExecutionPayloadBid`][get-execution-payload-bid-api] API call. The + validator is required to send the `SignedBidRequestAuth` in the request body + in order to authenticate the request to the builder. If a builder has + multiple builder indices associated with them, the validator will have to + call the upstream builder software each time for each builder index. 2. Assemble a `SignedBeaconBlock` according to the process outlined in the - \[Gloas - specs\][https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal] - but with the best `ExecutionPayloadBid` from the prior step. + [Gloas validator specs][gloas-validator-specs] but with the best + [`SignedExecutionPayloadBid`][signed-execution-payload-bid] from the prior + step. 3. The proposer returns the `SignedBeaconBlock` back to the upstream block - building software. + building software via + [`submitSignedBeaconBlock`][submit-signed-beacon-block] API call. 4. The upstream block building software constructs the - `SignedExecutionPayloadEnvelope` from the - `SignedBlindedExecutionPayloadEnvelope` and broadcasts it to the PTC - committee. + [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] + corresponding to the + [`SignedExecutionPayloadBid`][signed-execution-payload-bid] and broadcasts it + to the PTC committee. + +[can-builder-cover-bid]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#can_builder_cover_bid +[get-execution-payload-bid-api]: ./../../apis/builder/execution_payload_bid.yaml +[gloas-consensus-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas +[gloas-validator-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal +[is-active-builder]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#is_active_builder +[submit-signed-beacon-block]: ./../../apis/builder/beacon_block.yaml +[signed-execution-payload-bid]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid +[signed-execution-payload-envelope]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadenvelope +[validator-registration-v2]: ./builder.md#validatorregistrationv2 +[verify-execution-payload-bid-signature]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#verify_execution_payload_bid_signature diff --git a/wordlist.txt b/wordlist.txt index 970e86c..56973e4 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -28,6 +28,11 @@ validator's vc wei EIP +ePBS Fulu fulu -submitBlindedBlockV \ No newline at end of file +Gloas +gloas +PTC +submitBlindedBlockV +ValidatorRegistrationsV \ No newline at end of file From ec5f63fb8c11e26300273fbf607ba6dc91906ec5 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 7 Jan 2026 18:12:49 +0530 Subject: [PATCH 22/31] add some notes --- specs/gloas/builder.md | 28 +++++++++----------------- specs/gloas/validator.md | 43 ++++++++++++++++++++++++++++------------ 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 0267d27..2a28628 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -27,7 +27,7 @@ This document documents the builder behaviour with the Builder-API post ePBS. It describes how builders interact with validators through -[`ValidatorRegistrationV2`][validator-registration-v2] and construct +\[`ValidatorRegistrationV2`\][validator-registration-v2] and construct [`SignedExecutionPayloadBid`][signed-execution-payload-bid] and [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] objects. @@ -81,10 +81,10 @@ In Gloas, Execution payloads are built for a specific `slot`, `parent_hash`, `validator_index` along with the `parent_root` tuple corresponding to a unique beacon block serving as the parent. -This is because in Gloas with [EIP-7732][eip-7732], the execution payload and -beacon blocks are decoupled. The `parent_hash` could refer to a beacon block -which is an ancestor of the parent beacon block corresponding to the current -beacon block for which we are building the execution payload. +This is because in Gloas with [EIP-7732], the execution payload and beacon +blocks are decoupled. The `parent_hash` could refer to a beacon block which is +an ancestor of the parent beacon block corresponding to the current beacon block +for which we are building the execution payload. We update `is_eligible_for_bid` below. *Note*: `hash_tree_root` is defined in the [Gloas consensus specs][gloas-consensus-specs]. @@ -99,14 +99,11 @@ def is_eligible_for_bid(state: BeaconState, # [New in Gloas] validator_index: ValidatorIndex): # Verify slot - if slot != state.slot: - return False + assert slot == state.slot - if validator_index not in state.validators.keys(): - return False + assert validator_index in state.validator.keys() - if validator_index not in registrations: - return False + assert validator_index in registrations.keys() # Verify parent hash # [Modified in Gloas:EIP7732] @@ -148,10 +145,6 @@ The following fields are removed: A `validator_registration_v2` is considered valid if the following function completes without raising any assertions. -*Note*: [`is_eligible_for_registration`][is-eligible-for-registration] and -[`verify_registration_signature`][verify-registration-signature] are defined in -the [Gloas consensus specs][gloas-consensus-specs]. - ```python def process_registration_v2(state: BeaconState, registration: SignedValidatorRegistrationV2, @@ -173,7 +166,7 @@ def process_registration_v2(state: BeaconState, assert registration.proposal_slot >= prev_registration.proposal_slot # Verify registration signature - assert verify_registration_signature(state, registration) + assert verify_registration_v2_signature(state, registration) ``` ## Constructing a `SignedExecutionPayloadBid` @@ -199,8 +192,5 @@ documented in the [Gloas consensus specs][gloas-builder-specs]. [eip-7732]: https://eips.ethereum.org/EIPS/eip-7732 [gloas-builder-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/builder.md [gloas-consensus-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas -[is-eligible-for-registration]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#is_eligible_for_registration [signed-execution-payload-bid]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid [signed-execution-payload-envelope]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadenvelope -[validator-registration-v2]: #validatorregistrationv2 -[verify-registration-signature]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#verify_registration_signature diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 7e41ece..e0cc63b 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -164,23 +164,40 @@ are also defined in the consensus specs. ```python def validate_bid( - state: BeaconState, signed_bid: SignedExecutionPayloadBid, fee_recipient: ExecutionAddress + state: BeaconState, reg: SignedValidatorRegistrationV2, bid: SignedExecutionPayloadBid, bid_request_auth: SignedBidRequestAuth, fee_recipient: ExecutionAddress ) -> bool: - builder = state.builders[signed_bid.builder_index] + bid = bid.message + + assert bid.builder_index == bid_request_auth.message.builder_index + + builder = state.builders[bid.builder_index] assert is_active_builder(state, builder) - assert signed_bid.slot == state.slot - assert signed_bid.fee_recipient == fee_recipient - assert signed_bid.parent_block_hash == state.latest_block_hash - assert signed_bid.parent_block_root == hash_tree_root(state.latest_block_header) - assert signed_bid.prev_randao == get_randao_mix(state, get_current_epoch(state)) + assert bid.slot == state.slot + assert bid.fee_recipient == fee_recipient + assert bid.parent_block_hash == state.latest_block_hash + assert bid.parent_block_root == hash_tree_root(state.latest_block_header) + assert bid.prev_randao == get_randao_mix(state, get_current_epoch(state)) - if signed_bid.value > 0: - assert can_builder_cover_bid(state, signed_bid.builder_index, signed_bid.value) + if not reg.message.builder_preferences.execution_payment_accepted: + assert bid.execution_payment == 0 - return verify_execution_payload_bid_signature(state, signed_bid) + if bid.value > 0: + assert can_builder_cover_bid(state, bid.builder_index, signed_bid.value) + + return verify_execution_payload_bid_signature(state, bid) ``` +Note that, the fee recipient specified in `bid.fee_recipient` does not +necessarily correspond to the fee recipient of the execution payload. Even if a +builder pays the validator via execution layer payments, we require that the +bid's fee recipient matches the validators expected fee recipient and not the +builder's fee recipient. + +To express per-builder preferences we need validators to remember which +registration they have sent to the builder, so that they can validate whether +the bid conforms to the preferences expressed by the validators. + ## Block proposal ### Constructing the `BeaconBlockBody` @@ -202,8 +219,8 @@ beacon `state` in a given `slot` must take the following actions: [`SignedExecutionPayloadBid`][signed-execution-payload-bid] from the prior step. 3. The proposer returns the `SignedBeaconBlock` back to the upstream block - building software via - [`submitSignedBeaconBlock`][submit-signed-beacon-block] API call. + building software via [`submitSignedBeaconBlock`][submit-signed-beacon-block] + API call. 4. The upstream block building software constructs the [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] corresponding to the @@ -215,8 +232,8 @@ beacon `state` in a given `slot` must take the following actions: [gloas-consensus-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas [gloas-validator-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/validator.md#block-proposal [is-active-builder]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#is_active_builder -[submit-signed-beacon-block]: ./../../apis/builder/beacon_block.yaml [signed-execution-payload-bid]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid [signed-execution-payload-envelope]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadenvelope +[submit-signed-beacon-block]: ./../../apis/builder/beacon_block.yaml [validator-registration-v2]: ./builder.md#validatorregistrationv2 [verify-execution-payload-bid-signature]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#verify_execution_payload_bid_signature From 2ee40cdc161bf34935c75b1160e1a237955fee16 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 7 Jan 2026 22:19:15 +0530 Subject: [PATCH 23/31] fix return type of execution_payload_bid.yaml --- apis/builder/execution_payload_bid.yaml | 4 ++-- specs/gloas/builder.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index 0578d64..2b9441e 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -98,10 +98,10 @@ post: enum: [ gloas ] example: "gloas" data: - $ref: "../../beacon-apis/types/gloas/execution_payload_bid.yaml#/Gloas/ExecutionPayloadBid" + $ref: "../../beacon-apis/types/gloas/execution_payload_bid.yaml#/Gloas/SignedExecutionPayloadBid" application/octet-stream: schema: - description: "SSZ serialized `ExecutionPayloadBid` bytes. Use Accept header to choose this response type" + description: "SSZ serialized `SignedExecutionPayloadBid` bytes. Use Accept header to choose this response type" "204": description: No bid is available. "400": diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 2a28628..6aa1c80 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -161,7 +161,7 @@ def process_registration_v2(state: BeaconState, assert is_eligible_for_registration(state, validator) # Verify that the old registration's proposal slot is earlier than the new registration's proposal slot - if validator_index in registrations: + if validator_index in registrations.keys(): prev_registration = registrations[validator_index] assert registration.proposal_slot >= prev_registration.proposal_slot From 104cd7deffefc981d06af9e2ed8e9d577b6a3054 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Wed, 7 Jan 2026 23:12:18 +0530 Subject: [PATCH 24/31] use max_trusted_bid in builder preferences --- specs/gloas/builder.md | 12 ++++++++---- specs/gloas/validator.md | 7 +++---- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 6aa1c80..178cda3 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -39,7 +39,7 @@ describes how builders interact with validators through ```python class BuilderPreferences(Container): - execution_payment_accepted: boolean + max_trusted_bid: uint64 ``` #### `ValidatorRegistrationV2` @@ -119,9 +119,13 @@ def is_eligible_for_bid(state: BeaconState, Using validator registrations, a proposer can express the preferences it has for a builder. Currently, the only preference that is supported is: -- `execution_payment_accepted`: This is a boolean which indicates that the - proposer is willing to accept a trusted execution layer payment from the - builder. +- `max_trusted_bid`: Specifies the maximum value (in Gwei) that a proposer is + willing to accept as a trusted execution layer payment from the builder. A + value of `0` indicates that the proposer does not accept any trusted payments + from the builder, requiring all payments to be cryptographically verifiable + on-chain. A value of `UINT64_MAX` indicates that the proposer will accept any + trusted payment amount from the builder. Proposers may adjust this parameter + based on their level of trust in the builder's reliability and reputation. ## Validator Registration V2 diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index e0cc63b..f8b3e1b 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -118,8 +118,8 @@ information: - `gas_limit`: The value a validator prefers for the execution block gas limit. - `validator_index`: The validator's index. Used to identify the beacon chain validator and verify the wrapping signature. -- `execution_payment_accepted`: Whether the proposer is willing to accept a - trusted payment from the builder with index `builder_index`. +- `max_trusted_bid`: The amount(in Gwei) the proposer is willing to accept as a + trusted execution layer payment from the builder. - `proposal_slot`: This is set to the slot in which the validator will be proposing. This can be looked up in `state.proposal_lookahead`. @@ -179,8 +179,7 @@ def validate_bid( assert bid.parent_block_root == hash_tree_root(state.latest_block_header) assert bid.prev_randao == get_randao_mix(state, get_current_epoch(state)) - if not reg.message.builder_preferences.execution_payment_accepted: - assert bid.execution_payment == 0 + assert bid.execution_payment <= reg.message.builder_preferences.max_trusted_bid if bid.value > 0: assert can_builder_cover_bid(state, bid.builder_index, signed_bid.value) From aef010da70d43a7f7a1911c21202a2fb1d99cb66 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 8 Jan 2026 10:48:55 +0530 Subject: [PATCH 25/31] run linter --- specs/gloas/builder.md | 36 ++++++++++++++------------ specs/gloas/validator.md | 56 +++++++++++++++++++++++----------------- 2 files changed, 52 insertions(+), 40 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 178cda3..5b4acaf 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -2,8 +2,6 @@ - - - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) - [Containers](#containers) @@ -67,7 +65,9 @@ class SignedValidatorRegistrationV2(Container): [Gloas consensus specs][gloas-consensus-specs]. ```python -def verify_registration_v2_signature(state: BeaconState, signed_registration: SignedValidatorRegistrationV2) -> bool: +def verify_registration_v2_signature( + state: BeaconState, signed_registration: SignedValidatorRegistrationV2 +) -> bool: validator = state.validators[signed_registration.message.validator_index] pubkey = validator.pubkey domain = compute_domain(DOMAIN_APPLICATION_BUILDER) @@ -90,14 +90,16 @@ We update `is_eligible_for_bid` below. *Note*: `hash_tree_root` is defined in the [Gloas consensus specs][gloas-consensus-specs]. ```python -def is_eligible_for_bid(state: BeaconState, - registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], - slot: Slot, - parent_hash: Hash32, - # [New in Gloas] - parent_root: Root, - # [New in Gloas] - validator_index: ValidatorIndex): +def is_eligible_for_bid( + state: BeaconState, + registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], + slot: Slot, + parent_hash: Hash32, + # [New in Gloas] + parent_root: Root, + # [New in Gloas] + validator_index: ValidatorIndex, +): # Verify slot assert slot == state.slot @@ -150,10 +152,12 @@ A `validator_registration_v2` is considered valid if the following function completes without raising any assertions. ```python -def process_registration_v2(state: BeaconState, - registration: SignedValidatorRegistrationV2, - registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], - current_timestamp: uint64): +def process_registration_v2( + state: BeaconState, + registration: SignedValidatorRegistrationV2, + registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], + current_timestamp: uint64, +): signature = registration.signature registration = registration.message validator_index = registration.validator_index @@ -182,7 +186,7 @@ The specification for a block builder to construct a ## Constructing a `SignedExecutionPayloadEnvelope` If the builder's [`SignedExecutionPayloadBid`][signed-execution-payload-bid] has -been accepted by the proposer and it has been included in it's +been accepted by the proposer and it has been included in the `SignedBeaconBlock`, then the builder has to construct a [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] corresponding to the [`SignedExecutionPayloadBid`][signed-execution-payload-bid] diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index f8b3e1b..df0217f 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -2,8 +2,6 @@ - - - [Gloas - Honest Validator](#gloas---honest-validator) - [Introduction](#introduction) - [Containers](#containers) @@ -44,22 +42,22 @@ corresponding to the bid to the PTC committee. #### `BidRequestAuth` `BidRequestAuth` is used to authenticate requests to get the bid from a builder. -This is useful so that other builders don't DDOS the builder to get their latest -bid. +This is useful so that other builders do not DDOS the builder to get their +latest bid. ```python class BidRequestAuth(Container): - builder_index: BuilderIndex - validator_index: ValidatorIndex - proposer_slot: Slot + builder_index: BuilderIndex + validator_index: ValidatorIndex + proposer_slot: Slot ``` #### `SignedBidRequestAuth` ```python class SignedBidRequestAuth(Container): - message: BidRequestAuth - signature: BLSSignature + message: BidRequestAuth + signature: BLSSignature ``` ## Helper @@ -71,8 +69,7 @@ class SignedBidRequestAuth(Container): ```python def get_proposer_slots_in_upcoming_epoch( - state: BeaconState, - validator_index: ValidatorIndex + state: BeaconState, validator_index: ValidatorIndex ) -> List[Slot]: """ Return all slots where validator_index is the proposer within the lookahead window in the next epoch. @@ -80,12 +77,12 @@ def get_proposer_slots_in_upcoming_epoch( proposer_slots = [] current_epoch_start_slot = compute_start_slot_at_epoch(get_current_epoch(state)) next_epoch_proposer_lookahead = state.proposer_lookahead[SLOTS_PER_EPOCH:] - + for offset, proposer_index in enumerate(next_epoch_proposer_lookahead): if proposer_index == validator_index: slot = current_epoch_start_slot + SLOTS_PER_EPOCH + offset proposer_slots.append(slot) - + return proposer_slots ``` @@ -126,24 +123,31 @@ information: ### Validator Registration dissemination This specification suggests validators re-submit registrations only if they will -be proposing in the upcoming epoch(E+1). This is such that we don't send too +be proposing in the upcoming epoch(E+1). This is such that we do not send too many validator registrations all at once to builders. Validators run `create_validator_registrations` at every epoch boundary to create validator registrations for all the slots they will be proposing in the upcoming epoch. ```python -def create_validator_registrations(state: BeaconState, validator_index: ValidatorIndex, gas_limit: uint64, builder_preferences: BuilderPreferences) -> List[ValidatorRegistrationV2]: +def create_validator_registrations( + state: BeaconState, + validator_index: ValidatorIndex, + gas_limit: uint64, + builder_preferences: BuilderPreferences, +) -> List[ValidatorRegistrationV2]: slots = get_proposer_slots_in_upcoming_epoch(state, validator_index) registrations: List[ValidatorRegistrationV2] = [] for slot in slots: - registrations.append(ValidatorRegistrationV2( - fee_recipient=fee_recipient, - gas_limit=gas_limit, - validator_index=validator_index, - builder_preferences=builder_preferences, - proposal_slot=slot - )) + registrations.append( + ValidatorRegistrationV2( + fee_recipient=fee_recipient, + gas_limit=gas_limit, + validator_index=validator_index, + builder_preferences=builder_preferences, + proposal_slot=slot, + ) + ) return registrations ``` @@ -164,14 +168,18 @@ are also defined in the consensus specs. ```python def validate_bid( - state: BeaconState, reg: SignedValidatorRegistrationV2, bid: SignedExecutionPayloadBid, bid_request_auth: SignedBidRequestAuth, fee_recipient: ExecutionAddress + state: BeaconState, + reg: SignedValidatorRegistrationV2, + bid: SignedExecutionPayloadBid, + bid_request_auth: SignedBidRequestAuth, + fee_recipient: ExecutionAddress, ) -> bool: bid = bid.message assert bid.builder_index == bid_request_auth.message.builder_index builder = state.builders[bid.builder_index] - + assert is_active_builder(state, builder) assert bid.slot == state.slot assert bid.fee_recipient == fee_recipient From ef1ffcec543fd17967c8b0c35c4b07a593b11de0 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 8 Jan 2026 10:51:34 +0530 Subject: [PATCH 26/31] fix spellchecker --- wordlist.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/wordlist.txt b/wordlist.txt index 56973e4..353ab83 100644 --- a/wordlist.txt +++ b/wordlist.txt @@ -33,6 +33,7 @@ Fulu fulu Gloas gloas +Gwei PTC submitBlindedBlockV ValidatorRegistrationsV \ No newline at end of file From e988c62d5d1c6aff7a64b9659d7393d54ce1d8af Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 8 Jan 2026 12:36:34 +0530 Subject: [PATCH 27/31] update bid request auth according to feedback --- specs/gloas/builder.md | 13 ++++++++++--- specs/gloas/validator.md | 14 +++++++++----- types/gloas/bid_request_auth.yaml | 15 +++++---------- 3 files changed, 24 insertions(+), 18 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 5b4acaf..7dfef92 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -4,6 +4,7 @@ - [Gloas - Builder Specification](#gloas---builder-specification) - [Introduction](#introduction) + - [Constants](#constants) - [Containers](#containers) - [New Containers](#new-containers) - [`BuilderPreferences`](#builderpreferences) @@ -29,6 +30,11 @@ describes how builders interact with validators through [`SignedExecutionPayloadBid`][signed-execution-payload-bid] and [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] objects. +## Constants + +| Name | Value | | ---------------------------- | -------------------| | +`MAX_TRUSTED_BID` | `uint64('2**64-1')`| + ## Containers ### New Containers @@ -125,9 +131,10 @@ a builder. Currently, the only preference that is supported is: willing to accept as a trusted execution layer payment from the builder. A value of `0` indicates that the proposer does not accept any trusted payments from the builder, requiring all payments to be cryptographically verifiable - on-chain. A value of `UINT64_MAX` indicates that the proposer will accept any - trusted payment amount from the builder. Proposers may adjust this parameter - based on their level of trust in the builder's reliability and reputation. + on-chain. A value of `MAX_TRUSTED_BID` indicates that the proposer will accept + any trusted payment amount from the builder. Proposers may adjust this + parameter based on their level of trust in the builder's reliability and + reputation. ## Validator Registration V2 diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index df0217f..d0e2174 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -4,6 +4,7 @@ - [Gloas - Honest Validator](#gloas---honest-validator) - [Introduction](#introduction) + - [Constants](#constants) - [Containers](#containers) - [New Containers](#new-containers) - [`BidRequestAuth`](#bidrequestauth) @@ -35,6 +36,11 @@ external builder network broadcasts the [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] corresponding to the bid to the PTC committee. +## Constants + +| Name | Value | | -------------------------------- | -------------------| | +`MAX_BUILDER_INDICES` | `uint64('2**64-1')`| + ## Containers ### New Containers @@ -47,9 +53,7 @@ latest bid. ```python class BidRequestAuth(Container): - builder_index: BuilderIndex - validator_index: ValidatorIndex - proposer_slot: Slot + builder_indices: List[BuilderIndex, MAX_BUILDER_INDICES] ``` #### `SignedBidRequestAuth` @@ -176,7 +180,7 @@ def validate_bid( ) -> bool: bid = bid.message - assert bid.builder_index == bid_request_auth.message.builder_index + assert bid.builder_index in bid_request_auth.message.builder_indices builder = state.builders[bid.builder_index] @@ -190,7 +194,7 @@ def validate_bid( assert bid.execution_payment <= reg.message.builder_preferences.max_trusted_bid if bid.value > 0: - assert can_builder_cover_bid(state, bid.builder_index, signed_bid.value) + assert can_builder_cover_bid(state, bid.builder_index, bid.value) return verify_execution_payload_bid_signature(state, bid) ``` diff --git a/types/gloas/bid_request_auth.yaml b/types/gloas/bid_request_auth.yaml index 4053307..a640113 100644 --- a/types/gloas/bid_request_auth.yaml +++ b/types/gloas/bid_request_auth.yaml @@ -1,17 +1,12 @@ Gloas: BidRequestAuth: type: object - required: [builder_index, validator_index, proposal_slot] + required: [builder_indices] properties: - builder_index: - $ref: "../../builder-oapi.yaml#/components/schemas/Uint64" - description: "The index of the builder to which the validator is sending the request." - validator_index: - $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" - description: "The index of the validator that is sending the request." - proposal_slot: - $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" - description: "The slot at which the proposer is building a block." + builder_indices: + type: array + items: + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" SignedBidRequestAuth: type: object required: [message, signature] From fbaeee56d7bb7a370766d917389f3ed158519304 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Thu, 8 Jan 2026 21:15:31 +0530 Subject: [PATCH 28/31] minor updates --- apis/builder/execution_payload_bid.yaml | 4 ++-- specs/gloas/builder.md | 17 +++++++++-------- specs/gloas/validator.md | 24 +++++++++++------------- types/gloas/registration.yaml | 8 ++++---- 4 files changed, 26 insertions(+), 27 deletions(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index 2b9441e..c14a687 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -63,8 +63,8 @@ post: required: false description: | Optional header containing the proposer's timeout for the request in milliseconds. - Builders should use this header to adjust the amount of time by which they delay getBid - requests to maximise block rewards. Otherwise, getExecutionPayloadBid requests will timeout and the proposer + Builders should use this header to adjust the amount of time by which they delay the + requests to maximise block rewards. Otherwise, requests will timeout and the proposer will not receive the header in time. schema: type: integer diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 7dfef92..8641a4f 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -26,14 +26,14 @@ This document documents the builder behaviour with the Builder-API post ePBS. It describes how builders interact with validators through -\[`ValidatorRegistrationV2`\][validator-registration-v2] and construct +[`ValidatorRegistrationV2`][validator-registration-v2] and construct [`SignedExecutionPayloadBid`][signed-execution-payload-bid] and [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] objects. ## Constants | Name | Value | | ---------------------------- | -------------------| | -`MAX_TRUSTED_BID` | `uint64('2**64-1')`| +`MAX_TRUSTED_BID` | `2**64 - 1`| ## Containers @@ -109,7 +109,7 @@ def is_eligible_for_bid( # Verify slot assert slot == state.slot - assert validator_index in state.validator.keys() + assert validator_index in state.validators.keys() assert validator_index in registrations.keys() @@ -161,12 +161,12 @@ completes without raising any assertions. ```python def process_registration_v2( state: BeaconState, - registration: SignedValidatorRegistrationV2, + signed_registration: SignedValidatorRegistrationV2, registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], current_timestamp: uint64, ): - signature = registration.signature - registration = registration.message + signature = signed_registration.signature + registration = signed_registration.message validator_index = registration.validator_index proposal_slot = registration.proposal_slot @@ -181,7 +181,7 @@ def process_registration_v2( assert registration.proposal_slot >= prev_registration.proposal_slot # Verify registration signature - assert verify_registration_v2_signature(state, registration) + assert verify_registration_v2_signature(state, signed_registration) ``` ## Constructing a `SignedExecutionPayloadBid` @@ -193,7 +193,7 @@ The specification for a block builder to construct a ## Constructing a `SignedExecutionPayloadEnvelope` If the builder's [`SignedExecutionPayloadBid`][signed-execution-payload-bid] has -been accepted by the proposer and it has been included in the +been accepted by the proposer and it has been included in its `SignedBeaconBlock`, then the builder has to construct a [`SignedExecutionPayloadEnvelope`][signed-execution-payload-envelope] corresponding to the [`SignedExecutionPayloadBid`][signed-execution-payload-bid] @@ -209,3 +209,4 @@ documented in the [Gloas consensus specs][gloas-builder-specs]. [gloas-consensus-specs]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas [signed-execution-payload-bid]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadbid [signed-execution-payload-envelope]: https://github.com/ethereum/consensus-specs/blob/master/specs/gloas/beacon-chain.md#signedexecutionpayloadenvelope +[validator-registration-v2]: #validatorregistrationv2 diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index d0e2174..6d38f99 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -39,7 +39,7 @@ corresponding to the bid to the PTC committee. ## Constants | Name | Value | | -------------------------------- | -------------------| | -`MAX_BUILDER_INDICES` | `uint64('2**64-1')`| +`MAX_BUILDER_INDICES` | `2**64 - 1`| ## Containers @@ -96,10 +96,9 @@ def get_proposer_slots_in_upcoming_epoch( To construct the `BidRequestAuth`, we need to fill the following information: -- `builder_index`: This builder index for which the validator is sending a - request to get the bid. -- `validator_index`: The proposer's validator index. -- `proposal_slot`: The slot at which the proposer is building a block. +- `builder_indices`: These are the builder indices corresponding to the builder + from whom we are fetching the bid. These indices will be known by the + validators when they whitelist the builder. The validator constructs the `SignedBidRequestAuth` by signing the `BidRequestAuth`. It sends the `SignedBidRequestAuth` in the request body along @@ -138,6 +137,7 @@ def create_validator_registrations( validator_index: ValidatorIndex, gas_limit: uint64, builder_preferences: BuilderPreferences, + fee_recipient: ExecutionAddress, ) -> List[ValidatorRegistrationV2]: slots = get_proposer_slots_in_upcoming_epoch(state, validator_index) registrations: List[ValidatorRegistrationV2] = [] @@ -174,11 +174,11 @@ are also defined in the consensus specs. def validate_bid( state: BeaconState, reg: SignedValidatorRegistrationV2, - bid: SignedExecutionPayloadBid, + signed_bid: SignedExecutionPayloadBid, bid_request_auth: SignedBidRequestAuth, fee_recipient: ExecutionAddress, ) -> bool: - bid = bid.message + bid = signed_bid.message assert bid.builder_index in bid_request_auth.message.builder_indices @@ -196,7 +196,7 @@ def validate_bid( if bid.value > 0: assert can_builder_cover_bid(state, bid.builder_index, bid.value) - return verify_execution_payload_bid_signature(state, bid) + return verify_execution_payload_bid_signature(state, signed_bid) ``` Note that, the fee recipient specified in `bid.fee_recipient` does not @@ -215,16 +215,14 @@ the bid conforms to the preferences expressed by the validators. #### Receiving ExecutionPayloadBid -To obtain an execution payload, a block proposer building a block on top of a -beacon `state` in a given `slot` must take the following actions: +To obtain execution payloads for a given `slot`, a block proposer building a +block on top of a beacon `state` must take the following actions: 1. Call upstream builder software to get a [`SignedExecutionPayloadBid`][signed-execution-payload-bid] using the [`getExecutionPayloadBid`][get-execution-payload-bid-api] API call. The validator is required to send the `SignedBidRequestAuth` in the request body - in order to authenticate the request to the builder. If a builder has - multiple builder indices associated with them, the validator will have to - call the upstream builder software each time for each builder index. + in order to authenticate the request to the builder. 2. Assemble a `SignedBeaconBlock` according to the process outlined in the [Gloas validator specs][gloas-validator-specs] but with the best [`SignedExecutionPayloadBid`][signed-execution-payload-bid] from the prior diff --git a/types/gloas/registration.yaml b/types/gloas/registration.yaml index 1135975..b0d46f4 100644 --- a/types/gloas/registration.yaml +++ b/types/gloas/registration.yaml @@ -2,11 +2,11 @@ Gloas: BuilderPreferences: type: object description: "Per-builder preferences that a validator can express." - required: [execution_payment_accepted] + required: [max_trusted_bid] properties: - execution_payment_accepted: - type: boolean - description: "Indicates that the proposer is willing to accept a trusted execution layer payment from the builder." + max_trusted_bid: + $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" + description: "Indicates the maximum amount that a proposer is willing to accept as a trusted payment amount from the builder." ValidatorRegistrationV2: type: object description: "The `ValidatorRegistrationV2` object for Gloas fork, replacing pubkey and timestamp with validator_index, proposal_slot, and builder_preferences." From 0cd43992adbecc879a7dc8057bd938751922b7e2 Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Fri, 9 Jan 2026 13:36:58 +0530 Subject: [PATCH 29/31] use a salt in the bid request auth --- apis/builder/execution_payload_bid.yaml | 3 ++- specs/gloas/builder.md | 3 +-- specs/gloas/validator.md | 13 +++++-------- types/gloas/bid_request_auth.yaml | 10 +++++----- 4 files changed, 13 insertions(+), 16 deletions(-) diff --git a/apis/builder/execution_payload_bid.yaml b/apis/builder/execution_payload_bid.yaml index c14a687..15dd90e 100644 --- a/apis/builder/execution_payload_bid.yaml +++ b/apis/builder/execution_payload_bid.yaml @@ -10,7 +10,8 @@ post: - The hash of the execution layer block the proposer will build on. - The root of the beacon block the proposer will build on. - The index of the proposer. - - A signed bid request auth to authenticate the request to a specific builder index. + - A signed bid request auth using a builder-specific salt to authenticate the request. Proposers are required + to set the salt to the URL provided by the whitelisted builder. The builder responds with a 200 response containing an execution payload bid if it can provide one. diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index 8641a4f..a8b8bda 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -33,7 +33,7 @@ describes how builders interact with validators through ## Constants | Name | Value | | ---------------------------- | -------------------| | -`MAX_TRUSTED_BID` | `2**64 - 1`| +`MAX_TRUSTED_BID` | `2**64 - 1` | ## Containers @@ -163,7 +163,6 @@ def process_registration_v2( state: BeaconState, signed_registration: SignedValidatorRegistrationV2, registrations: Dict[ValidatorIndex, ValidatorRegistrationV2], - current_timestamp: uint64, ): signature = signed_registration.signature registration = signed_registration.message diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 6d38f99..34e9f2b 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -39,7 +39,7 @@ corresponding to the bid to the PTC committee. ## Constants | Name | Value | | -------------------------------- | -------------------| | -`MAX_BUILDER_INDICES` | `2**64 - 1`| +`MAX_SALT_BYTES` | `4096` | ## Containers @@ -53,7 +53,7 @@ latest bid. ```python class BidRequestAuth(Container): - builder_indices: List[BuilderIndex, MAX_BUILDER_INDICES] + salt: ByteList[MAX_SALT_BYTES] ``` #### `SignedBidRequestAuth` @@ -96,9 +96,9 @@ def get_proposer_slots_in_upcoming_epoch( To construct the `BidRequestAuth`, we need to fill the following information: -- `builder_indices`: These are the builder indices corresponding to the builder - from whom we are fetching the bid. These indices will be known by the - validators when they whitelist the builder. +- `salt`: This is a 4kB salt which has to be specific to each whitelisted + builder. The spec requires the proposer to set it to the URL provided by the + whitelisted builder. The validator constructs the `SignedBidRequestAuth` by signing the `BidRequestAuth`. It sends the `SignedBidRequestAuth` in the request body along @@ -175,13 +175,10 @@ def validate_bid( state: BeaconState, reg: SignedValidatorRegistrationV2, signed_bid: SignedExecutionPayloadBid, - bid_request_auth: SignedBidRequestAuth, fee_recipient: ExecutionAddress, ) -> bool: bid = signed_bid.message - assert bid.builder_index in bid_request_auth.message.builder_indices - builder = state.builders[bid.builder_index] assert is_active_builder(state, builder) diff --git a/types/gloas/bid_request_auth.yaml b/types/gloas/bid_request_auth.yaml index a640113..0393bcd 100644 --- a/types/gloas/bid_request_auth.yaml +++ b/types/gloas/bid_request_auth.yaml @@ -1,12 +1,12 @@ Gloas: BidRequestAuth: type: object - required: [builder_indices] + required: [salt] properties: - builder_indices: - type: array - items: - $ref: "../../beacon-apis/types/primitive.yaml#/Uint64" + salt: + type: string + maxLength: 4096 + description: "A builder-specific salt (max 4096 bytes) used to authenticate bid requests. Must be set to the URL provided by the whitelisted builder." SignedBidRequestAuth: type: object required: [message, signature] From b299c3439ac4a66d2f9d6d8c8d011fbe857caaeb Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Fri, 9 Jan 2026 13:56:05 +0530 Subject: [PATCH 30/31] correctly render constants table --- specs/gloas/builder.md | 6 +++--- specs/gloas/validator.md | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index a8b8bda..da013da 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -1,5 +1,4 @@ - - [Gloas - Builder Specification](#gloas---builder-specification) @@ -32,8 +31,9 @@ describes how builders interact with validators through ## Constants -| Name | Value | | ---------------------------- | -------------------| | -`MAX_TRUSTED_BID` | `2**64 - 1` | +| Name | Value | +| ----------------------------------------- | ------------------ | +| `MAX_TRUSTED_BID` | `2**64 - 1` | ## Containers diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 34e9f2b..0461cf2 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -38,8 +38,9 @@ corresponding to the bid to the PTC committee. ## Constants -| Name | Value | | -------------------------------- | -------------------| | -`MAX_SALT_BYTES` | `4096` | +| Name | Value | +| ----------------------------------------- | ------------------ | +| `MAX_SALT_BYTES` | `4096` | ## Containers From d7bf68f56de7cc1d60acd426f94a5610b5e64f4f Mon Sep 17 00:00:00 2001 From: Bharath Vedartham Date: Fri, 9 Jan 2026 22:40:20 +0530 Subject: [PATCH 31/31] address feedback --- specs/gloas/validator.md | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 0461cf2..57e0ee0 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -122,7 +122,7 @@ information: - `max_trusted_bid`: The amount(in Gwei) the proposer is willing to accept as a trusted execution layer payment from the builder. - `proposal_slot`: This is set to the slot in which the validator will be - proposing. This can be looked up in `state.proposal_lookahead`. + proposing. This can be looked up in `state.proposer_lookahead`. ### Validator Registration dissemination @@ -180,14 +180,13 @@ def validate_bid( ) -> bool: bid = signed_bid.message - builder = state.builders[bid.builder_index] - - assert is_active_builder(state, builder) + assert is_active_builder(state, bid.builder_index) assert bid.slot == state.slot assert bid.fee_recipient == fee_recipient assert bid.parent_block_hash == state.latest_block_hash assert bid.parent_block_root == hash_tree_root(state.latest_block_header) assert bid.prev_randao == get_randao_mix(state, get_current_epoch(state)) + assert bid.gas_limit <= reg.message.gas_limit assert bid.execution_payment <= reg.message.builder_preferences.max_trusted_bid