Skip to content

test_bal_create2_selfdestruct_then_recreate_and_write()

Documentation for tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_opcodes.py::test_bal_create2_selfdestruct_then_recreate_and_write@8acae1b0.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_opcodes.py::test_bal_create2_selfdestruct_then_recreate_and_write --fork Amsterdam

Ensure storage_reads unions the wiped SSTOREs of an address that two transactions each recreate, write and destroy at the same CREATE2 destination.

Reported in erigontech/erigon#23407.

Source code in tests/amsterdam/eip7928_block_level_access_lists/test_block_access_lists_opcodes.py
4046
4047
4048
4049
4050
4051
4052
4053
4054
4055
4056
4057
4058
4059
4060
4061
4062
4063
4064
4065
4066
4067
4068
4069
4070
4071
4072
4073
4074
4075
4076
4077
4078
4079
4080
4081
4082
4083
4084
4085
4086
4087
4088
4089
4090
4091
4092
4093
4094
4095
4096
4097
4098
4099
4100
4101
4102
4103
4104
4105
4106
4107
4108
4109
4110
4111
4112
4113
4114
def test_bal_create2_selfdestruct_then_recreate_and_write(
    pre: Alloc,
    blockchain_test: BlockchainTestFiller,
) -> None:
    """
    Ensure `storage_reads` unions the wiped `SSTORE`s of an address that two
    transactions each recreate, write and destroy at the same CREATE2
    destination.

    Reported in https://github.com/erigontech/erigon/issues/23407.
    """
    alice = pre.fund_eoa()
    beneficiary = pre.fund_eoa(amount=0)
    salt = 0
    target_balance = 100

    # The balance names the slot, so the second transaction cannot pick its
    # own until the first one has drained the account.
    initcode = bytes(
        Op.SSTORE(Op.SELFBALANCE, 0xCAFE) + Op.SELFDESTRUCT(beneficiary)
    )
    factory = pre.deploy_contract(
        code=Om.MSTORE(initcode, 0)
        + Op.POP(Op.CREATE2(offset=0, size=len(initcode), salt=salt))
    )
    target = compute_create_address(
        address=factory,
        salt=salt,
        initcode=initcode,
        opcode=Op.CREATE2,
    )
    pre.fund_address(target, target_balance)

    blockchain_test(
        pre=pre,
        blocks=[
            Block(
                txs=[Transaction(sender=alice, to=factory) for _ in range(2)],
                expected_block_access_list=BlockAccessListExpectation(
                    account_expectations={
                        target: BalAccountExpectation(
                            balance_changes=[
                                BalBalanceChange(
                                    block_access_index=1, post_balance=0
                                ),
                            ],
                            nonce_changes=[],
                            code_changes=[],
                            storage_changes=[],
                            storage_reads=[0, target_balance],
                        ),
                        beneficiary: BalAccountExpectation(
                            balance_changes=[
                                BalBalanceChange(
                                    block_access_index=1,
                                    post_balance=target_balance,
                                ),
                            ],
                        ),
                    }
                ),
            )
        ],
        post={
            target: Account.NONEXISTENT,
            beneficiary: Account(balance=target_balance),
            factory: Account(nonce=3),
        },
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.