Test SWAPN 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_single(0) = 145, so
SWAPN swaps position 1 with position 146.
This test verifies the transaction succeeds (doesn't revert) when SWAPN
is the last byte of the code with no immediate byte following it.
Source code in tests/amsterdam/eip8024_dupn_swapn_exchange/test_swapn.py
| def test_endofcode_behavior(
pre: Alloc,
state_test: StateTestFiller,
) -> None:
"""
Test SWAPN 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_single(0) = 145, so
SWAPN swaps position 1 with position 146.
This test verifies the transaction succeeds (doesn't revert) when SWAPN
is the last byte of the code with no immediate byte following it.
"""
sender = pre.fund_eoa()
# decode_single(0) = 145, which swaps position 1 with position 146
# We need 146 items on the stack for this to succeed
stack_height = 146
marker_value = 0x42
# Build code: store marker, push enough items, then SWAPN (no immediate)
code = Bytecode()
code += Op.PUSH1(marker_value) + Op.PUSH1(0) + Op.SSTORE # Store marker
# Push 146 items to stack so SWAPN with implicit imm=0 succeeds
for i in range(stack_height):
code += Op.PUSH1(i % 256)
# Add just the SWAPN opcode without immediate byte
# After SWAPN, pc += 2 goes beyond code, causing implicit STOP
code += Op.SWAPN # 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)
|