Skip to content

chore(deps): create eels t8n transition tool #1807

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

Merged
merged 4 commits into from
Jun 28, 2025
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
32 changes: 7 additions & 25 deletions src/ethereum_clis/clis/besu.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,20 @@
import tempfile
import textwrap
from pathlib import Path
from typing import ClassVar, Dict, List, Optional
from typing import ClassVar, Dict, Optional

import requests # type: ignore

from ethereum_test_base_types import BlobSchedule
from ethereum_test_exceptions import (
BlockException,
ExceptionBase,
ExceptionMapper,
TransactionException,
)
from ethereum_test_forks import Fork
from ethereum_test_types import Alloc, Environment, Transaction

from ..transition_tool import TransitionTool, dump_files_to_directory, model_dump_config
from ..types import TransitionToolInput, TransitionToolOutput
from ..types import TransitionToolOutput


class BesuTransitionTool(TransitionTool):
Expand Down Expand Up @@ -98,36 +96,20 @@ def shutdown(self):
def evaluate(
self,
*,
alloc: Alloc,
txs: List[Transaction],
env: Environment,
fork: Fork,
chain_id: int,
reward: int,
blob_schedule: BlobSchedule | None = None,
transition_tool_data: TransitionTool.TransitionToolData,
debug_output_path: str = "",
state_test: bool = False,
slow_request: bool = False,
) -> TransitionToolOutput:
"""Execute `evm t8n` with the specified arguments."""
if not self.process:
self.start_server()

fork_name = fork.transition_tool_name(
block_number=env.number,
timestamp=env.timestamp,
)

input_json = TransitionToolInput(
alloc=alloc,
txs=txs,
env=env,
).model_dump(mode="json", **model_dump_config)
input_json = transition_tool_data.to_input().model_dump(mode="json", **model_dump_config)

state_json = {
"fork": fork_name,
"chainid": chain_id,
"reward": reward,
"fork": transition_tool_data.fork_name,
"chainid": transition_tool_data.chain_id,
"reward": transition_tool_data.reward,
}

post_data = {"state": state_json, "input": input_json}
Expand Down
16 changes: 9 additions & 7 deletions src/ethereum_clis/tests/test_execution_specs.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,13 +164,15 @@ def test_evm_t8n(
expected = json.load(exp)

t8n_output = default_t8n.evaluate(
alloc=alloc,
txs=txs,
env=env,
fork=Berlin,
chain_id=1,
reward=0,
blob_schedule=Berlin.blob_schedule(),
transition_tool_data=TransitionTool.TransitionToolData(
alloc=alloc,
txs=txs,
env=env,
fork=Berlin,
chain_id=1,
reward=0,
blob_schedule=Berlin.blob_schedule(),
),
)
assert to_json(t8n_output.alloc) == expected.get("alloc")
if isinstance(default_t8n, ExecutionSpecsTransitionTool):
Expand Down
51 changes: 21 additions & 30 deletions src/ethereum_clis/transition_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -136,11 +136,24 @@ class TransitionToolData:
alloc: Alloc
txs: List[Transaction]
env: Environment
fork_name: str
fork: Fork
chain_id: int
reward: int
blob_schedule: BlobSchedule | None
state_test: bool
state_test: bool = False

@property
def fork_name(self) -> str:
"""Return the fork name."""
return self.fork.transition_tool_name(
block_number=self.env.number,
timestamp=self.env.timestamp,
)

def __post_init__(self):
"""Modify the reward if the environment number is 0."""
if self.env.number == 0:
self.reward = -1

def to_input(self) -> TransitionToolInput:
"""Convert the data to a TransactionToolInput object."""
Expand Down Expand Up @@ -493,15 +506,8 @@ def dump_debug_stream(
def evaluate(
self,
*,
alloc: Alloc,
txs: List[Transaction],
env: Environment,
fork: Fork,
chain_id: int,
reward: int,
blob_schedule: BlobSchedule | None,
transition_tool_data: TransitionToolData,
debug_output_path: str = "",
state_test: bool = False,
slow_request: bool = False,
) -> TransitionToolOutput:
"""
Expand All @@ -510,36 +516,21 @@ def evaluate(
If a client's `t8n` tool varies from the default behavior, this method
can be overridden.
"""
fork_name = fork.transition_tool_name(
block_number=env.number,
timestamp=env.timestamp,
)
if env.number == 0:
reward = -1
t8n_data = self.TransitionToolData(
alloc=alloc,
txs=txs,
env=env,
fork_name=fork_name,
chain_id=chain_id,
reward=reward,
blob_schedule=blob_schedule,
state_test=state_test,
)

if self.t8n_use_server:
if not self.process:
self.start_server()
return self._evaluate_server(
t8n_data=t8n_data,
t8n_data=transition_tool_data,
debug_output_path=debug_output_path,
timeout=SLOW_REQUEST_TIMEOUT if slow_request else NORMAL_SERVER_TIMEOUT,
)

if self.t8n_use_stream:
return self._evaluate_stream(t8n_data=t8n_data, debug_output_path=debug_output_path)
return self._evaluate_stream(
t8n_data=transition_tool_data, debug_output_path=debug_output_path
)

return self._evaluate_filesystem(
t8n_data=t8n_data,
t8n_data=transition_tool_data,
debug_output_path=debug_output_path,
)
16 changes: 9 additions & 7 deletions src/ethereum_test_specs/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -498,13 +498,15 @@ def generate_block_data(
)

transition_tool_output = t8n.evaluate(
alloc=previous_alloc,
txs=txs,
env=env,
fork=fork,
chain_id=self.chain_id,
reward=fork.get_reward(env.number, env.timestamp),
blob_schedule=fork.blob_schedule(),
transition_tool_data=TransitionTool.TransitionToolData(
alloc=previous_alloc,
txs=txs,
env=env,
fork=fork,
chain_id=self.chain_id,
reward=fork.get_reward(env.number, env.timestamp),
blob_schedule=fork.blob_schedule(),
),
debug_output_path=self.get_next_transition_tool_output_path(),
slow_request=self.is_tx_gas_heavy_test(),
)
Expand Down
18 changes: 10 additions & 8 deletions src/ethereum_test_specs/state.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,15 +182,17 @@ def make_state_test_fixture(
raise Exception(f"Empty accounts in pre state: {empty_accounts}")

transition_tool_output = t8n.evaluate(
alloc=pre_alloc,
txs=[tx],
env=env,
fork=fork,
chain_id=self.chain_id,
reward=0, # Reward on state tests is always zero
blob_schedule=fork.blob_schedule(),
transition_tool_data=TransitionTool.TransitionToolData(
alloc=pre_alloc,
txs=[tx],
env=env,
fork=fork,
chain_id=self.chain_id,
reward=0, # Reward on state tests is always zero
blob_schedule=fork.blob_schedule(),
state_test=True,
),
debug_output_path=self.get_next_transition_tool_output_path(),
state_test=True,
slow_request=self.is_tx_gas_heavy_test(),
)

Expand Down
47 changes: 29 additions & 18 deletions src/pytest_plugins/filler/filler.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def pytest_addoption(parser: pytest.Parser):
action="store",
dest="evm_bin",
type=Path,
default="ethereum-spec-evm-resolver",
default=None,
help=(
"Path to an evm executable (or name of an executable in the PATH) that provides `t8n`."
" Default: `ethereum-spec-evm-resolver`."
Expand Down Expand Up @@ -345,18 +345,23 @@ def pytest_configure(config):

# Instantiate the transition tool here to check that the binary path/trace option is valid.
# This ensures we only raise an error once, if appropriate, instead of for every test.
t8n = TransitionTool.from_binary_path(
binary_path=config.getoption("evm_bin"), trace=config.getoption("evm_collect_traces")
)
if (
isinstance(config.getoption("numprocesses"), int)
and config.getoption("numprocesses") > 0
and "Besu" in str(t8n.detect_binary_pattern)
):
pytest.exit(
"The Besu t8n tool does not work well with the xdist plugin; use -n=0.",
returncode=pytest.ExitCode.USAGE_ERROR,
evm_bin = config.getoption("evm_bin")
if evm_bin is None:
assert TransitionTool.default_tool is not None, "No default transition tool found"
t8n = TransitionTool.default_tool(trace=config.getoption("evm_collect_traces"))
else:
t8n = TransitionTool.from_binary_path(
binary_path=evm_bin, trace=config.getoption("evm_collect_traces")
)
if (
isinstance(config.getoption("numprocesses"), int)
and config.getoption("numprocesses") > 0
and "Besu" in str(t8n.detect_binary_pattern)
):
pytest.exit(
"The Besu t8n tool does not work well with the xdist plugin; use -n=0.",
returncode=pytest.ExitCode.USAGE_ERROR,
)

if "Tools" not in config.stash[metadata_key]:
config.stash[metadata_key]["Tools"] = {
Expand Down Expand Up @@ -538,7 +543,7 @@ def pytest_html_report_title(report):


@pytest.fixture(autouse=True, scope="session")
def evm_bin(request: pytest.FixtureRequest) -> Path:
def evm_bin(request: pytest.FixtureRequest) -> Path | None:
"""Return configured evm tool binary path used to run t8n."""
return request.config.getoption("evm_bin")

Expand All @@ -553,11 +558,17 @@ def verify_fixtures_bin(request: pytest.FixtureRequest) -> Path | None:


@pytest.fixture(autouse=True, scope="session")
def t8n(request: pytest.FixtureRequest, evm_bin: Path) -> Generator[TransitionTool, None, None]:
def t8n(
request: pytest.FixtureRequest, evm_bin: Path | None
) -> Generator[TransitionTool, None, None]:
"""Return configured transition tool."""
t8n = TransitionTool.from_binary_path(
binary_path=evm_bin, trace=request.config.getoption("evm_collect_traces")
)
if evm_bin is None:
assert TransitionTool.default_tool is not None, "No default transition tool found"
t8n = TransitionTool.default_tool(trace=request.config.getoption("evm_collect_traces"))
else:
t8n = TransitionTool.from_binary_path(
binary_path=evm_bin, trace=request.config.getoption("evm_collect_traces")
)
if not t8n.exception_mapper.reliable:
warnings.warn(
f"The t8n tool that is currently being used to fill tests ({t8n.__class__.__name__}) "
Expand Down Expand Up @@ -590,7 +601,7 @@ def do_fixture_verification(
def evm_fixture_verification(
request: pytest.FixtureRequest,
do_fixture_verification: bool,
evm_bin: Path,
evm_bin: Path | None,
verify_fixtures_bin: Path | None,
) -> Generator[FixtureConsumer | None, None, None]:
"""
Expand Down
12 changes: 8 additions & 4 deletions src/pytest_plugins/forks/forks.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,11 +524,15 @@ def get_fork_option(config, option_name: str, parameter_name: str) -> Set[Fork]:
return

evm_bin = config.getoption("evm_bin", None)
if evm_bin is not None:
if evm_bin is None:
assert TransitionTool.default_tool is not None, "No default transition tool found"
t8n = TransitionTool.default_tool()
elif evm_bin is not None:
t8n = TransitionTool.from_binary_path(binary_path=evm_bin)
config.unsupported_forks = frozenset( # type: ignore
fork for fork in selected_fork_set if not t8n.is_fork_supported(fork)
)

config.unsupported_forks = frozenset( # type: ignore
fork for fork in selected_fork_set if not t8n.is_fork_supported(fork)
)


@pytest.hookimpl(trylast=True)
Expand Down
Loading