Skip to content

Commit

Permalink
eof sections order test
Browse files Browse the repository at this point in the history
  • Loading branch information
winsvega committed May 22, 2024
1 parent a1a68c7 commit 1af5456
Show file tree
Hide file tree
Showing 2 changed files with 212 additions and 0 deletions.
3 changes: 3 additions & 0 deletions src/ethereum_test_tools/eof/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,9 @@ def list_header(sections: List["Section"]) -> bytes:
Creates the single code header for all code sections contained in
the list.
"""
if sections[0].skip_header_listing:
return b""

if sections[0].kind not in SUPPORT_MULTI_SECTION_HEADER:
return b"".join(s.header for s in sections)

Expand Down
209 changes: 209 additions & 0 deletions tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_section_order.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
"""
Different variations of EOF sections displacement
"""

from enum import Enum
from typing import List

import pytest

from ethereum_test_tools import EOFTestFiller
from ethereum_test_tools import Opcodes as Op
from ethereum_test_tools.eof.v1 import (
AutoSection,
Bytes,
Container,
EOFException,
Section,
SectionKind,
)
from ethereum_test_tools.eof.v1.constants import NON_RETURNING_SECTION

from .spec import EOF_FORK_NAME

REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md"
REFERENCE_SPEC_VERSION = "8dcb0a8c1c0102c87224308028632cc986a61183"

pytestmark = pytest.mark.valid_from(EOF_FORK_NAME)


class SectionTest(Enum):
MISSING = 1
WRONG_ORDER = 2


class TestPosition(Enum):
BODY = 1
HEADER = 2
BODY_AND_HEADER = 3


def get_expected_code_exception(
section_kind, section_test, test_position
) -> tuple[str, EOFException | None]:
match (section_kind, section_test, test_position):
case (SectionKind.TYPE, SectionTest.MISSING, TestPosition.HEADER):
return "ef000102000100030400010000800001305000ef", EOFException.MISSING_TYPE_HEADER
case (SectionKind.TYPE, SectionTest.MISSING, TestPosition.BODY):
return (
"ef0001010004020001000304000100305000ef",
EOFException.INVALID_SECTION_BODIES_SIZE,
)
case (SectionKind.TYPE, SectionTest.MISSING, TestPosition.BODY_AND_HEADER):
return "ef0001020001000304000100305000ef", EOFException.MISSING_TYPE_HEADER
case (SectionKind.TYPE, SectionTest.WRONG_ORDER, TestPosition.HEADER):
return (
"ef000102000100030100040400010000800001305000ef",
EOFException.MISSING_TYPE_HEADER,
)
case (SectionKind.TYPE, SectionTest.WRONG_ORDER, TestPosition.BODY):
return (
"ef000101000402000100030400010030500000800001ef",
# TODO why invalid first section type? it should say that the body incorrect
EOFException.INVALID_FIRST_SECTION_TYPE,
)
case (SectionKind.TYPE, SectionTest.WRONG_ORDER, TestPosition.BODY_AND_HEADER):
return (
"ef000102000100030100040400010030500000800001ef",
EOFException.MISSING_TYPE_HEADER,
)
case (SectionKind.CODE, SectionTest.MISSING, TestPosition.HEADER):
return "ef00010100040400010000800001305000ef", EOFException.MISSING_CODE_HEADER
case (SectionKind.CODE, SectionTest.MISSING, TestPosition.BODY):
return (
"ef000101000402000100030400010000800001ef",
# TODO should be an exception of empty code bytes, because it can understand that
# ef byte is data section byte
EOFException.INVALID_SECTION_BODIES_SIZE,
)
case (SectionKind.CODE, SectionTest.MISSING, TestPosition.BODY_AND_HEADER):
return "ef00010100040400010000800001ef", EOFException.MISSING_CODE_HEADER
case (SectionKind.CODE, SectionTest.WRONG_ORDER, TestPosition.HEADER):
return (
"ef000101000404000102000100030000800001305000ef",
EOFException.MISSING_CODE_HEADER,
)
case (SectionKind.CODE, SectionTest.WRONG_ORDER, TestPosition.BODY):
return (
"ef000101000402000100030400010000800001ef305000",
EOFException.UNDEFINED_INSTRUCTION,
)
case (SectionKind.CODE, SectionTest.WRONG_ORDER, TestPosition.BODY_AND_HEADER):
return (
"ef000101000404000102000100030000800001ef305000",
EOFException.MISSING_CODE_HEADER,
)
case (SectionKind.DATA, SectionTest.MISSING, TestPosition.HEADER):
return "ef000101000402000100030000800001305000ef", EOFException.MISSING_DATA_SECTION
case (SectionKind.DATA, SectionTest.MISSING, TestPosition.BODY):
return (
"ef000101000402000100030400010000800001305000",
# TODO we declared that data has 1 byte, but didn't provide any bytes
None,
)
case (SectionKind.DATA, SectionTest.MISSING, TestPosition.BODY_AND_HEADER):
return "ef000101000402000100030000800001305000", EOFException.MISSING_DATA_SECTION
case (SectionKind.DATA, SectionTest.WRONG_ORDER, TestPosition.HEADER):
return (
"ef000101000404000102000100030000800001305000ef",
EOFException.MISSING_CODE_HEADER,
)
case (SectionKind.DATA, SectionTest.WRONG_ORDER, TestPosition.BODY):
return (
"ef000101000402000100030400010000800001ef305000",
EOFException.UNDEFINED_INSTRUCTION,
)
case (SectionKind.DATA, SectionTest.WRONG_ORDER, TestPosition.BODY_AND_HEADER):
return (
"ef000101000404000102000100030000800001ef305000",
EOFException.MISSING_CODE_HEADER,
)
return "", None


@pytest.mark.parametrize("section_kind", [SectionKind.TYPE, SectionKind.CODE, SectionKind.DATA])
@pytest.mark.parametrize("section_test", [SectionTest.MISSING, SectionTest.WRONG_ORDER])
@pytest.mark.parametrize(
"test_position", [TestPosition.BODY, TestPosition.HEADER, TestPosition.BODY_AND_HEADER]
)
def test_section_order(
eof_test: EOFTestFiller,
section_kind: SectionKind,
section_test: SectionTest,
test_position: TestPosition,
):
"""
Test sections order and it appearance in body and header
"""

def calculate_skip_flag(kind, position) -> bool:
return (
False
if (section_kind != kind)
else (
True
if section_test == SectionTest.MISSING
and (test_position == position or test_position == TestPosition.BODY_AND_HEADER)
else False
)
)

def make_section_order(kind) -> List[Section]:
if section_test != SectionTest.WRONG_ORDER:
return [section_type, section_code, section_data]
if kind == SectionKind.TYPE:
return [section_code, section_type, section_data]
if kind == SectionKind.CODE or kind == SectionKind.DATA:
return [section_type, section_data, section_code]
return [section_type, section_code, section_data]

section_code = Section.Code(
code=Op.ADDRESS + Op.POP + Op.STOP,
code_inputs=0,
code_outputs=NON_RETURNING_SECTION,
max_stack_height=1,
skip_header_listing=calculate_skip_flag(SectionKind.CODE, TestPosition.HEADER),
skip_body_listing=calculate_skip_flag(SectionKind.CODE, TestPosition.BODY),
)
section_type = Section(
kind=SectionKind.TYPE,
data=Bytes.fromhex("00800001"),
custom_size=4,
skip_header_listing=calculate_skip_flag(SectionKind.TYPE, TestPosition.HEADER),
skip_body_listing=calculate_skip_flag(SectionKind.TYPE, TestPosition.BODY),
)
section_data = Section.Data(
"ef",
skip_header_listing=calculate_skip_flag(SectionKind.DATA, TestPosition.HEADER),
skip_body_listing=calculate_skip_flag(SectionKind.DATA, TestPosition.BODY),
)

eof_code = Container(
sections=make_section_order(section_kind),
auto_type_section=AutoSection.NONE,
auto_sort_sections=(
AutoSection.AUTO
if section_test != SectionTest.WRONG_ORDER
else (
AutoSection.ONLY_BODY
if test_position == TestPosition.HEADER
else (
AutoSection.ONLY_HEADER
if test_position == TestPosition.BODY
else AutoSection.NONE
)
)
),
)

expected_code, expected_exception = get_expected_code_exception(
section_kind, section_test, test_position
)

# TODO remove this after Container class implementation is reliable
assert bytes(eof_code).hex() == bytes.fromhex(expected_code).hex()

eof_test(
data=eof_code,
expect_exception=expected_exception,
)

0 comments on commit 1af5456

Please sign in to comment.