Web3.js: transaction confirmation workflow issue with Ganache

Created on 12 Jul 2019  路  1Comment  路  Source: ChainSafe/web3.js

Description

web3-1.0.0-beta.55 (also tested beta.52) subscribes to newHeads _after_ sending the transaction, which means web3 may miss emitted newHeads notifications. While it is unlikely for this race condition to be a problem on mainnet, or even test nets, it is pretty much guaranteed to be a problem when testing against Ganache.

Expected behavior

When a sent transaction is mined via await web3.eth.sendTransaction, web3 should request the transaction's receipt and resolve the promise.

Actual behavior

I suspect what happens is:

  1. web3 sends the transaction to Ganache
  2. Ganache receives the transaction and returns the transactionHash
  3. web3 receives the transactionHash then sends a newHeads subscription to Ganache
  4. Ganache mines the transaction and emits a newHeads notification

    • note: web3 _isn't_ subscribed yet

  5. Ganache receives the newHeads subscription.
  6. web3 waits for forever.

Previous versions (like beta.37 don't have this issue)

Steps to reproduce the behavior

Full reproduction:

Run:

mkdir test
cd ./test
npm init -y
npm install [email protected] [email protected] -E

Save this code as test.js:

const Ganache = require("ganache-core");
const Web3 = require("web3");

const server = Ganache.server();
server.listen(8545, async () => {
  const provider = new Web3.providers.WebsocketProvider("ws://localhost:8545");
  const options = { transactionConfirmationBlocks: 1 };
  const web3 = new Web3(provider, null, options);
  const accounts = await web3.eth.getAccounts();
  const transactionReceipt = await web3.eth.sendTransaction({ from: accounts[0], to: accounts[1], value: 1 });
  // never gets here.
  console.log(transactionReceipt);

  // shut down the Ganache server
  server.close();
});

Run:

node test.js

The application hangs.

A clumsy workaround (passer-bys: do NOT use this in your testing code!):

const Ganache = require("ganache-core");
const Web3 = require("web3");

const server = Ganache.server();
server.listen(8545, async () => {
  const provider = new Web3.providers.WebsocketProvider("ws://localhost:8545");
  const options = { transactionConfirmationBlocks: 1 };
  const web3 = new Web3(provider, null, options);
  const accounts = await web3.eth.getAccounts();
  const transactionReceiptPromise = web3.eth.sendTransaction({ from: accounts[0], to: accounts[1], value: 1 });

  // web3 newHeads race-condition workaround:
  await new Promise(resolve => setTimeout(resolve, 500)); // 500 is arbitrary
  await web3.currentProvider.send("evm_mine"); // force another block to be mined

  const transactionReceipt = await transactionReceiptPromise;
  // This works now!
  console.log(transactionReceipt);

  // shut down the Ganache server
  server.close();
});

Versions

2.x bug

Most helpful comment

Deactivating of automine is currently the workaround for it:
Bildschirmfoto 2019-07-12 um 17 07 53

I will add an additional check before the newHeads subscription gets started for being compatible with Ganache.

>All comments

Deactivating of automine is currently the workaround for it:
Bildschirmfoto 2019-07-12 um 17 07 53

I will add an additional check before the newHeads subscription gets started for being compatible with Ganache.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

sundbry picture sundbry  路  3Comments

webersson picture webersson  路  3Comments

FradSer picture FradSer  路  3Comments

dhl picture dhl  路  3Comments

TinyWJL picture TinyWJL  路  3Comments