Skip to content

test_create_account_creation_charge()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py::test_create_account_creation_charge@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_create_account_creation_charge --fork Amsterdam

Verify NEW_ACCOUNT is charged for a new account and refunded for a pre-existing balance-only leaf.

Empty init code means zero code deposit, so NEW_ACCOUNT is the only create state cost. A fresh target is charged it; a pre-existing balance-only target (balance, no code, zero nonce) refunds it on success. The probe SSTORE both confirms the create succeeded and makes state gas dominate, so gas_used drops by exactly NEW_ACCOUNT when refunded.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
@pytest.mark.parametrize(
    "target",
    [
        pytest.param("new", id="new_account"),
        pytest.param("existing", id="existing_account"),
    ],
)
@pytest.mark.with_all_create_opcodes()
@pytest.mark.valid_from("EIP8037")
def test_create_account_creation_charge(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    create_opcode: Op,
    target: str,
) -> None:
    """
    Verify NEW_ACCOUNT is charged for a new account and refunded for a
    pre-existing balance-only leaf.

    Empty init code means zero code deposit, so NEW_ACCOUNT is the only
    create state cost. A fresh target is charged it; a pre-existing
    balance-only target (balance, no code, zero nonce) refunds it on
    success. The probe SSTORE both confirms the create succeeded and
    makes state gas dominate, so gas_used drops by exactly NEW_ACCOUNT
    when refunded.
    """
    new_account = fork.gas_costs().NEW_ACCOUNT
    sstore_state_gas = Op.SSTORE(new_value=1).state_cost(fork)
    mstore_value, size = init_code_at_high_bytes(Op.STOP)
    create_call = (
        create_opcode(value=0, offset=0, size=size, salt=0)
        if create_opcode == Op.CREATE2
        else create_opcode(value=0, offset=0, size=size)
    )

    storage = Storage()
    factory = pre.deploy_contract(
        code=Op.MSTORE(0, mstore_value)
        + Op.SSTORE(
            storage.store_next(1, "create_succeeds"), Op.GT(create_call, 0)
        )
    )

    # Factory deployed via deploy_contract starts at nonce 1.
    if create_opcode == Op.CREATE2:
        create_address = compute_create2_address(
            address=factory, salt=0, initcode=bytes(Op.STOP)
        )
    else:
        create_address = compute_create_address(address=factory, nonce=1)
    if target == "existing":
        pre.fund_address(create_address, amount=1)

    tx = Transaction(
        to=factory,
        state_gas_reservoir=new_account + sstore_state_gas,
        sender=pre.fund_eoa(),
    )

    # State gas dominates regular: a new account adds NEW_ACCOUNT on top
    # of the probe SSTORE, a pre-existing target refunds it.
    expected = sstore_state_gas + (new_account if target == "new" else 0)
    state_test(
        pre=pre,
        tx=tx,
        post={factory: Account(storage=storage)},
        blockchain_test_header_verify=Header(gas_used=expected),
    )

Parametrized Test Cases

This test generates 4 parametrized test cases across 1 fork.