Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

new(tests): EOF - EIP-4750: Runtime stack overflow at CALLF #678

Merged
merged 3 commits into from
Jul 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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,
),
marioevz marked this conversation as resolved.
Show resolved Hide resolved
],
),
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}),
)