Skip to content

Commit

Permalink
Merge pull request #301 from spencer-tb/hive-fixture-refactor
Browse files Browse the repository at this point in the history
improvement: Fixture generation split based on hive specificity
  • Loading branch information
marioevz authored Sep 21, 2023
2 parents eab85da + 70dc4ed commit 59c0cb4
Show file tree
Hide file tree
Showing 20 changed files with 1,759 additions and 334 deletions.
4 changes: 2 additions & 2 deletions docs/getting_started/executing_tests_command_line.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ Output:
```console
usage: fill [-h] [--evm-bin EVM_BIN] [--traces] [--solc-bin SOLC_BIN]
[--filler-path FILLER_PATH] [--output OUTPUT] [--flat-output]
[--disable-hive] [--forks] [--fork FORK] [--from FROM]
[--enable-hive] [--forks] [--fork FORK] [--from FROM]
[--until UNTIL] [--test-help]

options:
Expand All @@ -136,7 +136,7 @@ Arguments defining filler location and output:
deleted.
--flat-output Output each test case in the directory without the
folder structure.
--disable-hive Output tests skipping hive-related properties.
--enable-hive Output test fixtures with the hive-specific properties.

Arguments defining debug behavior:
--t8n-dump-dir T8N_DUMP_DIR
Expand Down
2 changes: 2 additions & 0 deletions src/ethereum_test_tools/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
FixtureEngineNewPayload,
Header,
HistoryStorageAddress,
HiveFixture,
JSONEncoder,
Removable,
Storage,
Expand Down Expand Up @@ -77,6 +78,7 @@
"FixtureEngineNewPayload",
"Header",
"HistoryStorageAddress",
"HiveFixture",
"Initcode",
"JSONEncoder",
"Opcode",
Expand Down
2 changes: 2 additions & 0 deletions src/ethereum_test_tools/common/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@
Hash,
Header,
HeaderNonce,
HiveFixture,
JSONEncoder,
Number,
Removable,
Expand Down Expand Up @@ -77,6 +78,7 @@
"Header",
"HeaderNonce",
"HistoryStorageAddress",
"HiveFixture",
"JSONEncoder",
"Number",
"Removable",
Expand Down
157 changes: 101 additions & 56 deletions src/ethereum_test_tools/common/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -2569,16 +2569,21 @@ class FixtureEngineNewPayload:
to_json=True,
),
)
version: int = field(
json_encoder=JSONEncoder.Field(),
)
beacon_root: Optional[FixedSizeBytesConvertible] = field(
default=None,
json_encoder=JSONEncoder.Field(
name="parentBeaconBlockRoot",
cast_type=Hash,
),
)
version: int = field(
json_encoder=JSONEncoder.Field(),
)
valid: bool = field(
json_encoder=JSONEncoder.Field(
skip_string_convert=True,
),
)
error_code: Optional[EngineAPIError] = field(
default=None,
json_encoder=JSONEncoder.Field(
Expand All @@ -2594,6 +2599,7 @@ def from_fixture_header(
header: FixtureHeader,
transactions: List[Transaction],
withdrawals: Optional[List[Withdrawal]],
valid: bool,
error_code: Optional[EngineAPIError],
) -> Optional["FixtureEngineNewPayload"]:
"""
Expand All @@ -2611,6 +2617,7 @@ def from_fixture_header(
withdrawals=withdrawals,
),
version=new_payload_version,
valid=valid,
error_code=error_code,
)

Expand Down Expand Up @@ -2641,13 +2648,6 @@ class FixtureBlock:
to_json=True,
),
)
new_payload: Optional[FixtureEngineNewPayload] = field(
default=None,
json_encoder=JSONEncoder.Field(
name="engineNewPayload",
to_json=True,
),
)
expected_exception: Optional[str] = field(
default=None,
json_encoder=JSONEncoder.Field(
Expand Down Expand Up @@ -2689,9 +2689,9 @@ class FixtureBlock:


@dataclass(kw_only=True)
class Fixture:
class BaseFixture:
"""
Cross-client compatible Ethereum test fixture.
Base Ethereum test fixture class.
"""

info: Dict[str, str] = field(
Expand All @@ -2701,36 +2701,78 @@ class Fixture:
to_json=True,
),
)
blocks: List[FixtureBlock] = field(
fork: str = field(
json_encoder=JSONEncoder.Field(
name="blocks",
to_json=True,
name="network",
),
)
fcu_version: Optional[int] = field(
name: str = field(
default="",
json_encoder=JSONEncoder.Field(
name="engineFcuVersion",
skip=True,
),
)
genesis: FixtureHeader = field(
_json: Dict[str, Any] | None = field(
default=None,
json_encoder=JSONEncoder.Field(
name="genesisBlockHeader",
to_json=True,
skip=True,
),
)

def __post_init__(self):
"""
Post init hook to convert to JSON after instantiation.
"""
self._json = to_json(self)

def to_json(self) -> Dict[str, Any]:
"""
Convert to JSON.
"""
assert self._json is not None, "Fixture not initialized"
self._json["_info"] = self.info
return self._json

def fill_info(
self,
t8n: TransitionTool,
ref_spec: ReferenceSpec | None,
):
"""
Fill the info field for this fixture
"""
self.info["filling-transition-tool"] = t8n.version()
if ref_spec is not None:
ref_spec.write_info(self.info)


@dataclass(kw_only=True)
class Fixture(BaseFixture):
"""
Cross-client specific test fixture information.
"""

genesis_rlp: Bytes = field(
json_encoder=JSONEncoder.Field(
name="genesisRLP",
),
)
head: Hash = field(
genesis: FixtureHeader = field(
json_encoder=JSONEncoder.Field(
name="lastblockhash",
name="genesisBlockHeader",
to_json=True,
),
)
fork: str = field(
blocks: Optional[List[FixtureBlock]] = field(
default=None,
json_encoder=JSONEncoder.Field(
name="network",
name="blocks",
to_json=True,
),
)
head: Hash = field(
json_encoder=JSONEncoder.Field(
name="lastblockhash",
),
)
pre_state: Mapping[str, Account] = field(
Expand All @@ -2753,42 +2795,45 @@ class Fixture:
name="sealEngine",
),
)
name: str = field(
default="",


@dataclass(kw_only=True)
class HiveFixture(BaseFixture):
"""
Hive specific test fixture information.
"""

genesis: FixtureHeader = field(
json_encoder=JSONEncoder.Field(
skip=True,
name="genesisBlockHeader",
to_json=True,
),
)

_json: Dict[str, Any] | None = field(
payloads: Optional[List[Optional[FixtureEngineNewPayload]]] = field(
default=None,
json_encoder=JSONEncoder.Field(
skip=True,
name="engineNewPayloads",
to_json=True,
),
)
fcu_version: Optional[int] = field(
default=None,
json_encoder=JSONEncoder.Field(
name="engineFcuVersion",
),
)
pre_state: Mapping[str, Account] = field(
json_encoder=JSONEncoder.Field(
name="pre",
cast_type=Alloc,
to_json=True,
),
)
post_state: Optional[Mapping[str, Account]] = field(
default=None,
json_encoder=JSONEncoder.Field(
name="postState",
cast_type=Alloc,
to_json=True,
),
)

def __post_init__(self):
"""
Post init hook to convert to JSON after instantiation.
"""
self._json = to_json(self)

def to_json(self) -> Dict[str, Any]:
"""
Convert to JSON.
"""
assert self._json is not None, "Fixture not initialized"
self._json["_info"] = self.info
return self._json

def fill_info(
self,
t8n: TransitionTool,
ref_spec: ReferenceSpec | None,
):
"""
Fill the info field for this fixture
"""
self.info["filling-transition-tool"] = t8n.version()
if ref_spec is not None:
ref_spec.write_info(self.info)
50 changes: 34 additions & 16 deletions src/ethereum_test_tools/filling/fill.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
"""
Filler object definitions.
"""
from typing import List, Optional
from typing import List, Optional, Union

from ethereum_test_forks import Fork
from evm_transition_tool import TransitionTool

from ..common import Fixture, alloc_to_accounts
from ..common import Fixture, HiveFixture, alloc_to_accounts
from ..reference_spec.reference_spec import ReferenceSpec
from ..spec import BaseTest

Expand All @@ -18,35 +18,53 @@ def fill_test(
engine: str,
spec: ReferenceSpec | None,
eips: Optional[List[int]] = None,
) -> Fixture:
) -> Optional[Union[Fixture, HiveFixture]]:
"""
Fills fixtures for the specified fork.
"""
t8n.reset_traces()

pre, genesis_rlp, genesis = test_spec.make_genesis(t8n, fork)

(blocks, head, alloc, fcu_version) = test_spec.make_blocks(
(blocks, payloads, head, alloc, fcu_version) = test_spec.make_blocks(
t8n,
genesis,
pre,
fork,
eips=eips,
)

fork_name = fork.name()
fixture = Fixture(
blocks=blocks,
genesis=genesis,
genesis_rlp=genesis_rlp,
head=head,
fork="+".join([fork_name] + [str(eip) for eip in eips]) if eips is not None else fork_name,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
seal_engine=engine,
name=test_spec.tag,
fcu_version=fcu_version,
network_info = (
"+".join([fork.name()] + [str(eip) for eip in eips]) if eips is not None else fork.name()
)

fixture: Union[Fixture, HiveFixture]
if test_spec.base_test_config.enable_hive:
if fork.engine_new_payload_version() is not None:
fixture = HiveFixture(
payloads=payloads,
fcu_version=fcu_version,
genesis=genesis,
fork=network_info,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
name=test_spec.tag,
)
else: # pre Merge tests are not supported in Hive
# TODO: remove this logic. if hive enabled set --from to Merge
return None
else:
fixture = Fixture(
blocks=blocks,
genesis=genesis,
genesis_rlp=genesis_rlp,
head=head,
fork=network_info,
pre_state=pre,
post_state=alloc_to_accounts(alloc),
seal_engine=engine,
name=test_spec.tag,
)
fixture.fill_info(t8n, spec)

return fixture
Loading

0 comments on commit 59c0cb4

Please sign in to comment.