coins.cpp raw
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 RPCMethod getreceivedbyaddress()
81 {
82 return RPCMethod{
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 RPCMethod& 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 RPCMethod getreceivedbylabel()
123 {
124 return RPCMethod{
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 RPCMethod& 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 RPCMethod getbalance()
165 {
166 return RPCMethod{
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 RPCMethod& 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 RPCMethod lockunspent()
215 {
216 return RPCMethod{
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 RPCMethod& 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 RPCMethod listlockunspent()
348 {
349 return RPCMethod{
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 RPCMethod& 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 RPCMethod getbalances()
402 {
403 return RPCMethod{
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, "nonmempool", "sum of coins that are spent by transactions not in the mempool (usually an over-estimate due to not accounting for change or spends that conflict with each other)"},
416 {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 }},
418 RESULT_LAST_PROCESSED_BLOCK,
419 }
420 },
421 RPCExamples{
422 HelpExampleCli("getbalances", "") +
423 HelpExampleRpc("getbalances", "")},
424 [](const RPCMethod& self, const JSONRPCRequest& request) -> UniValue
425 {
426 const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
427 if (!rpc_wallet) return UniValue::VNULL;
428 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 wallet.BlockUntilSyncedToCurrentChain();
433
434 LOCK(wallet.cs_wallet);
435
436 const auto bal = GetBalance(wallet, /*min_depth=*/0, /*avoid_reuse=*/true, /*include_nonmempool=*/true);
437
438 UniValue balances{UniValue::VOBJ};
439 {
440 UniValue balances_mine{UniValue::VOBJ};
441 balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
442 balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
443 balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
444 balances_mine.pushKV("nonmempool", ValueFromAmount(bal.m_mine_nonmempool));
445 if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
446 balances_mine.pushKV("used", ValueFromAmount(bal.m_mine_used));
447 }
448 balances.pushKV("mine", std::move(balances_mine));
449 }
450 AppendLastProcessedBlock(balances, wallet);
451 return balances;
452 },
453 };
454 }
455
456 RPCMethod listunspent()
457 {
458 return RPCMethod{
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 RPCMethod& 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
695