1

I have written a simple API server in NodeJS that uses web3 (version 1 beta 27) to interact with a remote Parity node.

The guts of the call is as follows

const invoke = async (req, res) => {
  const { params: { address } } = req
  try {
    const theContract = new web3.eth.Contract(abi, contractAddress, { from: SENDER_ADDRESS })
    const fn = theContract.methods.doTheThing(address)
    const account = web3.eth.accounts.privateKeyToAccount(PRIVATE_KEY)
    const data = fn.encodeABI()
    const nonce = await web3.eth.getTransactionCount(SENDER_ADDRESS, 'pending')
    const payload = {
      nonce,
      data,
      gas,
      from: SENDER_ADDRESS,
      to: contractAddress
    }
    const signedTx = await account.signTransaction(payload, account.privateKey)
    const { rawTransaction } = signedTx
    const response = await web3.eth.sendSignedTransaction(rawTransaction)
    const { transactionHash: tx } = response
    res.json({ tx })
  } catch (err) {
    res.status(500).json({ error: err.message })
  }
}

This works perfectly if I only make one call to the API at a time, and it even works fine if I make a few calls that roughly overlap. (tested it with curl using a number of terminal windows)

But if I use a script to call the API many times simultaniously (which is a reasonable simulation of a real-world condition) most of the calls fail, saying There is another transaction with same nonce in the queue.

One solution that's been recommended to me is to create a personal address within Parity itself rather than creating an address in the form of a public/private key pair on my machine, but that does not seem like a best-practice solution.

The issue is that web3.eth.getTransactionCount(SENDER_ADDRESS, 'pending') is returning the same nonce if the API is invoked too quickly. One thought is that I could simply retry if the caught error includes the There is another transaction with same nonce in the queue. message but that seems fragile to say the least.

What is the correct way to queue up simultaneous requests like this?

2
  • you will have to implemented your own logic to handle the nonce. This is a very common issue. The simplest you can do is get the nonce once from the node and the increment it in memory every time you want to sign and send a new transaction. This is a very naive approach, of course as. You will have to take care of failed transaction e.g. due to network error and make sure you do no create a nonce gap i.e. send transaction with bigger nonce than the current one
    – ppoliani
    Commented Oct 12, 2020 at 8:03
  • Did you find a good solution for this? Commented Oct 1, 2021 at 13:52

1 Answer 1

2

You can use batch request, it allows you to send in a specific order transactions:

http://web3js.readthedocs.io/en/1.0/web3-eth.html?highlight=batch#batchrequest

4
  • batch request does not help as each API call is entirely independent from each other.
    – Dave Sag
    Commented Jan 22, 2018 at 4:56
  • I don't understand. What is the problem? batch lets you queue up whetever call/transaction you want to make. It does not care about what's inside. Commented Jan 22, 2018 at 5:12
  • 1
    The API only calls the function with one address. Thousands of independent external entities can invoke the API. Each call to the API is exclusive of each other so there is nothing to batch.
    – Dave Sag
    Commented Jan 22, 2018 at 6:07
  • Oh, ok, misunderstanding. In my knowledge, there is no way to do that. Blockchain is not something meant to be fast (at least for now) Commented Jan 22, 2018 at 6:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.