How Replace-By-Fee (RBF) Works in Bitcoin Core: BIP-125 Implementation and Mempool Policy
TLDR: Bitcoin Core implements Replace-By-Fee (RBF) through BIP-125 opt-in signaling, where transactions signal replaceability via nSequence values ≤ 0xfffffffd, and the mempool enforces strict fee-bumping rules defined in src/policy/rbf.cpp to prevent DoS attacks.
Replace-By-Fee (RBF) is a critical mechanism in the bitcoin/bitcoin repository that allows users to replace unconfirmed transactions with versions paying higher fees. According to the Bitcoin Core source code, the implementation follows BIP-125 "opt-in RBF," requiring explicit signaling from wallets and rigorous validation during mempool acceptance to protect the network from spam.
Signaling Opt-In RBF via nSequence
A transaction is considered RBF-signaled when at least one input contains a sequence number meeting BIP-125 criteria. The utility function SignalsOptInRBF in src/util/rbf.cpp (lines 9-15) performs this detection:
bool SignalsOptInRBF(const CTransaction& tx)
{
for (const CTxIn& txin : tx.vin) {
if (txin.nSequence <= MAX_BIP125_RBF_SEQUENCE) {
return true;
}
}
return false;
}
Here, MAX_BIP125_RBF_SEQUENCE equals 0xfffffffd. Any input with nSequence less than or equal to this value indicates the transaction may be replaced.
However, replaceability also depends on ancestors. The IsRBFOptIn function in src/policy/rbf.cpp (lines 24-49) checks both the transaction itself and any unconfirmed parents:
RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
{
if (SignalsOptInRBF(tx)) return REPLACEABLE_BIP125;
// Check unconfirmed ancestors for RBF signaling...
}
If any unconfirmed parent signals RBF, the child transaction is also treated as replaceable, allowing chains of unconfirmed transactions to be updated together.
Wallet Configuration and Transaction Creation
Bitcoin Core wallets control RBF behavior through the -walletrbf startup flag, parsed in src/wallet/init.cpp (lines 77-78). This sets the m_signal_rbf member in CWallet (defined in src/wallet/wallet.cpp around line 3064).
When constructing transactions, the wallet determines sequence numbers in src/wallet/spend.cpp (lines 1283-1289):
const uint32_t default_sequence{
coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf)
? MAX_BIP125_RBF_SEQUENCE : CTxIn::MAX_SEQUENCE_NONFINAL};
This logic checks both per-transaction overrides (m_signal_bip125_rbf) and the wallet default. If either is true, inputs use MAX_BIP125_RBF_SEQUENCE, making the transaction replaceable.
For GUI users, the "opt-in RBF" checkbox in src/qt/sendcoinsdialog.cpp (lines 183-187 and 840) propagates this setting to the coin control object, ultimately flowing into the transaction builder logic above.
Mempool Validation Rules
When a replacement transaction arrives, the mempool enforces several anti-DoS rules implemented in src/policy/rbf.cpp:
Fee Monotonicity (Rule #3)
The replacement must pay a higher absolute fee than the original(s). The code at lines 1009-1012 validates:
if (replacement_fees < original_fees) {
return state.Invalid(...);
}
Bandwidth Cost Coverage (Rule #4)
The additional fee must cover the relay cost for the replacement's virtual size (lines 1017-1022):
if (additional_fees < relay_fee.GetFee(replacement_vsize)) {
return state.Invalid(...);
}
This ensures the network is compensated for re-broadcasting the transaction data.
Cluster Limits (Rule #5)
To prevent excessive mempool churn, the implementation limits conflicting clusters. GetEntriesForConflicts (lines 63-71 in src/policy/rbf.cpp) enforces MAX_REPLACEMENT_CANDIDATES, ensuring no more than 100 transactions are evicted per replacement.
Package RBF Support
Bitcoin Core extends RBF to package replacements, allowing parent-child transaction groups to be replaced atomically. The PackageRBFChecks function in src/validation.cpp (lines 673-1082) reuses the standard fee rules but validates them across the entire package. This enables "child-pays-for-parent" scenarios where a child's additional fee can sponsor the parent's replacement.
RPC and User Interface
Several RPC methods expose RBF functionality:
bumpfee(src/wallet/rpc/bumpfee.cpp): Constructs a replacement transaction usingMAX_BIP125_RBF_SEQUENCEand verifies the original is replaceable viaIsRBFOptIn.getmempoolentry(src/rpc/mempool.cpp, lines 558-563): Returns anrbfboolean indicating replaceability status.createrawtransaction: Accepts areplaceableparameter that sets appropriatenSequencevalues.
Command-Line Examples
Create a replaceable raw transaction:
bitcoin-cli createrawtransaction \
'[{"txid":"<parent_txid>","vout":0}]' \
'{"<dest_address>":0.001}' \
0 \
'{"replaceable":true}'
Bump an existing transaction's fee:
bitcoin-cli bumpfee <txid>
Check replaceability status:
bitcoin-cli getmempoolentry <txid>
# Returns: "rbf": true
Summary
- Opt-in signaling requires
nSequence ≤ 0xfffffffd, detected bySignalsOptInRBFinsrc/util/rbf.cpp. - Wallet defaults are controlled by
-walletrbfand stored inm_signal_rbf, applied during transaction construction insrc/wallet/spend.cpp. - Mempool rules enforce fee monotonicity, bandwidth cost coverage, and cluster limits through
src/policy/rbf.cpp. - Package RBF allows atomic replacement of transaction groups via
PackageRBFChecksinsrc/validation.cpp. - RPC exposure includes
bumpfee,getmempoolentry, and raw transaction utilities.
Frequently Asked Questions
What is MAX_BIP125_RBF_SEQUENCE and why does it matter?
MAX_BIP125_RBF_SEQUENCE is the constant 0xfffffffd defined in the Bitcoin Core headers. It serves as the threshold value for BIP-125 replaceability: any transaction input with nSequence less than or equal to this value signals that the transaction may be replaced. Values higher than this (such as 0xffffffff) indicate finality, meaning the transaction cannot be replaced even if unconfirmed.
How do I make all my wallet transactions replaceable by default?
Start Bitcoin Core with the -walletrbf=1 command-line flag or add walletrbf=1 to your bitcoin.conf file. This sets the wallet's default RBF signaling behavior, causing all new transactions created by that wallet to use nSequence = MAX_BIP125_RBF_SEQUENCE unless explicitly overridden per-transaction.
Can I replace a transaction if its parent is unconfirmed but signaled RBF?
Yes. According to IsRBFOptIn in src/policy/rbf.cpp, a transaction is considered replaceable if any of its unconfirmed ancestors signaled RBF. This inheritance ensures that chains of unconfirmed transactions can be updated together, provided the root signals replaceability.
What happens if a replacement transaction doesn't pay enough additional fee?
The mempool rejects the replacement. Specifically, the PaysForRBF logic in src/policy/rbf.cpp requires that the additional fee (replacement fee minus original fee) must at least cover the relay fee for the replacement transaction's virtual size. If this check fails, Bitcoin Core returns an "insufficient fee" error and keeps the original transaction in the mempool.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →