Skip to content

test_worst_initcode_jumpdest_analysis()

Documentation for tests/benchmark/test_worst_bytecode.py::test_worst_initcode_jumpdest_analysis@0f7c73a7.

Generate fixtures for these test cases for Prague with:

fill -v tests/benchmark/test_worst_bytecode.py::test_worst_initcode_jumpdest_analysis --fork Prague

Test the jumpdest analysis performance of the initcode.

This benchmark places a very long initcode in the memory and then invoke CREATE instructions with this initcode up to the block gas limit. The initcode itself has minimal execution time but forces the EVM to perform the full jumpdest analysis on the parametrized byte pattern. The initicode is modified by mixing-in the returned create address between CREATE invocations to prevent caching.

Source code in tests/benchmark/test_worst_bytecode.py
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
@pytest.mark.valid_from("Cancun")
@pytest.mark.parametrize(
    "pattern",
    [
        Op.STOP,
        Op.JUMPDEST,
        Op.PUSH1[bytes(Op.JUMPDEST)],
        Op.PUSH2[bytes(Op.JUMPDEST + Op.JUMPDEST)],
        Op.PUSH1[bytes(Op.JUMPDEST)] + Op.JUMPDEST,
        Op.PUSH2[bytes(Op.JUMPDEST + Op.JUMPDEST)] + Op.JUMPDEST,
    ],
    ids=lambda x: x.hex(),
)
def test_worst_initcode_jumpdest_analysis(
    state_test: StateTestFiller,
    pre: Alloc,
    fork: Fork,
    pattern: Bytecode,
):
    """
    Test the jumpdest analysis performance of the initcode.

    This benchmark places a very long initcode in the memory and then invoke CREATE instructions
    with this initcode up to the block gas limit. The initcode itself has minimal execution time
    but forces the EVM to perform the full jumpdest analysis on the parametrized byte pattern.
    The initicode is modified by mixing-in the returned create address between CREATE invocations
    to prevent caching.
    """
    max_code_size = fork.max_code_size()
    initcode_size = fork.max_initcode_size()

    # Expand the initcode pattern to the transaction data so it can be used in CALLDATACOPY
    # in the main contract. TODO: tune the tx_data_len param.
    tx_data_len = 1024
    tx_data = pattern * (tx_data_len // len(pattern))
    tx_data += (tx_data_len - len(tx_data)) * bytes(Op.JUMPDEST)
    assert len(tx_data) == tx_data_len
    assert initcode_size % len(tx_data) == 0

    # Prepare the initcode in memory.
    code_prepare_initcode = sum(
        (
            Op.CALLDATACOPY(dest_offset=i * len(tx_data), offset=0, size=Op.CALLDATASIZE)
            for i in range(initcode_size // len(tx_data))
        ),
        Bytecode(),
    )

    # At the start of the initcode execution, jump to the last opcode.
    # This forces EVM to do the full jumpdest analysis.
    initcode_prefix = Op.JUMP(initcode_size - 1)
    code_prepare_initcode += Op.MSTORE(
        0, Op.PUSH32[bytes(initcode_prefix).ljust(32, bytes(Op.JUMPDEST))]
    )

    # Make sure the last opcode in the initcode is JUMPDEST.
    code_prepare_initcode += Op.MSTORE(initcode_size - 32, Op.PUSH32[bytes(Op.JUMPDEST) * 32])

    code_invoke_create = (
        Op.PUSH1[len(initcode_prefix)]
        + Op.MSTORE
        + Op.CREATE(value=Op.PUSH0, offset=Op.PUSH0, size=Op.MSIZE)
    )

    initial_random = Op.PUSH0
    code_prefix = code_prepare_initcode + initial_random
    code_loop_header = Op.JUMPDEST
    code_loop_footer = Op.JUMP(len(code_prefix))
    code_loop_body_len = (
        max_code_size - len(code_prefix) - len(code_loop_header) - len(code_loop_footer)
    )

    code_loop_body = (code_loop_body_len // len(code_invoke_create)) * bytes(code_invoke_create)
    code = code_prefix + code_loop_header + code_loop_body + code_loop_footer
    assert (max_code_size - len(code_invoke_create)) < len(code) <= max_code_size

    env = Environment()

    tx = Transaction(
        to=pre.deploy_contract(code=code),
        data=tx_data,
        gas_limit=env.gas_limit,
        sender=pre.fund_eoa(),
    )

    state_test(
        env=env,
        pre=pre,
        post={},
        tx=tx,
    )

Parametrized Test Cases

The interactive table below is also available as a standalone page.

Test ID (Abbreviated) pattern
...fork_Cancun-state_test-00 STOP
...fork_Cancun-state_test-5b JUMPDEST
...fork_Cancun-state_test-605b PUSH1_0x5b
...fork_Cancun-state_test-615b5b PUSH2_0x5b5b
...fork_Cancun-state_test-605b5b
...fork_Cancun-state_test-615b5b5b
...fork_Cancun-blockchain_test_from_state_test-00 STOP
...fork_Cancun-blockchain_test_from_state_test-5b JUMPDEST
...fork_Cancun-blockchain_test_from_state_test-605b PUSH1_0x5b
...fork_Cancun-blockchain_test_from_state_test-615b5b PUSH2_0x5b5b
...fork_Cancun-blockchain_test_from_state_test-605b5b
...fork_Cancun-blockchain_test_from_state_test-615b5b5b
...fork_Prague-state_test-00 STOP
...fork_Prague-state_test-5b JUMPDEST
...fork_Prague-state_test-605b PUSH1_0x5b
...fork_Prague-state_test-615b5b PUSH2_0x5b5b
...fork_Prague-state_test-605b5b
...fork_Prague-state_test-615b5b5b
...fork_Prague-blockchain_test_from_state_test-00 STOP
...fork_Prague-blockchain_test_from_state_test-5b JUMPDEST
...fork_Prague-blockchain_test_from_state_test-605b PUSH1_0x5b
...fork_Prague-blockchain_test_from_state_test-615b5b PUSH2_0x5b5b
...fork_Prague-blockchain_test_from_state_test-605b5b
...fork_Prague-blockchain_test_from_state_test-615b5b5b
...fork_Osaka-state_test-00 STOP
...fork_Osaka-state_test-5b JUMPDEST
...fork_Osaka-state_test-605b PUSH1_0x5b
...fork_Osaka-state_test-615b5b PUSH2_0x5b5b
...fork_Osaka-state_test-605b5b
...fork_Osaka-state_test-615b5b5b
...fork_Osaka-blockchain_test_from_state_test-00 STOP
...fork_Osaka-blockchain_test_from_state_test-5b JUMPDEST
...fork_Osaka-blockchain_test_from_state_test-605b PUSH1_0x5b
...fork_Osaka-blockchain_test_from_state_test-615b5b PUSH2_0x5b5b
...fork_Osaka-blockchain_test_from_state_test-605b5b
...fork_Osaka-blockchain_test_from_state_test-615b5b5b