Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
13 changes: 6 additions & 7 deletions packages/testing/src/execution_testing/cli/diff_opcode_counts.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,17 +55,16 @@ def load_fixtures_from_file(
def extract_opcode_counts_from_fixtures(
fixtures: Fixtures,
) -> Dict[str, OpcodeCount]:
"""Extract opcode_count from info field for each fixture."""
"""Extract opcode_count from the metadata field for each fixture."""
opcode_counts = {}
for fixture_name, fixture in fixtures.items():
if (
hasattr(fixture, "info")
and fixture.info
and "opcode_count" in fixture.info
):
if not (hasattr(fixture, "info") and fixture.info):
continue
metadata = fixture.info.get("metadata")
if isinstance(metadata, dict) and "opcode_count" in metadata:
try:
opcode_count = OpcodeCount.model_validate(
fixture.info["opcode_count"]
metadata["opcode_count"]
)
opcode_counts[fixture_name] = opcode_count
except Exception as e:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1812,13 +1812,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
fixture.post_state, group.pre
)

fill_metadata: Dict[str, Any] = {}
if t8n.opcode_count is not None:
fill_metadata["opcode_count"] = (
t8n.opcode_count.model_dump()
)
if fill_result.metadata:
fill_metadata.update(fill_result.metadata)

fixture.fill_info(
t8n.version(),
test_case_description,
fixture_source_url=fixture_source_url,
opcode_count=t8n.opcode_count,
ref_spec=reference_spec,
_info_metadata=t8n._info_metadata,
metadata=fill_metadata,
)

output_subdir = resolve_fixture_subfolder(
Expand Down
7 changes: 3 additions & 4 deletions packages/testing/src/execution_testing/fixtures/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@
from pydantic_core.core_schema import ValidatorFunctionWrapHandler

from execution_testing.base_types import CamelModel, ReferenceSpec
from execution_testing.client_clis.cli_types import OpcodeCount
from execution_testing.fixtures.post_verifications import PostVerifications
from execution_testing.forks import Fork, TransitionFork

Expand Down Expand Up @@ -170,18 +169,18 @@ def fill_info(
t8n_version: str,
test_case_description: str,
fixture_source_url: str,
opcode_count: OpcodeCount | None,
ref_spec: ReferenceSpec | None,
_info_metadata: Dict[str, Any] | None,
metadata: Dict[str, Any] | None = None,
) -> None:
"""Fill the info field for this fixture."""
if "comment" not in self.info:
self.info["comment"] = "`execution-specs` generated test"
self.info["filling-transition-tool"] = t8n_version
self.info["description"] = test_case_description
self.info["url"] = fixture_source_url
if opcode_count is not None:
self.info["opcode_count"] = opcode_count.model_dump()
if metadata:
self.info["metadata"] = metadata
if ref_spec is not None:
ref_spec.write_info(self.info)
if _info_metadata:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,6 @@ def test_base_fixtures_parsing(fixture: BaseFixture) -> None:
"t8n-version",
"test_case_description",
fixture_source_url="fixture_source_url",
opcode_count=None,
ref_spec=None,
_info_metadata={},
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ def _make_fixture(nonce: int = 0) -> TransactionFixture:
f"test description {nonce}",
fixture_source_url="http://example.com",
ref_spec=None,
opcode_count=None,
_info_metadata={},
)
return fixture
Expand Down
3 changes: 2 additions & 1 deletion packages/testing/src/execution_testing/specs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
)

import pytest
from pydantic import BaseModel, ConfigDict
from pydantic import BaseModel, ConfigDict, Field
from typing_extensions import Self

from execution_testing.base_types import to_hex
Expand Down Expand Up @@ -96,6 +96,7 @@ class FillResult(BaseModel):
benchmark_gas_used: int | None = None
benchmark_opcode_count: OpcodeCount | None = None
post_verifications: PostVerifications | None = None
metadata: Dict[str, Any] = Field(default_factory=dict)


class BaseTest(BaseModel):
Expand Down
4 changes: 4 additions & 0 deletions packages/testing/src/execution_testing/specs/benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,10 @@ def generate(
self._verify_target_opcode_count(
fill_result.benchmark_opcode_count
)

if self.target_opcode is not None:
fill_result.metadata["target_opcode"] = str(self.target_opcode)

return fill_result
else:
raise Exception(f"Unsupported fixture format: {fixture_format}")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,18 @@ class TransactionReceipt(CamelModel):
def strip_extra_fields(cls, data: Any) -> Any:
"""Strip extra fields from t8n tool output not part of model."""
if isinstance(data, dict):
data = dict(data)
# geth (1.16+) returns extra fields in receipts
data.pop("type", None)
data.pop("blockNumber", None)
root = data.get("root")
root_is_empty = root in (None, "", "0x", b"", bytearray())
if not root_is_empty:
# geth's t8n JSON uses `root` for pre-Byzantium receipts while
# also populating `status`. For fixture re-encoding, a
# non-empty root must take precedence over status.
data.setdefault("post_state", root)
data.pop("status", None)
return data

transaction_hash: Hash | None = None
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
Environment,
Withdrawal,
)
from ..receipt_types import TransactionReceipt
from ..transaction_types import (
AuthorizationTuple,
Transaction,
Expand Down Expand Up @@ -93,6 +94,31 @@ def test_storage() -> None:
}


def test_transaction_receipt_maps_non_empty_root_to_post_state() -> None:
"""Non-empty `root` from geth should be treated as pre-Byzantium state."""
receipt = TransactionReceipt.model_validate(
{
"root": "0x" + "11" * 32,
"status": "0x1",
}
)
assert str(receipt.post_state) == "0x" + "11" * 32
assert receipt.status is None


def test_transaction_receipt_keeps_status_when_root_is_empty() -> None:
"""Empty `root` should not override Byzantium-style receipt status."""
receipt = TransactionReceipt.model_validate(
{
"root": "0x",
"status": "0x1",
}
)
assert receipt.post_state is None
assert receipt.status is not None
assert int(receipt.status) == 1


@pytest.mark.parametrize(
["account"],
[
Expand Down
Loading