test: Test rbf metadata sync of malleated tx
What changed, and why it matters
This commit only adds a new automated test to Bitcoin Core. It checks that when a user creates a replace-by-fee (RBF) transaction and someone later alters (malleates) that transaction, the wallet still correctly preserves the user's original comment and the ID of the transaction it replaced. There is no change to production wallet code here, only a regression test.
No action required; treat as routine test addition. Review the underlying wallet behavior being tested only if the test fails.
Security signals we found
No production code changed
Regression test for RBF metadata propagation after transaction malleation
Asserts preservation of user-provided comment and replacement txid
Evidence from the diff
The diff adds test_malleated_rbf_metadata_synced() to test/functional/wallet_txn_clone.py. The test creates a legacy-address wallet, funds it, sends a transaction with a comment, bumps the fee via bumpfee, malleates the bumped transaction, mines the malleated version, and asserts that gettransaction returns both the original comment and the replaces_txid field pointing to the pre-bump transaction. This is purely test coverage; no wallet logic is modified.
Changed components
test/functional/wallet_txn_clone.pyInspect captured patch +21 / −0
### test/functional/wallet_txn_clone.py
@@ -146,6 +146,7 @@ def run_test(self):
assert_equal(self.nodes[0].getbalance(), expected)
self.test_malleated_metadata_synced()
+ self.test_malleated_rbf_metadata_synced()
def malleate_tx(self, wallet, txid):
rawtx = wallet.getrawtransaction(txid)
@@ -180,6 +181,26 @@ def test_malleated_metadata_synced(self):
assert_equal(wallet.gettransaction(malleated_txid)["comment"], "testing")
+ def test_malleated_rbf_metadata_synced(self):
+ self.log.info("Test malleation of a rbf has copied user provided and replacement metadata")
+ self.nodes[0].createwallet("rbf_metadata_clone")
+ wallet = self.nodes[0].get_wallet_rpc("rbf_metadata_clone")
+ def_wallet = self.nodes[0].get_wallet_rpc(self.default_wallet_name)
+
+ def_wallet.sendtoaddress(wallet.getnewaddress(address_type="legacy"), 1)
+
+ self.generate(self.nodes[0], 1)
+
+ orig_txid = wallet.sendtoaddress(def_wallet.getnewaddress(), 0.9999, comment="testing")
+ txid = wallet.bumpfee(orig_txid)["txid"]
+ malleated_tx, malleated_txid = self.malleate_tx(wallet, txid)
+
+ self.generateblock(self.nodes[0], def_wallet.getnewaddress(), [malleated_tx])
+
+ txinfo = wallet.gettransaction(malleated_txid)
+ assert_equal(txinfo["comment"], "testing")
+ assert_equal(txinfo["replaces_txid"], orig_txid)
+
if __name__ == '__main__':
TxnMallTest(__file__).main()Why this scored 12/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.