Skip to content

test_inner_create_succeeds_code_deposit_state_gas()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py::test_inner_create_succeeds_code_deposit_state_gas@8acae1b0.

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_inner_create_succeeds_code_deposit_state_gas --fork Amsterdam

Verify state gas accumulation and top-level failure handling in a creation tx whose initcode runs a successful inner CREATE.

Under EIP-2780 the outer (tx-level) created account's NEW_ACCOUNT is charged at the top frame from gas_left (not the intrinsic), so gas_limit must cover it on top of the inner CREATE's own state gas. On success the block state gas is the outer NEW_ACCOUNT plus the inner account creation and code deposit.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
@pytest.mark.parametrize(
    "outer_outcome",
    [
        pytest.param("succeeds", id="outer_succeeds"),
        pytest.param("reverts", id="outer_reverts"),
        pytest.param("halts", id="outer_halts"),
    ],
)
@pytest.mark.with_all_create_opcodes()
@pytest.mark.valid_from("EIP8037")
def test_inner_create_succeeds_code_deposit_state_gas(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: Fork,
    create_opcode: Op,
    outer_outcome: str,
) -> None:
    """
    Verify state gas accumulation and top-level failure handling in a
    creation tx whose initcode runs a successful inner CREATE.

    Under EIP-2780 the outer (tx-level) created account's ``NEW_ACCOUNT``
    is charged at the top frame from ``gas_left`` (not the intrinsic), so
    ``gas_limit`` must cover it on top of the inner CREATE's own state
    gas. On success the block state gas is the outer ``NEW_ACCOUNT`` plus
    the inner account creation and code deposit.
    """
    outer_state_gas = fork.create_state_gas(code_size=0)

    deploy_code = Op.STOP
    inner_initcode = Op.MSTORE(
        0,
        int.from_bytes(bytes(deploy_code), "big") << 248,
    ) + Op.RETURN(31, 1, code_deposit_size=len(deploy_code))
    inner_bytes = bytes(inner_initcode)
    inner_code_deposit = inner_initcode.state_cost(fork)

    setup = Op.MSTORE(
        0,
        int.from_bytes(inner_bytes, "big") << (256 - 8 * len(inner_bytes)),
    )
    if create_opcode == Op.CREATE2:
        inner_create = Op.POP(Op.CREATE2(0, 0, len(inner_bytes), 0))
    else:
        inner_create = Op.POP(Op.CREATE(0, 0, len(inner_bytes)))
    # Inner account creation plus the inner contract's code deposit.
    inner_state_gas = inner_create.state_cost(fork) + inner_code_deposit

    if outer_outcome == "succeeds":
        termination = Op.RETURN(0, 0)
    elif outer_outcome == "reverts":
        termination = Op.REVERT(0, 0)
    else:
        termination = Op.INVALID

    initcode = setup + inner_create + termination

    sender = pre.fund_eoa()
    intrinsic_calc = fork.transaction_intrinsic_cost_calculator()
    intrinsic_total = intrinsic_calc(
        calldata=bytes(initcode), contract_creation=True
    )

    if outer_outcome == "halts":
        initcode_gas = initcode.execution_cost(fork)
    else:
        initcode_gas = initcode.gas_cost(fork)
    # The outer created account's NEW_ACCOUNT is a top-frame state charge
    # under EIP-2780; gas_limit must cover it alongside the initcode and
    # the inner code deposit.
    gas_limit = (
        intrinsic_total
        + outer_state_gas
        + initcode_gas
        + inner_code_deposit
        + 1000
    )

    create_address = compute_create_address(address=sender, nonce=0)

    tx = Transaction(
        sender=sender,
        to=None,
        data=initcode,
        gas_limit=gas_limit,
    )

    if outer_outcome == "succeeds":
        post: dict = {create_address: Account(code=b"")}
        block = Block(
            txs=[tx],
            header_verify=Header(gas_used=outer_state_gas + inner_state_gas),
        )
    else:
        post = {create_address: Account.NONEXISTENT}
        block = Block(txs=[tx])

    blockchain_test(pre=pre, blocks=[block], post=post)

Parametrized Test Cases

This test generates 6 parametrized test cases across 1 fork.