Merge bitcoin/bitcoin#25122: rpc: getreceivedbylabel, return early if no addresses were found in the address book

baa3ddc49c doc: add release notes about `getreceivedbylabel` returning an error if the label is not in the address book. (furszy)
8897a21658 rpc: getreceivedbylabel, don't loop over the entire wallet txs map if no destinations were found for the input label. (furszy)

Pull request description:

  Built on top of #23662, coming from comment https://github.com/bitcoin/bitcoin/pull/23662#pullrequestreview-971407999.

  If `wallet.GetLabelAddresses()` returns an empty vector (the wallet does not have stored destinations with that label in the addressbook) or if none of the returned destinations are from the wallet, we can return the function right away.
  Otherwise, we are walking through all the wallet txs + outputs for no reason (`output_scripts` is empty).

ACKs for top commit:
  achow101:
    ACK baa3ddc49c
  theStack:
    re-ACK baa3ddc49c
  w0xlt:
    ACK baa3ddc49c

Tree-SHA512: 00e10365b179bf008da2f3ef8fbb3ee04a330426374020e3f2d0151b16991baba4ef2b944e4659452f3e4d6cb20f128d0918ddf0453933a25a4d9fd8414a1911
This commit is contained in:
Andrew Chow 2022-05-23 12:08:22 -04:00
commit 5ebff43025
No known key found for this signature in database
GPG key ID: 17565732E08E5E41
3 changed files with 22 additions and 13 deletions

View file

@ -85,6 +85,9 @@ Tools and Utilities
Wallet
------
- RPC `getreceivedbylabel` now returns an error, "Label not found
in wallet" (-4), if the label is not in the address book. (#25122)
GUI changes
-----------

View file

@ -18,28 +18,31 @@
namespace wallet {
static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
{
std::set<CScript> output_scripts;
std::set<CTxDestination> addresses;
if (by_label) {
// Get the set of addresses assigned to label
std::string label = LabelFromValue(params[0]);
for (const auto& address : wallet.GetLabelAddresses(label)) {
auto output_script{GetScriptForDestination(address)};
if (wallet.IsMine(output_script)) {
output_scripts.insert(output_script);
}
}
addresses = wallet.GetLabelAddresses(LabelFromValue(params[0]));
if (addresses.empty()) throw JSONRPCError(RPC_WALLET_ERROR, "Label not found in wallet");
} else {
// Get the address
CTxDestination dest = DecodeDestination(params[0].get_str());
if (!IsValidDestination(dest)) {
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
}
CScript script_pub_key = GetScriptForDestination(dest);
if (!wallet.IsMine(script_pub_key)) {
throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
addresses.insert(dest);
}
// Filter by own scripts only
std::set<CScript> output_scripts;
for (const auto& address : addresses) {
auto output_script{GetScriptForDestination(address)};
if (wallet.IsMine(output_script)) {
output_scripts.insert(output_script);
}
output_scripts.insert(script_pub_key);
}
if (output_scripts.empty()) {
throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
}
// Minimum confirmations

View file

@ -129,6 +129,9 @@ class ReceivedByTest(BitcoinTestFramework):
txid = self.nodes[0].sendtoaddress(addr, 0.1)
self.sync_all()
# getreceivedbylabel returns an error if the wallet doesn't own the label
assert_raises_rpc_error(-4, "Label not found in wallet", self.nodes[0].getreceivedbylabel, "dummy")
# listreceivedbylabel should return received_by_label_json because of 0 confirmations
assert_array_result(self.nodes[1].listreceivedbylabel(),
{"label": label},