Retry blocks with empty debug traces/stateDiffs instead of serving them#2
Open
elina-chertova wants to merge 1 commit into
Open
Conversation
debug_traceBlockByHash (callTracer/prestateTracer) returns one entry per transaction, but fetch_debug_frames/fetch_debug_state_diffs collapse any RPC error or null result (including the 'not found'/'cannot query unfinalized data' responses they normalize to Null) into an empty vec![]. That empty vector was stored and cached as if the block legitimately had no traces, so blocks with transactions could be silently served with empty traces/stateDiffs. Add a completeness check in add_traces mirroring add_logs/add_receipts: a block that has transactions but no debug trace/stateDiff entries is marked invalid so enrich_block_with_retry re-fetches the whole block. Blocks with zero transactions correctly have no entries and are left untouched.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
debug_traceBlockByHash(callTracer / prestateTracer) returns exactly one entry per transaction. Butfetch_debug_frames/fetch_debug_state_diffscollapse any RPC error or anullresult into an emptyvec![]:Critically,
validate_errornormalizes the transient "not found" / "cannot query unfinalized data" responses toOk(Value::Null)— i.e. exactly the block-not-ready-yet case that should be retried. Instead, the empty vector is assigned onto the block and the whole-block retry loop (enrich_block_with_retry) treats it as ready, because its readiness check (!b.is_invalid) is only ever tripped by the logs/receipts hash checks (add_logs/add_receipts) — never by empty traces. So a block whose trace call momentarily errored or returned null is silently served (and cached) with empty traces/stateDiffs.This reproduced in production on the Rust hotblocks providers (
evm-data-service-rs:0.1.4): ~40% of a 20-block eth-sepolia window had empty trace data while the upstream returned it, which forced an operational revert of all trace/statediff hotblocks datasets back to the TypeScript image.Note: the earlier
v0.1.5fix (64a709d) addressed the trace-API (trace_replayBlockTransactions) path only; the debug-API path above was untouched and still carried the bug.Fix
Add a completeness check in
add_traces, mirroring the existingadd_logs/add_receiptsnot-ready handling: a block that has transactions but came back with no debug trace / stateDiff entries is marked invalid, soenrich_block_with_retryre-fetches the whole block instead of accepting the gap. A block with zero transactions correctly has no entries and is left untouched (the same way an emptyeth_getLogsresult is correct whenlogsBloom == 0).This makes a transient upstream trace error survivable by retry rather than turning it into permanently cached corrupt data — it does not "tolerate" the bad data as valid.
Test
crates/evm-source/tests/debug_traces.rsdrives the real fetch pipeline against a mock node that returns a block with one transaction butnullfordebug_traceBlockByHash, and asserts the block is flagged not-ready.FAILED ... block with transactions but empty debug traces must be marked invalidtest result: ok. 1 passed(Verified locally with
cargo test -p evm-source --test debug_traces. The repo'spipeline.rs/parity.rssuites depend on git-LFS fixtures that were not available in my sandbox, so they could not be run here; this new test builds its block JSON inline and is unaffected.)Falsification
If, after this lands, the trace/statediff datasets re-migrated to Rust still show empty traces for blocks that have transactions (compared against the TS image or a reference node), or if
enrich_block_with_retrystarts bailing/crash-looping on a healthy chain head because the retry window (10×50ms) is too short for normal head-following trace lag, then this fix is wrong/insufficient.