Skip to content

fix(web3): querying different RPCs returns different head blocks#1702

Open
sanbotto wants to merge 4 commits into
stagingfrom
fix/KEEP-928-fix-web3-query-events
Open

fix(web3): querying different RPCs returns different head blocks#1702
sanbotto wants to merge 4 commits into
stagingfrom
fix/KEEP-928-fix-web3-query-events

Conversation

@sanbotto

@sanbotto sanbotto commented Jul 2, 2026

Copy link
Copy Markdown

Fixes a bug in the "Query Contract Events" web3 step where a resolved (non-user-specified) toBlock was computed once via a standalone eth_blockNumber call and then reused for a later eth_getLogs call. Because the RPC provider's endpoint is a load-balanced pool of backend nodes that do not sync in unison, the two calls could land on different endpoints, and if the log query landed on a slightly slower endpoint than the one that answered the head check, it would reject the range with -32602 block range extends beyond current head.

This was discovered when an unrelated issue caused it to surface during the debugging session (see this PM doc).

The step's reported toBlock output is derived only from that same query's results (the highest block among the returned events, or no forward progress if none) rather than a separate getBlockNumber() call, since a second call could itself land on a different, more-advanced replica and overstate what was actually scanned. An explicit user-provided toBlock is left untouched so a genuine misconfiguration still surfaces as an error. Unit tests cover the retry/failover wiring and the tip-batch query against a mocked contract, verifying the "latest" tag, the max-of-events derivation, and the no-events fallback.

Opening as draft since I wanna test it in a PR env.

@github-actions

github-actions Bot commented Jul 2, 2026

Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

@sanbotto

sanbotto commented Jul 6, 2026

Copy link
Copy Markdown
Author

Just finished running a smoke test. The new code path is functionally correct against our RPC endpoints.

@sanbotto sanbotto marked this pull request as ready for review July 6, 2026 22:45
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

@github-actions

github-actions Bot commented Jul 7, 2026

Copy link
Copy Markdown

PR Environment Deployed

Your PR environment has been deployed!

Environment Details:

Components:

  • Keeperhub Application
  • PostgreSQL Database (isolated instance)
  • LocalStack (SQS emulation)
  • Redis (isolated instance)
  • Schedule Dispatcher (staging image)
  • Block Dispatcher (staging image)
  • Event Tracker (staging image)

The environment will be automatically cleaned up when this PR is closed or merged.

@joelorzet joelorzet left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @sanbotto, nice fix. One question on scope: isTipBatch keys off end === range.toBlock, so only the final batch queries "latest". When the range length leaves a small remainder over the 2000 batch size (for example a fromBlock/blockCount that makes the tip batch tiny), the batch right before it ends within a few blocks of the head, and a lagging replica can still reject it with the same -32602 beyond current head. Retries don't reliably help there for the same reason they don't in the tip case, since the mismatch can persist across replicas.

Would it be worth scoping the "latest" batch to the near-head region rather than the exact last batch, so no fixed batch ever ends within replica-lag distance of the head? Low frequency, but it's the same failure one batch over.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants