Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(specs,fixtures,tests): New Spec/Fixture type: ConfigSpec #1252

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
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
2 changes: 2 additions & 0 deletions src/ethereum_test_fixtures/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
from .base import BaseFixture, FixtureFormat, LabeledFixtureFormat
from .blockchain import BlockchainEngineFixture, BlockchainFixture, BlockchainFixtureCommon
from .collector import FixtureCollector, TestInfo
from .config import ConfigFixture
from .consume import FixtureConsumer
from .eof import EOFFixture
from .state import StateFixture
Expand All @@ -13,6 +14,7 @@
"BlockchainEngineFixture",
"BlockchainFixture",
"BlockchainFixtureCommon",
"ConfigFixture",
"EOFFixture",
"FixtureCollector",
"FixtureConsumer",
Expand Down
58 changes: 58 additions & 0 deletions src/ethereum_test_fixtures/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
"""Definitions for configuration tests fixtures."""

import hashlib
import json
from functools import cached_property
from typing import ClassVar

from pydantic import computed_field

from ethereum_test_base_types import Hash
from ethereum_test_forks import ForkConfig

from .base import BaseFixture


class ConfigFixture(BaseFixture):
"""Represents a configuration test fixture."""

fork: str
"""
Fork of the network the fixture is for.

Must be excluded from the hash computation and it's for reference only.
"""

network_name: str
"""Name of the network the fixture is for."""

config: ForkConfig
"""Configuration for the test."""

format_name: ClassVar[str] = "config_test"
description: ClassVar[str] = "Tests that generate a config test fixture."

@computed_field(alias="hash") # type: ignore[misc]
@cached_property
def config_hash(self) -> Hash:
"""
Compute the hash of the configuration.

This hash must be used to validate the configuration for a given network.

All fields are included in the hash computation except for the `hash` field itself,
the `network_name` and the `fork`.

The keys are sorted in lexicographic order before computing the hash.

If a field's value is `null`, its key and value are excluded from the hash computation.

The hash used is SHA-256.
"""
json_obj = self.config.model_dump(mode="json", by_alias=True, exclude_none=True)
json_str = json.dumps(json_obj, sort_keys=True, separators=(",", ":"))
return Hash(hashlib.sha256(json_str.encode("utf-8")).digest())

def get_fork(self) -> str | None:
"""Return fork of the fixture as a string."""
return self.fork
2 changes: 2 additions & 0 deletions src/ethereum_test_forks/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""Ethereum test fork definitions."""

from .base_fork import Fork, ForkAttribute
from .config import ForkConfig
from .forks.forks import (
ArrowGlacier,
Berlin,
Expand Down Expand Up @@ -54,6 +55,7 @@
"Byzantium",
"Constantinople",
"ConstantinopleFix",
"ForkConfig",
"Frontier",
"GrayGlacier",
"Homestead",
Expand Down
7 changes: 7 additions & 0 deletions src/ethereum_test_forks/base_fork.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from ethereum_test_vm import EVMCodeType, Opcodes

from .base_decorators import prefer_transition_to_method
from .config import ForkConfig
from .gas_costs import GasCosts


Expand Down Expand Up @@ -506,6 +507,12 @@ def fork_at(cls, block_number: int = 0, timestamp: int = 0) -> Type["BaseFork"]:
"""
return cls

@classmethod
@abstractmethod
def config(cls, *, chain_id: int) -> ForkConfig:
"""Return the configuration for the fork."""
pass

@classmethod
@abstractmethod
def transition_tool_name(cls, block_number: int = 0, timestamp: int = 0) -> str:
Expand Down
45 changes: 45 additions & 0 deletions src/ethereum_test_forks/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
"""Definition for the configuration of a client in a given fork."""

from ethereum_test_base_types import Address, CamelModel, ForkBlobSchedule


class ForkConfig(CamelModel):
"""Represents a configuration test fixture."""

chain_id: int
"""
ID of the network this config is for.
"""

homestead_block: int | None = None
dao_fork_block: int | None = None
dao_fork_support: bool | None = None

# EIP150 implements the Gas price changes (/~https://github.com/ethereum/EIPs/issues/150)
eip_150_block: int | None = None
eip_155_block: int | None = None
eip_158_block: int | None = None

byzantium_block: int | None = None
constantinople_block: int | None = None
petersburg_block: int | None = None
istanbul_block: int | None = None
muir_glacier_block: int | None = None
berlin_block: int | None = None
london_block: int | None = None
arrow_glacier_block: int | None = None
gray_glacier_block: int | None = None
merge_netsplit_block: int | None = None

# Fork scheduling was switched from blocks to timestamps here

shanghai_time: int | None = None
cancun_time: int | None = None
prague_time: int | None = None
osaka_time: int | None = None

terminal_total_difficulty: int | None = None

deposit_contract_address: Address | None = None

blob_schedule: ForkBlobSchedule | None = None
Loading
Loading