Skip to content

feat(alloy-op-evm): post-exec block executor and SDM warming inspector#20213

Open
nonsense wants to merge 4 commits intodevelopfrom
nonsense/sdm/post-exec-block-executor
Open

feat(alloy-op-evm): post-exec block executor and SDM warming inspector#20213
nonsense wants to merge 4 commits intodevelopfrom
nonsense/sdm/post-exec-block-executor

Conversation

@nonsense
Copy link
Copy Markdown
Contributor

@nonsense nonsense commented Apr 21, 2026

Fixes: #20178
Fixes: #20179


This PR add post-execution refund mechanism where the sequencer detects intra-block warming and carries the resulting gas refunds in a 0x7D transaction appended at the end of the block.

Verifiers re-run the block and reject it unless the embedded payload matches what they independently computed - this is probably something we want to remove, but is a good sanity check right now.

SDM is still disabled by default at every layer.

  1. CLI flag — --rollup.sdm-enabled defaults to false. The payload builder's with_sdm_enabled(false) is what OpNode passes in. Without this flag, the sequencer's payload path is identical to pre-feature (no 0x7D injection, no try_include_post_exec_tx call).
  2. Block executor — PostExecMode::Disabled is #[derive(Default)]. Under Disabled, post_exec_refund = 0 for every tx, settlement deltas are all zero, and the canonical gas path collapses to the pre-feature behavior.
  3. No verifier path switches automatically — even after merging, no existing node code constructs an executor in Verify mode. You'd have to opt in via the new
    context_for_block_with_post_exec_mode helper, which isn't wired into any existing pipeline in this branch.

End-to-end tests are added in a follow-up PR.

Related: #20216


  • confirm that there is no change in behavior on develop with this PR

@nonsense nonsense requested a review from einar-oplabs April 21, 2026 14:03
@nonsense nonsense force-pushed the nonsense/sdm/post-exec-block-executor branch from d88b6a5 to 4fafc44 Compare April 22, 2026 11:23
@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 22, 2026

Codecov Report

❌ Patch coverage is 0% with 1326 lines in your changes missing coverage. Please review.
✅ Project coverage is 0.5%. Comparing base (11b9948) to head (052c1d6).

Files with missing lines Patch % Lines
rust/alloy-op-evm/src/block/mod.rs 0.0% 703 Missing ⚠️
rust/alloy-op-evm/src/post_exec/inspector.rs 0.0% 348 Missing ⚠️
rust/op-reth/crates/payload/src/builder.rs 0.0% 96 Missing ⚠️
rust/alloy-op-evm/src/lib.rs 0.0% 71 Missing ⚠️
rust/op-reth/crates/evm/src/post_exec_ext.rs 0.0% 62 Missing ⚠️
rust/op-reth/crates/evm/src/lib.rs 0.0% 28 Missing ⚠️
rust/alloy-op-evm/src/post_exec/mod.rs 0.0% 9 Missing ⚠️
rust/op-reth/crates/payload/src/config.rs 0.0% 8 Missing ⚠️
...ust/kona/crates/proof/executor/src/builder/core.rs 0.0% 1 Missing ⚠️

❗ There is a different number of reports uploaded between BASE (11b9948) and HEAD (052c1d6). Click for more details.

HEAD has 13 uploads less than BASE
Flag BASE (11b9948) HEAD (052c1d6)
cannon-go-tests-64 1 0
contracts-bedrock-tests 12 0
Additional details and impacted files
@@             Coverage Diff             @@
##           develop   #20213      +/-   ##
===========================================
- Coverage     75.1%     0.5%   -74.7%     
===========================================
  Files          183      489     +306     
  Lines        11304    63445   +52141     
===========================================
- Hits          8494      326    -8168     
- Misses        2666    63119   +60453     
+ Partials       144        0     -144     
Flag Coverage Δ
cannon-go-tests-64 ?
contracts-bedrock-tests ?
unit 0.5% <0.0%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
rust/op-reth/crates/rpc/src/debug.rs 0.0% <ø> (ø)
rust/op-reth/crates/rpc/src/witness.rs 0.0% <ø> (ø)
...ust/kona/crates/proof/executor/src/builder/core.rs 0.0% <0.0%> (ø)
rust/op-reth/crates/payload/src/config.rs 0.0% <0.0%> (ø)
rust/alloy-op-evm/src/post_exec/mod.rs 0.0% <0.0%> (ø)
rust/op-reth/crates/evm/src/lib.rs 0.0% <0.0%> (ø)
rust/op-reth/crates/evm/src/post_exec_ext.rs 0.0% <0.0%> (ø)
rust/alloy-op-evm/src/lib.rs 0.0% <0.0%> (ø)
rust/op-reth/crates/payload/src/builder.rs 0.0% <0.0%> (ø)
rust/alloy-op-evm/src/post_exec/inspector.rs 0.0% <0.0%> (ø)
... and 1 more

... and 661 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Add the canonical post-exec block executor, along with the first
feature riding on it — SDM (Sequencer-Defined Metering) block-level
warming refunds, delivered by the SDMWarmingInspector.

- OpBlockExecutor gains three PostExecModes (Disabled / Produce /
  Verify(payload) / Invalid). Produce accumulates per-tx refund
  entries for the payload builder to append as a synthetic 0x7D tx;
  Verify validates an embedded payload against local replay;
  Disabled is the legacy path (byte-identical to pre-SDM).
- SDMWarmingInspector tracks first-warmer provenance for accounts
  and storage slots, emits exact refund attribution events for every
  re-touch past the EIP-2929 warm threshold, and suppresses claims
  from Deposit and synthetic PostExec tx kinds.
- Verify-mode validations reject duplicate payload indexes, payload
  entries targeting deposits or the 0x7D tx itself, and refunds that
  exceed the tx's raw gas. `apply_pre_execution_changes` debug_asserts
  the Produce hooks are wired so a downstream fork can't silently drop
  refunds.
- Canonical gas settlement credits the sender, debits the beneficiary
  and base-fee recipient by the refunded-gas component of their share,
  and commits the deltas when canonical gas falls below raw gas.
- beneficiary_gas_price can legitimately saturate at zero when a
  legacy tx's gas price equals basefee; inline comment documents the
  consensus-valid zero case.
Extend op-reth's EvmConfig with the post-exec hooks the new
OpBlockExecutor expects. Downstream uses:

- The payload builder asks the executor to Produce + drains refund
  entries via post_exec_executor_for_block + take_post_exec_entries.
- The replay RPC asks for the same Produce mode but on a stripped
  block (0x7D removed) to compare synthesized refunds against the
  embedded payload.

OpEvm auto-wires the SDMWarmingInspector begin/take hooks so callers
don't have to plumb them manually; the alloy-op-evm debug_assert
guards the failure mode if a downstream fork bypasses OpEvm.
Append a type-0x7D post-exec transaction at the tail of the block
when the sequencer builds under --rollup.sdm-enabled. The tx carries
the executor's accumulated refund entries as its RLP payload and
canonicalizes this node's gas accounting with what a verifier will
later independently replay.

- OpBuilderConfig/CLI flag (`--rollup.sdm-enabled`) — off by default.
  When off, the payload path is byte-identical to the pre-feature code.
- try_include_post_exec_tx wraps the executor's refund entries in a
  TxPostExec, executes it, and aborts the payload build with
  PayloadBuilderError::EvmExecutionError on any synthetic-tx
  execution failure. Silently dropping it would yield a payload that
  no honest verifier can reproduce.
- Unit tests pin the abort path (should-not-be-Ok-on-failure), the
  no-entries skip, and the happy-path wrapping of entries.
- custom-node example switches to NoopPayloadServiceBuilder; the
  upstream OpPayloadBuilder is now specialized for OpTransactionSigned
  to carry the post-exec tx and no longer composes with the example's
  custom tx type. Doc comment explains what downstream forks need.
@nonsense nonsense force-pushed the nonsense/sdm/post-exec-block-executor branch from 4fafc44 to 8f80648 Compare April 22, 2026 12:33
…tants

- Reject 0x7D txs in Disabled/Invalid modes. Previously
  `execute_transaction_without_commit` short-circuited any post-exec
  tx regardless of mode, so a follower with SDM off would silently
  accept a payload it never validates — state would diverge without
  a loud failure.
- Reject Produce-mode refunds that exceed raw gas used. An inspector
  over-attribution would otherwise saturate canonical gas to zero
  and emit an SDMGasEntry that a verifier rejects at pre-execution;
  failing the payload build here is strictly better than shipping a
  block the sequencer can't self-verify.
- Replace the 2500/2000/2100 magic numbers in SDMWarmingInspector with
  ACCOUNT_REWARM_REFUND / SLOAD_REWARM_REFUND / SSTORE_REWARM_REFUND
  and cite the EIP-2929 derivation.
- Restore `OpBuilderConfig::new(da_config, gas_limit_config)` to its
  pre-branch 2-arg signature; add `new_with_sdm` for the SDM-aware
  constructor so external callers don't break.

Tests pin:
- Disabled/Invalid modes hard-fail at `execute_transaction` time.
- Produce mode rejects a fake over-refund take-hook.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nonsense nonsense force-pushed the nonsense/sdm/post-exec-block-executor branch from 37f0705 to 052c1d6 Compare April 22, 2026 13:42
@nonsense nonsense marked this pull request as ready for review April 22, 2026 13:43
@nonsense nonsense requested a review from a team as a code owner April 22, 2026 13:43
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.

SDM: Payload builder support for 0x7D post exec tx SDM: Execution-side block-level warming accounting

1 participant