Skip to content

builder_api: add Gloas Staked Builder API client - #819

Open
NikhilSharmaWe wants to merge 15 commits into
grandinetech:glamsterdam-devnet-7from
NikhilSharmaWe:gloas-builder-api-client
Open

builder_api: add Gloas Staked Builder API client#819
NikhilSharmaWe wants to merge 15 commits into
grandinetech:glamsterdam-devnet-7from
NikhilSharmaWe:gloas-builder-api-client

Conversation

@NikhilSharmaWe

@NikhilSharmaWe NikhilSharmaWe commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Part of #769. Client side of the Gloas Staked Builder API (ethereum/builder-specs#138), aligned with the clarifications in ethereum/builder-specs#165 (ACDT CL guidance: implement before merge).

Changes

  • Add DOMAIN_REQUEST_AUTH (0x0B000001) and the Gloas builder containers (RequestAuthV1, SignedRequestAuthV1, BuilderPreferencesV1, BuilderPreferencesRequestV1) to builder_api
  • Add three HTTP client methods:
    • get_execution_payload_bid — POST /eth/v1/builder/execution_payload_bid/{slot}/{parent_hash}/{parent_root}/{proposer_pubkey} with a required SignedRequestAuthV1 body (JSON or SSZ), required Date-Milliseconds and X-Timeout-Ms headers (timeout matches the reqwest timeout), and always Eth-Consensus-Version. 200 returns a bid, 204 means no bid. Gloas+ only; rejects earlier phases and auth.message.slot ≠ path slot before the request.
    • submit_builder_preferences — POST /eth/v1/builder/builder_preferences/{validator_pubkey} with BuilderPreferencesRequestV1 (SSZ field order: auth then preferences), expects 202
    • submit_signed_beacon_block — POST /eth/v1/builder/beacon_blocks, expects 202
  • Signing support for RequestAuthV1 (SignForAllForks, genesis fork + zero genesis validators root, per spec compute_domain(DOMAIN_REQUEST_AUTH))
  • Prometheus histograms for the three calls

Notes

Tests

  • cargo test -p builder_api --features blst — httpmock coverage for all three endpoints (200/204/400/500, required auth body + timing / consensus-version headers, auth slot mismatch, non-2xx handling, pre-Gloas rejection), DOMAIN_REQUEST_AUTH signing-root check, and SSZ field-order lock for BuilderPreferencesRequestV1

@NikhilSharmaWe

Copy link
Copy Markdown
Contributor Author

cc @hangleang

@hangleang

Copy link
Copy Markdown
Member

cc @hangleang

Thanks for the contributions, I was occupy by other urgent tasks so I won't be able to review within this week or two

@hangleang

Copy link
Copy Markdown
Member

FYI: clients have agreed to implement the spec PR ethereum/builder-specs#165 even it still unmerged (see https://forkcast.org/calls/acdt/090/?breakout=cl#t=70 on decisions), could you update the PR accordingly?

@NikhilSharmaWe

NikhilSharmaWe commented Aug 6, 2026

Copy link
Copy Markdown
Contributor Author

@hangleang Updated with ethereum/builder-specs#165 as requested:

  • Required SignedRequestAuth on bid fetch
  • Required Date-Milliseconds and X-Timeout-Ms
  • Always send Eth-Consensus-Version
  • BuilderPreferencesRequest SSZ order: auth then preferences

Tests updated; cargo test -p builder_api --features blst passes.

Comment thread builder_api/src/gloas/containers.rs
Comment thread builder_api/src/gloas/containers.rs Outdated
Comment thread builder_api/src/gloas/containers.rs Outdated
Comment thread builder_api/src/api.rs
Comment thread builder_api/src/api.rs
.builder_submit_builder_preferences_times
.start_timer()
});

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

why won't check slot like get_execution_payload_bid does?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in e5ba389
auth.message.slot is treated as the proposal slot and rejected if it has already passed.

Comment thread builder_api/src/api.rs Outdated
})
}

async fn parse_gloas_response<T: DeserializeOwned + SszRead<Phase>>(

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this function almost identical to parse_response below, can we reuse the function?

@NikhilSharmaWe NikhilSharmaWe Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 0e01a9c. JSON/SSZ decoding was extracted into decode_ssz_or_json_response and reused. parse_response remains a wrapper for legacy builder responses because it also updates the separate supports_block_ssz cache.

Comment thread builder_api/src/api.rs Outdated
let request = self
.client
.post(url.into_url())
.timeout(remaining_time)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this might be the wrong deadline for this endpoint. I guess this is copied from post_blinded_block pre-Gloas path which proposer require builder to response before attestation deadline, so it has the payload to construct and publish beacon block before deadline. but now builder is responsible to publish their payload, and this endpoint is just notify them to publish payload envelope by themselves through beacon node

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed in a5867d4. The signed-block notification now uses the fixed request timeout instead of the attestation-interval deadline.

Comment thread builder_api/src/api.rs Outdated
let request = self
.client
.post(url.into_url())
.timeout(REQUEST_TIMEOUT)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

the interval timeout should be put on this endpoint instead, as now proposer request bid from builder to choose on proposal hot path

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in 25b73d3
The bid request is bounded by the remaining time before the next interval, capped at one second.

Comment thread builder_api/src/api.rs Outdated
.header(DATE_MS_HEADER, format!("{date_ms}"))
.header(
X_TIMEOUT_MS_HEADER,
format!("{}", REQUEST_TIMEOUT.as_millis()),

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

same here

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done in same 25b73d3. X-Timeout-Ms and the reqwest timeout use the same computed millisecond value.

Comment thread builder_api/src/api.rs Outdated
"/eth/v1/builder/execution_payload_bid/{slot}/{parent_hash:?}/{parent_root:?}/{pubkey:?}"
))?;

let use_json = self.config.builder_api_format == BuilderApiFormat::Json;

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

should have fallback to json format if builder doesn't support SSZ, same as other two endpoints

@NikhilSharmaWe NikhilSharmaWe Aug 14, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Done for bids in e049bac, then extended across all Gloas POST bodies in 0e01a9c. A 415 retries once as JSON; 400 and other client errors are not retried.

Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
…inguish skipped bids from 204

Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
@NikhilSharmaWe
NikhilSharmaWe force-pushed the gloas-builder-api-client branch from 42285f3 to 0e01a9c Compare August 14, 2026 07:59
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
Signed-off-by: Nikhil Sharma <nikhilsharma230303@gmail.com>
@NikhilSharmaWe

NikhilSharmaWe commented Aug 20, 2026

Copy link
Copy Markdown
Contributor Author

@hangleang, I have resolved the reviews. Let me know if there are any issues or improvements required.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants