Cancel pending transactions on Ethereum

Oct 9, 2017 00:23 · 695 words · 4 minutes read ethereum pending transaction geth

Transactions model

Ethereum transactions model is vastly different from Bitcoin. Instead of using UTXO (unspent transaction outputs) transaction uniqueness and order are achieved using transaction nonce. It is an integer (uint256) counter which is incremented for each transaction of an account. Its value is effectively the number of transactions sent from a given address and its value must be included in every transaction.

There are two rules:

  • transactions must be processed in order (transaction with a nonce of 1 must be processed before the transaction with a nonce of 2)
  • no skipping (transaction with a nonce of 4 cannot be included in a block until transactions with nonces of 1, 2, 3 are processed)

This way the network is able to identify duplicates of transactions and enforce their order (which is essential for smart contracts).

Gas price and transaction fees

Each transaction must set gas price which directly affects transaction fees. Miners optimize their profits by including transactions with a high gas price first.

If gas price is low the transaction will wait for a long time until it is mined. Eventually, it will be mined (sometimes many hours later) or dropped (miners have limited resources to queue pending transactions). However, even if the transaction is dropped by miners it may still await in pendingTransaction list of your client and artificially increase your nonce.

You can explore the list of pending transactions on Etherscan.

Blocked account

When a transaction is waiting for being mined all subsequent transactions are blocked. They cannot be included in a block until the previous one is included (it is determined by mentioned nonce value). Even if subsequent transactions have a very high gas price they cannot be processed as it would break the order of transactions and produce different state than expected. This makes the account effectively blocked.

How to cancel pending transaction

A single transaction with a low gas price renders the whole account unusable for many hours. The easiest and often most viable solution is to cancel the transaction. But wait, there is no such method in wallets or even API for that!

Fortunately, it is possible. The solution is not obvious but quite logical. A transaction can be overridden with a different transaction that is more attractive to miners.

The solution is to send another transaction with the same nonce and higher gas price. But what kind of transaction can act as a NOP (no operation)?

It turns out that transaction of sending 0 ether to itself (from == to) is a perfect candidate without any side effects. Obviously, the transaction must be signed by the same account as the one that sent the pending transaction.

Let’s start geth console

geth attach

The first step is to identify pending transaction hash. You can list pending transactions using geth specific call:

eth.pendingTransactions

Also, you can locate it in the list of transactions from your account on Etherscan.

Next, we need to unlock the account to sign the transaction.

personal.unlockAccount('<YOUR_ACCOUNT>')
Unlock account <YOUR_ACCOUNT>
Passphrase:
true

When we unlocked the account and identified the pending transaction nonce and previous gasPrice, we can send zero value transaction from and to your account using more reasonable gas price and the same nonce as the pending transaction.

The gas price should be at least 10% higher than previously but I suggest checking ETH Gas Stations for the recommended gas price which varies depending on the network congestion.

gasPrice should be expressed in wei units (smallest Ethereum unit 10e-18).

You can use web3 helpers to convert Ethereum units, for example, web3.toWei(21, 'gwei').

eth.sendTransaction({
    from: '<YOUR_ACCOUNT>',
    to: '<YOUR_ACCOUNT>',
    value: 0,
    gasPrice: <NEW_HIGHER_GAS_PRICE>,
    gasLimit: 24000,
    nonce: '<NONCE_OF_YOUR_PENDING_TRANSACTION>'
});

A long way ahead of GUI wallets

One can very easily block the account by sending a transaction with a low gas price. It may happen even if the price is reasonable but the network is experiencing congestion. Unfortunately, at the time of writing, Ethereum clients (official Wallet, Mist, MetaMask etc.) do not support canceling transactions nor increasing the gas price after transaction broadcast. I hope that such low-level solution will not be needed in the future as it may cause a lot of issues for the beginners.