Skip to content

Add Gloas bid inclusion#9221

Merged
mergify[bot] merged 8 commits intosigp:unstablefrom
dapplion:gloas-bid-inclusion
Apr 29, 2026
Merged

Add Gloas bid inclusion#9221
mergify[bot] merged 8 commits intosigp:unstablefrom
dapplion:gloas-bid-inclusion

Conversation

@dapplion
Copy link
Copy Markdown
Collaborator

Select bid from p2p and local block building. Recycles boost factor flag. Once the builder API gloas design finalizes we can extend this logic to consider trusted and trustless bids over http queries.

When producing a Gloas block, select between the locally-built bid and
the highest gossip-verified builder bid for the same parent, using
`builder_boost_factor` (mirroring the pre-Gloas builder/local race in
`execution_layer`):

- `boosted_bid = (cached_bid.value / 100) * boost_factor` (raw on `None`)
- if `local_value_wei >= boosted_bid_wei` -> keep local
- if EL signaled `should_override_builder` -> keep local
- else -> use the cached builder bid and drop local payload data
  (the builder reveals the envelope)

`cached_bid.value` is in gwei (u64); `payload_value` is in wei
(Uint256); the comparison is performed in wei.

`should_override_builder` is now plumbed from `GetPayloadResponseGloas`
through `BlockProposalContentsGloas` into the new `LocalBuildResult` so
the selection step can honor the EL hint.

Selection logic is factored into a pure `select_payload_bid_pure`
function with unit tests covering empty cache, no local build, override
hook, boost=0, neutral boost, local-higher, tie, and boost amplification.
Two readability fixes after self-review:

- `select_payload_bid_pure` now takes `LocalBuildResult` directly instead of
  `Option<LocalBuildResult>`. The `None` branch was scaffolding for a
  hypothetical "skip the EL build entirely" path, but in practice the local
  build is always needed as the fallback for empty-cache slots, so it never
  becomes None. `produce_execution_payload_bid` returns `LocalBuildResult`
  directly to match.

- Tests collapsed onto a single positional `pick(local_payload_gwei,
  should_override, cached_gwei, boost) -> (BuilderIndex, bool)` helper, with
  arg semantics documented on the helper's doc comment so the call sites stay
  one-liners that read as truth-table rows.
Removes the explicit `unsupported fork for ExecutionPayloadHeader` error
when decoding a `BuilderBid` for Gloas. The Gloas variant reuses the
Fulu wire format (`ExecutionPayloadHeaderFulu` as the header) so existing
relays can serve Gloas-fork lighthouses without a wire-protocol change —
the bid is mapped onto a Gloas self-build wrapper at the producer
(builder_index = u64::MAX, infinity sig).

The auto-generated `map_ref_into(ExecutionPayloadHeaderRef)` macros are
replaced with explicit match arms because `ExecutionPayloadHeader` has
no Gloas variant; the Gloas builder bid maps to the Fulu header ref.
When a builder is configured, the Gloas producer now races local EL +
relay using the existing pre-Gloas `get_payload` selection (with
`builder_boost_factor`, `should_override_builder`, and the
`builder-fallback-*` chain-health gates), and wraps whichever wins as a
Gloas self-build bid (`builder_index = u64::MAX`, infinity sig, value 0).

That self-build candidate is then compared against the highest p2p
gossip-cache bid via `select_payload_bid_pure`, again using
`builder_boost_factor`. The same operator knob applies at both layers.

For the relay-won case `payload_data` is `None` at production time —
the proposer must unblind via the existing mev-boost endpoint before
envelope publication (relay never reveals up front).

Adds:
- `GloasPayloadSource` enum in `execution_layer`
- `get_payload_gloas_with_builder` (delegates to pre-Gloas `get_payload`)

`LocalBuildResult.payload_data` is now `Option<...>` so the relay-blinded
case can flow through the existing select path unchanged.
Replaces the earlier "BuilderBid::Gloas reuses Fulu wire shape" hack
with the protocol-honest design: Gloas-aware relays return a
`SignedExecutionPayloadBid` directly (the native commitment type).

- Reverts the `BuilderBid::Gloas` variant (and the subsequent macro
  expansion fallout). `BuilderBid` correctly stops at Fulu again — that
  envelope shape is retired in Gloas.
- Adds a new builder-client endpoint:
  `GET /eth/v1/builder/payload_bid/{slot}/{parent_hash}/{pubkey}`
  returning `ForkVersionedResponse<SignedExecutionPayloadBid<E>>`.
- Adds `ForkVersionDecode for SignedExecutionPayloadBid<E>` (Gloas-only).
- `get_payload_gloas_with_builder` no longer routes through pre-Gloas
  `get_payload`; instead races the new Gloas relay endpoint against
  local EL using `builder_boost_factor`. The local EL's
  `should_override_builder` flag still forces local.
- `GloasPayloadSource::Builder` now carries `SignedExecutionPayloadBid`
  directly. Producer extracts bid fields from `signed_bid.message` —
  no Fulu→Gloas translation.
The new builder-client method `get_builder_header_gloas` calls the same
URL as the pre-Gloas `get_builder_header` — relays dispatch on the
slot's fork (returning `SignedBuilderBid` for pre-Gloas slots,
`SignedExecutionPayloadBid` for Gloas slots). The two Rust methods exist
because the response types differ and Rust can't dispatch on return
type, but the wire URL is identical (no new spec route invented).

`BuilderBid` itself stops at Fulu — adding a Gloas variant would force
60+ pre-Gloas call sites to handle `Option<header>` since Gloas has no
`ExecutionPayloadHeader`. The minimal-diff path keeps `BuilderBid`
untouched and adds a parallel client method.
Drops the relay-side plumbing for Gloas (the get_payload_gloas_with_builder
race, the SignedExecutionPayloadBid ForkVersionDecode impl, the
get_builder_header_gloas method, the GloasPayloadSource enum) until the
relay wire format for Gloas is settled.

The constraint trilemma (existing macro / existing get_builder_header /
no new code) couldn't be resolved without either:
  - adding a Gloas variant to BuilderBid (breaks the
    map_builder_bid_ref_into_execution_payload_header_ref macro since
    ExecutionPayloadHeader has no Gloas variant),
  - adding a Gloas variant to ExecutionPayloadHeader (massive blast
    radius across state_root/receipts_root/etc. accessors), or
  - duplicating HTTP boilerplate.

Rather than ship a design that gets rewritten once the spec lands, this
PR ships only the gossip-cache selection (Path C — the proposer picks a
SignedExecutionPayloadBid from the gossip cache via select_payload_bid_pure
using builder_boost_factor). Path B (mev-boost-as-self-build) is a
follow-up that will revisit the wire-format question.
@dapplion dapplion added ready-for-review The code is ready for review gloas labels Apr 29, 2026
@jimmygchen jimmygchen self-requested a review April 29, 2026 10:04
SignedExecutionPayloadBid<T::EthSpec>,
BeaconState<T::EthSpec>,
Option<ExecutionPayloadData<T::EthSpec>>,
LocalBuildResult<T::EthSpec>,
Copy link
Copy Markdown
Member

@jimmygchen jimmygchen Apr 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doc comments may need update as we no longer return an Option here

Copy link
Copy Markdown
Member

@jimmygchen jimmygchen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, very clean with good tests!

Just a small comment on updating the doc and removing this TODO

// TODO(gloas) add builder boost factor

@jimmygchen jimmygchen added ready-for-merge This PR is ready to merge. and removed ready-for-review The code is ready for review labels Apr 29, 2026
@mergify mergify Bot added the queued label Apr 29, 2026
@mergify
Copy link
Copy Markdown

mergify Bot commented Apr 29, 2026

Merge Queue Status

  • Entered queue2026-04-29 11:32 UTC · Rule: default
  • 🟠 Preparing checks
  • ⏳ Merge

@mergify
Copy link
Copy Markdown

mergify Bot commented Apr 29, 2026

Merge Queue Status

This pull request spent 30 minutes 4 seconds in the queue, including 27 minutes 23 seconds running CI.

Required conditions to merge

mergify Bot added a commit that referenced this pull request Apr 29, 2026
mergify Bot added a commit that referenced this pull request Apr 29, 2026
@mergify mergify Bot merged commit 0e427ab into sigp:unstable Apr 29, 2026
39 checks passed
@mergify mergify Bot removed the queued label Apr 29, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gloas ready-for-merge This PR is ready to merge.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants