cmd/evm: fix regressions in statetest cmd#21111
Conversation
yperbasis
left a comment
There was a problem hiding this comment.
Context: Fixes issue #21080: (a) stateRoot no longer printed on stderr, (b) JSON result reports empty.RootHash instead of the real computed root when there's an error. Both root causes were introduced by #21058.
The core fixes are correct. Three observations worth addressing before merge:
1. enginextest default-workers regression (likely the biggest issue)
cmd/evm/enginexrunner.go drops:
if workers <= 0 {
// Knee of the wall-time vs. RAM curve on the full EEST engine_x set
// (~64k tests / ~36k groups): workers=8 reaches plateau speedup at
// ~4.3GB peak RSS. Higher values barely improve wall time and
// values >24 risk MDBX virtual-memory exhaustion.
workers = 8
}Combined with WorkersFlag.Value = 1, this means evm enginextest <dir> (no flag) now runs at 1 worker instead of 8 — i.e., the typical EEST engine_x sweep gets ~8× slower by default. The PR title says "fix regressions in statetest cmd" but this is a new regression in enginextest. The deleted comment was load-bearing tuning lore for the engine_x workload; the unified default of 1 makes sense for statetest/blocktest but not here.
Options:
- Keep the safety net in
enginexrunner.goso a missing--workersstill maps to 8. - Or explicitly document that EEST
engine_xruns should always pass--workers=8(preferably with a banner whenworkers == 1 && len(groups) > some_threshold).
2. stderr emission gate differs from the original
Previously (pre-#21058), the stderr emission was gated on --json (MachineFlag):
if jsonOut {
fmt.Fprintf(os.Stderr, "{\"stateRoot\": ...}", ...)
}After this PR (cmd/evm/staterunner.go):
emitStateRoot := ctx.Int(WorkersFlag.Name) <= 1The new gate is broader: any sequential run now writes {\"stateRoot\":...} lines to stderr, even without --json. This adds a per-test stderr line for users who weren't expecting it (e.g. anyone redirecting 2>err.log). goevmlab always uses --json, so it's unaffected — but the spec of the gate quietly changed. Consider:
emitStateRoot := ctx.Bool(MachineFlag.Name) && ctx.Int(WorkersFlag.Name) <= 1The added comment correctly justifies the workers <= 1 clause but is silent about why the --json clause was dropped.
3. Silent no-op for --workers=0 or negative values
cmd/evm/staterunner.go and cmd/evm/blockrunner.go both dropped the if workers <= 0 { workers = 1 } safety net. With WorkersFlag.Value = 1, the implicit default is fine, but the user passing --workers=0 explicitly now lands here:
for w := 0; w < workers; w++ { // never enters
wg.Add(1)
go func() { ... }()
}
go func() { wg.Wait(); close(resultCh) }() // immediate close
for fr := range resultCh { ... } // empty→ command silently produces zero results, exit code 0. Either restore the safety net or validate up-front and return an error.
What's right
execution/tests/testutil/state_test_util.go: returning the realrootinstead ofempty.RootHashoncheckedErris the correct fix —RunNoVerifyalways computes commitment afterapplyErr, so a meaningful root is available even forintrinsic gas too low-type errors (issue #21080's second screenshot).- The unused
common/emptyimport is correctly dropped. - Flag-default unification (0 → 1) and typo fix in
Usage("defaul") are clean. - The gate on
workers <= 1for stderr emission does correctly avoid the interleaving problem in parallel mode — that part of the reasoning is sound; only the--jsonhalf is missing. - In-Go test path (
execution/tests/state_test.go) discards the returned root, so thestate_test_util.gochange has no effect there.
Suggested fix sketch
// cmd/evm/enginexrunner.go
workers := cliCtx.Int(WorkersFlag.Name)
if workers <= 0 {
workers = 8 // keep engine_x-specific default, see comment above
}
// cmd/evm/staterunner.go + blockrunner.go
workers := ctx.Int(WorkersFlag.Name)
if workers <= 0 {
return nil, fmt.Errorf(\"--workers must be > 0, got %d\", workers)
}
// cmd/evm/staterunner.go
emitStateRoot := ctx.Bool(MachineFlag.Name) && ctx.Int(WorkersFlag.Name) <= 1There was a problem hiding this comment.
Pull request overview
This PR addresses regressions in evm statetest output formatting/contents (per #21080), primarily by ensuring the computed post-state root can still be surfaced for tooling that consumes the stderr JSONL stream.
Changes:
- Return the computed post-state root from
StateTest.Runeven when the error classification fails, instead of returning an “empty” root. - Re-introduce per-subtest
stateRootemission tostderr(JSONL) for sequentialstatetestruns. - Change
--workersdefault to1and simplify worker handling in several runners.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| execution/tests/testutil/state_test_util.go | Returns computed root alongside error-checking outcomes to avoid losing stateRoot in error cases. |
| cmd/evm/staterunner.go | Emits stateRoot JSONL on stderr (sequential mode) and simplifies passing --workers into parallel runner. |
| cmd/evm/main.go | Changes --workers default to 1 and updates its help text. |
| cmd/evm/enginexrunner.go | Removes the previous “auto/default workers” behavior for engine-x runs. |
| cmd/evm/blockrunner.go | Simplifies passing --workers into blocktest parallel runner. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
@yperbasis the first 2 are all intentional and not issues
|
|
@yperbasis point 3 is addressed in 8d327e8. ready for another review |
for #21080