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