Skip to content

test_collision_with_create2_revert_in_initcode()

Documentation for tests/paris/eip7610_create_collision/test_revert_in_create.py::test_collision_with_create2_revert_in_initcode@b47f0253.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/paris/eip7610_create_collision/test_revert_in_create.py::test_collision_with_create2_revert_in_initcode --fork Amsterdam

Test that a CREATE transaction collision with pre-existing storage causes the transaction to fail, even when the initcode would perform CREATE2 with reverting inner initcode.

The initcode (if it were to run) would: 1. Execute CREATE2 with inner initcode that reverts with 32 bytes of data 2. Store RETURNDATASIZE to storage slot 0 3. Copy returndata to memory and store to slot 1

Since there's a collision (pre-existing storage), the CREATE TX should fail and the pre-existing account should remain unchanged.

Source code in tests/paris/eip7610_create_collision/test_revert_in_create.py
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
@pytest.mark.ported_from(
    [
        "https://github.com/ethereum/tests/tree/v13.3/src/GeneralStateTestsFiller/stCreate2/RevertInCreateInInitCreate2ParisFiller.json",  # noqa: E501
    ],
    pr=["https://github.com/ethereum/execution-specs/pull/2031"],
)
def test_collision_with_create2_revert_in_initcode(
    state_test: StateTestFiller,
    pre: Alloc,
) -> None:
    """
    Test that a CREATE transaction collision with pre-existing storage causes
    the transaction to fail, even when the initcode would perform CREATE2 with
    reverting inner initcode.

    The initcode (if it were to run) would:
    1. Execute CREATE2 with inner initcode that reverts with 32 bytes of data
    2. Store RETURNDATASIZE to storage slot 0
    3. Copy returndata to memory and store to slot 1

    Since there's a collision (pre-existing storage), the CREATE TX should fail
    and the pre-existing account should remain unchanged.
    """
    inner_initcode = Op.MSTORE(0, 0x112233) + Op.REVERT(0, 32)

    initcode = (
        Op.MSTORE(0, Op.PUSH32(bytes(inner_initcode).ljust(32, b"\0")))
        + Op.CREATE2(value=0, offset=0, size=len(inner_initcode), salt=0)
        + Op.SSTORE(0, Op.RETURNDATASIZE)
        + Op.RETURNDATACOPY(0, 0, 32)
        + Op.SSTORE(1, Op.MLOAD(0))
        + Op.STOP
    )

    sender = pre.fund_eoa()
    tx = Transaction(
        sender=sender,
        to=None,
        data=initcode,
        gas_limit=10_000_000,
    )

    # Pre-existing account with storage - this causes collision per EIP-7610.
    pre[tx.created_contract] = Account(
        balance=10,
        storage={0x00: 0x01},
    )

    state_test(
        pre=pre,
        post={
            (tx.created_contract): Account(
                balance=10,
                nonce=0,
                storage={0x00: 0x01},
            ),
        },
        tx=tx,
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 6 forks.