Skip to content

Reject blocks that interact with a blacklisted address - #535

Open
0w3n-d wants to merge 1 commit into
od/builder-sim-payment-step5from
od/builder-sim-blacklist-step6
Open

Reject blocks that interact with a blacklisted address#535
0w3n-d wants to merge 1 commit into
od/builder-sim-payment-step5from
od/builder-sim-blacklist-step6

Conversation

@0w3n-d

@0w3n-d 0w3n-d commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Issue: #527 (step 6 of 10)

Base branch: od/builder-sim-payment-step5 (#534, step 5). Retarget as the stack
merges.

What this PR does

Rejects a block that interacts with a listed address, where interaction means
effect:

  1. the coinbase or the bid trace's proposer_fee_recipient, checked directly
    because neither has to change state — a block with no priority fees leaves
    the coinbase untouched, and an unpaid recipient stays absent from the state;
  2. any transaction's to, since a call that changes nothing leaves no account
    update behind;
  3. any address in the execution's account_updates: senders, created accounts,
    value recipients and storage writes.

validate and validate_merged take apply_blacklist, so a non-filtering
proposer's block skips the check.

Rule 3 makes reth's DatabaseLogger unnecessary. The account updates execute
already returns are the set of accounts execution changed, so no read-tracking
database wrapper is needed at all.

Deliberate divergence from the reth simulator

reth rejects a block that merely reads a listed account during execution: it
scans every account touched in the revm cache. That over-approximates — an
unrelated read trips it. This simulator rejects only interaction by effect.

The two therefore disagree on one class of block, and a builder's verdict depends
on which simulator drew the request. The direction is the safer one (fewer false
positives, not more false negatives), and an_account_that_is_only_read_is_not_blacklisted
records it. If they should be aligned, the fix is to move this rule into
helix-common and switch reth to it, the same shape as #533.

What this PR deliberately does not do

No blacklist refresh task. The list is an injected Arc<DashSet<Address>>;
polling blacklist_endpoint arrives with the servers in step 9.

Tests

Written first and signed off before implementation. 9 new, 41 in the file:

  • Listed sender, recipient, coinbase and proposer fee recipient each rejected.
  • A listed internal value target is rejected: the forwarder sends it the
    value, so it never appears as any transaction's to and only the state change
    reveals it. This is what rule 3 buys.
  • A listed created account is rejected, its address derived from creator and
    nonce.
  • An account that is only read is accepted, with a five-byte probe contract
    (PUSH0 CALLDATALOAD BALANCE POP STOP) in the genesis. The test asserts the
    probe's receipt succeeded, so it cannot pass by the call having failed.
  • A block touching nothing listed passes, and apply_blacklist = false skips the
    check.

just fmt-check, just test and cargo clippy --all-features --no-deps -- -D warnings
are clean. 75 tests pass in helix-builder, up from 66.

Reviewer checklist

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

Interaction means effect: a state change, or a transaction addressed to
the account. The coinbase and the proposer fee recipient are checked
directly, since neither has to change state.

Reading an account is not interaction. The reth simulator rejects such a
block, so the two disagree; see the test that records it.

Step 6 of #527.

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