You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Helix currently implements the Bellatrix→Fulu builder-API shape: getHeader, registerValidator, getPayload. Gloas (ePBS) replaces these with getExecutionPayloadBid, submitBuilderPreferences, and submitSignedBeaconBlock respectively — a different flow, not a version bump of the same one. This issue scopes what's needed for helix to support it.
Why
Gloas (EIP-7732) removes the execution payload from the beacon block body entirely. The block carries a SignedExecutionPayloadBid directly, and the full payload is revealed after the block is proposed via a SignedExecutionPayloadEnvelope broadcast to the PTC — not returned synchronously to the proposer. There's no more "blinded block" concept. Based on the Gloas builder-API spec: builder.md, validator.md, merged via ethereum/builder-specs#165.
Resolved design question: does helix need a gossip/libp2p stack for envelope publishing? No — a connected beacon node's own HTTP API bridges HTTP↔gossip for every Gloas primitive (POST /eth/v1/beacon/execution_payload_envelopes publishes to gossip on helix's behalf; /eth/v1/events?topics=... streams gossip observations back). helix stays HTTP-only.
Resolved design question: who holds the on-chain builder identity (deposit, builder_index, signing key) that signs SignedExecutionPayloadBid/SignedExecutionPayloadEnvelope? For now, helix signs under its own configured identity (reusing the relay's existing signing key; builder_index is a placeholder RelayConfig field until a real on-chain registration exists), the same centralizing-trust model it already uses for SignedBuilderBid. Supporting external builders submitting their own signed bids/envelopes is deferred (tracked separately, not yet a step).
Resolved design question: does helix's builder→relay submit_block wire shape need to become progressive-list-aware to carry Gloas payloads? No. crates/types/src/bid_submission.rs's ExecutionPayload/SignedBidSubmission is helix's own bounded-list builder↔relay representation, shared unchanged across Bellatrix–Fulu — it is not a mirror of the real per-fork consensus SSZ types. External builders keep submitting via the same bounded-list shape for Gloas; helix converts to the real, progressive-list consensus types (ExecutionPayloadGloas/ExecutionRequestsGloas) only at the outbound bid/envelope boundary (step 5).
Resolved design question:ExecutionPayloadBid splits value/execution_payment into two separate fields. Since submitBuilderPreferences's max_execution_payment is a proposer-side cap rather than something a builder declares, and helix's existing submission only carries one value, execution_payment is set equal to value for now. Revisit if/when payment splitting becomes a real product need.
Affected surface
File
Role today
Gloas impact
crates/relay/src/api/proposer/get_header.rs
serves SignedBuilderBid
Parallel Gloas path serving SignedExecutionPayloadBid; different auth model (SignedBuilderRequestAuth), new parent_root param
crates/relay/src/api/proposer/header_stream.rs
SSE stream of SignedBuilderBid frames
Needs a Gloas frame type
crates/relay/src/api/proposer/register.rs
validator registration
submitBuilderPreferences stores max_execution_payment per-slot per-proposer instead of a long-lived registration
crates/relay/src/api/proposer/get_payload.rs
diffs blinded block header vs. held payload
No blinded-block concept in Gloas; replaced by accept-full-block + trigger envelope construction
Step 1: Add builder-API-only auth/preference types (RequestAuth, BuilderPreferences) and stub the three new proposer-facing endpoints (getExecutionPayloadBid, submitBuilderPreferences, submitSignedBeaconBlock), validating request shape and signatures only — not wired to the auctioneer yet (PR: Add Gloas builder-API auth/preference types and stub the 3 new proposer endpoints #496)
Step 6: Wire getExecutionPayloadBid/submitSignedBeaconBlock to read the winning submission out of the auctioneer's existing ctx.payloads/bid-sorter (same map get_header already reads), convert via step 5, and sign under helix's own GloasBuilderIdentity; replace the placeholder GloasPayloadStore/NoHeldPayloads with a real auctioneer-backed lookup (tests: auctioneer::get_execution_payload_bid::tests::build_signed_bid_*, api::proposer::submit_signed_beacon_block::construct_signed_envelope_tests::*) (PR: Serve real Gloas bids and envelopes from the auctioneer's existing submissions #515, stacked on Unblock Gloas submissions through the existing bid-submission wire shape #514)
(Reordered from the original numbering: this step used to be "step 6, backfill hydration.rs/execution_payload.rs" and the old step 5 — updating submit_block's wire shape — turned out to be blocked on it, since helix's ExecutionPayload had no Gloas representation at all. The old step 5's actual remaining work (reading real submissions and serving a real signed bid/envelope) is folded into the new step 6 above.)
Open questions
Re-verify endpoint names/shapes against whatever CL version is actually targeted once Gloas nears a release tag rather than a devnet branch.
Status
Helix currently implements the Bellatrix→Fulu builder-API shape:
getHeader,registerValidator,getPayload. Gloas (ePBS) replaces these withgetExecutionPayloadBid,submitBuilderPreferences, andsubmitSignedBeaconBlockrespectively — a different flow, not a version bump of the same one. This issue scopes what's needed for helix to support it.Why
Gloas (EIP-7732) removes the execution payload from the beacon block body entirely. The block carries a
SignedExecutionPayloadBiddirectly, and the full payload is revealed after the block is proposed via aSignedExecutionPayloadEnvelopebroadcast to the PTC — not returned synchronously to the proposer. There's no more "blinded block" concept. Based on the Gloas builder-API spec: builder.md, validator.md, merged via ethereum/builder-specs#165.Resolved design question: does helix need a gossip/libp2p stack for envelope publishing? No — a connected beacon node's own HTTP API bridges HTTP↔gossip for every Gloas primitive (
POST /eth/v1/beacon/execution_payload_envelopespublishes to gossip on helix's behalf;/eth/v1/events?topics=...streams gossip observations back). helix stays HTTP-only.Resolved design question: who holds the on-chain builder identity (deposit,
builder_index, signing key) that signsSignedExecutionPayloadBid/SignedExecutionPayloadEnvelope? For now, helix signs under its own configured identity (reusing the relay's existing signing key;builder_indexis a placeholderRelayConfigfield until a real on-chain registration exists), the same centralizing-trust model it already uses forSignedBuilderBid. Supporting external builders submitting their own signed bids/envelopes is deferred (tracked separately, not yet a step).Resolved design question: does helix's builder→relay
submit_blockwire shape need to become progressive-list-aware to carry Gloas payloads? No.crates/types/src/bid_submission.rs'sExecutionPayload/SignedBidSubmissionis helix's own bounded-list builder↔relay representation, shared unchanged across Bellatrix–Fulu — it is not a mirror of the real per-fork consensus SSZ types. External builders keep submitting via the same bounded-list shape for Gloas; helix converts to the real, progressive-list consensus types (ExecutionPayloadGloas/ExecutionRequestsGloas) only at the outbound bid/envelope boundary (step 5).Resolved design question:
ExecutionPayloadBidsplitsvalue/execution_paymentinto two separate fields. SincesubmitBuilderPreferences'smax_execution_paymentis a proposer-side cap rather than something a builder declares, and helix's existing submission only carries one value,execution_paymentis set equal tovaluefor now. Revisit if/when payment splitting becomes a real product need.Affected surface
crates/relay/src/api/proposer/get_header.rsSignedBuilderBidSignedExecutionPayloadBid; different auth model (SignedBuilderRequestAuth), newparent_rootparamcrates/relay/src/api/proposer/header_stream.rsSignedBuilderBidframescrates/relay/src/api/proposer/register.rssubmitBuilderPreferencesstoresmax_execution_paymentper-slot per-proposer instead of a long-lived registrationcrates/relay/src/api/proposer/get_payload.rscrates/relay/src/auctioneer/get_payload.rs::unblind()crates/relay/src/api/builder/submit_block.rscrates/types/src/builder_bid.rsBuilderBid, no per-fork enumExecutionPayloadBid/SignedExecutionPayloadBidtype, not an extensioncrates/types/src/hydration.rsexecution_payload.rs/fields.rs(step 5)Steps (each becomes one PR)
RequestAuth,BuilderPreferences) and stub the three new proposer-facing endpoints (getExecutionPayloadBid,submitBuilderPreferences,submitSignedBeaconBlock), validating request shape and signatures only — not wired to the auctioneer yet (PR: Add Gloas builder-API auth/preference types and stub the 3 new proposer endpoints #496)submitSignedBeaconBlockto construct and POST aSignedExecutionPayloadEnvelopeto a connected beacon node (PR: Construct and sign the Gloas SignedExecutionPayloadEnvelope, and broadcast it to beacon nodes #503, stacked on Update Gloas spec references to point at the merged spec #501)getExecutionPayloadBidto serve real bids from the auctioneer (value/execution_paymentsplit,parent_rootcheck,max_execution_paymentenforcement) (PR: Wire getExecutionPayloadBid to the auctioneer, checking parent_hash/parent_root #507, stacked on Construct and sign the Gloas SignedExecutionPayloadEnvelope, and broadcast it to beacon nodes #503)submitBuilderPreferencesto real per-slot per-proposer storage (PR: Wire submitBuilderPreferences to per-proposer per-slot storage on the auctioneer #509, stacked on Wire getExecutionPayloadBid to the auctioneer, checking parent_hash/parent_root #507)hydration.rs/execution_payload.rs's stubbed Gloas arms — unblock Gloas-fork decode through the existing bounded-list wire shape, add real progressive-list conversions (to_lighthouse_gloas_payload,execution_requests_to_gloas) for use at the outbound boundary (tests:hydration::tests::*decodes_under_gloas_fork*,execution_payload::tests::*gloas*,fields::tests::*gloas*) (PR: Unblock Gloas submissions through the existing bid-submission wire shape #514, stacked on Wire submitBuilderPreferences to per-proposer per-slot storage on the auctioneer #509)getExecutionPayloadBid/submitSignedBeaconBlockto read the winning submission out of the auctioneer's existingctx.payloads/bid-sorter (same mapget_headeralready reads), convert via step 5, and sign under helix's ownGloasBuilderIdentity; replace the placeholderGloasPayloadStore/NoHeldPayloadswith a real auctioneer-backed lookup (tests:auctioneer::get_execution_payload_bid::tests::build_signed_bid_*,api::proposer::submit_signed_beacon_block::construct_signed_envelope_tests::*) (PR: Serve real Gloas bids and envelopes from the auctioneer's existing submissions #515, stacked on Unblock Gloas submissions through the existing bid-submission wire shape #514)(Reordered from the original numbering: this step used to be "step 6, backfill hydration.rs/execution_payload.rs" and the old step 5 — updating submit_block's wire shape — turned out to be blocked on it, since helix's ExecutionPayload had no Gloas representation at all. The old step 5's actual remaining work (reading real submissions and serving a real signed bid/envelope) is folded into the new step 6 above.)
Open questions