@EIPChecklist.Opcode.Test.DataPortion.AllZeros()
@EIPChecklist.Opcode.Test.DataPortion.MaxValue()
@pytest.mark.parametrize(
"immediate",
[0, 1, 15, 78, 79, 80, 81, 128, 129, 200, 255],
ids=lambda x: f"exchange_imm_{x}",
)
def test_exchange_valid_immediates(
immediate: int,
pre: Alloc,
fork: Fork,
state_test: StateTestFiller,
) -> None:
"""Test EXCHANGE with valid immediate values (0-81 and 128-255)."""
sender = pre.fund_eoa()
# Decode the immediate to get the stack indices
# EXCHANGE with decoded (n, m) swaps position (n+1) with position (m+1)
n, m = decode_pair(immediate)
stack_height = m + 1 # Need at least m+1 items
value_at_n_plus_1 = 0xAAAA
value_at_m_plus_1 = 0xBBBB
# Build stack
code = Bytecode()
for i in range(stack_height):
stack_pos = stack_height - i
if stack_pos == n + 1:
code += Op.PUSH2(value_at_n_plus_1)
elif stack_pos == m + 1:
code += Op.PUSH2(value_at_m_plus_1)
else:
code += Op.PUSH2(0x1000 + i)
# Pass immediate as bytes (raw immediate byte for testing)
code += Op.EXCHANGE[immediate.to_bytes(1, "big")]
# Store the swapped values
for i in range(stack_height):
code += Op.PUSH1(i) + Op.SSTORE
code += Op.STOP
contract_address = pre.deploy_contract(code=code)
tx = Transaction(to=contract_address, sender=sender)
# Build expected storage
expected_storage = {}
for i in range(stack_height):
stack_pos = i + 1
if stack_pos == n + 1:
expected_storage[i] = value_at_m_plus_1
elif stack_pos == m + 1:
expected_storage[i] = value_at_n_plus_1
else:
original_i = stack_height - stack_pos
expected_storage[i] = 0x1000 + original_i
post = {contract_address: Account(storage=expected_storage)}
state_test(pre=pre, post=post, tx=tx)