Skip to content

Commit b870605

Browse files
authored
new(tests): add EOF CALLF stack overflow validation tests (ethereum#1073)
1 parent ac6ebba commit b870605

File tree

1 file changed

+87
-1
lines changed

1 file changed

+87
-1
lines changed

osaka/eip7692_eof_v1/eip4750_functions/test_code_validation.py

Lines changed: 87 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,21 @@
66

77
from ethereum_test_tools import EOFException, EOFTestFiller
88
from ethereum_test_tools.eof.v1 import Container, Section
9-
from ethereum_test_tools.eof.v1.constants import MAX_CODE_SECTIONS
9+
from ethereum_test_tools.eof.v1.constants import (
10+
MAX_CODE_OUTPUTS,
11+
MAX_CODE_SECTIONS,
12+
MAX_OPERAND_STACK_HEIGHT,
13+
)
1014
from ethereum_test_tools.vm.opcode import Opcodes as Op
1115

1216
from .. import EOF_FORK_NAME
1317

1418
REFERENCE_SPEC_GIT_PATH = "EIPS/eip-4750.md"
1519
REFERENCE_SPEC_VERSION = "14400434e1199c57d912082127b1d22643788d11"
1620

21+
MAX_RUNTIME_OPERAND_STACK_HEIGHT = 1024
22+
"""Maximum height of the EVM runtime operand stack."""
23+
1724
pytestmark = pytest.mark.valid_from(EOF_FORK_NAME)
1825

1926
VALID: List[Container] = [
@@ -343,3 +350,82 @@ def test_unreachable_code_sections(
343350
(i.e. code sections not reachable from the code section 0).
344351
"""
345352
eof_test(data=container, expect_exception=EOFException.UNREACHABLE_CODE_SECTIONS)
353+
354+
355+
@pytest.mark.parametrize("callee_outputs", [1, 2, MAX_CODE_OUTPUTS])
356+
def test_callf_stack_height_limit_exceeded(eof_test, callee_outputs):
357+
"""
358+
Test for invalid EOF code containing CALLF instruction exceeding the stack height limit.
359+
The code reaches the maximum runtime stack height (1024)
360+
which is above the EOF limit for the stack height in the type section (1023).
361+
"""
362+
callf_stack_height = MAX_RUNTIME_OPERAND_STACK_HEIGHT - callee_outputs
363+
container = Container(
364+
sections=[
365+
Section.Code(
366+
Op.PUSH0 * callf_stack_height + Op.CALLF[1] + Op.STOP,
367+
max_stack_height=MAX_RUNTIME_OPERAND_STACK_HEIGHT,
368+
),
369+
Section.Code(
370+
Op.PUSH0 * callee_outputs + Op.RETF,
371+
code_outputs=callee_outputs,
372+
max_stack_height=callee_outputs,
373+
),
374+
],
375+
)
376+
eof_test(data=container, expect_exception=EOFException.MAX_STACK_HEIGHT_ABOVE_LIMIT)
377+
378+
379+
@pytest.mark.parametrize("callee_outputs", [1, 2, MAX_CODE_OUTPUTS - 1, MAX_CODE_OUTPUTS])
380+
@pytest.mark.parametrize(
381+
"max_stack_height", [0, 1, MAX_OPERAND_STACK_HEIGHT - 1, MAX_OPERAND_STACK_HEIGHT]
382+
)
383+
def test_callf_stack_overflow_by_outputs(eof_test, callee_outputs, max_stack_height):
384+
"""
385+
Test for invalid EOF code containing CALLF instruction exceeding the runtime stack height limit
386+
by calling a function with at least one output. The computed stack height of the code section 0
387+
is always above the maximum allowed in the EOF type section. Therefore, the test declares
388+
an invalid max_stack_height.
389+
"""
390+
callf_stack_height = (MAX_RUNTIME_OPERAND_STACK_HEIGHT + 1) - callee_outputs
391+
container = Container(
392+
sections=[
393+
Section.Code(
394+
Op.PUSH0 * callf_stack_height + Op.CALLF[1] + Op.STOP,
395+
max_stack_height=max_stack_height,
396+
),
397+
Section.Code(
398+
Op.PUSH0 + Op.DUP1 + Op.RETF,
399+
code_outputs=callee_outputs,
400+
max_stack_height=callee_outputs,
401+
),
402+
],
403+
)
404+
eof_test(data=container, expect_exception=EOFException.STACK_OVERFLOW)
405+
406+
407+
@pytest.mark.parametrize(
408+
"callee_stack_height",
409+
[2, 3, MAX_OPERAND_STACK_HEIGHT - 1, MAX_OPERAND_STACK_HEIGHT],
410+
)
411+
def test_callf_stack_overflow_by_height(eof_test, callee_stack_height):
412+
"""
413+
Test for invalid EOF code containing CALLF instruction exceeding the runtime stack height limit
414+
by calling a function with 2+ maximum stack height.
415+
The callee with the maximum stack height of 1 is valid because runtime limit (1024)
416+
is 1 bigger than the EOF limit (1023).
417+
"""
418+
container = Container(
419+
sections=[
420+
Section.Code(
421+
Op.PUSH0 * MAX_OPERAND_STACK_HEIGHT + Op.CALLF[1] + Op.STOP,
422+
max_stack_height=MAX_OPERAND_STACK_HEIGHT,
423+
),
424+
Section.Code(
425+
Op.PUSH0 * callee_stack_height + Op.POP * callee_stack_height + Op.RETF,
426+
code_outputs=0,
427+
max_stack_height=callee_stack_height,
428+
),
429+
],
430+
)
431+
eof_test(data=container, expect_exception=EOFException.STACK_OVERFLOW)

0 commit comments

Comments
 (0)