Commit a6da5d3
authored
feat: add EIP-8037 / TIP-1016 state gas support (bluealloy/revm#3406)
* feat: implement EIP-8037 state gas (reservoir model)
Add state gas accounting with reservoir model across interpreter, handler,
context, and precompile crates. Includes comprehensive EIP-8037 test suite
with 35+ test vectors covering SSTORE, CALL, CREATE, SELFDESTRUCT, reservoir
refill, and gas opcode behavior.
* rm statetest jsons
* Rename spent to regular_gas_spent in ResultGas and simplify reservoir refill
- Rename ResultGas::spent to regular_gas_spent to distinguish from state gas after EIP-8037
- Add total_gas_spent() method and deprecate old spent()/set_spent()/with_spent() accessors
- Simplify reservoir refill logic: replace handler_reservoir_refill() with inline max()
- Remove unnecessary reservoir manipulation in precompile path
- Update op-revm handler to use simplified reservoir refill
- Update Cargo.lock dependencies
* Simplify EIP-8037 state gas: remove redundant fields from ResultGas and update test data
* Move EIP-7702 state gas refund split into pre_execution
Consolidate the EIP-8037 auth list refund splitting logic from
run_without_catch_error into apply_eip7702_auth_list, avoiding
duplication between handler and inspector. pre_execution now takes
init_and_floor_gas as a mutable reference and returns only the
regular refund portion.
* Add PrecompileFailure type for state gas propagation on error
Introduce PrecompileFailure wrapper that carries both the error and
an optional GasTracker, allowing precompiles that charge state gas
(EIP-8037) to propagate gas info back to the caller on failure for
proper reservoir refill.
* Convert precompile errors to PrecompileFailure via .into()
Update all precompile Err returns to use .into() for converting
PrecompileError to PrecompileFailure, enabling state gas tracking
on precompile failures.
* Fix EIP-8037 state gas accounting regression
Commit 14bd5a61 introduced a regression in gas accounting by incorrectly
erasing both remaining and reservoir gas from total_gas_spent. The reservoir
should not be erased since it's tracked separately via state_gas_spent.
This fix reverts the erase_cost line from erase_cost(remaining + reservoir)
to erase_cost(remaining), which correctly accounts for:
- Regular gas: deducted from remaining calculation
- State gas: tracked separately in state_gas_spent field
Results:
- State test failures reduced from 20 to 4 (pre-regression count)
- All 408 workspace tests now pass
- Updated EIP-8037 test data and assertions to match correct values
* Move state gas deduction into first_frame_input
Refactor to improve code organization by moving the state gas deduction
logic from the execution method into the first_frame_input method, where
frame initialization concerns are naturally grouped together.
This keeps frame setup logic cohesive and simplifies the execution method
to focus on the execution loop rather than frame setup details.
No functional change - same gas accounting and execution behavior.
* Fix EIP-8037 gas accounting: floor gas, reservoir, inspector, validation
Four fixes for EIP-8037 state gas interactions:
1. post_execution: Fix EIP-7623 floor gas check to account for EIP-8037
reservoir. Per EIP-8037, gas_used = tx.gas - gas_left - reservoir.
The floor check now subtracts reservoir when computing gas used.
2. handler: Simplify reservoir handling in last_frame_result to always
use the frame's final reservoir value directly. It already reflects
child frame restorations via handle_reservoir_remaining_gas.
3. handler: Add EIP-8037 floor gas validation when gas_limit exceeds
TX_MAX_GAS_LIMIT. The maximum gas_used is capped at TX_MAX_GAS_LIMIT
since excess goes to reservoir, so floor_gas must not exceed that cap.
4. inspector: Remove double deduction of initial_state_gas in
inspect_execution. The first_frame_input method already handles the
deduction; the explicit deduction in the inspector was redundant.
* Fix EIP-8037 reservoir accounting: tx_gas_used, child revert refunds, and EIP-7702
- tx_gas_used now subtracts unused reservoir gas (tx.gas - gas_left - state_gas_left)
- Child revert/halt returns all state gas to parent reservoir (matching Python spec)
- EIP-7702 state gas refund goes to reservoir instead of reducing initial_state_gas
- Refund cap uses gas_used excluding reservoir
- Precompile provider preserves reservoir across gas tracker replacement
- Updated EIP-8037 test expectations and test data
* Fix CREATE/CREATE2 static call check ordering for EIP-8037 state gas recovery
Move require_non_staticcall! after gas charging in the CREATE/CREATE2
instruction handler. In the execution-specs, the static check is inside
generic_create() after all gas (including state gas) has been charged.
The previous ordering prevented state gas from being recorded on the
frame, so on child error the parent could not recover it via
handle_reservoir_remaining_gas.
* Simplify last_frame_result: remove initial_reservoir parameter and fix reservoir handling
- Remove unused `initial_reservoir` parameter from `last_frame_result` across all handlers
- Fix precompile provider to save reservoir before overwriting gas tracker
- Add deprecated `gas_used()` method on ExecutionResult pointing to `tx_gas_used()`
* Revert CREATE/CREATE2 static call check to before gas charging
Static call check doesn't need to be after gas charging - CREATE in a
static context is always an error regardless of gas accounting.
* Fix reservoir handling: restore state gas on revert/halt
On revert/halt, state changes are rolled back so state gas should be
refunded back to the reservoir. Only on success should the frame's
final reservoir be used as-is.
* Fix EIP-8037 state_gas_spent accounting for EIP-7702 auth list
Two bugs in state_gas_spent reporting:
1. build_result_gas added full initial_state_gas without subtracting
eip7702_reservoir_refund, overcounting state gas for existing
authority accounts. This caused block_state_gas_used to be too
high and block_regular_gas_used to be too low.
2. On revert/halt, last_frame_result set state_gas_spent before
restoring it to the reservoir, leaving a stale execution value.
Now correctly zeroed since state changes are rolled back.
* Improve precompile reservoir handling and apply formatting fixes
Refactor precompile provider to properly handle reservoir refill logic
for both success and error/halt cases, ensuring state gas accounting
is correct when precompiles don't track reservoir. Also apply rustfmt
formatting across multiple files.
* Fix precompile_provider compilation errors against current precompile API
PrecompileOutput has gas_used (not gas: GasTracker) and PrecompileError
is a flat enum (no .error/.gas subfields). Use record_regular_cost()
to avoid deprecation warning.
* Simplify precompile interface: remove gas_limit from PrecompileOutput, flatten PrecompileError
Remove gas_limit field from PrecompileOutput (only gas_used needed) and
eliminate the PrecompileError wrapper layer so errors are returned directly
as the enum variant without .into() conversion.
* Fix EIP-8037 reservoir refill tests and complete precompile interface cleanup
Update 4 EIP-8037 tests to match current reservoir refill behavior: on
revert/halt at the top level, state_gas_spent is zeroed and state gas is
restored to the reservoir (state changes rolled back). Regenerate testdata.
Also complete the PrecompileOutput/PrecompileError simplification from the
previous commit: remove reverted field, flatten error matching in tests.
* temporary remove all ee-tests
* Fix state gas accounting: include reservoir in total_gas_spent and prevent underflow
- Remove saturating_sub of reservoir from total_gas_spent in build_result_gas
- Use saturating_sub in block_regular_gas_used to prevent underflow
* Apply formatting fixes and use saturating arithmetic for state gas spent
* Revert "temporary remove all ee-tests"
This reverts commit 03986fcd15d861b32ce2e56186ffd9ebdbfa3871.
* Fix total_gas_spent to exclude reservoir and use saturating arithmetic
Compute total_gas_spent as limit - remaining - reservoir in
build_result_gas to correctly exclude unused state gas. Use
saturating_sub in Gas::spent/total_gas_spent to prevent underflow.
Add std feature to ee-tests revm dependency.
* Use build_result_gas helper in system call gas handling
Replace manual ResultGas construction with the shared build_result_gas
function for consistency with the main execution path.
* bump rust to 1.91
* Remove redundant gas_limit from Gas, delegate to GasTracker
Gas had its own `limit` field duplicating `GasTracker::gas_limit`.
Remove it and delegate `Gas::limit()` to `self.tracker.limit()`.
Also fixes `Gas::new_spent` which previously set tracker gas_limit
to 0 instead of the actual limit.
* refactor(precompile): restructure PrecompileOutput for state gas and reservoir support (bluealloy/revm#3541)
* refactor(precompile): split PrecompileOutput and PrecompileError for state gas support
Rename PrecompileOutput to PrecompileOutputEth (simple gas_used + bytes) for
individual precompile functions. Introduce new PrecompileOutput with halt,
gas_used, state_gas_used, reservoir, and bytes fields for provider-level results.
Split PrecompileError: non-fatal errors become PrecompileHaltReason (expressed
via PrecompileOutput::halt), while PrecompileError now only holds fatal errors
(Fatal/FatalAny) that abort EVM execution.
New type aliases:
- PrecompileEthResult = Result<PrecompileOutputEth, PrecompileHaltReason>
- PrecompileResult = Result<PrecompileOutput, PrecompileError>
* refactor(precompile): replace Option<PrecompileHalt> with PrecompileStatus enum
Introduce PrecompileStatus enum (Success, Revert, Halt) to replace the
Option<PrecompileHalt> field in PrecompileOutput. Add PrecompileEthFn type
alias for legacy precompile function signatures, with Precompile::execute()
now returning PrecompileOutput via a From<PrecompileEthResult> conversion.
Add helper methods: is_success, is_revert, halt_reason, into_halt_reason.
* refactor(handler): extract precompile_output_to_interpreter_result helper
Add a standalone function that converts PrecompileOutput into
InterpreterResult, and use it in EthPrecompiles::run. Fmt and clippy fixes.
* refactor(precompile): thread reservoir through PrecompileOutput and revert execute signature
- Add `reservoir` parameter to PrecompileOutput::new, halt, revert constructors
- Add `from_eth_result` constructor that takes reservoir
- Revert Precompile::execute to return PrecompileEthResult
- Move PrecompileOutput conversion to call site in EthPrecompiles
- Remove unused into_halt_reason and From<PrecompileEthResult> impl
* refactor(precompile): change Precompile fn_ from PrecompileEthFn to PrecompileFn (bluealloy/revm#3546)
Change the Precompile struct's fn_ field from PrecompileEthFn (fn(&[u8], u64) -> PrecompileEthResult)
to PrecompileFn (fn(&[u8], u64, u64) -> PrecompileOutput) so precompiles receive reservoir
directly and return PrecompileOutput.
Add call_eth_precompile helper to wrap existing PrecompileEthFn implementations into
the new PrecompileFn signature. Each precompile module gets a thin wrapper using this helper.
* refactor(precompile): add eth_precompile_fn! macro to eliminate wrapper boilerplate
Replace 17 hand-written PrecompileEthFn-to-PrecompileFn wrapper functions
with the new eth_precompile_fn! macro that generates them uniformly.
* refactor(op-revm): use eth_precompile_fn! macro for precompile wrappers
Replace 8 hand-written wrapper functions in op-revm with the
eth_precompile_fn! macro.
* style: apply cargo fmt
* Rename Eth precompile structs
* fix(op-revm): add missing reservoir argument to execute calls in tests
* refactor(precompile): move reservoir into PrecompileOutput and add PrecompileStatus helpers
PrecompileOutput now carries reservoir and state_gas_used, so
precompile_output_to_interpreter_result no longer needs a separate
reservoir parameter. Added convenience methods on PrecompileStatus
and fixed unused import warning.
* fix: update bench and test code for new Precompile API
Update eip2537 benchmarks to use Precompile::execute() instead of
removed precompile() method, and fix manual div_ceil clippy warning.
* docs: fix ResultGas doc comments to match current API
Remove references to removed getters (limit, spent, intrinsic_gas,
remaining) and update table and derived values to reflect the actual
methods (total_gas_spent, tx_gas_used, block_regular_gas_used, etc.).
* docs: fix broken doc links and typos in ResultGas
- Fix unresolved links to non-existent `regular_gas_spent` and
`with_regular_gas_spent` methods in deprecation notes
- Fix typos: "substract" → "subtract", "enought" → "enough"
- Fix stale comments referencing `regular_gas_spent` field
* feat: track state_gas_spent and reservoir in GasInspector
* fix: validate max(intrinsic_gas, floor_gas) against TX_MAX_GAS_LIMIT cap
* chore: add must_use annotations to gas recording methods and minor cleanups
* refactor: update custom_precompile_journal example to use PrecompileOutput API
Use `PrecompileOutput::from_eth_result` and `precompile_output_to_interpreter_result`
instead of manually constructing InterpreterResult, aligning with the new gas handling.
* refactor: make Precompile::execute return Result<PrecompileOutput, PrecompileError>
Distinguish fatal/unrecoverable precompile errors from non-fatal halts
by returning a Result. PrecompileFn signature updated accordingly, and
all call sites now propagate or unwrap the error.
* chore: bump MSRV to 1.91 in CI
* fix: exclude EIP-8037 reservoir gas from op-revm fee settlement
The core revm handler already excludes reservoir gas when calculating
beneficiary rewards and caller reimbursement, but op-revm's fee
settlement did not account for it. Once Osaka/EIP-8037 is enabled,
transactions with leftover reservoir gas would over-credit
BASE_FEE_RECIPIENT and OPERATOR_FEE_RECIPIENT, and under-refund
operator fees to the caller.
- reward_beneficiary: use effective_used (gas.used() - reservoir) for
base_fee_amount and operator_fee_cost calculations
- operator_fee_refund: include gas.reservoir() when computing gas_used
so the refund correctly covers unused reservoir gas
- handler validation: use initial_regular_gas (excluding state gas)
when checking floor_gas against TX_MAX_GAS_LIMIT cap1 parent c79483d commit a6da5d3
3 files changed
Lines changed: 103 additions & 64 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
195 | 195 | | |
196 | 196 | | |
197 | 197 | | |
| 198 | + | |
| 199 | + | |
198 | 200 | | |
199 | 201 | | |
200 | 202 | | |
| |||
214 | 216 | | |
215 | 217 | | |
216 | 218 | | |
217 | | - | |
218 | | - | |
| 219 | + | |
219 | 220 | | |
220 | 221 | | |
221 | 222 | | |
| |||
237 | 238 | | |
238 | 239 | | |
239 | 240 | | |
| 241 | + | |
240 | 242 | | |
241 | 243 | | |
242 | 244 | | |
| 245 | + | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
| 249 | + | |
243 | 250 | | |
244 | 251 | | |
245 | 252 | | |
| |||
314 | 321 | | |
315 | 322 | | |
316 | 323 | | |
| 324 | + | |
| 325 | + | |
317 | 326 | | |
318 | 327 | | |
319 | 328 | | |
320 | | - | |
| 329 | + | |
321 | 330 | | |
322 | 331 | | |
323 | 332 | | |
324 | 333 | | |
325 | 334 | | |
326 | | - | |
| 335 | + | |
327 | 336 | | |
328 | 337 | | |
329 | 338 | | |
| |||
419 | 428 | | |
420 | 429 | | |
421 | 430 | | |
422 | | - | |
| 431 | + | |
423 | 432 | | |
424 | 433 | | |
425 | 434 | | |
| |||
509 | 518 | | |
510 | 519 | | |
511 | 520 | | |
512 | | - | |
| 521 | + | |
513 | 522 | | |
514 | 523 | | |
515 | 524 | | |
| |||
525 | 534 | | |
526 | 535 | | |
527 | 536 | | |
528 | | - | |
| 537 | + | |
529 | 538 | | |
530 | 539 | | |
531 | 540 | | |
| |||
545 | 554 | | |
546 | 555 | | |
547 | 556 | | |
548 | | - | |
| 557 | + | |
549 | 558 | | |
550 | 559 | | |
551 | 560 | | |
552 | 561 | | |
553 | | - | |
| 562 | + | |
554 | 563 | | |
555 | 564 | | |
556 | 565 | | |
| |||
566 | 575 | | |
567 | 576 | | |
568 | 577 | | |
569 | | - | |
| 578 | + | |
570 | 579 | | |
571 | 580 | | |
572 | 581 | | |
| |||
583 | 592 | | |
584 | 593 | | |
585 | 594 | | |
586 | | - | |
| 595 | + | |
587 | 596 | | |
588 | 597 | | |
589 | 598 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
209 | 209 | | |
210 | 210 | | |
211 | 211 | | |
| 212 | + | |
212 | 213 | | |
213 | | - | |
| 214 | + | |
214 | 215 | | |
215 | 216 | | |
216 | 217 | | |
| |||
0 commit comments