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
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ def from_fixture(cls, fixture_path: Path) -> Self:
return cls(
header=pre_alloc_group.genesis,
alloc=pre_alloc_group.pre,
chain_id=1, # TODO: PreAllocGroups don't contain chain ID
chain_id=pre_alloc_group.chain_id,
fork=pre_alloc_group.fork,
)
except ValidationError:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
MINIMAL_TEST_CONTENTS = """
from execution_testing import Transaction
def test_function(state_test, pre):
tx = Transaction(to=0, gas_limit=21_000, sender=pre.fund_eoa())
tx = Transaction(
to=0, gas_limit=21_000, sender=pre.fund_eoa()
).with_signature_and_sender()
state_test(pre=pre, post={}, tx=tx)
"""

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,10 @@
from execution_testing.specs import BaseTest
from execution_testing.specs.base import FillResult, OpMode
from execution_testing.test_types import EnvironmentDefaults
from execution_testing.test_types.chain_config_types import ChainConfigDefaults
from execution_testing.test_types.chain_config_types import (
DEFAULT_CHAIN_ID,
ChainConfigDefaults,
)
from execution_testing.tools.utility.versioning import (
generate_github_url,
get_current_commit_hash_or_tag,
Expand Down Expand Up @@ -939,15 +942,16 @@ def pytest_configure(config: pytest.Config) -> None:
TransitionToolCacheStats()
)

# Default chain id can be overwritten by user flag or env var
ChainConfigDefaults.chain_id = DEFAULT_CHAIN_ID
chain_id = config.getoption("chain_id")

if chain_id is None:
env_chain_id = os.environ.get("CHAIN_ID")
if env_chain_id is not None:
chain_id = int(env_chain_id)

if chain_id is not None:
ChainConfigDefaults.chain_id = chain_id
ChainConfigDefaults.chain_id = int(chain_id)


@pytest.hookimpl(trylast=True)
Expand Down Expand Up @@ -1714,6 +1718,7 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
pre_alloc_hash=pre_alloc_hash,
test_id=test_id,
fork=fork,
chain_id=ChainConfigDefaults.chain_id,
environment=genesis_environment,
pre=pre,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1147,7 +1147,9 @@ def test_consensus_fixtures_split_by_fork(

@pytest.mark.valid_from("Prague")
def test_fork_split_example(state_test, pre) -> None:
tx = Transaction(to=0, gas_limit=21_000, sender=pre.fund_eoa())
tx = Transaction(
to=0, gas_limit=21_000, sender=pre.fund_eoa()
).with_signature_and_sender()
state_test(pre=pre, post={}, tx=tx)
"""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -765,7 +765,9 @@ def test_fixture_output_based_on_command_line_args(
def test_max_gas_limit(state_test, pre, block_gas_limit) -> None:
env = Environment()
assert block_gas_limit == {expected_gas_limit}
tx = Transaction(gas_limit=block_gas_limit, sender=pre.fund_eoa())
tx = Transaction(
gas_limit=block_gas_limit, sender=pre.fund_eoa()
).with_signature_and_sender()
state_test(env=env, pre=pre, post={{}}, tx=tx)
"""
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@
MINIMAL_TEST_CONTENTS = """
from execution_testing import Transaction
def test_function(state_test, pre) -> None:
tx = Transaction(to=0, gas_limit=21_000, sender=pre.fund_eoa())
tx = Transaction(
to=0, gas_limit=21_000, sender=pre.fund_eoa()
).with_signature_and_sender()
state_test(pre=pre, post={}, tx=tx)
"""

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
"""Tests for the extract_config CLI helpers."""

from pathlib import Path

import pytest

from execution_testing.base_types import Alloc
from execution_testing.cli.extract_config import GenesisState
from execution_testing.fixtures.pre_alloc_groups import PreAllocGroupBuilder
from execution_testing.forks import (
Fork,
Prague,
forks_from_until,
get_deployed_forks,
)
from execution_testing.test_types import Environment


def forks_from_prague_onward() -> list[Fork]:
"""Return deployed forks from Prague onward."""
all_forks = get_deployed_forks()
return list(forks_from_until(Prague, all_forks[-1]))


@pytest.mark.parametrize("fork", forks_from_prague_onward())
def test_genesis_state_from_pre_alloc_group_uses_stored_chain_id(
tmp_path: Path,
fork: Fork,
) -> None:
"""Pre-alloc group files should preserve the configured chain ID."""
builder = PreAllocGroupBuilder(
test_ids=["test_id"],
environment=Environment()
.set_fork_requirements(fork)
.model_dump(mode="json", exclude={"parent_hash"}),
fork=fork.name(),
chain_id=12345,
pre=Alloc().model_dump(mode="json"),
)
fixture_path = tmp_path / "pre_alloc.json"
fixture_path.write_text(
builder.model_dump_json(by_alias=True, exclude_none=True, indent=2)
)

genesis_state = GenesisState.from_fixture(fixture_path)

assert genesis_state.chain_id == 12345
assert genesis_state.get_client_environment()["HIVE_CHAIN_ID"] == "12345"


@pytest.mark.parametrize("fork", forks_from_prague_onward())
def test_genesis_state_from_legacy_pre_alloc_group_defaults_chain_id(
tmp_path: Path,
fork: Fork,
) -> None:
"""Legacy pre-alloc groups without chain ID should still default to 1."""
builder = PreAllocGroupBuilder(
test_ids=["test_id"],
environment=Environment()
.set_fork_requirements(fork)
.model_dump(mode="json", exclude={"parent_hash"}),
fork=fork.name(),
pre=Alloc().model_dump(mode="json"),
)
fixture_path = tmp_path / "legacy_pre_alloc.json"
fixture_path.write_text(builder.model_dump_json(exclude={"chain_id"}))

genesis_state = GenesisState.from_fixture(fixture_path)

assert genesis_state.chain_id == 1
assert genesis_state.get_client_environment()["HIVE_CHAIN_ID"] == "1"
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
"""Tests for pytest commands (e.g., fill) click CLI."""

import json
import shutil
from pathlib import Path
from typing import Callable

Expand All @@ -12,12 +14,11 @@
from ..pytest_commands.fill import fill

MINIMAL_TEST_FILE_NAME = "test_example.py"
MINIMAL_TEST_CONTENTS = """
from execution_testing import Transaction
def test_function(state_test, pre):
tx = Transaction(to=0, gas_limit=21_000, sender=pre.fund_eoa())
state_test(pre=pre, post={}, tx=tx)
"""
VECTORS_DIR = Path(__file__).parent / "vectors"
MINIMAL_TEST_SOURCE = VECTORS_DIR / "vector_pytest_fill_command_example.py"
VALID_FROM_PRAGUE_BLOCKCHAIN_TEST_SOURCE = (
VECTORS_DIR / "vector_pytest_fill_command_valid_from_prague.py"
)


@pytest.fixture
Expand Down Expand Up @@ -102,7 +103,7 @@ def minimal_test_path(self, pytester: pytest.Pytester) -> Path:
"""
tests_dir = pytester.mkdir("tests")
test_file = tests_dir / MINIMAL_TEST_FILE_NAME
test_file.write_text(MINIMAL_TEST_CONTENTS)
shutil.copyfile(MINIMAL_TEST_SOURCE, test_file)
return test_file

@pytest.fixture
Expand Down Expand Up @@ -208,6 +209,45 @@ def test_fill_no_html_option(
run_fill(*fill_args)
assert not default_html_path.exists()

def test_generate_pre_alloc_groups_preserves_chain_id_for_valid_from(
self,
pytester: Pytester,
default_fixtures_output: Path,
) -> None:
"""
Custom chain ID should be preserved for valid_from-selected forks.
"""
tests_dir = pytester.mkdir("tests")
prague_tests_dir = tests_dir / "prague"
prague_tests_dir.mkdir()
test_file = prague_tests_dir / "test_chain_id_pre_alloc.py"
shutil.copyfile(VALID_FROM_PRAGUE_BLOCKCHAIN_TEST_SOURCE, test_file)

pytester.copy_example(
name="src/execution_testing/cli/pytest_commands/pytest_ini_files/pytest-fill.ini"
)
result = pytester.runpytest(
"-c",
"pytest-fill.ini",
"--generate-pre-alloc-groups",
"--chain-id",
"12345",
f"--output={default_fixtures_output}",
str(test_file),
"-q",
)
assert result.ret == pytest.ExitCode.OK, "\n".join(result.outlines)

pre_alloc_dir = (
default_fixtures_output / "blockchain_tests_engine_x" / "pre_alloc"
)
pre_alloc_files = sorted(pre_alloc_dir.glob("*.json"))
assert pre_alloc_files, f"No pre-alloc files found in {pre_alloc_dir}"

for pre_alloc_file in pre_alloc_files:
payload = json.loads(pre_alloc_file.read_text())
assert payload["chainId"] == 12345, pre_alloc_file

def test_fill_html_option(
self,
run_fill: Callable[..., RunResult],
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
"""Vector file for pytest fill command example coverage."""

from typing import Any

from execution_testing import Transaction


def test_function(state_test: Any, pre: Any) -> None:
"""Generate a minimal signed state test transaction."""
tx = Transaction(
to=0, gas_limit=21_000, sender=pre.fund_eoa()
).with_signature_and_sender()
state_test(pre=pre, post={}, tx=tx)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Vector file for valid_from-based pre-alloc group coverage."""

from typing import Any

import pytest

from execution_testing import Account, Block, TestAddress, Transaction

TEST_ADDRESS = Account(balance=1_000_000)


@pytest.mark.valid_from("Prague")
def test_chain_id_pre_alloc(blockchain_test: Any) -> None:
"""Generate a blockchain test selected by the valid_from marker."""
blockchain_test(
pre={TestAddress: TEST_ADDRESS},
post={},
blocks=[Block(txs=[Transaction()])],
)
44 changes: 37 additions & 7 deletions packages/testing/src/execution_testing/cli/tox_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
from pathlib import Path

import click
import semver
from pyspelling import __main__ as pyspelling_main # type: ignore
from rich.console import Console

Expand Down Expand Up @@ -85,20 +86,50 @@ def markdownlint(args: tuple[str, ...]) -> None:

Allows argument forwarding to markdownlint-cli2.
"""
expected_version = "0.20.0"
markdownlint = shutil.which("markdownlint-cli2")
if not markdownlint:
# Note: There's an additional step in test.yaml to run markdownlint-
# cli2 in GitHub Actions
click.echo(
"********* Install 'markdownlint-cli2' to enable markdown linting\
*********\
```\
sudo npm install -g markdownlint-cli2@0.20.0\
```\
"
"********* Install 'markdownlint-cli2' to enable markdown linting"
" *********\n"
"```\n"
f"sudo npm install -g markdownlint-cli2@{expected_version}\n"
"```"
)
sys.exit(0)

result = subprocess.run(
[markdownlint, "--version"],
capture_output=True,
text=True,
)
if result.returncode == 0:
version_match = re.search(r"v?(\d+\.\d+\.\d+)", result.stdout)
installed_version = version_match.group(1) if version_match else None
if installed_version:
installed = semver.Version.parse(installed_version)
expected = semver.Version.parse(expected_version)
minor_mismatch = (installed.major, installed.minor) != (
expected.major,
expected.minor,
)
else:
minor_mismatch = False
if minor_mismatch:
lines = [
f"WARNING: markdownlint-cli2 {installed_version} "
f"installed, CI uses {expected_version}",
"",
"Lint results may differ from CI.",
f" npm install -g markdownlint-cli2@{expected_version}",
]
width = max(len(line) for line in lines) + 4
border = "*" * width
box = "\n".join(f"* {line:<{width - 4}} *" for line in lines)
click.echo(f"\n{border}\n{box}\n{border}\n")

args_list: list[str] = (
list(args) if len(args) > 0 else ["./docs/**/*.md", "./*.md"]
)
Expand Down Expand Up @@ -219,7 +250,6 @@ def codespell() -> None:
sys.exit(1)

sys.exit(0)
sys.exit(pyspelling_main.main())


@click.command()
Expand Down
Loading
Loading