Skip to content

execution: fix 37 failing state tests on stable shard#21124

Merged
taratorio merged 8 commits into
mainfrom
worktree-fix-spec-statetests
May 12, 2026
Merged

execution: fix 37 failing state tests on stable shard#21124
taratorio merged 8 commits into
mainfrom
worktree-fix-spec-statetests

Conversation

@taratorio

Copy link
Copy Markdown
Member

Summary

Fix the 37 failing EEST state-test fixtures that the evm statetest CLI surfaces against fixtures/state_tests from execution-spec-tests v5.4.0. After this change ./build/bin/evm statetest --workers=12 fixtures/state_tests reports 63556 / 63556 passing.

Before this PR the CLI failed 37 subtests — these are real Erigon validation gaps that TestState was masking with a lenient wrapper that swallowed expectException mismatches. The failures fell into two buckets:

  • Pre-fork tx-type rejection (28 fixtures) — typed transactions accepted on forks before the EIP that introduced them: EIP-2930 type-1 on pre-Berlin, EIP-1559 type-2 on pre-London, EIP-4844 type-3 on Shanghai.
  • EIP-4844 blob-tx structural validation (9 fixtures, all in static/Cancun/stEIP4844_blobtransactions) — blob txs with to == nil (TYPE_3_TX_CONTRACT_CREATION), an empty blobVersionedHashes list (TYPE_3_TX_ZERO_BLOBS), or a versioned hash whose first byte ≠ 0x01 (TYPE_3_TX_INVALID_BLOB_VERSIONED_HASH).

Changes

execution/types/blob_tx.go — close the EIP-4844 validity gaps in BlobTx.AsMessage

Added three checks that the EIP-4844 spec defines as transaction validity rules but that previously only ran during block validation (misc.ValidateBlobs), bypassing the state-test code path and any other caller that goes through AsMessage without a block context:

  • Reject tx.To == nil (contract creation is not permitted for blob txs) with ErrNilToFieldTx.
  • Reject empty BlobVersionedHashes with new sentinel ErrBlobTxnEmptyBlobs.
  • Reject any versioned hash whose first byte is not kzg.BlobCommitmentVersionKZG with new sentinel ErrBlobTxnInvalidVersionedHash.

The pre-existing if !rules.IsCancun check is moved to the top of the method (consistent with the other AsMessage implementations) so that pre-fork rejections happen before any other work.

execution/tests/testutil/state_test_util.go — route the state-test runner through production validation

RunNoVerify used to build the Message from JSON via toMessage and feed it straight to ApplyMessage, bypassing every consensus-level validation. The runner now:

  1. Decodes post.txbytes via types.DecodeTransaction for every EEST fixture (all 63556 carry it) and calls tx.AsMessage(signer, baseFee, rules) — the same code path real block processing uses. Tx-type-vs-fork rejection and the new EIP-4844 checks fall out of this automatically.
  2. Falls back to toMessage only for the six in-tree corner-case fixtures under execution/tests/test-corners/state/* that don't ship txbytes. None of those exercise pre-fork tx-type rejection, so bypassing AsMessage validation there is fine.
  3. Builds BlockContext early (before AsMessage) so a single blockContext.Rules(config) provides the chain rules AsMessage needs, and the same context is reused for the EVM construction afterwards — no duplicated rules-construction code.
  4. Computes a pre-state root once right after MakePreState via domains.ComputeCommitment. This is essentially free (the trie state is still warm from MakePreState's own flush) and lets every early-return path return a real root that satisfies the test framework's post.Root check for rejected-tx fixtures.
  5. Early-returns on every error with the pre-state root. No more applyErr bookkeeping — each if err != nil { return statedb, preRoot, gasUsed, err } returns immediately, and the post-state finalize/commit/computeCommitment path runs only on a successful apply.
  6. Skips the coinbase touch on rejected txs. On pre-EIP-158 forks (Frontier, Homestead) a stray AddBalance(coinbase, 0) creates an empty account that doesn't get pruned, which would break the post-state root the fixture expects for an unapplied tx. The touch now runs only after a successful ApplyMessage.

Why route the test runner through AsMessage

The original state-test runner duplicated nothing — it just skipped validation. Two consequences:

  • Real Erigon validation gaps (the 9 EIP-4844 ones, fixed in blob_tx.go) were invisible to TestState because toMessage never invoked the checks.
  • Any new validation added to AsMessage in the future would still be skipped by tests, defeating the purpose of state-test coverage.

Decoding txbytes and calling production AsMessage removes both problems with no new test-only validator. The only test-specific code that remains is toMessage, used solely for the six corner-case fixtures that pre-date txbytes support.

Verification

  • ./build/bin/evm statetest --workers=12 fixtures/state_tests63556 / 63556 pass (was 63519 / 37).
  • go test ./execution/tests/ -run "TestState$|TestStateCornerCases$" — pass.
  • make lint — clean.
  • GOGC=80 make test-all — 222 packages OK, 0 failures.

Performance

12-worker evm statetest over the full fixture set on a tmpfs (ramdisk):

Variant run 1 run 2 run 3 mean
Before this PR (HEAD) 122.92s 121.86s 122.05s 122.28s
After this PR 118.92s 119.56s 120.43s 119.64s

Slightly faster (~2.1%) despite the added pre-state ComputeCommitment: the new early-return path skips a redundant FinalizeTx + CommitBlock + ComputeCommitment on rejected-tx fixtures (where no state changed anyway), and the pre-state commitment is essentially a cache walk since MakePreState just flushed the same trie.

Test plan

  • ./build/bin/evm statetest --workers=12 fixtures/state_tests returns 0 failures against EEST v5.4.0 fixtures_develop.tar.gz.
  • go test ./execution/tests/ -run "TestState$|TestStateCornerCases$" passes.
  • make lint is clean.
  • CI All tests workflow is green.

@taratorio taratorio requested review from mh0lt and yperbasis as code owners May 12, 2026 05:11
@taratorio taratorio changed the title Worktree fix spec statetests execution: fix 37 failing state tests on stable shard May 12, 2026
@taratorio taratorio requested a review from AskAlexSharov May 12, 2026 05:12
@taratorio taratorio requested a review from Giulio2002 as a code owner May 12, 2026 10:36
@taratorio taratorio enabled auto-merge May 12, 2026 10:36
@taratorio taratorio added this pull request to the merge queue May 12, 2026
Merged via the queue into main with commit 3873840 May 12, 2026
58 checks passed
@taratorio taratorio deleted the worktree-fix-spec-statetests branch May 12, 2026 11:59
yperbasis added a commit that referenced this pull request May 18, 2026
Remove 11 Go files and 1 readme that contain only a license header and
package declaration, only commented-out code, or document a package that
no longer exists. Follow-up to #19665.

- cl/transition/impl/funcmap/impl.go - entire Impl struct/methods in a
  block comment; only file in the package; no external references.
- cl/utils/time_test.go - both test bodies commented out.
- cmd/rpcdaemon/graphql/graph/model/test.go - just `package model`.
- cmd/sentinel/sentinelcli/flags/{flags,defaultFlags}.go - the whole
  package was empty (only these two files, neither imported anywhere).
- common/log/skip.go - just `package log`.
- db/integrity/receipts_no_duplicates_test.go - just `package integrity`.
- db/kv/temporal/historyv2/{changeset.go,readme.md} - the package was
  intentionally removed in #19665 but was accidentally re-introduced by
  a rebase artifact in #21124 (whose commit message is entirely about
  state-test fixes and never mentions historyv2); the codebase has zero
  references to it.
- db/state/reconst.go - orphan `package state` declaration in a 66-file
  package.
- execution/tracing/tracers/tracer.go - just `package tracers`; the
  sibling `tracers.go` is the real file.
- execution/tracing/tracers/logger/logger2_test.go - test body fully
  commented out.

Intentionally kept: doc.go files (godoc), gen.go/mockgen.go/abi.go
(//go:generate hosts), node/interfaces/*/keep.go (sub-module package
markers), and execution/commitment/bin_patricia_hashed{,_test}.go
(commented-out reference implementation worth preserving).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@yperbasis yperbasis mentioned this pull request May 18, 2026
3 tasks
nivanovvv pushed a commit to nivanovvv/erigon that referenced this pull request May 18, 2026
## Summary

Remove 11 Go files and 1 readme that contain only a license header and
package declaration, only commented-out code, or document a package that
no longer exists. Follow-up to erigontech#19665.

### Removed

- `cl/transition/impl/funcmap/impl.go` — entire `Impl` struct/methods in
a block comment; only file in the package; no external references.
- `cl/utils/time_test.go` — both test bodies commented out.
- `cmd/rpcdaemon/graphql/graph/model/test.go` — just `package model`.
- `cmd/sentinel/sentinelcli/flags/{flags,defaultFlags}.go` — the whole
package was empty (only these two files, neither imported anywhere).
- `common/log/skip.go` — just `package log`.
- `db/integrity/receipts_no_duplicates_test.go` — just `package
integrity`.
- `db/kv/temporal/historyv2/{changeset.go,readme.md}` — the package was
intentionally removed in erigontech#19665 but was accidentally re-introduced by a
rebase artifact in erigontech#21124 (whose commit message is entirely about
state-test fixes and never mentions historyv2); the codebase has zero
references to it.
- `db/state/reconst.go` — orphan `package state` declaration in a
66-file package.
- `execution/tracing/tracers/tracer.go` — just `package tracers`; the
sibling `tracers.go` is the real file.
- `execution/tracing/tracers/logger/logger2_test.go` — test body fully
commented out.

### Intentionally kept

Several other files matched "empty-except-package-and-comments" but
serve real purposes and were left alone:

- `doc.go` files in `common/log/v3/{,term/}`, `execution/rlp/`,
`execution/vm/{,runtime/}`, `p2p/dnsdisc/`, `node/{,app/workerpool/}`,
`rpc/` — godoc package documentation.
- `gen.go` / `mockgen.go` / `abi.go` files in `cmd/pics/contracts/`,
`txnprovider/shutter/internal/contracts/`, `execution/tests/contracts/`,
`execution/state/contracts/`, `rpc/jsonrpc/contracts/`,
`execution/protocol/rules/aura/auraabi/`,
`node/gointerfaces/{sentryproto,remoteproto,downloaderproto}/` —
`//go:generate` hosts.
-
`node/interfaces/{,p2psentinel/,types/,web3/,downloader/,txpool/,execution/,p2psentry/,remote/}keep.go`
— package markers for the `.proto`-only sub-module rooted at
`node/interfaces/` (has its own `go.mod`).
- `execution/commitment/bin_patricia_hashed{,_test}.go` — commented-out
reference implementation worth preserving for future work.

## Test plan

- [x] `make erigon integration` — clean build.
- [x] `make lint` — `0 issues.`
- [ ] CI green.

Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants