fix(evm): restore frame gas after inspector callback to preserve rescue_gas#170
Closed
fix(evm): restore frame gas after inspector callback to preserve rescue_gas#170
Conversation
…ue_gas GasInspector::call_end (revm) calls gas.spend_all() on error results such as OutOfGas. This is called from frame_end in inspect_frame_run and inspect_frame_init, before frame_return_result has a chance to call rescue_gas(). The rescue_gas mechanism saves the remaining gas of a frame halted by MegaETH's additional limits (e.g. state growth limit) so it can be refunded to the sender in last_frame_result. With the inspector path, spend_all() zeroes gas.remaining() first, so rescue_gas() reads 0 and the refund is lost. This causes different gas_used values compared to the non-inspector path, resulting in a receipts root mismatch when validating blocks. Fix: save gas.remaining() before calling frame_end, then restore it afterwards if the inspector callback reduced it. The inspector still receives the unmodified (pre-spend_all) gas value for its callbacks, which is fine since GasInspector computes last_gas_cost from the delta between step() and step_end() readings rather than from the final remaining value.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When an inspector is attached (e.g.
TracerEip3155),frame_endis called after each subcall frame completes, which triggersGasInspector::call_end→gas.spend_all()for any error result (includingOutOfGas).This happens in both
inspect_frame_runandinspect_frame_init, beforeframe_return_resulthas a chance to callrescue_gas().MegaETH's rescue_gas mechanism saves
gas.remaining()from frames halted by additional limits (state growth, compute gas, etc.) to refund the sender inlast_frame_result.With the inspector path,
spend_all()zeroesgas.remaining()first, sorescue_gas()always reads 0 — the refund is lost.This causes different
gas_usedvalues compared to the non-inspector path, producing a receipts root mismatch when validating blocks with an inspector attached.Fix: in both
inspect_frame_initandinspect_frame_run, savegas.remaining()before callingframe_end, then restore it if the inspector callback reduced it.Root cause trace
Verification
Validated against block 3021764 on MegaETH mainnet:
TracerEip3155before fix: receipts root mismatchTracerEip3155after fix: block validates correctly