Skip to content

Build a block for each slot from the node's mempool - #557

Open
0w3n-d wants to merge 1 commit into
od/builder-slot-context-step2from
od/builder-assemble-step3
Open

Build a block for each slot from the node's mempool#557
0w3n-d wants to merge 1 commit into
od/builder-slot-context-step2from
od/builder-assemble-step3

Conversation

@0w3n-d

@0w3n-d 0w3n-d commented Sep 1, 2026

Copy link
Copy Markdown
Collaborator

Issue: #550 (step 3 of 6)

What this PR does

Builds a block for each slot the watcher publishes. The role now runs end to
end up to the point of submission: it fills from the node's mempool, pays the
proposer, and logs the block and its value.

create_payload(gas_ceil = registered_gas_limit)   // ethrex applies the 1/1024 clamp
PayloadBuildContext::new -> apply_system_operations
ctx.remaining_gas -= payout_gas_reserve           // reserve
fill_transactions                                  // tip-sorted, from the mempool
ctx.remaining_gas += payout_gas_reserve            // restore
apply_tx_to_payload(payout)                        // trailing transfer
extract_requests -> apply_withdrawals -> finalize_payload

The coinbase is the builder, so tips accrue here and the bid is

payout = ctx.block_value + subsidy_wei - payout_gas_reserve * base_fee

Reserving the full payout_gas_reserve rather than the actual 21000 is
deliberate: it under-credits the builder slightly and can never overdraw it.

fill_transactions gates only on ctx.remaining_gas, which is pub, so the
reservation needs no ethrex change.

Two fixes to earlier steps

  • The default subsidy was unusable. At 1 gwei it could not cover the
    payout's own gas (21000 x base fee, around 2e13 wei), so every build with an
    idle mempool failed. Raised to 0.001 ETH. an_empty_mempool_still_bids_the_subsidy
    caught this; step 1's assertions are updated to match.
  • The step 2 SlotContext drain in main.rs is replaced by the real consumer,
    so nothing is dead.

What this PR deliberately does not do

No signing and no submission — BuiltBlock's blobs_bundle, requests and
account_updates carry #[allow(dead_code)] until step 4 consumes them. No
custom ordering: this uses ethrex's tip-sorted fill_transactions. No in-slot
rebuilding; the block is built once per slot event.

Tests

13 new, written before the implementation and signed off first, all against a
real chain (dev_genesis_store + funded_signers) with transactions admitted
through add_transaction_to_pool.

  • The block (3): mempool txs are included; the block extends the parent with
    the builder as coinbase; the header gas limit follows the registered limit
    through ethrex's clamp.
  • The payout (4): it is last, is a plain zero-tip transfer to the fee
    recipient, and pays exactly the bid; the bid matches the formula; the fee
    recipient's balance rises by the bid
    , checked against the parent state the
    way the relay's paid_by_balance does; and the reserve survives a full block
    — without it that test fails, which is the point.
  • Refusals (4): an idle mempool still bids the subsidy; zero subsidy with no
    tips is refused; an unaffordable payout is refused; paying ourselves is
    refused. A bad slot is skipped with a typed error, never submitted broken.
  • Consensus (2): withdrawals are applied; a blob transaction reaches the block
    with the sidecar the mempool holds.

127 pass in the crate.

Reviewer checklist

  • CI (lint, unit-test) is green
  • Matches the linked issue/step
  • No unexplained scope creep or unrelated files touched

Reserve the payout gas by lowering `remaining_gas` before the fill and
restoring it after. `fill_transactions` spends the whole budget.

Raise the default subsidy to 0.001 ETH. At 1 gwei the old default could
not cover the payout's own gas, so every idle slot was skipped.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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