2

Suppose I sign and send several transactions using the following function:

async function send(web3, account, transaction) {
    const options = {
        to  : transaction._parent._address,
        data: transaction.encodeABI(),
        gas : await transaction.estimateGas({from: account.address})
    };
    const signed  = await web3.eth.accounts.signTransaction(options, account.privateKey);
    const receipt = await web3.eth.sendSignedTransaction(signed.rawTransaction);
    return receipt;
}

As you can see, I leave the nonce configuration to the node.

After signing and sending all transactions, I iterate the receipts in order to determine that all transactions have been added to the blockchain:

for (let i = 0; i < receipts.length; i++) {
    while (receipts[i].blockNumber + 12 > await web3.eth.getBlockNumber()) {
        web3.currentProvider.send({method: "evm_mine"}, () => {}); // if running on ganache
    }
    if (await web3.eth.getTransactionReceipt(receipts[i].transactionHash)) {
        console.log(`transaction ${i} confirmed`);
    }
    else {
        console.log(`transaction ${i} cancelled`);
    }
}

It is crucial to me that the transactions will be added to the blockchain by order of submission.

I know that the nonce ensures this, but I am wondering, in case a transaction ends up in an orphaned/forked block, what happens to all remaining transactions, and how can I still ensure that they will be executed by order?

It would be very easy for me if I knew that all remaining transactions were subsequently removed from the pool, in which case, I could simply resubmit all of them without setting the nonce to any specific value.

Can I count on it, or should I take the "orphaned" transaction and resubmit it with the exact same nonce? And how should I handle the remaining transactions?

Thank you!

  • 1
    Partially similar question here does not refer to my concerns. – goodvibration Dec 25 '19 at 17:43
  • 2
    I think this is an awesome question, because it raises a potential problem that will be rare, possibly grave, hard to reproduce and hard to track when it happens. Thank you. – David Ammouial Dec 26 '19 at 1:08
2

Let's suppose you have signed three transactions with nonces 10, 11 and 12. Also assume that they were mined at blocks A, B and C.

It is possible for a chain reorg to occur at block C, with the new blocks being B', C' and D'. Any transactions occurring in blocks B and C that do not appear in the newer blocks B', C' and D' should not be considered as mined.

In theory transactions 11 and 12 will be again in the pending pool and miners can add them to subsequent blocks.

In practice pending pool size is limited and transaction will be discarded at some point.

If you care about the transactions you should inspect the pending pool and re-send them if they have disappeared.

How much you have to wait for sending again? It depends on the particular operation and network congestion. If you are in a hurry perhaps increasing the gas price will help but you have to sign new transactions, if you are not in a hurry you can try every hour until the network accept them.

|improve this answer|||||
1

There is not a strict one-up requirement for transaction nonces, i.e. you can post a transaction with nonce 42 then another one with nonce 44 and it will be accepted. If there is no transaction 43 on anyone's roadmap this is fine, but I understand you're asking about the outcome if transaction 43 did exist but ended up being invalidated and you didn't notice before transaction 44 was sent.

I think in theory it's your responsibility to check that a transaction is valid before submitting the next one, if the order is important and/or you want an all-or-nothing behaviour.

Another way to make a transaction group, well, transactional, is to have it executed by a smart contract in one single transaction.

This is one reason why transaction finality is such a big issue in consensus protocol discussions. Algorithms such as IBFT that guarantee transaction finality take this load off developers' shoulders.

|improve this answer|||||
  • "Another way to make a transaction group, well, transactional, is to have it executed by a smart contract in one single transaction" - of course, but i would obviously do that if I had the option. I have about 50 thousand transcactions, and it's impossible to fit them all in a single block. I've already grouped them into batches of 100 each (in the contract). But I still have to submit them separately at this point. – goodvibration Dec 26 '19 at 11:19
  • "in theory it's your responsibility to check that a transaction is valid before submitting the next one" - well, that kinda repeats what I've asked rather than answering it. – goodvibration Dec 26 '19 at 11:20
  • 1
    With regards to the first paragraph in your answer - from the research that I've conducted, I believe that most of the facts stated in it are plain wrong. AFAIK, transaction with nonce 44 will not go through until transaction with nonce 43 has. – goodvibration Dec 26 '19 at 11:22
  • Regardless of all of the above - thank you for the effort of course. – goodvibration Dec 26 '19 at 11:22

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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