// Copyright (c) 2011-2022 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include #include #include #include namespace wallet { static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) { std::vector addresses; if (by_label) { // Get the set of addresses assigned to label addresses = wallet.ListAddrBookAddresses(CWallet::AddrBookFilter{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"); } addresses.emplace_back(dest); } // Filter by own scripts only std::set output_scripts; for (const auto& address : addresses) { auto output_script{GetScriptForDestination(address)}; if (wallet.IsMine(output_script)) { output_scripts.insert(output_script); } } if (output_scripts.empty()) { throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet"); } // Minimum confirmations int min_depth = 1; if (!params[1].isNull()) min_depth = params[1].getInt(); const bool include_immature_coinbase{params[2].isNull() ? false : params[2].get_bool()}; // Tally CAmount amount = 0; for (const std::pair& wtx_pair : wallet.mapWallet) { const CWalletTx& wtx = wtx_pair.second; int depth{wallet.GetTxDepthInMainChain(wtx)}; if (depth < min_depth // Coinbase with less than 1 confirmation is no longer in the main chain || (wtx.IsCoinBase() && (depth < 1)) || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)) { continue; } for (const CTxOut& txout : wtx.tx->vout) { if (output_scripts.count(txout.scriptPubKey) > 0) { amount += txout.nValue; } } } return amount; } RPCHelpMan getreceivedbyaddress() { return RPCHelpMan{"getreceivedbyaddress", "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n", { {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."}, {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."}, {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."}, }, RPCResult{ RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address." }, RPCExamples{ "\nThe amount from transactions with at least 1 confirmation\n" + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") + "\nThe amount including unconfirmed transactions, zero confirmations\n" + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0") + "\nThe amount with at least 6 confirmations\n" + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") + "\nThe amount with at least 6 confirmations including immature coinbase outputs\n" + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6 true") + "\nAs a JSON-RPC call\n" + HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6") }, [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue { const std::shared_ptr pwallet = GetWalletForJSONRPCRequest(request); if (!pwallet) return UniValue::VNULL; // Make sure the results are valid at least up to the most recent block // the user could have gotten from another RPC command prior to now pwallet->BlockUntilSyncedToCurrentChain(); LOCK(pwallet->cs_wallet); return ValueFromAmount(GetReceived(*pwallet, request.params, /*by_label=*/false)); }, }; } RPCHelpMan getreceivedbylabel() { return RPCHelpMan{"getreceivedbylabel", "\nReturns the total amount received by addresses with