fix(evm): don't pay the beneficiary for the unused EIP-8037 reservoir - #395
Open
Xowiek wants to merge 1 commit into
Open
fix(evm): don't pay the beneficiary for the unused EIP-8037 reservoir#395Xowiek wants to merge 1 commit into
Xowiek wants to merge 1 commit into
Conversation
ArcEvmHandler overrides reward_beneficiary to pay the full effective gas price to the beneficiary, and takes the gas it pays for from exec_result.gas().used(). Under EIP-8037 the tx-level Gas built by last_frame_result spans the whole tx.gas_limit and keeps the unused state gas reservoir outside `remaining`, so used() still counts it. revm's reimburse_caller, which Arc does not override, returns remaining + reservoir + refunded to the caller. Paying the beneficiary for used() as well credits the reservoir twice, and the two credits add up to more than the caller was charged. revm's own post_execution::reward_beneficiary subtracts gas.reservoir() for this reason. The Arc override predates EIP-8037 support in revm-handler 18.0.0 and did not pick the subtraction up when revm was bumped. No current network is affected: the reservoir is only non-zero once EIP-8037 is enabled, which revm does at Amsterdam, and no Arc chain spec schedules Amsterdam. The change is a no-op until then.
Xowiek
requested review from
ZhiyuCircle,
ancazamfir,
romac and
sergio-mena
as code owners
September 12, 2026 19:55
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.
ArcEvmHandler::reward_beneficiarypays the beneficiary for:Under EIP-8037 that also counts gas the caller gets back.
last_frame_resultrebuilds the top-level gas over the whole tx gas limit, returns only the regularremaining, and keeps the unused state gas reservoir separately:so
used()—tx.gas_limit - remaining - refunded— still includes the reservoir. Arc doesn't overridereimburse_caller, and revm's version handsremaining + reservoir + refundedback to the caller. The reservoir ends up both refunded and paid to the beneficiary.revm's own
post_execution::reward_beneficiaryleaves it out for exactly this reason:EIP-8037 support landed in revm-handler 18.0.0. The Arc override was written before that and didn't pick the subtraction up when revm was bumped.
With a 20M gas limit, 1M regular gas left, a 3M reservoir and a price of 10, the caller is charged 200,000,000. On
main, reimbursement plus reward come to:The extra 30,000,000 is
reservoir × priceof native coin that was never debited from anyone.This isn't reachable on any network today. The reservoir is only non-zero with EIP-8037 enabled, revm enables it at
SpecId::AMSTERDAM, and no Arc chain spec schedules Amsterdam — mainnet and localdev stop at Osaka, testnet and devnet at Prague. So the change is a no-op for every existing block.create_evmalready turns off revm's Amsterdam EIP-7708 logs ahead of the spec being enabled; this is the same kind of change for the fee path.The added test runs revm's
reimburse_callerand Arc'sreward_beneficiaryon the gaslast_frame_resultproduces, and checks the two credits equal what the caller was charged. It fails onmainwith the output above.cargo test -p arc-evmpasses (150 tests), as dofmtandclippy.