Skip to content

test_recreate_in_later_block()

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

Generate fixtures for these test cases for Amsterdam with:

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

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
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
@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 4 forks.