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)
|