wallet: sync tx replacement metadata to malleated txs
What changed, and why it matters
This Bitcoin Core wallet patch fixes a bookkeeping bug: when a user replaces (bumps) a transaction, the wallet now also marks any malleated versions of the original transaction as replaced. Without this, the wallet could let a user try to bump a transaction that was already replaced, which would waste fees and create confusion, but it does not appear to allow theft or remote code execution.
Treat as a routine wallet correctness fix. Include in release notes as a minor bugfix. No emergency response required. Users relying on bumpfee/RBF should upgrade at normal cadence.
Security signals we found
Fixes inconsistent wallet metadata state after RBF replacement
Prevents repeated bump attempts on already-replaced malleated transactions
Potential fee waste / user confusion from duplicate bump attempts
No evidence of remote exploitability, consensus bypass, or fund theft
Evidence from the diff
MarkReplaced() in src/wallet/wallet.cpp now iterates over GetMalleatedVariants(wtx) and writes the replacement txid (m_replaced_by_txid) and metadata for each variant. Previously only the original wtx was updated. Malleated variants are transactions with the same inputs/outputs but different txids (e.g., due to signature malleability or low-R grinding). The bug meant bumpfee could attempt to RBF-bump a variant that was already replaced, producing an invalid or redundant transaction rather than being rejected early.
Changed components
src/wallet/wallet.cppCWallet::MarkReplacedbumpfee / RBF replacement flowwallet transaction metadata persistenceInspect captured patch +11 / −0
### src/wallet/wallet.cpp
@@ -1030,6 +1030,17 @@ bool CWallet::MarkReplaced(const Txid& originalHash, const Txid& newHash)
success = false;
}
+ // The new transaction also replaces any malleated variants of wtx,
+ // so bumpfee refuses to bump them afterwards
+ for (CWalletTx* variant : GetMalleatedVariants(wtx)) {
+ if (variant == &wtx) continue;
+ variant->m_replaced_by_txid = newHash;
+ if (!batch.WriteTxMetadata(*variant)) {
+ WalletLogPrintf("%s: Updating variant tx %s failed\n", __func__, variant->GetHash().ToString());
+ success = false;
+ }
+ }
+
NotifyTransactionChanged(originalHash, CT_UPDATED);
return success;Why this scored 40/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.