Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Provider (Ankr) returns wrong eth_blockNumber response, causing EventFilter polling errors #4569

Open
mstephen77 opened this issue Feb 1, 2024 · 3 comments
Assignees
Labels
investigate Under investigation and may be a bug. v6 Issues regarding v6

Comments

@mstephen77
Copy link

mstephen77 commented Feb 1, 2024

Ethers Version

6.10.0

Search Terms

polling, network

Describe the Problem

I've set up a listener for events (Logs, Filters, or any other names) on a JsonRpcProvider through public HTTP endpoint.

For some reason (e.g. connectivity issues, node load, etc.) the library doesn't get a response in a timely manner, and that causes the library to send another request before the previous request resolves (or possibly due to multiple setTimeout calls?).
That race condition causes the library to make an EventFilter where filter.fromBlock > filter.toBlock and results in the server returning the following error:

{
  "code": "UNKNOWN_ERROR",
  "error": {
    "code": -32000,
    "message": "invalid block range params"
  },
  "payload": {
    "method": "eth_getLogs",
    "params": [
      {
        "topics": [
          null
        ],
        "fromBlock": "0x123f6dd",
        "toBlock": "0x123f6db"
      }
    ],
    "id": 96,
    "jsonrpc": "2.0"
  },
  "shortMessage": "could not coalesce error"
}

I've a workaround in my code (which is not ideal) like so (subscriber-polling.ts):

  async #poll(blockNumber: number): Promise<void> {
        // The initial block hasn't been determined yet
        if (this.#blockNumber === -2) { return; }

        const filter = copy(this.#filter);
-       filter.fromBlock = this.#blockNumber + 1;
-       filter.toBlock = blockNumber;
+       filter.fromBlock = Math.min(this.#blockNumber + 1, blockNumber);
+       filter.toBlock = Math.max(this.#blockNumber + 1, blockNumber);

        const logs = await this.#provider.getLogs(filter);

        // No logs could just mean the node has not indexed them yet,
        // so we keep a sliding window of 60 blocks to keep scanning
        if (logs.length === 0) {
            if (this.#blockNumber < blockNumber - 60) {
                this.#blockNumber = blockNumber - 60;
            }
            return;
        }

        for (const log of logs) {
            this.#provider.emit(this.#filter, log);

            // Only advance the block number when logs were found to
            // account for networks (like BNB and Polygon) which may
            // sacrifice event consistency for block event speed
-           this.#blockNumber = log.blockNumber;
+           this.#blockNumber = Math.max(this.#blockNumber, log.blockNumber);
        }
    }

Code Snippet

No response

Contract ABI

No response

Errors

No response

Environment

Ethereum (mainnet/ropsten/rinkeby/goerli), node.js (v12 or newer)

Environment (Other)

No response

@mstephen77 mstephen77 added investigate Under investigation and may be a bug. v6 Issues regarding v6 labels Feb 1, 2024
@mstephen77
Copy link
Author

Trying to replicate the problem in a Fiddle, turns out the provider (using Ankr at https://rpc.ankr.com/eth) is returning wrong (or cached?) data which causes these errors.
Fiddle: https://jsfiddle.net/9jv5hrwe/17

In my console it shows:
Request for eth_blockNumber with request id 123
image
Request for eth_blockNumber with request id 126
image

I think it would help to check for condition filter.fromBlock > filter.toBlock
Let me know if there's anything I could do to help

@mstephen77 mstephen77 changed the title Polling race condition Provider (Ankr) returns wrong eth_blockNumber response, causing EventFilter polling errors Feb 2, 2024
@ricmoo
Copy link
Member

ricmoo commented Feb 2, 2024

Thanks! Is this reliably reproducible?

@mstephen77
Copy link
Author

As of my experience, it often fails within less than <25 new blocks on Ankr public HTTP RPC endpoint.
I haven't tested other endpoints so far, and the fix is fairly simple to make sure fromBlock < toBlock (in case we get a cached response from the server).

I opened PR #4573 for this issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate Under investigation and may be a bug. v6 Issues regarding v6
Projects
None yet
Development

No branches or pull requests

2 participants