chain/ethereum: Restore eth_getLogs block range reduction under alloy - #6723
Open
datanexus-vincent wants to merge 1 commit into
Open
datanexus-vincent wants to merge 1 commit into
datanexus-vincent wants to merge 1 commit into
Conversation
`log_stream` shrinks the block range when a provider rejects an
`eth_getLogs` request as too heavy. It recognized such a rejection by
looking for `ServerError(-32005)` / `ServerError(-32000)` in the error
string, which is rust-web3's `Debug` rendering of `jsonrpc_core::ErrorCode`.
Since the alloy migration in v0.42.0 the adapter returns
`RpcError::ErrorResp(ErrorPayload { code, .. })`, rendered as
`server returned an error response: error code -32005: ...` (`Display`)
or `ErrorResp(ErrorPayload { code: -32005, .. })` (`Debug`). Neither
contains `ServerError(`, so the code-based fingerprints stopped matching
and graph-node retried the same oversized range 10 times, logged
"Unexpected RPC error", and restarted the block stream in a loop. The
`503 Service Unavailable` entry broke the same way: alloy surfaces an
HTTP 503 as `TransportErrorKind::HttpError`, rendered `HTTP error 503
with empty body`.
Replace the string list with `is_too_many_logs_err`, which matches the
error structurally: on `ErrorPayload::code` for -32005/-32000, on HTTP
status for 503, and on message fragments for providers that use a
non-standard code (zkSync Era, Monad). This is the approach
`interpret_eth_call_error` already takes for `eth_call`. It also avoids
a trap the string check had: the two call sites see different renderings
of the same error, since `log_stream` gets it through `TimeoutError`,
which formats with `Debug`, while the retry predicate in
`logs_with_sigs` gets the bare `RpcError`.
The reduction policy (`step / 10`, down to a single block) and the
`GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE` defaults are unchanged.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
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_streamadapts to providers that capeth_getLogsby shrinking the block range when a request is rejected as too heavy. It identified such a rejection with a string fingerprint list:ServerError(-32005)is rust-web3'sDebugrendering ofjsonrpc_core::ErrorCode. The alloy migration in v0.42.0 (#6063, #6317) carried the list over unchanged, but alloy renders the same error differently:Displayserver returned an error response: error code -32005: Requested range exceeds maximum RPC range limitDebugErrorResp(ErrorPayload { code: -32005, message: "...", data: None })Neither contains
ServerError(. The503 Service Unavailableentry broke the same way — alloy surfaces an HTTP 503 asTransportErrorKind::HttpError, renderedHTTP error 503 with empty body.So on v0.42.0 through v0.45.0 only the two message-substring entries (zkSync Era, Monad) still match. A provider that caps a range with
-32005now causes 10 identical retries, anUnexpected RPC errorwarning, and a block-stream restart — in a loop — instead of thestep / 10reduction. This affects Besu (--rpc-max-logs-range,-32005"Requested range exceeds maximum RPC range limit"), the geth/erigon/reth result cap, Infura, and Alchemy, whenever the provider's cap is belowGRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE.Change
Replace the string list with
is_too_many_logs_err, which matches the error structurally:RpcError::ErrorRespwith code-32005(EIP-1474 "limit exceeded") or-32000(geth's catch-all, used by Alchemy for size and timeout errors);TransportErrorKind::HttpErrorwith status 503, for Alchemy shedding load;Try with this block range, Monad'sblock range too large, plus geth'squery returned more thanfor proxies that rewrite the code but keep the message).This follows
interpret_eth_call_errorincall_helper.rs, which already matchesRpcError::ErrorRespon code and message rather than on the formatted string.Both places that used the old check now call the helper: the
.when()retry predicate inlogs_with_sigsand the reduction branch inlog_stream. That matters beyond tidiness — the two see different renderings of the same error (log_streamgets it throughTimeoutError, which formats withDebug; the predicate gets the bareRpcError), so a string-only fix would have had to cover both forms and stay correct across alloy bumps.Matching
-32000on the code alone is broader than a cap error, and is what graph-node did before v0.42.0. The asymmetry justifies it: a missed cap error loops the block stream indefinitely, while a spurious match only shrinks the range for the rest of thatlog_streambatch, which is re-created with a freshstepfor the next one. Shrinking is itself a retry, so a transient-32000still gets further attempts. Happy to require a size/timeout message fragment alongside-32000if you'd rather trade it the other way.The reduction policy (
step / 10, floor at a single block),GRAPH_ETHEREUM_MAX_BLOCK_RANGE_SIZE, and theeth_calldeterministic-error handling are untouched.Tests
Six unit tests in
ethereum_adapter::testscovering the provider errors above, the errors that must not trigger a reduction (-32601method not found,-32603internal error, HTTP 429,NullResp),TimeoutError::Elapsed, and a regression guard asserting that neither alloy rendering contains the old web3 fingerprints.cargo fmt --all -- --checkandcargo clippy --all-targetsare clean.Notes
Invalid block rangefor some rejections. I left it out deliberately — it is ambiguous enough that a genuinely invalid range would be retried down to a single block before erroring.🤖 Co-authored with Claude Code