Skip to content

test_create_address_dynamic_nonce()

Documentation for tests/frontier/create/test_create_preimage_layout.py::test_create_address_dynamic_nonce@b314d18e.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/frontier/create/test_create_preimage_layout.py::test_create_address_dynamic_nonce --fork Amsterdam

Verify CreatePreimageLayout dynamic nonce encoding matches CREATE.

A contract calls CREATE(value=0, offset=0, size=0) in a loop, computes the expected address using the dynamic nonce RLP encoder, and reverts if any computed address differs from the actual one.

The loop runs from nonce 1 to 260, crossing the RLP encoding boundary at nonce 128 (1-byte to 2-byte encoding) and at 256 where it has to change the 0x80 prefix to 0x81.

Source code in tests/frontier/create/test_create_preimage_layout.py
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
@pytest.mark.valid_from("Osaka")
def test_create_address_dynamic_nonce(
    pre: Alloc,
    state_test: StateTestFiller,
) -> None:
    """
    Verify CreatePreimageLayout dynamic nonce encoding matches CREATE.

    A contract calls CREATE(value=0, offset=0, size=0) in a loop,
    computes the expected address using the dynamic nonce RLP encoder,
    and reverts if any computed address differs from the actual one.

    The loop runs from nonce 1 to 260, crossing the RLP encoding
    boundary at nonce 128 (1-byte to 2-byte encoding) and at
    256 where it has to change the 0x80 prefix to 0x81.
    """
    iterations = 260

    # Memory[0:32] is used as the loop counter.
    # Layout starts at offset 32 to avoid conflict.
    layout = CreatePreimageLayout(
        sender_address=Op.ADDRESS,
        nonce=Op.PUSH1(1),
        offset=32,
    )

    # Build the loop body: check address, revert on mismatch,
    # increment nonce, decrement counter.
    body = (
        Conditional(
            condition=Op.EQ(
                layout.address_op(),
                Op.CREATE(value=0, offset=0, size=0),
            ),
            if_false=Op.REVERT(0, 0),
        )
        + layout.increment_nonce_op()
        + Op.MSTORE(0, Op.SUB(Op.MLOAD(0), 1))
    )

    code: Bytecode = layout
    code += Op.MSTORE(0, iterations)
    code += While(body=body, condition=Op.MLOAD(0))
    code += Op.SSTORE(0, 1)
    code += Op.STOP

    contract = pre.deploy_contract(code=code)
    sender = pre.fund_eoa()

    tx = Transaction(
        to=contract,
        sender=sender,
    )

    post = {contract: Account(storage={0: 1})}
    for nonce in range(1, iterations + 1):
        created = compute_create_address(address=contract, nonce=nonce)
        post[created] = Account(nonce=1)

    state_test(pre=pre, tx=tx, post=post)

Parametrized Test Cases

This test generates 1 parametrized test case across 2 forks.