Skip to content

test_selfdestruct_in_create_tx_initcode()

Documentation for tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py::test_selfdestruct_in_create_tx_initcode@622620d8.

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

Verify state gas accounting when a creation tx's initcode immediately SELFDESTRUCTs to a new beneficiary.

Under EIP-2780 the created contract'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 initcode. The block state gas is the created contract's NEW_ACCOUNT plus the fresh beneficiary's NEW_ACCOUNT charged by the SELFDESTRUCT.

Source code in tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
@pytest.mark.valid_from("EIP8037")
def test_selfdestruct_in_create_tx_initcode(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: Fork,
) -> None:
    """
    Verify state gas accounting when a creation tx's initcode
    immediately SELFDESTRUCTs to a new beneficiary.

    Under EIP-2780 the created contract'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 initcode. The block state gas is the
    created contract's ``NEW_ACCOUNT`` plus the fresh beneficiary's
    ``NEW_ACCOUNT`` charged by the SELFDESTRUCT.
    """
    create_state_gas = fork.create_state_gas(code_size=0)

    beneficiary = 0xDEAD
    # `account_new` folds the beneficiary's `ACCOUNT_WRITE` execution
    # cost and account-creation state gas into `gas_cost`.
    initcode = Op.SELFDESTRUCT(beneficiary, account_new=True)

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

    # State: the created contract's top-frame NEW_ACCOUNT plus the fresh
    # beneficiary's NEW_ACCOUNT from the SELFDESTRUCT.
    expected_state = create_state_gas + initcode.state_cost(fork)

    initcode_gas = initcode.gas_cost(fork)
    gas_limit = intrinsic_execution + create_state_gas + initcode_gas + 1000

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

    blockchain_test(
        pre=pre,
        blocks=[
            Block(
                txs=[tx],
                header_verify=Header(gas_used=expected_state),
            ),
        ],
        post={},
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.