Skip to content

test_stack_underflow()

Documentation for tests/frontier/opcodes/test_swap.py::test_stack_underflow@ffe48572.

Generate fixtures for these test cases for Bogota with:

fill -v tests/frontier/opcodes/test_swap.py::test_stack_underflow --fork Bogota

Test that the stack underflows when there are not enough elements for the SWAP* opcode to operate.

For each SWAPn operation, we push exactly (n-1) elements to cause an underflow when trying to swap with the nth element.

Source code in tests/frontier/opcodes/test_swap.py
@pytest.mark.parametrize(
    "swap_opcode",
    [getattr(Op, f"SWAP{i}") for i in range(1, 17)],
    ids=lambda op: str(op),
)
@pytest.mark.valid_from("Frontier")
@pytest.mark.eels_base_coverage
def test_stack_underflow(
    state_test: StateTestFiller,
    fork: Fork,
    pre: Alloc,
    swap_opcode: Op,
) -> None:
    """
    Test that the stack underflows when there are not enough elements for the
    `SWAP*` opcode to operate.

    For each SWAPn operation, we push exactly (n-1) elements to cause an
    underflow when trying to swap with the nth element.
    """
    env = Environment()

    # Calculate which position we're swapping with (1-based index)
    swap_pos = swap_opcode.int() - 0x90 + 1

    # Push exactly (n-1) elements for SWAPn to cause underflow
    contract_code = Bytecode()
    for i in range(swap_pos - 1):
        contract_code += Op.PUSH1(i % 256)

    # Attempt to perform the SWAP operation
    contract_code += swap_opcode

    # Store the top of the stack in storage slot 0
    contract_code += Op.PUSH1(0) + Op.SSTORE

    # Deploy the contract with the generated bytecode.
    contract = pre.deploy_contract(contract_code)

    # Create a transaction to execute the contract.
    tx = Transaction(
        sender=pre.fund_eoa(),
        to=contract,
        protected=fork.supports_protected_txs(),
    )

    # Define the expected post-state.
    post = {}
    storage = Storage()
    storage.store_next(0, f"SWAP{swap_pos} failed due to stack underflow")
    post[contract] = Account(storage=storage)

    # Run the state test.
    state_test(env=env, pre=pre, post=post, tx=tx)

Parametrized Test Cases

This test generates 16 parametrized test cases across 17 forks.