EIP-8141: charge a frame's entry gas and its target's delegation access - #12856
EIP-8141: charge a frame's entry gas and its target's delegation access#12856Marchhill wants to merge 2 commits into
Conversation
|
Claude finished @Marchhill's task in 9m 32s —— View job Review: EIP-8141 frame entry gas + delegation accessRead the two reviewable commits (
VerdictThe charges themselves look right, and the delegation half in particular is a faithful port of
Two Medium findings, both about how the change is expressed and covered rather than about the gas numbers, so neither is a claim that the branch computes the wrong price today.
The one concrete behavioural divergence is inside #1: Finding 5 — two orderings worth a spec pointerNeither is a bug I can demonstrate; both are places where the code's correctness rests entirely on the PR description's claim about the reference, and a pointer would make them reviewable.
Not verifiedI could not build or run anything — |
EVM Opcode Benchmark DiffAggregated runs: base=1, pr=1 No significant regressions or improvements detected. |
| { | ||
| try { return ConvertToBlockchainTests(_serializer.Deserialize<Dictionary<string, BlockchainTestJson>>(json)); } | ||
| catch (Exception) { return ConvertToBlockchainTests(CoerceFromHalf(_serializer.Deserialize<Dictionary<string, HalfBlockchainTestJson>>(json))); } | ||
| Dictionary<string, BlockchainTestJson> tests; |
There was a problem hiding this comment.
Yes — you were right, this branch was cut from #12854 so it carried all three of its files verbatim. I have rebased it straight onto eip8141-frame-txs-devnet7, dropping the fixture-loading commits; the tests here are plain FrameTxProcessorTests unit tests and never touch the fixture loader, so it did not need to stack on #12854. This PR is now just the entry charge, the delegation access and their tests. Leaving the thread open for you.
Every frame pays, within its own gas limit, to resolve its target the way create_evm_from_frame does: cold or warm account access, plus the EIP-8037 NEW_ACCOUNT state cost when a value transfer revives a dead target. EIP-2929 seeds the accessed set with every precompile, which the shared frame tracker does not hold, so a precompile target pays warm. The state reservoir starts empty, so the entry state cost spills into execution gas, and a charge exceeding the frame's gas halts the frame exceptionally with all of it consumed. A caller that cannot fund the value transfer still reverts before the charge, consuming nothing. Expose the cold account-access price on the gas policy so the frame path prices it the same way the VM's account-access metering does.
6053609 to
b5b268c
Compare
|
Claude finished @Marchhill's task in 8m 58s —— View job Re-review: EIP-8141 frame entry gas + delegation accessRebased since my last pass — the three #12854 fixture-loader files are gone, so the diff is now exactly the two charges and their tests (
Where the previous findings stand
The delegation half remains a faithful port of Two new Medium findings, both from following the entry charge into paths the tests don't reach.
A in one line: B in one line: C — the two orderings from last timeNeither is a bug I can demonstrate; both are places where correctness rests on the PR description's claim about the reference, and a pointer would make them reviewable.
D — test duplication
Not verifiedI could not build or test: |
A frame whose target is an EIP-7702 delegated EOA followed the designation for code but discarded the resolved address, so the delegation target's access was neither charged nor warmed. Mirror resolve_delegated_code_address: charge its cold or warm access on top of the target's own entry charge, warm it for the frames that follow, and fail the frame consuming its whole gas limit when it cannot afford the charge. The target counts as accessed by then, so a self-designation is warm, as is a designated precompile. The designated code is read only after its access is paid for, keeping an unaffordable designation out of the block access list. EIP-7702 bars a precompile reached through a delegation from executing as one.
b5b268c to
e63add7
Compare
Changes
Two consecutive gaps on the EIP-8141 frame execution path, both in
create_evm_from_frame:NEW_ACCOUNTstate cost when a value transfer revives a dead target. EIP-2929 seeds the accessed set with every precompile, which the shared frame tracker does not hold, so a precompile target pays warm. A charge the frame cannot afford halts it exceptionally, consuming its whole gas limit; a caller that cannot fund the value transfer still reverts before the charge, consuming nothing.The cold account-access price is exposed on the gas policy so the frame path prices it exactly as the VM's account-access metering does.
The affordability check is split so the target's access charge is tested before the deadness query behind the value transfer. That query is itself a recorded read on the BAL-generating world state, and BAL reads survive the frame's failure, so testing the sum first would write an unaffordable frame's target into the block access list — a header-visible divergence. The CALL path is sequenced the same way.
Both follow the reference
create_evm_from_frame/resolve_delegated_code_address, including the ordering: the target's access is charged and the target marked accessed before the designation is resolved, so a self-designation resolves warm.Types of changes
What types of changes does your code introduce?
Testing
Requires testing
If yes, did you write tests?
Notes on testing
FrameTxProcessorTestscovers both charges: cold-vs-warm target entry access, a frame whose gas is below its entry charge, the designated address's access for a contract and a precompile designation, a frame that can pay the target access but not the designation, and the resulting block access list in both cases. Two frames sharing one target pin the cross-frame warmth and its rollback when the first frame reverts, a self-designating target pins that it halts on its own designator bytes, and a frame priced below its target's access pins that the target stays out of the block access list.Each change was revert-checked separately and serialized. Reverting the delegation production code fails exactly the four discriminating delegation tests; reverting the entry charge fails exactly ten, matching the prediction in both cases. Frame suites are green across Core (110), Evm (178), TxPool (77) and Blockchain (29).
Existing expectations that pinned the absence of an entry charge were updated rather than removed: the precompile-target gas cases now read
identityGas + WarmAccess, and the EIP-8272 empty-reference case is now standard-bound rather than floor-bound, since the entry charge lifts both envelopes over their calldata floors.Documentation
Requires documentation update
Requires explanation in Release Notes
Remarks
The merged EIP-8141 fixtures cannot validate this on
eip8141-frame-txs-devnet7yet.Bogotahere composes as Osaka + EIP-8141, while the fixtures are Amsterdam-composed, so the blocks are rejected at header validation (BlockLevelAccessListHashNotEnabled) before any gas is metered — the wholetarget_resolutionsuite scores the same with and without these changes. The unit tests are the working oracle on this branch becauseEip8141Prototypederives from Amsterdam and therefore carries the block access list, EIP-8037 and EIP-8038.Verified end to end against the fixtures on the devnet-8 composition, where the same two charges take all four delegation cases from failing to passing:
test_delegated_target_entry_charge(cold and warm),test_delegated_to_precompile_targetandtest_verify_frame_delegated_to_precompile_target.