evm-rpc: retry transient 'invalid block height' on finalized-head probe (fixes hyperliquid-testnet dump crash-loop)#513
Open
elina-chertova wants to merge 1 commit into
Conversation
getLatestBlockhash() probes the finalized head via eth_getBlockByNumber with only validateResult and no validateError, so when a load-balanced provider transiently returns -32603 'invalid block height' for the finalized tag (its backend lagging the finalized pointer), the RpcError propagates as fatal and crash-loops the dump. getBlocks() already maps this exact error to a RetryError for Hyperliquid; apply the same mapping on the finalized-head probe so it retries instead of crashing.
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.
Symptom
hyperliquid-testnet_Writer_Short_Stall(evm-archive, kind=ingest). The parquet writer's last block has not advanced for 48h; thewritecontainer logs"no blocks were found. waiting 300 sec"in a steady loop.Root cause (proven)
The writer is starved because the upstream
dump-hyperliquid-testnet-0pod crash-loops (6 restarts/1h, 119/24h, 317/48h — spanning the entire 48h stall). The dump fetches blocks fine for ~10 min, then dies. The previous (crashed) container's last line:The dump probes the finalized head via
Rpc.getLatestBlockhash('finalized')→eth_getBlockByNumber(["finalized", false]). The load-balanced provider (uniblock) momentarily returns-32603 "invalid block height"when a backend node lags behind its finalized pointer (57603085 ≈ chain head 57603305). ThisgetLatestBlockhashcall passes onlyvalidateResultand novalidateError, soreceiveResultthrows a plainRpcError— which is not a connection error and so is not retried — and the process exits. On restart the dump resumes from the last persisted raw chunk, re-fetches the same range, hits the same transient error before it can flush a new chunk, and crash-loops indefinitely → the writer never receives new raw data →Writer_Short_Stall.This is a missed path of the existing Hyperliquid fix:
getBlocks()already maps this exact error to aRetryError(commit 7946278, "add retries for hl specific error"), butgetLatestBlockhash()— the finalized-head probe — was not given the same handler.Fix (tested)
Add the same
validateErrorto thegetLatestBlockhashcall so"invalid block height"throwsRetryError(retried by the client's built-in retry machinery —isConnectionError(RetryError) === true) instead of crashing. Other RPC errors still propagate asRpcError. One block re-fetch hits a healthy backend, so the probe converges. Minimal change, mirroring the established pattern.Verification
npx vitest --run finalized-head-retryinevm/evm-rpc: red → green.getLatestBlockhash('finalized')throwsRpcError: invalid block height(reproduces the production crash atsrc/rpc.ts:113).execution reverted) still surface.evm/evm-rpcsuite: 154 passed, 27 skipped, 0 failed.rush build --to @subsquid/evm-rpccompiles clean.Falsification
If the dump still crash-loops after deploy with
eth_getBlockByNumber(["finalized", …])raising an error whose message does not contain"invalid block height", or if the provider returns this error persistently (every attempt, so retries never converge and the dump hangs without progress), then the trigger is a different/persistent provider failure, not the transient one this handles.Operator note (not part of this PR)
The trigger is uniblock (chainId=998) intermittently failing the
finalizedtag —https://status.uniblock.dev. A provider swap would remove today's trigger but is a temporary mitigation, not a durable fix (prior provider-swap PRs for this exact symptom — infra #578, #581 — were closed); this code change is the durable resolution so a single provider hiccup can no longer crash-loop the dump.Related to #502 (recover from transient
ForkExceptionon the finalized dump) — same theme (don't crash-loop on transient finalized-stream errors), different cause: that PR handles aForkExceptioninutil-internal-dump-cliand explicitly re-throws non-fork errors; this handles a plainRpcErrorin@subsquid/evm-rpc's finalized-head probe, which #502 does not catch.