Skip to content

Constantinople-fork divergence on legacy Cancun GeneralStateTests #20894

@yperbasis

Description

@yperbasis

Background

The new `TestLegacyCancunState` (added in #20892) walks `execution/tests/legacy-tests/LegacyTests/Cancun/GeneralStateTests` to catch the d3 RIPEMD-160 touch path that the Hive `legacy-cancun` simulator surfaced. Most of those tests pass; six fixtures consistently fail on the Constantinople subtest only, with post-state-root mismatches.

Failures (all Constantinople fork, all post-state-root mismatches)

File Failing subtest indexes
`stSStoreTest/sstoreGas.json` 0
`stCreateTest/CREATE_HighNonce.json` 0
`stCreate2/CREATE2_HighNonce.json` 0
`stCreate2/CREATE2_HighNonceDelegatecall.json` 0–3, 5, 11–15, 17, 23
`stPreCompiledContracts2/CallEcrecover_Overflow.json` 0–4
`stPreCompiledContracts2/ecrecoverShortBuff.json` 0

All other forks (Byzantium, ConstantinopleFix, Berlin, Istanbul, London, Paris, Shanghai, Cancun, …) pass. The failures are pre-existing — verified by reverting #20892's STATICCALL change and re-running.

Why this wasn't caught locally before

`TestLegacyCancunState` is the first local runner to walk `LegacyTests/Cancun/GeneralStateTests`. Geth's `tests/state_test.go` walks `LegacyTests/Constantinople/GeneralStateTests` (an older snapshot — see `tests/init_test.go:40` in go-ethereum), which does not include these specific fixtures. The fixtures' `_info.filling-rpc-server` shows they were generated by `evm 1.13.11-unstable-…20240124` (geth itself), so geth passes them by definition — Erigon only notices by walking the Cancun snapshot or running Hive `legacy-cancun`.

Sample divergence

`CREATE_HighNonce/Constantinople/0`:

  • pre-state `0xb94f5374…` has `nonce = 0xffffffffffffffff` (max uint64) and 102 bytes of code; the tx invokes it.
  • expected post-state root: `0xf5ffa088bcc12fb74a9d1d1ff8dab72e02d0b26d2c834de1504fb48eaaf3ea66`
  • Erigon computes: `0xc8e453a40ff2bf75e275958a382d54971d2f8b713ce2c59ca5e0d90b2f2cce03`

Three orthogonal clusters

Group by suspected root cause; each likely its own small consensus fix:

  1. EIP-1283 SSTORE gas metering (`sstoreGas`) — Constantinople-only; reverted by Petersburg.
  2. Max-uint64 nonce CREATE/CREATE2 behavior (`_HighNonce`) — pre-EIP-2681 (Berlin), behavior was specified differently across forks.
  3. ECRecover with malformed/overflow input (`CallEcrecover_Overflow`, `ecrecoverShortBuff`) — likely an input-validation/normalization difference.

Workaround

#20892 `st.SkipLoad`s the six files with a comment pointing at this issue, so the test catches future regressions on the d3 RIPEMD-160 path without gating PRs on this orthogonal cluster.

Notes for whoever picks this up

  • Reproduction: `go test -timeout 5m -count=1 -run "TestLegacyCancunState/" ./execution/tests/ -short=false` (after temporarily removing the corresponding `SkipLoad` line in `execution/tests/state_test.go`).
  • `-v` on the same command reports the "got vs want" post-state root for each failing index.
  • All six are pure state tests (not blockchain tests), so reproducing under `evm statetest` should match the test runner output.

Metadata

Metadata

Assignees

Labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions