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
24 changes: 22 additions & 2 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,28 @@ jobs:
uvx --from actionlint-py actionlint

py3:
name: py3 (${{ matrix.label }})
runs-on: [self-hosted-ghr, size-xl-x64]
needs: static
strategy:
fail-fast: false
matrix:
include:
- label: pre-cancun
from_fork: Frontier
until_fork: Shanghai
- label: cancun
from_fork: Cancun
until_fork: Cancun
- label: prague
from_fork: Prague
until_fork: Prague
- label: osaka
from_fork: Osaka
until_fork: Osaka
- label: amsterdam
from_fork: Amsterdam
until_fork: Amsterdam
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
Expand All @@ -66,8 +86,8 @@ jobs:
with:
python-version: "3.14"
- uses: ./.github/actions/setup-env
- name: Run py3 tests
run: tox -e py3
- name: Run py3 tests (${{ matrix.label }})
run: tox -e py3 -- --from ${{ matrix.from_fork }} --until ${{ matrix.until_fork }}
env:
PYTEST_XDIST_AUTO_NUM_WORKERS: auto
- name: Upload coverage reports to Codecov
Expand Down
2 changes: 1 addition & 1 deletion packages/testing/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ classifiers = [
]
dependencies = [
"click>=8.1.0,<9",
"ethereum-hive>=0.1.0a1,<1.0.0",
"ethereum-hive>=0.1.0a5,<1.0.0",
"ethereum-execution",
"gitpython>=3.1.31,<4",
"PyJWT>=2.3.0,<3",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,26 @@ def test_suite_description() -> str:
)


@pytest.fixture(scope="function", autouse=True)
def _per_test_reporting(
client: Client,
hive_test: HiveTest,
) -> None:
"""
Register a test for execution against a multi-test client.

Activate log segment capturing in the Hive backend for correct
client log reporting in the multi-test client case.

Parameter order matters: `client` listed before `hive_test`
ensures pytest sets up `client` first and tears it down last.
This guarantees `hive_test` teardown (`test.end()`) runs while
the hive node still exists, before `client` teardown calls
`mark_test_completed` / `client.stop()`.
"""
hive_test.register_multi_test_client(client)


@pytest.fixture(scope="function")
def client(
multi_test_hive_test: HiveTest,
Expand Down Expand Up @@ -179,6 +199,7 @@ def client(
multi_test_client_manager.register_client(
group_identifier, resolved_client
)
resolved_client.multi_test = True

try:
yield resolved_client
Expand Down
33 changes: 32 additions & 1 deletion packages/testing/src/execution_testing/specs/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@
from execution_testing.forks import Fork
from execution_testing.forks.base_fork import BaseFork
from execution_testing.test_types import Environment, Withdrawal
from execution_testing.test_types.receipt_types import (
TransactionReceipt,
)


class HashMismatchExceptionError(Exception):
Expand Down Expand Up @@ -109,6 +112,7 @@ class BaseTest(BaseModel):
gas_optimization_max_gas_limit: int | None = None
expected_benchmark_gas_used: int | None = None
skip_gas_used_validation: bool = False
expected_receipt_status: int | None = None
is_tx_gas_heavy_test: bool = False
is_exception_test: bool = False

Expand Down Expand Up @@ -170,7 +174,7 @@ def from_test(
) -> Self:
"""Create a test in a different format from a base test."""
for k in BaseTest.model_fields.keys():
if k not in kwargs:
if k not in kwargs and k in base_test.model_fields_set:
kwargs[k] = getattr(base_test, k)
return cls(**kwargs)

Expand Down Expand Up @@ -288,5 +292,32 @@ def validate_benchmark_gas(
f"{gas_benchmark_value}"
)

def validate_receipt_status(
self,
*,
receipts: List[TransactionReceipt],
block_number: int,
) -> None:
"""
Validate receipt status for every transaction in a block.

When expected_receipt_status is set, verify that all
receipts match. Catches silent OOG failures that roll
back state and invalidate benchmarks.
"""
if "expected_receipt_status" not in self.model_fields_set:
return
for i, receipt in enumerate(receipts):
if receipt.status is not None and (
int(receipt.status) != self.expected_receipt_status
):
raise Exception(
f"Transaction {i} in block "
f"{block_number} has receipt "
f"status {int(receipt.status)}, "
f"expected "
f"{self.expected_receipt_status}."
)


TestSpec = Callable[[Fork], Generator[BaseTest, None, None]]
20 changes: 16 additions & 4 deletions packages/testing/src/execution_testing/specs/blockchain.py
Original file line number Diff line number Diff line change
Expand Up @@ -858,8 +858,7 @@ def make_fixture(
invalid_blocks = 0
benchmark_gas_used: int | None = None
benchmark_opcode_count: OpcodeCount | None = None
for i, block in enumerate(self.blocks):
is_last_block = i == len(self.blocks) - 1
for block in self.blocks:
# This is the most common case, the RLP needs to be constructed
# based on the transactions to be included in the block.
# Set the environment according to the block to execute.
Expand All @@ -869,9 +868,16 @@ def make_fixture(
previous_env=env,
previous_alloc=alloc,
)
block_number = int(built_block.header.number)
is_last_block = block is self.blocks[-1]
if is_last_block and self.operation_mode == OpMode.BENCHMARKING:
benchmark_gas_used = int(built_block.result.gas_used)
benchmark_opcode_count = built_block.result.opcode_count
if built_block.result.receipts:
self.validate_receipt_status(
receipts=built_block.result.receipts,
block_number=block_number,
)
include_receipts = (
block.include_receipts_in_output
if block.include_receipts_in_output is not None
Expand Down Expand Up @@ -953,17 +959,23 @@ def make_hive_fixture(
invalid_blocks = 0
benchmark_gas_used: int | None = None
benchmark_opcode_count: OpcodeCount | None = None
for i, block in enumerate(self.blocks):
is_last_block = i == len(self.blocks) - 1
for block in self.blocks:
built_block = self.generate_block_data(
t8n=t8n,
block=block,
previous_env=env,
previous_alloc=alloc,
)
block_number = int(built_block.header.number)
is_last_block = block is self.blocks[-1]
if is_last_block and self.operation_mode == OpMode.BENCHMARKING:
benchmark_gas_used = int(built_block.result.gas_used)
benchmark_opcode_count = built_block.result.opcode_count
if built_block.result.receipts:
self.validate_receipt_status(
receipts=built_block.result.receipts,
block_number=block_number,
)
fixture_payloads.append(
built_block.get_fixture_engine_new_payload()
)
Expand Down
1 change: 0 additions & 1 deletion tox.ini
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,6 @@ commands =
--clean \
--until Amsterdam \
--durations=50 \
--ignore=tests/ported_static \
{posargs} \
tests

Expand Down
8 changes: 4 additions & 4 deletions uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading