RBF Transaction Double Spend Analysis

Blockchain Analysis Jan 21, 2021

With an average transaction fee of $11, Bitcoin is far from cheap to send. The extensive fees that must be paid all but obsolete Lightning Network as a viable alternative (since one must pay a fee to 'enter' into the network and yet another fee if they wish to close the channel that they've created; not to mention, they must relinquish custody of their coins to a 3rd-party service provider if they're not running their own full nodes...plus give up the trustless transactional nature of Bitcoin).

Due to these exorbitant fees, many are enticed to send transactions at a rate that is lower than the average, which means that they'll be looking at one more than one block for their transaction to confirm.

While this may be understood by most users, the dangers of accepting zero-conf transactions does not appear to be. Unfortunately, the ones that have failed to understand this the most are wallet developers (both software & hardware).

This has led to an epidemic of 'RBF' double-spend transactions + unruly levels of transaction spam clogging up the networks around the clock.

The total number of 'doublespend' transactions that you see in the screenshot above (572) reflect the total number of double spend attempts that the site's full node was able to detect in its memory pool.

for reference, the site is: https://bitaps.com/

The site that provides this information has been around for some time and they also provide transaction IDs for the specific UTXOs that someone is attempting to double spend from as well as the transaction ID of the fraudulent attempted double spend and the TX ID of the spend that's likely to be accepted into the chain as the 'official' transaction.

Taking a Look at One of These Transaction Double Spend Attempts

More than likely, you're curious as hell about these doublespend attempts on the chain (especially since they're so prevalent these days).

Fair enough - so are we. So let's check one out.

Base Transaction

The 'base transaction' (from which the spends are being made) is = 8412d27851100020d5a703aefa16179696796039c228630ed825562d6ce731ea

Below is the real investigation that we need to do on one of these supposed double spend transactions

Let's start by breaking this whole thing down, piece by piece.

Here is the parent transaction:

Now let's take a look at the first set of transactions that follow in this chain (yes, this is a chain and its going to get slightly confusing whether you understand Bitcoin very well or not)

Here's the first transaction:

This transaction is unconfirmed at the time of writing. The total amount to be spent is 0.00101000 Bitcoins. This amount isn't going to change at all.

  • The sending address = 1ESZHXJKJSFbs9CHqHQU21LRUprbA9Yi9m
  • And the miner fee = 0.00000567

That's not going to change either.

What will change is the miner fee as well as the recipient address (the output)

The recipient address in this transaction was: bc1qfxlf7tu77gg9v4d26fmkc9hut73z355lz3yh5m

Taking a Look at the Second Transaction

Here's the second transaction:

With this transaction, it should be immediately noticeable that there are two distinct changes, which are in the:

  1. Recipient address (output)
  2. Miner's fee

This time, the recipient address = 12U9Yh7zNVchJpbs8nBFAbY7bhNq5WMyor

And the miner fee = 0.00001728

Differences Between the First Transaction to the Second

The miner fee for the second transaction is three times as high as the first one.

  • The first fee = 0.00000567
  • The second fee = 0.00001728

Thus, the second transaction would be significantly more likely to complete than the other.

With that in mind the next step would be to move to the next portion of this transaction.

Next Portion?

Yes. This is a chained RBF double-spend attempt (elaborate), that  ultimately resolves to a segwit address 'bc1' prefixed address.

Chained Transactions

So before we move forward, its worth taking a little bit of time out to explain how chained transactions work on the blockchain (Bitcoin, specifically).

If you're not familiar with at least the basic structure of how Bitcoin works, then this will seem like mumbo jumbo to you unfortunately. But if you have some understanding of UTXOs and transactions, then continue to read along so that you can get a better idea of how this works.

Starting With Your Typical Basic Transaction

Let's start off with our typical transaction (see below):

What we see above is pretty basic.

  1. Bob starts off with 50 bitcoins.
  2. He decides that he wants to send .5 bitcoins to Alice.
  3. However, Bitcoin works in a wonky way that mandates that you spend the entire amount in that transaction. So Bob cannot just spend 0.5 bitcoins to Alice and leave the remaining 49.5 in his wallet, he must spend the full 50 bitcoins.
  4. Okay, no problem, Bob sends the other 49.5 to another wallet that he owns. This is considered "change" (no different than what a cashier gives you if you pay for something that costs $15.55 with a $20 bill).

Basic enough right?

Moving forward.

Transaction Conditions

We're going to briefly breakdown how Bob is able to spend those funds.

Basics on Spending Funds From a Bitcoin Wallet

A bitcoin wallet is typically going to start with a private key and a public key.

Obviously, the most important part of this tandem is the private key:

The private key is what enables users to create a public key (this is not the address though! But still important)

From that point, there are some cryptographic operations performed on the 'public key' (not to mention base58 encoding and version byte additions; blah blah) and you eventually get what's known as a Bitcoin address:

What you see above is the most important part.

In order to spend a transaction (p2pkh), Bob will typically need to provide his public key and then sign something with his private key.

Because of the magic of cryptography (we aren't going to get into the nitty gritty details here), we can validate that the signature Bob has given was with a private key that pairs with his public key without having to see his private key.

Thus, Bob can keep his private key secure while the network can validate Bob's transactions without worry.

Typically the workflow from a public key is as follows:

Great, are we up to speed here? Kind of? Alright good.

Back to the Transaction With Bob and Alice

Unfortunately, things are going to get a bit confusing, but hopefully you pick this part up:

In the chart above we can see that Alice is transferring funds back to Bob, correct?

Alice's signature is also on the 'input', so we know that Alice has the right to spend these coins:

The assumption that most make is that Alice's transaction must have been confirmed before Bob's transaction can be created.

However, that is not the case.

If Bob and Alice were in the same room, Alice could technically sign her input going to Bob's wallet, then Bob could attempt to spend that signed transaction from his wallet (all in one transaction chain).

This is actually valid because it doesn't break consensus rules, we just need to make sure that Alice has the requisite bitcoins to make such a transaction, and if she does, then Bob's transaction can be considered valid too.

Here's How This is Being Gamed on the Bitcoin Protocol

There's a small little excerpt in the 'Mastering Bitcoin' book that many may have missed (but its super duper important).

It goes as follows:

"When a chain of transactions is transmitted across the network, they don't always arrive int he same order. Sometimes, the child might arrive before the parent. In that case, the nodes that see a child first can see that it references a parent transaction that is not yet known.
Rather than reject the child, they put it in a temporary pool to await the arrival of its parent and propagate it to every other node. The pool of transactions without parents is known as the orphan transaction pool.
Once the parent arrives, any orphans that reference the UTXO created by the parent are released from the pool, ready to be mined in a block. Transaction chains can be arbitrarily long, with any number of generations transmitted simultaneously. The mechanism of holding orphans in the orphan pool ensures that otherwise valid transactions will not be rejected cause just because their parent has been delayed and that eventually the chain they belong to is reconstructed in the correct order, regardless of the order of arrival."

Thus, the transaction in particular that we're analyzing here is a chained transaction (these types of transactions need to be manually crafted rather than produced with 'garden variety' wallet software).

Let's take another look at that transaction (with additional annotations on it):

In the section above, we just got finished looking at child transaction #1 (as well as determining which one would be more likely be accepted by miners).

Now let's take a look at child transaction #2 (remember that child #2 is actually a child of child #1; so until child #1 is confirmed, child #2 cannot be confirmed // but due to the specifications of the Bitcoin protocol [as described in the 'Mastering Bitcoin' text], neither child transaction attempt will be invalidated out of anyone's mempool. Thus, the presence of either version of child transaction #2 does not inhibit the other).

Brief Recap:

The original (parent transaction) is shown below:

The boxed output in the screenshot above represents the output address: 1ESZHXJKJSFbs9CHqHQU21LRUprbA9Yi9m

From that point, the output spent to that address (1ESZHXJKJSFbs9CHqHQU21LRUprbA9Yi9m) was then referenced in two different transactions in the mempool as part of the chained transaction double spend attempt.

Attempt #1:

Attempt #2:

As noted before, attempt #2 is the one that possesses a greater mining fee than attempt #1. However, bitaps labels the output for both of these transactions as "spent", which is interesting:

Now that we're up to speed, let's move on to child set #2.

Breaking Down Child Set #2

The first transaction in that child set corresponds with the following (in our transaction matrix):

Which corresponds with:

As we can see the 12U9Yh7zNVchJpbs8nBFAbY7bhNq5WMyor address ended up being the input for this transaction.

And the output address = bc1qfxlf7tu77gg9v4d26fmkc9hut73z355lz3yh5m

Its strongly worth noting that the output address of this transaction is a P2WPKH transaction (which means that its a segwit-enabled transaction / encoded using bech32)

Below is the specific script for the address in question:

0 P2WPKH OP_0 OP_PUSHBYTES[20] 49be9f2f9ef2105655aad2776c16fc5fa228d29f

Below is another screenshot of the same transaction with the spent output total and the miner fee highlighted (since these tend to be the two variables of the transaction that do change):

Taking a Look at Child Transaction #2; Attempt Two

As noted, there's more than one attempted child in this chain here.

Below is the annotated transaction matrix showing which transaction in the chain that we're referring to:

Here's what that pending TX looks like:

Again, we can see that 12U9Yh7zNVchJpbs8nBFAbY7bhNq5WMyor is our input for this transaction.

However, our output is an entirely different address from the previous child tx #2 attempt: 16UxpvT6EeCwfSTPuF9WnmwXTUm4kPD7dv

Again, the output spent as well as the 'miner fee' are squared for clarity:

It would be awesome if we could say that our journey is over here, but its far from over at this point.

Tracking Down the Real String of Transactions

As noted earlier, the parent transaction is this one: 8412d27851100020d5a703aefa16179696796039c228630ed825562d6ce731ea

Here are the inputs of that transaction:

And here the outputs:

This is what the transaction looks via a visualizer (EY Blockchain):

The most important fact that we need to take away from this part of the transaction is this detail here:

The block that this transaction was confirmed in 666942.

The next transactions in the chain become a hell of a lot more important for what we have going on (and show perhaps what the true intent of the "double spend" transaction may have been all along).

The next transaction ID = fc66f632fc0babf8de145392fe7d6bcaf91db2acbd6f62f615e626ce3116f5e3 (or is it?)

Prepare to get your mind exploded here:

Yeah, that transaction got invalidated.

It was rbf'd, even though it was sent parallel to the other child #1 transaction that we identified earlier (we assumed that the other transaction was simply the one that was invalidated)

See below:

This is definitely the same  transaction that we were looking at earlier (so which one is the real one?):

Stalking Down the Real TX

Specifically, we now know that the transaction that we originally thought was valid ended up being grossly invalid (rejected) by the protocol.

The real transaction ID reflecting the transfer between the two entities shown above = 7c833551d2f096b2e59e1b15cf341260eb061213b41b41860f3af6729dbf3a76

Let's take a look at that transaction below:

What immediately sticks out is the fact that the total amount being sent to the output address has decreased to some extent, but since there are no more recipients for the transaction, it makes sense to assume that the remainder was a bumped mining fee (which is actually what RBF is for).

However, we never actually saw the RBF'd transaction come through on the blockchain at any point in time... which is a great way that this exercise exemplifies how difficult it is to track down these transactions to their valid root.

If we look even closer at the (valid) transaction traveling from 12U9Yh7zNVchJpbs8nBFAbY7bhNq5WMyor, we'll find the following:

Which is starkly different from the (now invalid) transaction we see here:


There's no way to really tell what the hell is/was going on here without speaking to the person that initiated the transaction chain.

Every single other path that we followed other than the linear path that we just explored above would've had to have been marked invalid on the chain (and indeed it was).

Judging by the above transaction that we dissected, there's a possibility that the 16UxpvT6EeCwfSTPuF9WnmwXTUm4kPD7dv address ended up getting screwed out of a significant amount of Bitcoin since the original transaction had 0.00097544 bitcoins headed to it vs. 0.00043569.

At current prices, that's the difference between $312.22 to $139.46.

So, not exactly a bank heist - but in theory, if 16Uxpv were a counterparty of some sort, it is more than possible that their wallet client could have falsely attributed the first total to their balance vs. the second.

Both the valid transaction as well as its parent can be found within the same block.

Obviously, the invalid transactions would've been seen first, and the invalid version of the valid transaction chain would've been left within the mempool (and not removed) due to the rules that we enumerated from 'Mastering Bitcoin' above about how mempools handle child transactions whose parent has yet to arrive (since the child transaction must occur monotonically, in chronological order in accordance with its parent transaction).


There's a chance that this was the original intent of the sender...whoever they are.

Notably, the transactions have 'version 2' ticked on them, which could indicate that there are some additional characteristics about them that downgraded nodes are unable to see.

Tonal Bitcoin Example

Tonal Bitcoins are a great example of this practice in motion in live time.

They aren't given a 'version 2' flag (normal, valid transactions receive a 'version 1' byte). But rather, they have a different demarcation altogether for Bitcoin (in terms of tabulating the totals), than the other clients do.

Therefore, those transactions are different (not seen by legacy nodes ; nonstandard), but still valid (and they are mined if they do come up on the chain - there's a possibility that they are being mined at this very point).

As time goes on, we'll definitely make the concerted effort to locate more of these transactions on the chain, since this is far from the only type of RBF transaction double-spend attempt that we'll find (and some of them are extremely creative with TX chains that range as long as 20-30+ TXs, which could be a DDoS risk if there are enough inputs in the parent transaction since the entire chain would need to be validated or evaluated by whatever node is receiving it and only one of the attacker's chains will be validated, so they suffer no risk of having to pay all of the fines associated with the multiple different versions of the chain that they could broadcast through the network.

For good measure, here is a 585+ input transaction (which has 50 outputs that its sending to): https://explorer.bitquery.io/bitcoin/tx/24fd83e84309d59e0f68cfc16ab81dfd80a23dde8652333bae4395cea356dbd5

This transaction did actually end up getting confirmed on the blockchain with an exorbitant fee of 0.05042421 BTC , which amounts to approximately $1.6k at Bitcoin's current price at the time of writing (approx. $32k).



Happy to serve and help wherever I'm needed in the blockchain space. #Education #EthicalContent #BringingLibretotheForefront

Great! You've successfully subscribed.
Great! Next, complete checkout for full access.
Welcome back! You've successfully signed in.
Success! Your account is fully activated, you now have access to all content.