Skip to content

test_create2_revert_preserves_balance()

Documentation for tests/constantinople/eip1014_create2/test_create2_revert.py::test_create2_revert_preserves_balance@b314d18e.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/constantinople/eip1014_create2/test_create2_revert.py::test_create2_revert_preserves_balance --fork Amsterdam

Test that CREATE2 revert preserves pre-existing balance at target.

Address X has a pre-existing balance but no code. CREATE2 targets X with init code that reverts. After the revert, X must still have its original balance, nonce=0, and no code or storage.

Source code in tests/constantinople/eip1014_create2/test_create2_revert.py
24
25
26
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
@pytest.mark.valid_from("Constantinople")
@pytest.mark.pre_alloc_mutable
def test_create2_revert_preserves_balance(
    state_test: StateTestFiller,
    pre: Alloc,
) -> None:
    """
    Test that CREATE2 revert preserves pre-existing balance at target.

    Address X has a pre-existing balance but no code. CREATE2 targets X
    with init code that reverts. After the revert, X must still have its
    original balance, nonce=0, and no code or storage.
    """
    env = Environment()
    factory_storage = Storage()
    salt = 0
    pre_balance = 1

    # Init code that writes storage then reverts.
    initcode = Op.SSTORE(0, 1) + Op.REVERT(offset=0, size=0)

    # Factory receives initcode via calldata, does CREATE2.
    factory = pre.deploy_contract(
        Op.CALLDATACOPY(0, 0, Op.CALLDATASIZE)
        + Op.SSTORE(
            factory_storage.store_next(0, "create2_result"),
            Op.CREATE2(
                value=0,
                offset=0,
                size=Op.CALLDATASIZE,
                salt=salt,
            ),
        )
        + Op.STOP,
        storage=factory_storage.canary(),
    )

    target = compute_create2_address(factory, salt, initcode)

    # Pre-allocate target with balance only.
    pre[target] = Account(balance=pre_balance)

    sender = pre.fund_eoa()

    state_test(
        env=env,
        pre=pre,
        post={
            # CREATE2 returns 0 on failure.
            factory: Account(storage=factory_storage),
            # Target keeps its balance, no code deployed.
            target: Account(balance=pre_balance, nonce=0, code=b""),
        },
        tx=Transaction(
            sender=sender,
            to=factory,
            data=initcode,
        ),
    )

Parametrized Test Cases

This test generates 1 parametrized test case across 11 forks.