Skip to content

test_create_opcode_initcode()

Documentation for tests/shanghai/eip3860_initcode/test_initcode.py::TestCreateInitcode::test_create_opcode_initcode@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/shanghai/eip3860_initcode/test_initcode.py::TestCreateInitcode::test_create_opcode_initcode --fork Bogota

Test contract creation with valid and invalid initcode lengths.

Test contract creation via CREATE/CREATE2, parametrized by initcode that is on/over the max allowed limit.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.parametrize(
    "initcode_name",
    [
        "max_size_zeros",
        "max_size_ones",
        "over_limit_zeros",
        "over_limit_ones",
        "empty",
        "single_byte",
        "32_bytes",
        "33_bytes",
        "max_size_minus_word",
        "max_size_minus_word_plus_byte",
    ],
)
@pytest.mark.parametrize("opcode", [Op.CREATE, Op.CREATE2], ids=get_create_id)
class TestCreateInitcode:
    """
    Test contract creation with valid and invalid initcode lengths.

    Test contract creation via CREATE/CREATE2, parametrized by initcode that is
    on/over the max allowed limit.
    """

    @pytest.fixture
    def create2_salt(self) -> int:
        """
        Salt value used for CREATE2 contract creation.
        """
        return 0xDEADBEEF

    @pytest.fixture
    def create_code(
        self, opcode: Op, create2_salt: int, initcode: Initcode
    ) -> Bytecode:
        """
        Generate the CREATE/CREATE2 bytecode.
        """
        return (
            opcode(
                size=Op.CALLDATASIZE,
                salt=create2_salt,
                init_code_size=len(initcode),
            )
            if opcode == Op.CREATE2
            else opcode(size=Op.CALLDATASIZE, init_code_size=len(initcode))
        )

    @pytest.fixture
    def creator_code(self, fork: Fork, create_code: Bytecode) -> Bytecode:
        """
        Generate code for the creator contract which calls CREATE/CREATE2.
        """
        return (
            Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)
            + Op.GAS
            + create_code
            + Op.GAS
            # stack: [Gas 2, Call Result, Gas 1]
            + Op.SWAP1
            # stack: [Call Result, Gas 2, Gas 1]
            + Op.PUSH1[0]
            # stack: [0, Call Result, Gas 2, Gas 1]
            + Op.SSTORE
            # stack: [Gas 2, Gas 1]
            + Op.SWAP1
            # stack: [Gas 1, Gas 2]
            + Op.SUB
            # stack: [Gas 1 - Gas 2]
            + Op.PUSH1[Op.GAS.gas_cost(fork)]
            # stack: [Op.GAS cost, Gas 1 - Gas 2]
            + Op.SWAP1
            # stack: [Gas 1 - Gas 2, Op.GAS cost]
            + Op.SUB
            # stack: [Gas 1 - Gas 2 - Op.GAS cost]
            + Op.PUSH1[1]
            # stack: [1, Gas 1 - Gas 2 - Op.GAS cost]
            + Op.SSTORE
        )

    @pytest.fixture
    def creator_contract_address(
        self, pre: Alloc, creator_code: Bytecode
    ) -> Address:
        """Return address of creator contract."""
        return pre.deploy_contract(creator_code, label="creator_contract")

    @pytest.fixture
    def created_contract_address(  # noqa: D103
        self,
        opcode: Op,
        create2_salt: int,
        initcode: Initcode,
        creator_contract_address: Address,
    ) -> Address:
        """
        Calculate address of the contract created by the creator contract.
        """
        return compute_create_address(
            address=creator_contract_address,
            nonce=1,
            salt=create2_salt,
            initcode=initcode,
            opcode=opcode,
        )

    @pytest.fixture
    def caller_code(self, creator_contract_address: Address) -> Bytecode:
        """
        Generate code for the caller contract that calls the creator contract.
        """
        return Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE) + Op.SSTORE(
            Op.CALL(
                address=creator_contract_address, args_size=Op.CALLDATASIZE
            ),
            1,
        )

    @pytest.fixture
    def caller_contract_address(
        self, pre: Alloc, caller_code: Bytecode
    ) -> Address:
        """Return address of the caller contract."""
        return pre.deploy_contract(caller_code, label="caller_contract")

    @pytest.fixture
    def tx(
        self, caller_contract_address: Address, initcode: Initcode, sender: EOA
    ) -> Transaction:
        """Generate transaction that executes the caller contract."""
        return Transaction(
            to=caller_contract_address,
            data=initcode,
            state_gas_reservoir=0,  # Don't hide state gas from Op.GAS
            sender=sender,
        )

    @pytest.mark.bigmem
    @pytest.mark.xdist_group(name="bigmem")
    @pytest.mark.slow()
    def test_create_opcode_initcode(
        self,
        state_test: StateTestFiller,
        pre: Alloc,
        post: Alloc,
        tx: Transaction,
        initcode: Initcode,
        caller_contract_address: Address,
        creator_contract_address: Address,
        created_contract_address: Address,
        create_code: Bytecode,
        fork: Fork,
    ) -> None:
        """
        Test contract creation with valid and invalid initcode lengths.

        Test contract creation via CREATE/CREATE2, parametrized by initcode
        that is on/over the max allowed limit.
        """
        if len(initcode) > fork.max_initcode_size():
            # Call returns 0 as out of gas s[0]==1
            post[caller_contract_address] = Account(
                nonce=1,
                storage={
                    0: 1,
                    1: 0,
                },
            )

            post[created_contract_address] = Account.NONEXISTENT
            post[creator_contract_address] = Account(
                nonce=1,
                storage={
                    0: 0,
                    1: 0,
                },
            )

        else:
            expected_gas_usage = create_code.gas_cost(fork)
            # The initcode is only executed if the length check succeeds
            expected_gas_usage += initcode.gas_cost(fork)

            # Call returns 1 as valid initcode length s[0]==1 && s[1]==1
            post[caller_contract_address] = Account(
                nonce=1,
                storage={
                    0: 0,
                    1: 1,
                },
            )

            post[created_contract_address] = Account(code=initcode.deploy_code)
            post[creator_contract_address] = Account(
                nonce=2,
                storage={
                    0: created_contract_address,
                    1: expected_gas_usage,
                },
            )

        state_test(pre=pre, post=post, tx=tx)

test_create_opcode_initcode(state_test, pre, post, tx, initcode, caller_contract_address, creator_contract_address, created_contract_address, create_code, fork)

Test contract creation with valid and invalid initcode lengths.

Test contract creation via CREATE/CREATE2, parametrized by initcode that is on/over the max allowed limit.

Source code in tests/shanghai/eip3860_initcode/test_initcode.py
@pytest.mark.bigmem
@pytest.mark.xdist_group(name="bigmem")
@pytest.mark.slow()
def test_create_opcode_initcode(
    self,
    state_test: StateTestFiller,
    pre: Alloc,
    post: Alloc,
    tx: Transaction,
    initcode: Initcode,
    caller_contract_address: Address,
    creator_contract_address: Address,
    created_contract_address: Address,
    create_code: Bytecode,
    fork: Fork,
) -> None:
    """
    Test contract creation with valid and invalid initcode lengths.

    Test contract creation via CREATE/CREATE2, parametrized by initcode
    that is on/over the max allowed limit.
    """
    if len(initcode) > fork.max_initcode_size():
        # Call returns 0 as out of gas s[0]==1
        post[caller_contract_address] = Account(
            nonce=1,
            storage={
                0: 1,
                1: 0,
            },
        )

        post[created_contract_address] = Account.NONEXISTENT
        post[creator_contract_address] = Account(
            nonce=1,
            storage={
                0: 0,
                1: 0,
            },
        )

    else:
        expected_gas_usage = create_code.gas_cost(fork)
        # The initcode is only executed if the length check succeeds
        expected_gas_usage += initcode.gas_cost(fork)

        # Call returns 1 as valid initcode length s[0]==1 && s[1]==1
        post[caller_contract_address] = Account(
            nonce=1,
            storage={
                0: 0,
                1: 1,
            },
        )

        post[created_contract_address] = Account(code=initcode.deploy_code)
        post[creator_contract_address] = Account(
            nonce=2,
            storage={
                0: created_contract_address,
                1: expected_gas_usage,
            },
        )

    state_test(pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 20 parametrized test cases across 6 forks.