diff --git a/src/wallet/rpc/addresses.cpp b/src/wallet/rpc/addresses.cpp index acaa2d8b15..472ee1252f 100644 --- a/src/wallet/rpc/addresses.cpp +++ b/src/wallet/rpc/addresses.cpp @@ -542,6 +542,10 @@ RPCHelpMan getaddressinfo() { {RPCResult::Type::STR, "label name", "Label name (defaults to \"\")."}, }}, + {RPCResult::Type::ARR, "use_txids", "", + { + {RPCResult::Type::STR_HEX, "txid", "The ids of transactions involving this wallet which received with the address"}, + }}, } }, RPCExamples{ @@ -635,6 +639,15 @@ RPCHelpMan getaddressinfo() } ret.pushKV("labels", std::move(labels)); + // NOTE: Intentionally not special-casing a single txid: while addresses + // should never be reused, it's not unexpected to have RBF result in + // multiple txids for a single use. + UniValue use_txids(UniValue::VARR); + pwallet->FindScriptPubKeyUsed(std::set{scriptPubKey}, [&use_txids](const CWalletTx&wtx) { + use_txids.push_back(wtx.GetHash().GetHex()); + }); + ret.pushKV("use_txids", std::move(use_txids)); + return ret; }, }; diff --git a/test/functional/wallet_basic.py b/test/functional/wallet_basic.py index f798eee365..eccf76146c 100755 --- a/test/functional/wallet_basic.py +++ b/test/functional/wallet_basic.py @@ -653,6 +653,16 @@ class WalletTest(BitcoinTestFramework): assert not address_info["iswatchonly"] assert not address_info["isscript"] assert not address_info["ischange"] + assert_equal(address_info['use_txids'], []) + + # Test getaddressinfo 'use_txids' field + addr = "mneYUmWYsuk7kySiURxCi3AGxrAqZxLgPZ" + txid_1 = self.nodes[0].sendtoaddress(addr, 1) + address_info = self.nodes[0].getaddressinfo(addr) + assert_equal(address_info['use_txids'], [txid_1]) + txid_2 = self.nodes[0].sendtoaddress(addr, 1) + address_info = self.nodes[0].getaddressinfo(addr) + assert_equal(sorted(address_info['use_txids']), sorted([txid_1, txid_2])) # Test getaddressinfo 'ischange' field on change address. self.generate(self.nodes[0], 1, sync_fun=self.no_op)