ethers.js: Contract methods are slow

Summary

Contract methods that send transactions are approx 5x slower than they could be. The reason seems to be poll function used in sendTransaction method of JsonRpcProvider, with a hardcoded interval.

This is a crucial factor of the speed of test execution, written in ethers.js.

Important notes

  • I am using JsonRpcProvider
  • I am connecting to devnet (geth modified by 0x team for testing purposes)
  • Full code to reproduce example is available here.

Steps to reproduce

I prepared a simple test comparing the speed of test execution of truffle vs ethers, here is a snippet:

  ...
  it("truffle", async () => {
    ...

    console.time("    truffle send");
    await metaCoinInstance.sendCoin(
      safeMathInstance.address,
      accountTwo,
      amount,
      { from: accountOne }
    );
    console.timeEnd("    truffle send");

    console.time("    truffle call");
    await metaCoinInstance.balances(accountTwo);
    console.timeEnd("    truffle call");
  });


  it('ethers', async () => {
    ...
    console.time("    ethers send");
    await coinContract.sendCoin(mathContract.address, accountTwo, amount);
    console.timeEnd("    ethers send");

    console.time("    ethers call");
    (await coinContract.balances(accountTwo));
    console.timeEnd("    ethers call");
  });

Common results are sth like this:

  Contract: MetaCoin with truffle
    truffle send: 50.286ms
    truffle call: 40.342ms
    ✓ should send coin correctly (104ms)

  MetaCoin with ethers.js
    ethers send: 138.884ms
    ethers call: 13.162ms
    ✓ ethers (406ms)

Results vary a lot from run to run, but the general pattern is:

  • Calls 1.5-3x faster for ethers.js
  • Sends are 3-5x slower for ethers.js

Potential cause

My guess is the reason poll methods used in JsonRpcProvider here.

It seems to use options.onceBlock, that does not work well for subsecond block intervals here.

Proposed solution

Add option for faster polling for tests.

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 4
  • Comments: 15 (8 by maintainers)

Commits related to this issue

Most upvoted comments

I’ve moved it to “on deck”. I have some “pays the rent” work to get done first, but this is on the “short term” stack of things to do for ethers. 😃

This is now published in 4.0.26. Let me know if there are any problems!

Thanks! 😃

I’ve put a new version up (not published to NPM, but available on the GitHub master branch) which should hopefully fix this. Can someone try it out and let me know if it helps?

Hmmm. I have noticed that onceBlock can be slow on certain nodes, because while eth_sendTransacrion returns a hash immediately, eth_getTransactionByHash does not return the transaction immediately when then queried. I have be planning to add a wuickCheck option that will re-poll the first time quickly (e.g. 100ms) after the first failure. Let me experiment, and possibly send you some code to hack in to see if that resolves the slowness. 😃

I’ve already posted an answer in #424 that the fix works. Thanks again @ricmoo

@ricmoo Going to test next week, but if you ever want some benchmark tests, we have about 600 unit tests using Ethers and ganache here: https://github.com/horizon-games/multi-token-standard

Just need to git clone, yarn install && yarn build && yarn ganache and in another terminal yarn test

Takes about 40-50 minutes on my machine right now to run all the tests.

Going to add my vote on this issue 😃!

Oh, sorry. I didn’t have a chance today, it took a lot longer than I expected to get #405 done… I plan to dig into the Provider issues early next week.

This is only an issue, like you said, for testing, or on PoA networks in general.

There are a few solutions; you can use the sendUncheckedTransaction method (see this issue for details https://github.com/ethers-io/ethers.js/issues/340#issuecomment-447512944 on how to extend a Signer to use it)

Or you can decrease the polling interval: provider.pollingInterval = 500. Keep in mind not to do that to Etherscan or INFURA though, or you will get soft-banned pretty quick. 😃