@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),
},
)