From 60e2e446e78367a1523a6362248edd3ccad832f1 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Fri, 12 Jun 2026 13:16:14 +0200 Subject: [PATCH 1/3] Reject bids with invalid prev_randao during gossip validation `prev_randao` is deterministic for `parent_block_root`, and the state transition function only allows bids with the correct `prev_randao`. However, gossip rules ignore `prev_randao` and conflate them into a pool keyed by `(bid.slot, bid.parent_block_hash, bid.parent_block_root)`. So, someone who just sends a large bid with wrong `prev_randao` will force smaller bids with correct `prev_randao` to be ignored by spec, while also not allowing inclusion of their bid, i.e., it's unchargeable. Add reject rule to filter incorrect `prev_randao`, the value is known because the rules already require `bid.parent_block_root` to be known in fork choice. Also sync the other missing beacon-chain.md rules to validator.md. --- specs/gloas/builder.md | 4 +++- specs/gloas/p2p-interface.md | 6 ++++-- specs/gloas/validator.md | 11 +++++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/specs/gloas/builder.md b/specs/gloas/builder.md index af465eede42..46863cd4dd4 100644 --- a/specs/gloas/builder.md +++ b/specs/gloas/builder.md @@ -115,7 +115,9 @@ to include. They produce a `SignedExecutionPayloadBid` as follows. 04. Set `bid.block_hash` to be the block hash of the constructed payload, that is `payload.block_hash`. 05. Set `bid.prev_randao` to be the previous RANDAO of the constructed payload, - that is `payload.prev_randao`. + that is `payload.prev_randao`. This value **MUST** equal + `get_randao_mix(parent_state, get_current_epoch(parent_state))`, where + `parent_state` is the post-state of `bid.parent_block_root`. 06. Set `bid.fee_recipient` to be an execution address to receive the payment. The proposer's preferred fee recipient is obtained from the `SignedProposerPreferences` whose `message.proposal_slot` matches `bid.slot` diff --git a/specs/gloas/p2p-interface.md b/specs/gloas/p2p-interface.md index 1a21cfcd418..696a6eb3acb 100644 --- a/specs/gloas/p2p-interface.md +++ b/specs/gloas/p2p-interface.md @@ -390,6 +390,8 @@ where `parent_state` is the post-state of `bid.parent_block_root`, and the alias - _[REJECT]_ The bid is for a higher slot than its parent block -- i.e. validate that `bid.slot` is greater than the slot of the block with root `bid.parent_block_root`. +- _[REJECT]_ `bid.prev_randao` is the correct RANDAO mix -- i.e. validate that + `bid.prev_randao == get_randao_mix(parent_state, get_current_epoch(parent_state))`. - _[REJECT]_ `signed_execution_payload_bid.signature` is valid with respect to the `bid.builder_index`. @@ -415,8 +417,8 @@ def is_gas_limit_target_compatible( *Note*: Implementations SHOULD include DoS prevention measures to mitigate spam from malicious builders submitting numerous bids with minimal value increments. Possible strategies include: (1) only forwarding bids that exceed the current -highest bid by a minimum threshold, or (2) forwarding only the highest observed -bid at regular time intervals. +highest bid passing all validations by a minimum threshold, or (2) forwarding +only the highest such bid at regular time intervals. ###### `proposer_preferences` diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index 87f907618c8..fcc8d1c8d3e 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -195,19 +195,26 @@ top of a `state` MUST take the following actions in order to construct the `signed_execution_payload_bid` from a builder. The block proposer MAY obtain these signed messages by other off-protocol means. - The `signed_execution_payload_bid` MUST satisfy the verification conditions - found in `process_execution_payload_bid` with the alias - `bid = signed_execution_payload_bid.message`, that is: + found in + [`process_execution_payload_bid`](./beacon-chain.md#new-process_execution_payload_bid) + with the alias `bid = signed_execution_payload_bid.message`, that is: - For external builders, the signature MUST be valid. + - For external builders, `bid.builder_index` MUST be a valid/active builder + index -- i.e. `is_active_builder(state, bid.builder_index)` returns `True`. - For self-builds, set `bid.builder_index` to `BUILDER_INDEX_SELF_BUILD`. - For self-builds, the signature MUST be `bls.G2_POINT_AT_INFINITY` and the `bid.value` MUST be zero. - The builder balance can cover the `bid.value`. + - The length of `bid.blob_kzg_commitments` is less than or equal to + `get_blob_parameters(get_current_epoch(state)).max_blobs_per_block`. - The `bid.slot` is for the proposal block slot. - The `bid.parent_block_hash` equals `state.latest_execution_payload_bid.block_hash` if `should_build_on_full(store, head)` is true, otherwise `state.latest_execution_payload_bid.parent_block_hash`. - The `bid.parent_block_root` equals the current block's `parent_root`. + - The `bid.prev_randao` equals + `get_randao_mix(state, get_current_epoch(state))`. - Select one bid and set `block.body.signed_execution_payload_bid = signed_execution_payload_bid`. From f9db2f4473f4568f47f7b2d2ef771ef9b4617eca Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 15 Jun 2026 10:01:12 +0200 Subject: [PATCH 2/3] Fix implied --- specs/gloas/p2p-interface.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/specs/gloas/p2p-interface.md b/specs/gloas/p2p-interface.md index 696a6eb3acb..0fdddbfcd56 100644 --- a/specs/gloas/p2p-interface.md +++ b/specs/gloas/p2p-interface.md @@ -417,8 +417,8 @@ def is_gas_limit_target_compatible( *Note*: Implementations SHOULD include DoS prevention measures to mitigate spam from malicious builders submitting numerous bids with minimal value increments. Possible strategies include: (1) only forwarding bids that exceed the current -highest bid passing all validations by a minimum threshold, or (2) forwarding -only the highest such bid at regular time intervals. +highest bid by a minimum threshold, or (2) forwarding only the highest observed +bid at regular time intervals. ###### `proposer_preferences` From 52a86cb2d99cdf58525ffa389ac0b5eeea0fb629 Mon Sep 17 00:00:00 2001 From: Etan Kissling Date: Mon, 15 Jun 2026 13:56:03 +0200 Subject: [PATCH 3/3] Just the Randao addition --- specs/gloas/validator.md | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/specs/gloas/validator.md b/specs/gloas/validator.md index fcc8d1c8d3e..7b1d6bd6b50 100644 --- a/specs/gloas/validator.md +++ b/specs/gloas/validator.md @@ -195,18 +195,13 @@ top of a `state` MUST take the following actions in order to construct the `signed_execution_payload_bid` from a builder. The block proposer MAY obtain these signed messages by other off-protocol means. - The `signed_execution_payload_bid` MUST satisfy the verification conditions - found in - [`process_execution_payload_bid`](./beacon-chain.md#new-process_execution_payload_bid) - with the alias `bid = signed_execution_payload_bid.message`, that is: + found in `process_execution_payload_bid` with the alias + `bid = signed_execution_payload_bid.message`, that is: - For external builders, the signature MUST be valid. - - For external builders, `bid.builder_index` MUST be a valid/active builder - index -- i.e. `is_active_builder(state, bid.builder_index)` returns `True`. - For self-builds, set `bid.builder_index` to `BUILDER_INDEX_SELF_BUILD`. - For self-builds, the signature MUST be `bls.G2_POINT_AT_INFINITY` and the `bid.value` MUST be zero. - The builder balance can cover the `bid.value`. - - The length of `bid.blob_kzg_commitments` is less than or equal to - `get_blob_parameters(get_current_epoch(state)).max_blobs_per_block`. - The `bid.slot` is for the proposal block slot. - The `bid.parent_block_hash` equals `state.latest_execution_payload_bid.block_hash` if