Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
22b324e
refactor(test-benchmark): Remove repricing marker from `unchunkified`…
kamilchodola Mar 5, 2026
dbe5c3a
fix(ethrex): update exception mapper for BAL validation errors (#2414)
edg-l Mar 5, 2026
16657e8
feat(tests): port EXTCODEHASH call to selfdestruct test (#2412)
chfast Mar 5, 2026
000fc1b
refactor(test-execute): split function + add unit test for nonce comp…
felix314159 Mar 5, 2026
53fe6fe
chore(test-client-clis): map ethrex BAL validation errors to INVALID_…
edg-l Mar 5, 2026
452e5f5
feat(tests): add basic ecmul precompile tests (#2403)
chfast Mar 5, 2026
d95c86e
feat(bench): add bloatnet ERC20 stubs for 50GB, 9.39GB, 1GB, 4.23MB (…
CPerezz Mar 5, 2026
a517953
refactor(spec-specs): use kwargs for message call output collision re…
spencer-tb Mar 5, 2026
5aff974
chore(test-client-clis): fix mapping missing for Block access list te…
matkt Mar 5, 2026
9baeae2
feat(tests): port EXTCODEHASH created and deleted account test (#2416)
chfast Mar 5, 2026
f63449c
feat(tests): add ECMUL scalar coverage for EIP-196 (#2424)
chfast Mar 5, 2026
a0f6c80
feat(tests): add basic ecpairing precompile tests (#2422)
chfast Mar 6, 2026
4baa94f
fix(benchmarks): move account_query test from compute to stateful (#2…
jochem-brouwer Mar 6, 2026
b822879
fix(benchmarks): fix fill issues with mint/approve erc20 updates (#2413)
jochem-brouwer Mar 6, 2026
e275279
fix(bench): fix solidity input check on balanceof sload bench (#2432)
jochem-brouwer Mar 6, 2026
de5e83d
feat(tests-static): Port rest of ecmul tests (#2425)
marioevz Mar 6, 2026
5fe1813
fix: perform more actions before aborting and prio oldest prs/issues …
felix314159 Mar 6, 2026
20d79d6
feat(tests): port EXTCODECOPY bounds test to frontier (#2417)
chfast Mar 6, 2026
446eabf
fix(benchmarks): fix mint test (#2435)
jochem-brouwer Mar 6, 2026
0a59524
feat(tests): port EXTCODEHASH created-and-deleted recheck in outer ca…
chfast Mar 6, 2026
ffb354b
feat(tests): add ecpairing coordinate validation tests for BN254 (#2438)
chfast Mar 6, 2026
ea4b6df
feat(tests): add ecrecover tests for combined invalid r and s values …
chfast Mar 7, 2026
3e80173
feat(tests): port EXTCODEHASH subcall CALLCODE selfdestruct test (#2418)
chfast Mar 9, 2026
68fae57
chore(tests-static): Port remaining EC Pairing static tests (#2443)
marioevz Mar 9, 2026
7ec6751
fix(consume): delay client stop on test failure to flush logs (#2445)
spencer-tb Mar 9, 2026
d1929c5
feat(tests): add ecpairing test for fq2 multiplicative inverse bug (#…
spencer-tb Mar 9, 2026
2aaa46f
feat(tests): add gas consumption test for invalid ecadd/ecmul/ecpairi…
chfast Mar 9, 2026
4583530
chore(tooling): add PR template instruction to CLAUDE.md (#2454)
chfast Mar 9, 2026
595ea5c
docs(specs, tests): fixed comments with values related to gas limits …
SamueleA Mar 9, 2026
1363db6
refactor(json_loader): json_loader to use the fill workflow (#2369)
gurukamath Mar 9, 2026
5052ee8
fix(test-execute): stop inserting empty Account in execute empty_acco…
chfast Mar 9, 2026
9629639
refactor(spec-specs): add opcode gas constants
Carsons-Eels Mar 3, 2026
6c75799
refactor(spec-specs): renamed GAS_BLOBHASH_OPCODE to GAS_BLOBHASH to …
Carsons-Eels Mar 3, 2026
1b0910f
refactor(testing): add per-opcode gas constants to GasCosts
Carsons-Eels Mar 3, 2026
4fb062e
refactor: move post-frontier opcodes
Carsons-Eels Mar 10, 2026
7aad8e3
refactor: added gas tiers for the test code
Carsons-Eels Mar 10, 2026
799cf49
refactor: use gas module refs for opcode constants
Carsons-Eels Mar 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
6 changes: 6 additions & 0 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ jobs:
# --- Stale settings ---
days-before-stale: 60

# raise this from the default 30
operations-per-run: 200

# process oldest first
ascending: true

# --- PR settings ---
days-before-pr-close: 0 # PR immediately auto-closes when marked stale
stale-pr-label: 'stale'
Expand Down
14 changes: 5 additions & 9 deletions .github/workflows/test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -94,23 +94,19 @@ jobs:
PYPY_GC_MAX: "2G"
PYPY_GC_MIN: "1G"

json_infra:
json_loader:
runs-on: [self-hosted-ghr, size-xl-x64]
needs: static
steps:
- uses: actions/checkout@08eba0b27e820071cde6df949e0beb9ba4906955
with:
submodules: recursive
fetch-depth: 0 # Fetch full history for commit comparison
- uses: ./.github/actions/setup-uv
with:
python-version: "3.11"
- uses: ./.github/actions/setup-env
- uses: ./.github/actions/setup-geth
- uses: ./.github/actions/get-changed-files
id: get-changed-files
- name: Run json infra tests
run: tox -e json_infra -- --file-list="${{ steps.get-changed-files.outputs.file_list }}"
- name: Fill and run json_loader tests
run: tox -e json_loader
env:
PYTEST_XDIST_AUTO_NUM_WORKERS: auto

tests_pytest_py3:
runs-on: [self-hosted-ghr, size-xl-x64]
Expand Down
1 change: 1 addition & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ When done with changes, ask the user if they'd like to run `/lint` before commit
- **There is no `main` branch.** Default branch = most active fork (currently `forks/amsterdam`). Run `git remote show origin | grep HEAD` to check.
- `mainnet` = stable specs for forks live on mainnet
- PRs target the default branch
- PRs strictly follow the template in `.github/PULL_REQUEST_TEMPLATE.md`. In the Checklist section, include unchecked items that don't apply β€” only remove them if they are truly irrelevant to the PR type.

## PR Reviews

Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ Below is an example.

```bash
uv run pytest \
'tests/json_infra/test_state_tests.py::test_state_tests_frontier[stAttackTest - ContractCreationSpam - 0]' \
'tests/json_loader/test_state_tests.py::test_state_tests_frontier[stAttackTest - ContractCreationSpam - 0]' \
--evm_trace
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ def _add_default_ignores(self, args: List[str]) -> List[str]:
# Directories to ignore by default
default_ignores = [
"tests/evm_tools",
"tests/json_infra",
"tests/json_loader",
"tests/fixtures",
]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import io
import json
import logging
import time
from typing import Generator, Literal, cast

import pytest
Expand Down Expand Up @@ -76,6 +77,7 @@ def genesis_header(fixture: BlockchainFixtureCommon) -> FixtureHeader:

@pytest.fixture(scope="function")
def client(
request: pytest.FixtureRequest,
hive_test: HiveTest,
# configured within: rlp/conftest.py & engine/conftest.py
client_files: dict,
Expand Down Expand Up @@ -106,6 +108,10 @@ def client(
assert client is not None, error_message
logger.info(f"Client ({client_type.name}) ready!")
yield client
# Allow the client to flush logs before stopping on failure.
result_call = getattr(request.node, "result_call", None)
if result_call is not None and result_call.failed:
time.sleep(1)
logger.info(f"Stopping client ({client_type.name})...")
with total_timing_data.time("Stop client"):
client.stop()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

import io
import json
import logging
import time
from typing import Dict, Generator, Mapping, cast

import pytest
Expand Down Expand Up @@ -188,15 +190,14 @@ def client_enode_url(client: Client) -> str:

@pytest.fixture(scope="function")
def sync_client(
request: pytest.FixtureRequest,
hive_test: HiveTest,
sync_client_files: Dict,
environment: Dict,
sync_client_type: ClientType, # Separate parametrization for sync client
client_enode_url: str, # Get the enode URL from fixture
) -> Generator[Client, None, None]:
"""Start a sync client that will sync from the client under test."""
import logging

logger = logging.getLogger(__name__)
logger.info(f"Starting sync client setup for {sync_client_type.name}")

Expand Down Expand Up @@ -253,6 +254,10 @@ def sync_client(
yield sync_client

# Cleanup
# Allow the client to flush logs before stopping on failure.
result_call = getattr(request.node, "result_call", None)
if result_call is not None and result_call.failed:
time.sleep(1)
sync_client.stop()


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -741,18 +741,13 @@ def _fund_address(

def _empty_account(self) -> Address:
"""
Execute implementation of empty account creation.
Execute implementation of empty_account.

Return a previously unused address. The account is not
created on-chain β€” it remains nonexistent.
"""
eoa = next(self._eoa_iterator)
logger.debug(f"Creating empty account at {eoa}")

self.__internal_setitem__(
eoa,
Account(
nonce=0,
balance=0,
),
)
logger.debug(f"Returning unused address {eoa} (nonexistent account)")
return Address(eoa)

def minimum_balance_for_pending_transactions(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
from filelock import FileLock
from pytest_metadata.plugin import metadata_key

from execution_testing.base_types import Address, Number, Wei
from execution_testing.base_types import Account, Address, Number, Wei
from execution_testing.logging import get_logger
from execution_testing.rpc import EthRPC
from execution_testing.rpc.rpc_types import JSONRPCError
Expand Down Expand Up @@ -406,12 +406,16 @@ def session_worker_key(
logger.info(f"Refund transaction confirmed: {refund_tx.hash}")


@pytest.fixture(scope="function")
def worker_key(
eth_rpc: EthRPC, session_worker_key: EOA
) -> Generator[EOA, None, None]:
"""Prepare the worker key for the current test."""
logger.debug(f"Preparing worker key {session_worker_key} for test")
def sync_worker_key_nonce(eth_rpc: EthRPC, session_worker_key: EOA) -> Account:
"""
Synchronize the worker key nonce with the on-chain nonce.

Fetch the account state and update the local nonce if it differs
from the RPC nonce. This handles both nonce increases (normal
progression) and decreases (chain reverts).

Return the fetched account for further use.
"""
try:
session_worker_account = eth_rpc.get_account(
session_worker_key, block_number="latest", skip_code=True
Expand All @@ -427,6 +431,16 @@ def worker_key(
logger.info(f"Worker key nonce mismatch: {wk_nonce} != {rpc_nonce}")
logger.info(f"Updating worker key nonce to {rpc_nonce}")
session_worker_key.nonce = rpc_nonce
return session_worker_account


@pytest.fixture(scope="function")
def worker_key(
eth_rpc: EthRPC, session_worker_key: EOA
) -> Generator[EOA, None, None]:
"""Prepare the worker key for the current test."""
logger.debug(f"Preparing worker key {session_worker_key} for test")
session_worker_account = sync_worker_key_nonce(eth_rpc, session_worker_key)

# Record the start balance of the worker key
worker_key_start_balance = session_worker_account.balance
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
"""Test the sender plugin's worker key nonce synchronization."""

from unittest.mock import MagicMock

import pytest

from execution_testing.base_types import Account, Number
from execution_testing.rpc.rpc_types import JSONRPCError
from execution_testing.test_types import EOA

from ..sender import sync_worker_key_nonce


@pytest.fixture
def mock_eth_rpc() -> MagicMock:
"""Create a mock EthRPC instance."""
return MagicMock()


@pytest.fixture
def mock_eoa() -> EOA:
"""Create a mock EOA with a known nonce."""
return EOA(
key=b"\x01" * 32,
nonce=0,
)


@pytest.mark.parametrize(
"initial_nonce,rpc_nonce",
[
pytest.param(
5,
10,
id="rpc_nonce_higher_than_local",
),
pytest.param(
10,
5,
id="rpc_nonce_lower_than_local_chain_revert",
),
pytest.param(
7,
0,
id="rpc_nonce_reset_to_zero_full_revert",
),
],
)
def test_worker_key_nonce_sync(
mock_eth_rpc: MagicMock,
mock_eoa: EOA,
initial_nonce: int,
rpc_nonce: int,
) -> None:
"""Test worker key nonce is updated whenever it differs from RPC."""
mock_eoa.nonce = Number(initial_nonce)
mock_eth_rpc.get_account.return_value = Account(
nonce=rpc_nonce, balance=10**18
)

sync_worker_key_nonce(mock_eth_rpc, mock_eoa)

assert mock_eoa.nonce == Number(rpc_nonce), (
f"Expected nonce to be synced to {rpc_nonce}, got {mock_eoa.nonce}"
)


def test_worker_key_nonce_unchanged_when_matching(
mock_eth_rpc: MagicMock,
mock_eoa: EOA,
) -> None:
"""Test worker key nonce is not modified when it matches RPC."""
mock_eoa.nonce = Number(5)
mock_eth_rpc.get_account.return_value = Account(nonce=5, balance=10**18)

sync_worker_key_nonce(mock_eth_rpc, mock_eoa)

assert mock_eoa.nonce == Number(5)


def test_sync_falls_back_to_pending_on_jsonrpc_error(
mock_eth_rpc: MagicMock,
mock_eoa: EOA,
) -> None:
"""Test fallback to pending block when latest is unavailable."""
mock_eoa.nonce = Number(3)
pending_account = Account(nonce=5, balance=10**18)
mock_eth_rpc.get_account.side_effect = [
JSONRPCError(code=-32000, message="not available"),
pending_account,
]

result = sync_worker_key_nonce(mock_eth_rpc, mock_eoa)

assert mock_eoa.nonce == Number(5)
assert result is pending_account
assert mock_eth_rpc.get_account.call_count == 2
Original file line number Diff line number Diff line change
Expand Up @@ -378,7 +378,7 @@ def _fund_address(

def _empty_account(self) -> Address:
"""
Filler implementation of empty account creation.
Filler implementation of empty_account.
"""
salt = self.get_next_account_salt(EMPTY_ACCOUNT_HASH)
return Address(eoa_from_hash(EMPTY_ACCOUNT_HASH, salt))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,13 +143,13 @@ def test_alloc_fund_eoa_basic() -> None:


def test_alloc_empty_account() -> None:
"""Test `Alloc.empty_account` functionality."""
"""Test `Alloc.empty_account` returns a nonexistent address."""
pre = create_test_alloc()
empty_addr = pre.empty_account()

# Check that we get a valid address (address generation works)
assert isinstance(empty_addr, Address)
# Note: empty_account() only returns address, doesn't add to pre
# The address must not be in the pre-state (nonexistent account).
assert empty_addr not in pre


def test_alloc_deploy_contract_code_types() -> None:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -319,10 +319,10 @@ def _fund_address(

def empty_account(self) -> Address:
"""
Return a previously unused account guaranteed to be empty.
Return the address of a previously unused nonexistent account.

This ensures the account has zero balance, zero nonce, no code, and no
storage. The account is not a precompile or a system contract.
The address is guaranteed to not be a precompile or a system contract.
No account is created β€” it remains nonexistent in the pre-state.
"""
return self._empty_account()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,5 @@ addopts =
--tb short
--dist load
--ignore tests/cancun/eip4844_blobs/point_evaluation_vectors/
--ignore tests/json_infra
--ignore tests/json_loader
--ignore tests/evm_tools
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,5 @@ addopts =
--tb short
--dist load
--ignore tests/cancun/eip4844_blobs/point_evaluation_vectors/
--ignore tests/json_infra
--ignore tests/json_loader
--ignore tests/evm_tools
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ addopts =
--tb short
--dist loadgroup
--ignore tests/cancun/eip4844_blobs/point_evaluation_vectors/
--ignore tests/json_infra
--ignore tests/json_loader
--ignore tests/evm_tools
# these customizations require the pytest-custom-report plugin
report_passed_verbose = FILLED
Expand Down
11 changes: 8 additions & 3 deletions packages/testing/src/execution_testing/client_clis/clis/besu.py
Original file line number Diff line number Diff line change
Expand Up @@ -458,7 +458,8 @@ class BesuExceptionMapper(ExceptionMapper):
# BAL Exceptions: TODO - review once all clients completed.
BlockException.INVALID_BAL_EXTRA_ACCOUNT: (
r"Block access list hash mismatch, "
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)"
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)|"
r"Block access list validation failed for block 0x[a-f0-9]+"
),
BlockException.INVALID_BAL_HASH: (
r"Block access list hash mismatch, "
Expand All @@ -468,14 +469,18 @@ class BesuExceptionMapper(ExceptionMapper):
r"Block access list hash mismatch, "
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)"
),
BlockException.BLOCK_ACCESS_LIST_GAS_LIMIT_EXCEEDED: (
r"Block access list validation failed for block 0x[a-f0-9]+"
),
BlockException.INVALID_BLOCK_ACCESS_LIST: (
r"Block access list hash mismatch, "
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)|"
r"Block access list validation failed for block"
r"Block access list validation failed for block 0x[a-f0-9]+"
),
BlockException.INCORRECT_BLOCK_FORMAT: (
r"Block access list hash mismatch, "
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)"
r"calculated:\s*(0x[a-f0-9]+)\s+header:\s*(0x[a-f0-9]+)|"
r"Block access list validation failed for block 0x[a-f0-9]+"
),
}

Expand Down
Loading