Skip to content

Commit e74649e

Browse files
author
MarcoFalke
committed
Merge #14411: [wallet] Restore ability to list incoming transactions by label
da427db Rename ListTransactions filter variable (Russell Yanofsky) 65b740f [wallet] Restore ability to list incoming transactions by label (Russell Yanofsky) Pull request description: This change partially reverts #13075 and #14023. Fixes #14382 Tree-SHA512: 8c4e56104b3a45784cdc06bae8e5facdfff04fe3545b63a35e0ec2e440a41b79d84833ca4c4e728d8af7ebb8a519303a9eda7bee4bbfb92bd50c58587a33eb30
2 parents c7366d2 + da427db commit e74649e

File tree

3 files changed

+51
-25
lines changed

3 files changed

+51
-25
lines changed

src/wallet/rpcwallet.cpp

Lines changed: 27 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1261,25 +1261,26 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
12611261
/**
12621262
* List transactions based on the given criteria.
12631263
*
1264-
* @param pwallet The wallet.
1265-
* @param wtx The wallet transaction.
1266-
* @param nMinDepth The minimum confirmation depth.
1267-
* @param fLong Whether to include the JSON version of the transaction.
1268-
* @param ret The UniValue into which the result is stored.
1269-
* @param filter The "is mine" filter bool.
1264+
* @param pwallet The wallet.
1265+
* @param wtx The wallet transaction.
1266+
* @param nMinDepth The minimum confirmation depth.
1267+
* @param fLong Whether to include the JSON version of the transaction.
1268+
* @param ret The UniValue into which the result is stored.
1269+
* @param filter_ismine The "is mine" filter flags.
1270+
* @param filter_label Optional label string to filter incoming transactions.
12701271
*/
1271-
static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter)
1272+
static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* const pwallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label)
12721273
{
12731274
CAmount nFee;
12741275
std::list<COutputEntry> listReceived;
12751276
std::list<COutputEntry> listSent;
12761277

1277-
wtx.GetAmounts(listReceived, listSent, nFee, filter);
1278+
wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine);
12781279

12791280
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
12801281

12811282
// Sent
1282-
if ((!listSent.empty() || nFee != 0))
1283+
if (!filter_label)
12831284
{
12841285
for (const COutputEntry& s : listSent)
12851286
{
@@ -1311,6 +1312,9 @@ static void ListTransactions(interfaces::Chain::Lock& locked_chain, CWallet* con
13111312
if (pwallet->mapAddressBook.count(r.destination)) {
13121313
label = pwallet->mapAddressBook[r.destination].name;
13131314
}
1315+
if (filter_label && label != *filter_label) {
1316+
continue;
1317+
}
13141318
UniValue entry(UniValue::VOBJ);
13151319
if (involvesWatchonly || (::IsMine(*pwallet, r.destination) & ISMINE_WATCH_ONLY)) {
13161320
entry.pushKV("involvesWatchonly", true);
@@ -1352,10 +1356,12 @@ UniValue listtransactions(const JSONRPCRequest& request)
13521356

13531357
if (request.fHelp || request.params.size() > 4)
13541358
throw std::runtime_error(
1355-
"listtransactions ( \"dummy\" count skip include_watchonly)\n"
1359+
"listtransactions ( \"label\" count skip include_watchonly )\n"
1360+
"\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
13561361
"\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n"
13571362
"\nArguments:\n"
1358-
"1. \"dummy\" (string, optional) If set, should be \"*\" for backwards compatibility.\n"
1363+
"1. \"label\" (string, optional) If set, should be a valid label name to return only incoming transactions\n"
1364+
" with the specified label, or \"*\" to disable filtering and return all transactions.\n"
13591365
"2. count (numeric, optional, default=10) The number of transactions to return\n"
13601366
"3. skip (numeric, optional, default=0) The number of transactions to skip\n"
13611367
"4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
@@ -1400,8 +1406,12 @@ UniValue listtransactions(const JSONRPCRequest& request)
14001406
// the user could have gotten from another RPC command prior to now
14011407
pwallet->BlockUntilSyncedToCurrentChain();
14021408

1409+
const std::string* filter_label = nullptr;
14031410
if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
1404-
throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
1411+
filter_label = &request.params[0].get_str();
1412+
if (filter_label->empty()) {
1413+
throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
1414+
}
14051415
}
14061416
int nCount = 10;
14071417
if (!request.params[1].isNull())
@@ -1431,7 +1441,7 @@ UniValue listtransactions(const JSONRPCRequest& request)
14311441
for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
14321442
{
14331443
CWalletTx *const pwtx = (*it).second;
1434-
ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter);
1444+
ListTransactions(*locked_chain, pwallet, *pwtx, 0, true, ret, filter, filter_label);
14351445
if ((int)ret.size() >= (nCount+nFrom)) break;
14361446
}
14371447
}
@@ -1568,7 +1578,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
15681578
CWalletTx tx = pairWtx.second;
15691579

15701580
if (depth == -1 || tx.GetDepthInMainChain(*locked_chain) < depth) {
1571-
ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter);
1581+
ListTransactions(*locked_chain, pwallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
15721582
}
15731583
}
15741584

@@ -1585,7 +1595,7 @@ static UniValue listsinceblock(const JSONRPCRequest& request)
15851595
if (it != pwallet->mapWallet.end()) {
15861596
// We want all transactions regardless of confirmation count to appear here,
15871597
// even negative confirmation ones, hence the big negative.
1588-
ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter);
1598+
ListTransactions(*locked_chain, pwallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
15891599
}
15901600
}
15911601
paltindex = paltindex->pprev;
@@ -1688,7 +1698,7 @@ static UniValue gettransaction(const JSONRPCRequest& request)
16881698
WalletTxToJSON(pwallet->chain(), *locked_chain, wtx, entry);
16891699

16901700
UniValue details(UniValue::VARR);
1691-
ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter);
1701+
ListTransactions(*locked_chain, pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
16921702
entry.pushKV("details", details);
16931703

16941704
std::string strHex = EncodeHexTx(*wtx.tx, RPCSerializationFlags());
@@ -4143,7 +4153,7 @@ static const CRPCCommand commands[] =
41434153
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
41444154
{ "wallet", "listreceivedbylabel", &listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
41454155
{ "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
4146-
{ "wallet", "listtransactions", &listtransactions, {"dummy","count","skip","include_watchonly"} },
4156+
{ "wallet", "listtransactions", &listtransactions, {"label|dummy","count","skip","include_watchonly"} },
41474157
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
41484158
{ "wallet", "listwalletdir", &listwalletdir, {} },
41494159
{ "wallet", "listwallets", &listwallets, {} },

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)
@@ -134,7 +148,8 @@ def run_test(self):
134148
# Create one transaction on node 0 with a unique amount for
135149
# each possible type of wallet import RPC.
136150
for i, variant in enumerate(IMPORT_VARIANTS):
137-
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())
151+
variant.label = "label {} {}".format(i, variant)
152+
variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))
138153
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
139154
variant.initial_amount = 1 - (i + 1) / 64
140155
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)