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

uncaughtException when instantiating JsonRpcProvider and adding subscription in bad network conditions #3924

Open
deodad opened this issue Mar 23, 2023 · 7 comments
Assignees
Labels
bug Verified to be an issue. fixed/complete This Bug is fixed or Enhancement is complete and published. v6 Issues regarding v6

Comments

@deodad
Copy link

deodad commented Mar 23, 2023

Ethers Version

6.2.0

Search Terms

No response

Describe the Problem

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.

https://replit.com/@deodad/Ethers-Uncaught-Exception?v=1

Code Snippet

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")
  }
})()

Contract ABI

No response

Errors

No response

Environment

node.js (v12 or newer)

Environment (Other)

No response

@deodad deodad added investigate Under investigation and may be a bug. v6 Issues regarding v6 labels Mar 23, 2023
@ricmoo ricmoo added bug Verified to be an issue. on-deck This Enhancement or Bug is currently being worked on. and removed investigate Under investigation and may be a bug. labels Mar 23, 2023
@ricmoo
Copy link
Member

ricmoo commented 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.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.

Make sense?

@ricmoo
Copy link
Member

ricmoo commented Mar 23, 2023

(also, huge thanks for providing a concise example to reproduce against ;))

@ricmoo ricmoo added fixed/complete This Bug is fixed or Enhancement is complete and published. and removed on-deck This Enhancement or Bug is currently being worked on. labels Mar 23, 2023
@ricmoo
Copy link
Member

ricmoo commented 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
Copy link
Author

deodad commented 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
Copy link

Hello,

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.

@ricmoo
Copy link
Member

ricmoo commented 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 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. :)

@antoinedc
Copy link

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Verified to be an issue. fixed/complete This Bug is fixed or Enhancement is complete and published. v6 Issues regarding v6
Projects
None yet
Development

No branches or pull requests

3 participants