Skip to content

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

Open

Description

@deodad

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

Activity

  1. added
    investigateUnder investigation and may be a bug.
    v6Issues regarding v6
    on Mar 23, 2023
  2. added
    bugVerified to be an issue.
    on-deckThis Enhancement or Bug is currently being worked on.
    and removed
    investigateUnder investigation and may be a bug.
    on Mar 23, 2023
  3. ricmoo commented on Mar 23, 2023

    @ricmoo
    Member

    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?

  4. ricmoo commented on Mar 23, 2023

    @ricmoo
    Member

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

  5. added
    fixed/completeThis Bug is fixed or Enhancement is complete and published.
    and removed
    on-deckThis Enhancement or Bug is currently being worked on.
    on Mar 23, 2023
  6. ricmoo commented on Mar 23, 2023

    @ricmoo
    Member

    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!

  7. deodad commented on Mar 24, 2023

    @deodad
    Author

    @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 :)

  8. antoinedc commented on Sep 11, 2023

    @antoinedc

    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.

  9. ricmoo commented on Sep 11, 2023

    @ricmoo
    Member

    @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. :)

  10. antoinedc commented on Sep 13, 2023

    @antoinedc

    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

Metadata

Metadata

Assignees

Labels

bugVerified to be an issue.fixed/completeThis Bug is fixed or Enhancement is complete and published.v6Issues regarding v6

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions