Skip to content

Commit

Permalink
new(tests): EOF - EIP-4750: Runtime stack overflow at CALLF (#678)
Browse files Browse the repository at this point in the history
* new(tests): Add test for stack reaching max size in called function

* new(tests): Add test for CALLF runtime stack overflow

* Update changelog
  • Loading branch information
gumb0 authored Jul 17, 2024
1 parent 4520ea7 commit 0154afa
Show file tree
Hide file tree
Showing 4 changed files with 272 additions and 0 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ Test fixtures for use by clients are available for each release on the [Github r
- ✨ Convert a few eip1153 tests from ethereum/tests repo into .py ([#440](https://github.com/ethereum/execution-spec-tests/pull/440)).
- ✨ Add tests for [EIP-7480: EOF - Data section access instructions](https://eips.ethereum.org/EIPS/eip-7480) ([#518](https://github.com/ethereum/execution-spec-tests/pull/518), [#664](https://github.com/ethereum/execution-spec-tests/pull/664)).
- ✨ Add tests for subcontainer kind validation from [EIP-7620: EOF Contract Creation](https://eips.ethereum.org/EIPS/eip-7620) for the cases with deeply nested containers and non-first code sections ([#676](https://github.com/ethereum/execution-spec-tests/pull/676)).
- ✨ Add tests for runtime stack overflow at CALLF instruction from [EIP-4750: EOF - Functions](https://eips.ethereum.org/EIPS/eip-4750) for the cases with deeply nested containers and non-first code sections ([#678](https://github.com/ethereum/execution-spec-tests/pull/678)).

### 🛠️ Framework

Expand Down
3 changes: 3 additions & 0 deletions tests/prague/eip7692_eof_v1/eip4750_functions/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
"""
EOF tests for EIP-4750 functions
"""
14 changes: 14 additions & 0 deletions tests/prague/eip7692_eof_v1/eip4750_functions/helpers.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
"""
EOF Functions tests helpers
"""

import itertools

"""Storage addresses for common testing fields"""
_slot = itertools.count()
next(_slot) # don't use slot 0
slot_code_worked = next(_slot)
slot_last_slot = next(_slot)

"""Storage values for common testing fields"""
value_code_worked = 0x2015
254 changes: 254 additions & 0 deletions tests/prague/eip7692_eof_v1/eip4750_functions/test_callf_execution.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
"""
EOF CALLF execution tests
"""

import pytest

from ethereum_test_tools import Account, EOFStateTestFiller
from ethereum_test_tools import Opcodes as Op
from ethereum_test_tools.eof.v1 import Container, Section

from .. import EOF_FORK_NAME
from .helpers import slot_code_worked, value_code_worked

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

pytestmark = pytest.mark.valid_from(EOF_FORK_NAME)


def test_callf_stack_size_1024(
eof_state_test: EOFStateTestFiller,
):
"""Test stack reaching 1024 items in called function"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1023
+ Op.CALLF[1]
+ Op.POP * 1023
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1023,
),
Section.Code(
Op.PUSH0 + Op.POP + Op.RETF,
code_inputs=0,
code_outputs=0,
max_stack_height=1,
),
],
),
container_post=Account(storage={slot_code_worked: value_code_worked}),
)


def test_callf_with_inputs_stack_size_1024(
eof_state_test: EOFStateTestFiller,
):
"""Test stack reaching 1024 items in called function with inputs"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1023
+ Op.CALLF[1]
+ Op.POP * 1023
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1023,
),
Section.Code(
Op.PUSH0 + Op.POP + Op.RETF,
code_inputs=3,
code_outputs=3,
max_stack_height=4,
),
],
),
container_post=Account(storage={slot_code_worked: value_code_worked}),
)


def test_callf_stack_size_1024_at_callf(
eof_state_test: EOFStateTestFiller,
):
"""Test stack reaching 1024 items in called function at CALLF instruction"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1023
+ Op.CALLF[1]
+ Op.POP * 1023
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1023,
),
Section.Code(
Op.CALLF[2] +
# stack has 1024 items
Op.POP + Op.RETF,
code_inputs=0,
code_outputs=0,
max_stack_height=1,
),
Section.Code(
Op.PUSH0 + Op.RETF, # stack has 1024 items
code_inputs=0,
code_outputs=1,
max_stack_height=1,
),
],
),
container_post=Account(storage={slot_code_worked: value_code_worked}),
)


def test_callf_stack_size_1024_at_push(
eof_state_test: EOFStateTestFiller,
):
"""Test stack reaching 1024 items in nested called function at PUSH0 instruction"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1022
+ Op.CALLF[1]
+ Op.POP * 1022
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1022,
),
Section.Code(
Op.PUSH0 +
# stack has 1023 items
Op.CALLF[2] + Op.POP + Op.RETF,
code_inputs=0,
code_outputs=0,
max_stack_height=1,
),
Section.Code(
Op.PUSH0 +
# stack has 1024 items
Op.POP + Op.RETF,
code_inputs=0,
code_outputs=0,
max_stack_height=1,
),
],
),
container_post=Account(storage={slot_code_worked: value_code_worked}),
)


def test_callf_stack_overflow(
eof_state_test: EOFStateTestFiller,
):
"""Test stack overflowing 1024 items in called function"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1023
+ Op.CALLF[1]
+ Op.POP * 1023
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1023,
),
Section.Code(
Op.PUSH0 +
# Stack has 1024 items
Op.CALLF[2] + Op.POP + Op.RETF,
code_inputs=0,
code_outputs=0,
max_stack_height=1,
),
Section.Code(
Op.PUSH0 +
# Runtime stack overflow
Op.POP + Op.RETF,
code_inputs=0,
code_outputs=0,
max_stack_height=1,
),
],
),
container_post=Account(storage={slot_code_worked: 0}),
)


def test_callf_with_inputs_stack_size_1024_at_push(
eof_state_test: EOFStateTestFiller,
):
"""Test stack reaching 1024 items in nested called function with inputs at PUSH0 instruction"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1022
+ Op.CALLF[1]
+ Op.POP * 1022
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1022,
),
Section.Code(
Op.PUSH0 +
# Stack has 1023 items
Op.CALLF[2] + Op.POP + Op.RETF,
code_inputs=3,
code_outputs=3,
max_stack_height=4,
),
Section.Code(
Op.PUSH0 +
# Stack has 1024 items
Op.POP + Op.RETF,
code_inputs=3,
code_outputs=3,
max_stack_height=4,
),
],
),
container_post=Account(storage={slot_code_worked: value_code_worked}),
)


def test_callf_with_inputs_stack_overflow(
eof_state_test: EOFStateTestFiller,
):
"""Test stack overflowing 1024 items in called function with inputs"""
eof_state_test(
data=Container(
sections=[
Section.Code(
code=Op.PUSH0 * 1023
+ Op.CALLF[1]
+ Op.POP * 1023
+ Op.SSTORE(slot_code_worked, value_code_worked)
+ Op.RETURN(0, 0),
max_stack_height=1023,
),
Section.Code(
Op.PUSH0 +
# Stack has 1024 items
Op.CALLF[2] + Op.POP + Op.RETF,
code_inputs=3,
code_outputs=3,
max_stack_height=4,
),
Section.Code(
Op.PUSH0 +
# Runtime stackoverflow
Op.POP + Op.RETF,
code_inputs=3,
code_outputs=3,
max_stack_height=4,
),
],
),
container_post=Account(storage={slot_code_worked: 0}),
)

0 comments on commit 0154afa

Please sign in to comment.