aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWladimir J. van der Laan <laanwj@gmail.com>2018-11-10 12:45:39 +0100
committerWladimir J. van der Laan <laanwj@gmail.com>2018-11-10 12:45:44 +0100
commit5150accdd2a7c7f0edf964d56bd7d34b5f740cdc (patch)
tree3f85d39b7547cdfef45bf0da99fc0629b1ec81e2
parent1e49fe450dbb0c258776526dba3ee583461d42ff (diff)
parent89306ab0df93bfdf5630910bc20b1eccb7379172 (diff)
Merge #14441: [wallet] Backport(0.17): Restore ability to list incoming transactions by label
89306ab0df93bfdf5630910bc20b1eccb7379172 [wallet] Restore ability to list incoming transactions by label (Russell Yanofsky) Pull request description: Backport of PR #14411 to v0.17. This change partially reverts #13075 and #14023. Fixes #14382 Tree-SHA512: 1f8300e1a79e826cd706561265b8788deef505fa510be1a76ed9a62e5fca37cf6a741423ac0e5de2a36d6e8b9f25f141885455aacacbbf6474814e6eae406a27
-rw-r--r--doc/release-notes.md18
-rw-r--r--src/wallet/rpcwallet.cpp23
-rwxr-xr-xtest/functional/wallet_import_rescan.py25
-rwxr-xr-xtest/functional/wallet_listtransactions.py7
4 files changed, 56 insertions, 17 deletions
diff --git a/doc/release-notes.md b/doc/release-notes.md
index 7f4ece80ad..ea9a45347d 100644
--- a/doc/release-notes.md
+++ b/doc/release-notes.md
@@ -71,7 +71,23 @@ Notable changes
0.17.x change log
=================
-...
+`listtransactions` label support
+--------------------------------
+
+The `listtransactions` RPC `account` parameter which was deprecated in 0.17.0
+and renamed to `dummy` has been un-deprecated and renamed again to `label`.
+
+When bitcoin is configured with the `-deprecatedrpc=accounts` setting, specifying
+a label/account/dummy argument will return both outgoing and incoming
+transactions. Without the `-deprecatedrpc=accounts` setting, it will only return
+incoming transactions (because it used to be possible to create transactions
+spending from specific accounts, but this is no longer possible with labels).
+
+When `-deprecatedrpc=accounts` is set, it's possible to pass the empty string ""
+to list transactions that don't have any label. Without
+`-deprecatedrpc=accounts`, passing the empty string is an error because returning
+only non-labeled transactions is not generally useful behavior and can cause
+confusion.
Credits
=======
diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp
index bb7ceb424c..a3de618059 100644
--- a/src/wallet/rpcwallet.cpp
+++ b/src/wallet/rpcwallet.cpp
@@ -1805,9 +1805,14 @@ static void ListTransactions(CWallet* const pwallet, const CWalletTx& wtx, const
bool fAllAccounts = (strAccount == std::string("*"));
bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
+ bool list_sent = fAllAccounts;
+
+ if (IsDeprecatedRPCEnabled("accounts")) {
+ list_sent |= strAccount == strSentAccount;
+ }
+
// Sent
- if ((!listSent.empty() || nFee != 0) && (fAllAccounts || strAccount == strSentAccount))
- {
+ if (list_sent) {
for (const COutputEntry& s : listSent)
{
UniValue entry(UniValue::VOBJ);
@@ -1901,12 +1906,14 @@ UniValue listtransactions(const JSONRPCRequest& request)
std::string help_text {};
if (!IsDeprecatedRPCEnabled("accounts")) {
- help_text = "listtransactions (dummy count skip include_watchonly)\n"
- "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions for account 'account'.\n"
+ help_text = "listtransactions (label count skip include_watchonly)\n"
+ "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
+ "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n"
"Note that the \"account\" argument and \"otheraccount\" return value have been removed in V0.17. To use this RPC with an \"account\" argument, restart\n"
"bitcoind with -deprecatedrpc=accounts\n"
"\nArguments:\n"
- "1. \"dummy\" (string, optional) If set, should be \"*\" for backwards compatibility.\n"
+ "1. \"label\" (string, optional) If set, should be a valid label name to return only incoming transactions\n"
+ " with the specified label, or \"*\" to disable filtering and return all transactions.\n"
"2. count (numeric, optional, default=10) The number of transactions to return\n"
"3. skip (numeric, optional, default=0) The number of transactions to skip\n"
"4. include_watchonly (bool, optional, default=false) Include transactions to watch-only addresses (see 'importaddress')\n"
@@ -2012,8 +2019,8 @@ UniValue listtransactions(const JSONRPCRequest& request)
std::string strAccount = "*";
if (!request.params[0].isNull()) {
strAccount = request.params[0].get_str();
- if (!IsDeprecatedRPCEnabled("accounts") && strAccount != "*") {
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"*\"");
+ if (!IsDeprecatedRPCEnabled("accounts") && strAccount.empty()) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
}
}
int nCount = 10;
@@ -4801,7 +4808,7 @@ static const CRPCCommand commands[] =
{ "wallet", "listlockunspent", &listlockunspent, {} },
{ "wallet", "listreceivedbyaddress", &listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
{ "wallet", "listsinceblock", &listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
- { "wallet", "listtransactions", &listtransactions, {"account|dummy","count","skip","include_watchonly"} },
+ { "wallet", "listtransactions", &listtransactions, {"account|label|dummy","count","skip","include_watchonly"} },
{ "wallet", "listunspent", &listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
{ "wallet", "listwallets", &listwallets, {} },
{ "wallet", "loadwallet", &loadwallet, {"filename"} },
diff --git a/test/functional/wallet_import_rescan.py b/test/functional/wallet_import_rescan.py
index aa4e37ed60..b6e3a4bcd5 100755
--- a/test/functional/wallet_import_rescan.py
+++ b/test/functional/wallet_import_rescan.py
@@ -46,11 +46,11 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
if self.call == Call.single:
if self.data == Data.address:
- response = self.try_rpc(self.node.importaddress, address=self.address["address"], rescan=rescan)
+ response = self.try_rpc(self.node.importaddress, address=self.address["address"], label=self.label, rescan=rescan)
elif self.data == Data.pub:
- response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], rescan=rescan)
+ response = self.try_rpc(self.node.importpubkey, pubkey=self.address["pubkey"], label=self.label, rescan=rescan)
elif self.data == Data.priv:
- response = self.try_rpc(self.node.importprivkey, privkey=self.key, rescan=rescan)
+ response = self.try_rpc(self.node.importprivkey, privkey=self.key, label=self.label, rescan=rescan)
assert_equal(response, None)
elif self.call == Call.multi:
@@ -61,18 +61,32 @@ class Variant(collections.namedtuple("Variant", "call data rescan prune")):
"timestamp": timestamp + TIMESTAMP_WINDOW + (1 if self.rescan == Rescan.late_timestamp else 0),
"pubkeys": [self.address["pubkey"]] if self.data == Data.pub else [],
"keys": [self.key] if self.data == Data.priv else [],
+ "label": self.label,
"watchonly": self.data != Data.priv
}], {"rescan": self.rescan in (Rescan.yes, Rescan.late_timestamp)})
assert_equal(response, [{"success": True}])
def check(self, txid=None, amount=None, confirmations=None):
- """Verify that listreceivedbyaddress returns expected values."""
+ """Verify that listtransactions/listreceivedbyaddress return expected values."""
+
+ txs = self.node.listtransactions(label=self.label, count=10000, skip=0, include_watchonly=True)
+ assert_equal(len(txs), self.expected_txs)
addresses = self.node.listreceivedbyaddress(minconf=0, include_watchonly=True, address_filter=self.address['address'])
if self.expected_txs:
assert_equal(len(addresses[0]["txids"]), self.expected_txs)
if txid is not None:
+ tx, = [tx for tx in txs if tx["txid"] == txid]
+ assert_equal(tx["label"], self.label)
+ assert_equal(tx["address"], self.address["address"])
+ assert_equal(tx["amount"], amount)
+ assert_equal(tx["category"], "receive")
+ assert_equal(tx["label"], self.label)
+ assert_equal(tx["txid"], txid)
+ assert_equal(tx["confirmations"], confirmations)
+ assert_equal("trusted" not in tx, True)
+
address, = [ad for ad in addresses if txid in ad["txids"]]
assert_equal(address["address"], self.address["address"])
assert_equal(address["amount"], self.expected_balance)
@@ -136,7 +150,8 @@ class ImportRescanTest(BitcoinTestFramework):
# Create one transaction on node 0 with a unique amount for
# each possible type of wallet import RPC.
for i, variant in enumerate(IMPORT_VARIANTS):
- variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress())
+ variant.label = "label {} {}".format(i, variant)
+ variant.address = self.nodes[1].getaddressinfo(self.nodes[1].getnewaddress(variant.label))
variant.key = self.nodes[1].dumpprivkey(variant.address["address"])
variant.initial_amount = 10 - (i + 1) / 4.0
variant.initial_txid = self.nodes[0].sendtoaddress(variant.address["address"], variant.initial_amount)
diff --git a/test/functional/wallet_listtransactions.py b/test/functional/wallet_listtransactions.py
index 5a17395abd..00a6b9c393 100755
--- a/test/functional/wallet_listtransactions.py
+++ b/test/functional/wallet_listtransactions.py
@@ -97,9 +97,10 @@ class ListTransactionsTest(BitcoinTestFramework):
txid = self.nodes[1].sendtoaddress(multisig["address"], 0.1)
self.nodes[1].generate(1)
self.sync_all()
- 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"]
- 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']
- assert_array_result(txs, {"category": "receive", "amount": Decimal("0.1")}, {"txid": txid})
+ assert len(self.nodes[0].listtransactions(label="watchonly", count=100, skip=0, include_watchonly=False)) == 0
+ assert_array_result(self.nodes[0].listtransactions(label="watchonly", count=100, skip=0, include_watchonly=True),
+ {"category": "receive", "amount": Decimal("0.1")},
+ {"txid": txid, "label": "watchonly"})
self.run_rbf_opt_in_test()