Skip to content

test_cross_frame_refund_repays_spill_at_merge()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_cross_frame_refund.py::test_cross_frame_refund_repays_spill_at_merge@622620d8.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_cross_frame_refund.py::test_cross_frame_refund_repays_spill_at_merge --fork Amsterdam

Test a cross-frame refund repays the spill when the child merges.

The frame sets a slot with an empty or half-slot reservoir, spilling the uncovered state charge from gas_left. A child sharing the caller's storage clears the slot and the credit lands in the reservoir, which repays the spill on the merge: gas_left is higher after the clearing call than before it, and the clearing window costs exactly the spilled amount less than a no-op window. Half-slot funding makes the spill smaller than the full-slot refund, catching repayment tracked by slot count.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_cross_frame_refund.py
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
@pytest.mark.parametrize("call_opcode", [Op.CALLCODE, Op.DELEGATECALL])
@pytest.mark.parametrize(
    "fund_half_slot",
    [False, True],
    ids=["empty-reservoir", "half-slot-reservoir"],
)
@pytest.mark.valid_from("EIP8037")
def test_cross_frame_refund_repays_spill_at_merge(
    state_test: StateTestFiller,
    pre: Alloc,
    call_opcode: Opcode,
    fork: Fork,
    fund_half_slot: bool,
) -> None:
    """
    Test a cross-frame refund repays the spill when the child merges.

    The frame sets a slot with an empty or half-slot reservoir, spilling
    the uncovered state charge from `gas_left`. A child sharing the
    caller's storage clears the slot and the credit lands in the
    reservoir, which repays the spill on the merge:
    `gas_left` is higher after the clearing call than before it, and
    the clearing window costs exactly the spilled amount less than a
    no-op window. Half-slot funding makes the spill smaller than the
    full-slot refund, catching repayment tracked by slot count.
    """
    sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)
    reservoir = sstore_state_gas // 2 if fund_half_slot else 0
    spilled = sstore_state_gas - reservoir

    clearer = pre.deploy_contract(code=Op.SSTORE(SLOT_X, 0))
    window = Op.POP(call_opcode(address=clearer))
    contract = pre.deploy_contract(
        code=clearing_probe_code(Op.SSTORE(SLOT_X, 1), [window] * 3)
    )

    tx = Transaction(
        to=contract,
        state_gas_reservoir=reservoir,
        sender=pre.fund_eoa(),
    )

    post = {
        contract: Account(
            storage={
                SLOT_X: 0,
                SLOT_MARKER: 1,
                SLOT_INCREASED: 1,
                SLOT_RESULT: -spilled,
            }
        )
    }
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 4 parametrized test cases across 1 fork.