Skip to content

test_repaid_credit_enters_next_call_forwarding_base()

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

Test repaid gas participates in the next call's 63/64 base.

Without the repayment, the parent has one gas less than the smallest base whose 63/64 allowance can run the probe. The clearing child's merge repays a full slot charge before the probe call, so the allowance grows, the probe completes, and its marker changes.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_cross_frame_refund.py
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
@pytest.mark.valid_from("EIP8037")
def test_repaid_credit_enters_next_call_forwarding_base(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
) -> None:
    """
    Test repaid gas participates in the next call's 63/64 base.

    Without the repayment, the parent has one gas less than the
    smallest base whose 63/64 allowance can run the probe. The clearing
    child's merge repays a full slot charge before the probe call, so
    the allowance grows, the probe completes, and its marker changes.
    """
    intrinsic_cost = fork.transaction_intrinsic_cost_calculator()()
    sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)

    clearer_code = WARM_CLEAR(SLOT_X, 0)
    clearer = pre.deploy_contract(code=clearer_code)
    head = FRESH_SET(SLOT_X, 1) + Op.POP(
        Op.DELEGATECALL(gas=Op.GAS, address=clearer, address_warm=False)
    )

    # A nonzero-to-nonzero write leaves an observable success marker
    # without consuming state gas of its own.
    probe_code = Op.SSTORE.with_metadata(
        key_warm=False,
        original_value=1,
        current_value=1,
        new_value=2,
    )(SLOT_X, 2)
    probe = pre.deploy_contract(code=probe_code, storage={SLOT_X: 1})
    probe_execution = probe_code.execution_cost(fork)

    # Find the smallest base whose EIP-150 allowance
    # `base - base // 64` covers the probe exactly.
    forwarding_base = (probe_execution - 1) * 64 // 63 + 1
    assert (
        forwarding_base - 1 - (forwarding_base - 1) // 64
        < probe_execution
        <= forwarding_base - forwarding_base // 64
    )
    repaid_base = forwarding_base - 1 + sstore_state_gas
    assert repaid_base - repaid_base // 64 >= probe_execution

    probe_call = Op.CALL(
        gas=0xFFFFFFFF,
        address=probe,
        value=0,
        args_offset=0,
        args_size=0,
        ret_offset=0,
        ret_size=0,
        address_warm=False,
    )
    # With no repayment, paying the call's own execution cost leaves
    # `forwarding_base - 1`, so the probe OOGs by construction. The
    # repayment is the only additional execution gas available.
    sliver = probe_call.execution_cost(fork) + forwarding_base - 1
    clear_budget = budget_above_sstore_stipend(fork, clearer_code)
    assert sliver >= clear_budget * 64 // 63 + 1
    gas_limit = (
        intrinsic_cost
        + head.gas_cost(fork)
        + clearer_code.gas_cost(fork)
        + sliver
    )

    contract = pre.deploy_contract(code=head + Op.POP(probe_call))
    tx = Transaction(
        to=contract,
        gas_limit=gas_limit,
        sender=pre.fund_eoa(),
    )

    post = {
        contract: Account(storage={SLOT_X: 0}),
        probe: Account(storage={SLOT_X: 2}),
    }
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.