Repository navigation
Conversation
Clients poll eth_getBlockByNumber for the block after the tip before it is produced. Every upstream answers null, and the request already knows that (EmptyResultBeyondConfidence: the block is above the network's highest head), but that only stopped the fallback escape. The upstream loop and the hedge keeper still treated the null as a miss, so each request walked every routed upstream, including the paid fallback tier on networks that route all tiers in one list, and the retry layer repeated the walk. Accept the empty result as the answer in both places when the block is beyond confidence. A block at or below the head that a primary misses still sweeps and escapes as before. On internal-erpc eth-mainnet this is the ~17 r/s of eth_getBlockByNumber reaching Chainstack/Infura since the #31 roll, ~97% of which came back null. The pre-rewrite lineage avoided it by pinning near-tip getBlockByNumber to the tip leader (#14). Co-Authored-By: Claude Opus 5.5 <[email protected]>
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.
Stacked on #31 (
fix/fallback-tier-subscriptions@ 361a84a, the image running on all five internal-erpc instances).Problem
Since the #31 roll, internal-erpc eth-mainnet sends ~17 r/s of
eth_getBlockByNumberto paid fallbacks (Chainstack/Infura). ~97% of those come backnull.Clients poll
eth_getBlockByNumberfor the block after the tip, about 9s before it is produced (each future block is requested ~5 times). No upstream has it. eRPC already knows this:EmptyResultBeyondConfidencesays the block is above the network's highest head, andemptyIsMissuses that to skip the fallback escape. But two places ignore it:nullas "try the next upstream" unless the method is inemptyResultAcceptkeeprejects the emptyish result, so the race keeps goingSo each request walks every routed upstream, and the retry layer repeats the walk. On eth-mainnet, which routes every tier in one ordered list, that means the paid fallbacks.
The pre-rewrite lineage (the old
ws-eth-call-lag-test1image) avoided this through #14, which pinned near-tip getBlockByNumber to the tip leader. The rewrittenfeat/websocket-supportkeeps only an ordering hint (preferTipLeaderForNearTipGetBlock).ws-tip-leader-8e98cb2was reverted on Oct 2 for the same symptom.The hedge-keeper change in #31 (46c6a83) is not the cause. With a
nullresult the leg returns the response, notErrUpstreamsExhausted, so the removed rule never applied. The repro gives the same numbers with and without it.Change
When the requested block is beyond confidence, an empty result is the answer:
erpc/networks.go: the upstream loop accepts it, so no sweep and no escapeerpc/network_executor.go: the hedgekeepaccepts it, so sibling legs are cancelledA block at or below the head that a primary misses still sweeps and escapes as before.
Tests
erpc/networks_failover_hedge_empty_test.go:TestFailover_EmptyBeyondHeadDoesNotSweepToFallbacksnullfor head+1, with an eth-mainnet-like failsafe (retry 5, hedge maxCount 1)AllTiersRouted(eth-mainnet shape): 0 fallback hits, at most 1 primary hit per requestFallbacksCordonedByPolicy: no fallback escape. The policy'sprobeExcludedmirrors still reach cordoned fallbacks; that predates fix(ws): keep heads and filter subscriptions on primaries while they are up #31 and is unchanged.TestFailover_EmptyAtHeadStillEscapesToFallbacks: primariesnullat the head and fallbacks have the block, so the request still escapes and returns itnew tests pass, and fail without the fix
go test ./erpc/ ./indexer/... ./common/ ./upstream/ ./telemetry/ ./architecture/evm/(running)canary, then internal-erpc: paid
eth_getBlockByNumberon evm:1 drops;erpc_network_hedged_request_total{network="evm:1"}back near ~34 r/sRollout note
#30 (
feat/cll-on-websocket-support) is rebased on #31, so it needs another rebase and rebuild after this lands. Draft services-argocd-deployments#1721 pinscll-ws-tier-subs-11108fd, which has this bug.🤖 Generated with Claude Code