Skip to content

test_endofcode_behavior()

Documentation for tests/amsterdam/eip8024_dupn_swapn_exchange/test_exchange.py::test_endofcode_behavior@b314d18e.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip8024_dupn_swapn_exchange/test_exchange.py::test_endofcode_behavior --fork Amsterdam

Test EXCHANGE when the immediate byte is beyond the end of code.

Per EIP-8024, code[pc + 1] evaluates to 0 if beyond the end of the code, matching PUSH behavior. With immediate = 0, decode_pair(0) = (9, 16), so EXCHANGE swaps positions 10 and 17.

This test verifies the transaction succeeds (doesn't revert) when EXCHANGE is the last byte of the code with no immediate byte following it.

Source code in tests/amsterdam/eip8024_dupn_swapn_exchange/test_exchange.py
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
def test_endofcode_behavior(
    pre: Alloc,
    state_test: StateTestFiller,
) -> None:
    """
    Test EXCHANGE when the immediate byte is beyond the end of code.

    Per EIP-8024, code[pc + 1] evaluates to 0 if beyond the end of the code,
    matching PUSH behavior. With immediate = 0, decode_pair(0) = (9, 16), so
    EXCHANGE swaps positions 10 and 17.

    This test verifies the transaction succeeds (doesn't revert) when EXCHANGE
    is the last byte of the code with no immediate byte following it.
    """
    sender = pre.fund_eoa()

    # decode_pair(0) = (9, 16), which swaps positions 10 and 17
    # We need 17 items on the stack for this to succeed
    stack_height = 17
    marker_value = 0x42

    # Build code: store marker, push enough items, then EXCHANGE (no immediate)
    code = Bytecode()
    code += Op.PUSH1(marker_value) + Op.PUSH1(0) + Op.SSTORE  # Store marker

    # Push 17 items to stack so EXCHANGE with implicit imm=0 succeeds
    for i in range(stack_height):
        code += Op.PUSH1(i)

    # Add just the EXCHANGE opcode without immediate byte
    # After EXCHANGE, pc += 2 goes beyond code, causing implicit STOP
    code += Op.EXCHANGE  # no immediate

    contract_address = pre.deploy_contract(code=code)

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

    # If tx succeeds, storage[0] = marker_value
    # Bad implementation would revert and have empty storage
    post = {contract_address: Account(storage={0: marker_value})}

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

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.