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