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