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