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

fix(fw,tests): Fixes to EOF #513

Merged
merged 25 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
d135808
refactor(fw): compute_create3_address
marioevz Apr 17, 2024
f7c9abd
fix(tests): tox
marioevz Apr 17, 2024
9b21dfe
refactor(fw): eof_v1: use pydantic
marioevz Apr 17, 2024
d382a5d
fix(fw): tpx
marioevz Apr 17, 2024
2aaade1
fix(fw): RJUMPV custom dataportion parser
marioevz Apr 17, 2024
7d268fc
fix(tests): eofv1: RJUMPI calls
marioevz Apr 17, 2024
37757b8
new(fw): RJUMPV unit test
marioevz Apr 17, 2024
0920f36
feat(fw): subscriptable opcodes
marioevz Apr 17, 2024
b28a08f
fix(fw): Opcode add, mul
marioevz Apr 17, 2024
0882c4c
fix(tests): test hardcoding bytecode of initcode
marioevz Apr 17, 2024
9636ce6
fix(fw): fix
marioevz Apr 17, 2024
8377a6f
fix(tests): eof: fix RJUMP*, CALLF data portions
marioevz Apr 17, 2024
cb0ff1a
hack(fw): Add str as allowed EOF exception
marioevz Apr 17, 2024
e9a3030
fix(tests): eof: fix test_execution_function.py
marioevz Apr 17, 2024
650f1b9
changelog
marioevz Apr 17, 2024
7510998
chore: add unknown words to dictionary
danceratopz Apr 18, 2024
ff9e23d
fetch exceptions with evmone
winsvega Apr 18, 2024
469b834
eof .py test example
winsvega Apr 18, 2024
bdd115b
fix(fw): add unchecked_stack opcode property (CALLF)
marioevz Apr 18, 2024
3bba0b8
refactor(fw): eof: refactor and add section creation helpers
marioevz Apr 18, 2024
d8ee6f0
fix: tox
marioevz Apr 18, 2024
f0d5000
fix(tests): eof: refactor
marioevz Apr 18, 2024
b77576a
refactor(tests): replace Section(kind=, with Section.Code, Section.Data
marioevz Apr 18, 2024
e7a4e06
fix(fw): eof: consistent magic, version, and header terminator types.
marioevz Apr 18, 2024
f9a8609
fix(fw): eof: proper magic
marioevz Apr 18, 2024
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 @@ -16,6 +16,7 @@ Test fixtures for use by clients are available for each release on the [Github r
- ✨ Add Macro enum that represents byte sequence of Op instructions ([#457](https://github.com/ethereum/execution-spec-tests/pull/457))
- ✨ Number of parameters used to call opcodes (to generate bytecode) is now checked ([#492](https://github.com/ethereum/execution-spec-tests/pull/492)).
- ✨ Libraries have been refactored to use `pydantic` for type checking in most test types ([#486](https://github.com/ethereum/execution-spec-tests/pull/486), [#501](https://github.com/ethereum/execution-spec-tests/pull/501), [#508](https://github.com/ethereum/execution-spec-tests/pull/508)).
- ✨ Opcodes are now subscriptable and it's used to define the data portion of the opcode: `Op.PUSH1(1) == Op.PUSH1[1] == b"\x60\x01"` ([#513](https://github.com/ethereum/execution-spec-tests/pull/513))

### 🔧 EVM Tools

Expand Down
21 changes: 8 additions & 13 deletions src/ethereum_test_tools/common/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,22 +71,17 @@ def copy_opcode_cost(length: int) -> int:
return 3 + (ceiling_division(length, 32) * 3) + cost_memory_bytes(length, 0)


def compute_create3_address(address: str | int, salt: int, init_container: bytes) -> str:
def compute_create3_address(
address: FixedSizeBytesConvertible,
salt: FixedSizeBytesConvertible,
init_container: BytesConvertible,
) -> Address:
"""
Compute address of the resulting contract created using the `CREATE2`
Compute address of the resulting contract created using the `CREATE3`
opcode.
"""
ff = bytes([0xFF])
if type(address) is str:
if address.startswith("0x"):
address = address[2:]
address_bytes = bytes.fromhex(address)
elif type(address) is int:
address_bytes = address.to_bytes(length=20, byteorder="big")
salt_bytes = salt.to_bytes(length=32, byteorder="big")
initcode_hash = keccak256(init_container)
hash = keccak256(ff + address_bytes + salt_bytes + initcode_hash)
return "0x" + hash[-20:].hex()
hash = keccak256(b"\xff" + Address(address) + Hash(salt) + keccak256(Bytes(init_container)))
return Address(hash[-20:])


def eip_2028_transaction_data_cost(data: BytesConvertible) -> int:
Expand Down
40 changes: 20 additions & 20 deletions src/ethereum_test_tools/eof/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
"""

from abc import abstractmethod
from dataclasses import dataclass, replace
from dataclasses import dataclass
from enum import Enum, IntEnum
from functools import cached_property
from typing import Dict, List, Optional, Sized, SupportsBytes, Tuple
from typing import Dict, List, Optional, Tuple

from ...common import Bytes
from ...common.conversions import BytesConvertible
from ...common.types import CopyValidateModel
from ...exceptions import EOFException
from ...vm.opcode import Opcodes as Op
from ..constants import EOF_HEADER_TERMINATOR, EOF_MAGIC
Expand Down Expand Up @@ -43,13 +43,12 @@ class AutoSection(Enum):
SUPPORT_MULTI_SECTION_HEADER = [SectionKind.CODE, SectionKind.CONTAINER]


@dataclass(kw_only=True)
class Section:
class Section(CopyValidateModel):
"""
Class that represents a section in an EOF V1 container.
"""

data: SupportsBytes | str | bytes = bytes()
data: Bytes = Bytes(b"")
"""
Data to be contained by this section.
Can be SupportsBytes, another EOF container or any other abstract data.
Expand Down Expand Up @@ -114,23 +113,23 @@ def with_max_stack_height(self, max_stack_height) -> "Section":
Creates a copy of the section with `max_stack_height` set to the
specified value.
"""
return replace(self, max_stack_height=max_stack_height)
return self.copy(max_stack_height=max_stack_height)

def with_auto_max_stack_height(self) -> "Section":
"""
Creates a copy of the section with `auto_max_stack_height` set to True.
"""
return replace(self, auto_max_stack_height=True)
return self.copy(auto_max_stack_height=True)

def with_auto_code_inputs_outputs(self) -> "Section":
"""
Creates a copy of the section with `auto_code_inputs_outputs` set to
True.
"""
return replace(self, auto_code_inputs_outputs=True)
return self.copy(auto_code_inputs_outputs=True)


class Bytecode(SupportsBytes, Sized):
class Bytecode:
"""Abstract class used to define a class that generates bytecode."""

@property
Expand All @@ -154,8 +153,7 @@ def __len__(self) -> int:
return len(self.bytecode)


@dataclass(kw_only=True, frozen=True)
class Container(Bytecode):
class Container(CopyValidateModel, Bytecode):
"""
Class that represents an EOF V1 container.
"""
Expand All @@ -178,11 +176,11 @@ class Container(Bytecode):
Custom version value used to override the mandatory EOF V1 value
for testing purposes.
"""
custom_terminator: Optional[bytes] = None
custom_terminator: Optional[Bytes] = None
"""
Custom terminator bytes used to terminate the header.
"""
extra: Optional[bytes] = None
extra: Optional[Bytes] = None
"""
Extra data to be appended at the end of the container, which will
not be considered part of any of the sections, for testing purposes.
Expand All @@ -204,11 +202,13 @@ class Container(Bytecode):
Body: type section first, all code sections, data section(s), last
container sections
"""
validity_error: EOFException | None = None
validity_error: EOFException | str | None = None
"""
Optional error expected for the container.

TODO: Remove str
"""
raw_bytes: Optional[BytesConvertible] = None
raw_bytes: Optional[Bytes] = None
"""
Optional raw bytes that represent the container.
Used to have a cohesive type among all test cases, even those that do not
Expand All @@ -222,7 +222,7 @@ def bytecode(self) -> bytes:
"""
if self.raw_bytes is not None:
assert self.sections is None or len(self.sections) == 0
return Bytes(self.raw_bytes)
return self.raw_bytes

assert self.sections is not None

Expand Down Expand Up @@ -258,7 +258,7 @@ def bytecode(self) -> bytes:
auto_code_inputs,
auto_code_outputs,
auto_max_height,
) = compute_code_stack_values(Bytes(s.data))
) = compute_code_stack_values(s.data)
if s.auto_max_stack_height:
max_stack_height = auto_max_height
if s.auto_code_inputs_outputs:
Expand Down Expand Up @@ -351,7 +351,7 @@ def bytecode(self) -> bytes:
if s.kind == SectionKind.TYPE and self.auto_type_section == AutoSection.ONLY_HEADER:
continue
if s.data:
c += Bytes(s.data)
c += s.data

# Add extra (garbage)
if self.extra is not None:
Expand Down Expand Up @@ -434,7 +434,7 @@ def create_sections_header(kind: SectionKind | int, sections: List[Section]) ->
if isinstance(cs.data, Container):
h += len(cs.data).to_bytes(2, "big")
else:
h += len(Bytes(cs.data)).to_bytes(2, "big")
h += len(cs.data).to_bytes(2, "big")
else:
for s in sections:
h += s.header
Expand Down
33 changes: 33 additions & 0 deletions src/ethereum_test_tools/exceptions/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,11 @@ class EOFException(ExceptionBase):
Exception raised when an EOF container is invalid
"""

DEFAULT_EXCEPTION = auto()
"""
Expect some exception, not yet known
"""

UNKNOWN_VERSION = auto()
"""
EOF container has an unknown version
Expand Down Expand Up @@ -232,10 +237,18 @@ class EOFException(ExceptionBase):
"""
EOF container data header missing bytes
"""
ZERO_SECTION_SIZE = auto()
"""
EOF container data header construction is wrong
"""
INCOMPLETE_CONTAINER = auto()
"""
EOF container bytes are incomplete
"""
INVALID_SECTION_BODIES_SIZE = auto()
"""
Sections bodies does not match sections headers
"""
TRAILING_BYTES = auto()
"""
EOF container has bytes beyond data section
Expand All @@ -244,6 +257,26 @@ class EOFException(ExceptionBase):
"""
EOF container missing terminator bytes between header and body
"""
MISSING_HEADERS_TERMINATOR = auto()
"""
Some type of another exception about missing headers terminator
"""
INVALID_FIRST_SECTION_TYPE = auto()
"""
EOF container header does not have types section first
"""
INCOMPLETE_SECTION_NUMBER = auto()
"""
EOF container header has section that is missing declaration bytes
"""
INCOMPLETE_SECTION_SIZE = auto()
"""
EOF container header has section that is defined incorrectly
"""
TOO_MANY_CODE_SECTIONS = auto()
"""
EOF container header has too many code sections
"""


"""
Expand Down
3 changes: 3 additions & 0 deletions src/ethereum_test_tools/tests/test_eof_v1.py
Original file line number Diff line number Diff line change
Expand Up @@ -921,6 +921,9 @@ def test_eof_v1_assemble(container: Container, hex: str):


def remove_comments_from_string(input_string):
"""
Remove comments from a string and leave only valid hex characters.
"""
# Split the string into individual lines
lines = input_string.split("\n")

Expand Down
Loading
Loading