fix(svm): preserve SolanaError through QuorumFallback for shouldFailImmediate codes#1443
Merged
Merged
Conversation
…mmediate codes QuorumFallbackSolanaRpcFactory wrapped the underlying SolanaError in a plain Error via createSendErrorWithMessage on aggregation, and also wrapped on the quorumThreshold===1 short-circuit. Both wrappers erased the SolanaError type, so callers' isSolanaError(...) checks fell through to default error handling. This broke the slot walk-back in getNearestSlotTime: when a Solana RPC returns SVM_SLOT_SKIPPED for the requested slot, _callGetTimestampForSlotWithRetry is supposed to return undefined and let the do-while loop try the prior slot. Instead the wrapped Error fell through `if (!isSolanaError(err)) throw err` and crashed the dataworker. Both sites now rethrow the original error when shouldFailImmediate(method, error) is true. The fallback short-circuit drops its own wrapper, and the final aggregation step only wraps when at least one rejection is a non- shouldFailImmediate failure (i.e. a real provider issue worth surfacing with the "Not enough providers succeeded" context). Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pxrl
reviewed
May 24, 2026
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Contributor
Author
|
Addressed pxrl's review feedback on #1443. The comment said the comments in this PR were too verbose. I trimmed them in 403d5f7:
Checks: |
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Mirrors the src tree (src/providers/solana/quorumFallbackRpcFactory.ts) and the convention set by test/providers/solana/utils.test.ts. The flat test/Solana*.ts siblings predate that structure. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
pxrl
approved these changes
May 24, 2026
Contributor
Author
|
pxrl approved #1443 with no inline comments, and the PR is already merged (head |
This was referenced May 24, 2026
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.
Summary
QuorumFallbackSolanaRpcFactorywrapped the underlyingSolanaErrorin a plainErrorat two points (final aggregation viacreateSendErrorWithMessage, and thequorumThreshold === 1 && shouldFailImmediateshort-circuit). Both wrappers erased theSolanaErrortype, so callers'isSolanaError(err)checks fell through to default error handling.provider.getBlockTime(421829272)returnedSVM_SLOT_SKIPPED(network-wide skipped slot, reproducible against the public RPC), but_callGetTimestampForSlotWithRetrysaw a genericErrorand re-threw instead of returningundefined. That brokegetNearestSlotTime's slot walk-back and crashedzion-across-l2-executor-solana.shouldFailImmediate(method, error)is true. The final aggregation step still wraps with the descriptiveNot enough providers succeeded...context whenever at least one rejection is a non-deterministic provider failure — that's the case where surfacing the provider URLs and successful peers is genuinely useful.Test plan
test/SolanaQuorumFallbackProvider.tscover: single-rejection skipped slot rethrows theSolanaError; multi-provider all-skipped rethrows the first rejection; non-shouldFailImmediatefailures keep the wrapping path withcause;shouldFailImmediatecodes on unrelated methods still wrap; mixed failures fall through to the wrapper; successful responses still pass through.npx hardhat test test/SolanaQuorumFallbackProvider.ts test/providers/utils.test.ts test/providers/solana/utils.test.ts— 22 passing.npx hardhat test test/SolanaCachedProvider.ts test/SolanaRateLimitedProvider.ts test/SolanaRetryProvider.ts— 15 passing (no regressions in the surrounding factory chain).npx tsc --project tsconfig.build.json --noEmitclean.prettier --checkandeslintclean.Background
Surfaced in Slack thread; full diagnosis traced the error from the dataworker stack through
SVMBlockFinder.findBlock→getNearestSlotTime→getTimestampForSlot→ theQuorumFallbackwrapping. Slot 421829272 was a real network-wide skipped slot — the dataworker recovers automatically on restart, but the same crash will recur whenever a skipped slot lands near the head until this lands.🤖 Generated with Claude Code