Skip to content

Commit

Permalink
feat(fw): Implement Section.Func
Browse files Browse the repository at this point in the history
  • Loading branch information
marioevz committed Jul 11, 2024
1 parent 0a9da60 commit dd224a8
Show file tree
Hide file tree
Showing 4 changed files with 152 additions and 152 deletions.
119 changes: 35 additions & 84 deletions src/ethereum_test_tools/eof/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from dataclasses import dataclass
from enum import Enum, IntEnum, auto
from functools import cached_property
from typing import Any, Dict, List, Optional, Tuple
from typing import Any, List, Optional

from pydantic import Field, GetCoreSchemaHandler
from pydantic_core.core_schema import (
Expand Down Expand Up @@ -148,15 +148,6 @@ class Section(CopyValidateModel):
"""
max_stack_height: int = 0
"""
Maximum height data stack reaches during execution of code section.
"""
auto_max_stack_height: bool = False
"""
Whether to automatically compute the best suggestion for the
max_stack_height value for this code section.
"""
auto_code_inputs_outputs: bool = False
"""
Whether to automatically compute the best suggestion for the code_inputs,
code_outputs values for this code section.
"""
Expand Down Expand Up @@ -202,19 +193,6 @@ def type_definition(self) -> bytes:
self.code_outputs,
self.max_stack_height,
)
if self.auto_max_stack_height or self.auto_code_inputs_outputs:
(
auto_code_inputs,
auto_code_outputs,
auto_max_height,
) = compute_code_stack_values(self.data)
if self.auto_max_stack_height:
max_stack_height = auto_max_height
if self.auto_code_inputs_outputs:
code_inputs, code_outputs = (
auto_code_inputs,
auto_code_outputs,
)

return (
code_inputs.to_bytes(length=TYPES_INPUTS_BYTE_LENGTH, byteorder="big")
Expand All @@ -229,19 +207,6 @@ def with_max_stack_height(self, max_stack_height) -> "Section":
"""
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 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 self.copy(auto_code_inputs_outputs=True)

@staticmethod
def list_header(sections: List["Section"]) -> bytes:
"""
Expand Down Expand Up @@ -274,33 +239,56 @@ def list_header(sections: List["Section"]) -> bytes:
return h

@classmethod
def Code( # noqa: N802
cls, code: BytesConvertible | Bytecode = Bytecode(), **kwargs
) -> "Section":
def Code(cls, code: Bytecode = Bytecode(), **kwargs) -> "Section": # noqa: N802
"""
Creates a new code section with the specified code.
"""
kwargs.pop("kind", None)
if "max_stack_height" not in kwargs and isinstance(code, Bytecode):
assert "kind" not in kwargs, "Kind is automatically set to CODE for code sections."
if "max_stack_height" not in kwargs:
kwargs["max_stack_height"] = code.max_stack_height
return cls(kind=SectionKind.CODE, data=code, **kwargs)

@classmethod
def Function(cls, code: Bytecode = Bytecode(), **kwargs) -> "Section": # noqa: N802
"""
Creates a new code section with the specified code aimed to be processed as a function.
Code inputs, outputs and stack height are automatically calculated.
"""
assert "kind" not in kwargs, "Kind is automatically set to CODE for function sections."
if "code_inputs" not in kwargs:
code_inputs = code.min_stack_height
kwargs["code_inputs"] = code_inputs
else:
code_inputs = kwargs["code_inputs"]
code = code.with_min_stack_height(code_inputs)
if "code_outputs" not in kwargs:
code_outputs = max(
0, code.min_stack_height - code.popped_stack_items + code.pushed_stack_items
)
kwargs["code_outputs"] = code_outputs
else:
code_outputs = kwargs["code_outputs"]
if "max_stack_height" not in kwargs:
kwargs["max_stack_height"] = code.max_stack_height
return cls(kind=SectionKind.CODE, data=code, **kwargs)

@classmethod
def Container( # noqa: N802
cls, container: "Container" | BytesConvertible, **kwargs
) -> "Section":
def Container(cls, container: "Container", **kwargs) -> "Section": # noqa: N802
"""
Creates a new container section with the specified container.
"""
kwargs.pop("kind", None)
assert (
"kind" not in kwargs
), "Kind is automatically set to CONTAINER for container sections."
return cls(kind=SectionKind.CONTAINER, data=container, **kwargs)

@classmethod
def Data(cls, data: BytesConvertible = b"", **kwargs) -> "Section": # noqa: N802
"""
Creates a new data section with the specified data.
"""
kwargs.pop("kind", None)
assert "kind" not in kwargs, "Kind is automatically set to DATA for data sections."
return cls(kind=SectionKind.DATA, data=data, **kwargs)


Expand Down Expand Up @@ -445,7 +433,7 @@ def bytecode(self) -> bytes:
return c

@classmethod
def Code(cls, code: BytesConvertible = Bytecode(), **kwargs) -> "Container": # noqa: N802
def Code(cls, code: Bytecode = Bytecode(), **kwargs) -> "Container": # noqa: N802
"""
Creates simple container with a single code section.
"""
Expand Down Expand Up @@ -524,40 +512,3 @@ def count_sections(sections: List[Section], kind: SectionKind | int) -> int:
Counts sections from a list that match a specific kind
"""
return len([s for s in sections if s.kind == kind])


OPCODE_MAP: Dict[int, Op] = {x.int(): x for x in Op}


def compute_code_stack_values(code: bytes) -> Tuple[int, int, int]:
"""
Computes the stack values for the given bytecode.
TODO: THIS DOES NOT WORK WHEN THE RJUMP* JUMPS BACKWARDS (and many other
things).
"""
i = 0
stack_height = 0
min_stack_height = 0
max_stack_height = 0

# compute type annotation
while i < len(code):
op = OPCODE_MAP.get(code[i])
if op is None:
return (0, 0, 0)
elif op == Op.RJUMPV:
i += 1
if i < len(code):
count = code[i]
i += count * 2
else:
i += 1 + op.data_portion_length

stack_height -= op.popped_stack_items
min_stack_height = min(stack_height, min_stack_height)
stack_height += op.pushed_stack_items
max_stack_height = max(stack_height, max_stack_height)
if stack_height < 0:
stack_height = 0
return (abs(min_stack_height), stack_height, max_stack_height)
Loading

0 comments on commit dd224a8

Please sign in to comment.