Skip to content

test_code_deposit_oog_preserves_parent_reservoir()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py::test_code_deposit_oog_preserves_parent_reservoir@5c024cbb.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py::test_code_deposit_oog_preserves_parent_reservoir --fork Amsterdam

Test parent reservoir preserved after child code deposit OOG.

A caller contract invokes the factory via CALL with limited gas. The child CREATE returns enough bytes that code deposit state gas exceeds the child frame's available gas (reservoir spillover plus the limited gas_left). The factory's SSTORE after the failed CREATE proves the reservoir was not inflated by a spill-then-halt refund.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py
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
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
@pytest.mark.valid_from("EIP8037")
def test_code_deposit_oog_preserves_parent_reservoir(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
) -> None:
    """
    Test parent reservoir preserved after child code deposit OOG.

    A caller contract invokes the factory via CALL with limited gas.
    The child CREATE returns enough bytes that code deposit state gas
    exceeds the child frame's available gas (reservoir spillover plus
    the limited gas_left). The factory's SSTORE after the failed
    CREATE proves the reservoir was not inflated by a spill-then-halt
    refund.
    """
    gas_costs = fork.gas_costs()
    new_account_state_gas = gas_costs.NEW_ACCOUNT
    sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)

    # Small deploy size; code deposit state gas will exceed the
    # limited gas available in the CREATE child frame.
    deploy_size = 4096
    init_code = Op.RETURN(0, deploy_size)

    # Limited regular gas forwarded to the factory.  After CREATE
    # takes 63/64, the factory retains ~23 K for its SSTOREs.
    child_gas = 1_500_000

    factory_storage = Storage()
    factory = pre.deploy_contract(
        code=(
            Op.MSTORE(0, Op.PUSH32(bytes(init_code)))
            + Op.SSTORE(
                factory_storage.store_next(0, "create_fails"),
                Op.CREATE(
                    value=0,
                    offset=32 - len(init_code),
                    size=len(init_code),
                ),
            )
            # Reservoir must be fully preserved after failed CREATE;
            # parent can still perform its own SSTORE.
            + Op.SSTORE(
                factory_storage.store_next(1, "parent_sstore"),
                1,
            )
        ),
    )

    # Caller invokes factory with limited gas via CALL.
    caller = pre.deploy_contract(
        code=Op.CALL(gas=child_gas, address=factory),
    )

    # Reservoir = new-account state gas + one SSTORE's state gas.
    # Code deposit draws from the reservoir first then spills into
    # gas_left, which the limited CALL gas cannot cover.
    tx = Transaction(
        to=caller,
        state_gas_reservoir=new_account_state_gas + sstore_state_gas,
        sender=pre.fund_eoa(),
    )

    post = {factory: Account(storage=factory_storage)}
    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.