Skip to content

[wip] feat(rex7): checkpoint compute gas settlement with V0 gas clamp enforcement - #367

Open
RealiCZ wants to merge 43 commits into
cz/chore/upgrade-revm-40from
cz/feat/rex7-checkpoint-gas
Open

[wip] feat(rex7): checkpoint compute gas settlement with V0 gas clamp enforcement#367
RealiCZ wants to merge 43 commits into
cz/chore/upgrade-revm-40from
cz/feat/rex7-checkpoint-gas

Conversation

@RealiCZ

@RealiCZ RealiCZ commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

Summary

Rex7 replaces per-opcode compute-gas recording with checkpoint settlement, and replaces post-opcode limit checking inside plain segments with gas-clamp enforcement. Roughly 140 plain opcodes now dispatch to revm's own instructions with no wrapper at all: the interpreter's gas counter is the accounting source, and compute gas settles as a segment delta at each checkpoint. Enforcement inside a segment is delegated to revm's own per-opcode gas check by hiding the gas above the remaining compute headroom, so a limit-crossing opcode is stopped before it executes rather than being caught after it has already run.

The checkpoints are exactly the positions that had to stay wrapped anyway — the storage-gas opcodes, the CALL / CREATE family, the volatile / detention opcodes, GAS, and frame entry / resume / exit — so the change removes metering cost without adding any new one. The interpreter_hotloop benchmark drops from 1.81 ms to 0.96 ms (−47%), which is the vanilla-revm floor for that workload.

For a transaction that stays inside every resource limit and in which no frame ends in an exceptional halt, Rex7 is bit-identical to Rex6: same gas, same receipt, same state, same GAS readings, same recorded compute total. Segment sums telescope to the per-opcode sums exactly.

Rex7 is the unstable spec and is not scheduled on any network.

What changed

Checkpoint settlement. The Rex7 instruction table starts from revm's own table and overrides only the checkpoint entries. Each checkpoint opens with checkpoint_prologue! — settle the open segment as baseline − remaining, hand the clamp-hidden gas back so the body runs on the true counter, re-open the window — and closes with checkpoint_epilogue!, which re-applies the clamp against the freshly settled usage. Storage-gas charges are excluded from the open segment as they are taken, so the exclusion survives a body that aborts before its own measurement window closes.

Gas clamp. At each checkpoint exit, frame entry, and frame resume, interpreter-visible gas is clamped to min(frame remaining compute budget, tx-level remaining under the effective limit). The constraint that bound the clamp is captured at the moment it is applied, so a clamp-induced out-of-gas is classified against what was actually in force: frame-local budget becomes a frame revert with MegaLimitExceeded carrying the frame's own budget, transaction-level becomes an OutOfGas halt with gas rescue, and a detained limit becomes VolatileDataAccessOutOfGas with the same rescue. The clamp is unobservable to a transaction that never exceeds a limit: GAS, call-gas forwarding, and storage-gas charges all see the restored counter.

Exceptional-halt carve-out. A frame that ends in an exceptional halt returns none of its budget, so that budget has to be settled as compute gas — but not as one number. The executed part (the open segment, less any storage gas a checkpoint body charged before aborting) records through the ordinary enforcing path, because a parent frame keeps executing after absorbing a failed child and leaving that work out of enforcement would let the following code spend the same headroom twice. The destroyed part (whatever the frame still held when its result became final) is reported and accumulated but never compared against any limit, at transaction level or block level — enforcing it would turn an ordinary EVM halt into a resource-limit failure with the gas rescued, changing a receipt this carve-out requires to keep identical.

The split is taken from the frame's final result, after the create-return processing that can still turn a successful constructor into a code-deposit out-of-gas, an EIP-3541 reject, or a runtime code-size reject.

Spec migration rebuilds the limit tracker. AdditionalLimit latches spec-derived flags at construction, and MegaContext::with_cfg used to keep every latch from construction time when the incoming cfg migrated the spec. It now rebuilds the tracker from the new spec (keeping the configured runtime limits) so the latched state cannot diverge from the context's spec, pinned by migration regression tests in both directions and both builder orders. Checkpoint gating itself stays a runtime spec check inside the shared handlers, matching the upstream revm idiom; the frame-dense bench_subcall microbenchmarks for the frozen specs pay a small instruction-count overhead for those checks, which is acknowledged — realistic-shape benchmarks are unaffected.

Public API changes (mega-reth integration surface)

  • MegaTransactionOutcome gains compute_gas_destroyed: u64.
  • BlockLimiter splits compute gas into two counters: block_compute_gas_used (full reported total, semantics unchanged) and the new block_compute_gas_enforced (the counter block admission compares).
  • BlockLimiter::post_execution_update_raw takes compute_gas_destroyed as a new parameter (8 → 9 arguments).
  • New sandbox::SandboxUsage { usage: LimitUsage, burned_compute_gas: u64 }; SandboxOutcome::Completed.limit_usage changes type accordingly.
  • MegaBlockLimitExceededError::ComputeGasLimit.block_used now reports the enforced reading — the counter that was actually compared.

A consumer that accumulates compute_gas_used into any further limit must subtract compute_gas_destroyed first.

Deliberate deviations from Rex6

Each of these is documented in docs/spec/upgrades/rex7.md:

  1. Exceptional halts report more compute gas. A transaction that halts exceptionally, or that contains an inner frame which does, may report a strictly higher compute total than under Rex6. EVM gas, the receipt, and the outer transaction's success or failure are unchanged.
  2. One shape enforces more strictly. An ordinary out-of-gas taken with no clamp in force arrives at frame exit with the interpreter's counter already zeroed by revm, so the whole segment measures as executed and is enforced in full. The split cannot be recovered there, and the fail-closed reading is the one that does not let destroyed budget escape accounting.
  3. Top-frame tie-break. When the frame's remaining compute budget equals the transaction-level remaining budget, the clamp binds to the transaction-level constraint, so the exceed halts with gas rescue. Rex6 classifies the same equality as frame-local, which the top-level frame absorbs into a revert.
  4. Double-exceed preference. When the crossing opcode would exhaust both the true remaining EVM gas and the compute headroom, the halt is attributed to the compute limit, which is the classification that preserves the sender's refund.
  5. actual may exceed limit. The actual on a compute-gas halt reason is the transaction's full reported total, which carries destroyed remainders that were never enforced.

Testing

New suites under crates/mega-evm/tests/rex7/ (86 tests): checkpoint settlement, gas-clamp enforcement, the executed/destroyed burn split, exceptional halts, clamp classification, gas-leakage paths under an active clamp, latch surfacing, interceptor and precompile resume settlement, Rex6/Rex7 parity across transaction shapes, the double-exceed corner, and a parity case for every checkpoint opcode. Block-level lane separation is covered by tests/block_executor/compute_gas_lanes.rs.

cargo test -p mega-evm is green across all 14 test binaries. Spec-migration parity with direct construction (with_cfg in both directions and both builder orders) is pinned by regression tests in crates/mega-evm/src/evm/context.rs.

Notes for reviewers

This branch is stacked on #365 (revm 40.0.3 upgrade) and targets cz/chore/upgrade-revm-40, so the diff here excludes the revm upgrade itself.

Marked WIP: the semantics above are settled and implemented, but Rex7 is unfrozen and a few questions are still open — whether the destroyed remainder belongs in the reported total at all given that block_compute_gas_used is the block's public compute statistic, whether the two clamp-induced halt paths (OutOfGas vs MemoryOOG, which differ in whether revm zeroed the counter) should be converged, and whether SandboxUsage's shape is the one mega-reth wants to consume.

RealiCZ added 30 commits August 11, 2026 14:54
Plain opcodes in the REX7 instruction table run revm's raw instructions with
no per-opcode recording; compute gas settles as an interpreter-gas delta at
each checkpoint (storage-gas opcodes, CALL/CREATE family, volatile opcodes,
frame entry/resume/exit). Per-transaction totals are unchanged; a limit
exceed now surfaces at the next checkpoint. Specs <= REX6 are untouched.
Covers plain segments, SSTORE/LOG, SLOAD, the CALL family (success, revert,
nested), CREATE/CREATE2, SELFDESTRUCT, volatile detention below the cap and
the GAS reading, each with minimum and scaled SALT buckets. Also pins the two
places the models differ: checkpoint-coarsened halts and out-of-gas frames.
At every checkpoint and frame entry/resume the interpreter's visible gas is
clamped to the compute headroom -- the tighter of the frame-local budget and the
TX-level detained limit -- and the hidden remainder is recorded together with the
constraint that bound it. revm's own per-opcode gas check then stops a crossing
opcode at the clamp boundary before it executes, so a plain-opcode segment is
bounded with no per-opcode accounting at all.

Checkpoint handlers gain a prologue (settle the open segment, restore the clamp
so CALL forwarding, GAS and storage charges observe the true counter) and an
epilogue (re-clamp against the possibly detained headroom). GAS joins the
checkpoint set so the clamp stays unobservable. The frame's final result restores
the hidden gas and reclassifies a clamp-induced out-of-gas as the compute exceed
it stands for: frame-local binding reverts to the parent, TX-level binding halts
with the gas rescued, and detention keeps its VolatileDataAccessOutOfGas
attribution.

Transactions that stay inside every limit remain bit-identical to per-opcode
accounting; a crossing now halts one opcode earlier, with that opcode's cost
excluded from the recorded usage. Specs <= REX6 are unchanged.
Pins that the clamp is unobservable through GAS, that a crossing opcode is
stopped before it executes with its cost excluded from usage, that a detention
cap is enforced inside a checkpoint-free loop, and that a clamp-induced
out-of-gas is reclassified by whichever constraint bound the clamp (frame-local
revert, TX-level halt with rescue, volatile-detention attribution) including the
double-exceed corner where the compute classification wins.

The checkpoint-settlement suite's enforcement case is updated from the
checkpoint-deferred halt to the V0 halt position.
A frame-local compute exceed reports as a revert, which the per-opcode layering
carries past the detention tail rather than returning on, so the cap is installed
even though the frame is about to unwind; a TX-level exceed reports as an
out-of-gas halt, which that layering short-circuits on. The volatile checkpoint
handlers now reproduce both arms when recording their own body, instead of
returning on either.

Adds a REX6/REX7 parity test for a volatile checkpoint whose own body crosses the
compute limit, covering the halt, the recorded usage and the resulting detained
limit together.
Record REX7 checkpoint settlement and V0 gas-clamp enforcement on the
upgrade page, gate matching rules under details on compute-gas and
related metering pages, and update AGENTS.md protocol wording.
…e-break

Document that per-opcode enforcement (through Rex6) reports actual > limit
while gas-clamp enforcement (Rex7+) reports actual ≤ limit on compute and
detention halts. Normatively state that equal frame and TX remaining headroom
binds the clamp to the TX level (halt + rescue), unlike Rex6's frame-local
revert classification at the top frame.
The clamp used a zero hidden amount as the sentinel for "no clamp", which
also happens to be what an exactly-equal clamp hides. A segment whose true
remaining matched the compute headroom therefore enforced the limit but was
never reclassified: the crossing opcode's ordinary out-of-gas propagated as
an EVM out-of-gas, with no gas rescue and no MegaLimitExceeded payload.

Record the clamp as state instead — present exactly while it binds, carrying
the constraint it was bound to — so the equal case reclassifies like every
other clamp, and a segment whose own gas runs out first records no clamp at
all and keeps the EVM's own out-of-gas.
The frame-exit settlement read the interpreter's counter, and the
interpreter zeroes that counter only for a plain out-of-gas. Memory OOG,
stack underflow/overflow, invalid jump and unknown opcode all keep their
loop-exit reading and have their remainder burned later by the frame-return
rules, so the settlement saw almost none of it: a transaction that burned
its whole million-gas envelope on a memory OOG reported 21,009 compute gas,
and that figure feeds the block-level compute accounting.

Drive the settlement off the halt classification instead, and cover the
whole remainder the frame still held at the last checkpoint, including gas
the V0 clamp was hiding from the interpreter.

The burn is recorded outside limit enforcement. It is gas the EVM destroyed
rather than work the network performed, and it is bounded by the sender's
gas envelope rather than by the compute limit, so enforcing it would turn an
ordinary EVM halt into a resource-limit failure with the remaining gas
rescued — changing a receipt the carve-out requires to stay identical. No
enforcement is lost: the executed part of an exceptionally halted frame's
tail is bounded by the clamp or by a frame gas remainder that was already
under the headroom.
A clamp bound to a sub-frame's compute budget latched the transaction-level
limit into the exceed. The frame-local revert then carried that number in
its MegaLimitExceeded payload, where the calling contract can decode it and
branch on it: the same nested call that reverts with limit=956851 under
per-opcode enforcement reverted with limit=1000000 under the clamp.

Carry the binding constraint's own limit on the clamp and latch that, so
both paths report the budget that actually stopped execution.
The clamp exceed is latched at the frame's final result, and the frame-exit
settlement that closes the partial plain segment runs after it. The latch is
sticky, so the halt reason kept the pre-settlement snapshot: a transaction
ending on 21,500 compute gas reported ComputeGasLimitExceeded.actual =
21,000.

Re-read the usage from the tracker once the settlement has closed, which is
what the detention path already effectively does by rebuilding its reason
from live usage.
The helper's contract said the two runs must be indistinguishable, and the
precision invariant names state explicitly, but the assertion never looked
at it: two specs producing the same result and the same usage from different
account or storage state passed.

Compare a normalised view — account info, code, status flags, and each
slot's original/present pair. Raw EvmState carries journal bookkeeping
(`transaction_id`, per-slot `is_cold`) that identical runs can legitimately
differ on.
The exceptional-halt carve-out was written around the interpreter zeroing
its own gas counter, which it does only for ordinary out-of-gas, and said
nothing about whether the burned remainder enforces. State the rule by halt
classification, and state that the burn is reported but never evaluated
against a limit.

The clamp section now says when the clamp is in force — an exact equality
binds and hides nothing — and pins the two fields a clamp-induced exceed
reports: the binding constraint's own limit, and the transaction's final
compute usage rather than a pre-settlement snapshot.
An exceptional halt settled its whole open segment plus the clamp-hidden
gas into the non-enforcing lane, so the opcodes the frame had already
run stopped counting against the parent frame and the transaction. Code
that keeps executing after absorbing the failure could then spend the
same compute headroom a second time.

Split the settlement in two: the executed tail settles through the
ordinary enforcing path at frame exit, and only the remainder the frame
destroys goes to the non-enforcing lane. The destroyed part is read
from the frame's final result after action processing, which is also
the first point the classification is final -- revm's create-return can
still turn a successful constructor into a code-deposit out-of-gas, an
EIP-3541 reject or a runtime code-size reject.

The reported total is unchanged for every shape that was already
correct; what moves is which half of it enforces.
A checkpoint body charges its storage gas before running the raw
opcode and subtracts it back out when it records its own compute
window. A body that halts in between -- LOG in a static frame,
SELFDESTRUCT whose inner instruction runs out of gas -- never reaches
that subtraction, so the frame-exit settlement reported the charge as
compute gas.

Exclude the charge from the open segment as it is made, at every site
that debits MegaETH storage gas from inside a checkpoint body. The
normal path re-syncs the segment right afterwards, so nothing changes
there.
The KeylessDeploy sandbox exported one compute total, whose REX7
reading already includes the remainders its exceptionally halted frames
destroyed. The parent merged that as ordinary usage and then ran a
post-merge limit check, so a burn that the sandbox itself never
enforced became enforcing the moment it crossed the boundary -- turning
a constructor's ordinary EVM halt into an outer ComputeGasLimitExceeded
with the gas rescued.

Carry the split across in SandboxUsage and merge the two lanes
separately, so the parent reports the sandbox's whole total and
enforces only the part the sandbox performed.
The clamp stops the crossing opcode before it executes, so the usage
being enforced stays at or below the limit -- but the reported actual
is the transaction's full total, which also carries the remainders of
any frame that halted exceptionally earlier. Those are reported and
never enforced, so actual can be larger than limit.
Covers the four faces the executed half has to bind (transaction
compute limit, the caller's remaining-budget reading, the detention cap
base), the two boundaries that decide what belongs to which half (a
checkpoint's storage charge, revm's post-action create rejects), the
sandbox merge, and the inspected execution loop.

The code-deposit claim in the compute-gas suite moves from an EIP-3541
rejection to an empty deploy: under REX7 a failed deposit destroys the
CREATE frame's whole remainder, which dwarfs the charge under test.
…frame

Rewrites the carve-out in the upgrade page and the compute-gas spec:
which half enforces, where the split is taken from, what happens at the
sandbox boundary, and the one shape the split cannot recover -- an
ordinary out-of-gas with no clamp in force, whose zeroed counter makes
the whole segment measure as executed.

Also corrects the clamp contract: what a clamp keeps at or below the
limit is the enforced usage, and the reported actual can be larger
because it carries earlier frames' destroyed remainders.
The executed / destroyed split stopped at the transaction tracker. The
outcome carried one compute number -- the full reported total, destroyed
remainders included -- and the block limiter accumulated it into the one
counter it compares against the block compute-gas limit. A transaction
that destroyed a large gas envelope while performing almost no work
therefore closed the block's compute capacity for the transactions behind
it, re-enforcing at block level exactly what the transaction level had
excluded.

Carry the destroyed part through MegaTransactionOutcome into the commit
path, and give the limiter two counters: block_compute_gas_used keeps
reporting every transaction's whole total, while a new enforced counter
carries only the work performed and is what admission, the block-full
predicate and the ComputeGasLimit error read. Nothing is destroyed before
Rex7, so the two counters advance in lockstep on every frozen spec.
Drives both block compute-gas counters through the real run/commit path
in the two shapes that destroy a remainder: an ordinary frame that halts
on its first opcode, and one nested inside the KeylessDeploy sandbox,
where the outer transaction succeeds and nothing in its result hints
that a remainder was destroyed at all.

Each asserts the block reports the whole total, enforces only the work
performed, and still admits the cheap transaction behind it. Two more
pin the other directions: executed work does still close a block, and
Rex6 keeps the two counters identical.
State the block-level half of the exceptional-halt carve-out: a node
that tracks cumulative block compute gas tracks two readings, reports
the one that carries destroyed remainders and compares the one that does
not. The carve-out already said no resource limit is evaluated against a
destroyed remainder; it did not say which counter a block-level ceiling
is allowed to read, which is where the rule was lost.
…rames

The within-limit bit-identical claim conflicted with the exceptional-halt
carve-out: a StackUnderflow inside all resource limits can still diverge
on reported compute total. Require that no frame ends in an exceptional
halt before asserting compute-total / four-dimension parity with Rex6.
@mega-maxwell

mega-maxwell Bot commented Aug 13, 2026

Copy link
Copy Markdown

Claude review status

Living comment — rewritten in place. The review workflow keeps this single comment up to date instead of posting a new one each round, so it always describes the latest reviewed commit and the earlier text is intentionally gone. No reply is needed here; reply to a finding in its own review thread, and answer an open question in a reply on this PR. The next review round reconciles your answer.

🛠️ Review did not finish

Attempted 0047ff0d..f849383f · updated 2026-08-13T07:32:13+00:00

This round did not publish: MODEL_ACTION_FAILED in phase review_retry. Anything listed below is from the last round that did. Re-run the workflow or push a new commit to try again.

@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 96.44970% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.7%. Comparing base (ccdeba2) to head (f849383).

Files with missing lines Patch % Lines
crates/mega-evm/src/evm/instructions.rs 93.6% 7 Missing and 2 partials ⚠️
crates/mega-evm/src/limit/limit.rs 95.8% 1 Missing and 4 partials ⚠️
crates/mega-evm/src/limit/compute_gas.rs 94.7% 1 Missing and 1 partial ⚠️
crates/mega-evm/src/block/limit.rs 97.8% 0 Missing and 1 partial ⚠️
crates/mega-evm/src/limit/frame_limit.rs 80.0% 1 Missing ⚠️

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed-hq

codspeed-hq Bot commented Aug 13, 2026

Copy link
Copy Markdown

Merging this PR will regress 12 benchmarks

⚠️ Different runtime environments detected

Some benchmarks with significant performance changes were compared across different runtime environments,
which may affect the accuracy of the results.

Open the report in CodSpeed to investigate

⚡ 7 improved benchmarks
❌ 12 regressed benchmarks
✅ 363 untouched benchmarks
🆕 8 new benchmarks

Warning

Please fix the performance issues or acknowledge them on CodSpeed.

Performance Changes

Benchmark BASE HEAD Efficiency
rex5 2.3 ms 2.5 ms -8.42%
rex6 2.3 ms 2.5 ms -8.26%
rex4 2.4 ms 2.6 ms -8.04%
mini_rex 2.1 ms 2.2 ms -6.73%
rex5 5.1 ms 5.4 ms -6.15%
rex4 5 ms 5.3 ms -6.14%
rex6 5.2 ms 5.5 ms -6.06%
mini_rex 2.4 ms 2.6 ms -5.76%
mini_rex 4.4 ms 4.6 ms -5.6%
rex4 2.8 ms 2.9 ms -5.55%
rex5 2.8 ms 3 ms -5.15%
rex6 2.9 ms 3 ms -5.06%
rex7 371.3 ms 187.3 ms +98.23%
rex7/compute_only_500 346.4 µs 301 µs +15.09%
rex7/volatile_then_compute_500 346.6 µs 301.7 µs +14.91%
rex7/baseline_add 132.9 µs 123.2 µs +7.92%
rex7 2.9 ms 2.7 ms +6.99%
rex7 198 µs 186.1 µs +6.37%
rex7 180.8 µs 170.3 µs +6.17%
🆕 equivalence N/A 9.7 ms N/A
... ... ... ... ...

ℹ️ Only the first 20 benchmarks are displayed. Go to the app to view all benchmarks.

Tip

Investigate this regression by commenting @codspeedbot fix this regression on this PR, or directly use the CodSpeed MCP with your agent.


Comparing cz/feat/rex7-checkpoint-gas (f849383) with cz/chore/upgrade-revm-40 (ccdeba2)

Open in CodSpeed

@RealiCZ RealiCZ added spec:unstable Changes to the unstable spec (currently REX5) api:breaking Crate interface change — downstream users must update comp:core Changes to the `mega-evm` core crate comp:doc Changes in the documentation labels Aug 13, 2026
@github-actions

Copy link
Copy Markdown

🧬 Mutation testing — ✅ PASS

Diff mutation score: 100.0% (4/4 viable mutants killed)

  • caught: 4
  • survived (real gaps): 0
  • timed out (inconclusive): 0
  • suppressed (equivalent/dead-code): 0
  • unviable: 0 · timeout total: 0

No new test gaps introduced by this change. 🎉

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 0047ff0de4

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

);
}
}
self.settle_exceptional_halt_burn(result);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Settle exceptional-halt burns after inspector callbacks

When inspected execution is enabled, inspect_frame_run invokes after_frame_run before frame_end, but frame_end is explicitly allowed to transform the final result and gas. Consequently, an inspector that changes a halt to a revert/success, changes a success to a halt, or adjusts the remaining gas leaves burned_compute_gas based on the pre-inspector result, causing MegaTransactionOutcome and block compute-gas admission to diverge from the frame result actually returned. Defer exceptional-halt burn settlement until after frame_end has finalized the inspected result.

AGENTS.md reference: crates/mega-evm/src/evm/AGENTS.md:L22-L23

Useful? React with 👍 / 👎.

{
rex6::instruction_table::<WIRE, H>()
use revm::bytecode::opcode::*;
let mut table = instructions::instruction_table::<WIRE, H>();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Update the scoped Rex7 table guidance

This implementation now constructs Rex7 directly from revm's raw instruction table and overrides its checkpoint opcodes, but crates/mega-evm/src/evm/AGENTS.md still tells future contributors that Rex7 aliases its predecessor and expresses its delta only through shared-handler spec dispatch. That repository guidance is now false and can cause later opcode changes or reviews to inspect and modify the wrong layer; update it to describe the new standalone checkpoint table.

AGENTS.md reference: crates/mega-evm/src/evm/AGENTS.md:L25-L26

Useful? React with 👍 / 👎.

@github-actions

github-actions Bot commented Aug 13, 2026

Copy link
Copy Markdown

🧬 Mutation testing — ❌ FAIL

Diff mutation score: 88.5% (46/52 viable mutants killed)

  • caught: 46
  • survived (real gaps): 6
  • timed out (inconclusive): 0
  • suppressed (equivalent/dead-code): 0
  • unviable: 53 · timeout total: 0

Survivors needing attention

Each mutation below changed the code but no test failed. Add a test that kills it, or — if it is provably equivalent/dead — add a justified entry to mutants/suppressions.toml.

  • crates/mega-evm/src/evm/instructions.rs:2233:19: replace == with != in volatile_data_ext::sload_checkpoint
  • crates/mega-evm/src/evm/instructions.rs:2233:46: replace && with || in volatile_data_ext::sload_checkpoint
  • crates/mega-evm/src/evm/instructions.rs:2255:34: replace && with || in volatile_data_ext::selfbalance_checkpoint
  • crates/mega-evm/src/evm/instructions.rs:2255:19: replace == with != in volatile_data_ext::selfbalance_checkpoint
  • crates/mega-evm/src/limit/limit.rs:340:60: replace && with || in AdditionalLimit::latch_clamp_exceed
  • crates/mega-evm/src/limit/limit.rs:341:47: replace < with <= in AdditionalLimit::latch_clamp_exceed

Tip: run /improve-mutation-score to triage and fix these.

with_cfg / with_cfg_unpinned now reconstruct AdditionalLimit from the new
spec and the already-configured runtime limits so tracker latch bits stay
aligned with MegaContext.spec.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fc0fab97da

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +854 to +855
let remaining = $context.interpreter.gas.remaining();
let segment = additional_limit.checkpoint_baseline().saturating_sub(remaining);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Exclude inspector gas edits from checkpoint deltas

When inspected REX7 execution is used, inspect_instructions invokes mutable step/step_end callbacks inside this baseline window, so any inspector that debits gas is counted as compute at the next checkpoint while a gas increase suppresses real opcode usage through the saturating subtraction. REX6 records inside each opcode handler before step_end, so the same inspector produces different compute totals and can change limit outcomes; checkpoint accounting should resynchronize around inspector callbacks or otherwise exclude their gas edits.

AGENTS.md reference: crates/mega-evm/src/evm/AGENTS.md:L22-L23

Useful? React with 👍 / 👎.

<details>
<summary>Rex7 (unstable): checkpoint settlement of compute gas</summary>

Under Rex7, the metering order above continues to govern every **checkpoint** opcode — the storage-affecting set listed in this section, the volatile / detention-guarded set, and `GAS` — and those checkpoints still charge storage gas before the body and record compute gas after it.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Limit storage-gas wording to storage checkpoints

This sentence says every listed checkpoint—including volatile opcodes and GAS—charges storage gas before its body, but those handlers charge only ordinary compute gas; only storage-affecting checkpoints apply a storage-gas surcharge. Because this is normative protocol documentation, an independent implementation following the statement would deduct nonexistent storage gas and produce different gas accounting, so qualify the charge as applying only where the checkpoint has a storage-gas component.

AGENTS.md reference: docs/spec/AGENTS.md:L113-L114

Useful? React with 👍 / 👎.

Comment thread crates/mega-evm/src/evm/instructions.rs Outdated
Comment on lines +2524 to +2526
// REX7: settle the open segment and restore the clamp before any gas observation,
// so the storage charge and the body's 63/64 forwarding math see the true counter.
checkpoint_prologue!(context, CHECKPOINT);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the clamp before charging CALL static gas

For REX7, this prologue is reached only after the outer volatile_data_ext::wrap_call_volatile_check has debited the CALL-family static cost. If the clamped compute headroom is smaller than that cost while the true EVM gas is sufficient, the outer debit fails before this restoration runs, so a checkpoint opcode is incorrectly treated as a plain-segment crossing: its body never loads or warms the target, beneficiary detention is not triggered, and the static cost is excluded from usage. Put the checkpoint prologue outside that debit so CALL checkpoints execute on the true counter and enforce after their body.

AGENTS.md reference: crates/mega-evm/src/evm/AGENTS.md:L17-L19

Useful? React with 👍 / 👎.

Comment on lines 690 to 691
pub(super) const fn gas_table(table: GasTable) -> GasTable {
rex6::gas_table(table)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Move the GAS static charge behind its checkpoint prologue

The REX7 gas table inherits the nonzero static entry for GAS, so the interpreter charges its 2 gas before dispatching gas_checkpoint. With an active clamp and less than 2 compute headroom but ample true EVM gas, dispatch fails before the handler can restore hidden gas, incorrectly classifying this checkpoint as a plain-opcode clamp crossing and returning the uncharged cost on a frame-local revert. Zero the REX7 GAS table entry and charge it explicitly after the checkpoint prologue.

AGENTS.md reference: crates/mega-evm/src/evm/AGENTS.md:L17-L19

Useful? React with 👍 / 👎.

…evm idiom

Drop the T12 const CHECKPOINT monomorphization and return the REX7
checkpoint macros and handlers to a runtime spec.is_enabled(REX7) gate.
Frame-exit settlement is unconditional again; AdditionalLimit's
checkpoint_accounting flag is the single source of truth. Gas-clamp
wording from the later rename is kept.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f849383f0b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +366 to +367
if let Some(clamp) = self.clamp.take() {
result.gas.erase_cost(clamp.hidden);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve gas for zero-hidden clamp exceeds

When true EVM gas exactly equals compute headroom, checkpoint_clamp_amount intentionally creates a binding clamp with hidden == 0; if the next plain opcode cannot afford its cost, revm has already spent the result gas to zero before this hook runs. Erasing a zero cost restores nothing, so try_rescue_gas later sees zero and a transaction-level limit exceed burns all pre-opcode gas; the analogous frame-local revert returns none of it to its caller. Preserve the pre-failure remainder for this equality case so the reclassified limit exceed retains the promised refund behavior.

AGENTS.md reference: AGENTS.md:L139-L141

Useful? React with 👍 / 👎.

Comment on lines 686 to 687
pub(super) const fn gas_table(table: GasTable) -> GasTable {
rex6::gas_table(table)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Restore the clamp before charging CREATE static gas

With an active clamp whose compute headroom is below CREATE/CREATE2's 32,000 static cost but whose true EVM gas is sufficient, inheriting the Rex6 gas table makes the interpreter reject the opcode before either handler can reach create_rex6's checkpoint prologue. The opcode is consequently treated as a plain-segment clamp crossing instead of a checkpoint, so its operand/memory/address work never runs; zero these Rex7 table entries and charge their static cost after the prologue, as required for other checkpoint opcodes.

AGENTS.md reference: crates/mega-evm/src/evm/AGENTS.md:L17-L19

Useful? React with 👍 / 👎.

);
}
}
self.settle_exceptional_halt_burn(result);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Settle exceptional precompile results before returning

When a REX7 precompile returns an exceptional result directly from frame_init, it never passes through after_frame_run, so this is the only burn-settlement call and it is skipped. For example, an invalid KZG invocation with substantially more forwarded gas than its fixed cost records only that fixed cost in precompiles.rs, while the parent destroys the whole forwarded allowance; the remainder is therefore absent from both compute_gas_destroyed and the reported/block compute total. Add equivalent split accounting to the frame-init result path, accounting for the precompile wrapper's normalized Gas shape rather than treating all of its reported remaining gas as destroyed.

AGENTS.md reference: AGENTS.md:L118-L121

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

api:breaking Crate interface change — downstream users must update comp:core Changes to the `mega-evm` core crate comp:doc Changes in the documentation spec:unstable Changes to the unstable spec (currently REX5)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant