@pytest.mark.ported_from(
[
"https://github.com/ethereum/tests/blob/v13.3/src/GeneralStateTestsFiller/VMTests/vmTests/pushFiller.yml",
],
pr=["https://github.com/ethereum/execution-spec-tests/pull/975"],
)
@pytest.mark.parametrize(
"push_opcode",
[getattr(Op, f"PUSH{i}") for i in range(1, 33)],
ids=lambda op: str(op),
)
@pytest.mark.parametrize("stack_height", range(1024, 1026))
@pytest.mark.valid_from("Frontier")
@pytest.mark.slow()
def test_stack_overflow(
state_test: StateTestFiller,
fork: Fork,
pre: Alloc,
push_opcode: Op,
stack_height: int,
) -> None:
"""
Test that the stack overflows when the stack limit of 1024 is exceeded.
"""
env = Environment()
# Input used to test the `PUSH*` opcode.
excerpt = get_input_for_push_opcode(push_opcode)
"""
Essentially write a n-byte message to storage by pushing [1024,1025] times
to stack. This simulates a "jump" over the stack limit of 1024.
The message is UTF-8 encoding of excerpt (say 0x45 for PUSH1). Within the
stack limit, the message is written to the to the storage at the same
offset (0x45 for PUSH1). The last iteration will overflow the stack and the
storage slot will be empty.
** Bytecode explanation **
+---------------------------------------------------+
| Bytecode | Stack | Storage |
|---------------------------------------------------|
| PUSH* excerpt | excerpt | |
| PUSH1 0 | 0 excerpt | |
| SSTORE | | [0]: excerpt |
+---------------------------------------------------+
"""
contract_code: Bytecode = Bytecode()
for _ in range(stack_height - 2):
# mostly push 0 to avoid contract size limit exceeded
contract_code += Op.PUSH1(0)
contract_code += push_opcode(excerpt) * 2 + Op.SSTORE
contract = pre.deploy_contract(contract_code)
tx = Transaction(
sender=pre.fund_eoa(),
to=contract,
protected=fork.supports_protected_txs(),
)
post = {}
key = int.from_bytes(excerpt, "big")
# Storage should ONLY have the message if stack does not overflow.
value = key if stack_height <= 1024 else 0
post[contract] = Account(storage={key: value})
state_test(env=env, pre=pre, post=post, tx=tx)