Are Wallets Ready For Opt-In Replace-by-Fee?

Jan 25, 2016

A common criticism of Opt-In
Replace-by-Fee (RBF) has
been that we need to give the ecosystem more time to implement detection of
opt-in RBF transactions, arguing that if we don’t users will be put at a
significantly greater risk of being ripped off by malicious double-spends. For
this criticism to be valid, user and merchant wallets must already be able to
detect situations where a transaction may be maliciously double-spent, and warn
their users appropriately. On the other hand, if they can’t do that, then
opt-in RBF doesn’t change the situation anyway: an attacker doesn’t need to use
it anyway to rip people off, and when wallet authors fix that they can
trivially add opt-in RBF detection anyway with one or two lines of code.

For merchants payment providers have responded quickly, with Shapeshift.io and
Coinbase - among others - publicly announcing that they’ve implemented opt-in
RBF detection as part of their zero-conf risk-mitigation strategies.

That leaves user wallets. We tested a selection of the eight most popular
wallets out there, including Blockchain.info, Coinbase, Bitcoin Wallet for
Android, Mycelium, Electrum, and others. What we found was every wallet tested
did a terrible job of protecting users from zero-conf double-spends:

Wallets not only failed to warn users that a double-spend might happen,
the majority even failed to warn their users that a double-spend has
happened.

Half the wallets tested could be double-spent by an attacker with
nearly zero technical sophistication with 100% probability of success.

The other half could be double-spent with about 25% success rates, again by
an attacker with nearly zero technical sophistication.

With the above in mind, deployment of opt-in RBF will have zero effect on
users’ vulnerability to double-spends. Instead we must strongly recommend that
users assume until a transaction is confirmed if the sender chooses to reverse
it they can. And in an ironic counter-example to Betteridge’s law of headlines,
the answer is yes.

Methodology

What do we mean by “protect”? We’ll use a simple scenario where Alice is
selling bitcoins to Bob in a person-to-person trade:

Alice sends bitcoins to Bob with transaction #1.

Bob’s wallet displays the unconfirmed transaction, convincing Bob the
transaction will eventually confirm.

Bob gives Alice the cash.

Alice now sends transaction #2 with a higher fee.

Alice succeeds if transaction #1 shows up on Bob’s wallet software and
transaction #2 is the one that gets mined. She fails if Bob’s wallet software
does not show transaction #1, or at least warns him that it can be easily
double-spent by Alice in a way that he’s likely to see and understand. Alice
also fails if Bob’s wallet software informs him of the double-spend when Alice
sends it, also in a way he’s likely to see and understand.

We assume Alice is not very technically sophisticated, beyond having the
ability to run custom double-spend-capable wallet software that someone else
wrote. Thus we will only look at the simplest way to double-spend: a low-fee transaction
followed by a higher-fee transaction. To that end we will use the author’s
doublespend.py
script from
replace-by-fee-tools in
either the default settings, or with the fee of the first transaction being
changed from the default using the --fee1 option. The script was run on a
full-RBF node using the author’s
replace-by-fee-v0.12.0rc1,
a fork of Bitcoin Core
v0.12.0rc1. Here’s a
typical attempt, this one (successfully) against a Blockchain.info wallet:

Even without a GUI these tools require relatively little technical
sophistication to use - the full-RBF fork preferentially
peers
with other full-RBF nodes automatically, and the doublespend.py script does the
rest. Adding this double-spend functionality to an existing open-source mobile
wallet would only be a day or two of work.

Results

Airbitz

Version 1.8.4 2016011302 was tested. Interestingly, the first double-spend
attempt at 11µBTC/KB did not show up in the UI immediately; a second attempt
using 50µBTC/KB did show up immediately. However, Airbitz also displayed the
first attempt about two minutes after broadcasting the first transaction - well
after the double-spend was broadcast - resulting in the following:

Even after the double-spend confirmed, the double-spent transaction was still
displayed as “pending”:

Bitcoin Wallet For Android

Version 4.46 was tested with a 11µBTC/KB transaction, which displayed immediately:

Yet again, ever after the double-spend was broadcast, and later confirmed, the
UI remained the same; even multiple days later the transaction is still
displayed in the UI.

Blockchain.info

The web interface was tested on 2016-01-22 with a 11µBTC/KB transaction.
Blockchain.info displayed it immediately, with no visible warning that the
transaction was unlikely to confirm in a reasonable amount of time:

After the double-spend was broadcast the UI remained the same; even after the
double-spend confirmed the UI gave no indication that the transaction was
double-spent, unless the user clicked on the transaction to open up the detailed
view:

Coinbase

The web-wallet interface was tested on 2016-01-22 with a 11µBTC/KB transaction.
Coinbase displayed it immediately, with no visible warning that the transaction
was unlikely to confirm in a reasonable amount of time:

As with Blockchain.info, even after the double-spend was broadcast, and later
confirmed, the UI remained the same. Coinbase even notified the email
associated with that account of the transaction after the double-spend was
broadcast:

There seems to be some kind of transaction expiration process, because as of
two days later the transaction had been silently removed from the account’s
list of transactions.

Copay

Version 1.8.2 was tested on Android. Copay doesn’t seem to display transactions
with less than 50µBTC/KB fees, so it took three attempts with 50µBTC/KB
transactions to get a succesful double-spend. While Copay didn’t detect the
double-spends immediately, when the double-spend confirmed it did display a clear
“transaction invalid” “possible double-spend” notification in the UI. However,
when the author re-opened Copay to get a screenshot of that UI while writing
this paragraph, the double-spent transaction was deleted, giving the user no
indication the transaction failed.

Electrum

Version 2.5.4 was tested in the default configuration. While previous versions
displayed 11µBTC/KB transactions prior to confirmation, as of this version it
appears that transactions must pay at least 50µBTC/KB to be displayed
immediately. It took three attempts to get a successful double-spend at
50µBTC/KB, upon which the double-spent transaction was simply removed from the
UI leaving the user no indication that the transaction had failed.

GreenBits

Version 1.63 was tested on Android in the default SPV configuration. GreenBits
doesn’t seem to display transactions with less than 50µBTC/KB fees, so it took
four attempts with 50µBTC/KB transactions (one attempt shown below, and another
two failures on another wallet). Again, even after the double-spend has
confirmed, GreenBits failed to notify the user:

Mycelium

Version 2.6.0 was tested on Android. Mycelium doesn’t seem to display
transactions with less than 50µBTC/KB fees, so it took two attempts to get a
successful double-spend. Mycelium didn’t detect the double-spend immediately,
however after the first confirmation of the double-spend transaction it did
display this unintuitive error message:

Eventually the double-spent transaction was deleted entirely from the
transaction history, leaving no indication that it had ever happened.