Skip to content

Commit

Permalink
Merge branch 'docs/include-all-parameters-in-test-parameter-datatable…
Browse files Browse the repository at this point in the history
…s' into raxhvl-include-all-parameters
  • Loading branch information
danceratopz committed Oct 1, 2024
2 parents 5e2d27f + e2592a2 commit 8f34168
Show file tree
Hide file tree
Showing 48 changed files with 392 additions and 375 deletions.
2 changes: 1 addition & 1 deletion .github/actions/setup-uv/action.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,6 @@ runs:
- name: Install UV
shell: bash
run: |
UV_VERSION="0.4.2"
UV_VERSION="0.4.17"
echo "Installing UV version $UV_VERSION..."
curl -LsSf https://astral.sh/uv/${UV_VERSION}/install.sh | sh
15 changes: 8 additions & 7 deletions .github/workflows/tox_verify.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,21 +8,22 @@ jobs:
strategy:
matrix:
include:
- os: ubuntu-24.04
python: "3.10"
evm-type: "stable"
tox-cmd: "uvx --with=tox-uv tox" # run-parallel --parallel-no-spinner" # TODO: disable parallelisation for uv testing
- os: ubuntu-24.04
# Temporarily disable
# - os: ubuntu-latest
# python: "3.10"
# evm-type: "stable"
# tox-cmd: "uvx --with=tox-uv tox" # run-parallel --parallel-no-spinner" # TODO: disable parallelisation for uv testing
- os: ubuntu-latest
python: "3.12"
evm-type: "stable"
tox-cmd: "uvx --with=tox-uv tox" # run-parallel --parallel-no-spinner"
# Disabled due to unavailable evm implementation for devnet-1
# - os: ubuntu-24.04
# - os: ubuntu-latest
# python: '3.11'
# evm-type: 'develop'
# tox-cmd: 'tox -e tests-develop'
# Disabled to not be gated by evmone implementation
# - os: ubuntu-24.04
# - os: ubuntu-latest
# python: '3.11'
# evm-type: 'eip7692'
# tox-cmd: 'tox -e tests-eip7692'
Expand Down
1 change: 1 addition & 0 deletions docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ Test fixtures for use by clients are available for each release on the [Github r
- 🐞 Fix `Conditional` code generator in EOF mode ([#821](https://github.com/ethereum/execution-spec-tests/pull/821))
- 🔀 `ethereum_test_rpc` library has been created with what was previously `ethereum_test_tools.rpc` ([#822](https://github.com/ethereum/execution-spec-tests/pull/822))
- ✨ Add `Wei` type to `ethereum_test_base_types` which allows parsing wei amounts from strings like "1 ether", "1000 wei", "10**2 gwei", etc ([#825](https://github.com/ethereum/execution-spec-tests/pull/825))
- 🔀 Replace `ethereum.base_types` with `ethereum-types` ([#850](https://github.com/ethereum/execution-spec-tests/pull/850))

### 🔧 EVM Tools

Expand Down
1 change: 1 addition & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ dependencies = [
"rich>=13.7.0,<14",
"solc-select>=1.0.4,<2",
"filelock>=3.15.1,<4",
"ethereum-types>=0.2.1,<0.3",
]

[project.urls]
Expand Down
21 changes: 8 additions & 13 deletions src/cli/gen_index.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
)

from ethereum_test_base_types import HexNumber
from ethereum_test_fixtures import FixtureFormats
from ethereum_test_fixtures import FIXTURE_FORMATS, BlockchainFixture, FixtureFormat
from ethereum_test_fixtures.consume import IndexFile, TestCaseIndexFile
from ethereum_test_fixtures.file import Fixtures

Expand Down Expand Up @@ -48,21 +48,16 @@ def count_json_files_exclude_index(start_path: Path) -> int:
return json_file_count


def infer_fixture_format_from_path(file: Path) -> FixtureFormats:
def infer_fixture_format_from_path(file: Path) -> FixtureFormat | None:
"""
Attempt to infer the fixture format from the file path.
"""
if "blockchain_tests_engine" in file.parts:
return FixtureFormats.BLOCKCHAIN_TEST_ENGINE
if "blockchain_tests" in file.parts:
return FixtureFormats.BLOCKCHAIN_TEST
for fixture_type in FIXTURE_FORMATS.values():
if fixture_type.output_base_dir_name() in file.parts:
return fixture_type
if "BlockchainTests" in file.parts: # ethereum/tests
return FixtureFormats.BLOCKCHAIN_TEST
if "state_tests" in file.parts:
return FixtureFormats.STATE_TEST
if "eof_tests" in file.parts:
return FixtureFormats.EOF_TEST
return FixtureFormats.UNSET_TEST_FORMAT
return BlockchainFixture
return None


@click.command(
Expand Down Expand Up @@ -200,7 +195,7 @@ def generate_fixtures_index(
json_path=relative_file_path,
fixture_hash=fixture.info.get("hash", None),
fork=fixture.get_fork(),
format=fixture.format,
format=fixture.__class__,
)
)

Expand Down
4 changes: 2 additions & 2 deletions src/ethereum_test_base_types/base_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -197,12 +197,12 @@ def or_none(cls, input: "Bytes | BytesConvertible | None") -> "Bytes | None":
return input
return cls(input)

def keccak256(self) -> "Bytes":
def keccak256(self) -> "Hash":
"""
Return the keccak256 hash of the opcode byte representation.
"""
k = keccak.new(digest_bits=256)
return Bytes(k.update(bytes(self)).digest())
return Hash(k.update(bytes(self)).digest())


S = TypeVar("S", bound="FixedSizeHexNumber")
Expand Down
24 changes: 13 additions & 11 deletions src/ethereum_test_fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,35 @@
Ethereum test fixture format definitions.
"""

from typing import List, Type
from typing import Dict

from .base import BaseFixture
from .base import BaseFixture, FixtureFormat
from .blockchain import EngineFixture as BlockchainEngineFixture
from .blockchain import Fixture as BlockchainFixture
from .blockchain import FixtureCommon as BlockchainFixtureCommon
from .collector import FixtureCollector, TestInfo
from .eof import Fixture as EOFFixture
from .formats import FixtureFormats
from .state import Fixture as StateFixture
from .verify import FixtureVerifier

FIXTURE_TYPES: List[Type[BaseFixture]] = [
BlockchainFixture,
BlockchainEngineFixture,
EOFFixture,
StateFixture,
]
FIXTURE_FORMATS: Dict[str, FixtureFormat] = {
f.fixture_format_name: f # type: ignore
for f in [
BlockchainFixture,
BlockchainEngineFixture,
EOFFixture,
StateFixture,
]
}
__all__ = [
"FIXTURE_TYPES",
"FIXTURE_FORMATS",
"BaseFixture",
"BlockchainFixture",
"BlockchainFixtureCommon",
"BlockchainEngineFixture",
"EOFFixture",
"FixtureCollector",
"FixtureFormats",
"FixtureFormat",
"FixtureVerifier",
"StateFixture",
"TestInfo",
Expand Down
31 changes: 27 additions & 4 deletions src/ethereum_test_fixtures/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,30 @@
import hashlib
import json
from functools import cached_property
from typing import Any, ClassVar, Dict
from typing import Any, ClassVar, Dict, Type

from pydantic import Field

from ethereum_test_base_types import CamelModel, ReferenceSpec

from .formats import FixtureFormats
from ethereum_test_forks import Fork


class BaseFixture(CamelModel):
"""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

# Fixture format properties
fixture_format_name: ClassVar[str] = "unset"
output_file_extension: ClassVar[str] = ".json"
description: ClassVar[str] = "Unknown fixture format; it has not been set."

@classmethod
def output_base_dir_name(cls) -> str:
"""
Returns the name of the subdirectory where this type of fixture should be dumped to.
"""
return cls.fixture_format_name.replace("test", "tests")

@cached_property
def json_dict(self) -> Dict[str, Any]:
Expand Down Expand Up @@ -69,3 +79,16 @@ def get_fork(self) -> str | None:
Returns the fork of the fixture as a string.
"""
raise NotImplementedError

@classmethod
def supports_fork(cls, fork: Fork) -> bool:
"""
Returns whether the fixture can be generated for the given fork.
By default, all fixtures support all forks.
"""
return True


# Type alias for a base fixture class
FixtureFormat = Type[BaseFixture]
27 changes: 19 additions & 8 deletions src/ethereum_test_fixtures/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
from typing import Annotated, Any, ClassVar, List, Literal, Tuple, Union, get_args, get_type_hints

from ethereum import rlp as eth_rlp
from ethereum.base_types import Uint
from ethereum.crypto.hash import keccak256
from ethereum_types.numeric import Uint
from pydantic import AliasChoices, Field, PlainSerializer, computed_field

from ethereum_test_base_types import (
Expand All @@ -24,7 +23,7 @@
ZeroPaddedHexNumber,
)
from ethereum_test_exceptions import EngineAPIError, ExceptionInstanceOrList
from ethereum_test_forks import Fork
from ethereum_test_forks import Fork, Paris
from ethereum_test_types.types import (
AuthorizationTupleGeneric,
ConsolidationRequest,
Expand All @@ -42,7 +41,6 @@
)

from .base import BaseFixture
from .formats import FixtureFormats


class HeaderForkRequirement(str):
Expand Down Expand Up @@ -182,7 +180,7 @@ def block_hash(self) -> Hash:
"""
Compute the RLP of the header
"""
return Hash(keccak256(self.rlp))
return self.rlp.keccak256()


class FixtureExecutionPayload(CamelModel):
Expand Down Expand Up @@ -500,19 +498,32 @@ class Fixture(FixtureCommon):
Cross-client specific blockchain test model use in JSON fixtures.
"""

fixture_format_name: ClassVar[str] = "blockchain_test"
description: ClassVar[str] = "Tests that generate a blockchain test fixture."

genesis_rlp: Bytes = Field(..., alias="genesisRLP")
blocks: List[FixtureBlock | InvalidFixtureBlock]
seal_engine: Literal["NoProof"] = Field("NoProof")

format: ClassVar[FixtureFormats] = FixtureFormats.BLOCKCHAIN_TEST


class EngineFixture(FixtureCommon):
"""
Engine specific test fixture information.
"""

fixture_format_name: ClassVar[str] = "blockchain_test_engine"
description: ClassVar[
str
] = "Tests that generate a blockchain test fixture in Engine API format."

payloads: List[FixtureEngineNewPayload] = Field(..., alias="engineNewPayloads")
sync_payload: FixtureEngineNewPayload | None = None

format: ClassVar[FixtureFormats] = FixtureFormats.BLOCKCHAIN_TEST_ENGINE
@classmethod
def supports_fork(cls, fork: Fork) -> bool:
"""
Returns whether the fixture can be generated for the given fork.
The Engine API is available only on Paris and afterwards.
"""
return fork >= Paris
11 changes: 5 additions & 6 deletions src/ethereum_test_fixtures/collector.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

from .base import BaseFixture
from .file import Fixtures
from .formats import FixtureFormats
from .verify import FixtureVerifier


Expand Down Expand Up @@ -139,8 +138,8 @@ def add_fixture(self, info: TestInfo, fixture: BaseFixture) -> Path:

fixture_path = (
self.output_dir
/ fixture.format.output_base_dir_name
/ fixture_basename.with_suffix(fixture.format.output_file_extension)
/ fixture.output_base_dir_name()
/ fixture_basename.with_suffix(fixture.output_file_extension)
)
if fixture_path not in self.all_fixtures.keys(): # relevant when we group by test function
self.all_fixtures[fixture_path] = Fixtures(root={})
Expand All @@ -163,7 +162,7 @@ def dump_fixtures(self) -> None:
os.makedirs(self.output_dir, exist_ok=True)
for fixture_path, fixtures in self.all_fixtures.items():
os.makedirs(fixture_path.parent, exist_ok=True)
if len({fixture.format for fixture in fixtures.values()}) != 1:
if len({fixture.__class__ for fixture in fixtures.values()}) != 1:
raise TypeError("All fixtures in a single file must have the same format.")
fixtures.collect_into_file(fixture_path)

Expand All @@ -173,11 +172,11 @@ def verify_fixture_files(self, evm_fixture_verification: FixtureVerifier) -> Non
"""
for fixture_path, name_fixture_dict in self.all_fixtures.items():
for fixture_name, fixture in name_fixture_dict.items():
if FixtureFormats.is_verifiable(fixture.format):
if evm_fixture_verification.is_verifiable(fixture.__class__):
info = self.json_path_to_test_item[fixture_path]
verify_fixtures_dump_dir = self._get_verify_fixtures_dump_dir(info)
evm_fixture_verification.verify_fixture(
fixture.format,
fixture.__class__,
fixture_path,
fixture_name=None,
debug_output_path=verify_fixtures_dump_dir,
Expand Down
17 changes: 11 additions & 6 deletions src/ethereum_test_fixtures/consume.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,16 @@
import datetime
import json
from pathlib import Path
from typing import List, TextIO
from typing import Annotated, List, TextIO

from pydantic import BaseModel, RootModel
from pydantic import BaseModel, PlainSerializer, PlainValidator, RootModel

from ethereum_test_base_types import HexNumber
from ethereum_test_fixtures import FIXTURE_FORMATS, FixtureFormat

from .blockchain import EngineFixture as BlockchainEngineFixture
from .blockchain import Fixture as BlockchainFixture
from .file import Fixtures
from .formats import FixtureFormats
from .state import Fixture as StateFixture


Expand All @@ -25,7 +26,11 @@ class TestCaseBase(BaseModel):
id: str
fixture_hash: HexNumber | None
fork: str | None
format: FixtureFormats
format: Annotated[
FixtureFormat,
PlainSerializer(lambda f: f.fixture_format_name),
PlainValidator(lambda f: FIXTURE_FORMATS[f] if f in FIXTURE_FORMATS else f),
]
__test__ = False # stop pytest from collecting this class as a test


Expand Down Expand Up @@ -129,14 +134,14 @@ def from_stream(cls, fd: TextIO) -> "TestCases":
fixtures = Fixtures.from_json_data(json.load(fd))
test_cases = []
for fixture_name, fixture in fixtures.items():
if fixture.format == FixtureFormats.BLOCKCHAIN_TEST_ENGINE:
if fixture == BlockchainEngineFixture:
print("Skipping engine fixture", fixture_name)
test_cases.append(
TestCaseStream(
id=fixture_name,
fixture_hash=fixture.hash,
fork=fixture.get_fork(),
format=fixture.format,
format=fixture.__class__,
fixture=fixture,
)
)
Expand Down
6 changes: 3 additions & 3 deletions src/ethereum_test_fixtures/eof.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
from ethereum_test_types.eof.v1 import ContainerKind

from .base import BaseFixture
from .formats import FixtureFormats


class Result(CamelModel):
Expand Down Expand Up @@ -50,9 +49,10 @@ class Fixture(BaseFixture):
Fixture for a single EOFTest.
"""

vectors: Mapping[Number, Vector]
fixture_format_name: ClassVar[str] = "eof_test"
description: ClassVar[str] = "Tests that generate an EOF test fixture."

format: ClassVar[FixtureFormats] = FixtureFormats.EOF_TEST
vectors: Mapping[Number, Vector]

def get_fork(self) -> str | None:
"""
Expand Down
Loading

0 comments on commit 8f34168

Please sign in to comment.