ethers.js
ethers.js copied to clipboard
Provider (Ankr) returns wrong eth_blockNumber response, causing EventFilter polling errors
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
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
Request for
eth_blockNumber with request id 126
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
Thanks! Is this reliably reproducible?
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.