You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
uncaughtException when instantiating JsonRpcProvider and adding subscription in bad network conditions #3924
When instantiating a JsonRpcProvider and setting up a listener, an thrown exception is thrown if the rpc url returns a bad status code and there doesn't seem to be any way to catch it.
import { JsonRpcProvider } from "ethers";
import nock from 'nock';
process.on('uncaughtException', (err) => {
console.error("but instead it is caught here, uncaught exception:", err)
process.exit(1);
})
nock.back.setMode('lockdown');
nock('https://eth-goerli.g.alchemy.com').post('/v2/apikey').reply(500);
/*** How do we instantiate a JsonRpcProvider and attach event listeners
*in a way that we avoid any uncaughtExceptions?*/
(async () => {
try {
const provider = new JsonRpcProvider('https://eth-goerli.g.alchemy.com/v2/apikey');
await provider.on('block', console.log)
} catch (e) {
console.log("we want to deal with the error here")
}
})()
I found the problem, which was in the poll loop of the PollingBlockSubscriber; when it crashed it threw and failed to re-schedule the next poll.
You still won't be able to get the error in the try block, since the provider.on is actually successful at installing a listener. It's during the next listener poll that things go awry.
In the next minor bump, I'll add an "error" event and a Type that includes the necessary details, that can be listened to in order to trap event errors.
But I think for your purposes, just "not crashing" is your main concern. :)
You won't get any block events until the network conditions have improved; but once the link is back up, you will get all previous blocks backfilled.
I'd like to reopen this issue, specifically regarding this comment:
You won't get any block events until the network conditions have improved; but once the link is back up, you will get all previous blocks backfilled.
This is not always desirable, and I don't think it's 100% right to assume that if a node is stopped, it wasn't on purpose.
When developing against a mainnet fork, you often have to restart your node, this doesn't mean that you want to get all the mainnet events that happened in between. In fact, most of the time, you don't care about this activity at all, as you just want the state.
My application synchronizes blocks & txs from development chain using ethers, users are often restarting their chain. When they do that on a fork, they end up with all the blocks between the previous & current run, which they don't want.
I thought this was originally an issue with Hardhat, so I opened this issue here: NomicFoundation/hardhat#4358 that has a bit more details on my specific use case and why it can be problematic.
Is there any way to clear this "cache" safely? Or workaround?
I wasn't sure if it was appropriate to reopen this, so let me know if I should open a new issue.
@antoinedc If you don't want the events backfilled, you can use provider.pause(true); provider.resume() which will cause all the block subscriber to reset its internal lastBlock to -2 which will then get set to the latest block number once the provider is back online.
I should add documentation for this use-case though, as it isn't obvious the pause(dropWhilePaused?) method can be used this way. :)
Ah I see, thanks. However, when should I call that? When I stop the node, the provider doesn't seem to emit an 'error' event, so I can't put it in there.
Activity
ricmoo commentedon Mar 23, 2023
I found the problem, which was in the poll loop of the PollingBlockSubscriber; when it crashed it threw and failed to re-schedule the next poll.
You still won't be able to get the error in the try block, since the
provider.onis actually successful at installing a listener. It's during the next listener poll that things go awry.In the next minor bump, I'll add an
"error"event and a Type that includes the necessary details, that can be listened to in order to trap event errors.But I think for your purposes, just "not crashing" is your main concern. :)
You won't get any block events until the network conditions have improved; but once the link is back up, you will get all previous blocks backfilled.
Make sense?
ricmoo commentedon Mar 23, 2023
(also, huge thanks for providing a concise example to reproduce against ;))
Stall block polling bootstrap when the network is down (#3924).
ricmoo commentedon Mar 23, 2023
This should be fixed in v6.2.1. Let me know if you have any feedback. And I'll add the
"error"event in v6.3.Thanks!
deodad commentedon Mar 24, 2023
@ricmoo incredible thank you for turning this around so quickly!
the error emitter sounds great and yes for now not crashing is our main concern :)
antoinedc commentedon Sep 11, 2023
Hello,
I'd like to reopen this issue, specifically regarding this comment:
This is not always desirable, and I don't think it's 100% right to assume that if a node is stopped, it wasn't on purpose.
When developing against a mainnet fork, you often have to restart your node, this doesn't mean that you want to get all the mainnet events that happened in between. In fact, most of the time, you don't care about this activity at all, as you just want the state.
My application synchronizes blocks & txs from development chain using ethers, users are often restarting their chain. When they do that on a fork, they end up with all the blocks between the previous & current run, which they don't want.
I thought this was originally an issue with Hardhat, so I opened this issue here: NomicFoundation/hardhat#4358 that has a bit more details on my specific use case and why it can be problematic.
Is there any way to clear this "cache" safely? Or workaround?
I wasn't sure if it was appropriate to reopen this, so let me know if I should open a new issue.
ricmoo commentedon Sep 11, 2023
@antoinedc If you don't want the events backfilled, you can use
provider.pause(true); provider.resume()which will cause all the block subscriber to reset its internallastBlockto-2which will then get set to the latest block number once the provider is back online.I should add documentation for this use-case though, as it isn't obvious the
pause(dropWhilePaused?)method can be used this way. :)antoinedc commentedon Sep 13, 2023
Ah I see, thanks. However, when should I call that? When I stop the node, the provider doesn't seem to emit an 'error' event, so I can't put it in there.
Stall block polling bootstrap when the network is down (ethers-io#3924).
Stall block polling bootstrap when the network is down (ethers-io#3924).