From 340cf6b836b87e96176bff573911c6686dab09cc Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 21 May 2026 11:23:56 +0200 Subject: [PATCH 1/3] feat(tests): Add `--allow-post-state-hash` option to json_loader Some fixture formats include `postStateHash` but omit the full `postState` dict (e.g. benchmark fixtures, which default to `include_full_post_state_in_output=False`). Without this flag the json_loader xfails such fixtures and EELS' state transition never runs. With `--allow-post-state-hash`, state transition runs and the existing `lastblockhash` assertion validates the post-state root via the block header. Behavior is unchanged when the flag is absent. --- tests/json_loader/conftest.py | 14 ++++++++++++++ .../helpers/load_blockchain_tests.py | 18 ++++++++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/tests/json_loader/conftest.py b/tests/json_loader/conftest.py index c8491ba1350..e5faa6b1532 100644 --- a/tests/json_loader/conftest.py +++ b/tests/json_loader/conftest.py @@ -94,6 +94,20 @@ def pytest_addoption(parser: Parser) -> None: help="Path to a file containing test ids, one per line", ) + parser.addoption( + "--allow-post-state-hash", + dest="allow_post_state_hash", + default=False, + action="store_const", + const=True, + help=( + "Verify blockchain fixtures that only include `postStateHash` " + "(not the full `postState` dict). The EELS state transition's " + "internal state-root check plus the `lastblockhash` assertion " + "are cryptographically sufficient." + ), + ) + def pytest_configure(config: Config) -> None: """ diff --git a/tests/json_loader/helpers/load_blockchain_tests.py b/tests/json_loader/helpers/load_blockchain_tests.py index 487df2411fb..d4d21a43012 100644 --- a/tests/json_loader/helpers/load_blockchain_tests.py +++ b/tests/json_loader/helpers/load_blockchain_tests.py @@ -103,7 +103,16 @@ def test_dict(self) -> Dict[str, Any]: def runtest(self) -> None: """Run a blockchain state test from JSON test case data.""" json_data = self.test_dict - if "postState" not in json_data: + has_post_state = "postState" in json_data + allow_post_state_hash = self.config.getoption( + "allow_post_state_hash", False + ) + post_state_hash_only = ( + not has_post_state + and "postStateHash" in json_data + and allow_post_state_hash + ) + if not has_post_state and not post_state_hash_only: pytest.xfail( f"{self.test_file}[{self.test_key}] doesn't have post state" ) @@ -187,10 +196,11 @@ def runtest(self) -> None: keccak256(rlp.encode(chain.blocks[-1].header)) == last_block_hash ) - expected_post_state = load.json_to_state(json_data["postState"]) - assert chain.state == expected_post_state + if has_post_state: + expected_post_state = load.json_to_state(json_data["postState"]) + assert chain.state == expected_post_state + close_state(expected_post_state) close_state(chain.state) - close_state(expected_post_state) def reportinfo(self) -> Tuple[Path, int, str]: """Return information for test reporting.""" From b19401d8053c0ec9cee97c81d276e8602765ed1d Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 21 May 2026 11:24:09 +0200 Subject: [PATCH 2/3] feat(bench-gas): Verify filled fixtures against EELS via json_loader The existing `bench-gas` recipe only checked that the configured EVM (geth via `EVM_BIN`) can fill benchmark fixtures. It said nothing about whether EELS and the configured EVM agree on the resulting state. This adds a Step 2 that symlinks the filled output under `tests/json_loader/` so the json_loader conftest applies, then runs `pytest --allow-post-state-hash --fork Osaka` against the fixtures. The EELS state transition validates each block's state root against the header internally; the `lastblockhash` assertion provides the final cryptographic check. Step 2 runs under PyPy 3.11 for a ~9x speedup over CPython on this workload (`1082 passed in 2:08` vs `19:32`). Step 1 stays on CPython since filling bottlenecks on subprocess I/O to the EVM binary, not on hot Python loops, so PyPy doesn't help there. The new `tests/json_loader/bench_gas_fixtures` symlink is gitignored. --- .gitignore | 1 + Justfile | 12 +++++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 6d26b16d6d5..b736a90b110 100644 --- a/.gitignore +++ b/.gitignore @@ -69,6 +69,7 @@ pip-delete-this-directory.txt .tox/ .just/ +tests/json_loader/bench_gas_fixtures /doc/_autosummary diff --git a/Justfile b/Justfile index 39041974066..350ba08ab61 100644 --- a/Justfile +++ b/Justfile @@ -212,10 +212,11 @@ test-ci-scripts *args: # --- Benchmarks --- -# Fill benchmark tests with --gas-benchmark-values +# Fill benchmark tests with --gas-benchmark-values, then verify with EELS [group('benchmark tests')] bench-gas *args: @mkdir -p "{{ output_dir }}/bench-gas/tmp" "{{ output_dir }}/bench-gas/logs" + @echo "==> Step 1/2: Filling benchmark fixtures with configured EVM (EVM_BIN={{ evm_bin }})" uv run fill \ --evm-bin="{{ evm_bin }}" \ --gas-benchmark-values 1 \ @@ -229,6 +230,15 @@ bench-gas *args: --clean \ "$@" \ tests/benchmark/compute + @echo "==> Step 2/2: Running filled fixtures against EELS via json_loader" + @rm -rf tests/json_loader/bench_gas_fixtures + ln -sfn "{{ output_dir }}/bench-gas/fixtures" tests/json_loader/bench_gas_fixtures + cd tests/json_loader && uv run --python pypy3.11 pytest \ + --fork Osaka \ + --allow-post-state-hash \ + -n auto --maxprocesses 10 --dist=loadfile \ + --basetemp="{{ output_dir }}/bench-gas/json-loader-tmp" \ + bench_gas_fixtures # Fill benchmark tests with --fixed-opcode-count 1 [group('benchmark tests')] From 2c609713dab969e8add6cd7791b0db507702df4e Mon Sep 17 00:00:00 2001 From: danceratopz Date: Thu, 21 May 2026 11:24:30 +0200 Subject: [PATCH 3/3] ci(bench): Install PyPy for bench-gas json_loader verify The new Step 2 in `bench-gas` runs the EELS verification under `uv run --python pypy3.11`. Pre-install PyPy via `uv` so the recipe doesn't pay the on-demand download cost mid-run. Gated to the `bench-gas` matrix entry; the other recipes don't need it. --- .github/workflows/benchmark.yaml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/benchmark.yaml b/.github/workflows/benchmark.yaml index 165bfa52039..c4466f8bd15 100644 --- a/.github/workflows/benchmark.yaml +++ b/.github/workflows/benchmark.yaml @@ -71,6 +71,11 @@ jobs: with: enable-cache: "false" + - name: Install PyPy for bench-gas json_loader verify + if: matrix.recipe == 'bench-gas' + shell: bash + run: uv python install pypy3.11 + - uses: ./.github/actions/build-evm-base id: evm-builder with: