Skip to content

test_call_frame_credit_repays_spill_before_fixed_gas_probe()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_cross_frame_refund.py::test_call_frame_credit_repays_spill_before_fixed_gas_probe@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_call_frame_credit_repays_spill_before_fixed_gas_probe --fork Amsterdam

Test a plain CALL credit repays the spill before a fixed-gas probe.

The transaction starts with no reservoir. The spilling frame merges its claim into the parent. A sibling or grandchild clears the slot, and its credit repays that claim when it reaches the parent. The probe receives only its execution cost, so it cannot fund its state charge from the repaid gas. It fails with or without the clear.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_cross_frame_refund.py
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
@pytest.mark.parametrize(
    "raises_credit",
    [
        pytest.param(True, id="credit_repaid_probe_oogs"),
        pytest.param(False, id="no_credit_probe_oogs"),
    ],
)
@pytest.mark.parametrize("depth", ["sibling", "grandchild"])
@pytest.mark.valid_from("EIP8037")
def test_call_frame_credit_repays_spill_before_fixed_gas_probe(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    depth: str,
    raises_credit: bool,
) -> None:
    """
    Test a plain CALL credit repays the spill before a fixed-gas probe.

    The transaction starts with no reservoir. The spilling frame merges
    its claim into the parent. A sibling or grandchild clears the slot,
    and its credit repays that claim when it reaches the parent. The
    probe receives only its execution cost, so it cannot fund its state
    charge from the repaid gas. It fails with or without the clear.
    """
    # A CALL callee owns its storage, so splitting the charge from the
    # credit needs one contract entered twice rather than two contracts.
    toggler = pre.deploy_contract(
        code=Op.SSTORE(SLOT_X, Op.ISZERO(Op.SLOAD(SLOT_X)))
    )
    clearing_target = toggler
    if depth == "grandchild":
        clearing_target = pre.deploy_contract(
            code=Op.POP(Op.CALL(gas=Op.GAS, address=toggler))
        )

    # Without the second entry no credit is raised. Both cases leave
    # the reservoir empty when the fixed-gas probe runs.
    if not raises_credit:
        clearing_target = pre.deploy_contract(code=Op.STOP)

    probe_storage = Storage()
    probe_code = Op.SSTORE(probe_storage.store_next(0, "probe_ran"), 1)
    probe = pre.deploy_contract(probe_code)
    probe_stipend = probe_code.execution_cost(fork)

    entry = pre.deploy_contract(
        code=(
            Op.POP(Op.CALL(gas=Op.GAS, address=toggler))
            + Op.POP(Op.CALL(gas=Op.GAS, address=clearing_target))
            + Op.POP(Op.CALL(gas=probe_stipend, address=probe))
        )
    )

    tx = Transaction(
        to=entry,
        state_gas_reservoir=0,
        sender=pre.fund_eoa(),
    )

    post = {
        toggler: Account(storage={SLOT_X: 0 if raises_credit else 1}),
        probe: Account(storage=probe_storage),
    }
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 4 parametrized test cases across 1 fork.