Skip to content

refactor!: add ResultGas struct to ExecutionResult#3413

Merged
rakita merged 11 commits intomainfrom
expose-gas
Feb 12, 2026
Merged

refactor!: add ResultGas struct to ExecutionResult#3413
rakita merged 11 commits intomainfrom
expose-gas

Conversation

@rakita
Copy link
Copy Markdown
Member

@rakita rakita commented Feb 9, 2026

Summary

  • Introduce ResultGas struct with gas_used, gas_refunded, gas_spent, and floor_gas fields to expose richer gas accounting to callers
  • Replace loose gas_used/gas_refunded fields in all three ExecutionResult variants (Success, Revert, Halt) with a single gas: ResultGas field
  • Add gas() accessor on ExecutionResult returning &ResultGas; existing gas_used() method still works
  • Thread InitialAndFloorGas through execution_result()post_execution::output() to populate gas_spent and floor_gas

Breaking changes

  • ExecutionResult variants now use gas: ResultGas instead of gas_used: u64 / gas_refunded: u64
  • Handler::execution_result() now takes an additional InitialAndFloorGas parameter
  • Serialization format changed (affects JSON testdata)

Test plan

  • cargo build --workspace
  • cargo clippy --workspace --all-targets --all-features
  • cargo nextest run --workspace — 361 tests pass
  • cargo check --target riscv32imac-unknown-none-elf --no-default-features — no_std OK
  • JSON testdata files regenerated

Replace loose `gas_used` and `gas_refunded` fields in all three
`ExecutionResult` variants with a single `gas: ResultGas` struct that
exposes richer gas accounting: `gas_used`, `gas_refunded`, `gas_spent`
(pre-refund), and `floor_gas` (EIP-7623).
@codspeed-hq
Copy link
Copy Markdown

codspeed-hq bot commented Feb 9, 2026

Merging this PR will improve performance by 3.1%

⚡ 1 improved benchmark
✅ 172 untouched benchmarks

Performance Changes

Benchmark BASE HEAD Efficiency
transact_commit_1000txs 2.8 ms 2.7 ms +3.1%

Comparing expose-gas (7f24d05) with main (67eecf4)

Open in CodSpeed

Remove the redundant `gas_used` field from `ResultGas` since it can
always be derived as `gas_spent - gas_refunded`. The struct now stores
only three independent values (gas_spent, gas_refunded, floor_gas) and
exposes `gas_used()` as a method.
- Rename fields to align with Gas struct methods:
  gas_spent → spent, gas_refunded → refunded, gas_used() → used()
  Eliminates redundant gas.gas_spent pattern (now gas.spent)
- Add #[serde(rename)] to preserve JSON key stability
- Add Display impl for ResultGas (conditionally shows refunded/floor)
- Simplify ExecutionResult Display to delegate to ResultGas Display
- Improve documentation with source mapping table
- Add tests for ResultGas Display and used() method
Add `limit` field to `ResultGas` so it contains all gas information
without requiring external context. Also add `remaining()` derived
method (limit - spent) to complement `used()` (spent - refunded).

ResultGas now mirrors the full Gas struct snapshot:
- limit: transaction gas limit
- spent: gas consumed before refund
- refunded: gas refund amount
- floor_gas: EIP-7623 floor gas
- used(): spent - refunded (derived)
- remaining(): limit - spent (derived)
…cution`

Add intrinsic_gas field to ResultGas so it carries the initial tx
overhead gas. Change post_execution to return ResultGas directly,
and have execution_result receive a pre-built ResultGas instead of
InitialAndFloorGas.
- Make all ResultGas fields private
- Add getter methods: limit(), spent(), refunded(), floor_gas(), intrinsic_gas()
- Add builder methods: with_limit(), with_spent(), with_refunded(), with_floor_gas(), with_intrinsic_gas()
- Add setter methods: set_limit(), set_spent(), set_refunded(), set_floor_gas(), set_intrinsic_gas()
- Add derived methods: final_used(), inner_refunded(), final_refunded()
- Rewrite struct doc table to reference getter methods instead of fields
- Fix used() doc formula to include floor_gas: max(spent - refunded, floor_gas)
- Fix incomplete refunded field doc, point to final_refunded()
- Remove stale final_used() reference, remove refunded() getter (replaced by inner_refunded)
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR refactors gas accounting exposure by introducing a ResultGas struct and embedding it into ExecutionResult variants, threading the required InitialAndFloorGas information through the handler pipeline and updating examples + JSON test vectors accordingly.

Changes:

  • Added ResultGas (limit/spent/refunded/floor/intrinsic + derived helpers) and replaced per-variant gas_used/gas_refunded fields with a single gas: ResultGas.
  • Updated handler/inspector/op-handler execution result plumbing to pass ResultGas into post_execution::output.
  • Regenerated ee-test JSON fixtures and updated examples/tests to use gas.used() / gas: ResultGas.

Reviewed changes

Copilot reviewed 37 out of 37 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
examples/custom_precompile_journal/src/main.rs Update example pattern matches/printing to use gas.used()
examples/bal_example/src/main.rs Update example printing to use gas.used()
crates/op-revm/src/handler.rs Thread ResultGas into execution_result, update FailedDeposit halt to include ResultGas
crates/inspector/src/handler.rs Thread ResultGas through inspector run paths; build ResultGas for system calls
crates/handler/src/system_call.rs Update test expected ExecutionResult to include gas: ResultGas
crates/handler/src/post_execution.rs Add build_result_gas helper and update output() to accept ResultGas
crates/handler/src/handler.rs Change post_execution() to return ResultGas and pass into execution_result()
crates/ee-tests/tests/revm_testdata/test_selfdestruct_multi_tx.json Update serialized result format to nested gas object
crates/ee-tests/tests/revm_testdata/test_multi_tx_create.json Update serialized result format to nested gas object
crates/ee-tests/tests/revm_testdata/test_frame_stack_index.json Update serialized result format to nested gas object
crates/ee-tests/tests/op_revm_testdata/test_tx_call_p256verify.json Update serialized result format to nested gas object
crates/ee-tests/tests/op_revm_testdata/test_log_inspector.json Update serialized result format to nested gas object
crates/ee-tests/tests/op_revm_testdata/test_l1block_load_for_pre_regolith.json Update serialized result format to nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_p256verify.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_granite.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bn254_pair_fjord.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_wrong_input_layout.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_pairing_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp_to_g1_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_map_fp2_to_g2_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_wrong_input_layout.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_msm_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g2_add_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_wrong_input_layout.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_msm_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_out_of_gas.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_tx_call_bls12_381_g1_add_input_wrong_size.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_halted_deposit_tx.json Update serialized halt format to include nested gas object
crates/ee-tests/tests/op_revm_testdata/test_deposit_tx.json Update serialized result format to nested gas object
crates/ee-tests/src/op_revm_tests.rs Update Rust assertions to construct ResultGas in expected results
crates/context/interface/src/result.rs Introduce ResultGas, refactor ExecutionResult gas fields, add gas() accessor and update Display

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +235 to +247
// Build ResultGas from the final gas state
// This include all necessary fields and gas values.
let result_gas = post_execution::build_result_gas(exec_result.gas(), init_and_floor_gas);

// Ensure gas floor is met and minimum floor gas is spent.
// if `cfg.is_eip7623_disabled` is true, floor gas will be set to zero
self.eip7623_check_gas_floor(evm, exec_result, init_and_floor_gas);
// Return unused gas to caller
self.reimburse_caller(evm, exec_result)?;
// Pay transaction fees to beneficiary
self.reward_beneficiary(evm, exec_result)?;
Ok(())
// Build ResultGas from the final gas state
Ok(result_gas)
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

result_gas is built before eip7623_check_gas_floor mutates the underlying Gas (it can set spent=floor and clear refunds). This makes ResultGas inconsistent with the actual charged/reimbursed gas (e.g., spent, remaining, and refunded values can be wrong when the floor triggers). Build ResultGas after the floor check (and after any other gas-mutating steps) so the snapshot matches final gas state.

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

This is correct and expected, we want gas and refund that we got from loop if we get gas after eip7623_check_gas_floor we will lose this information.

This info was needed for EIP-7778

Comment on lines +239 to +246
/// Returns the effective refund after EIP-7623 floor gas adjustment: `spent - used()`.
///
/// When `floor_gas` kicks in, this may be less than [`inner_refunded()`](ResultGas::inner_refunded).
/// Always satisfies: `spent == used() + final_refunded()`.
#[inline]
pub const fn final_refunded(&self) -> u64 {
self.spent.saturating_sub(self.used())
}
Copy link

Copilot AI Feb 11, 2026

Choose a reason for hiding this comment

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

final_refunded() docs claim it “Always satisfies: spent == used() + final_refunded()”, but used() can exceed spent when floor_gas > spent (EIP-7623 can enforce a minimum charge higher than actual spent). In that case final_refunded() saturates to 0 and the equality no longer holds. Please relax/qualify this invariant (or adjust the representation so spent >= used() is guaranteed).

Copilot uses AI. Check for mistakes.
Copy link
Copy Markdown
Contributor

Copilot AI commented Feb 12, 2026

@rakita I've opened a new pull request, #3422, to work on those changes. Once the pull request is ready, I'll request review from you.

rakita and others added 2 commits February 12, 2026 02:09
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
* Initial plan

* fix: correct grammar in handler.rs comment
@rakita rakita merged commit 0ee852c into main Feb 12, 2026
31 checks passed
@rakita rakita deleted the expose-gas branch February 12, 2026 13:20
@github-actions github-actions bot mentioned this pull request Feb 10, 2026
@rakita rakita restored the expose-gas branch February 23, 2026 12: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.

4 participants