BuilderHub is the central data source for BuilderNet builder registration and configuration.
Docs here: https://buildernet.org/docs/flashbots-infra
BuilderHub has these responsibilities:
- Builder identity management
- Provisioning of secrets and configuration
- Peer discovery
The Admin API (port 8081) requires HTTP Basic Auth. Configure via env vars or flags:
ADMIN_BASIC_USER(default:admin)ADMIN_BASIC_PASSWORD_BCRYPT(bcrypt hash of the password; required)
Generate a bcrypt hash (example using htpasswd):
htpasswd -nbBC 10 "" 'secret' | cut -d: -f2Run with:
export ADMIN_BASIC_USER=admin
export ADMIN_BASIC_PASSWORD_BCRYPT='$2y$12$...'
go run cmd/httpserver/main.goUse Basic Auth when calling admin endpoints, e.g.:
curl -u admin:secret http://localhost:8081/api/admin/v1/measurementsLocal development only: you can disable Admin API auth with --disable-admin-auth or DISABLE_ADMIN_AUTH=1. This is unsafe; never use in production.
Start the database and the server:
# Start a Postgres database container
docker run -d --name postgres-test -p 5432:5432 -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=postgres postgres
# Apply the DB migrations
for file in schema/*.sql; do psql "postgres://postgres:postgres@localhost:5432/postgres?sslmode=disable" -f $file; done
# Start the server
go run cmd/httpserver/main.go- See instructions on using Docker to run the full stack at
docs/devenv-setup.md - Also check out the
docker-compose.yamlfile, which sets up the BuilderHub, a mock proxy, and a Postgres database. - Finally, there's an e2e api spec test suite you can run:
./scripts/ci/integration-test.sh
# Public endpoints
curl localhost:8080/api/l1-builder/v1/measurements
# client-aTLS secured endpoints
curl localhost:8080/api/l1-builder/v1/builders
curl localhost:8080/api/l1-builder/v1/configuration
curl -X POST localhost:8080/api/l1-builder/v1/register_credentials/rbuilderRun test suite with database tests included:
RUN_DB_TESTS=1 make testInstall dev dependencies
go install mvdan.cc/[email protected]
go install honnef.co/go/tools/cmd/[email protected]
go install github.com/golangci/golangci-lint/cmd/[email protected]
go install go.uber.org/nilaway/cmd/[email protected]
go install github.com/daixiang0/[email protected]Lint, test, format
make lint
make test
make fmtBuilderHub exposes a JSON+REST API with these methods:
| API | Exposure | Authentication | Requested by | Served by |
|---|---|---|---|---|
| Get Secrets + Config | TDX Node | IP + Client-ATLS Attestation | Builder (via cvm-proxy) | cvm-proxy → BuilderHub |
| Register Credentials | TDX Node | IP + Client-ATLS Attestation | Builder (via cvm-proxy) | cvm-proxy → BuilderHub |
| Get Active Builders | TDX Node | IP + Client-ATLS Attestation | Builder (via cvm-proxy) | cvm-proxy → BuilderHub |
| Get Active Builders | Internal | HTTP Basic Auth | MEV-Share, block processor, … | BuilderHub |
| Get Allowed Measurements | Internal | HTTP Basic Auth | Users, Builders | nginx → BuilderHub |
| Admin Endpoints | Internal | HTTP Basic Auth |
See also a Bruno collection (Postman alternative) in docs/api-docs/.
GET /api/l1-builder/v1/configuration
Auth:
- IP + Client-ATLS Attestation
Response: testdata/get-configuration.json
POST /api/l1-builder/v1/register_credentials/<SERVICE>
Auth:
- IP + Client-ATLS Attestation
Request:
-
[service:
instance]: TLS cert{ "tls_cert": string (\n instead of newlines) } -
[service:
orderflow_proxy]: ECDSA pubkey address (for orderflow){ "ecdsa_pubkey_address": string } -
[service:
rbuilder]: ECDSA pubkey address (for bids){ "ecdsa_pubkey_address": string }
Response: 200 OK
GET /api/l1-builder/v1/builders (external, requests from builder via cvm-proxy)
GET /api/internal/l1-builder/v1/builders (internal, no auth, uses production network by default)
GET /api/internal/l1-builder/v2/network/{network}/builders (internal, no auth, for specific peer network)
Response: testdata/get-builders.json
Auth: public
GET /api/l1-builder/v1/measurements
Response: Array with currently allowed measurement JSONs
testdata/get-measurements.json
(created disabled by default)
POST /api/admin/v1/measurements
Payload
{
"measurement_id": "v1.2.3-20241010-rc1",
"attestation_type": "azure-tdx",
"measurements": {
"11": {
"expected": "efa43e0beff151b0f251c4abf48152382b1452b4414dbd737b4127de05ca31f7"
},
}
}Note that only the measurements given are expected, and any non-present will be ignored.
To allow any measurement, use an empty measurements field:
"measurements": {}.
{
"measurement_id": "test-blanket-allow",
"attestation_type": "azure-tdx",
"measurements": {}
}POST /api/admin/v1/measurements/activation/{measurement_id}
{
"enabled": true
}(created inactive by default)
POST /api/admin/v1/builders/
Payload
{
"name": string,
"ip_address": string
}POST /api/admin/v1/builders/activation/{builder_name}
{
"enabled": true
}Errors:
- if no active configuration available
GET /api/admin/v1/builders/configuration/{builder_name}/active
gets always the latest/active configuration
GET /api/admin/v1/builders/configuration/{builder_name}/full
gets always the latest/active configuration
if valid JSON, will create a new active configuration and disable the old configuration
POST /api/admin/v1/builders/configuration/{builder_name}
{
...
}POST /api/admin/v1/builders/secrets/{builderName}
Payload: JSON with secrets, both flattened/unflattened
{
...
}