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-3540: MAX_INITCODE_SIZE validation #630

Merged
merged 5 commits into from
Jun 27, 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
3 changes: 3 additions & 0 deletions src/ethereum_test_tools/exceptions/evmone_exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ class EvmoneExceptionMapper:
EOFException.TOPLEVEL_CONTAINER_TRUNCATED, "err: toplevel_container_truncated"
),
ExceptionMessage(EOFException.ORPHAN_SUBCONTAINER, "err: unreferenced_subcontainer"),
ExceptionMessage(
EOFException.CONTAINER_SIZE_ABOVE_LIMIT, "err: container_size_above_limit"
),
)

def __init__(self) -> None:
Expand Down
4 changes: 4 additions & 0 deletions src/ethereum_test_tools/exceptions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -692,6 +692,10 @@ class EOFException(ExceptionBase):
"""
EOF container has an unreferenced subcontainer.
'"""
CONTAINER_SIZE_ABOVE_LIMIT = auto()
"""
EOF container is above size limit
"""


"""
Expand Down
114 changes: 114 additions & 0 deletions tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_size.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
"""
EOF validation tests for EIP-3540 container size
"""

import pytest

from ethereum_test_tools import EOFTestFiller
from ethereum_test_tools import Opcodes as Op
from ethereum_test_tools.eof.v1 import Container, EOFException, Section
from ethereum_test_tools.eof.v1.constants import MAX_INITCODE_SIZE

from .. import EOF_FORK_NAME

REFERENCE_SPEC_GIT_PATH = "EIPS/eip-3540.md"
REFERENCE_SPEC_VERSION = "6b313505c75afa49a4f34de39c609ebebc7be87f"

pytestmark = pytest.mark.valid_from(EOF_FORK_NAME)

VALID_CONTAINER = Container(sections=[Section.Code(code=Op.STOP)])


@pytest.mark.parametrize(
"over_limit",
[0, 1, 2, 2**16 - MAX_INITCODE_SIZE],
)
def test_max_size(
eof_test: EOFTestFiller,
over_limit: int,
):
"""
Verify EOF container valid at maximum size, invalid above
"""
# Expand the minimal EOF code by more noop code, reaching the desired target container size.
code = Container(
sections=[
Section.Code(
code=Op.JUMPDEST * (MAX_INITCODE_SIZE - len(VALID_CONTAINER) + over_limit)
+ Op.STOP
)
]
)
assert len(code) == MAX_INITCODE_SIZE + over_limit
eof_test(
data=bytes(code),
expect_exception=None if over_limit == 0 else EOFException.CONTAINER_SIZE_ABOVE_LIMIT,
)


@pytest.mark.parametrize(
"size",
[MAX_INITCODE_SIZE + 1, MAX_INITCODE_SIZE * 2],
)
def test_above_max_size_raw(
eof_test: EOFTestFiller,
size: int,
):
"""
Verify EOF container invalid above maximum size, regardless of header contents
"""
code = Op.INVALID * size
eof_test(
data=bytes(code),
expect_exception=EOFException.CONTAINER_SIZE_ABOVE_LIMIT,
)


@pytest.mark.parametrize(
"code",
[
pytest.param(
Container(sections=[Section.Code(code=Op.STOP, custom_size=MAX_INITCODE_SIZE)]),
id="1st_code_section",
),
pytest.param(
Container(
sections=[
Section.Code(code=Op.STOP),
Section.Code(code=Op.STOP, custom_size=MAX_INITCODE_SIZE),
]
),
id="2nd_code_section",
),
pytest.param(
Container(
sections=[
Section.Code(code=Op.STOP),
Section.Container(container=Op.STOP, custom_size=MAX_INITCODE_SIZE),
]
),
id="1st_container_section",
),
pytest.param(
Container(
sections=[
Section.Code(code=Op.STOP),
Section.Container(container=Op.STOP),
Section.Container(container=Op.STOP, custom_size=MAX_INITCODE_SIZE),
]
),
id="2nd_container_section",
),
],
)
def test_section_after_end_of_container(
eof_test: EOFTestFiller,
code: Container,
):
"""
Verify EOF container is invalid if any of sections declares above container size
"""
eof_test(
data=bytes(code),
expect_exception=EOFException.INVALID_SECTION_BODIES_SIZE,
)
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ethereum_test_tools import EOFException, EOFTestFiller
from ethereum_test_tools.eof.v1 import Container, Section
from ethereum_test_tools.eof.v1.constants import MAX_INITCODE_SIZE
from ethereum_test_tools.vm.opcode import Opcodes as Op

from .. import EOF_FORK_NAME
Expand All @@ -17,6 +18,13 @@

pytestmark = pytest.mark.valid_from(EOF_FORK_NAME)

smallest_runtime_subcontainer = Container(
name="Runtime Subcontainer",
sections=[
Section.Code(code=Op.STOP),
],
)

VALID: List[Container] = [
Container(
name="empty_data_section",
Expand Down Expand Up @@ -48,10 +56,9 @@
Container(
name="max_data_section",
sections=[
Section.Code(
code=Op.ADDRESS + Op.POP + Op.STOP,
),
Section.Data(data=("1122334455667788" * 8 * 1024)[2:]),
Section.Code(code=Op.STOP),
# Hits the 49152 bytes limit for the entire container
Section.Data(data=b"\x00" * (MAX_INITCODE_SIZE - len(smallest_runtime_subcontainer))),
],
),
Container(
Expand Down Expand Up @@ -81,15 +88,6 @@
Section.Data(data="1122334455667788" * 16),
],
),
Container(
name="DATALOADN_max",
sections=[
Section.Code(
code=Op.DATALOADN[0xFFFF - 32] + Op.POP + Op.STOP,
),
Section.Data(data=("1122334455667788" * 8 * 1024)[2:]),
],
),
]

INVALID: List[Container] = [
Expand Down Expand Up @@ -122,6 +120,15 @@
],
validity_error=EOFException.INVALID_DATALOADN_INDEX,
),
Container(
name="data_section_over_container_limit",
sections=[
Section.Code(code=Op.STOP),
# Over the 49152 bytes limit for the entire container
Section.Data(data=(b"12345678" * 6 * 1024)[len(smallest_runtime_subcontainer) - 1 :]),
],
validity_error=EOFException.CONTAINER_SIZE_ABOVE_LIMIT,
),
]


Expand Down