Skip to content

Enable submit tx's directly to block builders - #4881

Open
jmg-duarte wants to merge 1 commit into
mainfrom
jmgd/builder-submission
Open

Enable submit tx's directly to block builders#4881
jmg-duarte wants to merge 1 commit into
mainfrom
jmgd/builder-submission

Conversation

@jmg-duarte

Copy link
Copy Markdown
Contributor

Description

Enables submitting transactions directly to block builders, leading to faster inclusion times.

After some experimenting, adding the main 10 block builders leads to 90% of auctions achieving 1 block settlements. One can check with the following query:

WITH non_colocated(solver) AS (
  VALUES <list of non-colocated solvers>
),
help AS (
  SELECT
    e.auction_id,
    a.block AS auction_block,
    s.block_number AS settle_block
  FROM settlement_executions AS e
  JOIN competition_auctions AS a
    ON a.id = e.auction_id
  JOIN non_colocated AS nc
    ON nc.solver = e.solver
  LEFT JOIN settlements AS s
    ON s.auction_id = e.auction_id
    AND s.solver = e.solver
    AND s.solution_uid = e.solution_uid
  WHERE
    e.start_timestamp >= CURRENT_TIMESTAMP - INTERVAL '17 HOUR' AND
    e.start_timestamp < CURRENT_TIMESTAMP - INTERVAL '0 HOUR'
    AND s.block_number IS NOT NULL
)
SELECT
  COUNT(*),
  settle_block - auction_block,
  ROUND(CAST(COUNT(*) AS DECIMAL) / SUM(COUNT(*)) OVER (), 3) AS frac
FROM help
GROUP BY
  settle_block - auction_block
ORDER BY
  settle_block - auction_block

Changes

  • Add builder support to the mempool
  • Infra to submit the requests to the builders
  • Tests

How to test

Tested in staging and prod

@jmg-duarte
jmg-duarte requested a review from a team as a code owner September 10, 2026 09:08
@claude

claude Bot commented Sep 10, 2026

Copy link
Copy Markdown
Contributor

Claude finished @jmg-duarte's task in 4m 23s —— View job


PR Review: Submit tx's directly to block builders

Nice, well-documented change — the Flashbots signature scheme, the "accept if any builder accepts" semantics, the revert-protection default flip for builder mempools, and the deny_unknown_fields hardening all look correct, and the tests (signature recovery, response classification, config default) are on-point.

I left 2 inline comments and have 1 additional finding below that couldn't be anchored inline because it lives in an unchanged file (domain/mempools.rs).

Additional finding (unchanged file: crates/driver/src/domain/mempools.rs)

Builder submissions lose the false-positive-revert protection of the cancellation heuristic (around lines 275–301). A builder-submitted tx is broadcast directly to builders and never enters the node's public mempool, so pending_transaction_count(signer) (queried against url) never reflects it. While a builder tx is in flight it therefore always looks "dropped" (pending_nonce == submission_nonce). For the node path a still-queued tx gives pending_nonce > submission_nonce, which is exactly what suppresses transient/false-positive resimulation_reverted results and keeps the tx alive (per the comment at lines 269–274). Builder submissions don't get that guard, so any transient estimate_gas revert during the wait window passes requires_cancellation and aborts with SimulationRevert, even though a builder might still include the tx. The getLogs check (line 282) covers the already-mined case, so this only affects genuinely-in-flight builder txs — but it does make builder submissions strictly more cancellation-prone than node submissions. Worth confirming this is acceptable or gating the pending-nonce signal for builder mempools. Fix this →

Inline comments

  • infra/mempool/mod.rs — misconfig (builder mempool + address-only signer) is enforced with a runtime assert! panic in Mempool::new; suggest validating at config-load time.
  • (attempted) domain/mempools.rs — see finding above.

Overall this looks solid to ship; the items above are mostly worth a confirmation rather than blockers.


  • Read PR diff and changed files
  • Review builder submission logic
  • Review config parsing
  • Review tests and metrics
  • Post inline comments and summary
    · branch jmgd/builder-submission

Comment on lines +109 to +122
if !config.builders.is_empty() {
// Builders get txs we sign ourselves. An address-only account
// relies on the node to sign and would fail on every settlement.
let address_only: Vec<_> = signers
.iter()
.filter(|(_, account)| matches!(account, Account::Address(_)))
.map(|(address, _)| address)
.collect();
assert!(
address_only.is_empty(),
"mempool {} submits to builders but accounts {address_only:?} cannot sign",
config.name
);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This misconfiguration (a builder mempool whose settlement account can't sign locally) is a static, config-time invariant, but it's enforced with an assert! inside Mempool::new, so it surfaces as a runtime panic during run() rather than a clean config-load error. Consider validating it in config/file/load.rs (alongside the other mempool checks that already return errors) so an operator gets a proper error message instead of a panic/stack trace on startup.

@jmg-duarte
jmg-duarte force-pushed the jmgd/builder-submission branch from c18c3bb to a4ec9d3 Compare September 10, 2026 09:16
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.

1 participant