Skip to content

Commit 7cbe74f

Browse files
committed
[wallet] Restore ability to list incoming transactions by label
This change partially reverts #13075 and #14023. Fixes #14382
1 parent f504a14 commit 7cbe74f

File tree

3 files changed

+44
-18
lines changed

3 files changed

+44
-18
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1375,8 +1375,9 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
13751375
* @param fLong Whether to include the JSON version of the transaction.
13761376
* @param ret The UniValue into which the result is stored.
13771377
* @param filter The "is mine" filter bool.
1378+
* @param filter_label Optional label string to filter incoming transactions.
13781379
*/
1379-
static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
1380+
static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
13801381
{
13811382
CAmount nFee;
13821383
std::list<COutputEntry> listReceived;
@@ -1387,7 +1388,7 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
13871388
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
13881389

13891390
// Sent
1390-
if ((!listSent.empty() || nFee != 0))
1391+
if (!filter_label)
13911392
{
13921393
for (const COutputEntry& s : listSent)
13931394
{
@@ -1419,6 +1420,9 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, int n
14191420
if (pwallet->mapAddressBook.count(r.destination)) {
14201421
label = pwallet->mapAddressBook[r.destination].name;
14211422
}
1423+
if (filter_label && label != *filter_label) {
1424+
continue;
1425+
}
14221426
UniValue entry(UniValue::VOBJ);
14231427
if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
14241428
entry.pushKV("involvesWatchonly", true);
@@ -1460,10 +1464,12 @@ UniValue listtransactions(const JSONRPCRequest& request)
14601464

14611465
if (request.fHelp || request.params.size() > 4)
14621466
throw std::runtime_error(
1463-
"listtransactions (dummy count skip include_watchonly)\n"
1467+
"listtransactions ( label count skip include_watchonly )\n"
1468+
"\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
14641469
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n"
14651470
"\nArguments:\n"
1466-
"1. \"dummy\" (string, optional) If set, should be \"*\" for backwards compatibility.\n"
1471+
"1. \"label\" (string, optional) If set, should be a valid label name to return only incoming transactions\n"
1472+
" with the specified label, or \"*\" to disable filtering and return all transactions.\n"
14671473
"2. count (numeric, optional, default=10) The number of transactions to return\n"
14681474
"3. skip (numeric, optional, default=0) The number of transactions to skip\n"
14691475
"4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
@@ -1508,8 +1514,12 @@ UniValue listtransactions(const JSONRPCRequest& request)
15081514
// the user could have gotten from another RPC command prior to now
15091515
pwallet->BlockUntilSyncedToCurrentChain();
15101516

1517+
const std::string* filter_label = nullptr;
15111518
if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
1512-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
1519+
filter_label = &request.params[0].get_str();
1520+
if (filter_label->empty()) {
1521+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
1522+
}
15131523
}
15141524
int nCount = 10;
15151525
if (!request.params[1].isNull())
@@ -1538,7 +1548,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
15381548
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
15391549
{
15401550
CWalletTx *const pwtx = (*it).second;
1541-
ListTransactions(pwallet, *pwtx, 0, true, ret, filter);
1551+
ListTransactions(pwallet, *pwtx, 0, true, ret, filter, filter_label);
15421552
if ((int)ret.size() >= (nCount+nFrom)) break;
15431553
}
15441554
}
@@ -1674,7 +1684,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16741684
CWalletTx tx = pairWtx.second;
16751685

16761686
if (depth == -1 || tx.GetDepthInMainChain() < depth) {
1677-
ListTransactions(pwallet, tx, 0, true, transactions, filter);
1687+
ListTransactions(pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
16781688
}
16791689
}
16801690

@@ -1691,7 +1701,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
16911701
if (it != pwallet->mapWallet.end()) {
16921702
// We want all transactions regardless of confirmation count to appear here,
16931703
// even negative confirmation ones, hence the big negative.
1694-
ListTransactions(pwallet, it->second, -100000000, true, removed, filter);
1704+
ListTransactions(pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
16951705
}
16961706
}
16971707
paltindex = paltindex->pprev;
@@ -1793,7 +1803,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
17931803
WalletTxToJSON(wtx, entry);
17941804

17951805
UniValue details(UniValue::VARR);
1796-
ListTransactions(pwallet, wtx, 0, false, details, filter);
1806+
ListTransactions(pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
17971807
entry.pushKV("details", details);
17981808

17991809
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
@@ -4094,7 +4104,7 @@ static const CRPCCommand commands[] =
40944104
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
40954105
{ "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
40964106
{ "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
4097-
{ "wallet", "listtransactions", &listtransactions, {"dummy","count","skip","include_watchonly"} },
4107+
{ "wallet", "listtransactions", &listtransactions, {"label|dummy","count","skip","include_watchonly"} },
40984108
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
40994109
{ "wallet", "listwallets", &listwallets, {} },
41004110
{ "wallet", "loadwallet", &loadwallet, {"filename"} },

test/functional/wallet_import_rescan.py

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,11 @@ def do_import(self, timestamp):
4646

4747
if self.call == Call.single:
4848
if self.data == Data.address:
49-
response = self.try_rpc(self.node.importaddress, address=self.address["address"], rescan=rescan)
49+
response = self.try_rpc(self.node.importaddress, address=self.address["address"], label=self.label, rescan=rescan)
5050
elif self.data == Data.pub:
51-
response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], rescan=rescan)
51+
response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
5252
elif self.data == Data.priv:
53-
response = self.try_rpc(self.node.importprivkey, privkey=self.key, rescan=rescan)
53+
response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan)
5454
assert_equal(response, None)
5555

5656
elif self.call in (Call.multiaddress, Call.multiscript):
@@ -61,18 +61,32 @@ def do_import(self, timestamp):
6161
"timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
6262
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
6363
"keys": [self.key] if self.data == Data.priv else [],
64+
"label": self.label,
6465
"watchonly": self.data != Data.priv
6566
}], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)})
6667
assert_equal(response, [{"success": True}])
6768

6869
def check(self, txid=None, amount=None, confirmations=None):
69-
"""Verify that listreceivedbyaddress returns expected values."""
70+
"""Verify that listtransactions/listreceivedbyaddress return expected values."""
71+
72+
txs = self.node.listtransactions(label=self.label, count=10000, include_watchonly=True)
73+
assert_equal(len(txs), self.expected_txs)
7074

7175
addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])
7276
if self.expected_txs:
7377
assert_equal(len(addresses[0]["txids"]), self.expected_txs)
7478

7579
if txid is not None:
80+
tx, = [tx for tx in txs if tx["txid"] == txid]
81+
assert_equal(tx["label"], self.label)
82+
assert_equal(tx["address"], self.address["address"])
83+
assert_equal(tx["amount"], amount)
84+
assert_equal(tx["category"], "receive")
85+
assert_equal(tx["label"], self.label)
86+
assert_equal(tx["txid"], txid)
87+
assert_equal(tx["confirmations"], confirmations)
88+
assert_equal("trusted" not in tx, True)
89+
7690
address, = [ad for ad in addresses if txid in ad["txids"]]
7791
assert_equal(address["address"], self.address["address"])
7892
assert_equal(address["amount"], self.expected_balance)
@@ -136,7 +150,8 @@ def run_test(self):
136150
# Create one transaction on node 0 with a unique amount for
137151
# each possible type of wallet import RPC.
138152
for i, variant in enumerate(IMPORT_VARIANTS):
139-
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())
153+
variant.label = "label {} {}".format(i, variant)
154+
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))
140155
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
141156
variant.initial_amount = 1 - (i + 1) / 64
142157
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)

test/functional/wallet_listtransactions.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -97,9 +97,10 @@ def run_test(self):
9797
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
9898
self.nodes[1].generate(1)
9999
self.sync_all()
100-
assert not [tx for tx in self.nodes[0].listtransactions(dummy="*", count=100, skip=0, include_watchonly=False) if "label" in tx and tx["label"] == "watchonly"]
101-
txs = [tx for tx in self.nodes[0].listtransactions(dummy="*", count=100, skip=0, include_watchonly=True) if "label" in tx and tx['label'] == 'watchonly']
102-
assert_array_result(txs, {"category": "receive", "amount": Decimal("0.1")}, {"txid": txid})
100+
assert len(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=False)) == 0
101+
assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, include_watchonly=True),
102+
{"category": "receive", "amount": Decimal("0.1")},
103+
{"txid": txid, "label": "watchonly"})
103104

104105
self.run_rbf_opt_in_test()
105106

0 commit comments

Comments
 (0)