feat: implement gloas builder api#9594
Conversation
There was a problem hiding this comment.
Code Review
This pull request implements external builder integration post-gloas (ePBS) in Lodestar, introducing a new GloasExecutionBuilder service, API endpoints for submitting builder preferences and fetching execution payload bids, and a BuilderPreferencesService in the validator client. Feedback on the changes highlights two critical improvements: parallelizing the validation of builder API bids using Promise.all to prevent blocking the block production hot path with sequential BLS signature verifications, and adding a concurrency guard to runBuilderPreferencesTask alongside transactional duty processing to prevent overlapping executions and duplicate submissions.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Performance Report✔️ no performance regression detected Full benchmark results
|
**Motivation** The pre-gloas builder circuit breaker (`updateBuilderStatus`) counts missed slots via fork choice and disables the external builder flow when the chain is unhealthy. This mechanism does not apply to gloas: - `produceBlockV4` always prefers a builder bid from the bid pool without any chain health check - post-gloas the beacon block is produced by the proposer regardless of bid source, so missed blocks are no longer a useful builder health signal. The failure mode to protect against is unrevealed payloads - the missed slot counting via `getSlotsPresent` also breaks post-gloas since each gloas block inserts multiple protoArray nodes (PENDING/EMPTY/FULL variants) **Description** - add `BuilderCircuitBreaker` which counts blocks with unrevealed payloads (no FULL variant in fork choice) within the fault inspection window and ignores builder bids in `produceBlockV4` while the breaker is active - the fault budget is scaled by blocks present in the window so sparse windows still trigger on high non-reveal rates - the current slot is excluded from the window as its payload reveal may still be in flight - blocks on all branches are counted, this keeps the result independent of which branch is head when the breaker is evaluated and errs toward local building when forks are frequent - the local block is always built, meaning fallback to the self-built block requires no extra work - the breaker will apply uniformly once bids are also accepted via the builder api (#9594), bid value comparison vs. the local payload is handled in #9595 - update breaker status during `prepareNextSlot` and lazily at block production time, the pre-gloas builder status update is now gated to pre-gloas forks - the existing `--builder.faultInspectionWindow` and `--builder.allowedFaults` flags configure the breaker on every fork, defaults are randomized per boot as before - add metrics - `beacon_builder_circuit_breaker_active`: whether the breaker is currently active (1) causing builder bids to be ignored - `beacon_builder_circuit_breaker_faults`: count of blocks with unrevealed payloads in the fault inspection window - `beacon_builder_circuit_breaker_blocks_present`: count of blocks present in the fault inspection window - `beacon_builder_circuit_breaker_payloads_revealed`: count of blocks with revealed payloads in the fault inspection window
Part of #9298