Note: This was originally published to the Bitcoin Development mailing list; reprinted below with an important correction.

Since Anthony Towns criticized my use of OTS1 to measure full-RBF adoption, I’ve been doing high-fee full-RBF testing to re-confirm my findings. Specifically, that means sending a high fee tx1 with a fee more than sufficient to get mined in the next block. Then 30 seconds later, I send tx2, a double spend with an even higher fee, removing one of tx1’s outputs. Propagation was verified for each full-RBF double-spend by checking debug.log on another very well-connected node.

Results: >31% of hash power, over at least 4 different pools, is mining full-RBF at the moment, assuming Binance Pool is mining full-RBF with half their hashing power (see below for details). This finding confirms my OTS calendar research, which found similar results.

Specifically, in my testing yesterday I successfully did the following full-RBF double-spends:

Antpool: 2ebe68edca320dabdd8b39ebae5f18efaac829055058a2c0f4bc2b37c69cd88c
         dac9895795efa3956cc775b4f48a5d2b01fa0ea0d7a915fa350baa4779d2e0e9
         b7d43485bf8f0f9792ba6889ab2f53fb462aa4997f3995d9d027375993fa7907
         e2cd91093399dcad5ad3fd73627e497c5e808434ecc7aaec13d9d488973f099c
         5bb7e7d6c34dfd2ae65466a2968a0e500ef25d9b70f7f2b299203dffc1a1b10d
         ad7d2f74eab240726604dfd66231f52ac7778567028cf818387dc9395474f63b
         1ddb11bad477e8b5bcdb36dbaa26065ae8e3c37b39b37a2b34780b98274bd076
         f16bb35670b66ab3c8ccbbaf5f06da5f311e9b05a02b23a77a6fec5e8e5951a4
         b6123a7c126b7937a23bf93cce09358bc2c1047a3bd20fad47bf187e453aadc5
         66f3da902d43ab0a2561d0477c7050d057bb0f69ade79015494363ad08ed172d
         17a6995a757e027b2a51b9cc58635b29553ccc6c164555c0ed922074a23bcbfe
Poolin: 68ca9ee95748dc98ba24018ea64c18de31fca552e4753ef012acd0b615cd7384
        477089a1e997a0115b3d4cd1d4ce21eb9dc83c45c14a7f7441e4fc74c3649ba2
EMCDPool: dde0975ad42fd9e03677f64b6c4f7efbe2ec0b6f905206d47893a77ac6336fca
          a0131d4f8cc13d70443cd87f2ee7543e1142640666a88f80d1e0c885c7eb2c12
Binance Pool: fb62691537d92f61dcb8ace979e0947b47dcbc7e9f50e79f77059ba0a669cdb5
              637c58f3c0447ee99808b37e4f9559096c00ceb0d21130a9254558c4d2d7ae63

Anyone running a full-RBF node with debug=mempool can easily verify all these double-spends by examining their debug.log files.

With Antpool, Poolin, and EMCDPool, it is most likely that they’re mining full-RBF with ~100% of their hash power. These pools mined every double-spend available to them, with the exception of some Antpool blocks found very close to when the double-spend was broadcast. Binance Pool did not mine a full-RBF replacement on two occasions, which makes me suspect they’re mining full-RBF with less than 100% of their hash power. During this testing, Binance Pool, AntPool, Poolin, and EMCDPool, also all mined multiple double-spends from my OTS calendars, further confirming my findings.

My OTS research also found examples of KuCoinPool and ULTIMUSPOOL mining full-RBF double spends. They didn’t find any blocks during this testing, so I have no data on them with this testing. Luxor did mine some blocks without mining the double-spends, so at the moment it’s reasonable to assume they have full-RBF fully or partially disabled, or have some kind of full-RBF propagation issue. They have confirmed similar issues to me in the past (eg employees unintentionally disabling it on some nodes during an upgrade), so it’s likely that has happened again. MARA Pool also mined some blocks without mining double-spends, so they too may have full-RBF fully or partially disabled, as I mentioned in my OTS research.2

The tool I used is my doublespend.py script. Note that this script was written years ago, pre-segwit, and I hastily updated it for recent Bitcoin Core/python-bitcoinlib versions. I haven’t checked if all the options like OP_Return outputs and multisig still work, and it doesn’t even take segwit into account when calculating fees. Don’t use it on a wallet with funds you can’t afford to lose; it definitely has bugs in it.

For reference, here is the logs from a successful double-spend attempt:

    $ sleep 15 ; ./doublespend.py --fee1 0.00018 --fee2 0.000224 `/home/user/bitcoin/src/bitcoin-cli getnewaddress` 0.00001
    DEBUG:root:Delta fee: 0.00002296
    DEBUG:root:Adding new input caec040f4435e98de9ae44a385e301312c5a3cddfb33f1bd08e1cf63307f87ce:0 with value 0.00072549 BTC
    DEBUG:root:Delta fee: 0.00003035
    DEBUG:root:Payment tx 01000000000101ce877f3063cfe108bdf133fbdd3c5a2c3101e385a344aee98de935440f04ecca0000000000ffffffff028a0f01000000000016 00149e12f3ef33ba4ccde4b85978e675c9fe59bb24a2e8030000000000001600149049e0f57ec5899c1eed2c5e9aab1c34ff5cec1f02473044022063834a187727c1eceb9b3e6ae9cc d0d369b51af3493fafba1d61ed3b273d48f7022049fbe71ecd600c7345fb6002e04275eb8445031df746eceaa6e6f5f413f67497012102c56d86e3031851822485d1a2f9f0e402f14b 96b64e711d5a2567412d1ea49a8b00000000
    INFO:root:Payment tx size: 0.222 KB, fees: 0.00002035, 0.00009166 BTC/KB
    INFO:root:Sent payment tx: 1c28870a78efd1c4616726ea0ca3f9d67f5591aab415222e2c9ec6184fc0b4f2
    INFO:root:Sleeping for 30 seconds
    DEBUG:root:Delta fee: 0.00004279
    DEBUG:root:Double-spend tx 01000000000101ce877f3063cfe108bdf133fbdd3c5a2c3101e385a344aee98de935440f04ecca0000000000ffffffff01ae0a010000000 0001600149e12f3ef33ba4ccde4b85978e675c9fe59bb24a20247304402201289c26da70e9ec4424fc2ff7194b57384c78c9c986c2efe6771ac6f5fda199702200cefa72560f21cd9a be846078ce13197029562102f7a44b8ec50772a851c1799012102c56d86e3031851822485d1a2f9f0e402f14b96b64e711d5a2567412d1ea49a8b00000000
    INFO:root:Double-spend tx size: 0.191 KB, fees: 0.00004279, 0.00022403 BTC/KB
    INFO:root:Sent double-spend tx: fb62691537d92f61dcb8ace979e0947b47dcbc7e9f50e79f77059ba0a669cdb5

Remember that if you want to replicate this, don’t be surprised if it takes quite a few attempts if you’re sending tx1 with next-block fees. A minority of hash power is mining full-RBF. There’s also a chance that in the ~30s or whatever you wait between tx1 and tx2, a block is found and tx1 gets mined. This chance is actually even higher than the ~5% you’d expect, because miners don’t instantly update their block templates.

So if ~30% of hash power is actively mining full-RBF, you might actually have a ~20% chance per attempt at succeeding at a naive high-fee/higher-fee double-spend. Thus there’s a:

\[(1-20\% )^{10} = 11\%\]

chance that 10 attempts in a row fail. Being that unlucky happens all the time; the Gods of Probability, probably hate you. :)

Finally, research like this is expensive in terms of my time and transaction fees; research via the OTS calendar approach is essentially free. Donations are appreciated as no-one is paying me to do full-RBF work or covering these expenses.

Cheapest/easiest way is via Lightning. Or on-chain: 1FCYd7j4CThTMzts78rh6iQJLBRGPW9fWv.

References