/Users/eugenesiegel/btc/bitcoin/src/wallet/rpc/coins.cpp
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2011-2022 The Bitcoin Core developers | 
| 2 |  | // Distributed under the MIT software license, see the accompanying | 
| 3 |  | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | 
| 4 |  |  | 
| 5 |  | #include <core_io.h> | 
| 6 |  | #include <hash.h> | 
| 7 |  | #include <key_io.h> | 
| 8 |  | #include <rpc/util.h> | 
| 9 |  | #include <script/script.h> | 
| 10 |  | #include <util/moneystr.h> | 
| 11 |  | #include <wallet/coincontrol.h> | 
| 12 |  | #include <wallet/receive.h> | 
| 13 |  | #include <wallet/rpc/util.h> | 
| 14 |  | #include <wallet/spend.h> | 
| 15 |  | #include <wallet/wallet.h> | 
| 16 |  |  | 
| 17 |  | #include <univalue.h> | 
| 18 |  |  | 
| 19 |  |  | 
| 20 |  | namespace wallet { | 
| 21 |  | static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) | 
| 22 | 0 | { | 
| 23 | 0 |     std::vector<CTxDestination> addresses; | 
| 24 | 0 |     if (by_label) { | 
| 25 |  |         // Get the set of addresses assigned to label | 
| 26 | 0 |         addresses = wallet.ListAddrBookAddresses(CWallet::AddrBookFilter{LabelFromValue(params[0])}); | 
| 27 | 0 |         if (addresses.empty()) throw JSONRPCError(RPC_WALLET_ERROR, "Label not found in wallet"); | 
| 28 | 0 |     } else { | 
| 29 |  |         // Get the address | 
| 30 | 0 |         CTxDestination dest = DecodeDestination(params[0].get_str()); | 
| 31 | 0 |         if (!IsValidDestination(dest)) { | 
| 32 | 0 |             throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address"); | 
| 33 | 0 |         } | 
| 34 | 0 |         addresses.emplace_back(dest); | 
| 35 | 0 |     } | 
| 36 |  |  | 
| 37 |  |     // Filter by own scripts only | 
| 38 | 0 |     std::set<CScript> output_scripts; | 
| 39 | 0 |     for (const auto& address : addresses) { | 
| 40 | 0 |         auto output_script{GetScriptForDestination(address)}; | 
| 41 | 0 |         if (wallet.IsMine(output_script)) { | 
| 42 | 0 |             output_scripts.insert(output_script); | 
| 43 | 0 |         } | 
| 44 | 0 |     } | 
| 45 |  | 
 | 
| 46 | 0 |     if (output_scripts.empty()) { | 
| 47 | 0 |         throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet"); | 
| 48 | 0 |     } | 
| 49 |  |  | 
| 50 |  |     // Minimum confirmations | 
| 51 | 0 |     int min_depth = 1; | 
| 52 | 0 |     if (!params[1].isNull()) | 
| 53 | 0 |         min_depth = params[1].getInt<int>(); | 
| 54 |  | 
 | 
| 55 | 0 |     const bool include_immature_coinbase{params[2].isNull() ? false : params[2].get_bool()}; | 
| 56 |  |  | 
| 57 |  |     // Tally | 
| 58 | 0 |     CAmount amount = 0; | 
| 59 | 0 |     for (const auto& [_, wtx] : wallet.mapWallet) { | 
| 60 | 0 |         int depth{wallet.GetTxDepthInMainChain(wtx)}; | 
| 61 | 0 |         if (depth < min_depth | 
| 62 |  |             // Coinbase with less than 1 confirmation is no longer in the main chain | 
| 63 | 0 |             || (wtx.IsCoinBase() && (depth < 1)) | 
| 64 | 0 |             || (wallet.IsTxImmatureCoinBase(wtx) && !include_immature_coinbase)) | 
| 65 | 0 |         { | 
| 66 | 0 |             continue; | 
| 67 | 0 |         } | 
| 68 |  |  | 
| 69 | 0 |         for (const CTxOut& txout : wtx.tx->vout) { | 
| 70 | 0 |             if (output_scripts.count(txout.scriptPubKey) > 0) { | 
| 71 | 0 |                 amount += txout.nValue; | 
| 72 | 0 |             } | 
| 73 | 0 |         } | 
| 74 | 0 |     } | 
| 75 |  | 
 | 
| 76 | 0 |     return amount; | 
| 77 | 0 | } | 
| 78 |  |  | 
| 79 |  |  | 
| 80 |  | RPCHelpMan getreceivedbyaddress() | 
| 81 | 0 | { | 
| 82 | 0 |     return RPCHelpMan{ | 
| 83 | 0 |         "getreceivedbyaddress", | 
| 84 | 0 |         "Returns the total amount received by the given address in transactions with at least minconf confirmations.\n", | 
| 85 | 0 |                 { | 
| 86 | 0 |                     {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."}, | 
| 87 | 0 |                     {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."}, | 
| 88 | 0 |                     {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."}, | 
| 89 | 0 |                 }, | 
| 90 | 0 |                 RPCResult{ | 
| 91 | 0 |                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address." | 
| 92 | 0 |                 }, | 
| 93 | 0 |                 RPCExamples{ | 
| 94 | 0 |             "\nThe amount from transactions with at least 1 confirmation\n" | 
| 95 | 0 |             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") + | 
| 96 | 0 |             "\nThe amount including unconfirmed transactions, zero confirmations\n" | 
| 97 | 0 |             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0") + | 
| 98 | 0 |             "\nThe amount with at least 6 confirmations\n" | 
| 99 | 0 |             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") + | 
| 100 | 0 |             "\nThe amount with at least 6 confirmations including immature coinbase outputs\n" | 
| 101 | 0 |             + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6 true") + | 
| 102 | 0 |             "\nAs a JSON-RPC call\n" | 
| 103 | 0 |             + HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6") | 
| 104 | 0 |                 }, | 
| 105 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 106 | 0 | { | 
| 107 | 0 |     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); | 
| 108 | 0 |     if (!pwallet) return UniValue::VNULL; | 
| 109 |  |  | 
| 110 |  |     // Make sure the results are valid at least up to the most recent block | 
| 111 |  |     // the user could have gotten from another RPC command prior to now | 
| 112 | 0 |     pwallet->BlockUntilSyncedToCurrentChain(); | 
| 113 |  | 
 | 
| 114 | 0 |     LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 115 |  | 
 | 
| 116 | 0 |     return ValueFromAmount(GetReceived(*pwallet, request.params, /*by_label=*/false)); | 
| 117 | 0 | }, | 
| 118 | 0 |     }; | 
| 119 | 0 | } | 
| 120 |  |  | 
| 121 |  |  | 
| 122 |  | RPCHelpMan getreceivedbylabel() | 
| 123 | 0 | { | 
| 124 | 0 |     return RPCHelpMan{ | 
| 125 | 0 |         "getreceivedbylabel", | 
| 126 | 0 |         "Returns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n", | 
| 127 | 0 |                 { | 
| 128 | 0 |                     {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."}, | 
| 129 | 0 |                     {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."}, | 
| 130 | 0 |                     {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."}, | 
| 131 | 0 |                 }, | 
| 132 | 0 |                 RPCResult{ | 
| 133 | 0 |                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label." | 
| 134 | 0 |                 }, | 
| 135 | 0 |                 RPCExamples{ | 
| 136 | 0 |             "\nAmount received by the default label with at least 1 confirmation\n" | 
| 137 | 0 |             + HelpExampleCli("getreceivedbylabel", "\"\"") + | 
| 138 | 0 |             "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n" | 
| 139 | 0 |             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") + | 
| 140 | 0 |             "\nThe amount with at least 6 confirmations\n" | 
| 141 | 0 |             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") + | 
| 142 | 0 |             "\nThe amount with at least 6 confirmations including immature coinbase outputs\n" | 
| 143 | 0 |             + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6 true") + | 
| 144 | 0 |             "\nAs a JSON-RPC call\n" | 
| 145 | 0 |             + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6, true") | 
| 146 | 0 |                 }, | 
| 147 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 148 | 0 | { | 
| 149 | 0 |     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); | 
| 150 | 0 |     if (!pwallet) return UniValue::VNULL; | 
| 151 |  |  | 
| 152 |  |     // Make sure the results are valid at least up to the most recent block | 
| 153 |  |     // the user could have gotten from another RPC command prior to now | 
| 154 | 0 |     pwallet->BlockUntilSyncedToCurrentChain(); | 
| 155 |  | 
 | 
| 156 | 0 |     LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 157 |  | 
 | 
| 158 | 0 |     return ValueFromAmount(GetReceived(*pwallet, request.params, /*by_label=*/true)); | 
| 159 | 0 | }, | 
| 160 | 0 |     }; | 
| 161 | 0 | } | 
| 162 |  |  | 
| 163 |  |  | 
| 164 |  | RPCHelpMan getbalance() | 
| 165 | 0 | { | 
| 166 | 0 |     return RPCHelpMan{ | 
| 167 | 0 |         "getbalance", | 
| 168 | 0 |         "Returns the total available balance.\n" | 
| 169 | 0 |                 "The available balance is what the wallet considers currently spendable, and is\n" | 
| 170 | 0 |                 "thus affected by options which limit spendability such as -spendzeroconfchange.\n", | 
| 171 | 0 |                 { | 
| 172 | 0 |                     {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Remains for backward compatibility. Must be excluded or set to \"*\"."}, | 
| 173 | 0 |                     {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Only include transactions confirmed at least this many times."}, | 
| 174 | 0 |                     {"include_watchonly", RPCArg::Type::BOOL, RPCArg::Default{false}, "No longer used"}, | 
| 175 | 0 |                     {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Do not include balance in dirty outputs; addresses are considered dirty if they have previously been used in a transaction."}, | 
| 176 | 0 |                 }, | 
| 177 | 0 |                 RPCResult{ | 
| 178 | 0 |                     RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet." | 
| 179 | 0 |                 }, | 
| 180 | 0 |                 RPCExamples{ | 
| 181 | 0 |             "\nThe total amount in the wallet with 0 or more confirmations\n" | 
| 182 | 0 |             + HelpExampleCli("getbalance", "") + | 
| 183 | 0 |             "\nThe total amount in the wallet with at least 6 confirmations\n" | 
| 184 | 0 |             + HelpExampleCli("getbalance", "\"*\" 6") + | 
| 185 | 0 |             "\nAs a JSON-RPC call\n" | 
| 186 | 0 |             + HelpExampleRpc("getbalance", "\"*\", 6") | 
| 187 | 0 |                 }, | 
| 188 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 189 | 0 | { | 
| 190 | 0 |     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); | 
| 191 | 0 |     if (!pwallet) return UniValue::VNULL; | 
| 192 |  |  | 
| 193 |  |     // Make sure the results are valid at least up to the most recent block | 
| 194 |  |     // the user could have gotten from another RPC command prior to now | 
| 195 | 0 |     pwallet->BlockUntilSyncedToCurrentChain(); | 
| 196 |  | 
 | 
| 197 | 0 |     LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 198 |  | 
 | 
| 199 | 0 |     const auto dummy_value{self.MaybeArg<std::string>("dummy")}; | 
| 200 | 0 |     if (dummy_value && *dummy_value != "*") { | 
| 201 | 0 |         throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\"."); | 
| 202 | 0 |     } | 
| 203 |  |  | 
| 204 | 0 |     const auto min_depth{self.Arg<int>("minconf")}; | 
| 205 |  | 
 | 
| 206 | 0 |     bool avoid_reuse = GetAvoidReuseFlag(*pwallet, request.params[3]); | 
| 207 |  | 
 | 
| 208 | 0 |     const auto bal = GetBalance(*pwallet, min_depth, avoid_reuse); | 
| 209 |  | 
 | 
| 210 | 0 |     return ValueFromAmount(bal.m_mine_trusted); | 
| 211 | 0 | }, | 
| 212 | 0 |     }; | 
| 213 | 0 | } | 
| 214 |  |  | 
| 215 |  | RPCHelpMan lockunspent() | 
| 216 | 0 | { | 
| 217 | 0 |     return RPCHelpMan{ | 
| 218 | 0 |         "lockunspent", | 
| 219 | 0 |         "Updates list of temporarily unspendable outputs.\n" | 
| 220 | 0 |                 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n" | 
| 221 | 0 |                 "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n" | 
| 222 | 0 |                 "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n" | 
| 223 | 0 |                 "Manually selected coins are automatically unlocked.\n" | 
| 224 | 0 |                 "Locks are stored in memory only, unless persistent=true, in which case they will be written to the\n" | 
| 225 | 0 |                 "wallet database and loaded on node start. Unwritten (persistent=false) locks are always cleared\n" | 
| 226 | 0 |                 "(by virtue of process exit) when a node stops or fails. Unlocking will clear both persistent and not.\n" | 
| 227 | 0 |                 "Also see the listunspent call\n", | 
| 228 | 0 |                 { | 
| 229 | 0 |                     {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"}, | 
| 230 | 0 |                     {"transactions", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The transaction outputs and within each, the txid (string) vout (numeric).", | 
| 231 | 0 |                         { | 
| 232 | 0 |                             {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "", | 
| 233 | 0 |                                 { | 
| 234 | 0 |                                     {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"}, | 
| 235 | 0 |                                     {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"}, | 
| 236 | 0 |                                 }, | 
| 237 | 0 |                             }, | 
| 238 | 0 |                         }, | 
| 239 | 0 |                     }, | 
| 240 | 0 |                     {"persistent", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to write/erase this lock in the wallet database, or keep the change in memory only. Ignored for unlocking."}, | 
| 241 | 0 |                 }, | 
| 242 | 0 |                 RPCResult{ | 
| 243 | 0 |                     RPCResult::Type::BOOL, "", "Whether the command was successful or not" | 
| 244 | 0 |                 }, | 
| 245 | 0 |                 RPCExamples{ | 
| 246 | 0 |             "\nList the unspent transactions\n" | 
| 247 | 0 |             + HelpExampleCli("listunspent", "") + | 
| 248 | 0 |             "\nLock an unspent transaction\n" | 
| 249 | 0 |             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + | 
| 250 | 0 |             "\nList the locked transactions\n" | 
| 251 | 0 |             + HelpExampleCli("listlockunspent", "") + | 
| 252 | 0 |             "\nUnlock the transaction again\n" | 
| 253 | 0 |             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + | 
| 254 | 0 |             "\nLock the transaction persistently in the wallet database\n" | 
| 255 | 0 |             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\" true") + | 
| 256 | 0 |             "\nAs a JSON-RPC call\n" | 
| 257 | 0 |             + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") | 
| 258 | 0 |                 }, | 
| 259 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 260 | 0 | { | 
| 261 | 0 |     std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request); | 
| 262 | 0 |     if (!pwallet) return UniValue::VNULL; | 
| 263 |  |  | 
| 264 |  |     // Make sure the results are valid at least up to the most recent block | 
| 265 |  |     // the user could have gotten from another RPC command prior to now | 
| 266 | 0 |     pwallet->BlockUntilSyncedToCurrentChain(); | 
| 267 |  | 
 | 
| 268 | 0 |     LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 269 |  | 
 | 
| 270 | 0 |     bool fUnlock = request.params[0].get_bool(); | 
| 271 |  | 
 | 
| 272 | 0 |     const bool persistent{request.params[2].isNull() ? false : request.params[2].get_bool()}; | 
| 273 |  | 
 | 
| 274 | 0 |     if (request.params[1].isNull()) { | 
| 275 | 0 |         if (fUnlock) { | 
| 276 | 0 |             if (!pwallet->UnlockAllCoins()) | 
| 277 | 0 |                 throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coins failed"); | 
| 278 | 0 |         } | 
| 279 | 0 |         return true; | 
| 280 | 0 |     } | 
| 281 |  |  | 
| 282 | 0 |     const UniValue& output_params = request.params[1].get_array(); | 
| 283 |  |  | 
| 284 |  |     // Create and validate the COutPoints first. | 
| 285 |  | 
 | 
| 286 | 0 |     std::vector<COutPoint> outputs; | 
| 287 | 0 |     outputs.reserve(output_params.size()); | 
| 288 |  | 
 | 
| 289 | 0 |     for (unsigned int idx = 0; idx < output_params.size(); idx++) { | 
| 290 | 0 |         const UniValue& o = output_params[idx].get_obj(); | 
| 291 |  | 
 | 
| 292 | 0 |         RPCTypeCheckObj(o, | 
| 293 | 0 |             { | 
| 294 | 0 |                 {"txid", UniValueType(UniValue::VSTR)}, | 
| 295 | 0 |                 {"vout", UniValueType(UniValue::VNUM)}, | 
| 296 | 0 |             }); | 
| 297 |  | 
 | 
| 298 | 0 |         const Txid txid = Txid::FromUint256(ParseHashO(o, "txid")); | 
| 299 | 0 |         const int nOutput = o.find_value("vout").getInt<int>(); | 
| 300 | 0 |         if (nOutput < 0) { | 
| 301 | 0 |             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative"); | 
| 302 | 0 |         } | 
| 303 |  |  | 
| 304 | 0 |         const COutPoint outpt(txid, nOutput); | 
| 305 |  | 
 | 
| 306 | 0 |         const auto it = pwallet->mapWallet.find(outpt.hash); | 
| 307 | 0 |         if (it == pwallet->mapWallet.end()) { | 
| 308 | 0 |             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction"); | 
| 309 | 0 |         } | 
| 310 |  |  | 
| 311 | 0 |         const CWalletTx& trans = it->second; | 
| 312 |  | 
 | 
| 313 | 0 |         if (outpt.n >= trans.tx->vout.size()) { | 
| 314 | 0 |             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds"); | 
| 315 | 0 |         } | 
| 316 |  |  | 
| 317 | 0 |         if (pwallet->IsSpent(outpt)) { | 
| 318 | 0 |             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output"); | 
| 319 | 0 |         } | 
| 320 |  |  | 
| 321 | 0 |         const bool is_locked = pwallet->IsLockedCoin(outpt); | 
| 322 |  | 
 | 
| 323 | 0 |         if (fUnlock && !is_locked) { | 
| 324 | 0 |             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output"); | 
| 325 | 0 |         } | 
| 326 |  |  | 
| 327 | 0 |         if (!fUnlock && is_locked && !persistent) { | 
| 328 | 0 |             throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked"); | 
| 329 | 0 |         } | 
| 330 |  |  | 
| 331 | 0 |         outputs.push_back(outpt); | 
| 332 | 0 |     } | 
| 333 |  |  | 
| 334 |  |     // Atomically set (un)locked status for the outputs. | 
| 335 | 0 |     for (const COutPoint& outpt : outputs) { | 
| 336 | 0 |         if (fUnlock) { | 
| 337 | 0 |             if (!pwallet->UnlockCoin(outpt)) throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coin failed"); | 
| 338 | 0 |         } else { | 
| 339 | 0 |             if (!pwallet->LockCoin(outpt, persistent)) throw JSONRPCError(RPC_WALLET_ERROR, "Locking coin failed"); | 
| 340 | 0 |         } | 
| 341 | 0 |     } | 
| 342 |  |  | 
| 343 | 0 |     return true; | 
| 344 | 0 | }, | 
| 345 | 0 |     }; | 
| 346 | 0 | } | 
| 347 |  |  | 
| 348 |  | RPCHelpMan listlockunspent() | 
| 349 | 0 | { | 
| 350 | 0 |     return RPCHelpMan{ | 
| 351 | 0 |         "listlockunspent", | 
| 352 | 0 |         "Returns list of temporarily unspendable outputs.\n" | 
| 353 | 0 |                 "See the lockunspent call to lock and unlock transactions for spending.\n", | 
| 354 | 0 |                 {}, | 
| 355 | 0 |                 RPCResult{ | 
| 356 | 0 |                     RPCResult::Type::ARR, "", "", | 
| 357 | 0 |                     { | 
| 358 | 0 |                         {RPCResult::Type::OBJ, "", "", | 
| 359 | 0 |                         { | 
| 360 | 0 |                             {RPCResult::Type::STR_HEX, "txid", "The transaction id locked"}, | 
| 361 | 0 |                             {RPCResult::Type::NUM, "vout", "The vout value"}, | 
| 362 | 0 |                         }}, | 
| 363 | 0 |                     } | 
| 364 | 0 |                 }, | 
| 365 | 0 |                 RPCExamples{ | 
| 366 | 0 |             "\nList the unspent transactions\n" | 
| 367 | 0 |             + HelpExampleCli("listunspent", "") + | 
| 368 | 0 |             "\nLock an unspent transaction\n" | 
| 369 | 0 |             + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + | 
| 370 | 0 |             "\nList the locked transactions\n" | 
| 371 | 0 |             + HelpExampleCli("listlockunspent", "") + | 
| 372 | 0 |             "\nUnlock the transaction again\n" | 
| 373 | 0 |             + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") + | 
| 374 | 0 |             "\nAs a JSON-RPC call\n" | 
| 375 | 0 |             + HelpExampleRpc("listlockunspent", "") | 
| 376 | 0 |                 }, | 
| 377 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 378 | 0 | { | 
| 379 | 0 |     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); | 
| 380 | 0 |     if (!pwallet) return UniValue::VNULL; | 
| 381 |  |  | 
| 382 | 0 |     LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 383 |  | 
 | 
| 384 | 0 |     std::vector<COutPoint> vOutpts; | 
| 385 | 0 |     pwallet->ListLockedCoins(vOutpts); | 
| 386 |  | 
 | 
| 387 | 0 |     UniValue ret(UniValue::VARR); | 
| 388 |  | 
 | 
| 389 | 0 |     for (const COutPoint& outpt : vOutpts) { | 
| 390 | 0 |         UniValue o(UniValue::VOBJ); | 
| 391 |  | 
 | 
| 392 | 0 |         o.pushKV("txid", outpt.hash.GetHex()); | 
| 393 | 0 |         o.pushKV("vout", (int)outpt.n); | 
| 394 | 0 |         ret.push_back(std::move(o)); | 
| 395 | 0 |     } | 
| 396 |  | 
 | 
| 397 | 0 |     return ret; | 
| 398 | 0 | }, | 
| 399 | 0 |     }; | 
| 400 | 0 | } | 
| 401 |  |  | 
| 402 |  | RPCHelpMan getbalances() | 
| 403 | 0 | { | 
| 404 | 0 |     return RPCHelpMan{ | 
| 405 | 0 |         "getbalances", | 
| 406 | 0 |         "Returns an object with all balances in " + CURRENCY_UNIT + ".\n", | 
| 407 | 0 |         {}, | 
| 408 | 0 |         RPCResult{ | 
| 409 | 0 |             RPCResult::Type::OBJ, "", "", | 
| 410 | 0 |             { | 
| 411 | 0 |                 {RPCResult::Type::OBJ, "mine", "balances from outputs that the wallet can sign", | 
| 412 | 0 |                 { | 
| 413 | 0 |                     {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"}, | 
| 414 | 0 |                     {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"}, | 
| 415 | 0 |                     {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"}, | 
| 416 | 0 |                     {RPCResult::Type::STR_AMOUNT, "used", /*optional=*/true, "(only present if avoid_reuse is set) balance from coins sent to addresses that were previously spent from (potentially privacy violating)"}, | 
| 417 | 0 |                 }}, | 
| 418 | 0 |                 RESULT_LAST_PROCESSED_BLOCK, | 
| 419 | 0 |             } | 
| 420 | 0 |             }, | 
| 421 | 0 |         RPCExamples{ | 
| 422 | 0 |             HelpExampleCli("getbalances", "") + | 
| 423 | 0 |             HelpExampleRpc("getbalances", "")}, | 
| 424 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 425 | 0 | { | 
| 426 | 0 |     const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request); | 
| 427 | 0 |     if (!rpc_wallet) return UniValue::VNULL; | 
| 428 | 0 |     const CWallet& wallet = *rpc_wallet; | 
| 429 |  |  | 
| 430 |  |     // Make sure the results are valid at least up to the most recent block | 
| 431 |  |     // the user could have gotten from another RPC command prior to now | 
| 432 | 0 |     wallet.BlockUntilSyncedToCurrentChain(); | 
| 433 |  | 
 | 
| 434 | 0 |     LOCK(wallet.cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 435 |  | 
 | 
| 436 | 0 |     const auto bal = GetBalance(wallet); | 
| 437 | 0 |     UniValue balances{UniValue::VOBJ}; | 
| 438 | 0 |     { | 
| 439 | 0 |         UniValue balances_mine{UniValue::VOBJ}; | 
| 440 | 0 |         balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted)); | 
| 441 | 0 |         balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending)); | 
| 442 | 0 |         balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature)); | 
| 443 | 0 |         if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) { | 
| 444 |  |             // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get | 
| 445 |  |             // the total balance, and then subtract bal to get the reused address balance. | 
| 446 | 0 |             const auto full_bal = GetBalance(wallet, 0, false); | 
| 447 | 0 |             balances_mine.pushKV("used", ValueFromAmount(full_bal.m_mine_trusted + full_bal.m_mine_untrusted_pending - bal.m_mine_trusted - bal.m_mine_untrusted_pending)); | 
| 448 | 0 |         } | 
| 449 | 0 |         balances.pushKV("mine", std::move(balances_mine)); | 
| 450 | 0 |     } | 
| 451 | 0 |     AppendLastProcessedBlock(balances, wallet); | 
| 452 | 0 |     return balances; | 
| 453 | 0 | }, | 
| 454 | 0 |     }; | 
| 455 | 0 | } | 
| 456 |  |  | 
| 457 |  | RPCHelpMan listunspent() | 
| 458 | 0 | { | 
| 459 | 0 |     return RPCHelpMan{ | 
| 460 | 0 |         "listunspent", | 
| 461 | 0 |         "Returns array of unspent transaction outputs\n" | 
| 462 | 0 |                 "with between minconf and maxconf (inclusive) confirmations.\n" | 
| 463 | 0 |                 "Optionally filter to only include txouts paid to specified addresses.\n", | 
| 464 | 0 |                 { | 
| 465 | 0 |                     {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum confirmations to filter"}, | 
| 466 | 0 |                     {"maxconf", RPCArg::Type::NUM, RPCArg::Default{9999999}, "The maximum confirmations to filter"}, | 
| 467 | 0 |                     {"addresses", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The bitcoin addresses to filter", | 
| 468 | 0 |                         { | 
| 469 | 0 |                             {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"}, | 
| 470 | 0 |                         }, | 
| 471 | 0 |                     }, | 
| 472 | 0 |                     {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n" | 
| 473 | 0 |                               "See description of \"safe\" attribute below."}, | 
| 474 | 0 |                     {"query_options", RPCArg::Type::OBJ_NAMED_PARAMS, RPCArg::Optional::OMITTED, "", | 
| 475 | 0 |                         { | 
| 476 | 0 |                             {"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""}, | 
| 477 | 0 |                             {"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""}, | 
| 478 | 0 |                             {"maximumCount", RPCArg::Type::NUM, RPCArg::DefaultHint{"unlimited"}, "Maximum number of UTXOs"}, | 
| 479 | 0 |                             {"minimumSumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""}, | 
| 480 | 0 |                             {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase UTXOs"} | 
| 481 | 0 |                         }, | 
| 482 | 0 |                         RPCArgOptions{.oneline_description="query_options"}}, | 
| 483 | 0 |                 }, | 
| 484 | 0 |                 RPCResult{ | 
| 485 | 0 |                     RPCResult::Type::ARR, "", "", | 
| 486 | 0 |                     { | 
| 487 | 0 |                         {RPCResult::Type::OBJ, "", "", | 
| 488 | 0 |                         { | 
| 489 | 0 |                             {RPCResult::Type::STR_HEX, "txid", "the transaction id"}, | 
| 490 | 0 |                             {RPCResult::Type::NUM, "vout", "the vout value"}, | 
| 491 | 0 |                             {RPCResult::Type::STR, "address", /*optional=*/true, "the bitcoin address"}, | 
| 492 | 0 |                             {RPCResult::Type::STR, "label", /*optional=*/true, "The associated label, or \"\" for the default label"}, | 
| 493 | 0 |                             {RPCResult::Type::STR, "scriptPubKey", "the output script"}, | 
| 494 | 0 |                             {RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT}, | 
| 495 | 0 |                             {RPCResult::Type::NUM, "confirmations", "The number of confirmations"}, | 
| 496 | 0 |                             {RPCResult::Type::NUM, "ancestorcount", /*optional=*/true, "The number of in-mempool ancestor transactions, including this one (if transaction is in the mempool)"}, | 
| 497 | 0 |                             {RPCResult::Type::NUM, "ancestorsize", /*optional=*/true, "The virtual transaction size of in-mempool ancestors, including this one (if transaction is in the mempool)"}, | 
| 498 | 0 |                             {RPCResult::Type::STR_AMOUNT, "ancestorfees", /*optional=*/true, "The total fees of in-mempool ancestors (including this one) with fee deltas used for mining priority in " + CURRENCY_ATOM + " (if transaction is in the mempool)"}, | 
| 499 | 0 |                             {RPCResult::Type::STR_HEX, "redeemScript", /*optional=*/true, "The redeem script if the output script is P2SH"}, | 
| 500 | 0 |                             {RPCResult::Type::STR, "witnessScript", /*optional=*/true, "witness script if the output script is P2WSH or P2SH-P2WSH"}, | 
| 501 | 0 |                             {RPCResult::Type::BOOL, "spendable", "(DEPRECATED) Always true"}, | 
| 502 | 0 |                             {RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"}, | 
| 503 | 0 |                             {RPCResult::Type::BOOL, "reused", /*optional=*/true, "(only present if avoid_reuse is set) Whether this output is reused/dirty (sent to an address that was previously spent from)"}, | 
| 504 | 0 |                             {RPCResult::Type::STR, "desc", /*optional=*/true, "(only when solvable) A descriptor for spending this output"}, | 
| 505 | 0 |                             {RPCResult::Type::ARR, "parent_descs", /*optional=*/false, "List of parent descriptors for the output script of this coin.", { | 
| 506 | 0 |                                 {RPCResult::Type::STR, "desc", "The descriptor string."}, | 
| 507 | 0 |                             }}, | 
| 508 | 0 |                             {RPCResult::Type::BOOL, "safe", "Whether this output is considered safe to spend. Unconfirmed transactions\n" | 
| 509 | 0 |                                                             "from outside keys and unconfirmed replacement transactions are considered unsafe\n" | 
| 510 | 0 |                                                             "and are not eligible for spending by fundrawtransaction and sendtoaddress."}, | 
| 511 | 0 |                         }}, | 
| 512 | 0 |                     } | 
| 513 | 0 |                 }, | 
| 514 | 0 |                 RPCExamples{ | 
| 515 | 0 |                     HelpExampleCli("listunspent", "") | 
| 516 | 0 |             + HelpExampleCli("listunspent", "6 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") | 
| 517 | 0 |             + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") | 
| 518 | 0 |             + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'") | 
| 519 | 0 |             + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ") | 
| 520 | 0 |                 }, | 
| 521 | 0 |         [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue | 
| 522 | 0 | { | 
| 523 | 0 |     const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request); | 
| 524 | 0 |     if (!pwallet) return UniValue::VNULL; | 
| 525 |  |  | 
| 526 | 0 |     int nMinDepth = 1; | 
| 527 | 0 |     if (!request.params[0].isNull()) { | 
| 528 | 0 |         nMinDepth = request.params[0].getInt<int>(); | 
| 529 | 0 |     } | 
| 530 |  | 
 | 
| 531 | 0 |     int nMaxDepth = 9999999; | 
| 532 | 0 |     if (!request.params[1].isNull()) { | 
| 533 | 0 |         nMaxDepth = request.params[1].getInt<int>(); | 
| 534 | 0 |     } | 
| 535 |  | 
 | 
| 536 | 0 |     std::set<CTxDestination> destinations; | 
| 537 | 0 |     if (!request.params[2].isNull()) { | 
| 538 | 0 |         UniValue inputs = request.params[2].get_array(); | 
| 539 | 0 |         for (unsigned int idx = 0; idx < inputs.size(); idx++) { | 
| 540 | 0 |             const UniValue& input = inputs[idx]; | 
| 541 | 0 |             CTxDestination dest = DecodeDestination(input.get_str()); | 
| 542 | 0 |             if (!IsValidDestination(dest)) { | 
| 543 | 0 |                 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str()); | 
| 544 | 0 |             } | 
| 545 | 0 |             if (!destinations.insert(dest).second) { | 
| 546 | 0 |                 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str()); | 
| 547 | 0 |             } | 
| 548 | 0 |         } | 
| 549 | 0 |     } | 
| 550 |  |  | 
| 551 | 0 |     bool include_unsafe = true; | 
| 552 | 0 |     if (!request.params[3].isNull()) { | 
| 553 | 0 |         include_unsafe = request.params[3].get_bool(); | 
| 554 | 0 |     } | 
| 555 |  | 
 | 
| 556 | 0 |     CoinFilterParams filter_coins; | 
| 557 | 0 |     filter_coins.min_amount = 0; | 
| 558 |  | 
 | 
| 559 | 0 |     if (!request.params[4].isNull()) { | 
| 560 | 0 |         const UniValue& options = request.params[4].get_obj(); | 
| 561 |  | 
 | 
| 562 | 0 |         RPCTypeCheckObj(options, | 
| 563 | 0 |             { | 
| 564 | 0 |                 {"minimumAmount", UniValueType()}, | 
| 565 | 0 |                 {"maximumAmount", UniValueType()}, | 
| 566 | 0 |                 {"minimumSumAmount", UniValueType()}, | 
| 567 | 0 |                 {"maximumCount", UniValueType(UniValue::VNUM)}, | 
| 568 | 0 |                 {"include_immature_coinbase", UniValueType(UniValue::VBOOL)} | 
| 569 | 0 |             }, | 
| 570 | 0 |             true, true); | 
| 571 |  | 
 | 
| 572 | 0 |         if (options.exists("minimumAmount")) | 
| 573 | 0 |             filter_coins.min_amount = AmountFromValue(options["minimumAmount"]); | 
| 574 |  | 
 | 
| 575 | 0 |         if (options.exists("maximumAmount")) | 
| 576 | 0 |             filter_coins.max_amount = AmountFromValue(options["maximumAmount"]); | 
| 577 |  | 
 | 
| 578 | 0 |         if (options.exists("minimumSumAmount")) | 
| 579 | 0 |             filter_coins.min_sum_amount = AmountFromValue(options["minimumSumAmount"]); | 
| 580 |  | 
 | 
| 581 | 0 |         if (options.exists("maximumCount")) | 
| 582 | 0 |             filter_coins.max_count = options["maximumCount"].getInt<int64_t>(); | 
| 583 |  | 
 | 
| 584 | 0 |         if (options.exists("include_immature_coinbase")) { | 
| 585 | 0 |             filter_coins.include_immature_coinbase = options["include_immature_coinbase"].get_bool(); | 
| 586 | 0 |         } | 
| 587 | 0 |     } | 
| 588 |  |  | 
| 589 |  |     // Make sure the results are valid at least up to the most recent block | 
| 590 |  |     // the user could have gotten from another RPC command prior to now | 
| 591 | 0 |     pwallet->BlockUntilSyncedToCurrentChain(); | 
| 592 |  | 
 | 
| 593 | 0 |     UniValue results(UniValue::VARR); | 
| 594 | 0 |     std::vector<COutput> vecOutputs; | 
| 595 | 0 |     { | 
| 596 | 0 |         CCoinControl cctl; | 
| 597 | 0 |         cctl.m_avoid_address_reuse = false; | 
| 598 | 0 |         cctl.m_min_depth = nMinDepth; | 
| 599 | 0 |         cctl.m_max_depth = nMaxDepth; | 
| 600 | 0 |         cctl.m_include_unsafe_inputs = include_unsafe; | 
| 601 | 0 |         filter_coins.check_version_trucness = false; | 
| 602 | 0 |         LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 603 | 0 |         vecOutputs = AvailableCoins(*pwallet, &cctl, /*feerate=*/std::nullopt, filter_coins).All(); | 
| 604 | 0 |     } | 
| 605 |  | 
 | 
| 606 | 0 |     LOCK(pwallet->cs_wallet); | Line | Count | Source |  | 259 | 0 | #define LOCK(cs) UniqueLock UNIQUE_NAME(criticalblock)(MaybeCheckNotHeld(cs), #cs, __FILE__, __LINE__) | Line | Count | Source |  | 11 | 0 | #define UNIQUE_NAME(name) PASTE2(name, __COUNTER__) | Line | Count | Source |  | 9 | 0 | #define PASTE2(x, y) PASTE(x, y) | Line | Count | Source |  | 8 | 0 | #define PASTE(x, y) x ## y | 
 | 
 | 
 | 
 | 
| 607 |  | 
 | 
| 608 | 0 |     const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE); | 
| 609 |  | 
 | 
| 610 | 0 |     for (const COutput& out : vecOutputs) { | 
| 611 | 0 |         CTxDestination address; | 
| 612 | 0 |         const CScript& scriptPubKey = out.txout.scriptPubKey; | 
| 613 | 0 |         bool fValidAddress = ExtractDestination(scriptPubKey, address); | 
| 614 | 0 |         bool reused = avoid_reuse && pwallet->IsSpentKey(scriptPubKey); | 
| 615 |  | 
 | 
| 616 | 0 |         if (destinations.size() && (!fValidAddress || !destinations.count(address))) | 
| 617 | 0 |             continue; | 
| 618 |  |  | 
| 619 | 0 |         UniValue entry(UniValue::VOBJ); | 
| 620 | 0 |         entry.pushKV("txid", out.outpoint.hash.GetHex()); | 
| 621 | 0 |         entry.pushKV("vout", (int)out.outpoint.n); | 
| 622 |  | 
 | 
| 623 | 0 |         if (fValidAddress) { | 
| 624 | 0 |             entry.pushKV("address", EncodeDestination(address)); | 
| 625 |  | 
 | 
| 626 | 0 |             const auto* address_book_entry = pwallet->FindAddressBookEntry(address); | 
| 627 | 0 |             if (address_book_entry) { | 
| 628 | 0 |                 entry.pushKV("label", address_book_entry->GetLabel()); | 
| 629 | 0 |             } | 
| 630 |  | 
 | 
| 631 | 0 |             std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey); | 
| 632 | 0 |             if (provider) { | 
| 633 | 0 |                 if (scriptPubKey.IsPayToScriptHash()) { | 
| 634 | 0 |                     const CScriptID hash = ToScriptID(std::get<ScriptHash>(address)); | 
| 635 | 0 |                     CScript redeemScript; | 
| 636 | 0 |                     if (provider->GetCScript(hash, redeemScript)) { | 
| 637 | 0 |                         entry.pushKV("redeemScript", HexStr(redeemScript)); | 
| 638 |  |                         // Now check if the redeemScript is actually a P2WSH script | 
| 639 | 0 |                         CTxDestination witness_destination; | 
| 640 | 0 |                         if (redeemScript.IsPayToWitnessScriptHash()) { | 
| 641 | 0 |                             bool extracted = ExtractDestination(redeemScript, witness_destination); | 
| 642 | 0 |                             CHECK_NONFATAL(extracted); | Line | Count | Source |  | 103 | 0 |     inline_check_non_fatal(condition, __FILE__, __LINE__, __func__, #condition) | 
 | 
| 643 |  |                             // Also return the witness script | 
| 644 | 0 |                             const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(witness_destination); | 
| 645 | 0 |                             CScriptID id{RIPEMD160(whash)}; | 
| 646 | 0 |                             CScript witnessScript; | 
| 647 | 0 |                             if (provider->GetCScript(id, witnessScript)) { | 
| 648 | 0 |                                 entry.pushKV("witnessScript", HexStr(witnessScript)); | 
| 649 | 0 |                             } | 
| 650 | 0 |                         } | 
| 651 | 0 |                     } | 
| 652 | 0 |                 } else if (scriptPubKey.IsPayToWitnessScriptHash()) { | 
| 653 | 0 |                     const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(address); | 
| 654 | 0 |                     CScriptID id{RIPEMD160(whash)}; | 
| 655 | 0 |                     CScript witnessScript; | 
| 656 | 0 |                     if (provider->GetCScript(id, witnessScript)) { | 
| 657 | 0 |                         entry.pushKV("witnessScript", HexStr(witnessScript)); | 
| 658 | 0 |                     } | 
| 659 | 0 |                 } | 
| 660 | 0 |             } | 
| 661 | 0 |         } | 
| 662 |  | 
 | 
| 663 | 0 |         entry.pushKV("scriptPubKey", HexStr(scriptPubKey)); | 
| 664 | 0 |         entry.pushKV("amount", ValueFromAmount(out.txout.nValue)); | 
| 665 | 0 |         entry.pushKV("confirmations", out.depth); | 
| 666 | 0 |         if (!out.depth) { | 
| 667 | 0 |             size_t ancestor_count, descendant_count, ancestor_size; | 
| 668 | 0 |             CAmount ancestor_fees; | 
| 669 | 0 |             pwallet->chain().getTransactionAncestry(out.outpoint.hash, ancestor_count, descendant_count, &ancestor_size, &ancestor_fees); | 
| 670 | 0 |             if (ancestor_count) { | 
| 671 | 0 |                 entry.pushKV("ancestorcount", uint64_t(ancestor_count)); | 
| 672 | 0 |                 entry.pushKV("ancestorsize", uint64_t(ancestor_size)); | 
| 673 | 0 |                 entry.pushKV("ancestorfees", uint64_t(ancestor_fees)); | 
| 674 | 0 |             } | 
| 675 | 0 |         } | 
| 676 | 0 |         entry.pushKV("spendable", true); // Any coins we list are always spendable | 
| 677 | 0 |         entry.pushKV("solvable", out.solvable); | 
| 678 | 0 |         if (out.solvable) { | 
| 679 | 0 |             std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey); | 
| 680 | 0 |             if (provider) { | 
| 681 | 0 |                 auto descriptor = InferDescriptor(scriptPubKey, *provider); | 
| 682 | 0 |                 entry.pushKV("desc", descriptor->ToString()); | 
| 683 | 0 |             } | 
| 684 | 0 |         } | 
| 685 | 0 |         PushParentDescriptors(*pwallet, scriptPubKey, entry); | 
| 686 | 0 |         if (avoid_reuse) entry.pushKV("reused", reused); | 
| 687 | 0 |         entry.pushKV("safe", out.safe); | 
| 688 | 0 |         results.push_back(std::move(entry)); | 
| 689 | 0 |     } | 
| 690 |  | 
 | 
| 691 | 0 |     return results; | 
| 692 | 0 | }, | 
| 693 | 0 |     }; | 
| 694 | 0 | } | 
| 695 |  | } // namespace wallet |