Summary
While implementing EIP-8037 (two-dimensional gas accounting) in Nethermind, we found three real gas-accounting edge cases that were not covered by the current execution-spec tests. All three involve interactions between EIP-8037's state-gas reservoir and existing gas rules.
We would like to suggest adding execution-spec test coverage for these scenarios.
1. Intrinsic gas validation must include state gas for CREATE / setcode transactions
Under EIP-8037, some intrinsic costs are split into regular and state components.
Examples:
- contract creation:
CreateRegular + CreateState
- EIP-7702 setcode/auth transactions: regular per-auth cost + state per-auth cost
A transaction whose gasLimit covers only the regular intrinsic component, but not regular + state, should fail intrinsic gas validation.
Suggested tests
- CREATE transaction with:
gasLimit = 21000 + CreateRegular + calldata_cost
- omitting
CreateState
- expected result:
- rejected as below intrinsic gas
Similarly for EIP-7702 setcode/auth transactions:
gasLimit covers only the regular per-auth intrinsic cost
- expected result:
- rejected as below intrinsic gas
2. EIP-7623 floor gas must still be enforced when EIP-8037 is active
Amsterdam inherits EIP-7623 floor gas.
The minimum required gas is:
max(regular + state, floor)
A transaction where floor > regular + state must still be rejected if gasLimit < floor, even if it satisfies regular + state.
Suggested test
Send a transaction with 100 non-zero calldata bytes to an existing account:
tokens = 100 * 4 = 400
regular_intrinsic = 21000 + 400 * 4 = 22600
state = 0
floor = 21000 + 400 * 10 = 25000
Cases:
gasLimit = 23000
- expected result: rejected
gasLimit = 25000
- expected result: accepted
3. Nested CREATE code deposit must not borrow caller gas via state spill
When a CREATE returns initcode output, code deposit under EIP-8037 has:
- a regular component:
CodeDepositRegularPerWord * words
- a state component:
CostPerStateByte * bytes
If the child frame's state reservoir is insufficient, the shortfall spills into regular gas.
The important invariant is:
- the child frame's own regular gas must cover both:
- the regular code deposit cost
- any spill from missing state gas
It must not be possible for the deposit charge to succeed by consuming the caller's retained gas after the child frame has been merged back.
Suggested test
A contract called via CALL performs CREATE of a 1-byte contract.
Because the parent frame has no state reservoir, the child also has no state reservoir, so the full code-deposit state cost spills into regular gas.
Tune gas so that after initcode execution the child ends with:
- enough gas to satisfy the regular deposit check in isolation
- enough gas to satisfy the state-cost check in isolation
- but not enough gas to pay both together once state spill is accounted for
For a 1-byte deployed contract:
regularDepositCost = 6
stateDepositCost = 1174
- total regular required =
1180
A child ending with 1175 gas should fail code deposit.
Expected result:
- nested CREATE fails
- caller gas is not used to make the child code deposit succeed
Context
These cases were found during Nethermind's Amsterdam / EIP-8037 implementation.
Nethermind fixes and regression tests: NethermindEth/nethermind#10712
Summary
While implementing EIP-8037 (two-dimensional gas accounting) in Nethermind, we found three real gas-accounting edge cases that were not covered by the current execution-spec tests. All three involve interactions between EIP-8037's state-gas reservoir and existing gas rules.
We would like to suggest adding execution-spec test coverage for these scenarios.
1. Intrinsic gas validation must include state gas for CREATE / setcode transactions
Under EIP-8037, some intrinsic costs are split into regular and state components.
Examples:
CreateRegular + CreateStateA transaction whose
gasLimitcovers only the regular intrinsic component, but notregular + state, should fail intrinsic gas validation.Suggested tests
gasLimit = 21000 + CreateRegular + calldata_costCreateStateSimilarly for EIP-7702 setcode/auth transactions:
gasLimitcovers only the regular per-auth intrinsic cost2. EIP-7623 floor gas must still be enforced when EIP-8037 is active
Amsterdam inherits EIP-7623 floor gas.
The minimum required gas is:
max(regular + state, floor)A transaction where
floor > regular + statemust still be rejected ifgasLimit < floor, even if it satisfiesregular + state.Suggested test
Send a transaction with 100 non-zero calldata bytes to an existing account:
tokens = 100 * 4 = 400regular_intrinsic = 21000 + 400 * 4 = 22600state = 0floor = 21000 + 400 * 10 = 25000Cases:
gasLimit = 23000gasLimit = 250003. Nested CREATE code deposit must not borrow caller gas via state spill
When a CREATE returns initcode output, code deposit under EIP-8037 has:
CodeDepositRegularPerWord * wordsCostPerStateByte * bytesIf the child frame's state reservoir is insufficient, the shortfall spills into regular gas.
The important invariant is:
It must not be possible for the deposit charge to succeed by consuming the caller's retained gas after the child frame has been merged back.
Suggested test
A contract called via CALL performs CREATE of a 1-byte contract.
Because the parent frame has no state reservoir, the child also has no state reservoir, so the full code-deposit state cost spills into regular gas.
Tune gas so that after initcode execution the child ends with:
For a 1-byte deployed contract:
regularDepositCost = 6stateDepositCost = 11741180A child ending with
1175gas should fail code deposit.Expected result:
Context
These cases were found during Nethermind's Amsterdam / EIP-8037 implementation.
Nethermind fixes and regression tests: NethermindEth/nethermind#10712