Skip to content

test_create_nonce_overflow()

Documentation for tests/berlin/eip2929_gas_cost_increases/test_create.py::test_create_nonce_overflow@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/berlin/eip2929_gas_cost_increases/test_create.py::test_create_nonce_overflow --fork Bogota

Test that a failed CREATE/CREATE2 due to sender nonce overflow does not warm the contract address.

A creator contract with nonce 2^64-1 (max) attempts to create. The create aborts because the nonce cannot be incremented, and a subsequent BALANCE check verifies the would-be contract address remains cold.

Source code in tests/berlin/eip2929_gas_cost_increases/test_create.py
@pytest.mark.valid_from("Berlin")
@pytest.mark.parametrize(
    "create_opcode",
    [
        pytest.param(Op.CREATE, id="CREATE"),
        pytest.param(Op.CREATE2, id="CREATE2"),
    ],
)
def test_create_nonce_overflow(
    state_test: StateTestFiller,
    pre: Alloc,
    env: Environment,
    fork: Fork,
    create_opcode: Op,
) -> None:
    """
    Test that a failed CREATE/CREATE2 due to sender nonce overflow does not
    warm the contract address.

    A creator contract with nonce 2^64-1 (max) attempts to create. The
    create aborts because the nonce cannot be incremented, and a subsequent
    BALANCE check verifies the would-be contract address remains cold.
    """
    initcode = Op.STOP

    creator_code = Op.MSTORE(
        0, Op.PUSH32(bytes(initcode).ljust(32, b"\0"))
    ) + Op.SSTORE(
        0,
        create_opcode(value=0, offset=0, size=len(initcode)),
    )

    # Nonce at max value (2^64-1) causes CREATE to abort
    creator_address = pre.deploy_contract(
        creator_code, nonce=2**64 - 1, storage={0: 1}
    )

    # Pre-compute the address that would have been created
    contract_address = compute_create_address(
        address=creator_address,
        nonce=2**64 - 1,
        salt=0,
        initcode=initcode,
        opcode=create_opcode,
    )

    # Measure gas cost of BALANCE on the would-be contract address;
    # cold access proves the address was not warmed by the failed create
    cold_balance = Op.BALANCE(contract_address, address_warm=False)
    checker_address = pre.deploy_contract(
        CodeGasMeasure(
            code=cold_balance,
            extra_stack_items=1,
            sstore_key=1,
        )
    )

    entry_address = pre.deploy_contract(
        Op.CALL(gas=Op.GAS, address=creator_address)
        + Op.CALL(gas=Op.GAS, address=checker_address)
        + Op.STOP
    )

    tx = Transaction(
        to=entry_address,
        gas_limit=1_000_000,
        sender=pre.fund_eoa(),
    )

    post = {
        # CREATE returned 0 (failed)
        creator_address: Account(storage={0: 0}),
        # BALANCE gas cost matches cold access
        checker_address: Account(storage={1: cold_balance.gas_cost(fork)}),
    }
    state_test(env=env, pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 2 parametrized test cases across 9 forks.