Skip to content

test_swapn_full_stack()

Documentation for tests/amsterdam/eip8024_dupn_swapn_exchange/test_swapn.py::test_swapn_full_stack@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/amsterdam/eip8024_dupn_swapn_exchange/test_swapn.py::test_swapn_full_stack --fork Bogota

Test SWAPN succeeds on a completely full stack.

SWAPN swaps in place without pushing, so it must work at the stack limit. The top marker is swapped down to position stack_index + 1; popping stack_index items then exposes it. If a faulty implementation had not swapped, the popped-to item would hold the planted deep marker instead, so either direction of failure is visible in storage.

Source code in tests/amsterdam/eip8024_dupn_swapn_exchange/test_swapn.py
@EIPChecklist.Opcode.Test.StackComplexOperations.DataPortionVariables.Top()
@EIPChecklist.Opcode.Test.StackComplexOperations.DataPortionVariables.Middle()
@pytest.mark.parametrize(
    "stack_index",
    [17, 126, 235],
    ids=lambda x: f"swapn_full_stack_{x}",
)
def test_swapn_full_stack(
    stack_index: int,
    pre: Alloc,
    fork: Fork,
    state_test: StateTestFiller,
) -> None:
    """
    Test SWAPN succeeds on a completely full stack.

    SWAPN swaps in place without pushing, so it must work at the stack
    limit. The top marker is swapped down to position `stack_index + 1`;
    popping `stack_index` items then exposes it. If a faulty
    implementation had not swapped, the popped-to item would hold the
    planted deep marker instead, so either direction of failure is
    visible in storage.
    """
    sender = pre.fund_eoa()

    top_marker = 0xAAAA
    deep_marker = 0xBBBB

    # Full stack, top-down: the top marker at position 1, the deep
    # marker at the swap target, position stack_index + 1.
    stack = [0] * fork.max_stack_height()
    stack[0] = top_marker
    stack[stack_index] = deep_marker

    code = Bytecode()
    for value in reversed(stack):
        code += Op.PUSH2(value) if value else Op.PUSH0

    code += Op.SWAPN[stack_index]

    # Pop down to the swap target and store the item now there.
    code += Op.POP * stack_index
    code += Op.PUSH1(0) + Op.SSTORE
    code += Op.STOP

    contract_address = pre.deploy_contract(code=code, storage={0: 0xBA5E})

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

    post = {contract_address: Account(storage={0: top_marker})}

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

Parametrized Test Cases

This test generates 3 parametrized test cases across 2 forks.