Skip to content

Commit

Permalink
new(tests): EOF - EIP-3540: MAX_INITCODE_SIZE validation (#630)
Browse files Browse the repository at this point in the history
* new(tests): EOF - EIP-3540 container size

Tests ipsilon/eof#125

* fix(tests): Adjust to container size limit

* Update tests/prague/eip7692_eof_v1/eip3540_eof_v1/test_container_size.py

* Update tests/prague/eip7692_eof_v1/eip7480_data_section/test_code_validation.py

* fix(tests): import

---------

Co-authored-by: Mario Vega <[email protected]>
  • Loading branch information
pdobacz and marioevz committed Jun 27, 2024
1 parent f514b68 commit 7139105
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 13 deletions.
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

0 comments on commit 7139105

Please sign in to comment.