Skip to content

Commit

Permalink
fix(fw): base fixture json generation
Browse files Browse the repository at this point in the history
  • Loading branch information
marioevz committed Mar 27, 2024
1 parent cb23696 commit 9a575ed
Show file tree
Hide file tree
Showing 3 changed files with 37 additions and 45 deletions.
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ As part of the pydantic conversion, the fixtures have the following (possibly br

- `expectException` fields now print the exceptions in sorted order.
- State test field `transaction` now uses the proper zero-padded hex number format for fields `maxPriorityFeePerGas`, `maxFeePerGas`, and `maxFeePerBlobGas`
- Fixtures' hashes (in the `_info` field) are now calculated by removing the "_info" field entirely instead of it being set to an empty dict.

## 🔜 [v2.1.1](https://github.com/ethereum/execution-spec-tests/releases/tag/v2.1.1) - 2024-03-09

Expand Down
69 changes: 28 additions & 41 deletions src/ethereum_test_tools/spec/base/base_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
import hashlib
import json
from abc import abstractmethod
from functools import reduce
from functools import cached_property, reduce
from itertools import count
from os import path
from pathlib import Path
Expand All @@ -18,7 +18,6 @@

from ...common import Environment, Transaction, Withdrawal
from ...common.conversions import to_hex
from ...common.json import to_json
from ...common.types import CamelModel, Result
from ...reference_spec.reference_spec import ReferenceSpec

Expand Down Expand Up @@ -67,15 +66,36 @@ def verify_result(result: Result, env: Environment):


class BaseFixture(CamelModel):
"""
Represents a base Ethereum test fixture of any type.
"""
"""Represents a base Ethereum test fixture of any type."""

info: Dict[str, str] = Field(default_factory=dict, alias="_info")
format: ClassVar[FixtureFormats] = FixtureFormats.UNSET_TEST_FORMAT

_json: Optional[Dict[str, Any]] = None
@cached_property
def json_dict(self) -> Dict[str, Any]:
"""
Returns the JSON representation of the fixture.
"""
return self.model_dump(mode="json", by_alias=True, exclude_none=True, exclude={"_info"})

format: ClassVar[FixtureFormats] = FixtureFormats.UNSET_TEST_FORMAT
@cached_property
def hash(self) -> str:
"""
Returns the hash of the fixture.
"""
json_str = json.dumps(self.json_dict, sort_keys=True, separators=(",", ":"))
h = hashlib.sha256(json_str.encode("utf-8")).hexdigest()
return f"0x{h}"

def json_dict_with_info(self, hash_only: bool = False) -> Dict[str, Any]:
"""
Returns the JSON representation of the fixture with the info field.
"""
dict_with_info = self.json_dict.copy()
dict_with_info["_info"] = {"hash": self.hash}
if not hash_only:
dict_with_info["_info"].update(self.info)
return dict_with_info

def fill_info(
self,
Expand All @@ -91,39 +111,6 @@ def fill_info(
if ref_spec is not None:
ref_spec.write_info(self.info)

def model_post_init(self, __context):
"""
Post init hook to convert to JSON after instantiation.
"""
super().model_post_init(__context)
previous_hash = None
if "hash" in self.info: # e.g., we're loading an existing fixture from file
previous_hash = self.info["hash"]
self._json = to_json(self)
self.add_hash()
if previous_hash and previous_hash != self.info["hash"]:
raise HashMismatchException(previous_hash, self.info["hash"])

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 add_hash(self) -> None:
"""
Calculate the hash of the fixture and add it to the fixture and fixture's
json.
"""
assert self._json is not None, "Fixture not initialized"
self._json["_info"] = {}
json_str = json.dumps(self._json, sort_keys=True, separators=(",", ":"))
h = hashlib.sha256(json_str.encode("utf-8")).hexdigest()
self.info["hash"] = f"0x{h}"
self._json["_info"] = self.info

@classmethod
def collect_into_file(cls, fd: TextIO, fixtures: Dict[str, "BaseFixture"]):
"""
Expand All @@ -132,7 +119,7 @@ def collect_into_file(cls, fd: TextIO, fixtures: Dict[str, "BaseFixture"]):
json_fixtures: Dict[str, Dict[str, Any]] = {}
for name, fixture in fixtures.items():
assert isinstance(fixture, cls), f"Invalid fixture type: {type(fixture)}"
json_fixtures[name] = fixture.to_json()
json_fixtures[name] = fixture.json_dict_with_info()
json.dump(json_fixtures, fd, indent=4)


Expand Down
12 changes: 8 additions & 4 deletions src/ethereum_test_tools/tests/test_filling/test_fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

from ... import Header
from ...code import Yul
from ...common import Account, Environment, Hash, TestAddress, Transaction, to_json
from ...common import Account, Environment, Hash, TestAddress, Transaction
from ...exceptions import TransactionException
from ...spec import BlockchainTest, StateTest
from ...spec.blockchain.types import Block
Expand Down Expand Up @@ -156,7 +156,7 @@ def test_fill_state_test(
)
assert generated_fixture.format == fixture_format
fixture = {
f"000/my_chain_id_test/{fork}": to_json(generated_fixture),
f"000/my_chain_id_test/{fork}": generated_fixture.json_dict_with_info(hash_only=True),
}

expected_json_file = f"chainid_{fork.name().lower()}_{fixture_format.value}.json"
Expand Down Expand Up @@ -499,7 +499,9 @@ def test_fill_blockchain_valid_txs( # noqa: D102
assert isinstance(blockchain_test_fixture, BlockchainFixtureCommon)

fixture = {
f"000/my_blockchain_test/{fork.name()}": to_json(blockchain_test_fixture),
f"000/my_blockchain_test/{fork.name()}": blockchain_test_fixture.json_dict_with_info(
hash_only=True
),
}

with open(
Expand Down Expand Up @@ -872,7 +874,9 @@ def test_fill_blockchain_invalid_txs(
assert generated_fixture.format == fixture_format
assert isinstance(generated_fixture, BlockchainFixtureCommon)
fixture = {
f"000/my_blockchain_test/{fork.name()}": to_json(generated_fixture),
f"000/my_blockchain_test/{fork.name()}": generated_fixture.json_dict_with_info(
hash_only=True
),
}

with open(
Expand Down

0 comments on commit 9a575ed

Please sign in to comment.