Repository navigation
feat(pbs): dial builders outside the config for ePBS requests - #506
Open
JasonVranek wants to merge 1 commit into
Open
JasonVranek wants to merge 1 commit into
JasonVranek wants to merge 1 commit into
Conversation
Auth data that is an http(s) URL now also routes to the relay entry with the same scheme, host and port. Either form may end in `?` and parameters for the builder: Commit-Boost routes on the part before `?` and forwards the signed auth, parameters included, unchanged. When no relay entry matches, Commit-Boost dials the builder the auth data names for a bid or preferences request: `https://<hostname>`, or the URL. The target is resolved once, and the lookup and the dial share the request's budget. A name that does not resolve, or any address that is not public unicast, gets 400; a lookup or dial setup that runs out of time counts as a builder that did not answer. At most 32 lookups run at once, since a timed-out lookup keeps its blocking thread. The dial goes only to the checked addresses, with no proxy and no redirects. A request from a Commit-Boost never leads to a dial, so a dial that reaches a Commit-Boost, this one included, goes no further. Auth data, a dialed builder's error body and a dial target come from the request, so they are logged escaped, the body capped at 1 KiB and the target as its origin. The signed block gets 202 once it has been forwarded, whatever the builders answer, since the beacon node gossips it anyway. A block whose bid came from a dialed builder, which is not a relay entry, would otherwise always get 500. When no builder accepts the block, Commit-Boost logs a warning.
JasonVranek
added this pull request to stack #507
October 7, 2026 04:11
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Builds on #505. There, a bid or preferences request whose auth data matches no relay entry gets
400, so a validator key whose builder config names a builder the operator has not added to Commit-Boost gets no bids from it. This PR has Commit-Boost dial the builder the auth data names, behind an SSRF guard, and routes auth data written as a builder URL. It also answers the signed block with202once it has been forwarded, whatever the builders answer, which addresses a review comment on #505.What it does
httporhttpsURL matches the first relay entry with the same scheme, host and port. The path and the pubkey in the relay URL do not count.?and form-encoded parameters for the builder, such asbuilder-a.example.com?filter=1, a way for a proposer to state a preference like transaction filtering. Commit-Boost routes on the part before?and forwards the signed auth, parameters included, unchanged, so the parameters arrive signed by the proposer. A builder that does not accept them answers400, so a proposer sets them only for builders that accept them. Without a?, routing is unchanged.https://<hostname>on the default port, or the URL's scheme, host and port. There is no setting to turn it off. Dialed requests count underrelay_id="dial", and each dial logs the builder's origin and the addresses it connects to. A key without builder config sends Commit-Boost's own hostname, so Commit-Boost dialshttps://<its hostname>on port 443:400when that hostname resolves to a loopback or private address, as it usually does, and otherwise one request to whatever serves HTTPS on that host, which is Commit-Boost only behind a TLS proxy, where the loop guard below stops it.202once it has been forwarded, whatever the builders answer. This answers a review comment on epbs builder api endpoints #505: relays may do nothing with these requests, so an apparent failure should not be reported as one, and the beacon node gossips the block anyway. The block still goes only to configured relays, since Commit-Boost keeps no auction state; a dialed builder gets it over gossip.The ePBS docs page gets a section on builders outside the config, which also says what a key without builder config gets, the URL form and
?parameters in the routing reference,500in the metrics table for preferences only, and troubleshooting rows for both400s and for that warning.Scope
Commit-Boost now makes outbound requests to hosts named in request data. The proposer signs that data, but Commit-Boost does not verify the signature, so the target is treated as untrusted, and anyone who can reach Commit-Boost's PBS port can choose it:
timeout_register_validator_msfor preferences). If the name does not resolve, the answer is400and nothing is dialed. A lookup or dial setup that runs out of time counts as a builder that did not answer: no bid (204), or500for preferences.resolve_to_addrs), ignoresHTTP(S)_PROXYandALL_PROXY(a proxy would resolve the host again), follows no redirects, and sends none of the operator's relayheaders.X-CommitBoost-Version, which every Commit-Boost dial sends, never leads to a dial, so a dial that reaches a Commit-Boost, this one included, goes no further. Configured relays still serve such a request, so chained Commit-Boosts keep working.user:password@.Testing
cargo test --all-features: 402 passed (392 on part 1). Unit: URL-form auth data decoding (onlyhttpandhttps; opaque data such asbuilder-a:prodandhost:portparse as URLs and are refused), the dial target for each auth data form (URL, hostname, IPv6 hostname, a hostname with?parameters, an internal address, a non-hostname, a non-HTTP scheme), every resolved address checked, the lookup cap refusing a hostname but not an IP address, the dial pinned to the given address with redirects refused, the blocked-address table, and URL-form routing to relay entries and routing on the part before?. End to end: a bid dialed with its auth,?parameters included, unchanged, a bid naming Commit-Boost's own URL dialed once and answered with the second hop's400, a request from a Commit-Boost not dialed but still served by a configured relay, preferences dialed, an unmatchedlocalhostrefused as loopback, and no lookup once the deadline has passed. A builder's400and401reach the beacon node even with an error body over the 1 KiB read cap. The signed block gets202when every builder rejects it, and a pretty-printed JSON bid reaches the beacon node byte for byte.204, putting the500for a block no builder accepted back fails the all-reject test, and removing epbs builder api endpoints #505's passthrough arm fails only the passthrough test.HTTP_PROXYin a process that runs other tests in parallel), the escaping in logs and the 1 KiB cap on a logged error body, the refusal when the dial setup leaves no time, and the lookup's timing: its timeout and the time it leaves the dial (a local lookup finishes inside tokio's 1 ms timer tick, so a name slow enough to matter needs the network).--assert dial; Docker addresses are all private). Each key's auth data washttp://buildoor:8080, which no relay entry matches, so Commit-Boost dialed buildoor 95 times, for bid and preferences requests. All 17 observed slots were built from those bids, no dial was refused, and none looped.