Skip to content

Staked Builder API REST Client - #11026

Open
StefanBratanov wants to merge 20 commits into
Consensys:masterfrom
StefanBratanov:gloas-staked-builder-api-rest-client
Open

Staked Builder API REST Client#11026
StefanBratanov wants to merge 20 commits into
Consensys:masterfrom
StefanBratanov:gloas-staked-builder-api-rest-client

Conversation

@StefanBratanov

@StefanBratanov StefanBratanov commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

PR Description

Client for the builder rest api as per ethereum/builder-specs#138 . There is a repetition but I found it difficult to create a generic rest client implementation that both the VC client and builder client can use.

Fixed Issue(s)

related to #10822

Documentation

  • I thought about documentation and added the doc-change-required label to this PR if updates are required.

Changelog

  • I thought about adding a changelog entry, and added one if I deemed necessary.

Note

Medium Risk
New client code will carry signed beacon blocks and execution payload bids once wired into proposing; mistakes in encoding, headers, or error handling could affect block production, but this PR is an isolated library with no production wiring yet.

Overview
Adds a new builder:rest Gradle module that implements an OkHttp-based client for the Staked Builder API (Gloas).

StakedBuilderClient exposes three async operations: fetch execution payload bids (optional signed auth in JSON body vs empty POST), submit builder preferences (JSON), and submit signed beacon blocks (SSZ application/octet-stream). Shared plumbing includes BuilderApiMethod path templates, ResponseHandler status mapping to BuilderClientException, and AbstractBuilderRequest for JSON/empty/octet-stream POSTs with Eth-Consensus-Version headers.

OkHttpStakedBuilderClient delegates to per-endpoint request classes on an AsyncRunner. MockWebServer integration tests cover success paths, request shape, and 4xx/5xx errors. The parent builder project is included in settings.gradle with jar packaging disabled for the aggregator.

Reviewed by Cursor Bugbot for commit 246a35a. Bugbot is set up for automated code reviews on this repo. Configure here.

@StefanBratanov StefanBratanov changed the title Gloas staked builder api rest client Staked Builder API REST Client Jul 29, 2026
@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch from 0baf796 to 71a3287 Compare July 29, 2026 15:06
Comment thread builder/rest/src/main/java/tech/pegasys/teku/builder/rest/BuilderApiMethod.java Outdated
@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch from 5c4ae8d to 68b3483 Compare July 30, 2026 09:37

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit 68b3483. Configure here.

@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch from 75a1255 to f07ae53 Compare July 31, 2026 07:57
@Consensys Consensys deleted a comment from cursor Bot Jul 31, 2026
@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch 3 times, most recently from 921918d to 1f5f5d0 Compare August 3, 2026 08:00
@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch 2 times, most recently from 6ed7989 to f48c9d8 Compare August 5, 2026 13:17
@tbenr

tbenr commented Aug 5, 2026

Copy link
Copy Markdown
Contributor
  • Missing Eth-Consensus-Version request header on two endpoints. The spec marks this header required: true on both getExecutionPayloadBid and submitBuilderPreferences (the description qualifies it as "Required
    if the request body is SSZ encoded", but the OpenAPI declares it required unconditionally). The client sends it only for submitSignedBeaconBlock. A builder validating strictly against the OpenAPI schema would
    reject the other two requests. Since the milestone is trivially available, I'd send it on all three (it also future-proofs the JSON body across forks).

  • ResponseHandler.VOID is a shared mutable singleton. withHandler() is public and mutates the internal Int2ObjectOpenHashMap, which is not thread-safe. Any future caller doing
    ResponseHandler.VOID.withHandler(...) would mutate global state visible to all concurrent requests. Either make withHandler copy-on-write, drop it from the shared instance, or replace VOID with a factory method
    (ResponseHandler.voidHandler()).

  • All three central names already exist in the codebase for the legacy MEV-Boost Builder API. When this gets wired into ExecutionLayerManager (which already imports the old BuilderClient), both interfaces will coexist in the same call sites and imports will be genuinely confusing. Suggest
    StakedBuilderClient / StakedBuilderApiMethod or similar. Also note the old enum uses :param placeholders while the new one uses {param} — if both survive, converging on one convention would help.

  • AbstractBuilderRequestTestBase is named Abstract... but declared as a plain public class — declare it abstract.

  • getErrorMessage reads the full error body unbounded; a broken/hostile builder could return a huge payload that ends up in an exception message and log. Consider truncating (e.g. body.source().readUtf8(MAX)).

    Test coverage

    • shouldIncludeSignedRequestAuthInBodyWhenPresent only asserts body.size() > 0 — it should assert Content-Type: application/json and ideally round-trip the body back to the SignedRequestAuth to prove the schema
      used is the right one.
    • No test for the unknownResponseCodeHandler path (e.g. a 418) or for 503, and no test for a malformed 200 JSON body on the bid endpoint.

@rolfyone

rolfyone commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

would be good to add the references like OpenApiIntegrationTest does so that we can easily see the api definitions...

@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch from f48c9d8 to 01d69a4 Compare August 6, 2026 13:55

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

Reviewed by Cursor Bugbot for commit b1cde23. Configure here.

Comment thread builder/rest/src/main/java/tech/pegasys/teku/builder/rest/ResponseHandler.java Outdated
@StefanBratanov

Copy link
Copy Markdown
Contributor Author

@tbenr fixed the 5 points, will tackle testing one separately

@StefanBratanov

Copy link
Copy Markdown
Contributor Author

would be good to add the references like OpenApiIntegrationTest does so that we can easily see the api definitions...

They will show eventually anyways when we pipe them through the Beacon API.

@tbenr

tbenr commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

just one minor thing: Eth-Consensus-Version presence is not tested in all methods

@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch from bdcdaec to fa389c9 Compare August 10, 2026 17:33
@StefanBratanov

Copy link
Copy Markdown
Contributor Author

just one minor thing: Eth-Consensus-Version presence is not tested in all methods

Done

@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch 2 times, most recently from ab1645e to b5ffe69 Compare August 12, 2026 18:37
…oas/ePBS

Adds a new builder:rest Gradle submodule with an OkHttp-based REST client
for the Staked Builder API defined in builder-specs PR Consensys#138. The module is
self-contained with no wiring into existing Teku infrastructure yet.

Files added:
- BuilderClient interface (four Gloas builder endpoints)
- BuilderApiMethod enum with {param} URL template substitution
- BuilderIdentity record with JSON type definition and data wrapper
- BuilderClientException for typed error handling (with HTTP status code)
- ResponseHandler with per-status-code deserialization (200/202/204/400/401/500/503)
- AbstractBuilderRequest base class (GET, postJson, postEmpty, postOctetStream helpers)
- Four handler classes: GetBuilderIdentityRequest, GetExecutionPayloadBidRequest,
  SendBuilderPreferencesRequest, SendSignedBeaconBlockRequest
- OkHttpBuilderClient wrapping handlers with AsyncRunner for SafeFuture responses
- Integration tests using MockWebServer for all four handlers
…nt-Type

- SendSignedBeaconBlockRequest now takes Spec and sends Eth-Consensus-Version
  header derived from the block's slot milestone; postOctetStream gains a
  headers overload to support this
- postEmpty no longer sets Content-Type: application/json on a zero-length
  body; uses null MediaType so no Content-Type is sent (empty body is not
  valid JSON and would cause builders to return 400)
@StefanBratanov
StefanBratanov force-pushed the gloas-staked-builder-api-rest-client branch from b5ffe69 to 246a35a Compare August 13, 2026 14:27
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.

3 participants