Skip to content

Commit

Permalink
new(tests): EOF: tests for invalid non-returning sections
Browse files Browse the repository at this point in the history
Add new EOF validation tests where the a section marked
returning/non-returning does not match the reality.
  • Loading branch information
chfast committed Sep 9, 2024
1 parent 8eed02f commit bd7ea51
Show file tree
Hide file tree
Showing 3 changed files with 115 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
"""
EOF validation tests for non-returning code sections.
"""

import pytest

from ethereum_test_tools import EOFException, EOFTestFiller
from ethereum_test_tools.eof.v1 import Container, Section
from ethereum_test_tools.vm.opcode import Opcodes as Op
from ethereum_test_types.eof.v1 import NON_RETURNING_SECTION
from ethereum_test_vm import Bytecode

from .. import EOF_FORK_NAME

REFERENCE_SPEC_GIT_PATH = "EIPS/eip-6206.md"
REFERENCE_SPEC_VERSION = "2f365ea0cd58faa6e26013ea77ce6d538175f7d0"

pytestmark = pytest.mark.valid_from(EOF_FORK_NAME)


@pytest.mark.parametrize(
"code_section",
[
pytest.param(Section.Code(Op.STOP, code_outputs=0), id="stop"),
pytest.param(Section.Code(Op.INVALID, code_outputs=0), id="invalid0"),
pytest.param(
Section.Code(Op.ADDRESS + Op.POP + Op.INVALID, code_outputs=0), id="invalid1"
),
pytest.param(Section.Code(Op.RETURN(0, 0), code_outputs=0), id="return"),
pytest.param(Section.Code(Op.RETF, code_outputs=0), id="retf0"),
pytest.param(Section.Code(Op.PUSH0 + Op.RETF, code_outputs=1), id="retf1"),
],
)
def test_first_section_returning(eof_test: EOFTestFiller, code_section: Section):
"""Test EOF validation failing because the first section is not non-returning."""
eof_test(
data=Container(
sections=[code_section], validity_error=EOFException.INVALID_FIRST_SECTION_TYPE
)
)


@pytest.mark.parametrize(
"code_section",
[
pytest.param(Section.Code(Op.RETF, code_outputs=NON_RETURNING_SECTION), id="retf0"),
pytest.param(
Section.Code(Op.PUSH0 + Op.RETF, code_outputs=NON_RETURNING_SECTION), id="retf1"
),
],
)
def test_retf_in_nonreturning(eof_test: EOFTestFiller, code_section: Section):
"""
Test EOF validation failing because a non-returning section contains the RETF instruction.
"""
# TODO: This can be further parametrized to put the offending section as not-first one.
eof_test(
data=Container(
sections=[code_section], validity_error=EOFException.INVALID_NON_RETURNING_FLAG
)
)


@pytest.mark.parametrize("first", [True, False])
@pytest.mark.parametrize("code_prefix", [Bytecode(), Op.PUSH0])
def test_jumpf_in_nonreturning(eof_test: EOFTestFiller, first: bool, code_prefix: Bytecode):
"""
Test EOF validation failing because a non-returning section contains the JUMPF instruction.
"""
invalid_section = Section.Code(
code_prefix + Op.JUMPF[1 if first else 2],
code_outputs=NON_RETURNING_SECTION,
)
target_section = Section.Code(Op.RETF)
sections = [invalid_section, target_section]
if not first: # Prefix sections with additional valid JUMPF to invalid section
sections = [Section.Code(Op.JUMPF[1])] + sections

eof_test(
data=Container(
sections=sections,
validity_error=EOFException.INVALID_NON_RETURNING_FLAG,
)
)


@pytest.mark.parametrize(
"code_section",
[
pytest.param(Section.Code(Op.STOP, code_outputs=0), id="stop0"),
pytest.param(Section.Code(Op.PUSH0 + Op.STOP, code_outputs=1), id="stop1"),
pytest.param(Section.Code(Op.INVALID, code_outputs=0), id="invalid0"),
pytest.param(Section.Code(Op.PUSH0 + Op.INVALID, code_outputs=1), id="invalid1"),
],
)
def test_returning_section_not_returning(eof_test: EOFTestFiller, code_section: Section):
"""
Test EOF validation failing because a returning sections ends with non-returning instruction.
"""
eof_test(
data=Container(
sections=[
Section.Code(Op.CALLF[1] + Op.STOP, max_stack_height=code_section.code_outputs),
code_section,
],
validity_error=EOFException.INVALID_NON_RETURNING_FLAG,
)
)
12 changes: 6 additions & 6 deletions tests/prague/eip7692_eof_v1/tracker.md
Original file line number Diff line number Diff line change
Expand Up @@ -264,7 +264,7 @@
- [ ] RETF reached via different paths (ethereum/tests: src/EOFTestsFiller/efStack/retf_stack_validation_Copier.json)
- [ ] RETF in variable stack segment is not allowed (ethereum/tests: src/EOFTestsFiller/efStack/retf_variable_stack_Copier.json)
- [ ] Extra items on stack allowed for terminating instructions other than RETF (ethereum/tests: src/EOFTestsFiller/EIP5450/validInvalidFiller.yml)
- [ ] Invalid RETF in a non-returning function
- [x] Invalid RETF in a non-returning function (`tests/prague/eip7692_eof_v1/eip6206_jumpf/test_nonretruning_validation.py::test_first_section_returning_code`)

#### JUMPF

Expand All @@ -276,7 +276,7 @@
- [ ] JUMPF into function with fewer outputs than current one (ethereum/tests: src/EOFTestsFiller/efStack/jumpf_to_returning_Copier.json)
- [ ] Extra items on stack are allowed for JUMPF to returning function (ethereum/tests: src/EOFTestsFiller/efStack/jumpf_to_returning_Copier.json)
- [ ] JUMPF to returning in a variable stack segment is not allowed (ethereum/tests: src/EOFTestsFiller/efStack/jumpf_to_returning_variable_stack_Copier.json)
- [ ] Invalid JUMPF in a non-returning function
- [x] Invalid JUMPF in a non-returning function (`tests/prague/eip7692_eof_v1/eip6206_jumpf/test_nonretruning_validation.py::test_retf_in_nonreturning`)

#### Stack overflow

Expand Down Expand Up @@ -331,19 +331,19 @@

### Validation

- [ ] Zero section returning (ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/EIP4750/validInvalidFiller.yml)
- [ ] Zero section declared non-returning but ends with RETF (ethereum/tests: src/EOFTestsFiller/EIP4750/validInvalidFiller.yml)
- [x] Zero section returning (`tests/prague/eip7692_eof_v1/eip6206_jumpf/test_nonretruning_validation.py::test_first_section_returning` ethereum/tests: ./src/EOFTestsFiller/efExample/validInvalidFiller.yml src/EOFTestsFiller/EIP4750/validInvalidFiller.yml)
- [x] Zero section declared non-returning but ends with RETF (`tests/prague/eip7692_eof_v1/eip6206_jumpf/test_nonretruning_validation.py::test_retf_in_nonreturning` ethereum/tests: src/EOFTestsFiller/EIP4750/validInvalidFiller.yml)
- [ ] CALLF into non-returning function (ethereum/tests: src/EOFTestsFiller/efValidation/callf_into_nonreturning_Copier.json)
- [ ] Valid JUMPF into sections with equal number of outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_equal_outputs_Copier.json)
- [ ] Valid JUMPF into sections with different but compatible number of outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_compatible_outputs_Copier.json)
- [ ] JUMPF into sections with incompatible outputs (ethereum/tests: src/EOFTestsFiller/efValidation/jumpf_incompatible_outputs_Copier.json)
- [ ] Non-returning section without JUMPF (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Non-returning section with JUMPF (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [x] Non-returning section with JUMPF (`tests/prague/eip7692_eof_v1/eip6206_jumpf/test_nonretruning_validation.py::test_jumpf_in_nonreturning` ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Returning section with RETF (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Returning section with JUMPF (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Returning section with JUMPF to returning and RETF (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Returning section with JUMPF to non-returning and RETF (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Returning section without JUMPF not RETF
- [x] Returning section without JUMPF nor RETF (`tests/prague/eip7692_eof_v1/eip6206_jumpf/test_nonretruning_validation.py::test_returning_section_not_returning`)
- [ ] Invalid non-returning flag (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] Circular JUMPF between two sections (ethereum/tests: src/EOFTestsFiller/efValidation/non_returning_status_Copier.json)
- [ ] JUMPF into non-existing section
Expand Down
1 change: 1 addition & 0 deletions whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ nethermind
nexternal
nGo
nJSON
nonreturning
nop
NOP
NOPs
Expand Down

0 comments on commit bd7ea51

Please sign in to comment.