Double-spending is no longer a theoretical possibility but a practical reality. Most of the end-user applications used widely today leave their users vulnerable to being defrauded via double-spend attacks.

So what is double-spending and what can be done to protect users? First you need to understand two things:

  • Transactions in Bitcoin are made of inputs and outputs
  • A transaction is valid if its inputs have not been previously spent

A double-spend is a transaction that has successfully invalidated a previously accepted payment transaction. Over the years, several different types of double-spend attacks have been theorized and some even put to practice:

  • Race Attack - Two transactions that spend the same input are in a race against each other. The first to be confirmed is the winner.
  • Finney Attack - An attacker mines a block in secret. This secretly mined block contains a double-spend transaction. The attacker then broadcasts a payment transaction that an unsuspecting merchant accepts. The attacker then broadcasts the mined block.
  • Alternative History Attack - A.k.a "51% Attack"
  • Unconfirmed Transaction Replacement - A.k.a "Replace-by-fee (RBF) Attack"

Race Attack (left) and Finney Attack (right)

Alternative History Attack

This type of double-spend attack involves rewriting blocks to effectively erase a confirmed transaction from history. Once this is done, the inputs used in the original transaction can be double-spent however the attacker sees fit. The more confirmations a transaction has, the more difficult it becomes to change it. This is why it is recommended to wait at least a few confirmations before considering high-value transactions as final.

Note that it is not necessary, but highly unlikely, to be able to achieve a change-of-history double-spend attack without 51% of the network hashrate. But due to the size of the Bitcoin network, this is a very expensive and risky attack to manage successfully. There are many instances of this attack in recent history, but on much smaller networks:

As a network grows it becomes more and more expensive to launch a successful 51% attack. That's not to say that it is impossible or that Bitcoin itself is immune to double-spending. There are historical examples of successful double-spend attacks against Bitcoin. However these attacks take a different approach - they use unconfirmed transaction replacement. There are even historical examples of this happening in the wild:

Unconfirmed Transaction Replacement

Don't have access to 51% of the hash rate? Not to worry. There's another type of double-spend attack that is Much more accessible to the average Bitcoin user: Replace-by-fee (RBF) or Unconfirmed Transaction Replacement.

A transaction that has not yet been included in a block is considered "unconfirmed" - also referred to as a zero-confirmation ("0-conf") transaction. Once confirmed in a block, it is not possible to replace it in the manner described here.

To successfully double-spend by replacing an unconfirmed transaction, you will need to be able to:

  • Build raw transactions that use the replace-by-fee (RBF) feature
  • Broadcast raw transactions reliably
  • Fetch unspent transaction outputs (UTXO) for a given address
  • Get network fee estimate

There's An App For That!

All this can be done for you with the help of a script or, even more conveniently, as an app. To illustrate the point, I created PayNoWay to demonstrate to business owners what a practical double-spend attack can look like.

The app looks and acts like a "normal" mobile wallet application: Scan a QR code generated by a Point-of-Sale app; Send the payment (blue button); Send a double-spend transaction to recover the funds (red button); Wait for one of the transactions to be confirmed. A successful double-spend is not guaranteed, but the success rate is quite high (~90%) on mainnet Bitcoin.

Screenshots from PayNoWay

Almost every person to whom I have demonstrated the double-spend attack was shocked at just how easy it was. This attack is within the capabilities of many cryptocurrency users. Anyone who is accepting transactions as payment for goods or services without waiting for at least one confirmation is vulnerable and should be aware of the risks.

As a proof-of-concept the app also supports Litecoin mainnet, but the success rate is low due to replacement transactions being rejected by almost every relay node. However this does not mean that Litecoin is not susceptible. It would be possible to greatly improve the success rates by connecting directly to mining nodes - which are far less likely to reject any transactions that pay a higher fee.

Wallet Apps vs. Double-Spending

Let's have a look at how some of the most popular mobile and desktop apps perform against double-spending. The following testing criteria were used:

  • RBF Flag - Does the app display a warning to the user if a received transaction is RBF?
  • Double-Spend Alert - Does the app display a warning when a transaction was double-spent?
  • Child-Pays-For-Parent - Does the app allow the user to attempt to boost a received transaction's fee by using CPFP?
  • Correct Balance - Does the app show the correct balance before and after a double-spend?

Child pays for parent means, as the name implies, that spending an unconfirmed transaction will cause miners to consider confirming the parent transaction in order to get the fees from the child transaction included in the same block.

Only wallet applications that allow receiving on-chain Bitcoin payments were tested.

Android Wallet Apps
Name RBF Flag Double-Spend Alert Child-Pays-For-Parent Correct Balance
BLW ? ? ? ?
Bitcoin Wallet ? ? ? ?
Blockstream Green ? ? ? ?
BlueWallet ? ? ? ?
BRD ("Breadwallet") ? ? ? ?
Coinomi x x x
Eclair ? ? ? ?
Mycelium x
Samourai ? ? ? ?
Zap ? ? ? ?
iOS Wallet Apps
Name RBF Flag Double-Spend Alert Child-Pays-For-Parent Correct Balance
Blockstream Green x x x
BlueWallet ? ? ? ?
BRD ("Breadwallet") ? ? ? ?
Coinomi ? ? ? ?
Zap ? ? ? ?
Desktop Wallet Apps
Name RBF Flag Double-Spend Alert Child-Pays-For-Parent Correct Balance
Bitcoin Core ? ? ? ?
Coinomi ? ? ? ?
Electrum x
Wasabi ? ? ? ?
Zap ? ? ? ?
Web Wallets
Name RBF Flag Double-Spend Alert Child-Pays-For-Parent Correct Balance
Trezor x x x
blockchain.com ? ? ? ?

Block Explorers vs. Double-Spending

Some Bitcoin users rely on websites called "Block Explorers" to show them their account (address) balances and transaction details. This is a bad practice, but users will use what is the easiest for them. So it's up to the maintainers and operators of these websites to do their best to educate and protect their users.

The following testing criteria were used:

  • RBF Flag - Does the explorer display a warning to the user if a transaction is RBF?
  • Double-Spend Alert - Does the explorer display a warning when a transaction was double-spent?
  • Both txs visible - Are both the payment and double-spend transactions visible while unconfirmed?
  • Original tx preserved - Does the explorer keep the original payment transaction even after the double-spend transaction was confirmed?
Block Explorers
Name RBF Flag Double-Spend Alert Both txs visible Original tx preserved
bitaps.com
blockchain.info x
blockchair.com x x x x
blockcypher.com x
blockstream.info x x x
btc2.trezor.io x x x x
chain.so x x x x
insight x x x x
smartbit.com.au x x x

Solutions

There is no magical solution to this problem. Nodes and transaction relays can't know if a transaction is actually a malicious double-spend. A transaction might look suspicious because it's consuming the same exact inputs but has changed its outputs. But that doesn't necessarily mean that it is a malicious double-spend. Even worse, there's no guarantee that your wallet app will receive both the payment and double-spend transactions.

All that said, there are solutions!

  • Don't accept unconfirmed RBF transactions
  • Only accept confirmed transactions
  • Accept unconfirmed RBF transactions but monitor the memory pool for double-spends
  • Only accept payments via Lightning Network (LN) - Off-chain transactions that do not require confirmations for the recipient to know that they have been paid.

Which solution is best depends on the context. The best solution for in-person payments (cafes, bars, restaurants, etc) is to use Lightning Network only. On-chain payments have high fees and require more time to be safe. Using LN for this context is great because it reduces fees and is not vulnerable to double-spending.

The purpose of this article is to bring awareness to the community. Please do not double-spend against merchants who are accepting cryptocurrencies as payment. If you see a business accepting Bitcoin payments in a naive way, do try to bring it to their attention but in a responsible way. As a still small community we should do our best to help each other and encourage the businesses that do already accept Bitcoin payments.

I'd love to hear about other solutions to this problem, so please feel free to reach out to me with your ideas or suggestions. See my contact details below.

Additional Resources