Skip to content

Simulate merged blocks and disable block merging on builder-attributable failures - #508

Open
0w3n-d wants to merge 1 commit into
od/merged_block_sim_step2from
od/merged_block_sim_step3
Open

Simulate merged blocks and disable block merging on builder-attributable failures#508
0w3n-d wants to merge 1 commit into
od/merged_block_sim_step2from
od/merged_block_sim_step3

Conversation

@0w3n-d

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

Copy link
Copy Markdown
Collaborator

Issue: #500 (step 3 of 4)

Base branch: od/merged_block_sim_step2 (step 2, #506) -- stacked per CONTRIBUTING.md, not yet merged. Diff will shrink as earlier steps merge and this retargets down toward develop.

What this PR does

BlockMergingTile now sends every accepted merged block to the simulator via SimRequest::ValidateMerged, in addition to (not instead of) its existing immediate forward to the auctioneer -- the serving path is unchanged. The tile becomes a consumer of from_sim (confirmed via the spine-derive macro source that every spine queue defaults to MPMC unless explicitly flagged flavour("spmc"), so no queue-declaration change was needed for a second producer/consumer) and filters for its own tagged SimResult::ValidateMerged results, ignoring the auctioneer's ordinary submission-validation results that flow through the same queue.

On a builder-attributable failure, block merging is disabled -- which alone triggers the existing force-disconnect gating from #502, so no separate disconnect call is needed here -- and a critical Discord alert fires with the block hash, merge builder endpoint, and reason. "Builder-attributable" reuses BlockSimError::is_demotable() (the same logic used for bid-submission builder demotion) but additionally excludes SendError/SimulationDropped/HydrationMiss, since those are relay/simulator-side infra hiccups rather than anything the merge builder did wrong -- is_demotable() alone doesn't exclude them since it was calibrated for the bid-submission-demotion use case. Temporary/infra errors and successes take no action. Nothing except the admin endpoint from #502 ever re-enables merging.

SlotState gains registered_gas_limit/apply_blacklist/inclusion_list, captured from the same validator-registration and slot-event data that already feeds fee_recipient, to build each merged block's simulation request context.

What this PR deliberately does not do

No portal/admin-UI wiring for re-enabling merging -- that's step 4.

Tests

Written first, reviewed (including a correction: the initial draft classified SendError/SimulationDropped as disable-worthy since is_demotable() alone returns true for them; excluded per review since they're relay-side infra failures, not builder faults), then implemented against. The disable decision is extracted as a pure function (merge_sim_disable_check) so it's testable without constructing a full tile or triggering the (otherwise safe, since it's a no-op without a configured webhook URL) Discord alert call:

  • merge_sim_disable_check_table: every BlockSimError variant/reason against expected disable/no-disable outcome.
  • merge_sim_disable_check_reports_block_hash: the reported hash matches the actual merged block.
  • merge_sim_disable_check_none_on_success: a successful simulation never disables merging.

just fmt-check, cargo clippy --all-features --no-deps -- -D warnings, and just test (full workspace) all pass.

Reviewer checklist

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

…ble failures

BlockMergingTile now sends every accepted merged block to the simulator
via SimRequest::ValidateMerged, in addition to (not instead of) its
existing immediate forward to the auctioneer -- the serving path is
unchanged. The tile becomes a consumer of from_sim (already MPMC per
spine-derive's defaults, confirmed no queue-declaration change needed)
and filters for its own tagged SimResult::ValidateMerged results,
ignoring the auctioneer's ordinary submission-validation results on the
same queue.

On a builder-attributable failure, block merging is disabled -- which
alone triggers the existing force-disconnect gating from the previous
step, so no separate disconnect call is needed -- and a critical Discord
alert fires with the block hash, merge builder endpoint, and reason.
"Builder-attributable" reuses BlockSimError::is_demotable() (the same
logic used for bid-submission builder demotion) but additionally
excludes internal channel/queue failures (SendError, SimulationDropped,
HydrationMiss), which are relay/simulator-side infra hiccups rather than
anything the merge builder did wrong. Temporary/infra errors and
successes take no action. Nothing except the admin endpoint from the
first step ever re-enables merging.

SlotState gains registered_gas_limit/apply_blacklist/inclusion_list,
captured from the same validator-registration and slot-event data that
already feeds fee_recipient, to build each merged block's simulation
request context.

Co-Authored-By: Claude Sonnet 5 <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