Skip to content

test_calling_from_new_contract_to_pre_existing_contract()

Documentation for tests/cancun/eip6780_selfdestruct/test_selfdestruct.py::test_calling_from_new_contract_to_pre_existing_contract@21fb11c8.

Generate fixtures for these test cases for Prague with:

fill -v tests/cancun/eip6780_selfdestruct/test_selfdestruct.py::test_calling_from_new_contract_to_pre_existing_contract --fork Prague

Test that if an account created in the current transaction delegate-call a previously created account that executes self-destruct, the calling account is deleted.

Source code in tests/cancun/eip6780_selfdestruct/test_selfdestruct.py
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
@pytest.mark.parametrize("call_times", [1])
@pytest.mark.parametrize("selfdestruct_contract_initial_balance", [0, 1])
@pytest.mark.parametrize("call_opcode", [Op.DELEGATECALL, Op.CALLCODE])
@pytest.mark.parametrize("create_opcode", [Op.CREATE])
@pytest.mark.valid_from("Shanghai")
def test_calling_from_new_contract_to_pre_existing_contract(
    state_test: StateTestFiller,
    env: Environment,
    pre: Alloc,
    sender: EOA,
    sendall_recipient_addresses: List[Address],
    create_opcode: Op,
    call_opcode: Op,
    call_times: int,
    selfdestruct_contract_initial_balance: int,
):
    """
    Test that if an account created in the current transaction delegate-call a previously created
    account that executes self-destruct, the calling account is deleted.
    """
    pre_existing_selfdestruct_address = pre.deploy_contract(
        selfdestruct_code_preset(
            sendall_recipient_addresses=sendall_recipient_addresses,
        ),
    )
    # Our entry point is an initcode that in turn creates a self-destructing contract
    entry_code_storage = Storage()
    sendall_amount = 0

    entry_code_address = compute_create_address(address=sender, nonce=0)
    selfdestruct_contract_address = compute_create_address(address=entry_code_address, nonce=1)

    pre.fund_address(selfdestruct_contract_address, selfdestruct_contract_initial_balance)

    # self-destructing call
    selfdestruct_code = call_opcode(address=pre_existing_selfdestruct_address)
    selfdestruct_contract_initcode = Initcode(deploy_code=selfdestruct_code)
    initcode_copy_from_address = pre.deploy_contract(selfdestruct_contract_initcode)

    # Bytecode used to create the contract, can be CREATE or CREATE2
    create_bytecode = create_opcode(size=len(selfdestruct_contract_initcode))

    # Entry code that will be executed, creates the contract and then calls it in the same tx
    entry_code = (
        # Initcode is already deployed at `initcode_copy_from_address`, so just copy it
        Op.EXTCODECOPY(
            initcode_copy_from_address,
            0,
            0,
            len(selfdestruct_contract_initcode),
        )
        # And we store the created address for verification purposes
        + Op.SSTORE(
            entry_code_storage.store_next(selfdestruct_contract_address),
            create_bytecode,
        )
    )

    # Store the EXTCODE* properties of the created address
    entry_code += Op.SSTORE(
        entry_code_storage.store_next(len(selfdestruct_code)),
        Op.EXTCODESIZE(selfdestruct_contract_address),
    )

    entry_code += Op.SSTORE(
        entry_code_storage.store_next(selfdestruct_code.keccak256()),
        Op.EXTCODEHASH(selfdestruct_contract_address),
    )

    # Call the self-destructing contract multiple times as required, increasing the wei sent each
    # time
    entry_code_balance = 0
    for i in range(call_times):
        entry_code += Op.SSTORE(
            entry_code_storage.store_next(1),
            Op.CALL(
                Op.GASLIMIT,  # Gas
                selfdestruct_contract_address,  # Address
                i,  # Value
                0,
                0,
                0,
                0,
            ),
        )
        entry_code_balance += i
        sendall_amount += i

        entry_code += Op.SSTORE(
            entry_code_storage.store_next(0),
            Op.BALANCE(selfdestruct_contract_address),
        )

    # Check the EXTCODE* properties of the self-destructing contract again
    entry_code += Op.SSTORE(
        entry_code_storage.store_next(len(selfdestruct_code)),
        Op.EXTCODESIZE(selfdestruct_contract_address),
    )

    entry_code += Op.SSTORE(
        entry_code_storage.store_next(selfdestruct_code.keccak256()),
        Op.EXTCODEHASH(selfdestruct_contract_address),
    )

    # Lastly return zero so the entry point contract is created and we can retain the stored
    # values for verification.
    entry_code += Op.RETURN(max(len(selfdestruct_contract_initcode), 32), 1)

    if selfdestruct_contract_initial_balance > 0:
        # Address where the contract is created already had some balance,
        # which must be included in the send-all operation
        sendall_amount += selfdestruct_contract_initial_balance

    post: Dict[Address, Account] = {
        entry_code_address: Account(
            storage=entry_code_storage,
        ),
        selfdestruct_contract_address: Account.NONEXISTENT,  # type: ignore
        sendall_recipient_addresses[0]: Account(balance=sendall_amount, storage={0: 1}),
    }

    tx = Transaction(
        value=entry_code_balance,
        data=entry_code,
        sender=sender,
        to=None,
        gas_limit=500_000,
    )

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

Parametrized Test Cases

The interactive table below is also available as a standalone page.

Test ID (Abbreviated) create_opcode call_opcode selfdestruct_contract_initial_balance call_times
...fork_Shanghai-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Shanghai-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Shanghai-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Shanghai-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Shanghai-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Shanghai-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Shanghai-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Shanghai-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Cancun-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Cancun-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Cancun-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Cancun-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Cancun-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Cancun-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Cancun-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Cancun-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Prague-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Prague-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Prague-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Prague-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Prague-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Prague-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Prague-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Prague-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Osaka-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Osaka-state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Osaka-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Osaka-state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1
...fork_Osaka-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_0-call_times_1 CREATE DELEGATECALL 0 1
...fork_Osaka-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_DELEGATECALL-selfdestruct_contract_initial_balance_1-call_times_1 CREATE DELEGATECALL 1 1
...fork_Osaka-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_0-call_times_1 CREATE CALLCODE 0 1
...fork_Osaka-blockchain_test_from_state_test-create_opcode_CREATE-call_opcode_CALLCODE-selfdestruct_contract_initial_balance_1-call_times_1 CREATE CALLCODE 1 1