Skip to content

feat: add BuilderTransactions abstraction for end of block builder txs - #935

Open
MavenRain wants to merge 1 commit into
flashbots:developfrom
MavenRain:feat/builder-transaction-abstraction
Open

feat: add BuilderTransactions abstraction for end of block builder txs#935
MavenRain wants to merge 1 commit into
flashbots:developfrom
MavenRain:feat/builder-transaction-abstraction

Conversation

@MavenRain

Copy link
Copy Markdown

Summary

Closes #343. Adds BuilderTransactions, a trait for the transactions the builder itself appends at the end of the block, with the two phases the issue asks for: validation plus block space reservation before building, and the list of txs to include after building.

Problem

Everything the builder adds for itself is hardcoded today. create_payout_tx has exactly three production call sites (the combined refunds, the proposer payout, the per-bundle kickback) and the space for them is reserved in one place in BlockBuildingHelperFromProvider::new_with_execution_tracer. There is no way for a builder to add a block signature, an attestation or any other tx of its own without editing the finalization path, and no way to make sure the block keeps room for it.

Fix

crates/rbuilder/src/building/builder_tx.rs adds:

  • BuilderTransactions: validate and reserve_block_space run once before building, on the state of the parent block; transactions runs at finalization and returns the signed txs to append.
  • BuilderTransactionError, named after the equivalent type in op-rbuilder's builder_tx.rs so the two builders read the same way.
  • reserve_builder_txs_block_space, which validates every registered source and folds their reservations, passing the running total so a source can fit itself into the remaining budget.

Sources are registered per block with BlockBuildingContext::with_builder_transactions. Carrying them on the context rather than on BlockBuildingHelper follows the existing Arc<dyn RootHasher> precedent and leaves the helper trait, both of its test doubles and every dyn BlockBuildingHelper call site untouched.

Two behaviors are worth calling out:

  • The proposer payout tx is not modelled as a BuilderTransactions. It has to stay the last tx of the block (PartialBlock::finalize expects it there, ReceiptsData::pre_payment_logs_bloom is defined as the bloom of everything before it, bid adjustments index len - 1, and backtests infer the fee recipient from the last tx) and its value is only known once the bid is chosen. Builder txs are inserted before it.
  • Builder txs are committed in the same window as the combined refunds, that is under !adjust_finalized_block, so a finalization adjustment re-executes only the payout tx and leaves them untouched. Letting a builder tx depend on the payout value would mean generalizing FinalizeRevertStateCurrentIteration to an N-tx tail and teaching the receipts and tx-root caches about it; that is a much larger change and is not attempted here.

The reserved gas also widens the true_block_value deduction, because the bid ceiling is read before finalization and the builder pays for its own txs. With no sources registered, end_of_block_gas == payout_tx_gas and the whole path is a no-op.

Testing

cargo test -p rbuilder --lib builder_tx, covering: only the payout tx lands when nothing is registered; builder txs land before the payout tx with consecutive nonces and the payout stays last; a reseal reverts and rebuilds only the payout tx while the builder txs survive; a tx that cannot fit fails the block; space and value reservations are summed and chained; a failed validation aborts before any reservation. The payout test harness now funds the builder signer and can build an EOA fee recipient, which is what makes committing real end-of-block txs in a unit test possible.

Note for reviewers

Where the validation hook should be used first is #296 / #929 (checking the coinbase can cover the payout before building). I did not move that check in here to keep this PR to the abstraction itself; happy to fold it in as a BuilderTransactions impl in a follow-up, or to rebase this on top of that PR if it lands first.

Adds a trait for the transactions the builder appends at the end of the
block, with a validation and block space reservation hook that runs before
building and a hook returning the txs at finalization.

Implementations are registered per block with
BlockBuildingContext::with_builder_transactions and are committed after the
accumulated refunds and before the proposer payout tx, which stays the last
tx of the block.  The space they reserve is held back for the whole build and
is included in the true block value deduction, so the bid ceiling accounts
for the gas those txs burn.

Closes flashbots#343

Signed-off-by: Onyeka Obi <softwareengineerasaservant@isurvivable.cv>
@MavenRain
MavenRain requested review from ZanCorDX and dvush as code owners July 31, 2026 14:12
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.

Abstraction for Builder Transactions at the end of the block

1 participant