If you run a Bitcoin Core node or mining pool I want you to enable full-RBF. It’s very easy. Just add this line to your ~/.bitcoin/bitcoin.conf file:

mempoolfullrbf=1

Or if you’re running a “node-in-a-box” solution like Umbrel or Start9, just enable the full-RBF option in the settings. In fact, about 17% of Bitcoin Core v24.x nodes have already enabled full-RBF.

mempoolfullrbf=1 I'm doing my part

If you trust me, you can stop reading here. But you’re a Bitcoiner — don’t trust, verify — so you probably want to know more. So in this article, I’m going to cover what is full-RBF, why it’s good for multiparty protocols like Lightning and coinjoin, why it’s good for miners, and why a small minority of people hate it with a passion.

Contents

  1. What is Transaction Replacement?
    1. What Is Replace-by-Fee?
  2. Multi-Party Transactions and Replace-by-Fee
    1. Full-RBF vs BIP-125 RBF
  3. The Controversy
    1. Why Full-RBF Is Good For Decentralization
    2. Why Full-RBF Is Good For Miners
    3. Why Full-RBF Is Good For Wallet Authors
    4. Why Full-RBF Is Good For Privacy
  4. Full-RBF Peering
  5. Let’s Get This Done
  6. Footnotes

What is Transaction Replacement?

A transaction starts off as just data. Once your wallet signs that data, it tells one or more Bitcoin nodes about your unconfirmed transaction. Those nodes in turn gossip that transaction — that data — to other nodes they’re connected too. Eventually, the transaction data makes its way to miners, who at some point, may choose to include it in a block, turning it into a confirmed transaction.

Since an unconfirmed transaction is just data, it can easily be replaced. That’s very often useful! You might want to increase the fee of the transaction to get it confirmed sooner, add or remove payees, cancel it entirely, update it, etc. Satoshi even shipped Bitcoin Core v0.1.0 with a transaction replacement mechanism based on the nSequence field: if nSequence is higher, replace.

What Is Replace-by-Fee?

Unfortunately, the nSequence based replacement mechanism Satoshi came up with had a major design flaw: it didn’t make economic sense.

You could replace a single transaction over and over again, literally billions of times1. Transaction replacements use up network bandwidth, so obviously there had to be a limit. A replacement could also pay a lower fee than the replaced, which doesn’t make sense for miners: why should they mine the lower fee transaction?

Replace-by-fee fixed this by simply replacing one transaction with another, if the replacement paid a higher fee (plus some minimum amount, to pay for the network bandwidth used). This solves the network bandwidth problem, as you have to pay for the bandwidth you use. And it makes economic sense for miners, as they only replace a transaction when the replacement earns them more money.

Wallets use replace-by-fee for a variety of purposes:

  1. Fee bumping: by replacing a low-fee transaction with a higher-fee transaction, your transaction will be mined faster. Lots of wallets support fee bumping.

  2. Cancellation: an unconfirmed transaction can be cancelled by replacing it with a transaction that sends all the funds back to you. Electrum, BlueWallet, and Nunchuk all support cancellation, among others. Exchanges often use cancellation as well, to recover funds when customers call claiming they were hacked2.

  3. Cheaply paying multiple people: some entities like exchanges that make many transactions, pay multiple people with the same transaction, by adding outputs to existing unconfirmed transactions. This can save money because it uses less block space.

  4. Updating transactions: OpenTimestamps, as an example, uses replace-by-fee to update timestamp transactions with new timestamps as they come in. This gets timestamps created faster and cheaper.

Multi-Party Transactions and Replace-by-Fee

In protocols like coinjoin and multi-party Lightning channels, transactions are created with different inputs controlled by different parties. Wasabi coinjoins can even have literally hundreds of different people collaboratively creating a single transaction with hundreds of inputs and outputs.

Because an unconfirmed transaction is just data floating around a P2P network, those parties can double-spend their inputs by creating transactions that spend their inputs in different ways. This often happens unintentionally when, eg, people use the same coinjoin wallet seed on different computers at the same time. Attackers can intentionally double-spend their inputs too.

Replace-by-fee helps multiparty protocols by ensuring that the highest fee transaction — the one that will get mined the fastest — is the one that miners include in a block first. Accepting the transaction that will get mined first ensures attackers can’t gum up protocols like coinjoins by double-spending their inputs with low fees. For implementation reasons, this protection isn’t perfect, as I’ve discussed in more detail before. But it does make it much more expensive to conduct those attacks.

Full-RBF vs BIP-125 RBF

Unfortunately there’s a catch: BIP-125 allows replace-by-fee to be disabled, by setting a special nSequence value in a transaction. This causes problems with multiparty transactions, because either by accident — or intentionally by an attacker — a low-fee transaction with RBF disabled can be broadcast. If the transaction gets to a significant amount of hashing power, that will put the protocol in limbo until the low fee transaction gets mined. Full-RBF fixes this problem by removing the nSequence opt-out, ensuring it is always possible to replace a transaction. So the intended transaction will replace the low-fee one, and the multiparty protocol will make forward progress.

The whole reason why Bitcoin Core added the mempoolfullrbf option in v24 is because people recognized this is a problem, and decided to fix it. At least that was the plan…

The Controversy

You’re probably asking, why does BIP-125 allow full-RBF to be disabled? The reason is ultimately politics:

If Transactions Can't be Replaced, They Can't Be Double-Spent

As a Bitcoin user, you’ve been told over and over again that unless a transaction is confirmed, you might not get your money. You’ve probably also noticed that exchanges, merchants, etc. all require you to either pay with Lightning — or wait for a confirmation — before your money is considered good. This is because any ordinary wallet simply has no way of knowing if a particular unconfirmed transaction will actually get mined: an unconfirmed transaction is just data floating around a P2P network, and without extraordinary efforts like Sybil attacking the P2P network, there’s no way of knowing if miners even have that data.

These days wallets rarely even bother to tell you if an unconfirmed transaction has disabled RBF or not. There’s no reason to clutter up the UI with that useless information; unconfirmed is unconfirmed.

But there’s always been a very small number of centralized paid services claiming to take those extraordinary efforts to make unconfirmed, confirmed. Back in 2015 when BIP-125 was written, pressure from those entities lead to the compromise where Bitcoin Core added RBF, with a switch allowing it to be disabled.

Over the years those paid services have almost entirely died off, in part because Lightning makes secure instant transactions possible. But mainly because despite their extraordinary measures, they kept getting exploited. For example, a few years ago a Canadian Bitcoin ATM operator that accepted unconfirmed transactions lost $195,000 to double spends; I’ve personally been contacted by other ATM operators who told me they lost tens of thousands to double-spends of unconfirmed transactions. Needless to say, they’ve given up on that nonsense, and pretty much all Bitcoin ATM’s these days either accept Lightning. Or they give you a claim slip, and make you wait for a confirmation before giving you any cash.

The continuing fights over full-RBF are a ridiculous situation. At this point just four different entities spoke up against full-RBF when the mempoolfullrbf option was added: Muun Wallet, Bitrefill, GAP600, and Synonym. Of those four, Synonym doesn’t actually have a product: they just intend to offer “risk management” services in the future. Muun Wallet has openly admitted that their wallet’s acceptance of unconfirmed transactions is not good, and they’re fixing it ASAP. Bitrefill and Synonym3 are against all RBF, which certainly isn’t going to go away.

Why Full-RBF Is Good For Decentralization

That leaves GAP600, which is also known for their involvement with Craig Wright’s BSV scam; hatred of full-RBF is pretty common among the BCH/BSV crowd, so I’m not surprised to see them hating it too. What’s interesting, is they claim to be processing something like 10% of the entire Bitcoin transaction volume.

Given their involvement with the BSV scam, I’m not inclined to believe that figure is true (they’ve refused to provide supporting evidence for it, and continue to falsely imply that Shapeshift uses their service). But lets suppose it is, or at least, is somewhat true. This is not good for Bitcoin! GAP600 is a paid KYC/AML’d service that you can’t use without providing your identity; a single scam-affiliated entity learning KYC/AML information on 10% of all Bitcoin transactions is terrible for privacy. For all we know they’re selling Chainalysis ownership data on every transaction they process.

It’s not realistic for you or I to accept unconfirmed transactions. There’s simply no way for a regular self-sovereign wallet to reliably know if miners are mining a double-spend. Services like GAP600 claim to do this with some success using extraordinary efforts such as Sybil attacking the P2P network by connecting to all nodes simultaneously to learn how far transactions have propagated, partnering with miners directly, hiring full-time staff to monitor the network, etc. Indeed, if everyone did what services like GAP600 did, the P2P network would simply collapse due to all the connection slots being used up.

We don’t want a Bitcoin where centralized services always have a significant advantage over everyday merchants using fully self-sovereign solutions. Full-RBF gives everyone on a level playing field.

Why Full-RBF Is Good For Miners

Obviously, full-RBF is the profit-maximizing choice, at least in theory: you’re simply mining the transaction that pays the higher fee, rather than the one you saw first. Due to the relatively low number of full-RBF replacements out there, that difference isn’t too significant compared to the block reward.

But by mining full-RBF, you make Bitcoin in general a better place. And I think there’s a good argument that a better Bitcoin is better for miners too. Multiparty protocols in particular get a lot of usage: coinjoins are becoming a significant percentage of total block usage, and while growth of on-chain transactions is (obviously) stagnant, Lightning transactions are growing enormously; blocksize increases aren’t happening. So miners benefit when a single transaction — such as a Lightning channel open or close — can pay high fees because that one on-chain transaction is getting used by dozens, or even hundreds, of Lightning transactions. A tiny minority clinging to the idea of paying for coffee with unconfirmed transactions isn’t going to drive future fee revenue.

Full-RBF reduces legal risks for all miners. We want to clearly set the standard that miners can mine what they want, and aren’t responsible for protecting users from unconfirmed double-spends. The “first-seen” rule isn’t something that decentralized miners can reliably uphold: among many other things, every change you make to transaction acceptance can be used to double-spend. You certainly can’t expect a network of decentralized miners to all run the same version in lockstep.

Finally, full-RBF removes incentives to attack miners, and the network as a whole. One of the many ways you can double-spend unconfirmed transactions is by attacking transaction propagation. Even if an attacker can’t hack your mining nodes, they can profit by slowing down propagation enough to pull off a double-spend. We don’t want that to be profitable; running full-RBF negates the entire reason to do that kind of attack.

Why Full-RBF Is Good For Wallet Authors

It’s notable how many wallet authors have come out in support of full-RBF, including Coinkite, Green, Electrum, Wasabi, etc. In addition to the benefits to multiparty transactions, having full-RBF makes life a lot easier for single party wallets too. The weird distinction between replaceable and “non-replaceable” transaction adds complexity to UI’s, and causes significant headaches when users get their transactions stuck during mempool congestion. Full-RBF eliminates this by removing the need for the distinction entirely.

For coinjoin wallets in particular, the wide adoption of full-RBF solves a legal problem for their users: if you pay a merchant directly with a coinjoin, you can not guarantee that the payment will actually go through. Your counterparty can double spend their input, potentially causing the coinjoin payment to fail. If you’ve paid one of the rare merchants that are accepting unconfirmed payments, you’ve potentially just committed a theft without intending to do so. Coinjoin wallets are in a much better situation if no merchant accepts unconfirmed payments, turning a potential theft into the minor nuisance of having to try the payment again, making it safe to pay directly with coinjoins. Fortunately, in practice this is rarely an issue because acceptance of unconfirmed payments is so uncommon!

Why Full-RBF Is Good For Privacy

The distinction BIP-125 created between replaceable and “non-replaceable” transactions is yet another bit of data that Chainanalysis companies use to deanonymize transactions. It’s easy to understand why: if you send your coins with replaceability enabled, to a wallet that has replaceability disabled, it’s one more way that Chainanalysis can use to figure out which output is change and which output is the money transfer.

With full-RBF, wallets can create transactions that are a bit more uniform, with a better anonymity set.

Full-RBF Peering

If you turn on full-RBF with the mempoolfullrbf=1 option, your mempool will accept full-RBF replacements. But you won’t necessarily have any full-RBF peers, at least at first. If you just want to “do your part”, that’s fine: as more people enable full-RBF, the probability of you having at least one full-RBF peer increases pretty quickly, especially if you accept incoming connections.

But if you want to ensure you have a full-RBF peer, you can manually add some with the addnode option. I maintain a list that you’re free to use:

addnode=full-rbf1.btc.petertodd.net
addnode=full-rbf2.btc.petertodd.net
addnode=full-rbf3.btc.petertodd.net
addnode=full-rbf4.btc.petertodd.net

You can also run a full-RBF peering node instead. I maintain a full-RBF peering fork of Bitcoin Core v25.0 that advertises a full-RBF service bit, and ensures that it’s connected to at least 4 other full-RBF peers. I don’t maintain any binaries yet. But you can get it with:

git clone -b full-rbf-v25.0 https://github.com/petertodd/bitcoin.git

…and compile as usual.

Let’s Get This Done

This stupid debate has been going on for almost 10 years. Let’s get this over with and move on to payment protocols that actually work.

Footnotes

  1. About 4 billion times: nSequence is a 32-bit unsigned integer. 

  2. Unfortunately as hacks are a sensitive topic, I couldn’t get any exchanges to be willing to go on the record stating this publicly. But I’ve personally worked on exchange codebases that had this feature, and have spoken to multiple exchanges about this use-case. 

  3. Synonym CEO John Carvalho has even been asking wallets to stop enabling transaction replacement by default for years