Repository navigation
Restore eth_getLogs range reduction after alloy migration - #6729
Open
datanexus-vincent wants to merge 3 commits into
Open
datanexus-vincent wants to merge 3 commits into
datanexus-vincent wants to merge 3 commits into
Conversation
datanexus-vincent
marked this pull request as ready for review
October 8, 2026 16:14
Collaborator
There was a problem hiding this comment.
From what I see in the PR, the TooHeavy path looks good. I'm not sure about the MaybeTooHeavy one. Details are in the inline comments
-EDIT-
Also please follow the commit convention
https://github.com/graphprotocol/graph-node/blob/master/CONTRIBUTING.md#commit-messages-and-pull-requests
https://github.com/graphprotocol/graph-node/blob/master/CLAUDE.md#commit-convention
…tion log_stream shrinks the block range when a provider rejects eth_getLogs as too heavy. It recognised that by substring-matching the rendered error, including "ServerError(-32005)" and "ServerError(-32000)", which are rust-web3's Debug rendering. Since the alloy migration in v0.42.0 those strings never appear, so a provider enforcing a range or result cap got ten identical retries, "Unexpected RPC error", and a block stream restart loop instead of a smaller range. Match the alloy error structurally instead. A known cap message shrinks the range at once, without retrying. Caps are matched by message because most providers report them under a generic code such as -32602. Everything else is retried and surfaced as before, and the polling block stream lowers its own range in response, so an unknown cap still converges.
Some providers answer a cap with an error status and the reason in the body, e.g. Ankr with a 413 and GetBlock with a 403. The HTTP transport turns any non-2xx response into an HttpError carrying the raw body, and a 200 whose error object alloy cannot parse becomes a DeserError, so in both cases the message was invisible to the cap check. Read it out of the body on 400, 403, 413 and 503. Only the message is consulted, never the code, since a code in an error body is as likely a rate limit.
A `;`-separated list of extra eth_getLogs error messages to treat as a block-range or result cap, mirroring GRAPH_RPC_ETH_CALL_ERRORS, so operators can cover providers that are not hardcoded.
datanexus-vincent
force-pushed
the
fix/eth-getlogs-range-reduction
branch
2 times, most recently
from
October 14, 2026 18:24
75504e2 to
6860d56
Compare
This branch has not been deployed
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
log_streamshrinks theeth_getLogsblock range when a provider rejects a request as too heavy. It detected that by substring-matching the rendered error against a list that includedServerError(-32005)andServerError(-32000). Those are rust-web3'sDebugrendering of the error code.Since the alloy migration in v0.42.0 the error is an alloy
RpcError, which renders aserror code -32005: ...orErrorResp(ErrorPayload { code: -32005, .. }). The code fingerprints never match. A provider with a range or result cap belowGRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZEnow gets ten identical retries,Unexpected RPC error, and a block stream restart, and the subgraph never advances. Besu with--rpc-max-logs-rangeis the simplest reproduction.Change
The substring list is replaced by a structural check of the alloy error. A known cap message means the request is over the provider's cap: it is not retried, and
log_streamshrinks the range at once. Everything else is retried and then surfaced, exactly as before, and the polling block stream lowers its own range in response, so a cap under an unlisted message still converges the way it does on master.Caps are matched by message, not code. geth and reth report a cap under -32602 and Alchemy under -32600, which they also use for genuinely malformed requests, so the code alone cannot be trusted. The old list's code-based entries (-32005, -32000) are gone for the same reason: providers also use them for rate limits and transient failures, and shrinking on those sends more requests at a provider that is already refusing them.
Cap messages are also read from HTTP 400, 403, 413 and 503 bodies, and from 200 bodies alloy failed to deserialize. graph-node's HTTP transport turns any non-2xx response into an
HttpErrorcarrying the raw body, so a provider that pairs its cap with an error status was otherwise invisible. Ankr does this with a 413, GetBlock with a 403.Covered, each with its verbatim message in the tests: geth, reth, Besu, Alchemy, Infura, QuickNode, Ankr, zkSync Era, Monad, Dwellir, GetBlock. Other providers can be added without a release through a new
GRAPH_RPC_ETH_GET_LOGS_ERRORSvariable, a;-separated list of message fragments, mirroringGRAPH_RPC_ETH_CALL_ERRORS.Behaviour
The reduction policy itself, dividing the step by ten down to a single block, is untouched.
Testing
Unit tests cover every message fragment in isolation, the verbatim provider messages under their real codes, codes that must not match on their own, cap messages inside HTTP and undeserializable bodies, and statuses whose bodies must not be read.
cargo test -p graph-chain-ethereum,cargo clippy -p graph-chain-ethereum --all-targetsandcargo check -p graph-chain-ethereum --releasepass. The provider messages come from client sources and provider documentation, not from live requests.