Skip to content

Refactor/opcodes self deduct gas#10081

Draft
daniellehrner wants to merge 6 commits intobesu-eth:mainfrom
daniellehrner:refactor/opcodes-self-deduct-gas
Draft

Refactor/opcodes self deduct gas#10081
daniellehrner wants to merge 6 commits intobesu-eth:mainfrom
daniellehrner:refactor/opcodes-self-deduct-gas

Conversation

@daniellehrner
Copy link
Contributor

PR description

Move gas deduction from EVM loop into individual opcodes

Problem

EIP-8037 (multidimensional gas metering) requires that regular gas is charged before state gas for opcodes like SSTORE, SELFDESTRUCT, and CREATE. However, the EVM loop deducts regular gas after an operation's execute() returns while state gas is consumed during execute() via frame.consumeStateGas().

This forces an ugly decrement-then-increment workaround: operations temporarily deduct regular gas before the state gas charge, then add it back so the EVM loop can re-deduct it:

  frame.decrementRemainingGas(cost);    // deduct so state gas sees correct gasRemaining
  // ... charge state gas ...
  frame.incrementRemainingGas(cost);    // undo, because EVM loop will deduct again
  return new OperationResult(cost, null);

Solution

Each opcode now deducts its own gas inside execute() / staticOperation(). The EVM loop no longer performs gas deduction, it only checks for halt reasons.

  • Fixed-cost operations (76 ops via AbstractFixedCostOperation): gas deducted in staticOperation() or executeFixedCostOperation() (non-delegating ops)
  • Variable-cost operations (~25 ops): decrementRemainingGas(cost) < 0 replaces the separate check + deduction pattern
  • EVM.java: removed the post-execution frame.decrementRemainingGas(result.getGasCost()) from the main loop
  • State gas ordering (SSTORE, SELFDESTRUCT, CREATE, CALL): regular gas deduction naturally precedes state gas — no workaround needed

Fixed Issue(s)

Thanks for sending a pull request! Have you done the following?

  • Checked out our contribution guidelines?
  • Considered documentation and added the doc-change-required label to this PR if updates are required.
  • Considered the changelog and included an update if required.
  • For database changes (e.g. KeyValueSegmentIdentifier) considered compatibility and performed forwards and backwards compatibility tests

Locally, you can run these tests to catch failures early:

  • spotless: ./gradlew spotlessApply
  • unit tests: ./gradlew build
  • acceptance tests: ./gradlew acceptanceTest
  • integration tests: ./gradlew integrationTest
  • reference tests: ./gradlew ethereum:referenceTests:referenceTests
  • hive tests: Engine or other RPCs modified?

daniellehrner and others added 6 commits March 20, 2026 10:17
Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
…ient

When charge_state_gas fails (OutOfGasError), the spec modifies nothing:
no reservoir drain, no stateGasUsed increment. Remove consumeStateGasForced
which was incorrectly inflating stateGasUsed on failure, fixing short_one_gas
reference tests.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
accounting correctly reflects gas consumed on EIP-684 address collisions

Signed-off-by: daniellehrner <daniel.lehrner@consensys.net>
…irement

EIP-8037 specifies that regular gas must be deducted before state gas so
the reservoir/gasRemaining split is correct when state gas overflows.
Also updates devnet reference tests to bal@v5.5.1.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Move gas deduction from the EVM loop (post-execution) into each
operation itself. This eliminates the decrement-then-increment pattern
needed for EIP-8037 state gas ordering and makes gas accounting more
explicit per-opcode.

- EVM.java: remove post-switch gas deduction
- AbstractFixedCostOperation: execute() checks gas only; staticOperation
  methods and non-delegating executeFixedCostOperation deduct gas
- Variable-cost operations: use decrementRemainingGas as combined
  check+deduct
- CALL/CREATE/SSTORE/SELFDESTRUCT: natural ordering without workarounds
- Standardize GAS_COST constant and outOfGasResult naming across all ops

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@daniellehrner daniellehrner force-pushed the refactor/opcodes-self-deduct-gas branch from fffb242 to 85aa68c Compare March 20, 2026 09:52
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