Skip to content

test_recreate_in_later_block()

Documentation for tests/cancun/eip6780_selfdestruct/test_selfdestruct_finalization.py::test_recreate_in_later_block@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/cancun/eip6780_selfdestruct/test_selfdestruct_finalization.py::test_recreate_in_later_block --fork Bogota

A contract is created and self-destructs in one block, then the same factory creates it again at the same address in a later block. Before EIP-8246 the first account is gone by then, so the second creation starts from nothing; from EIP-8246 on it lands on the balance the first one left behind and adds to it.

Source code in tests/cancun/eip6780_selfdestruct/test_selfdestruct_finalization.py
@pytest.mark.parametrize(
    "endowment",
    [pytest.param(0, id="zero_balance"), pytest.param(3, id="funded")],
)
@EIPChecklist.Opcode.Test.ExecutionContext.Initcode.Reentry(eip=[8246])
def test_recreate_in_later_block(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: Fork,
    endowment: int,
) -> None:
    """
    A contract is created and self-destructs in one block, then the same
    factory creates it again at the same address in a later block. Before
    EIP-8246 the first account is gone by then, so the second creation
    starts from nothing; from EIP-8246 on it lands on the balance the first
    one left behind and adds to it.
    """
    sender = pre.fund_eoa()
    initcode = Op.SELFDESTRUCT(Op.ADDRESS)
    factory = pre.deploy_contract(
        code=Om.MSTORE(initcode, 0)
        + Op.SSTORE(
            Op.CALLDATALOAD(0),
            Op.CREATE2(
                value=Op.CALLVALUE, offset=0, size=len(initcode), salt=0
            ),
        )
        + Op.STOP
    )
    created = compute_create_address(
        address=factory, salt=0, initcode=initcode, opcode=Op.CREATE2
    )

    def deploy(slot: int) -> Transaction:
        tx = Transaction(
            sender=sender, to=factory, value=endowment, data=Hash(slot)
        )
        if fork.is_eip_enabled(7708) and endowment > 0:
            tx.expected_receipt = TransactionReceipt(
                logs=[
                    transfer_log(sender, factory, endowment),
                    transfer_log(factory, created, endowment),
                ]
            )
        return tx

    # Each deployment keeps its endowment under EIP-8246, so the second one
    # finds the first one's balance still there.
    final_balance = 2 * endowment if fork.is_eip_enabled(8246) else 0

    blockchain_test(
        pre=pre,
        blocks=[Block(txs=[deploy(1)]), Block(txs=[deploy(2)])],
        post={
            factory: Account(nonce=3, storage={1: created, 2: created}),
            created: finalized(fork, final_balance),
        },
    )

Parametrized Test Cases

This test generates 2 parametrized test cases across 5 forks.