Skip to content

fix(evm-rpc): tolerate per-tx null trace/stateDiff in trace_replayBlockTransactions#541

Open
elina-chertova wants to merge 1 commit into
masterfrom
alert-fix/dHLYGb-gnosis-statediff-null
Open

fix(evm-rpc): tolerate per-tx null trace/stateDiff in trace_replayBlockTransactions#541
elina-chertova wants to merge 1 commit into
masterfrom
alert-fix/dHLYGb-gnosis-statediff-null

Conversation

@elina-chertova

Copy link
Copy Markdown
Contributor

Problem

The evm-dump for gnosis-mainnet is stuck in a fatal crash-loop:

DataValidationError: server returned unexpected result: invalid value at /0/stateDiff: null is not an object
  at evm/evm-rpc/lib/rpc.js  (getResultValidator for trace_replayBlockTransactions)
  rpcMethod: trace_replayBlockTransactions   params: [<hash>, ["trace","stateDiff"]]

The upstream provider returns a valid HTTP 200 for trace_replayBlockTransactions, but with stateDiff: null for an individual transaction (verified: the same gnosis block returns a proper stateDiff object from two other providers, so the null is a provider-side defect, not inherent to the chain). Because getTraceTransactionReplayValidator requires stateDiff (and trace) to be a non-null object when the tracer is requested, validation throws a fatal DataValidationError and the whole ingestion process crashes and crash-loops — a single provider hiccup takes down the dump.

#497 already added tolerance for a block-level null (whole array). This extends the same treatment to the per-transaction case it missed (/0/stateDiff).

Fix

This makes the process survive a genuinely-external malformed response and retry the block, rather than crash-looping. (Complementary operator action — routing gnosis trace/stateDiff traffic away from the degraded provider — is being handled separately in ops; that only removes today's trigger, whereas this stops any provider hiccup from crash-looping ingestion.)

Test

evm/evm-rpc/test/trace-replay-null.test.ts — asserts the validator accepts a per-tx null stateDiff/trace. Fails on the pre-fix code ("... null is not an object"), passes after.

  • rush build -t @subsquid/evm-rpc — green (compiles)
  • vitest --run (evm-rpc) — 172 passed / 28 skipped, incl. the 2 new
  • tsc --noEmit -p tsconfig.test.json — clean

Falsification: if a provider persistently returns null for a block, _isInvalid retries 5× then throws (same as every other invalid-block path) — the durable resolution to a persistently-degraded provider is the routing change, not this PR; this PR ensures a transient null can no longer crash ingestion.

…ckTransactions

Some providers return `stateDiff: null` (or `trace: null`) for an individual
transaction inside an otherwise valid trace_replayBlockTransactions 200 response.
The per-tx validator required a non-null object and threw a fatal
DataValidationError ("invalid value at /0/stateDiff: null is not an object"),
crash-looping the dump.

Make the per-tx trace/stateDiff nullable and flag the block for retry via
_isInvalid, mirroring the block-level null handling added in #497 and the
debug_* trace paths.

Adds a regression test asserting the validator accepts a per-tx null.
@elina-chertova
elina-chertova requested a review from tmcgroul July 22, 2026 06:43
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.

1 participant