Bitcoin Core 22.99.0
P2P Digital Currency
rpcwallet.cpp
Go to the documentation of this file.
1// Copyright (c) 2010 Satoshi Nakamoto
2// Copyright (c) 2009-2020 The Bitcoin Core developers
3// Distributed under the MIT software license, see the accompanying
4// file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6#include <consensus/amount.h>
7#include <core_io.h>
8#include <interfaces/chain.h>
9#include <key_io.h>
10#include <node/context.h>
11#include <outputtype.h>
12#include <policy/feerate.h>
13#include <policy/fees.h>
14#include <policy/policy.h>
15#include <policy/rbf.h>
17#include <rpc/server.h>
18#include <rpc/util.h>
19#include <script/descriptor.h>
20#include <script/sign.h>
21#include <util/bip32.h>
22#include <util/fees.h>
23#include <util/message.h> // For MessageSign()
24#include <util/moneystr.h>
25#include <util/string.h>
26#include <util/system.h>
27#include <util/translation.h>
28#include <util/url.h>
29#include <util/vector.h>
30#include <wallet/coincontrol.h>
31#include <wallet/context.h>
32#include <wallet/feebumper.h>
33#include <wallet/load.h>
34#include <wallet/receive.h>
35#include <wallet/rpcwallet.h>
36#include <wallet/spend.h>
37#include <wallet/wallet.h>
38#include <wallet/walletdb.h>
39#include <wallet/walletutil.h>
40
41#include <optional>
42#include <stdint.h>
43
44#include <univalue.h>
45
46#include <map>
47
49
50static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
51static const std::string HELP_REQUIRING_PASSPHRASE{"\nRequires wallet passphrase to be set with walletpassphrase call if wallet is encrypted.\n"};
52
53static inline bool GetAvoidReuseFlag(const CWallet& wallet, const UniValue& param) {
54 bool can_avoid_reuse = wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
55 bool avoid_reuse = param.isNull() ? can_avoid_reuse : param.get_bool();
56
57 if (avoid_reuse && !can_avoid_reuse) {
58 throw JSONRPCError(RPC_WALLET_ERROR, "wallet does not have the \"avoid reuse\" feature enabled");
59 }
60
61 return avoid_reuse;
62}
63
64
69static bool ParseIncludeWatchonly(const UniValue& include_watchonly, const CWallet& wallet)
70{
71 if (include_watchonly.isNull()) {
72 // if include_watchonly isn't explicitly set, then check if we have a watchonly wallet
73 return wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
74 }
75
76 // otherwise return whatever include_watchonly was set to
77 return include_watchonly.get_bool();
78}
79
80
82bool HaveKey(const SigningProvider& wallet, const CKey& key)
83{
84 CKey key2;
85 key2.Set(key.begin(), key.end(), !key.IsCompressed());
86 return wallet.HaveKey(key.GetPubKey().GetID()) || wallet.HaveKey(key2.GetPubKey().GetID());
87}
88
89bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest& request, std::string& wallet_name)
90{
91 if (URL_DECODE && request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) == WALLET_ENDPOINT_BASE) {
92 // wallet endpoint was used
93 wallet_name = URL_DECODE(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
94 return true;
95 }
96 return false;
97}
98
99std::shared_ptr<CWallet> GetWalletForJSONRPCRequest(const JSONRPCRequest& request)
100{
102 WalletContext& context = EnsureWalletContext(request.context);
103
104 std::string wallet_name;
105 if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
106 const std::shared_ptr<CWallet> pwallet = GetWallet(context, wallet_name);
107 if (!pwallet) throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
108 return pwallet;
109 }
110
111 std::vector<std::shared_ptr<CWallet>> wallets = GetWallets(context);
112 if (wallets.size() == 1) {
113 return wallets[0];
114 }
115
116 if (wallets.empty()) {
117 throw JSONRPCError(
118 RPC_WALLET_NOT_FOUND, "No wallet is loaded. Load a wallet using loadwallet or create a new one with createwallet. (Note: A default wallet is no longer automatically created)");
119 }
121 "Wallet file not specified (must request wallet RPC through /wallet/<filename> uri-path).");
122}
123
125{
126 if (wallet.IsLocked()) {
127 throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
128 }
129}
130
131WalletContext& EnsureWalletContext(const std::any& context)
132{
133 auto wallet_context = util::AnyPtr<WalletContext>(context);
134 if (!wallet_context) {
135 throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
136 }
137 return *wallet_context;
138}
139
140// also_create should only be set to true only when the RPC is expected to add things to a blank wallet and make it no longer blank
142{
143 LegacyScriptPubKeyMan* spk_man = wallet.GetLegacyScriptPubKeyMan();
144 if (!spk_man && also_create) {
145 spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
146 }
147 if (!spk_man) {
148 throw JSONRPCError(RPC_WALLET_ERROR, "This type of wallet does not support this command");
149 }
150 return *spk_man;
151}
152
153static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue& entry)
154{
155 interfaces::Chain& chain = wallet.chain();
156 int confirms = wallet.GetTxDepthInMainChain(wtx);
157 entry.pushKV("confirmations", confirms);
158 if (wtx.IsCoinBase())
159 entry.pushKV("generated", true);
160 if (confirms > 0)
161 {
162 entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
163 entry.pushKV("blockheight", wtx.m_confirm.block_height);
164 entry.pushKV("blockindex", wtx.m_confirm.nIndex);
165 int64_t block_time;
166 CHECK_NONFATAL(chain.findBlock(wtx.m_confirm.hashBlock, FoundBlock().time(block_time)));
167 entry.pushKV("blocktime", block_time);
168 } else {
169 entry.pushKV("trusted", CachedTxIsTrusted(wallet, wtx));
170 }
171 uint256 hash = wtx.GetHash();
172 entry.pushKV("txid", hash.GetHex());
173 UniValue conflicts(UniValue::VARR);
174 for (const uint256& conflict : wallet.GetTxConflicts(wtx))
175 conflicts.push_back(conflict.GetHex());
176 entry.pushKV("walletconflicts", conflicts);
177 entry.pushKV("time", wtx.GetTxTime());
178 entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
179
180 // Add opt-in RBF status
181 std::string rbfStatus = "no";
182 if (confirms <= 0) {
183 RBFTransactionState rbfState = chain.isRBFOptIn(*wtx.tx);
184 if (rbfState == RBFTransactionState::UNKNOWN)
185 rbfStatus = "unknown";
186 else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
187 rbfStatus = "yes";
188 }
189 entry.pushKV("bip125-replaceable", rbfStatus);
190
191 for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
192 entry.pushKV(item.first, item.second);
193}
194
195static std::string LabelFromValue(const UniValue& value)
196{
197 std::string label = value.get_str();
198 if (label == "*")
199 throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
200 return label;
201}
202
216static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, bool override_min_fee)
217{
218 if (!fee_rate.isNull()) {
219 if (!conf_target.isNull()) {
220 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
221 }
222 if (!estimate_mode.isNull() && estimate_mode.get_str() != "unset") {
223 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate");
224 }
225 // Fee rates in sat/vB cannot represent more than 3 significant digits.
226 cc.m_feerate = CFeeRate{AmountFromValue(fee_rate, /* decimals */ 3)};
227 if (override_min_fee) cc.fOverrideFeeRate = true;
228 // Default RBF to true for explicit fee_rate, if unset.
229 if (!cc.m_signal_bip125_rbf) cc.m_signal_bip125_rbf = true;
230 return;
231 }
232 if (!estimate_mode.isNull() && !FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
234 }
235 if (!conf_target.isNull()) {
236 cc.m_confirm_target = ParseConfirmTarget(conf_target, wallet.chain().estimateMaxBlocks());
237 }
238}
239
241{
242 return RPCHelpMan{"getnewaddress",
243 "\nReturns a new Bitcoin address for receiving payments.\n"
244 "If 'label' is specified, it is added to the address book \n"
245 "so payments received with the address will be associated with 'label'.\n",
246 {
247 {"label", RPCArg::Type::STR, RPCArg::Default{""}, "The label name for the address to be linked to. It can also be set to the empty string \"\" to represent the default label. The label does not need to exist, it will be created if there is no label by the given name."},
248 {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
249 },
250 RPCResult{
251 RPCResult::Type::STR, "address", "The new bitcoin address"
252 },
254 HelpExampleCli("getnewaddress", "")
255 + HelpExampleRpc("getnewaddress", "")
256 },
257 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
258{
259 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
260 if (!pwallet) return NullUniValue;
261
262 LOCK(pwallet->cs_wallet);
263
264 if (!pwallet->CanGetAddresses()) {
265 throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
266 }
267
268 // Parse the label first so we don't generate a key if there's an error
269 std::string label;
270 if (!request.params[0].isNull())
271 label = LabelFromValue(request.params[0]);
272
273 OutputType output_type = pwallet->m_default_address_type;
274 if (!request.params[1].isNull()) {
275 std::optional<OutputType> parsed = ParseOutputType(request.params[1].get_str());
276 if (!parsed) {
277 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[1].get_str()));
278 } else if (parsed.value() == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
279 throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
280 }
281 output_type = parsed.value();
282 }
283
284 CTxDestination dest;
286 if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
288 }
289
290 return EncodeDestination(dest);
291},
292 };
293}
294
296{
297 return RPCHelpMan{"getrawchangeaddress",
298 "\nReturns a new Bitcoin address, for receiving change.\n"
299 "This is for use with raw transactions, NOT normal use.\n",
300 {
301 {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
302 },
303 RPCResult{
304 RPCResult::Type::STR, "address", "The address"
305 },
307 HelpExampleCli("getrawchangeaddress", "")
308 + HelpExampleRpc("getrawchangeaddress", "")
309 },
310 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
311{
312 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
313 if (!pwallet) return NullUniValue;
314
315 LOCK(pwallet->cs_wallet);
316
317 if (!pwallet->CanGetAddresses(true)) {
318 throw JSONRPCError(RPC_WALLET_ERROR, "Error: This wallet has no available keys");
319 }
320
321 OutputType output_type = pwallet->m_default_change_type.value_or(pwallet->m_default_address_type);
322 if (!request.params[0].isNull()) {
323 std::optional<OutputType> parsed = ParseOutputType(request.params[0].get_str());
324 if (!parsed) {
325 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[0].get_str()));
326 } else if (parsed.value() == OutputType::BECH32M && pwallet->GetLegacyScriptPubKeyMan()) {
327 throw JSONRPCError(RPC_INVALID_PARAMETER, "Legacy wallets cannot provide bech32m addresses");
328 }
329 output_type = parsed.value();
330 }
331
332 CTxDestination dest;
334 if (!pwallet->GetNewChangeDestination(output_type, dest, error)) {
336 }
337 return EncodeDestination(dest);
338},
339 };
340}
341
342
344{
345 return RPCHelpMan{"setlabel",
346 "\nSets the label associated with the given address.\n",
347 {
348 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to be associated with a label."},
349 {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."},
350 },
353 HelpExampleCli("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\" \"tabby\"")
354 + HelpExampleRpc("setlabel", "\"" + EXAMPLE_ADDRESS[0] + "\", \"tabby\"")
355 },
356 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
357{
358 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
359 if (!pwallet) return NullUniValue;
360
361 LOCK(pwallet->cs_wallet);
362
363 CTxDestination dest = DecodeDestination(request.params[0].get_str());
364 if (!IsValidDestination(dest)) {
365 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
366 }
367
368 std::string label = LabelFromValue(request.params[1]);
369
370 if (pwallet->IsMine(dest)) {
371 pwallet->SetAddressBook(dest, label, "receive");
372 } else {
373 pwallet->SetAddressBook(dest, label, "send");
374 }
375
376 return NullUniValue;
377},
378 };
379}
380
381void ParseRecipients(const UniValue& address_amounts, const UniValue& subtract_fee_outputs, std::vector<CRecipient> &recipients) {
382 std::set<CTxDestination> destinations;
383 int i = 0;
384 for (const std::string& address: address_amounts.getKeys()) {
385 CTxDestination dest = DecodeDestination(address);
386 if (!IsValidDestination(dest)) {
387 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + address);
388 }
389
390 if (destinations.count(dest)) {
391 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + address);
392 }
393 destinations.insert(dest);
394
395 CScript script_pub_key = GetScriptForDestination(dest);
396 CAmount amount = AmountFromValue(address_amounts[i++]);
397
398 bool subtract_fee = false;
399 for (unsigned int idx = 0; idx < subtract_fee_outputs.size(); idx++) {
400 const UniValue& addr = subtract_fee_outputs[idx];
401 if (addr.get_str() == address) {
402 subtract_fee = true;
403 }
404 }
405
406 CRecipient recipient = {script_pub_key, amount, subtract_fee};
407 recipients.push_back(recipient);
408 }
409}
410
411UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vector<CRecipient> &recipients, mapValue_t map_value, bool verbose)
412{
414
415 // This function is only used by sendtoaddress and sendmany.
416 // This should always try to sign, if we don't have private keys, don't try to do anything here.
417 if (wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
418 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
419 }
420
421 // Shuffle recipient list
422 std::shuffle(recipients.begin(), recipients.end(), FastRandomContext());
423
424 // Send
425 CAmount nFeeRequired = 0;
426 int nChangePosRet = -1;
429 FeeCalculation fee_calc_out;
430 const bool fCreated = CreateTransaction(wallet, recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true);
431 if (!fCreated) {
433 }
434 wallet.CommitTransaction(tx, std::move(map_value), {} /* orderForm */);
435 if (verbose) {
437 entry.pushKV("txid", tx->GetHash().GetHex());
438 entry.pushKV("fee_reason", StringForFeeReason(fee_calc_out.reason));
439 return entry;
440 }
441 return tx->GetHash().GetHex();
442}
443
445{
446 return RPCHelpMan{"sendtoaddress",
447 "\nSend an amount to a given address." +
449 {
450 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."},
451 {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
452 {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
453 "This is not part of the transaction, just kept in your wallet."},
454 {"comment_to", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment to store the name of the person or organization\n"
455 "to which you're sending the transaction. This is not part of the \n"
456 "transaction, just kept in your wallet."},
457 {"subtractfeefromamount", RPCArg::Type::BOOL, RPCArg::Default{false}, "The fee will be deducted from the amount being sent.\n"
458 "The recipient will receive less bitcoins than you enter in the amount field."},
459 {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
460 {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
461 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
462 " \"" + FeeModes("\"\n\"") + "\""},
463 {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
464 "dirty if they have previously been used in a transaction. If true, this also activates avoidpartialspends, grouping outputs by their addresses."},
465 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
466 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra information about the transaction."},
467 },
468 {
469 RPCResult{"if verbose is not set or set to false",
470 RPCResult::Type::STR_HEX, "txid", "The transaction id."
471 },
472 RPCResult{"if verbose is set to true",
473 RPCResult::Type::OBJ, "", "",
474 {
475 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
476 {RPCResult::Type::STR, "fee_reason", "The transaction fee reason."}
477 },
478 },
479 },
481 "\nSend 0.1 BTC\n"
482 + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1") +
483 "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode using positional arguments\n"
484 + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"sean's outpost\" false true 6 economical") +
485 "\nSend 0.1 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB, subtract fee from amount, BIP125-replaceable, using positional arguments\n"
486 + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"drinks\" \"room77\" true true null \"unset\" null 1.1") +
487 "\nSend 0.2 BTC with a confirmation target of 6 blocks in economical fee estimate mode using named arguments\n"
488 + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.2 conf_target=6 estimate_mode=\"economical\"") +
489 "\nSend 0.5 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n"
490 + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25")
491 + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25 subtractfeefromamount=false replaceable=true avoid_reuse=true comment=\"2 pizzas\" comment_to=\"jeremy\" verbose=true")
492 },
493 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
494{
495 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
496 if (!pwallet) return NullUniValue;
497
498 // Make sure the results are valid at least up to the most recent block
499 // the user could have gotten from another RPC command prior to now
500 pwallet->BlockUntilSyncedToCurrentChain();
501
502 LOCK(pwallet->cs_wallet);
503
504 // Wallet comments
505 mapValue_t mapValue;
506 if (!request.params[2].isNull() && !request.params[2].get_str().empty())
507 mapValue["comment"] = request.params[2].get_str();
508 if (!request.params[3].isNull() && !request.params[3].get_str().empty())
509 mapValue["to"] = request.params[3].get_str();
510
511 bool fSubtractFeeFromAmount = false;
512 if (!request.params[4].isNull()) {
513 fSubtractFeeFromAmount = request.params[4].get_bool();
514 }
515
516 CCoinControl coin_control;
517 if (!request.params[5].isNull()) {
518 coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
519 }
520
521 coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(*pwallet, request.params[8]);
522 // We also enable partial spend avoidance if reuse avoidance is set.
523 coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
524
525 SetFeeEstimateMode(*pwallet, coin_control, /* conf_target */ request.params[6], /* estimate_mode */ request.params[7], /* fee_rate */ request.params[9], /* override_min_fee */ false);
526
527 EnsureWalletIsUnlocked(*pwallet);
528
529 UniValue address_amounts(UniValue::VOBJ);
530 const std::string address = request.params[0].get_str();
531 address_amounts.pushKV(address, request.params[1]);
532 UniValue subtractFeeFromAmount(UniValue::VARR);
533 if (fSubtractFeeFromAmount) {
534 subtractFeeFromAmount.push_back(address);
535 }
536
537 std::vector<CRecipient> recipients;
538 ParseRecipients(address_amounts, subtractFeeFromAmount, recipients);
539 const bool verbose{request.params[10].isNull() ? false : request.params[10].get_bool()};
540
541 return SendMoney(*pwallet, coin_control, recipients, mapValue, verbose);
542},
543 };
544}
545
547{
548 return RPCHelpMan{"listaddressgroupings",
549 "\nLists groups of addresses which have had their common ownership\n"
550 "made public by common use as inputs or as the resulting change\n"
551 "in past transactions\n",
552 {},
553 RPCResult{
554 RPCResult::Type::ARR, "", "",
555 {
556 {RPCResult::Type::ARR, "", "",
557 {
559 {
560 {RPCResult::Type::STR, "address", "The bitcoin address"},
561 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
562 {RPCResult::Type::STR, "label", /* optional */ true, "The label"},
563 }},
564 }},
565 }
566 },
568 HelpExampleCli("listaddressgroupings", "")
569 + HelpExampleRpc("listaddressgroupings", "")
570 },
571 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
572{
573 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
574 if (!pwallet) return NullUniValue;
575
576 // Make sure the results are valid at least up to the most recent block
577 // the user could have gotten from another RPC command prior to now
578 pwallet->BlockUntilSyncedToCurrentChain();
579
580 LOCK(pwallet->cs_wallet);
581
582 UniValue jsonGroupings(UniValue::VARR);
583 std::map<CTxDestination, CAmount> balances = GetAddressBalances(*pwallet);
584 for (const std::set<CTxDestination>& grouping : GetAddressGroupings(*pwallet)) {
585 UniValue jsonGrouping(UniValue::VARR);
586 for (const CTxDestination& address : grouping)
587 {
588 UniValue addressInfo(UniValue::VARR);
589 addressInfo.push_back(EncodeDestination(address));
590 addressInfo.push_back(ValueFromAmount(balances[address]));
591 {
592 const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
593 if (address_book_entry) {
594 addressInfo.push_back(address_book_entry->GetLabel());
595 }
596 }
597 jsonGrouping.push_back(addressInfo);
598 }
599 jsonGroupings.push_back(jsonGrouping);
600 }
601 return jsonGroupings;
602},
603 };
604}
605
607{
608 return RPCHelpMan{"signmessage",
609 "\nSign a message with the private key of an address" +
611 {
612 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the private key."},
613 {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message to create a signature of."},
614 },
615 RPCResult{
616 RPCResult::Type::STR, "signature", "The signature of the message encoded in base 64"
617 },
619 "\nUnlock the wallet for 30 seconds\n"
620 + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
621 "\nCreate the signature\n"
622 + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
623 "\nVerify the signature\n"
624 + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
625 "\nAs a JSON-RPC call\n"
626 + HelpExampleRpc("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")
627 },
628 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
629{
630 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
631 if (!pwallet) return NullUniValue;
632
633 LOCK(pwallet->cs_wallet);
634
635 EnsureWalletIsUnlocked(*pwallet);
636
637 std::string strAddress = request.params[0].get_str();
638 std::string strMessage = request.params[1].get_str();
639
640 CTxDestination dest = DecodeDestination(strAddress);
641 if (!IsValidDestination(dest)) {
642 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
643 }
644
645 const PKHash* pkhash = std::get_if<PKHash>(&dest);
646 if (!pkhash) {
647 throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
648 }
649
650 std::string signature;
651 SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature);
654 } else if (err != SigningResult::OK){
656 }
657
658 return signature;
659},
660 };
661}
662
663static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
664{
665 std::set<CTxDestination> address_set;
666
667 if (by_label) {
668 // Get the set of addresses assigned to label
669 std::string label = LabelFromValue(params[0]);
670 address_set = wallet.GetLabelAddresses(label);
671 } else {
672 // Get the address
673 CTxDestination dest = DecodeDestination(params[0].get_str());
674 if (!IsValidDestination(dest)) {
675 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
676 }
677 CScript script_pub_key = GetScriptForDestination(dest);
678 if (!wallet.IsMine(script_pub_key)) {
679 throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
680 }
681 address_set.insert(dest);
682 }
683
684 // Minimum confirmations
685 int min_depth = 1;
686 if (!params[1].isNull())
687 min_depth = params[1].get_int();
688
689 // Tally
690 CAmount amount = 0;
691 for (const std::pair<const uint256, CWalletTx>& wtx_pair : wallet.mapWallet) {
692 const CWalletTx& wtx = wtx_pair.second;
693 if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx) || wallet.GetTxDepthInMainChain(wtx) < min_depth) {
694 continue;
695 }
696
697 for (const CTxOut& txout : wtx.tx->vout) {
698 CTxDestination address;
699 if (ExtractDestination(txout.scriptPubKey, address) && wallet.IsMine(address) && address_set.count(address)) {
700 amount += txout.nValue;
701 }
702 }
703 }
704
705 return amount;
706}
707
708
710{
711 return RPCHelpMan{"getreceivedbyaddress",
712 "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
713 {
714 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."},
715 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
716 },
717 RPCResult{
718 RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received at this address."
719 },
721 "\nThe amount from transactions with at least 1 confirmation\n"
722 + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
723 "\nThe amount including unconfirmed transactions, zero confirmations\n"
724 + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0") +
725 "\nThe amount with at least 6 confirmations\n"
726 + HelpExampleCli("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 6") +
727 "\nAs a JSON-RPC call\n"
728 + HelpExampleRpc("getreceivedbyaddress", "\"" + EXAMPLE_ADDRESS[0] + "\", 6")
729 },
730 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
731{
732 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
733 if (!pwallet) return NullUniValue;
734
735 // Make sure the results are valid at least up to the most recent block
736 // the user could have gotten from another RPC command prior to now
737 pwallet->BlockUntilSyncedToCurrentChain();
738
739 LOCK(pwallet->cs_wallet);
740
741 return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ false));
742},
743 };
744}
745
746
748{
749 return RPCHelpMan{"getreceivedbylabel",
750 "\nReturns the total amount received by addresses with <label> in transactions with at least [minconf] confirmations.\n",
751 {
752 {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The selected label, may be the default label using \"\"."},
753 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
754 },
755 RPCResult{
756 RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this label."
757 },
759 "\nAmount received by the default label with at least 1 confirmation\n"
760 + HelpExampleCli("getreceivedbylabel", "\"\"") +
761 "\nAmount received at the tabby label including unconfirmed amounts with zero confirmations\n"
762 + HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
763 "\nThe amount with at least 6 confirmations\n"
764 + HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
765 "\nAs a JSON-RPC call\n"
766 + HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")
767 },
768 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
769{
770 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
771 if (!pwallet) return NullUniValue;
772
773 // Make sure the results are valid at least up to the most recent block
774 // the user could have gotten from another RPC command prior to now
775 pwallet->BlockUntilSyncedToCurrentChain();
776
777 LOCK(pwallet->cs_wallet);
778
779 return ValueFromAmount(GetReceived(*pwallet, request.params, /* by_label */ true));
780},
781 };
782}
783
784
786{
787 return RPCHelpMan{"getbalance",
788 "\nReturns the total available balance.\n"
789 "The available balance is what the wallet considers currently spendable, and is\n"
790 "thus affected by options which limit spendability such as -spendzeroconfchange.\n",
791 {
792 {"dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Remains for backward compatibility. Must be excluded or set to \"*\"."},
793 {"minconf", RPCArg::Type::NUM, RPCArg::Default{0}, "Only include transactions confirmed at least this many times."},
794 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also include balance in watch-only addresses (see 'importaddress')"},
795 {"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."},
796 },
797 RPCResult{
798 RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received for this wallet."
799 },
801 "\nThe total amount in the wallet with 0 or more confirmations\n"
802 + HelpExampleCli("getbalance", "") +
803 "\nThe total amount in the wallet with at least 6 confirmations\n"
804 + HelpExampleCli("getbalance", "\"*\" 6") +
805 "\nAs a JSON-RPC call\n"
806 + HelpExampleRpc("getbalance", "\"*\", 6")
807 },
808 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
809{
810 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
811 if (!pwallet) return NullUniValue;
812
813 // Make sure the results are valid at least up to the most recent block
814 // the user could have gotten from another RPC command prior to now
815 pwallet->BlockUntilSyncedToCurrentChain();
816
817 LOCK(pwallet->cs_wallet);
818
819 const UniValue& dummy_value = request.params[0];
820 if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
821 throw JSONRPCError(RPC_METHOD_DEPRECATED, "dummy first argument must be excluded or set to \"*\".");
822 }
823
824 int min_depth = 0;
825 if (!request.params[1].isNull()) {
826 min_depth = request.params[1].get_int();
827 }
828
829 bool include_watchonly = ParseIncludeWatchonly(request.params[2], *pwallet);
830
831 bool avoid_reuse = GetAvoidReuseFlag(*pwallet, request.params[3]);
832
833 const auto bal = GetBalance(*pwallet, min_depth, avoid_reuse);
834
835 return ValueFromAmount(bal.m_mine_trusted + (include_watchonly ? bal.m_watchonly_trusted : 0));
836},
837 };
838}
839
841{
842 return RPCHelpMan{"getunconfirmedbalance",
843 "DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
844 {},
845 RPCResult{RPCResult::Type::NUM, "", "The balance"},
846 RPCExamples{""},
847 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
848{
849 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
850 if (!pwallet) return NullUniValue;
851
852 // Make sure the results are valid at least up to the most recent block
853 // the user could have gotten from another RPC command prior to now
854 pwallet->BlockUntilSyncedToCurrentChain();
855
856 LOCK(pwallet->cs_wallet);
857
859},
860 };
861}
862
863
865{
866 return RPCHelpMan{"sendmany",
867 "\nSend multiple times. Amounts are double-precision floating point numbers." +
869 {
870 {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""},
871 {"amounts", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::NO, "The addresses and amounts",
872 {
873 {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
874 },
875 },
876 {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
878 {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The addresses.\n"
879 "The fee will be equally deducted from the amount of each selected address.\n"
880 "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
881 "If no addresses are specified here, the sender pays the fee.",
882 {
883 {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
884 },
885 },
886 {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
887 {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
888 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
889 " \"" + FeeModes("\"\n\"") + "\""},
890 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
891 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra infomration about the transaction."},
892 },
893 {
894 RPCResult{"if verbose is not set or set to false",
895 RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
896 "the number of addresses."
897 },
898 RPCResult{"if verbose is set to true",
899 RPCResult::Type::OBJ, "", "",
900 {
901 {RPCResult::Type::STR_HEX, "txid", "The transaction id for the send. Only 1 transaction is created regardless of\n"
902 "the number of addresses."},
903 {RPCResult::Type::STR, "fee_reason", "The transaction fee reason."}
904 },
905 },
906 },
908 "\nSend two amounts to two different addresses:\n"
909 + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\"") +
910 "\nSend two amounts to two different addresses setting the confirmation and comment:\n"
911 + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 6 \"testing\"") +
912 "\nSend two amounts to two different addresses, subtract fee from amount:\n"
913 + HelpExampleCli("sendmany", "\"\" \"{\\\"" + EXAMPLE_ADDRESS[0] + "\\\":0.01,\\\"" + EXAMPLE_ADDRESS[1] + "\\\":0.02}\" 1 \"\" \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
914 "\nAs a JSON-RPC call\n"
915 + HelpExampleRpc("sendmany", "\"\", {\"" + EXAMPLE_ADDRESS[0] + "\":0.01,\"" + EXAMPLE_ADDRESS[1] + "\":0.02}, 6, \"testing\"")
916 },
917 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
918{
919 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
920 if (!pwallet) return NullUniValue;
921
922 // Make sure the results are valid at least up to the most recent block
923 // the user could have gotten from another RPC command prior to now
924 pwallet->BlockUntilSyncedToCurrentChain();
925
926 LOCK(pwallet->cs_wallet);
927
928 if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
929 throw JSONRPCError(RPC_INVALID_PARAMETER, "Dummy value must be set to \"\"");
930 }
931 UniValue sendTo = request.params[1].get_obj();
932
933 mapValue_t mapValue;
934 if (!request.params[3].isNull() && !request.params[3].get_str().empty())
935 mapValue["comment"] = request.params[3].get_str();
936
937 UniValue subtractFeeFromAmount(UniValue::VARR);
938 if (!request.params[4].isNull())
939 subtractFeeFromAmount = request.params[4].get_array();
940
941 CCoinControl coin_control;
942 if (!request.params[5].isNull()) {
943 coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
944 }
945
946 SetFeeEstimateMode(*pwallet, coin_control, /* conf_target */ request.params[6], /* estimate_mode */ request.params[7], /* fee_rate */ request.params[8], /* override_min_fee */ false);
947
948 std::vector<CRecipient> recipients;
949 ParseRecipients(sendTo, subtractFeeFromAmount, recipients);
950 const bool verbose{request.params[9].isNull() ? false : request.params[9].get_bool()};
951
952 return SendMoney(*pwallet, coin_control, recipients, std::move(mapValue), verbose);
953},
954 };
955}
956
957
959{
960 return RPCHelpMan{"addmultisigaddress",
961 "\nAdd an nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
962 "Each key is a Bitcoin address or hex-encoded public key.\n"
963 "This functionality is only intended for use with non-watchonly addresses.\n"
964 "See `importaddress` for watchonly p2sh address support.\n"
965 "If 'label' is specified, assign address to that label.\n",
966 {
967 {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
968 {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The bitcoin addresses or hex-encoded public keys",
969 {
970 {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address or hex-encoded public key"},
971 },
972 },
973 {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
974 {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
975 },
976 RPCResult{
977 RPCResult::Type::OBJ, "", "",
978 {
979 {RPCResult::Type::STR, "address", "The value of the new multisig address"},
980 {RPCResult::Type::STR_HEX, "redeemScript", "The string value of the hex-encoded redemption script"},
981 {RPCResult::Type::STR, "descriptor", "The descriptor for this multisig"},
982 }
983 },
985 "\nAdd a multisig address from 2 addresses\n"
986 + HelpExampleCli("addmultisigaddress", "2 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"") +
987 "\nAs a JSON-RPC call\n"
988 + HelpExampleRpc("addmultisigaddress", "2, \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
989 },
990 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
991{
992 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
993 if (!pwallet) return NullUniValue;
994
996
997 LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
998
999 std::string label;
1000 if (!request.params[2].isNull())
1001 label = LabelFromValue(request.params[2]);
1002
1003 int required = request.params[0].get_int();
1004
1005 // Get the public keys
1006 const UniValue& keys_or_addrs = request.params[1].get_array();
1007 std::vector<CPubKey> pubkeys;
1008 for (unsigned int i = 0; i < keys_or_addrs.size(); ++i) {
1009 if (IsHex(keys_or_addrs[i].get_str()) && (keys_or_addrs[i].get_str().length() == 66 || keys_or_addrs[i].get_str().length() == 130)) {
1010 pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
1011 } else {
1012 pubkeys.push_back(AddrToPubKey(spk_man, keys_or_addrs[i].get_str()));
1013 }
1014 }
1015
1016 OutputType output_type = pwallet->m_default_address_type;
1017 if (!request.params[3].isNull()) {
1018 std::optional<OutputType> parsed = ParseOutputType(request.params[3].get_str());
1019 if (!parsed) {
1020 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown address type '%s'", request.params[3].get_str()));
1021 } else if (parsed.value() == OutputType::BECH32M) {
1022 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Bech32m multisig addresses cannot be created with legacy wallets");
1023 }
1024 output_type = parsed.value();
1025 }
1026
1027 // Construct using pay-to-script-hash:
1028 CScript inner;
1029 CTxDestination dest = AddAndGetMultisigDestination(required, pubkeys, output_type, spk_man, inner);
1030 pwallet->SetAddressBook(dest, label, "send");
1031
1032 // Make the descriptor
1033 std::unique_ptr<Descriptor> descriptor = InferDescriptor(GetScriptForDestination(dest), spk_man);
1034
1035 UniValue result(UniValue::VOBJ);
1036 result.pushKV("address", EncodeDestination(dest));
1037 result.pushKV("redeemScript", HexStr(inner));
1038 result.pushKV("descriptor", descriptor->ToString());
1039 return result;
1040},
1041 };
1042}
1043
1045{
1047 int nConf{std::numeric_limits<int>::max()};
1048 std::vector<uint256> txids;
1049 bool fIsWatchonly{false};
1051 {
1052 }
1053};
1054
1055static UniValue ListReceived(const CWallet& wallet, const UniValue& params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
1056{
1057 // Minimum confirmations
1058 int nMinDepth = 1;
1059 if (!params[0].isNull())
1060 nMinDepth = params[0].get_int();
1061
1062 // Whether to include empty labels
1063 bool fIncludeEmpty = false;
1064 if (!params[1].isNull())
1065 fIncludeEmpty = params[1].get_bool();
1066
1068
1069 if (ParseIncludeWatchonly(params[2], wallet)) {
1070 filter |= ISMINE_WATCH_ONLY;
1071 }
1072
1073 bool has_filtered_address = false;
1074 CTxDestination filtered_address = CNoDestination();
1075 if (!by_label && params.size() > 3) {
1076 if (!IsValidDestinationString(params[3].get_str())) {
1077 throw JSONRPCError(RPC_WALLET_ERROR, "address_filter parameter was invalid");
1078 }
1079 filtered_address = DecodeDestination(params[3].get_str());
1080 has_filtered_address = true;
1081 }
1082
1083 // Tally
1084 std::map<CTxDestination, tallyitem> mapTally;
1085 for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
1086 const CWalletTx& wtx = pairWtx.second;
1087
1088 if (wtx.IsCoinBase() || !wallet.chain().checkFinalTx(*wtx.tx)) {
1089 continue;
1090 }
1091
1092 int nDepth = wallet.GetTxDepthInMainChain(wtx);
1093 if (nDepth < nMinDepth)
1094 continue;
1095
1096 for (const CTxOut& txout : wtx.tx->vout)
1097 {
1098 CTxDestination address;
1099 if (!ExtractDestination(txout.scriptPubKey, address))
1100 continue;
1101
1102 if (has_filtered_address && !(filtered_address == address)) {
1103 continue;
1104 }
1105
1106 isminefilter mine = wallet.IsMine(address);
1107 if(!(mine & filter))
1108 continue;
1109
1110 tallyitem& item = mapTally[address];
1111 item.nAmount += txout.nValue;
1112 item.nConf = std::min(item.nConf, nDepth);
1113 item.txids.push_back(wtx.GetHash());
1114 if (mine & ISMINE_WATCH_ONLY)
1115 item.fIsWatchonly = true;
1116 }
1117 }
1118
1119 // Reply
1121 std::map<std::string, tallyitem> label_tally;
1122
1123 // Create m_address_book iterator
1124 // If we aren't filtering, go from begin() to end()
1125 auto start = wallet.m_address_book.begin();
1126 auto end = wallet.m_address_book.end();
1127 // If we are filtering, find() the applicable entry
1128 if (has_filtered_address) {
1129 start = wallet.m_address_book.find(filtered_address);
1130 if (start != end) {
1131 end = std::next(start);
1132 }
1133 }
1134
1135 for (auto item_it = start; item_it != end; ++item_it)
1136 {
1137 if (item_it->second.IsChange()) continue;
1138 const CTxDestination& address = item_it->first;
1139 const std::string& label = item_it->second.GetLabel();
1140 auto it = mapTally.find(address);
1141 if (it == mapTally.end() && !fIncludeEmpty)
1142 continue;
1143
1144 CAmount nAmount = 0;
1145 int nConf = std::numeric_limits<int>::max();
1146 bool fIsWatchonly = false;
1147 if (it != mapTally.end())
1148 {
1149 nAmount = (*it).second.nAmount;
1150 nConf = (*it).second.nConf;
1151 fIsWatchonly = (*it).second.fIsWatchonly;
1152 }
1153
1154 if (by_label)
1155 {
1156 tallyitem& _item = label_tally[label];
1157 _item.nAmount += nAmount;
1158 _item.nConf = std::min(_item.nConf, nConf);
1159 _item.fIsWatchonly = fIsWatchonly;
1160 }
1161 else
1162 {
1164 if(fIsWatchonly)
1165 obj.pushKV("involvesWatchonly", true);
1166 obj.pushKV("address", EncodeDestination(address));
1167 obj.pushKV("amount", ValueFromAmount(nAmount));
1168 obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
1169 obj.pushKV("label", label);
1170 UniValue transactions(UniValue::VARR);
1171 if (it != mapTally.end())
1172 {
1173 for (const uint256& _item : (*it).second.txids)
1174 {
1175 transactions.push_back(_item.GetHex());
1176 }
1177 }
1178 obj.pushKV("txids", transactions);
1179 ret.push_back(obj);
1180 }
1181 }
1182
1183 if (by_label)
1184 {
1185 for (const auto& entry : label_tally)
1186 {
1187 CAmount nAmount = entry.second.nAmount;
1188 int nConf = entry.second.nConf;
1190 if (entry.second.fIsWatchonly)
1191 obj.pushKV("involvesWatchonly", true);
1192 obj.pushKV("amount", ValueFromAmount(nAmount));
1193 obj.pushKV("confirmations", (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
1194 obj.pushKV("label", entry.first);
1195 ret.push_back(obj);
1196 }
1197 }
1198
1199 return ret;
1200}
1201
1203{
1204 return RPCHelpMan{"listreceivedbyaddress",
1205 "\nList balances by receiving address.\n",
1206 {
1207 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
1208 {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include addresses that haven't received any payments."},
1209 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
1210 {"address_filter", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If present, only return information on this address."},
1211 },
1212 RPCResult{
1213 RPCResult::Type::ARR, "", "",
1214 {
1215 {RPCResult::Type::OBJ, "", "",
1216 {
1217 {RPCResult::Type::BOOL, "involvesWatchonly", /* optional */ true, "Only returns true if imported addresses were involved in transaction"},
1218 {RPCResult::Type::STR, "address", "The receiving address"},
1219 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount in " + CURRENCY_UNIT + " received by the address"},
1220 {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
1221 {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
1222 {RPCResult::Type::ARR, "txids", "",
1223 {
1224 {RPCResult::Type::STR_HEX, "txid", "The ids of transactions received with the address"},
1225 }},
1226 }},
1227 }
1228 },
1230 HelpExampleCli("listreceivedbyaddress", "")
1231 + HelpExampleCli("listreceivedbyaddress", "6 true")
1232 + HelpExampleRpc("listreceivedbyaddress", "6, true, true")
1233 + HelpExampleRpc("listreceivedbyaddress", "6, true, true, \"" + EXAMPLE_ADDRESS[0] + "\"")
1234 },
1235 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1236{
1237 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
1238 if (!pwallet) return NullUniValue;
1239
1240 // Make sure the results are valid at least up to the most recent block
1241 // the user could have gotten from another RPC command prior to now
1242 pwallet->BlockUntilSyncedToCurrentChain();
1243
1244 LOCK(pwallet->cs_wallet);
1245
1246 return ListReceived(*pwallet, request.params, false);
1247},
1248 };
1249}
1250
1252{
1253 return RPCHelpMan{"listreceivedbylabel",
1254 "\nList received transactions by label.\n",
1255 {
1256 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum number of confirmations before payments are included."},
1257 {"include_empty", RPCArg::Type::BOOL, RPCArg::Default{false}, "Whether to include labels that haven't received any payments."},
1258 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Whether to include watch-only addresses (see 'importaddress')"},
1259 },
1260 RPCResult{
1261 RPCResult::Type::ARR, "", "",
1262 {
1263 {RPCResult::Type::OBJ, "", "",
1264 {
1265 {RPCResult::Type::BOOL, "involvesWatchonly", /* optional */ true, "Only returns true if imported addresses were involved in transaction"},
1266 {RPCResult::Type::STR_AMOUNT, "amount", "The total amount received by addresses with this label"},
1267 {RPCResult::Type::NUM, "confirmations", "The number of confirmations of the most recent transaction included"},
1268 {RPCResult::Type::STR, "label", "The label of the receiving address. The default label is \"\""},
1269 }},
1270 }
1271 },
1273 HelpExampleCli("listreceivedbylabel", "")
1274 + HelpExampleCli("listreceivedbylabel", "6 true")
1275 + HelpExampleRpc("listreceivedbylabel", "6, true, true")
1276 },
1277 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1278{
1279 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
1280 if (!pwallet) return NullUniValue;
1281
1282 // Make sure the results are valid at least up to the most recent block
1283 // the user could have gotten from another RPC command prior to now
1284 pwallet->BlockUntilSyncedToCurrentChain();
1285
1286 LOCK(pwallet->cs_wallet);
1287
1288 return ListReceived(*pwallet, request.params, true);
1289},
1290 };
1291}
1292
1293static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
1294{
1295 if (IsValidDestination(dest)) {
1296 entry.pushKV("address", EncodeDestination(dest));
1297 }
1298}
1299
1311static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nMinDepth, bool fLong, UniValue& ret, const isminefilter& filter_ismine, const std::string* filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
1312{
1313 CAmount nFee;
1314 std::list<COutputEntry> listReceived;
1315 std::list<COutputEntry> listSent;
1316
1317 CachedTxGetAmounts(wallet, wtx, listReceived, listSent, nFee, filter_ismine);
1318
1319 bool involvesWatchonly = CachedTxIsFromMe(wallet, wtx, ISMINE_WATCH_ONLY);
1320
1321 // Sent
1322 if (!filter_label)
1323 {
1324 for (const COutputEntry& s : listSent)
1325 {
1326 UniValue entry(UniValue::VOBJ);
1327 if (involvesWatchonly || (wallet.IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
1328 entry.pushKV("involvesWatchonly", true);
1329 }
1330 MaybePushAddress(entry, s.destination);
1331 entry.pushKV("category", "send");
1332 entry.pushKV("amount", ValueFromAmount(-s.amount));
1333 const auto* address_book_entry = wallet.FindAddressBookEntry(s.destination);
1334 if (address_book_entry) {
1335 entry.pushKV("label", address_book_entry->GetLabel());
1336 }
1337 entry.pushKV("vout", s.vout);
1338 entry.pushKV("fee", ValueFromAmount(-nFee));
1339 if (fLong)
1340 WalletTxToJSON(wallet, wtx, entry);
1341 entry.pushKV("abandoned", wtx.isAbandoned());
1342 ret.push_back(entry);
1343 }
1344 }
1345
1346 // Received
1347 if (listReceived.size() > 0 && wallet.GetTxDepthInMainChain(wtx) >= nMinDepth) {
1348 for (const COutputEntry& r : listReceived)
1349 {
1350 std::string label;
1351 const auto* address_book_entry = wallet.FindAddressBookEntry(r.destination);
1352 if (address_book_entry) {
1353 label = address_book_entry->GetLabel();
1354 }
1355 if (filter_label && label != *filter_label) {
1356 continue;
1357 }
1358 UniValue entry(UniValue::VOBJ);
1359 if (involvesWatchonly || (wallet.IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
1360 entry.pushKV("involvesWatchonly", true);
1361 }
1362 MaybePushAddress(entry, r.destination);
1363 if (wtx.IsCoinBase())
1364 {
1365 if (wallet.GetTxDepthInMainChain(wtx) < 1)
1366 entry.pushKV("category", "orphan");
1367 else if (wallet.IsTxImmatureCoinBase(wtx))
1368 entry.pushKV("category", "immature");
1369 else
1370 entry.pushKV("category", "generate");
1371 }
1372 else
1373 {
1374 entry.pushKV("category", "receive");
1375 }
1376 entry.pushKV("amount", ValueFromAmount(r.amount));
1377 if (address_book_entry) {
1378 entry.pushKV("label", label);
1379 }
1380 entry.pushKV("vout", r.vout);
1381 if (fLong)
1382 WalletTxToJSON(wallet, wtx, entry);
1383 ret.push_back(entry);
1384 }
1385 }
1386}
1387
1388static const std::vector<RPCResult> TransactionDescriptionString()
1389{
1390 return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
1391 "transaction conflicted that many blocks ago."},
1392 {RPCResult::Type::BOOL, "generated", /* optional */ true, "Only present if the transaction's only input is a coinbase one."},
1393 {RPCResult::Type::BOOL, "trusted", /* optional */ true, "Whether we consider the transaction to be trusted and safe to spend from.\n"
1394 "Only present when the transaction has 0 confirmations (or negative confirmations, if conflicted)."},
1395 {RPCResult::Type::STR_HEX, "blockhash", /* optional */ true, "The block hash containing the transaction."},
1396 {RPCResult::Type::NUM, "blockheight", /* optional */ true, "The block height containing the transaction."},
1397 {RPCResult::Type::NUM, "blockindex", /* optional */ true, "The index of the transaction in the block that includes it."},
1398 {RPCResult::Type::NUM_TIME, "blocktime", /* optional */ true, "The block time expressed in " + UNIX_EPOCH_TIME + "."},
1399 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
1400 {RPCResult::Type::ARR, "walletconflicts", "Conflicting transaction ids.",
1401 {
1402 {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
1403 }},
1404 {RPCResult::Type::STR_HEX, "replaced_by_txid", /* optional */ true, "The txid if this tx was replaced."},
1405 {RPCResult::Type::STR_HEX, "replaces_txid", /* optional */ true, "The txid if the tx replaces one."},
1406 {RPCResult::Type::STR, "comment", /* optional */ true, ""},
1407 {RPCResult::Type::STR, "to", /* optional */ true, "If a comment to is associated with the transaction."},
1408 {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
1409 {RPCResult::Type::NUM_TIME, "timereceived", "The time received expressed in " + UNIX_EPOCH_TIME + "."},
1410 {RPCResult::Type::STR, "comment", /* optional */ true, "If a comment is associated with the transaction, only present if not empty."},
1411 {RPCResult::Type::STR, "bip125-replaceable", "(\"yes|no|unknown\") Whether this transaction could be replaced due to BIP125 (replace-by-fee);\n"
1412 "may be unknown for unconfirmed transactions not in the mempool."}};
1413}
1414
1416{
1417 return RPCHelpMan{"listtransactions",
1418 "\nIf a label name is provided, this will return only incoming transactions paying to addresses with the specified label.\n"
1419 "\nReturns up to 'count' most recent transactions skipping the first 'from' transactions.\n",
1420 {
1421 {"label|dummy", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, should be a valid label name to return only incoming transactions\n"
1422 "with the specified label, or \"*\" to disable filtering and return all transactions."},
1423 {"count", RPCArg::Type::NUM, RPCArg::Default{10}, "The number of transactions to return"},
1424 {"skip", RPCArg::Type::NUM, RPCArg::Default{0}, "The number of transactions to skip"},
1425 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
1426 },
1427 RPCResult{
1428 RPCResult::Type::ARR, "", "",
1429 {
1430 {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
1431 {
1432 {RPCResult::Type::BOOL, "involvesWatchonly", /* optional */ true, "Only returns true if imported addresses were involved in transaction."},
1433 {RPCResult::Type::STR, "address", "The bitcoin address of the transaction."},
1434 {RPCResult::Type::STR, "category", "The transaction category.\n"
1435 "\"send\" Transactions sent.\n"
1436 "\"receive\" Non-coinbase transactions received.\n"
1437 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
1438 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
1439 "\"orphan\" Orphaned coinbase transactions received."},
1440 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
1441 "for all other categories"},
1442 {RPCResult::Type::STR, "label", /* optional */ true, "A comment for the address/transaction, if any"},
1443 {RPCResult::Type::NUM, "vout", "the vout value"},
1444 {RPCResult::Type::STR_AMOUNT, "fee", /* optional */ true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
1445 "'send' category of transactions."},
1446 },
1448 {
1449 {RPCResult::Type::BOOL, "abandoned", /* optional */ true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
1450 "'send' category of transactions."},
1451 })},
1452 }
1453 },
1455 "\nList the most recent 10 transactions in the systems\n"
1456 + HelpExampleCli("listtransactions", "") +
1457 "\nList transactions 100 to 120\n"
1458 + HelpExampleCli("listtransactions", "\"*\" 20 100") +
1459 "\nAs a JSON-RPC call\n"
1460 + HelpExampleRpc("listtransactions", "\"*\", 20, 100")
1461 },
1462 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1463{
1464 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
1465 if (!pwallet) return NullUniValue;
1466
1467 // Make sure the results are valid at least up to the most recent block
1468 // the user could have gotten from another RPC command prior to now
1469 pwallet->BlockUntilSyncedToCurrentChain();
1470
1471 const std::string* filter_label = nullptr;
1472 if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
1473 filter_label = &request.params[0].get_str();
1474 if (filter_label->empty()) {
1475 throw JSONRPCError(RPC_INVALID_PARAMETER, "Label argument must be a valid label name or \"*\".");
1476 }
1477 }
1478 int nCount = 10;
1479 if (!request.params[1].isNull())
1480 nCount = request.params[1].get_int();
1481 int nFrom = 0;
1482 if (!request.params[2].isNull())
1483 nFrom = request.params[2].get_int();
1485
1486 if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
1487 filter |= ISMINE_WATCH_ONLY;
1488 }
1489
1490 if (nCount < 0)
1491 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1492 if (nFrom < 0)
1493 throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1494
1496
1497 {
1498 LOCK(pwallet->cs_wallet);
1499
1500 const CWallet::TxItems & txOrdered = pwallet->wtxOrdered;
1501
1502 // iterate backwards until we have nCount items to return:
1503 for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin(); it != txOrdered.rend(); ++it)
1504 {
1505 CWalletTx *const pwtx = (*it).second;
1506 ListTransactions(*pwallet, *pwtx, 0, true, ret, filter, filter_label);
1507 if ((int)ret.size() >= (nCount+nFrom)) break;
1508 }
1509 }
1510
1511 // ret is newest to oldest
1512
1513 if (nFrom > (int)ret.size())
1514 nFrom = ret.size();
1515 if ((nFrom + nCount) > (int)ret.size())
1516 nCount = ret.size() - nFrom;
1517
1518 const std::vector<UniValue>& txs = ret.getValues();
1519 UniValue result{UniValue::VARR};
1520 result.push_backV({ txs.rend() - nFrom - nCount, txs.rend() - nFrom }); // Return oldest to newest
1521 return result;
1522},
1523 };
1524}
1525
1527{
1528 return RPCHelpMan{"listsinceblock",
1529 "\nGet all transactions in blocks since block [blockhash], or all transactions if omitted.\n"
1530 "If \"blockhash\" is no longer a part of the main chain, transactions from the fork point onward are included.\n"
1531 "Additionally, if include_removed is set, transactions affecting the wallet which were removed are returned in the \"removed\" array.\n",
1532 {
1533 {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
1534 {"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
1535 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
1536 {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
1537 "(not guaranteed to work on pruned nodes)"},
1538 },
1539 RPCResult{
1540 RPCResult::Type::OBJ, "", "",
1541 {
1542 {RPCResult::Type::ARR, "transactions", "",
1543 {
1544 {RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
1545 {
1546 {RPCResult::Type::BOOL, "involvesWatchonly", /* optional */ true, "Only returns true if imported addresses were involved in transaction."},
1547 {RPCResult::Type::STR, "address", "The bitcoin address of the transaction."},
1548 {RPCResult::Type::STR, "category", "The transaction category.\n"
1549 "\"send\" Transactions sent.\n"
1550 "\"receive\" Non-coinbase transactions received.\n"
1551 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
1552 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
1553 "\"orphan\" Orphaned coinbase transactions received."},
1554 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT + ". This is negative for the 'send' category, and is positive\n"
1555 "for all other categories"},
1556 {RPCResult::Type::NUM, "vout", "the vout value"},
1557 {RPCResult::Type::STR_AMOUNT, "fee", /* optional */ true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
1558 "'send' category of transactions."},
1559 },
1561 {
1562 {RPCResult::Type::BOOL, "abandoned", /* optional */ true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
1563 "'send' category of transactions."},
1564 {RPCResult::Type::STR, "label", /* optional */ true, "A comment for the address/transaction, if any"},
1565 })},
1566 }},
1567 {RPCResult::Type::ARR, "removed", /* optional */ true, "<structure is the same as \"transactions\" above, only present if include_removed=true>\n"
1568 "Note: transactions that were re-added in the active chain will appear as-is in this array, and may thus have a positive confirmation count."
1569 , {{RPCResult::Type::ELISION, "", ""},}},
1570 {RPCResult::Type::STR_HEX, "lastblock", "The hash of the block (target_confirmations-1) from the best block on the main chain, or the genesis hash if the referenced block does not exist yet. This is typically used to feed back into listsinceblock the next time you call it. So you would generally use a target_confirmations of say 6, so you will be continually re-notified of transactions until they've reached 6 confirmations plus any new ones"},
1571 }
1572 },
1574 HelpExampleCli("listsinceblock", "")
1575 + HelpExampleCli("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\" 6")
1576 + HelpExampleRpc("listsinceblock", "\"000000000000000bacf66f7497b7dc45ef753ee9a7d38571037cdb1a57f663ad\", 6")
1577 },
1578 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1579{
1580 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
1581 if (!pwallet) return NullUniValue;
1582
1583 const CWallet& wallet = *pwallet;
1584 // Make sure the results are valid at least up to the most recent block
1585 // the user could have gotten from another RPC command prior to now
1586 wallet.BlockUntilSyncedToCurrentChain();
1587
1588 LOCK(wallet.cs_wallet);
1589
1590 std::optional<int> height; // Height of the specified block or the common ancestor, if the block provided was in a deactivated chain.
1591 std::optional<int> altheight; // Height of the specified block, even if it's in a deactivated chain.
1592 int target_confirms = 1;
1594
1595 uint256 blockId;
1596 if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
1597 blockId = ParseHashV(request.params[0], "blockhash");
1598 height = int{};
1599 altheight = int{};
1600 if (!wallet.chain().findCommonAncestor(blockId, wallet.GetLastBlockHash(), /* ancestor out */ FoundBlock().height(*height), /* blockId out */ FoundBlock().height(*altheight))) {
1601 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1602 }
1603 }
1604
1605 if (!request.params[1].isNull()) {
1606 target_confirms = request.params[1].get_int();
1607
1608 if (target_confirms < 1) {
1609 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1610 }
1611 }
1612
1613 if (ParseIncludeWatchonly(request.params[2], wallet)) {
1614 filter |= ISMINE_WATCH_ONLY;
1615 }
1616
1617 bool include_removed = (request.params[3].isNull() || request.params[3].get_bool());
1618
1619 int depth = height ? wallet.GetLastBlockHeight() + 1 - *height : -1;
1620
1621 UniValue transactions(UniValue::VARR);
1622
1623 for (const std::pair<const uint256, CWalletTx>& pairWtx : wallet.mapWallet) {
1624 const CWalletTx& tx = pairWtx.second;
1625
1626 if (depth == -1 || abs(wallet.GetTxDepthInMainChain(tx)) < depth) {
1627 ListTransactions(wallet, tx, 0, true, transactions, filter, nullptr /* filter_label */);
1628 }
1629 }
1630
1631 // when a reorg'd block is requested, we also list any relevant transactions
1632 // in the blocks of the chain that was detached
1633 UniValue removed(UniValue::VARR);
1634 while (include_removed && altheight && *altheight > *height) {
1635 CBlock block;
1636 if (!wallet.chain().findBlock(blockId, FoundBlock().data(block)) || block.IsNull()) {
1637 throw JSONRPCError(RPC_INTERNAL_ERROR, "Can't read block from disk");
1638 }
1639 for (const CTransactionRef& tx : block.vtx) {
1640 auto it = wallet.mapWallet.find(tx->GetHash());
1641 if (it != wallet.mapWallet.end()) {
1642 // We want all transactions regardless of confirmation count to appear here,
1643 // even negative confirmation ones, hence the big negative.
1644 ListTransactions(wallet, it->second, -100000000, true, removed, filter, nullptr /* filter_label */);
1645 }
1646 }
1647 blockId = block.hashPrevBlock;
1648 --*altheight;
1649 }
1650
1651 uint256 lastblock;
1652 target_confirms = std::min(target_confirms, wallet.GetLastBlockHeight() + 1);
1653 CHECK_NONFATAL(wallet.chain().findAncestorByHeight(wallet.GetLastBlockHash(), wallet.GetLastBlockHeight() + 1 - target_confirms, FoundBlock().hash(lastblock)));
1654
1656 ret.pushKV("transactions", transactions);
1657 if (include_removed) ret.pushKV("removed", removed);
1658 ret.pushKV("lastblock", lastblock.GetHex());
1659
1660 return ret;
1661},
1662 };
1663}
1664
1666{
1667 return RPCHelpMan{"gettransaction",
1668 "\nGet detailed information about in-wallet transaction <txid>\n",
1669 {
1670 {"txid", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction id"},
1671 {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"},
1672 "Whether to include watch-only addresses in balance calculation and details[]"},
1673 {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false},
1674 "Whether to include a `decoded` field containing the decoded transaction (equivalent to RPC decoderawtransaction)"},
1675 },
1676 RPCResult{
1677 RPCResult::Type::OBJ, "", "", Cat(Cat<std::vector<RPCResult>>(
1678 {
1679 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
1680 {RPCResult::Type::STR_AMOUNT, "fee", /* optional */ true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the\n"
1681 "'send' category of transactions."},
1682 },
1684 {
1685 {RPCResult::Type::ARR, "details", "",
1686 {
1687 {RPCResult::Type::OBJ, "", "",
1688 {
1689 {RPCResult::Type::BOOL, "involvesWatchonly", /* optional */ true, "Only returns true if imported addresses were involved in transaction."},
1690 {RPCResult::Type::STR, "address", /* optional */ true, "The bitcoin address involved in the transaction."},
1691 {RPCResult::Type::STR, "category", "The transaction category.\n"
1692 "\"send\" Transactions sent.\n"
1693 "\"receive\" Non-coinbase transactions received.\n"
1694 "\"generate\" Coinbase transactions received with more than 100 confirmations.\n"
1695 "\"immature\" Coinbase transactions received with 100 or fewer confirmations.\n"
1696 "\"orphan\" Orphaned coinbase transactions received."},
1697 {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
1698 {RPCResult::Type::STR, "label", /* optional */ true, "A comment for the address/transaction, if any"},
1699 {RPCResult::Type::NUM, "vout", "the vout value"},
1700 {RPCResult::Type::STR_AMOUNT, "fee", /* optional */ true, "The amount of the fee in " + CURRENCY_UNIT + ". This is negative and only available for the \n"
1701 "'send' category of transactions."},
1702 {RPCResult::Type::BOOL, "abandoned", /* optional */ true, "'true' if the transaction has been abandoned (inputs are respendable). Only available for the \n"
1703 "'send' category of transactions."},
1704 }},
1705 }},
1706 {RPCResult::Type::STR_HEX, "hex", "Raw data for transaction"},
1707 {RPCResult::Type::OBJ, "decoded", /* optional */ true, "The decoded transaction (only present when `verbose` is passed)",
1708 {
1709 {RPCResult::Type::ELISION, "", "Equivalent to the RPC decoderawtransaction method, or the RPC getrawtransaction method when `verbose` is passed."},
1710 }},
1711 })
1712 },
1714 HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1715 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" true")
1716 + HelpExampleCli("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\" false true")
1717 + HelpExampleRpc("gettransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1718 },
1719 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1720{
1721 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
1722 if (!pwallet) return NullUniValue;
1723
1724 // Make sure the results are valid at least up to the most recent block
1725 // the user could have gotten from another RPC command prior to now
1726 pwallet->BlockUntilSyncedToCurrentChain();
1727
1728 LOCK(pwallet->cs_wallet);
1729
1730 uint256 hash(ParseHashV(request.params[0], "txid"));
1731
1733
1734 if (ParseIncludeWatchonly(request.params[1], *pwallet)) {
1735 filter |= ISMINE_WATCH_ONLY;
1736 }
1737
1738 bool verbose = request.params[2].isNull() ? false : request.params[2].get_bool();
1739
1740 UniValue entry(UniValue::VOBJ);
1741 auto it = pwallet->mapWallet.find(hash);
1742 if (it == pwallet->mapWallet.end()) {
1743 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1744 }
1745 const CWalletTx& wtx = it->second;
1746
1747 CAmount nCredit = CachedTxGetCredit(*pwallet, wtx, filter);
1748 CAmount nDebit = CachedTxGetDebit(*pwallet, wtx, filter);
1749 CAmount nNet = nCredit - nDebit;
1750 CAmount nFee = (CachedTxIsFromMe(*pwallet, wtx, filter) ? wtx.tx->GetValueOut() - nDebit : 0);
1751
1752 entry.pushKV("amount", ValueFromAmount(nNet - nFee));
1753 if (CachedTxIsFromMe(*pwallet, wtx, filter))
1754 entry.pushKV("fee", ValueFromAmount(nFee));
1755
1756 WalletTxToJSON(*pwallet, wtx, entry);
1757
1758 UniValue details(UniValue::VARR);
1759 ListTransactions(*pwallet, wtx, 0, false, details, filter, nullptr /* filter_label */);
1760 entry.pushKV("details", details);
1761
1762 std::string strHex = EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
1763 entry.pushKV("hex", strHex);
1764
1765 if (verbose) {
1766 UniValue decoded(UniValue::VOBJ);
1767 TxToUniv(*wtx.tx, uint256(), decoded, false);
1768 entry.pushKV("decoded", decoded);
1769 }
1770
1771 return entry;
1772},
1773 };
1774}
1775
1777{
1778 return RPCHelpMan{"abandontransaction",
1779 "\nMark in-wallet transaction <txid> as abandoned\n"
1780 "This will mark this transaction and all its in-wallet descendants as abandoned which will allow\n"
1781 "for their inputs to be respent. It can be used to replace \"stuck\" or evicted transactions.\n"
1782 "It only works on transactions which are not included in a block and are not currently in the mempool.\n"
1783 "It has no effect on transactions which are already abandoned.\n",
1784 {
1785 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
1786 },
1789 HelpExampleCli("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1790 + HelpExampleRpc("abandontransaction", "\"1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d\"")
1791 },
1792 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1793{
1794 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
1795 if (!pwallet) return NullUniValue;
1796
1797 // Make sure the results are valid at least up to the most recent block
1798 // the user could have gotten from another RPC command prior to now
1799 pwallet->BlockUntilSyncedToCurrentChain();
1800
1801 LOCK(pwallet->cs_wallet);
1802
1803 uint256 hash(ParseHashV(request.params[0], "txid"));
1804
1805 if (!pwallet->mapWallet.count(hash)) {
1806 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid or non-wallet transaction id");
1807 }
1808 if (!pwallet->AbandonTransaction(hash)) {
1809 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction not eligible for abandonment");
1810 }
1811
1812 return NullUniValue;
1813},
1814 };
1815}
1816
1817
1819{
1820 return RPCHelpMan{"backupwallet",
1821 "\nSafely copies current wallet file to destination, which can be a directory or a path with filename.\n",
1822 {
1823 {"destination", RPCArg::Type::STR, RPCArg::Optional::NO, "The destination directory or file"},
1824 },
1827 HelpExampleCli("backupwallet", "\"backup.dat\"")
1828 + HelpExampleRpc("backupwallet", "\"backup.dat\"")
1829 },
1830 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1831{
1832 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
1833 if (!pwallet) return NullUniValue;
1834
1835 // Make sure the results are valid at least up to the most recent block
1836 // the user could have gotten from another RPC command prior to now
1837 pwallet->BlockUntilSyncedToCurrentChain();
1838
1839 LOCK(pwallet->cs_wallet);
1840
1841 std::string strDest = request.params[0].get_str();
1842 if (!pwallet->BackupWallet(strDest)) {
1843 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
1844 }
1845
1846 return NullUniValue;
1847},
1848 };
1849}
1850
1851
1853{
1854 return RPCHelpMan{"keypoolrefill",
1855 "\nFills the keypool."+
1857 {
1858 {"newsize", RPCArg::Type::NUM, RPCArg::DefaultHint{strprintf("%u, or as set by -keypool", DEFAULT_KEYPOOL_SIZE)}, "The new keypool size"},
1859 },
1862 HelpExampleCli("keypoolrefill", "")
1863 + HelpExampleRpc("keypoolrefill", "")
1864 },
1865 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1866{
1867 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
1868 if (!pwallet) return NullUniValue;
1869
1870 if (pwallet->IsLegacy() && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1871 throw JSONRPCError(RPC_WALLET_ERROR, "Error: Private keys are disabled for this wallet");
1872 }
1873
1874 LOCK(pwallet->cs_wallet);
1875
1876 // 0 is interpreted by TopUpKeyPool() as the default keypool size given by -keypool
1877 unsigned int kpSize = 0;
1878 if (!request.params[0].isNull()) {
1879 if (request.params[0].get_int() < 0)
1880 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected valid size.");
1881 kpSize = (unsigned int)request.params[0].get_int();
1882 }
1883
1884 EnsureWalletIsUnlocked(*pwallet);
1885 pwallet->TopUpKeyPool(kpSize);
1886
1887 if (pwallet->GetKeyPoolSize() < kpSize) {
1888 throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
1889 }
1890
1891 return NullUniValue;
1892},
1893 };
1894}
1895
1896
1898{
1899 return RPCHelpMan{"newkeypool",
1900 "\nEntirely clears and refills the keypool."+
1902 {},
1905 HelpExampleCli("newkeypool", "")
1906 + HelpExampleRpc("newkeypool", "")
1907 },
1908 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1909{
1910 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
1911 if (!pwallet) return NullUniValue;
1912
1913 LOCK(pwallet->cs_wallet);
1914
1915 LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
1916 spk_man.NewKeyPool();
1917
1918 return NullUniValue;
1919},
1920 };
1921}
1922
1923
1925{
1926 return RPCHelpMan{"walletpassphrase",
1927 "\nStores the wallet decryption key in memory for 'timeout' seconds.\n"
1928 "This is needed prior to performing transactions related to private keys such as sending bitcoins\n"
1929 "\nNote:\n"
1930 "Issuing the walletpassphrase command while the wallet is already unlocked will set a new unlock\n"
1931 "time that overrides the old one.\n",
1932 {
1933 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
1934 {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
1935 },
1938 "\nUnlock the wallet for 60 seconds\n"
1939 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
1940 "\nLock the wallet again (before 60 seconds)\n"
1941 + HelpExampleCli("walletlock", "") +
1942 "\nAs a JSON-RPC call\n"
1943 + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
1944 },
1945 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1946{
1947 std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1948 if (!wallet) return NullUniValue;
1949 CWallet* const pwallet = wallet.get();
1950
1951 int64_t nSleepTime;
1952 int64_t relock_time;
1953 // Prevent concurrent calls to walletpassphrase with the same wallet.
1954 LOCK(pwallet->m_unlock_mutex);
1955 {
1956 LOCK(pwallet->cs_wallet);
1957
1958 if (!pwallet->IsCrypted()) {
1959 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrase was called.");
1960 }
1961
1962 // Note that the walletpassphrase is stored in request.params[0] which is not mlock()ed
1963 SecureString strWalletPass;
1964 strWalletPass.reserve(100);
1965 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
1966 // Alternately, find a way to make request.params[0] mlock()'d to begin with.
1967 strWalletPass = request.params[0].get_str().c_str();
1968
1969 // Get the timeout
1970 nSleepTime = request.params[1].get_int64();
1971 // Timeout cannot be negative, otherwise it will relock immediately
1972 if (nSleepTime < 0) {
1973 throw JSONRPCError(RPC_INVALID_PARAMETER, "Timeout cannot be negative.");
1974 }
1975 // Clamp timeout
1976 constexpr int64_t MAX_SLEEP_TIME = 100000000; // larger values trigger a macos/libevent bug?
1977 if (nSleepTime > MAX_SLEEP_TIME) {
1978 nSleepTime = MAX_SLEEP_TIME;
1979 }
1980
1981 if (strWalletPass.empty()) {
1982 throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
1983 }
1984
1985 if (!pwallet->Unlock(strWalletPass)) {
1986 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
1987 }
1988
1989 pwallet->TopUpKeyPool();
1990
1991 pwallet->nRelockTime = GetTime() + nSleepTime;
1992 relock_time = pwallet->nRelockTime;
1993 }
1994
1995 // rpcRunLater must be called without cs_wallet held otherwise a deadlock
1996 // can occur. The deadlock would happen when RPCRunLater removes the
1997 // previous timer (and waits for the callback to finish if already running)
1998 // and the callback locks cs_wallet.
1999 AssertLockNotHeld(wallet->cs_wallet);
2000 // Keep a weak pointer to the wallet so that it is possible to unload the
2001 // wallet before the following callback is called. If a valid shared pointer
2002 // is acquired in the callback then the wallet is still loaded.
2003 std::weak_ptr<CWallet> weak_wallet = wallet;
2004 pwallet->chain().rpcRunLater(strprintf("lockwallet(%s)", pwallet->GetName()), [weak_wallet, relock_time] {
2005 if (auto shared_wallet = weak_wallet.lock()) {
2006 LOCK(shared_wallet->cs_wallet);
2007 // Skip if this is not the most recent rpcRunLater callback.
2008 if (shared_wallet->nRelockTime != relock_time) return;
2009 shared_wallet->Lock();
2010 shared_wallet->nRelockTime = 0;
2011 }
2012 }, nSleepTime);
2013
2014 return NullUniValue;
2015},
2016 };
2017}
2018
2019
2021{
2022 return RPCHelpMan{"walletpassphrasechange",
2023 "\nChanges the wallet passphrase from 'oldpassphrase' to 'newpassphrase'.\n",
2024 {
2025 {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The current passphrase"},
2026 {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The new passphrase"},
2027 },
2030 HelpExampleCli("walletpassphrasechange", "\"old one\" \"new one\"")
2031 + HelpExampleRpc("walletpassphrasechange", "\"old one\", \"new one\"")
2032 },
2033 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2034{
2035 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
2036 if (!pwallet) return NullUniValue;
2037
2038 LOCK(pwallet->cs_wallet);
2039
2040 if (!pwallet->IsCrypted()) {
2041 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletpassphrasechange was called.");
2042 }
2043
2044 // TODO: get rid of these .c_str() calls by implementing SecureString::operator=(std::string)
2045 // Alternately, find a way to make request.params[0] mlock()'d to begin with.
2046 SecureString strOldWalletPass;
2047 strOldWalletPass.reserve(100);
2048 strOldWalletPass = request.params[0].get_str().c_str();
2049
2050 SecureString strNewWalletPass;
2051 strNewWalletPass.reserve(100);
2052 strNewWalletPass = request.params[1].get_str().c_str();
2053
2054 if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
2055 throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
2056 }
2057
2058 if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
2059 throw JSONRPCError(RPC_WALLET_PASSPHRASE_INCORRECT, "Error: The wallet passphrase entered was incorrect.");
2060 }
2061
2062 return NullUniValue;
2063},
2064 };
2065}
2066
2067
2069{
2070 return RPCHelpMan{"walletlock",
2071 "\nRemoves the wallet encryption key from memory, locking the wallet.\n"
2072 "After calling this method, you will need to call walletpassphrase again\n"
2073 "before being able to call any methods which require the wallet to be unlocked.\n",
2074 {},
2077 "\nSet the passphrase for 2 minutes to perform a transaction\n"
2078 + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2079 "\nPerform a send (requires passphrase set)\n"
2080 + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 1.0") +
2081 "\nClear the passphrase since we are done before 2 minutes is up\n"
2082 + HelpExampleCli("walletlock", "") +
2083 "\nAs a JSON-RPC call\n"
2084 + HelpExampleRpc("walletlock", "")
2085 },
2086 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2087{
2088 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
2089 if (!pwallet) return NullUniValue;
2090
2091 LOCK(pwallet->cs_wallet);
2092
2093 if (!pwallet->IsCrypted()) {
2094 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an unencrypted wallet, but walletlock was called.");
2095 }
2096
2097 pwallet->Lock();
2098 pwallet->nRelockTime = 0;
2099
2100 return NullUniValue;
2101},
2102 };
2103}
2104
2105
2107{
2108 return RPCHelpMan{"encryptwallet",
2109 "\nEncrypts the wallet with 'passphrase'. This is for first time encryption.\n"
2110 "After this, any calls that interact with private keys such as sending or signing \n"
2111 "will require the passphrase to be set prior the making these calls.\n"
2112 "Use the walletpassphrase call for this, and then walletlock call.\n"
2113 "If the wallet is already encrypted, use the walletpassphrasechange call.\n",
2114 {
2115 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The pass phrase to encrypt the wallet with. It must be at least 1 character, but should be long."},
2116 },
2117 RPCResult{RPCResult::Type::STR, "", "A string with further instructions"},
2119 "\nEncrypt your wallet\n"
2120 + HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2121 "\nNow set the passphrase to use the wallet, such as for signing or sending bitcoin\n"
2122 + HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2123 "\nNow we can do something like sign\n"
2124 + HelpExampleCli("signmessage", "\"address\" \"test message\"") +
2125 "\nNow lock the wallet again by removing the passphrase\n"
2126 + HelpExampleCli("walletlock", "") +
2127 "\nAs a JSON-RPC call\n"
2128 + HelpExampleRpc("encryptwallet", "\"my pass phrase\"")
2129 },
2130 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2131{
2132 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
2133 if (!pwallet) return NullUniValue;
2134
2135 LOCK(pwallet->cs_wallet);
2136
2137 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
2138 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: wallet does not contain private keys, nothing to encrypt.");
2139 }
2140
2141 if (pwallet->IsCrypted()) {
2142 throw JSONRPCError(RPC_WALLET_WRONG_ENC_STATE, "Error: running with an encrypted wallet, but encryptwallet was called.");
2143 }
2144
2145 // TODO: get rid of this .c_str() by implementing SecureString::operator=(std::string)
2146 // Alternately, find a way to make request.params[0] mlock()'d to begin with.
2147 SecureString strWalletPass;
2148 strWalletPass.reserve(100);
2149 strWalletPass = request.params[0].get_str().c_str();
2150
2151 if (strWalletPass.empty()) {
2152 throw JSONRPCError(RPC_INVALID_PARAMETER, "passphrase can not be empty");
2153 }
2154
2155 if (!pwallet->EncryptWallet(strWalletPass)) {
2156 throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, "Error: Failed to encrypt the wallet.");
2157 }
2158
2159 return "wallet encrypted; The keypool has been flushed and a new HD seed was generated (if you are using HD). You need to make a new backup.";
2160},
2161 };
2162}
2163
2165{
2166 return RPCHelpMan{"lockunspent",
2167 "\nUpdates list of temporarily unspendable outputs.\n"
2168 "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
2169 "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
2170 "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
2171 "Manually selected coins are automatically unlocked.\n"
2172 "Locks are stored in memory only, unless persistent=true, in which case they will be written to the\n"
2173 "wallet database and loaded on node start. Unwritten (persistent=false) locks are always cleared\n"
2174 "(by virtue of process exit) when a node stops or fails. Unlocking will clear both persistent and not.\n"
2175 "Also see the listunspent call\n",
2176 {
2177 {"unlock", RPCArg::Type::BOOL, RPCArg::Optional::NO, "Whether to unlock (true) or lock (false) the specified transactions"},
2178 {"transactions", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The transaction outputs and within each, the txid (string) vout (numeric).",
2179 {
2181 {
2182 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
2183 {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
2184 },
2185 },
2186 },
2187 },
2188 {"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."},
2189 },
2190 RPCResult{
2191 RPCResult::Type::BOOL, "", "Whether the command was successful or not"
2192 },
2194 "\nList the unspent transactions\n"
2195 + HelpExampleCli("listunspent", "") +
2196 "\nLock an unspent transaction\n"
2197 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2198 "\nList the locked transactions\n"
2199 + HelpExampleCli("listlockunspent", "") +
2200 "\nUnlock the transaction again\n"
2201 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2202 "\nLock the transaction persistently in the wallet database\n"
2203 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\" true") +
2204 "\nAs a JSON-RPC call\n"
2205 + HelpExampleRpc("lockunspent", "false, \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"")
2206 },
2207 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2208{
2209 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
2210 if (!pwallet) return NullUniValue;
2211
2212 // Make sure the results are valid at least up to the most recent block
2213 // the user could have gotten from another RPC command prior to now
2214 pwallet->BlockUntilSyncedToCurrentChain();
2215
2216 LOCK(pwallet->cs_wallet);
2217
2218 RPCTypeCheckArgument(request.params[0], UniValue::VBOOL);
2219
2220 bool fUnlock = request.params[0].get_bool();
2221
2222 const bool persistent{request.params[2].isNull() ? false : request.params[2].get_bool()};
2223
2224 if (request.params[1].isNull()) {
2225 if (fUnlock) {
2226 if (!pwallet->UnlockAllCoins())
2227 throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coins failed");
2228 }
2229 return true;
2230 }
2231
2232 RPCTypeCheckArgument(request.params[1], UniValue::VARR);
2233
2234 const UniValue& output_params = request.params[1];
2235
2236 // Create and validate the COutPoints first.
2237
2238 std::vector<COutPoint> outputs;
2239 outputs.reserve(output_params.size());
2240
2241 for (unsigned int idx = 0; idx < output_params.size(); idx++) {
2242 const UniValue& o = output_params[idx].get_obj();
2243
2245 {
2246 {"txid", UniValueType(UniValue::VSTR)},
2247 {"vout", UniValueType(UniValue::VNUM)},
2248 });
2249
2250 const uint256 txid(ParseHashO(o, "txid"));
2251 const int nOutput = find_value(o, "vout").get_int();
2252 if (nOutput < 0) {
2253 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
2254 }
2255
2256 const COutPoint outpt(txid, nOutput);
2257
2258 const auto it = pwallet->mapWallet.find(outpt.hash);
2259 if (it == pwallet->mapWallet.end()) {
2260 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, unknown transaction");
2261 }
2262
2263 const CWalletTx& trans = it->second;
2264
2265 if (outpt.n >= trans.tx->vout.size()) {
2266 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout index out of bounds");
2267 }
2268
2269 if (pwallet->IsSpent(outpt.hash, outpt.n)) {
2270 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected unspent output");
2271 }
2272
2273 const bool is_locked = pwallet->IsLockedCoin(outpt.hash, outpt.n);
2274
2275 if (fUnlock && !is_locked) {
2276 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, expected locked output");
2277 }
2278
2279 if (!fUnlock && is_locked && !persistent) {
2280 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output already locked");
2281 }
2282
2283 outputs.push_back(outpt);
2284 }
2285
2286 std::unique_ptr<WalletBatch> batch = nullptr;
2287 // Unlock is always persistent
2288 if (fUnlock || persistent) batch = std::make_unique<WalletBatch>(pwallet->GetDatabase());
2289
2290 // Atomically set (un)locked status for the outputs.
2291 for (const COutPoint& outpt : outputs) {
2292 if (fUnlock) {
2293 if (!pwallet->UnlockCoin(outpt, batch.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Unlocking coin failed");
2294 } else {
2295 if (!pwallet->LockCoin(outpt, batch.get())) throw JSONRPCError(RPC_WALLET_ERROR, "Locking coin failed");
2296 }
2297 }
2298
2299 return true;
2300},
2301 };
2302}
2303
2305{
2306 return RPCHelpMan{"listlockunspent",
2307 "\nReturns list of temporarily unspendable outputs.\n"
2308 "See the lockunspent call to lock and unlock transactions for spending.\n",
2309 {},
2310 RPCResult{
2311 RPCResult::Type::ARR, "", "",
2312 {
2313 {RPCResult::Type::OBJ, "", "",
2314 {
2315 {RPCResult::Type::STR_HEX, "txid", "The transaction id locked"},
2316 {RPCResult::Type::NUM, "vout", "The vout value"},
2317 }},
2318 }
2319 },
2321 "\nList the unspent transactions\n"
2322 + HelpExampleCli("listunspent", "") +
2323 "\nLock an unspent transaction\n"
2324 + HelpExampleCli("lockunspent", "false \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2325 "\nList the locked transactions\n"
2326 + HelpExampleCli("listlockunspent", "") +
2327 "\nUnlock the transaction again\n"
2328 + HelpExampleCli("lockunspent", "true \"[{\\\"txid\\\":\\\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\\\",\\\"vout\\\":1}]\"") +
2329 "\nAs a JSON-RPC call\n"
2330 + HelpExampleRpc("listlockunspent", "")
2331 },
2332 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2333{
2334 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
2335 if (!pwallet) return NullUniValue;
2336
2337 LOCK(pwallet->cs_wallet);
2338
2339 std::vector<COutPoint> vOutpts;
2340 pwallet->ListLockedCoins(vOutpts);
2341
2343
2344 for (const COutPoint& outpt : vOutpts) {
2346
2347 o.pushKV("txid", outpt.hash.GetHex());
2348 o.pushKV("vout", (int)outpt.n);
2349 ret.push_back(o);
2350 }
2351
2352 return ret;
2353},
2354 };
2355}
2356
2358{
2359 return RPCHelpMan{"settxfee",
2360 "\nSet the transaction fee rate in " + CURRENCY_UNIT + "/kvB for this wallet. Overrides the global -paytxfee command line parameter.\n"
2361 "Can be deactivated by passing 0 as the fee. In that case automatic fee selection will be used by default.\n",
2362 {
2363 {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The transaction fee rate in " + CURRENCY_UNIT + "/kvB"},
2364 },
2365 RPCResult{
2366 RPCResult::Type::BOOL, "", "Returns true if successful"
2367 },
2369 HelpExampleCli("settxfee", "0.00001")
2370 + HelpExampleRpc("settxfee", "0.00001")
2371 },
2372 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2373{
2374 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
2375 if (!pwallet) return NullUniValue;
2376
2377 LOCK(pwallet->cs_wallet);
2378
2379 CAmount nAmount = AmountFromValue(request.params[0]);
2380 CFeeRate tx_fee_rate(nAmount, 1000);
2381 CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
2382 if (tx_fee_rate == CFeeRate(0)) {
2383 // automatic selection
2384 } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
2385 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
2386 } else if (tx_fee_rate < pwallet->m_min_fee) {
2387 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
2388 } else if (tx_fee_rate > max_tx_fee_rate) {
2389 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be more than wallet max tx fee (%s)", max_tx_fee_rate.ToString()));
2390 }
2391
2392 pwallet->m_pay_tx_fee = tx_fee_rate;
2393 return true;
2394},
2395 };
2396}
2397
2399{
2400 return RPCHelpMan{
2401 "getbalances",
2402 "Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
2403 {},
2404 RPCResult{
2405 RPCResult::Type::OBJ, "", "",
2406 {
2407 {RPCResult::Type::OBJ, "mine", "balances from outputs that the wallet can sign",
2408 {
2409 {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
2410 {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
2411 {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
2412 {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)"},
2413 }},
2414 {RPCResult::Type::OBJ, "watchonly", /* optional */ true, "watchonly balances (not present if wallet does not watch anything)",
2415 {
2416 {RPCResult::Type::STR_AMOUNT, "trusted", "trusted balance (outputs created by the wallet or confirmed outputs)"},
2417 {RPCResult::Type::STR_AMOUNT, "untrusted_pending", "untrusted pending balance (outputs created by others that are in the mempool)"},
2418 {RPCResult::Type::STR_AMOUNT, "immature", "balance from immature coinbase outputs"},
2419 }},
2420 }
2421 },
2423 HelpExampleCli("getbalances", "") +
2424 HelpExampleRpc("getbalances", "")},
2425 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2426{
2427 const std::shared_ptr<const CWallet> rpc_wallet = GetWalletForJSONRPCRequest(request);
2428 if (!rpc_wallet) return NullUniValue;
2429 const CWallet& wallet = *rpc_wallet;
2430
2431 // Make sure the results are valid at least up to the most recent block
2432 // the user could have gotten from another RPC command prior to now
2433 wallet.BlockUntilSyncedToCurrentChain();
2434
2435 LOCK(wallet.cs_wallet);
2436
2437 const auto bal = GetBalance(wallet);
2438 UniValue balances{UniValue::VOBJ};
2439 {
2440 UniValue balances_mine{UniValue::VOBJ};
2441 balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
2442 balances_mine.pushKV("untrusted_pending", ValueFromAmount(bal.m_mine_untrusted_pending));
2443 balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
2444 if (wallet.IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE)) {
2445 // If the AVOID_REUSE flag is set, bal has been set to just the un-reused address balance. Get
2446 // the total balance, and then subtract bal to get the reused address balance.
2447 const auto full_bal = GetBalance(wallet, 0, false);
2448 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));
2449 }
2450 balances.pushKV("mine", balances_mine);
2451 }
2452 auto spk_man = wallet.GetLegacyScriptPubKeyMan();
2453 if (spk_man && spk_man->HaveWatchOnly()) {
2454 UniValue balances_watchonly{UniValue::VOBJ};
2455 balances_watchonly.pushKV("trusted", ValueFromAmount(bal.m_watchonly_trusted));
2456 balances_watchonly.pushKV("untrusted_pending", ValueFromAmount(bal.m_watchonly_untrusted_pending));
2457 balances_watchonly.pushKV("immature", ValueFromAmount(bal.m_watchonly_immature));
2458 balances.pushKV("watchonly", balances_watchonly);
2459 }
2460 return balances;
2461},
2462 };
2463}
2464
2466{
2467 return RPCHelpMan{"getwalletinfo",
2468 "Returns an object containing various wallet state info.\n",
2469 {},
2470 RPCResult{
2471 RPCResult::Type::OBJ, "", "",
2472 {
2473 {
2474 {RPCResult::Type::STR, "walletname", "the wallet name"},
2475 {RPCResult::Type::NUM, "walletversion", "the wallet version"},
2476 {RPCResult::Type::STR, "format", "the database format (bdb or sqlite)"},
2477 {RPCResult::Type::STR_AMOUNT, "balance", "DEPRECATED. Identical to getbalances().mine.trusted"},
2478 {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance", "DEPRECATED. Identical to getbalances().mine.untrusted_pending"},
2479 {RPCResult::Type::STR_AMOUNT, "immature_balance", "DEPRECATED. Identical to getbalances().mine.immature"},
2480 {RPCResult::Type::NUM, "txcount", "the total number of transactions in the wallet"},
2481 {RPCResult::Type::NUM_TIME, "keypoololdest", /* optional */ true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only."},
2482 {RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
2483 {RPCResult::Type::NUM, "keypoolsize_hd_internal", /* optional */ true, "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
2484 {RPCResult::Type::NUM_TIME, "unlocked_until", /* optional */ true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
2485 {RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kvB"},
2486 {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "the Hash160 of the HD seed (only present when HD is enabled)"},
2487 {RPCResult::Type::BOOL, "private_keys_enabled", "false if privatekeys are disabled for this wallet (enforced watch-only wallet)"},
2488 {RPCResult::Type::BOOL, "avoid_reuse", "whether this wallet tracks clean/dirty coins in terms of reuse"},
2489 {RPCResult::Type::OBJ, "scanning", "current scanning details, or false if no scan is in progress",
2490 {
2491 {RPCResult::Type::NUM, "duration", "elapsed seconds since scan start"},
2492 {RPCResult::Type::NUM, "progress", "scanning progress percentage [0.0, 1.0]"},
2493 }},
2494 {RPCResult::Type::BOOL, "descriptors", "whether this wallet uses descriptors for scriptPubKey management"},
2495 }},
2496 },
2498 HelpExampleCli("getwalletinfo", "")
2499 + HelpExampleRpc("getwalletinfo", "")
2500 },
2501 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2502{
2503 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
2504 if (!pwallet) return NullUniValue;
2505
2506 // Make sure the results are valid at least up to the most recent block
2507 // the user could have gotten from another RPC command prior to now
2508 pwallet->BlockUntilSyncedToCurrentChain();
2509
2510 LOCK(pwallet->cs_wallet);
2511
2513
2514 size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
2515 const auto bal = GetBalance(*pwallet);
2516 int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
2517 obj.pushKV("walletname", pwallet->GetName());
2518 obj.pushKV("walletversion", pwallet->GetVersion());
2519 obj.pushKV("format", pwallet->GetDatabase().Format());
2520 obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
2521 obj.pushKV("unconfirmed_balance", ValueFromAmount(bal.m_mine_untrusted_pending));
2522 obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
2523 obj.pushKV("txcount", (int)pwallet->mapWallet.size());
2524 if (kp_oldest > 0) {
2525 obj.pushKV("keypoololdest", kp_oldest);
2526 }
2527 obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
2528
2529 LegacyScriptPubKeyMan* spk_man = pwallet->GetLegacyScriptPubKeyMan();
2530 if (spk_man) {
2531 CKeyID seed_id = spk_man->GetHDChain().seed_id;
2532 if (!seed_id.IsNull()) {
2533 obj.pushKV("hdseedid", seed_id.GetHex());
2534 }
2535 }
2536
2537 if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
2538 obj.pushKV("keypoolsize_hd_internal", (int64_t)(pwallet->GetKeyPoolSize() - kpExternalSize));
2539 }
2540 if (pwallet->IsCrypted()) {
2541 obj.pushKV("unlocked_until", pwallet->nRelockTime);
2542 }
2543 obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
2544 obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
2545 obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
2546 if (pwallet->IsScanning()) {
2547 UniValue scanning(UniValue::VOBJ);
2548 scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
2549 scanning.pushKV("progress", pwallet->ScanningProgress());
2550 obj.pushKV("scanning", scanning);
2551 } else {
2552 obj.pushKV("scanning", false);
2553 }
2554 obj.pushKV("descriptors", pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
2555 return obj;
2556},
2557 };
2558}
2559
2561{
2562 return RPCHelpMan{"listwalletdir",
2563 "Returns a list of wallets in the wallet directory.\n",
2564 {},
2565 RPCResult{
2566 RPCResult::Type::OBJ, "", "",
2567 {
2568 {RPCResult::Type::ARR, "wallets", "",
2569 {
2570 {RPCResult::Type::OBJ, "", "",
2571 {
2572 {RPCResult::Type::STR, "name", "The wallet name"},
2573 }},
2574 }},
2575 }
2576 },
2578 HelpExampleCli("listwalletdir", "")
2579 + HelpExampleRpc("listwalletdir", "")
2580 },
2581 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2582{
2583 UniValue wallets(UniValue::VARR);
2584 for (const auto& path : ListDatabases(GetWalletDir())) {
2586 wallet.pushKV("name", path.u8string());
2587 wallets.push_back(wallet);
2588 }
2589
2590 UniValue result(UniValue::VOBJ);
2591 result.pushKV("wallets", wallets);
2592 return result;
2593},
2594 };
2595}
2596
2598{
2599 return RPCHelpMan{"listwallets",
2600 "Returns a list of currently loaded wallets.\n"
2601 "For full information on the wallet, use \"getwalletinfo\"\n",
2602 {},
2603 RPCResult{
2604 RPCResult::Type::ARR, "", "",
2605 {
2606 {RPCResult::Type::STR, "walletname", "the wallet name"},
2607 }
2608 },
2610 HelpExampleCli("listwallets", "")
2611 + HelpExampleRpc("listwallets", "")
2612 },
2613 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2614{
2616
2617 WalletContext& context = EnsureWalletContext(request.context);
2618 for (const std::shared_ptr<CWallet>& wallet : GetWallets(context)) {
2619 LOCK(wallet->cs_wallet);
2620 obj.push_back(wallet->GetName());
2621 }
2622
2623 return obj;
2624},
2625 };
2626}
2627
2628static std::tuple<std::shared_ptr<CWallet>, std::vector<bilingual_str>> LoadWalletHelper(WalletContext& context, UniValue load_on_start_param, const std::string wallet_name)
2629{
2630 DatabaseOptions options;
2631 DatabaseStatus status;
2632 options.require_existing = true;
2634 std::vector<bilingual_str> warnings;
2635 std::optional<bool> load_on_start = load_on_start_param.isNull() ? std::nullopt : std::optional<bool>(load_on_start_param.get_bool());
2636 std::shared_ptr<CWallet> const wallet = LoadWallet(context, wallet_name, load_on_start, options, status, error, warnings);
2637
2638 if (!wallet) {
2639 // Map bad format to not found, since bad format is returned when the
2640 // wallet directory exists, but doesn't contain a data file.
2642 switch (status) {
2645 code = RPC_WALLET_NOT_FOUND;
2646 break;
2649 break;
2650 default: // RPC_WALLET_ERROR is returned for all other cases.
2651 break;
2652 }
2653 throw JSONRPCError(code, error.original);
2654 }
2655
2656 return { wallet, warnings };
2657}
2658
2660{
2661 return RPCHelpMan{"loadwallet",
2662 "\nLoads a wallet from a wallet file or directory."
2663 "\nNote that all wallet command-line options used when starting bitcoind will be"
2664 "\napplied to the new wallet.\n",
2665 {
2666 {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
2667 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
2668 },
2669 RPCResult{
2670 RPCResult::Type::OBJ, "", "",
2671 {
2672 {RPCResult::Type::STR, "name", "The wallet name if loaded successfully."},
2673 {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
2674 }
2675 },
2677 HelpExampleCli("loadwallet", "\"test.dat\"")
2678 + HelpExampleRpc("loadwallet", "\"test.dat\"")
2679 },
2680 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2681{
2682 WalletContext& context = EnsureWalletContext(request.context);
2683 const std::string name(request.params[0].get_str());
2684
2685 auto [wallet, warnings] = LoadWalletHelper(context, request.params[1], name);
2686
2688 obj.pushKV("name", wallet->GetName());
2689 obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2690
2691 return obj;
2692},
2693 };
2694}
2695
2697{
2698 std::string flags = "";
2699 for (auto& it : WALLET_FLAG_MAP)
2700 if (it.second & MUTABLE_WALLET_FLAGS)
2701 flags += (flags == "" ? "" : ", ") + it.first;
2702
2703 return RPCHelpMan{"setwalletflag",
2704 "\nChange the state of the given wallet flag for a wallet.\n",
2705 {
2706 {"flag", RPCArg::Type::STR, RPCArg::Optional::NO, "The name of the flag to change. Current available flags: " + flags},
2707 {"value", RPCArg::Type::BOOL, RPCArg::Default{true}, "The new state."},
2708 },
2709 RPCResult{
2710 RPCResult::Type::OBJ, "", "",
2711 {
2712 {RPCResult::Type::STR, "flag_name", "The name of the flag that was modified"},
2713 {RPCResult::Type::BOOL, "flag_state", "The new state of the flag"},
2714 {RPCResult::Type::STR, "warnings", "Any warnings associated with the change"},
2715 }
2716 },
2718 HelpExampleCli("setwalletflag", "avoid_reuse")
2719 + HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")
2720 },
2721 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2722{
2723 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
2724 if (!pwallet) return NullUniValue;
2725
2726 std::string flag_str = request.params[0].get_str();
2727 bool value = request.params[1].isNull() || request.params[1].get_bool();
2728
2729 if (!WALLET_FLAG_MAP.count(flag_str)) {
2730 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unknown wallet flag: %s", flag_str));
2731 }
2732
2733 auto flag = WALLET_FLAG_MAP.at(flag_str);
2734
2735 if (!(flag & MUTABLE_WALLET_FLAGS)) {
2736 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is immutable: %s", flag_str));
2737 }
2738
2740
2741 if (pwallet->IsWalletFlagSet(flag) == value) {
2742 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Wallet flag is already set to %s: %s", value ? "true" : "false", flag_str));
2743 }
2744
2745 res.pushKV("flag_name", flag_str);
2746 res.pushKV("flag_state", value);
2747
2748 if (value) {
2749 pwallet->SetWalletFlag(flag);
2750 } else {
2751 pwallet->UnsetWalletFlag(flag);
2752 }
2753
2754 if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
2755 res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
2756 }
2757
2758 return res;
2759},
2760 };
2761}
2762
2764{
2765 return RPCHelpMan{
2766 "createwallet",
2767 "\nCreates and loads a new wallet.\n",
2768 {
2769 {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name for the new wallet. If this is a path, the wallet will be created at the path location."},
2770 {"disable_private_keys", RPCArg::Type::BOOL, RPCArg::Default{false}, "Disable the possibility of private keys (only watchonlys are possible in this mode)."},
2771 {"blank", RPCArg::Type::BOOL, RPCArg::Default{false}, "Create a blank wallet. A blank wallet has no keys or HD seed. One can be set using sethdseed."},
2772 {"passphrase", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Encrypt the wallet with this passphrase."},
2773 {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{false}, "Keep track of coin reuse, and treat dirty and clean coins differently with privacy considerations in mind."},
2774 {"descriptors", RPCArg::Type::BOOL, RPCArg::Default{true}, "Create a native descriptor wallet. The wallet will use descriptors internally to handle address creation"},
2775 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
2776 {"external_signer", RPCArg::Type::BOOL, RPCArg::Default{false}, "Use an external signer such as a hardware wallet. Requires -signer to be configured. Wallet creation will fail if keys cannot be fetched. Requires disable_private_keys and descriptors set to true."},
2777 },
2778 RPCResult{
2779 RPCResult::Type::OBJ, "", "",
2780 {
2781 {RPCResult::Type::STR, "name", "The wallet name if created successfully. If the wallet was created using a full path, the wallet_name will be the full path."},
2782 {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
2783 }
2784 },
2786 HelpExampleCli("createwallet", "\"testwallet\"")
2787 + HelpExampleRpc("createwallet", "\"testwallet\"")
2788 + HelpExampleCliNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
2789 + HelpExampleRpcNamed("createwallet", {{"wallet_name", "descriptors"}, {"avoid_reuse", true}, {"descriptors", true}, {"load_on_startup", true}})
2790 },
2791 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2792{
2793 WalletContext& context = EnsureWalletContext(request.context);
2794 uint64_t flags = 0;
2795 if (!request.params[1].isNull() && request.params[1].get_bool()) {
2797 }
2798
2799 if (!request.params[2].isNull() && request.params[2].get_bool()) {
2801 }
2802 SecureString passphrase;
2803 passphrase.reserve(100);
2804 std::vector<bilingual_str> warnings;
2805 if (!request.params[3].isNull()) {
2806 passphrase = request.params[3].get_str().c_str();
2807 if (passphrase.empty()) {
2808 // Empty string means unencrypted
2809 warnings.emplace_back(Untranslated("Empty string given as passphrase, wallet will not be encrypted."));
2810 }
2811 }
2812
2813 if (!request.params[4].isNull() && request.params[4].get_bool()) {
2815 }
2816 if (request.params[5].isNull() || request.params[5].get_bool()) {
2817#ifndef USE_SQLITE
2818 throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without sqlite support (required for descriptor wallets)");
2819#endif
2821 }
2822 if (!request.params[7].isNull() && request.params[7].get_bool()) {
2823#ifdef ENABLE_EXTERNAL_SIGNER
2825#else
2826 throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without external signing support (required for external signing)");
2827#endif
2828 }
2829
2830#ifndef USE_BDB
2831 if (!(flags & WALLET_FLAG_DESCRIPTORS)) {
2832 throw JSONRPCError(RPC_WALLET_ERROR, "Compiled without bdb support (required for legacy wallets)");
2833 }
2834#endif
2835
2836 DatabaseOptions options;
2837 DatabaseStatus status;
2838 options.require_create = true;
2839 options.create_flags = flags;
2840 options.create_passphrase = passphrase;
2842 std::optional<bool> load_on_start = request.params[6].isNull() ? std::nullopt : std::optional<bool>(request.params[6].get_bool());
2843 const std::shared_ptr<CWallet> wallet = CreateWallet(context, request.params[0].get_str(), load_on_start, options, status, error, warnings);
2844 if (!wallet) {
2846 throw JSONRPCError(code, error.original);
2847 }
2848
2850 obj.pushKV("name", wallet->GetName());
2851 obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2852
2853 return obj;
2854},
2855 };
2856}
2857
2859{
2860 return RPCHelpMan{
2861 "restorewallet",
2862 "\nRestore and loads a wallet from backup.\n",
2863 {
2864 {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO, "The name that will be applied to the restored wallet"},
2865 {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO, "The backup file that will be used to restore the wallet."},
2866 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
2867 },
2868 RPCResult{
2869 RPCResult::Type::OBJ, "", "",
2870 {
2871 {RPCResult::Type::STR, "name", "The wallet name if restored successfully."},
2872 {RPCResult::Type::STR, "warning", "Warning message if wallet was not loaded cleanly."},
2873 }
2874 },
2876 HelpExampleCli("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
2877 + HelpExampleRpc("restorewallet", "\"testwallet\" \"home\\backups\\backup-file.bak\"")
2878 + HelpExampleCliNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
2879 + HelpExampleRpcNamed("restorewallet", {{"wallet_name", "testwallet"}, {"backup_file", "home\\backups\\backup-file.bak\""}, {"load_on_startup", true}})
2880 },
2881 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2882{
2883
2884 WalletContext& context = EnsureWalletContext(request.context);
2885
2886 auto backup_file = fs::u8path(request.params[1].get_str());
2887
2888 if (!fs::exists(backup_file)) {
2889 throw JSONRPCError(RPC_INVALID_PARAMETER, "Backup file does not exist");
2890 }
2891
2892 std::string wallet_name = request.params[0].get_str();
2893
2894 const fs::path wallet_path = fsbridge::AbsPathJoin(GetWalletDir(), fs::u8path(wallet_name));
2895
2896 if (fs::exists(wallet_path)) {
2897 throw JSONRPCError(RPC_INVALID_PARAMETER, "Wallet name already exists.");
2898 }
2899
2900 if (!TryCreateDirectories(wallet_path)) {
2901 throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Failed to create database path '%s'. Database already exists.", wallet_path.u8string()));
2902 }
2903
2904 auto wallet_file = wallet_path / "wallet.dat";
2905
2906 fs::copy_file(backup_file, wallet_file, fs::copy_option::fail_if_exists);
2907
2908 auto [wallet, warnings] = LoadWalletHelper(context, request.params[2], wallet_name);
2909
2911 obj.pushKV("name", wallet->GetName());
2912 obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2913
2914 return obj;
2915
2916},
2917 };
2918}
2919
2921{
2922 return RPCHelpMan{"unloadwallet",
2923 "Unloads the wallet referenced by the request endpoint otherwise unloads the wallet specified in the argument.\n"
2924 "Specifying the wallet name on a wallet endpoint is invalid.",
2925 {
2926 {"wallet_name", RPCArg::Type::STR, RPCArg::DefaultHint{"the wallet name from the RPC endpoint"}, "The name of the wallet to unload. If provided both here and in the RPC endpoint, the two must be identical."},
2927 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "Save wallet name to persistent settings and load on startup. True to add wallet to startup list, false to remove, null to leave unchanged."},
2928 },
2930 {RPCResult::Type::STR, "warning", "Warning message if wallet was not unloaded cleanly."},
2931 }},
2933 HelpExampleCli("unloadwallet", "wallet_name")
2934 + HelpExampleRpc("unloadwallet", "wallet_name")
2935 },
2936 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
2937{
2938 std::string wallet_name;
2939 if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
2940 if (!(request.params[0].isNull() || request.params[0].get_str() == wallet_name)) {
2941 throw JSONRPCError(RPC_INVALID_PARAMETER, "RPC endpoint wallet and wallet_name parameter specify different wallets");
2942 }
2943 } else {
2944 wallet_name = request.params[0].get_str();
2945 }
2946
2947 WalletContext& context = EnsureWalletContext(request.context);
2948 std::shared_ptr<CWallet> wallet = GetWallet(context, wallet_name);
2949 if (!wallet) {
2950 throw JSONRPCError(RPC_WALLET_NOT_FOUND, "Requested wallet does not exist or is not loaded");
2951 }
2952
2953 // Release the "main" shared pointer and prevent further notifications.
2954 // Note that any attempt to load the same wallet would fail until the wallet
2955 // is destroyed (see CheckUniqueFileid).
2956 std::vector<bilingual_str> warnings;
2957 std::optional<bool> load_on_start = request.params[1].isNull() ? std::nullopt : std::optional<bool>(request.params[1].get_bool());
2958 if (!RemoveWallet(context, wallet, load_on_start, warnings)) {
2959 throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
2960 }
2961
2962 UnloadWallet(std::move(wallet));
2963
2964 UniValue result(UniValue::VOBJ);
2965 result.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2966 return result;
2967},
2968 };
2969}
2970
2972{
2973 return RPCHelpMan{
2974 "listunspent",
2975 "\nReturns array of unspent transaction outputs\n"
2976 "with between minconf and maxconf (inclusive) confirmations.\n"
2977 "Optionally filter to only include txouts paid to specified addresses.\n",
2978 {
2979 {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum confirmations to filter"},
2980 {"maxconf", RPCArg::Type::NUM, RPCArg::Default{9999999}, "The maximum confirmations to filter"},
2981 {"addresses", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The bitcoin addresses to filter",
2982 {
2983 {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"},
2984 },
2985 },
2986 {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n"
2987 "See description of \"safe\" attribute below."},
2988 {"query_options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "JSON with query options",
2989 {
2990 {"minimumAmount", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(0)}, "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
2991 {"maximumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
2992 {"maximumCount", RPCArg::Type::NUM, RPCArg::DefaultHint{"unlimited"}, "Maximum number of UTXOs"},
2993 {"minimumSumAmount", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"unlimited"}, "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
2994 },
2995 "query_options"},
2996 },
2997 RPCResult{
2998 RPCResult::Type::ARR, "", "",
2999 {
3000 {RPCResult::Type::OBJ, "", "",
3001 {
3002 {RPCResult::Type::STR_HEX, "txid", "the transaction id"},
3003 {RPCResult::Type::NUM, "vout", "the vout value"},
3004 {RPCResult::Type::STR, "address", /* optional */ true, "the bitcoin address"},
3005 {RPCResult::Type::STR, "label", /* optional */ true, "The associated label, or \"\" for the default label"},
3006 {RPCResult::Type::STR, "scriptPubKey", "the script key"},
3007 {RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT},
3008 {RPCResult::Type::NUM, "confirmations", "The number of confirmations"},
3009 {RPCResult::Type::NUM, "ancestorcount", /* optional */ true, "The number of in-mempool ancestor transactions, including this one (if transaction is in the mempool)"},
3010 {RPCResult::Type::NUM, "ancestorsize", /* optional */ true, "The virtual transaction size of in-mempool ancestors, including this one (if transaction is in the mempool)"},
3011 {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)"},
3012 {RPCResult::Type::STR_HEX, "redeemScript", /* optional */ true, "The redeemScript if scriptPubKey is P2SH"},
3013 {RPCResult::Type::STR, "witnessScript", /* optional */ true, "witnessScript if the scriptPubKey is P2WSH or P2SH-P2WSH"},
3014 {RPCResult::Type::BOOL, "spendable", "Whether we have the private keys to spend this output"},
3015 {RPCResult::Type::BOOL, "solvable", "Whether we know how to spend this output, ignoring the lack of keys"},
3016 {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)"},
3017 {RPCResult::Type::STR, "desc", /* optional */ true, "(only when solvable) A descriptor for spending this output"},
3018 {RPCResult::Type::BOOL, "safe", "Whether this output is considered safe to spend. Unconfirmed transactions\n"
3019 "from outside keys and unconfirmed replacement transactions are considered unsafe\n"
3020 "and are not eligible for spending by fundrawtransaction and sendtoaddress."},
3021 }},
3022 }
3023 },
3025 HelpExampleCli("listunspent", "")
3026 + HelpExampleCli("listunspent", "6 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
3027 + HelpExampleRpc("listunspent", "6, 9999999 \"[\\\"" + EXAMPLE_ADDRESS[0] + "\\\",\\\"" + EXAMPLE_ADDRESS[1] + "\\\"]\"")
3028 + HelpExampleCli("listunspent", "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'")
3029 + HelpExampleRpc("listunspent", "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")
3030 },
3031 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3032{
3033 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
3034 if (!pwallet) return NullUniValue;
3035
3036 int nMinDepth = 1;
3037 if (!request.params[0].isNull()) {
3038 RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
3039 nMinDepth = request.params[0].get_int();
3040 }
3041
3042 int nMaxDepth = 9999999;
3043 if (!request.params[1].isNull()) {
3044 RPCTypeCheckArgument(request.params[1], UniValue::VNUM);
3045 nMaxDepth = request.params[1].get_int();
3046 }
3047
3048 std::set<CTxDestination> destinations;
3049 if (!request.params[2].isNull()) {
3050 RPCTypeCheckArgument(request.params[2], UniValue::VARR);
3051 UniValue inputs = request.params[2].get_array();
3052 for (unsigned int idx = 0; idx < inputs.size(); idx++) {
3053 const UniValue& input = inputs[idx];
3055 if (!IsValidDestination(dest)) {
3056 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
3057 }
3058 if (!destinations.insert(dest).second) {
3059 throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
3060 }
3061 }
3062 }
3063
3064 bool include_unsafe = true;
3065 if (!request.params[3].isNull()) {
3066 RPCTypeCheckArgument(request.params[3], UniValue::VBOOL);
3067 include_unsafe = request.params[3].get_bool();
3068 }
3069
3070 CAmount nMinimumAmount = 0;
3071 CAmount nMaximumAmount = MAX_MONEY;
3072 CAmount nMinimumSumAmount = MAX_MONEY;
3073 uint64_t nMaximumCount = 0;
3074
3075 if (!request.params[4].isNull()) {
3076 const UniValue& options = request.params[4].get_obj();
3077
3078 RPCTypeCheckObj(options,
3079 {
3080 {"minimumAmount", UniValueType()},
3081 {"maximumAmount", UniValueType()},
3082 {"minimumSumAmount", UniValueType()},
3083 {"maximumCount", UniValueType(UniValue::VNUM)},
3084 },
3085 true, true);
3086
3087 if (options.exists("minimumAmount"))
3088 nMinimumAmount = AmountFromValue(options["minimumAmount"]);
3089
3090 if (options.exists("maximumAmount"))
3091 nMaximumAmount = AmountFromValue(options["maximumAmount"]);
3092
3093 if (options.exists("minimumSumAmount"))
3094 nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
3095
3096 if (options.exists("maximumCount"))
3097 nMaximumCount = options["maximumCount"].get_int64();
3098 }
3099
3100 // Make sure the results are valid at least up to the most recent block
3101 // the user could have gotten from another RPC command prior to now
3102 pwallet->BlockUntilSyncedToCurrentChain();
3103
3104 UniValue results(UniValue::VARR);
3105 std::vector<COutput> vecOutputs;
3106 {
3107 CCoinControl cctl;
3108 cctl.m_avoid_address_reuse = false;
3109 cctl.m_min_depth = nMinDepth;
3110 cctl.m_max_depth = nMaxDepth;
3111 cctl.m_include_unsafe_inputs = include_unsafe;
3112 LOCK(pwallet->cs_wallet);
3113 AvailableCoins(*pwallet, vecOutputs, &cctl, nMinimumAmount, nMaximumAmount, nMinimumSumAmount, nMaximumCount);
3114 }
3115
3116 LOCK(pwallet->cs_wallet);
3117
3118 const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
3119
3120 for (const COutput& out : vecOutputs) {
3121 CTxDestination address;
3122 const CScript& scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
3123 bool fValidAddress = ExtractDestination(scriptPubKey, address);
3124 bool reused = avoid_reuse && pwallet->IsSpentKey(out.tx->GetHash(), out.i);
3125
3126 if (destinations.size() && (!fValidAddress || !destinations.count(address)))
3127 continue;
3128
3129 UniValue entry(UniValue::VOBJ);
3130 entry.pushKV("txid", out.tx->GetHash().GetHex());
3131 entry.pushKV("vout", out.i);
3132
3133 if (fValidAddress) {
3134 entry.pushKV("address", EncodeDestination(address));
3135
3136 const auto* address_book_entry = pwallet->FindAddressBookEntry(address);
3137 if (address_book_entry) {
3138 entry.pushKV("label", address_book_entry->GetLabel());
3139 }
3140
3141 std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
3142 if (provider) {
3143 if (scriptPubKey.IsPayToScriptHash()) {
3144 const CScriptID& hash = CScriptID(std::get<ScriptHash>(address));
3145 CScript redeemScript;
3146 if (provider->GetCScript(hash, redeemScript)) {
3147 entry.pushKV("redeemScript", HexStr(redeemScript));
3148 // Now check if the redeemScript is actually a P2WSH script
3149 CTxDestination witness_destination;
3150 if (redeemScript.IsPayToWitnessScriptHash()) {
3151 bool extracted = ExtractDestination(redeemScript, witness_destination);
3152 CHECK_NONFATAL(extracted);
3153 // Also return the witness script
3154 const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(witness_destination);
3155 CScriptID id;
3156 CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
3157 CScript witnessScript;
3158 if (provider->GetCScript(id, witnessScript)) {
3159 entry.pushKV("witnessScript", HexStr(witnessScript));
3160 }
3161 }
3162 }
3163 } else if (scriptPubKey.IsPayToWitnessScriptHash()) {
3164 const WitnessV0ScriptHash& whash = std::get<WitnessV0ScriptHash>(address);
3165 CScriptID id;
3166 CRIPEMD160().Write(whash.begin(), whash.size()).Finalize(id.begin());
3167 CScript witnessScript;
3168 if (provider->GetCScript(id, witnessScript)) {
3169 entry.pushKV("witnessScript", HexStr(witnessScript));
3170 }
3171 }
3172 }
3173 }
3174
3175 entry.pushKV("scriptPubKey", HexStr(scriptPubKey));
3176 entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
3177 entry.pushKV("confirmations", out.nDepth);
3178 if (!out.nDepth) {
3179 size_t ancestor_count, descendant_count, ancestor_size;
3180 CAmount ancestor_fees;
3181 pwallet->chain().getTransactionAncestry(out.tx->GetHash(), ancestor_count, descendant_count, &ancestor_size, &ancestor_fees);
3182 if (ancestor_count) {
3183 entry.pushKV("ancestorcount", uint64_t(ancestor_count));
3184 entry.pushKV("ancestorsize", uint64_t(ancestor_size));
3185 entry.pushKV("ancestorfees", uint64_t(ancestor_fees));
3186 }
3187 }
3188 entry.pushKV("spendable", out.fSpendable);
3189 entry.pushKV("solvable", out.fSolvable);
3190 if (out.fSolvable) {
3191 std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
3192 if (provider) {
3193 auto descriptor = InferDescriptor(scriptPubKey, *provider);
3194 entry.pushKV("desc", descriptor->ToString());
3195 }
3196 }
3197 if (avoid_reuse) entry.pushKV("reused", reused);
3198 entry.pushKV("safe", out.fSafe);
3199 results.push_back(entry);
3200 }
3201
3202 return results;
3203},
3204 };
3205}
3206
3207// Only includes key documentation where the key is snake_case in all RPC methods. MixedCase keys can be added later.
3208static std::vector<RPCArg> FundTxDoc()
3209{
3210 return {
3211 {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
3212 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
3213 " \"" + FeeModes("\"\n\"") + "\""},
3214 {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125 replaceable.\n"
3215 "Allows this transaction to be replaced by a transaction with higher fees"},
3216 {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
3217 "Used for fee estimation during coin selection.",
3218 {
3219 {"pubkeys", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Public keys involved in this transaction.",
3220 {
3221 {"pubkey", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A public key"},
3222 }},
3223 {"scripts", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Scripts involved in this transaction.",
3224 {
3225 {"script", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "A script"},
3226 }},
3227 {"descriptors", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Descriptors that provide solving data for this transaction.",
3228 {
3229 {"descriptor", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "A descriptor"},
3230 }},
3231 }},
3232 };
3233}
3234
3235void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out, int& change_position, const UniValue& options, CCoinControl& coinControl, bool override_min_fee)
3236{
3237 // Make sure the results are valid at least up to the most recent block
3238 // the user could have gotten from another RPC command prior to now
3239 wallet.BlockUntilSyncedToCurrentChain();
3240
3241 change_position = -1;
3242 bool lockUnspents = false;
3243 UniValue subtractFeeFromOutputs;
3244 std::set<int> setSubtractFeeFromOutputs;
3245
3246 if (!options.isNull()) {
3247 if (options.type() == UniValue::VBOOL) {
3248 // backward compatibility bool only fallback
3249 coinControl.fAllowWatchOnly = options.get_bool();
3250 }
3251 else {
3253 RPCTypeCheckObj(options,
3254 {
3255 {"add_inputs", UniValueType(UniValue::VBOOL)},
3256 {"include_unsafe", UniValueType(UniValue::VBOOL)},
3257 {"add_to_wallet", UniValueType(UniValue::VBOOL)},
3258 {"changeAddress", UniValueType(UniValue::VSTR)},
3259 {"change_address", UniValueType(UniValue::VSTR)},
3260 {"changePosition", UniValueType(UniValue::VNUM)},
3261 {"change_position", UniValueType(UniValue::VNUM)},
3262 {"change_type", UniValueType(UniValue::VSTR)},
3263 {"includeWatching", UniValueType(UniValue::VBOOL)},
3264 {"include_watching", UniValueType(UniValue::VBOOL)},
3265 {"inputs", UniValueType(UniValue::VARR)},
3266 {"lockUnspents", UniValueType(UniValue::VBOOL)},
3267 {"lock_unspents", UniValueType(UniValue::VBOOL)},
3268 {"locktime", UniValueType(UniValue::VNUM)},
3269 {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
3270 {"feeRate", UniValueType()}, // will be checked by AmountFromValue() below
3271 {"psbt", UniValueType(UniValue::VBOOL)},
3272 {"solving_data", UniValueType(UniValue::VOBJ)},
3273 {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
3274 {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
3275 {"replaceable", UniValueType(UniValue::VBOOL)},
3276 {"conf_target", UniValueType(UniValue::VNUM)},
3277 {"estimate_mode", UniValueType(UniValue::VSTR)},
3278 },
3279 true, true);
3280
3281 if (options.exists("add_inputs") ) {
3282 coinControl.m_add_inputs = options["add_inputs"].get_bool();
3283 }
3284
3285 if (options.exists("changeAddress") || options.exists("change_address")) {
3286 const std::string change_address_str = (options.exists("change_address") ? options["change_address"] : options["changeAddress"]).get_str();
3287 CTxDestination dest = DecodeDestination(change_address_str);
3288
3289 if (!IsValidDestination(dest)) {
3290 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
3291 }
3292
3293 coinControl.destChange = dest;
3294 }
3295
3296 if (options.exists("changePosition") || options.exists("change_position")) {
3297 change_position = (options.exists("change_position") ? options["change_position"] : options["changePosition"]).get_int();
3298 }
3299
3300 if (options.exists("change_type")) {
3301 if (options.exists("changeAddress") || options.exists("change_address")) {
3302 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both change address and address type options");
3303 }
3304 if (std::optional<OutputType> parsed = ParseOutputType(options["change_type"].get_str())) {
3305 coinControl.m_change_type.emplace(parsed.value());
3306 } else {
3307 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Unknown change type '%s'", options["change_type"].get_str()));
3308 }
3309 }
3310
3311 const UniValue include_watching_option = options.exists("include_watching") ? options["include_watching"] : options["includeWatching"];
3312 coinControl.fAllowWatchOnly = ParseIncludeWatchonly(include_watching_option, wallet);
3313
3314 if (options.exists("lockUnspents") || options.exists("lock_unspents")) {
3315 lockUnspents = (options.exists("lock_unspents") ? options["lock_unspents"] : options["lockUnspents"]).get_bool();
3316 }
3317
3318 if (options.exists("include_unsafe")) {
3319 coinControl.m_include_unsafe_inputs = options["include_unsafe"].get_bool();
3320 }
3321
3322 if (options.exists("feeRate")) {
3323 if (options.exists("fee_rate")) {
3324 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both fee_rate (" + CURRENCY_ATOM + "/vB) and feeRate (" + CURRENCY_UNIT + "/kvB)");
3325 }
3326 if (options.exists("conf_target")) {
3327 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and feeRate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
3328 }
3329 if (options.exists("estimate_mode")) {
3330 throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
3331 }
3332 coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
3333 coinControl.fOverrideFeeRate = true;
3334 }
3335
3336 if (options.exists("subtractFeeFromOutputs") || options.exists("subtract_fee_from_outputs") )
3337 subtractFeeFromOutputs = (options.exists("subtract_fee_from_outputs") ? options["subtract_fee_from_outputs"] : options["subtractFeeFromOutputs"]).get_array();
3338
3339 if (options.exists("replaceable")) {
3340 coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
3341 }
3342 SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);
3343 }
3344 } else {
3345 // if options is null and not a bool
3347 }
3348
3349 if (options.exists("solving_data")) {
3350 const UniValue solving_data = options["solving_data"].get_obj();
3351 if (solving_data.exists("pubkeys")) {
3352 for (const UniValue& pk_univ : solving_data["pubkeys"].get_array().getValues()) {
3353 const std::string& pk_str = pk_univ.get_str();
3354 if (!IsHex(pk_str)) {
3355 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", pk_str));
3356 }
3357 const std::vector<unsigned char> data(ParseHex(pk_str));
3358 const CPubKey pubkey(data.begin(), data.end());
3359 if (!pubkey.IsFullyValid()) {
3360 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not a valid public key", pk_str));
3361 }
3362 coinControl.m_external_provider.pubkeys.emplace(pubkey.GetID(), pubkey);
3363 // Add witness script for pubkeys
3364 const CScript wit_script = GetScriptForDestination(WitnessV0KeyHash(pubkey));
3365 coinControl.m_external_provider.scripts.emplace(CScriptID(wit_script), wit_script);
3366 }
3367 }
3368
3369 if (solving_data.exists("scripts")) {
3370 for (const UniValue& script_univ : solving_data["scripts"].get_array().getValues()) {
3371 const std::string& script_str = script_univ.get_str();
3372 if (!IsHex(script_str)) {
3373 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("'%s' is not hex", script_str));
3374 }
3375 std::vector<unsigned char> script_data(ParseHex(script_str));
3376 const CScript script(script_data.begin(), script_data.end());
3377 coinControl.m_external_provider.scripts.emplace(CScriptID(script), script);
3378 }
3379 }
3380
3381 if (solving_data.exists("descriptors")) {
3382 for (const UniValue& desc_univ : solving_data["descriptors"].get_array().getValues()) {
3383 const std::string& desc_str = desc_univ.get_str();
3384 FlatSigningProvider desc_out;
3385 std::string error;
3386 std::vector<CScript> scripts_temp;
3387 std::unique_ptr<Descriptor> desc = Parse(desc_str, desc_out, error, true);
3388 if (!desc) {
3389 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Unable to parse descriptor '%s': %s", desc_str, error));
3390 }
3391 desc->Expand(0, desc_out, scripts_temp, desc_out);
3392 coinControl.m_external_provider = Merge(coinControl.m_external_provider, desc_out);
3393 }
3394 }
3395 }
3396
3397 if (tx.vout.size() == 0)
3398 throw JSONRPCError(RPC_INVALID_PARAMETER, "TX must have at least one output");
3399
3400 if (change_position != -1 && (change_position < 0 || (unsigned int)change_position > tx.vout.size()))
3401 throw JSONRPCError(RPC_INVALID_PARAMETER, "changePosition out of bounds");
3402
3403 for (unsigned int idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
3404 int pos = subtractFeeFromOutputs[idx].get_int();
3405 if (setSubtractFeeFromOutputs.count(pos))
3406 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, duplicated position: %d", pos));
3407 if (pos < 0)
3408 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, negative position: %d", pos));
3409 if (pos >= int(tx.vout.size()))
3410 throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid parameter, position too large: %d", pos));
3411 setSubtractFeeFromOutputs.insert(pos);
3412 }
3413
3414 // Fetch specified UTXOs from the UTXO set to get the scriptPubKeys and values of the outputs being selected
3415 // and to match with the given solving_data. Only used for non-wallet outputs.
3416 std::map<COutPoint, Coin> coins;
3417 for (const CTxIn& txin : tx.vin) {
3418 coins[txin.prevout]; // Create empty map entry keyed by prevout.
3419 }
3420 wallet.chain().findCoins(coins);
3421 for (const auto& coin : coins) {
3422 if (!coin.second.out.IsNull()) {
3423 coinControl.SelectExternal(coin.first, coin.second.out);
3424 }
3425 }
3426
3428
3429 if (!FundTransaction(wallet, tx, fee_out, change_position, error, lockUnspents, setSubtractFeeFromOutputs, coinControl)) {
3430 throw JSONRPCError(RPC_WALLET_ERROR, error.original);
3431 }
3432}
3433
3435{
3436 return RPCHelpMan{"fundrawtransaction",
3437 "\nIf the transaction has no inputs, they will be automatically selected to meet its out value.\n"
3438 "It will add at most one change output to the outputs.\n"
3439 "No existing outputs will be modified unless \"subtractFeeFromOutputs\" is specified.\n"
3440 "Note that inputs which were signed may need to be resigned after completion since in/outputs have been added.\n"
3441 "The inputs added will not be signed, use signrawtransactionwithkey\n"
3442 "or signrawtransactionwithwallet for that.\n"
3443 "All existing inputs must either have their previous output transaction be in the wallet\n"
3444 "or be in the UTXO set. Solving data must be provided for non-wallet inputs.\n"
3445 "Note that all inputs selected must be of standard form and P2SH scripts must be\n"
3446 "in the wallet using importaddress or addmultisigaddress (to calculate fees).\n"
3447 "You can see whether this is the case by checking the \"solvable\" field in the listunspent output.\n"
3448 "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently supported for watch-only\n",
3449 {
3450 {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
3451 {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "for backward compatibility: passing in a true instead of an object will result in {\"includeWatching\":true}",
3452 Cat<std::vector<RPCArg>>(
3453 {
3454 {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{true}, "For a transaction with existing inputs, automatically include more if they are not enough."},
3455 {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
3456 "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
3457 "If that happens, you will need to fund the transaction with different inputs and republish it."},
3458 {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
3459 {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
3460 {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
3461 {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
3462 "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
3463 "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
3464 {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
3465 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
3466 {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
3467 {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The integers.\n"
3468 "The fee will be equally deducted from the amount of each specified output.\n"
3469 "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
3470 "If no outputs are specified here, the sender pays the fee.",
3471 {
3472 {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
3473 },
3474 },
3475 },
3476 FundTxDoc()),
3477 "options"},
3478 {"iswitness", RPCArg::Type::BOOL, RPCArg::DefaultHint{"depends on heuristic tests"}, "Whether the transaction hex is a serialized witness transaction.\n"
3479 "If iswitness is not present, heuristic tests will be used in decoding.\n"
3480 "If true, only witness deserialization will be tried.\n"
3481 "If false, only non-witness deserialization will be tried.\n"
3482 "This boolean should reflect whether the transaction has inputs\n"
3483 "(e.g. fully valid, or on-chain transactions), if known by the caller."
3484 },
3485 },
3486 RPCResult{
3487 RPCResult::Type::OBJ, "", "",
3488 {
3489 {RPCResult::Type::STR_HEX, "hex", "The resulting raw transaction (hex-encoded string)"},
3490 {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
3491 {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
3492 }
3493 },
3495 "\nCreate a transaction with no inputs\n"
3496 + HelpExampleCli("createrawtransaction", "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
3497 "\nAdd sufficient unsigned inputs to meet the output value\n"
3498 + HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
3499 "\nSign the transaction\n"
3500 + HelpExampleCli("signrawtransactionwithwallet", "\"fundedtransactionhex\"") +
3501 "\nSend the transaction\n"
3502 + HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")
3503 },
3504 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3505{
3506 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
3507 if (!pwallet) return NullUniValue;
3508
3509 RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType(), UniValue::VBOOL});
3510
3511 // parse hex string from parameter
3513 bool try_witness = request.params[2].isNull() ? true : request.params[2].get_bool();
3514 bool try_no_witness = request.params[2].isNull() ? true : !request.params[2].get_bool();
3515 if (!DecodeHexTx(tx, request.params[0].get_str(), try_no_witness, try_witness)) {
3516 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3517 }
3518
3519 CAmount fee;
3520 int change_position;
3521 CCoinControl coin_control;
3522 // Automatically select (additional) coins. Can be overridden by options.add_inputs.
3523 coin_control.m_add_inputs = true;
3524 FundTransaction(*pwallet, tx, fee, change_position, request.params[1], coin_control, /* override_min_fee */ true);
3525
3526 UniValue result(UniValue::VOBJ);
3527 result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
3528 result.pushKV("fee", ValueFromAmount(fee));
3529 result.pushKV("changepos", change_position);
3530
3531 return result;
3532},
3533 };
3534}
3535
3537{
3538 return RPCHelpMan{"signrawtransactionwithwallet",
3539 "\nSign inputs for raw transaction (serialized, hex-encoded).\n"
3540 "The second optional argument (may be null) is an array of previous transaction outputs that\n"
3541 "this transaction depends on but may not yet be in the block chain." +
3543 {
3544 {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction hex string"},
3545 {"prevtxs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The previous dependent transaction outputs",
3546 {
3548 {
3549 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
3550 {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
3551 {"scriptPubKey", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "script key"},
3552 {"redeemScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2SH) redeem script"},
3553 {"witnessScript", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, "(required for P2WSH or P2SH-P2WSH) witness script"},
3554 {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::OMITTED, "(required for Segwit inputs) the amount spent"},
3555 },
3556 },
3557 },
3558 },
3559 {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT"}, "The signature hash type. Must be one of\n"
3560 " \"DEFAULT\"\n"
3561 " \"ALL\"\n"
3562 " \"NONE\"\n"
3563 " \"SINGLE\"\n"
3564 " \"ALL|ANYONECANPAY\"\n"
3565 " \"NONE|ANYONECANPAY\"\n"
3566 " \"SINGLE|ANYONECANPAY\""},
3567 },
3568 RPCResult{
3569 RPCResult::Type::OBJ, "", "",
3570 {
3571 {RPCResult::Type::STR_HEX, "hex", "The hex-encoded raw transaction with signature(s)"},
3572 {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
3573 {RPCResult::Type::ARR, "errors", /* optional */ true, "Script verification errors (if there are any)",
3574 {
3575 {RPCResult::Type::OBJ, "", "",
3576 {
3577 {RPCResult::Type::STR_HEX, "txid", "The hash of the referenced, previous transaction"},
3578 {RPCResult::Type::NUM, "vout", "The index of the output to spent and used as input"},
3579 {RPCResult::Type::ARR, "witness", "",
3580 {
3581 {RPCResult::Type::STR_HEX, "witness", ""},
3582 }},
3583 {RPCResult::Type::STR_HEX, "scriptSig", "The hex-encoded signature script"},
3584 {RPCResult::Type::NUM, "sequence", "Script sequence number"},
3585 {RPCResult::Type::STR, "error", "Verification or signing error related to the input"},
3586 }},
3587 }},
3588 }
3589 },
3591 HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"")
3592 + HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")
3593 },
3594 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3595{
3596 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
3597 if (!pwallet) return NullUniValue;
3598
3599 RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
3600
3602 if (!DecodeHexTx(mtx, request.params[0].get_str())) {
3603 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
3604 }
3605
3606 // Sign the transaction
3607 LOCK(pwallet->cs_wallet);
3608 EnsureWalletIsUnlocked(*pwallet);
3609
3610 // Fetch previous transactions (inputs):
3611 std::map<COutPoint, Coin> coins;
3612 for (const CTxIn& txin : mtx.vin) {
3613 coins[txin.prevout]; // Create empty map entry keyed by prevout.
3614 }
3615 pwallet->chain().findCoins(coins);
3616
3617 // Parse the prevtxs array
3618 ParsePrevouts(request.params[1], nullptr, coins);
3619
3620 int nHashType = ParseSighashString(request.params[2]);
3621
3622 // Script verification errors
3623 std::map<int, bilingual_str> input_errors;
3624
3625 bool complete = pwallet->SignTransaction(mtx, coins, nHashType, input_errors);
3626 UniValue result(UniValue::VOBJ);
3627 SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
3628 return result;
3629},
3630 };
3631}
3632
3633static RPCHelpMan bumpfee_helper(std::string method_name)
3634{
3635 const bool want_psbt = method_name == "psbtbumpfee";
3636 const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)};
3637
3638 return RPCHelpMan{method_name,
3639 "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
3640 + std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
3641 "An opt-in RBF transaction with the given txid must be in the wallet.\n"
3642 "The command will pay the additional fee by reducing change outputs or adding inputs when necessary.\n"
3643 "It may add a new change output if one does not already exist.\n"
3644 "All inputs in the original transaction will be included in the replacement transaction.\n"
3645 "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
3646 "By default, the new fee will be calculated automatically using the estimatesmartfee RPC.\n"
3647 "The user can specify a confirmation target for estimatesmartfee.\n"
3648 "Alternatively, the user can specify a fee rate in " + CURRENCY_ATOM + "/vB for the new transaction.\n"
3649 "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
3650 "returned by getnetworkinfo) to enter the node's mempool.\n"
3651 "* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n",
3652 {
3653 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
3655 {
3656 {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
3657 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
3658 "\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n"
3659 "Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n"
3660 "WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"},
3661 {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n"
3662 "marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
3663 "be left unchanged from the original. If false, any input sequence numbers in the\n"
3664 "original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
3665 "so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
3666 "still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
3667 "are replaceable).\n"},
3668 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
3669 "\"" + FeeModes("\"\n\"") + "\""},
3670 },
3671 "options"},
3672 },
3673 RPCResult{
3674 RPCResult::Type::OBJ, "", "", Cat(
3675 want_psbt ?
3676 std::vector<RPCResult>{{RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction."}} :
3677 std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction."}},
3678 {
3679 {RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
3680 {RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
3681 {RPCResult::Type::ARR, "errors", "Errors encountered during processing (may be empty).",
3682 {
3683 {RPCResult::Type::STR, "", ""},
3684 }},
3685 })
3686 },
3688 "\nBump the fee, get the new transaction\'s " + std::string(want_psbt ? "psbt" : "txid") + "\n" +
3689 HelpExampleCli(method_name, "<txid>")
3690 },
3691 [want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3692{
3693 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
3694 if (!pwallet) return NullUniValue;
3695
3696 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
3697 throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
3698 }
3699
3700 RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
3701 uint256 hash(ParseHashV(request.params[0], "txid"));
3702
3703 CCoinControl coin_control;
3704 coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
3705 // optional parameters
3706 coin_control.m_signal_bip125_rbf = true;
3707
3708 if (!request.params[1].isNull()) {
3709 UniValue options = request.params[1];
3710 RPCTypeCheckObj(options,
3711 {
3712 {"confTarget", UniValueType(UniValue::VNUM)},
3713 {"conf_target", UniValueType(UniValue::VNUM)},
3714 {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
3715 {"replaceable", UniValueType(UniValue::VBOOL)},
3716 {"estimate_mode", UniValueType(UniValue::VSTR)},
3717 },
3718 true, true);
3719
3720 if (options.exists("confTarget") && options.exists("conf_target")) {
3721 throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and conf_target options should not both be set. Use conf_target (confTarget is deprecated).");
3722 }
3723
3724 auto conf_target = options.exists("confTarget") ? options["confTarget"] : options["conf_target"];
3725
3726 if (options.exists("replaceable")) {
3727 coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
3728 }
3729 SetFeeEstimateMode(*pwallet, coin_control, conf_target, options["estimate_mode"], options["fee_rate"], /* override_min_fee */ false);
3730 }
3731
3732 // Make sure the results are valid at least up to the most recent block
3733 // the user could have gotten from another RPC command prior to now
3734 pwallet->BlockUntilSyncedToCurrentChain();
3735
3736 LOCK(pwallet->cs_wallet);
3737
3738 EnsureWalletIsUnlocked(*pwallet);
3739
3740
3741 std::vector<bilingual_str> errors;
3742 CAmount old_fee;
3743 CAmount new_fee;
3746 // Targeting feerate bump.
3747 res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
3748 if (res != feebumper::Result::OK) {
3749 switch(res) {
3751 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0].original);
3752 break;
3754 throw JSONRPCError(RPC_INVALID_REQUEST, errors[0].original);
3755 break;
3757 throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0].original);
3758 break;
3760 throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
3761 break;
3762 default:
3763 throw JSONRPCError(RPC_MISC_ERROR, errors[0].original);
3764 break;
3765 }
3766 }
3767
3768 UniValue result(UniValue::VOBJ);
3769
3770 // For bumpfee, return the new transaction id.
3771 // For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
3772 if (!want_psbt) {
3773 if (!feebumper::SignTransaction(*pwallet, mtx)) {
3774 throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
3775 }
3776
3777 uint256 txid;
3778 if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
3779 throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
3780 }
3781
3782 result.pushKV("txid", txid.GetHex());
3783 } else {
3784 PartiallySignedTransaction psbtx(mtx);
3785 bool complete = false;
3786 const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false /* sign */, true /* bip32derivs */);
3788 CHECK_NONFATAL(!complete);
3790 ssTx << psbtx;
3791 result.pushKV("psbt", EncodeBase64(ssTx.str()));
3792 }
3793
3794 result.pushKV("origfee", ValueFromAmount(old_fee));
3795 result.pushKV("fee", ValueFromAmount(new_fee));
3796 UniValue result_errors(UniValue::VARR);
3797 for (const bilingual_str& error : errors) {
3798 result_errors.push_back(error.original);
3799 }
3800 result.pushKV("errors", result_errors);
3801
3802 return result;
3803},
3804 };
3805}
3806
3807static RPCHelpMan bumpfee() { return bumpfee_helper("bumpfee"); }
3808static RPCHelpMan psbtbumpfee() { return bumpfee_helper("psbtbumpfee"); }
3809
3811{
3812 return RPCHelpMan{"rescanblockchain",
3813 "\nRescan the local blockchain for wallet related transactions.\n"
3814 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
3815 {
3816 {"start_height", RPCArg::Type::NUM, RPCArg::Default{0}, "block height where the rescan should start"},
3817 {"stop_height", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "the last block height that should be scanned. If none is provided it will rescan up to the tip at return time of this call."},
3818 },
3819 RPCResult{
3820 RPCResult::Type::OBJ, "", "",
3821 {
3822 {RPCResult::Type::NUM, "start_height", "The block height where the rescan started (the requested height or 0)"},
3823 {RPCResult::Type::NUM, "stop_height", "The height of the last rescanned block. May be null in rare cases if there was a reorg and the call didn't scan any blocks because they were already scanned in the background."},
3824 }
3825 },
3827 HelpExampleCli("rescanblockchain", "100000 120000")
3828 + HelpExampleRpc("rescanblockchain", "100000, 120000")
3829 },
3830 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
3831{
3832 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
3833 if (!pwallet) return NullUniValue;
3834
3835 WalletRescanReserver reserver(*pwallet);
3836 if (!reserver.reserve()) {
3837 throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
3838 }
3839
3840 int start_height = 0;
3841 std::optional<int> stop_height;
3842 uint256 start_block;
3843 {
3844 LOCK(pwallet->cs_wallet);
3845 int tip_height = pwallet->GetLastBlockHeight();
3846
3847 if (!request.params[0].isNull()) {
3848 start_height = request.params[0].get_int();
3849 if (start_height < 0 || start_height > tip_height) {
3850 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid start_height");
3851 }
3852 }
3853
3854 if (!request.params[1].isNull()) {
3855 stop_height = request.params[1].get_int();
3856 if (*stop_height < 0 || *stop_height > tip_height) {
3857 throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid stop_height");
3858 } else if (*stop_height < start_height) {
3859 throw JSONRPCError(RPC_INVALID_PARAMETER, "stop_height must be greater than start_height");
3860 }
3861 }
3862
3863 // We can't rescan beyond non-pruned blocks, stop and throw an error
3864 if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {
3865 throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
3866 }
3867
3868 CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height, FoundBlock().hash(start_block)));
3869 }
3870
3871 CWallet::ScanResult result =
3872 pwallet->ScanForWalletTransactions(start_block, start_height, stop_height, reserver, true /* fUpdate */);
3873 switch (result.status) {
3875 break;
3877 throw JSONRPCError(RPC_MISC_ERROR, "Rescan failed. Potentially corrupted data files.");
3879 throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
3880 // no default case, so the compiler can warn about missing cases
3881 }
3882 UniValue response(UniValue::VOBJ);
3883 response.pushKV("start_height", start_height);
3884 response.pushKV("stop_height", result.last_scanned_height ? *result.last_scanned_height : UniValue());
3885 return response;
3886},
3887 };
3888}
3889
3891{
3892public:
3894
3895 void ProcessSubScript(const CScript& subscript, UniValue& obj) const
3896 {
3897 // Always present: script type and redeemscript
3898 std::vector<std::vector<unsigned char>> solutions_data;
3899 TxoutType which_type = Solver(subscript, solutions_data);
3900 obj.pushKV("script", GetTxnOutputType(which_type));
3901 obj.pushKV("hex", HexStr(subscript));
3902
3903 CTxDestination embedded;
3904 if (ExtractDestination(subscript, embedded)) {
3905 // Only when the script corresponds to an address.
3906 UniValue subobj(UniValue::VOBJ);
3907 UniValue detail = DescribeAddress(embedded);
3908 subobj.pushKVs(detail);
3909 UniValue wallet_detail = std::visit(*this, embedded);
3910 subobj.pushKVs(wallet_detail);
3911 subobj.pushKV("address", EncodeDestination(embedded));
3912 subobj.pushKV("scriptPubKey", HexStr(subscript));
3913 // Always report the pubkey at the top level, so that `getnewaddress()['pubkey']` always works.
3914 if (subobj.exists("pubkey")) obj.pushKV("pubkey", subobj["pubkey"]);
3915 obj.pushKV("embedded", std::move(subobj));
3916 } else if (which_type == TxoutType::MULTISIG) {
3917 // Also report some information on multisig scripts (which do not have a corresponding address).
3918 obj.pushKV("sigsrequired", solutions_data[0][0]);
3919 UniValue pubkeys(UniValue::VARR);
3920 for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
3921 CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
3922 pubkeys.push_back(HexStr(key));
3923 }
3924 obj.pushKV("pubkeys", std::move(pubkeys));
3925 }
3926 }
3927
3928 explicit DescribeWalletAddressVisitor(const SigningProvider* _provider) : provider(_provider) {}
3929
3931
3932 UniValue operator()(const PKHash& pkhash) const
3933 {
3934 CKeyID keyID{ToKeyID(pkhash)};
3936 CPubKey vchPubKey;
3937 if (provider && provider->GetPubKey(keyID, vchPubKey)) {
3938 obj.pushKV("pubkey", HexStr(vchPubKey));
3939 obj.pushKV("iscompressed", vchPubKey.IsCompressed());
3940 }
3941 return obj;
3942 }
3943
3944 UniValue operator()(const ScriptHash& scripthash) const
3945 {
3946 CScriptID scriptID(scripthash);
3948 CScript subscript;
3949 if (provider && provider->GetCScript(scriptID, subscript)) {
3950 ProcessSubScript(subscript, obj);
3951 }
3952 return obj;
3953 }
3954
3956 {
3958 CPubKey pubkey;
3959 if (provider && provider->GetPubKey(ToKeyID(id), pubkey)) {
3960 obj.pushKV("pubkey", HexStr(pubkey));
3961 }
3962 return obj;
3963 }
3964
3966 {
3968 CScript subscript;
3969 CRIPEMD160 hasher;
3970 uint160 hash;
3971 hasher.Write(id.begin(), 32).Finalize(hash.begin());
3972 if (provider && provider->GetCScript(CScriptID(hash), subscript)) {
3973 ProcessSubScript(subscript, obj);
3974 }
3975 return obj;
3976 }
3977
3980};
3981
3983{
3985 UniValue detail = DescribeAddress(dest);
3986 CScript script = GetScriptForDestination(dest);
3987 std::unique_ptr<SigningProvider> provider = nullptr;
3988 provider = wallet.GetSolvingProvider(script);
3989 ret.pushKVs(detail);
3990 ret.pushKVs(std::visit(DescribeWalletAddressVisitor(provider.get()), dest));
3991 return ret;
3992}
3993
3995static UniValue AddressBookDataToJSON(const CAddressBookData& data, const bool verbose)
3996{
3998 if (verbose) {
3999 ret.pushKV("name", data.GetLabel());
4000 }
4001 ret.pushKV("purpose", data.purpose);
4002 return ret;
4003}
4004
4006{
4007 return RPCHelpMan{"getaddressinfo",
4008 "\nReturn information about the given bitcoin address.\n"
4009 "Some of the information will only be present if the address is in the active wallet.\n",
4010 {
4011 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for which to get information."},
4012 },
4013 RPCResult{
4014 RPCResult::Type::OBJ, "", "",
4015 {
4016 {RPCResult::Type::STR, "address", "The bitcoin address validated."},
4017 {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address."},
4018 {RPCResult::Type::BOOL, "ismine", "If the address is yours."},
4019 {RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
4020 {RPCResult::Type::BOOL, "solvable", "If we know how to spend coins sent to this address, ignoring the possible lack of private keys."},
4021 {RPCResult::Type::STR, "desc", /* optional */ true, "A descriptor for spending coins sent to this address (only when solvable)."},
4022 {RPCResult::Type::STR, "parent_desc", /* optional */ true, "The descriptor used to derive this address if this is a descriptor wallet"},
4023 {RPCResult::Type::BOOL, "isscript", "If the key is a script."},
4024 {RPCResult::Type::BOOL, "ischange", "If the address was used for change output."},
4025 {RPCResult::Type::BOOL, "iswitness", "If the address is a witness address."},
4026 {RPCResult::Type::NUM, "witness_version", /* optional */ true, "The version number of the witness program."},
4027 {RPCResult::Type::STR_HEX, "witness_program", /* optional */ true, "The hex value of the witness program."},
4028 {RPCResult::Type::STR, "script", /* optional */ true, "The output script type. Only if isscript is true and the redeemscript is known. Possible\n"
4029 "types: nonstandard, pubkey, pubkeyhash, scripthash, multisig, nulldata, witness_v0_keyhash,\n"
4030 "witness_v0_scripthash, witness_unknown."},
4031 {RPCResult::Type::STR_HEX, "hex", /* optional */ true, "The redeemscript for the p2sh address."},
4032 {RPCResult::Type::ARR, "pubkeys", /* optional */ true, "Array of pubkeys associated with the known redeemscript (only if script is multisig).",
4033 {
4034 {RPCResult::Type::STR, "pubkey", ""},
4035 }},
4036 {RPCResult::Type::NUM, "sigsrequired", /* optional */ true, "The number of signatures required to spend multisig output (only if script is multisig)."},
4037 {RPCResult::Type::STR_HEX, "pubkey", /* optional */ true, "The hex value of the raw public key for single-key addresses (possibly embedded in P2SH or P2WSH)."},
4038 {RPCResult::Type::OBJ, "embedded", /* optional */ true, "Information about the address embedded in P2SH or P2WSH, if relevant and known.",
4039 {
4040 {RPCResult::Type::ELISION, "", "Includes all getaddressinfo output fields for the embedded address, excluding metadata (timestamp, hdkeypath, hdseedid)\n"
4041 "and relation to the wallet (ismine, iswatchonly)."},
4042 }},
4043 {RPCResult::Type::BOOL, "iscompressed", /* optional */ true, "If the pubkey is compressed."},
4044 {RPCResult::Type::NUM_TIME, "timestamp", /* optional */ true, "The creation time of the key, if available, expressed in " + UNIX_EPOCH_TIME + "."},
4045 {RPCResult::Type::STR, "hdkeypath", /* optional */ true, "The HD keypath, if the key is HD and available."},
4046 {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true, "The Hash160 of the HD seed."},
4047 {RPCResult::Type::STR_HEX, "hdmasterfingerprint", /* optional */ true, "The fingerprint of the master key."},
4048 {RPCResult::Type::ARR, "labels", "Array of labels associated with the address. Currently limited to one label but returned\n"
4049 "as an array to keep the API stable if multiple labels are enabled in the future.",
4050 {
4051 {RPCResult::Type::STR, "label name", "Label name (defaults to \"\")."},
4052 }},
4053 }
4054 },
4056 HelpExampleCli("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"") +
4057 HelpExampleRpc("getaddressinfo", "\"" + EXAMPLE_ADDRESS[0] + "\"")
4058 },
4059 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4060{
4061 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
4062 if (!pwallet) return NullUniValue;
4063
4064 LOCK(pwallet->cs_wallet);
4065
4066 std::string error_msg;
4067 CTxDestination dest = DecodeDestination(request.params[0].get_str(), error_msg);
4068
4069 // Make sure the destination is valid
4070 if (!IsValidDestination(dest)) {
4071 // Set generic error message in case 'DecodeDestination' didn't set it
4072 if (error_msg.empty()) error_msg = "Invalid address";
4073
4074 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, error_msg);
4075 }
4076
4078
4079 std::string currentAddress = EncodeDestination(dest);
4080 ret.pushKV("address", currentAddress);
4081
4082 CScript scriptPubKey = GetScriptForDestination(dest);
4083 ret.pushKV("scriptPubKey", HexStr(scriptPubKey));
4084
4085 std::unique_ptr<SigningProvider> provider = pwallet->GetSolvingProvider(scriptPubKey);
4086
4087 isminetype mine = pwallet->IsMine(dest);
4088 ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
4089
4090 if (provider) {
4091 auto inferred = InferDescriptor(scriptPubKey, *provider);
4092 bool solvable = inferred->IsSolvable() || IsSolvable(*provider, scriptPubKey);
4093 ret.pushKV("solvable", solvable);
4094 if (solvable) {
4095 ret.pushKV("desc", inferred->ToString());
4096 }
4097 } else {
4098 ret.pushKV("solvable", false);
4099 }
4100
4101
4102 DescriptorScriptPubKeyMan* desc_spk_man = dynamic_cast<DescriptorScriptPubKeyMan*>(pwallet->GetScriptPubKeyMan(scriptPubKey));
4103 if (desc_spk_man) {
4104 std::string desc_str;
4105 if (desc_spk_man->GetDescriptorString(desc_str, /* priv */ false)) {
4106 ret.pushKV("parent_desc", desc_str);
4107 }
4108 }
4109
4110 ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
4111
4112 UniValue detail = DescribeWalletAddress(*pwallet, dest);
4113 ret.pushKVs(detail);
4114
4115 ret.pushKV("ischange", ScriptIsChange(*pwallet, scriptPubKey));
4116
4117 ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
4118 if (spk_man) {
4119 if (const std::unique_ptr<CKeyMetadata> meta = spk_man->GetMetadata(dest)) {
4120 ret.pushKV("timestamp", meta->nCreateTime);
4121 if (meta->has_key_origin) {
4122 ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
4123 ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
4124 ret.pushKV("hdmasterfingerprint", HexStr(meta->key_origin.fingerprint));
4125 }
4126 }
4127 }
4128
4129 // Return a `labels` array containing the label associated with the address,
4130 // equivalent to the `label` field above. Currently only one label can be
4131 // associated with an address, but we return an array so the API remains
4132 // stable if we allow multiple labels to be associated with an address in
4133 // the future.
4134 UniValue labels(UniValue::VARR);
4135 const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
4136 if (address_book_entry) {
4137 labels.push_back(address_book_entry->GetLabel());
4138 }
4139 ret.pushKV("labels", std::move(labels));
4140
4141 return ret;
4142},
4143 };
4144}
4145
4147{
4148 return RPCHelpMan{"getaddressesbylabel",
4149 "\nReturns the list of addresses assigned the specified label.\n",
4150 {
4151 {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},
4152 },
4153 RPCResult{
4154 RPCResult::Type::OBJ_DYN, "", "json object with addresses as keys",
4155 {
4156 {RPCResult::Type::OBJ, "address", "json object with information about address",
4157 {
4158 {RPCResult::Type::STR, "purpose", "Purpose of address (\"send\" for sending address, \"receive\" for receiving address)"},
4159 }},
4160 }
4161 },
4163 HelpExampleCli("getaddressesbylabel", "\"tabby\"")
4164 + HelpExampleRpc("getaddressesbylabel", "\"tabby\"")
4165 },
4166 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4167{
4168 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
4169 if (!pwallet) return NullUniValue;
4170
4171 LOCK(pwallet->cs_wallet);
4172
4173 std::string label = LabelFromValue(request.params[0]);
4174
4175 // Find all addresses that have the given label
4177 std::set<std::string> addresses;
4178 for (const std::pair<const CTxDestination, CAddressBookData>& item : pwallet->m_address_book) {
4179 if (item.second.IsChange()) continue;
4180 if (item.second.GetLabel() == label) {
4181 std::string address = EncodeDestination(item.first);
4182 // CWallet::m_address_book is not expected to contain duplicate
4183 // address strings, but build a separate set as a precaution just in
4184 // case it does.
4185 bool unique = addresses.emplace(address).second;
4186 CHECK_NONFATAL(unique);
4187 // UniValue::pushKV checks if the key exists in O(N)
4188 // and since duplicate addresses are unexpected (checked with
4189 // std::set in O(log(N))), UniValue::__pushKV is used instead,
4190 // which currently is O(1).
4191 ret.__pushKV(address, AddressBookDataToJSON(item.second, false));
4192 }
4193 }
4194
4195 if (ret.empty()) {
4196 throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, std::string("No addresses with label " + label));
4197 }
4198
4199 return ret;
4200},
4201 };
4202}
4203
4205{
4206 return RPCHelpMan{"listlabels",
4207 "\nReturns the list of all labels, or labels that are assigned to addresses with a specific purpose.\n",
4208 {
4209 {"purpose", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "Address purpose to list labels for ('send','receive'). An empty string is the same as not providing this argument."},
4210 },
4211 RPCResult{
4212 RPCResult::Type::ARR, "", "",
4213 {
4214 {RPCResult::Type::STR, "label", "Label name"},
4215 }
4216 },
4218 "\nList all labels\n"
4219 + HelpExampleCli("listlabels", "") +
4220 "\nList labels that have receiving addresses\n"
4221 + HelpExampleCli("listlabels", "receive") +
4222 "\nList labels that have sending addresses\n"
4223 + HelpExampleCli("listlabels", "send") +
4224 "\nAs a JSON-RPC call\n"
4225 + HelpExampleRpc("listlabels", "receive")
4226 },
4227 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4228{
4229 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
4230 if (!pwallet) return NullUniValue;
4231
4232 LOCK(pwallet->cs_wallet);
4233
4234 std::string purpose;
4235 if (!request.params[0].isNull()) {
4236 purpose = request.params[0].get_str();
4237 }
4238
4239 // Add to a set to sort by label name, then insert into Univalue array
4240 std::set<std::string> label_set;
4241 for (const std::pair<const CTxDestination, CAddressBookData>& entry : pwallet->m_address_book) {
4242 if (entry.second.IsChange()) continue;
4243 if (purpose.empty() || entry.second.purpose == purpose) {
4244 label_set.insert(entry.second.GetLabel());
4245 }
4246 }
4247
4249 for (const std::string& name : label_set) {
4250 ret.push_back(name);
4251 }
4252
4253 return ret;
4254},
4255 };
4256}
4257
4259{
4260 return RPCHelpMan{"send",
4261 "\nEXPERIMENTAL warning: this call may be changed in future releases.\n"
4262 "\nSend a transaction.\n",
4263 {
4264 {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
4265 "That is, each address can only appear once and there can only be one 'data' object.\n"
4266 "For convenience, a dictionary, which holds the key-value pairs directly, is also accepted.",
4267 {
4269 {
4270 {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
4271 },
4272 },
4274 {
4275 {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
4276 },
4277 },
4278 },
4279 },
4280 {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
4281 {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
4282 " \"" + FeeModes("\"\n\"") + "\""},
4283 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
4285 Cat<std::vector<RPCArg>>(
4286 {
4287 {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
4288 {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
4289 "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
4290 "If that happens, you will need to fund the transaction with different inputs and republish it."},
4291 {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
4292 {"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
4293 {"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
4294 {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
4295 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
4296 {"include_watching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
4297 "Only solvable inputs can be used. Watch-only destinations are solvable if the public key and/or output script was imported,\n"
4298 "e.g. with 'importpubkey' or 'importmulti' with the 'pubkeys' or 'desc' field."},
4299 {"inputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Specify inputs instead of adding them automatically. A JSON array of JSON objects",
4300 {
4301 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
4302 {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
4303 {"sequence", RPCArg::Type::NUM, RPCArg::Optional::NO, "The sequence number"},
4304 },
4305 },
4306 {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
4307 {"lock_unspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
4308 {"psbt", RPCArg::Type::BOOL, RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."},
4309 {"subtract_fee_from_outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Outputs to subtract the fee from, specified as integer indices.\n"
4310 "The fee will be equally deducted from the amount of each specified output.\n"
4311 "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
4312 "If no outputs are specified here, the sender pays the fee.",
4313 {
4314 {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
4315 },
4316 },
4317 },
4318 FundTxDoc()),
4319 "options"},
4320 },
4321 RPCResult{
4322 RPCResult::Type::OBJ, "", "",
4323 {
4324 {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
4325 {RPCResult::Type::STR_HEX, "txid", /* optional */ true, "The transaction id for the send. Only 1 transaction is created regardless of the number of addresses."},
4326 {RPCResult::Type::STR_HEX, "hex", /* optional */ true, "If add_to_wallet is false, the hex-encoded raw transaction with signature(s)"},
4327 {RPCResult::Type::STR, "psbt", /* optional */ true, "If more signatures are needed, or if add_to_wallet is false, the base64-encoded (partially) signed transaction"}
4328 }
4329 },
4330 RPCExamples{""
4331 "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode\n"
4332 + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 6 economical\n") +
4333 "Send 0.2 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB using positional arguments\n"
4334 + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.2}' null \"unset\" 1.1\n") +
4335 "Send 0.2 BTC with a fee rate of 1 " + CURRENCY_ATOM + "/vB using the options argument\n"
4336 + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.2}' null \"unset\" null '{\"fee_rate\": 1}'\n") +
4337 "Send 0.3 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n"
4338 + HelpExampleCli("-named send", "outputs='{\"" + EXAMPLE_ADDRESS[0] + "\": 0.3}' fee_rate=25\n") +
4339 "Create a transaction that should confirm the next block, with a specific input, and return result without adding to wallet or broadcasting to the network\n"
4340 + HelpExampleCli("send", "'{\"" + EXAMPLE_ADDRESS[0] + "\": 0.1}' 1 economical '{\"add_to_wallet\": false, \"inputs\": [{\"txid\":\"a08e6907dbbd3d809776dbfc5d82e371b764ed838b5655e72f463568df1aadf0\", \"vout\":1}]}'")
4341 },
4342 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4343 {
4344 RPCTypeCheck(request.params, {
4345 UniValueType(), // outputs (ARR or OBJ, checked later)
4346 UniValue::VNUM, // conf_target
4347 UniValue::VSTR, // estimate_mode
4348 UniValueType(), // fee_rate, will be checked by AmountFromValue() in SetFeeEstimateMode()
4349 UniValue::VOBJ, // options
4350 }, true
4351 );
4352
4353 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
4354 if (!pwallet) return NullUniValue;
4355
4356 UniValue options{request.params[4].isNull() ? UniValue::VOBJ : request.params[4]};
4357 if (options.exists("conf_target") || options.exists("estimate_mode")) {
4358 if (!request.params[1].isNull() || !request.params[2].isNull()) {
4359 throw JSONRPCError(RPC_INVALID_PARAMETER, "Pass conf_target and estimate_mode either as arguments or in the options object, but not both");
4360 }
4361 } else {
4362 options.pushKV("conf_target", request.params[1]);
4363 options.pushKV("estimate_mode", request.params[2]);
4364 }
4365 if (options.exists("fee_rate")) {
4366 if (!request.params[3].isNull()) {
4367 throw JSONRPCError(RPC_INVALID_PARAMETER, "Pass the fee_rate either as an argument, or in the options object, but not both");
4368 }
4369 } else {
4370 options.pushKV("fee_rate", request.params[3]);
4371 }
4372 if (!options["conf_target"].isNull() && (options["estimate_mode"].isNull() || (options["estimate_mode"].get_str() == "unset"))) {
4373 throw JSONRPCError(RPC_INVALID_PARAMETER, "Specify estimate_mode");
4374 }
4375 if (options.exists("feeRate")) {
4376 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use fee_rate (" + CURRENCY_ATOM + "/vB) instead of feeRate");
4377 }
4378 if (options.exists("changeAddress")) {
4379 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_address");
4380 }
4381 if (options.exists("changePosition")) {
4382 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use change_position");
4383 }
4384 if (options.exists("includeWatching")) {
4385 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use include_watching");
4386 }
4387 if (options.exists("lockUnspents")) {
4388 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use lock_unspents");
4389 }
4390 if (options.exists("subtractFeeFromOutputs")) {
4391 throw JSONRPCError(RPC_INVALID_PARAMETER, "Use subtract_fee_from_outputs");
4392 }
4393
4394 const bool psbt_opt_in = options.exists("psbt") && options["psbt"].get_bool();
4395
4396 CAmount fee;
4397 int change_position;
4398 bool rbf = pwallet->m_signal_rbf;
4399 if (options.exists("replaceable")) {
4400 rbf = options["replaceable"].get_bool();
4401 }
4402 CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf);
4403 CCoinControl coin_control;
4404 // Automatically select coins, unless at least one is manually selected. Can
4405 // be overridden by options.add_inputs.
4406 coin_control.m_add_inputs = rawTx.vin.size() == 0;
4407 FundTransaction(*pwallet, rawTx, fee, change_position, options, coin_control, /* override_min_fee */ false);
4408
4409 bool add_to_wallet = true;
4410 if (options.exists("add_to_wallet")) {
4411 add_to_wallet = options["add_to_wallet"].get_bool();
4412 }
4413
4414 // Make a blank psbt
4415 PartiallySignedTransaction psbtx(rawTx);
4416
4417 // First fill transaction with our data without signing,
4418 // so external signers are not asked sign more than once.
4419 bool complete;
4420 pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false, true);
4421 const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, true, false);
4422 if (err != TransactionError::OK) {
4423 throw JSONRPCTransactionError(err);
4424 }
4425
4427 complete = FinalizeAndExtractPSBT(psbtx, mtx);
4428
4429 UniValue result(UniValue::VOBJ);
4430
4431 if (psbt_opt_in || !complete || !add_to_wallet) {
4432 // Serialize the PSBT
4434 ssTx << psbtx;
4435 result.pushKV("psbt", EncodeBase64(ssTx.str()));
4436 }
4437
4438 if (complete) {
4439 std::string err_string;
4440 std::string hex = EncodeHexTx(CTransaction(mtx));
4441 CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
4442 result.pushKV("txid", tx->GetHash().GetHex());
4443 if (add_to_wallet && !psbt_opt_in) {
4444 pwallet->CommitTransaction(tx, {}, {} /* orderForm */);
4445 } else {
4446 result.pushKV("hex", hex);
4447 }
4448 }
4449 result.pushKV("complete", complete);
4450
4451 return result;
4452 }
4453 };
4454}
4455
4457{
4458 return RPCHelpMan{"sethdseed",
4459 "\nSet or generate a new HD wallet seed. Non-HD wallets will not be upgraded to being a HD wallet. Wallets that are already\n"
4460 "HD will have a new HD seed set so that new keys added to the keypool will be derived from this new seed.\n"
4461 "\nNote that you will need to MAKE A NEW BACKUP of your wallet after setting the HD wallet seed." +
4463 {
4464 {"newkeypool", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether to flush old unused addresses, including change addresses, from the keypool and regenerate it.\n"
4465 "If true, the next address from getnewaddress and change address from getrawchangeaddress will be from this new seed.\n"
4466 "If false, addresses (including change addresses if the wallet already had HD Chain Split enabled) from the existing\n"
4467 "keypool will be used until it has been depleted."},
4468 {"seed", RPCArg::Type::STR, RPCArg::DefaultHint{"random seed"}, "The WIF private key to use as the new HD seed.\n"
4469 "The seed value can be retrieved using the dumpwallet command. It is the private key marked hdseed=1"},
4470 },
4473 HelpExampleCli("sethdseed", "")
4474 + HelpExampleCli("sethdseed", "false")
4475 + HelpExampleCli("sethdseed", "true \"wifkey\"")
4476 + HelpExampleRpc("sethdseed", "true, \"wifkey\"")
4477 },
4478 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4479{
4480 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
4481 if (!pwallet) return NullUniValue;
4482
4483 LegacyScriptPubKeyMan& spk_man = EnsureLegacyScriptPubKeyMan(*pwallet, true);
4484
4485 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
4486 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set a HD seed to a wallet with private keys disabled");
4487 }
4488
4489 LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
4490
4491 // Do not do anything to non-HD wallets
4492 if (!pwallet->CanSupportFeature(FEATURE_HD)) {
4493 throw JSONRPCError(RPC_WALLET_ERROR, "Cannot set an HD seed on a non-HD wallet. Use the upgradewallet RPC in order to upgrade a non-HD wallet to HD");
4494 }
4495
4496 EnsureWalletIsUnlocked(*pwallet);
4497
4498 bool flush_key_pool = true;
4499 if (!request.params[0].isNull()) {
4500 flush_key_pool = request.params[0].get_bool();
4501 }
4502
4503 CPubKey master_pub_key;
4504 if (request.params[1].isNull()) {
4505 master_pub_key = spk_man.GenerateNewSeed();
4506 } else {
4507 CKey key = DecodeSecret(request.params[1].get_str());
4508 if (!key.IsValid()) {
4509 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key");
4510 }
4511
4512 if (HaveKey(spk_man, key)) {
4513 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key (either as an HD seed or as a loose private key)");
4514 }
4515
4516 master_pub_key = spk_man.DeriveNewSeed(key);
4517 }
4518
4519 spk_man.SetHDSeed(master_pub_key);
4520 if (flush_key_pool) spk_man.NewKeyPool();
4521
4522 return NullUniValue;
4523},
4524 };
4525}
4526
4528{
4529 return RPCHelpMan{"walletprocesspsbt",
4530 "\nUpdate a PSBT with input information from our wallet and then sign inputs\n"
4531 "that we can sign for." +
4533 {
4534 {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The transaction base64 string"},
4535 {"sign", RPCArg::Type::BOOL, RPCArg::Default{true}, "Also sign the transaction when updating (requires wallet to be unlocked)"},
4536 {"sighashtype", RPCArg::Type::STR, RPCArg::Default{"DEFAULT"}, "The signature hash type to sign with if not specified by the PSBT. Must be one of\n"
4537 " \"DEFAULT\"\n"
4538 " \"ALL\"\n"
4539 " \"NONE\"\n"
4540 " \"SINGLE\"\n"
4541 " \"ALL|ANYONECANPAY\"\n"
4542 " \"NONE|ANYONECANPAY\"\n"
4543 " \"SINGLE|ANYONECANPAY\""},
4544 {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
4545 },
4546 RPCResult{
4547 RPCResult::Type::OBJ, "", "",
4548 {
4549 {RPCResult::Type::STR, "psbt", "The base64-encoded partially signed transaction"},
4550 {RPCResult::Type::BOOL, "complete", "If the transaction has a complete set of signatures"},
4551 }
4552 },
4554 HelpExampleCli("walletprocesspsbt", "\"psbt\"")
4555 },
4556 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4557{
4558 const std::shared_ptr<const CWallet> pwallet = GetWalletForJSONRPCRequest(request);
4559 if (!pwallet) return NullUniValue;
4560
4561 const CWallet& wallet{*pwallet};
4562 // Make sure the results are valid at least up to the most recent block
4563 // the user could have gotten from another RPC command prior to now
4564 wallet.BlockUntilSyncedToCurrentChain();
4565
4566 RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
4567
4568 // Unserialize the transaction
4570 std::string error;
4571 if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
4572 throw JSONRPCError(RPC_DESERIALIZATION_ERROR, strprintf("TX decode failed %s", error));
4573 }
4574
4575 // Get the sighash type
4576 int nHashType = ParseSighashString(request.params[2]);
4577
4578 // Fill transaction with our data and also sign
4579 bool sign = request.params[1].isNull() ? true : request.params[1].get_bool();
4580 bool bip32derivs = request.params[3].isNull() ? true : request.params[3].get_bool();
4581 bool complete = true;
4582
4583 if (sign) EnsureWalletIsUnlocked(*pwallet);
4584
4585 const TransactionError err{wallet.FillPSBT(psbtx, complete, nHashType, sign, bip32derivs)};
4586 if (err != TransactionError::OK) {
4587 throw JSONRPCTransactionError(err);
4588 }
4589
4590 UniValue result(UniValue::VOBJ);
4592 ssTx << psbtx;
4593 result.pushKV("psbt", EncodeBase64(ssTx.str()));
4594 result.pushKV("complete", complete);
4595
4596 return result;
4597},
4598 };
4599}
4600
4602{
4603 return RPCHelpMan{"walletcreatefundedpsbt",
4604 "\nCreates and funds a transaction in the Partially Signed Transaction format.\n"
4605 "Implements the Creator and Updater roles.\n"
4606 "All existing inputs must either have their previous output transaction be in the wallet\n"
4607 "or be in the UTXO set. Solving data must be provided for non-wallet inputs.\n",
4608 {
4609 {"inputs", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "Leave empty to add inputs automatically. See add_inputs option.",
4610 {
4612 {
4613 {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id"},
4614 {"vout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The output number"},
4615 {"sequence", RPCArg::Type::NUM, RPCArg::DefaultHint{"depends on the value of the 'locktime' and 'options.replaceable' arguments"}, "The sequence number"},
4616 },
4617 },
4618 },
4619 },
4620 {"outputs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The outputs (key-value pairs), where none of the keys are duplicated.\n"
4621 "That is, each address can only appear once and there can only be one 'data' object.\n"
4622 "For compatibility reasons, a dictionary, which holds the key-value pairs directly, is also\n"
4623 "accepted as second parameter.",
4624 {
4626 {
4627 {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
4628 },
4629 },
4631 {
4632 {"data", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A key-value pair. The key must be \"data\", the value is hex-encoded data"},
4633 },
4634 },
4635 },
4636 },
4637 {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
4639 Cat<std::vector<RPCArg>>(
4640 {
4641 {"add_inputs", RPCArg::Type::BOOL, RPCArg::Default{false}, "If inputs are specified, automatically include more if they are not enough."},
4642 {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
4643 "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
4644 "If that happens, you will need to fund the transaction with different inputs and republish it."},
4645 {"changeAddress", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
4646 {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
4647 {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
4648 {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
4649 {"lockUnspents", RPCArg::Type::BOOL, RPCArg::Default{false}, "Lock selected unspent outputs"},
4650 {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
4651 {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
4652 {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs to subtract the fee from.\n"
4653 "The fee will be equally deducted from the amount of each specified output.\n"
4654 "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
4655 "If no outputs are specified here, the sender pays the fee.",
4656 {
4657 {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
4658 },
4659 },
4660 },
4661 FundTxDoc()),
4662 "options"},
4663 {"bip32derivs", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include BIP 32 derivation paths for public keys if we know them"},
4664 },
4665 RPCResult{
4666 RPCResult::Type::OBJ, "", "",
4667 {
4668 {RPCResult::Type::STR, "psbt", "The resulting raw transaction (base64-encoded string)"},
4669 {RPCResult::Type::STR_AMOUNT, "fee", "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
4670 {RPCResult::Type::NUM, "changepos", "The position of the added change output, or -1"},
4671 }
4672 },
4674 "\nCreate a transaction with no inputs\n"
4675 + HelpExampleCli("walletcreatefundedpsbt", "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" \"[{\\\"data\\\":\\\"00010203\\\"}]\"")
4676 },
4677 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4678{
4679 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
4680 if (!pwallet) return NullUniValue;
4681
4682 CWallet& wallet{*pwallet};
4683 // Make sure the results are valid at least up to the most recent block
4684 // the user could have gotten from another RPC command prior to now
4685 wallet.BlockUntilSyncedToCurrentChain();
4686
4687 RPCTypeCheck(request.params, {
4688 UniValue::VARR,
4689 UniValueType(), // ARR or OBJ, checked later
4690 UniValue::VNUM,
4691 UniValue::VOBJ,
4692 UniValue::VBOOL
4693 }, true
4694 );
4695
4696 CAmount fee;
4697 int change_position;
4698 bool rbf{wallet.m_signal_rbf};
4699 const UniValue &replaceable_arg = request.params[3]["replaceable"];
4700 if (!replaceable_arg.isNull()) {
4701 RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL);
4702 rbf = replaceable_arg.isTrue();
4703 }
4704 CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
4705 CCoinControl coin_control;
4706 // Automatically select coins, unless at least one is manually selected. Can
4707 // be overridden by options.add_inputs.
4708 coin_control.m_add_inputs = rawTx.vin.size() == 0;
4709 FundTransaction(wallet, rawTx, fee, change_position, request.params[3], coin_control, /* override_min_fee */ true);
4710
4711 // Make a blank psbt
4712 PartiallySignedTransaction psbtx(rawTx);
4713
4714 // Fill transaction with out data but don't sign
4715 bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
4716 bool complete = true;
4717 const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs)};
4718 if (err != TransactionError::OK) {
4719 throw JSONRPCTransactionError(err);
4720 }
4721
4722 // Serialize the PSBT
4724 ssTx << psbtx;
4725
4726 UniValue result(UniValue::VOBJ);
4727 result.pushKV("psbt", EncodeBase64(ssTx.str()));
4728 result.pushKV("fee", ValueFromAmount(fee));
4729 result.pushKV("changepos", change_position);
4730 return result;
4731},
4732 };
4733}
4734
4736{
4737 return RPCHelpMan{"upgradewallet",
4738 "\nUpgrade the wallet. Upgrades to the latest version if no version number is specified.\n"
4739 "New keys may be generated and a new wallet backup will need to be made.",
4740 {
4741 {"version", RPCArg::Type::NUM, RPCArg::Default{FEATURE_LATEST}, "The version number to upgrade to. Default is the latest wallet version."}
4742 },
4743 RPCResult{
4744 RPCResult::Type::OBJ, "", "",
4745 {
4746 {RPCResult::Type::STR, "wallet_name", "Name of wallet this operation was performed on"},
4747 {RPCResult::Type::NUM, "previous_version", "Version of wallet before this operation"},
4748 {RPCResult::Type::NUM, "current_version", "Version of wallet after this operation"},
4749 {RPCResult::Type::STR, "result", /* optional */ true, "Description of result, if no error"},
4750 {RPCResult::Type::STR, "error", /* optional */ true, "Error message (if there is one)"}
4751 },
4752 },
4754 HelpExampleCli("upgradewallet", "169900")
4755 + HelpExampleRpc("upgradewallet", "169900")
4756 },
4757 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4758{
4759 std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
4760 if (!pwallet) return NullUniValue;
4761
4762 RPCTypeCheck(request.params, {UniValue::VNUM}, true);
4763
4764 EnsureWalletIsUnlocked(*pwallet);
4765
4766 int version = 0;
4767 if (!request.params[0].isNull()) {
4768 version = request.params[0].get_int();
4769 }
4771 const int previous_version{pwallet->GetVersion()};
4772 const bool wallet_upgraded{pwallet->UpgradeWallet(version, error)};
4773 const int current_version{pwallet->GetVersion()};
4774 std::string result;
4775
4776 if (wallet_upgraded) {
4777 if (previous_version == current_version) {
4778 result = "Already at latest version. Wallet version unchanged.";
4779 } else {
4780 result = strprintf("Wallet upgraded successfully from version %i to version %i.", previous_version, current_version);
4781 }
4782 }
4783
4785 obj.pushKV("wallet_name", pwallet->GetName());
4786 obj.pushKV("previous_version", previous_version);
4787 obj.pushKV("current_version", current_version);
4788 if (!result.empty()) {
4789 obj.pushKV("result", result);
4790 } else {
4791 CHECK_NONFATAL(!error.empty());
4792 obj.pushKV("error", error.original);
4793 }
4794 return obj;
4795},
4796 };
4797}
4798
4799#ifdef ENABLE_EXTERNAL_SIGNER
4801{
4802 return RPCHelpMan{
4803 "walletdisplayaddress",
4804 "Display address on an external signer for verification.",
4805 {
4806 {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "bitcoin address to display"},
4807 },
4808 RPCResult{
4810 {
4811 {RPCResult::Type::STR, "address", "The address as confirmed by the signer"},
4812 }
4813 },
4814 RPCExamples{""},
4815 [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
4816 {
4817 std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4818 if (!wallet) return NullUniValue;
4819 CWallet* const pwallet = wallet.get();
4820
4821 LOCK(pwallet->cs_wallet);
4822
4823 CTxDestination dest = DecodeDestination(request.params[0].get_str());
4824
4825 // Make sure the destination is valid
4826 if (!IsValidDestination(dest)) {
4827 throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
4828 }
4829
4830 if (!pwallet->DisplayAddress(dest)) {
4831 throw JSONRPCError(RPC_MISC_ERROR, "Failed to display address");
4832 }
4833
4834 UniValue result(UniValue::VOBJ);
4835 result.pushKV("address", request.params[0].get_str());
4836 return result;
4837 }
4838 };
4839}
4840#endif // ENABLE_EXTERNAL_SIGNER
4841
4854
4856{
4857// clang-format off
4858static const CRPCCommand commands[] =
4859{ // category actor (function)
4860 // ------------------ ------------------------
4861 { "rawtransactions", &fundrawtransaction, },
4862 { "wallet", &abandontransaction, },
4863 { "wallet", &abortrescan, },
4864 { "wallet", &addmultisigaddress, },
4865 { "wallet", &backupwallet, },
4866 { "wallet", &bumpfee, },
4867 { "wallet", &psbtbumpfee, },
4868 { "wallet", &createwallet, },
4869 { "wallet", &restorewallet, },
4870 { "wallet", &dumpprivkey, },
4871 { "wallet", &dumpwallet, },
4872 { "wallet", &encryptwallet, },
4873 { "wallet", &getaddressesbylabel, },
4874 { "wallet", &getaddressinfo, },
4875 { "wallet", &getbalance, },
4876 { "wallet", &getnewaddress, },
4877 { "wallet", &getrawchangeaddress, },
4878 { "wallet", &getreceivedbyaddress, },
4879 { "wallet", &getreceivedbylabel, },
4880 { "wallet", &gettransaction, },
4881 { "wallet", &getunconfirmedbalance, },
4882 { "wallet", &getbalances, },
4883 { "wallet", &getwalletinfo, },
4884 { "wallet", &importaddress, },
4885 { "wallet", &importdescriptors, },
4886 { "wallet", &importmulti, },
4887 { "wallet", &importprivkey, },
4888 { "wallet", &importprunedfunds, },
4889 { "wallet", &importpubkey, },
4890 { "wallet", &importwallet, },
4891 { "wallet", &keypoolrefill, },
4892 { "wallet", &listaddressgroupings, },
4893 { "wallet", &listdescriptors, },
4894 { "wallet", &listlabels, },
4895 { "wallet", &listlockunspent, },
4896 { "wallet", &listreceivedbyaddress, },
4897 { "wallet", &listreceivedbylabel, },
4898 { "wallet", &listsinceblock, },
4899 { "wallet", &listtransactions, },
4900 { "wallet", &listunspent, },
4901 { "wallet", &listwalletdir, },
4902 { "wallet", &listwallets, },
4903 { "wallet", &loadwallet, },
4904 { "wallet", &lockunspent, },
4905 { "wallet", &newkeypool, },
4906 { "wallet", &removeprunedfunds, },
4907 { "wallet", &rescanblockchain, },
4908 { "wallet", &send, },
4909 { "wallet", &sendmany, },
4910 { "wallet", &sendtoaddress, },
4911 { "wallet", &sethdseed, },
4912 { "wallet", &setlabel, },
4913 { "wallet", &settxfee, },
4914 { "wallet", &setwalletflag, },
4915 { "wallet", &signmessage, },
4916 { "wallet", &signrawtransactionwithwallet, },
4917 { "wallet", &unloadwallet, },
4918 { "wallet", &upgradewallet, },
4919 { "wallet", &walletcreatefundedpsbt, },
4920#ifdef ENABLE_EXTERNAL_SIGNER
4921 { "wallet", &walletdisplayaddress, },
4922#endif // ENABLE_EXTERNAL_SIGNER
4923 { "wallet", &walletlock, },
4924 { "wallet", &walletpassphrase, },
4925 { "wallet", &walletpassphrasechange, },
4926 { "wallet", &walletprocesspsbt, },
4927};
4928// clang-format on
4929 return MakeSpan(commands);
4930}
static constexpr CAmount MAX_MONEY
No amount larger than this (in satoshi) is valid.
Definition: amount.h:26
int64_t CAmount
Amount in satoshis (Can be negative)
Definition: amount.h:12
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath)
Write HD keypaths as strings.
Definition: bip32.cpp:63
UrlDecodeFn *const URL_DECODE
Definition: bitcoin-cli.cpp:44
static CAmount AmountFromValue(const UniValue &value)
Definition: bitcoin-tx.cpp:550
int flags
Definition: bitcoin-tx.cpp:525
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
Definition: check.h:32
size_t size() const
Definition: hash_type.h:63
unsigned char * begin()
Definition: hash_type.h:18
Address book data.
Definition: wallet.h:197
const std::string & GetLabel() const
Definition: wallet.h:210
std::string purpose
Definition: wallet.h:202
uint256 hashPrevBlock
Definition: block.h:25
bool IsNull() const
Definition: block.h:48
Definition: block.h:63
std::vector< CTransactionRef > vtx
Definition: block.h:66
Coin Control Features.
Definition: coincontrol.h:29
std::optional< OutputType > m_change_type
Override the default change type if set, ignored if destChange is set.
Definition: coincontrol.h:34
std::optional< bool > m_signal_bip125_rbf
Override the wallet's m_signal_rbf if set.
Definition: coincontrol.h:50
std::optional< unsigned int > m_confirm_target
Override the default confirmation target if set.
Definition: coincontrol.h:48
void SelectExternal(const COutPoint &outpoint, const CTxOut &txout)
Definition: coincontrol.h:96
int m_max_depth
Maximum chain depth value for coin availability.
Definition: coincontrol.h:60
bool fAllowWatchOnly
Includes watch only addresses which are solvable.
Definition: coincontrol.h:42
int m_min_depth
Minimum chain depth value for coin availability.
Definition: coincontrol.h:58
FlatSigningProvider m_external_provider
SigningProvider that has pubkeys and scripts to do spend size estimation for external inputs.
Definition: coincontrol.h:62
std::optional< CFeeRate > m_feerate
Override the wallet's m_pay_tx_fee if set.
Definition: coincontrol.h:46
bool fOverrideFeeRate
Override automatic min/max checks on fee, m_feerate must be set if true.
Definition: coincontrol.h:44
bool m_add_inputs
If false, only selected inputs are used.
Definition: coincontrol.h:36
CTxDestination destChange
Custom change destination, if not set an address is generated.
Definition: coincontrol.h:32
bool m_avoid_address_reuse
Forbids inclusion of dirty (previously used) addresses.
Definition: coincontrol.h:54
bool m_include_unsafe_inputs
If false, only safe inputs will be used.
Definition: coincontrol.h:38
bool m_avoid_partial_spends
Avoid partial use of funds sent to a given address.
Definition: coincontrol.h:52
FeeEstimateMode m_fee_mode
Fee estimation mode to control arguments to estimateSmartFee.
Definition: coincontrol.h:56
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:205
std::string str() const
Definition: streams.h:242
Fee rate in satoshis per kilobyte: CAmount / kB.
Definition: feerate.h:30
std::string ToString(const FeeEstimateMode &fee_estimate_mode=FeeEstimateMode::BTC_KVB) const
Definition: feerate.cpp:39
CKeyID seed_id
seed hash160
Definition: walletdb.h:92
An encapsulated private key.
Definition: key.h:27
const unsigned char * begin() const
Definition: key.h:89
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:93
const unsigned char * end() const
Definition: key.h:90
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:96
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:187
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:73
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:23
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:27
uint32_t n
Definition: transaction.h:30
uint256 hash
Definition: transaction.h:29
Definition: spend.h:17
An encapsulated public key.
Definition: pubkey.h:33
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:194
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:160
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:292
A hasher class for RIPEMD-160.
Definition: ripemd160.h:13
CRIPEMD160 & Write(const unsigned char *data, size_t len)
Definition: ripemd160.cpp:247
void Finalize(unsigned char hash[OUTPUT_SIZE])
Definition: ripemd160.cpp:273
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:406
bool IsPayToScriptHash() const
Definition: script.cpp:201
bool IsPayToWitnessScriptHash() const
Definition: script.cpp:210
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:26
The basic transaction that is broadcasted on the network and contained in blocks.
Definition: transaction.h:260
An input of a transaction.
Definition: transaction.h:66
COutPoint prevout
Definition: transaction.h:68
An output of a transaction.
Definition: transaction.h:129
CScript scriptPubKey
Definition: transaction.h:132
CAmount nValue
Definition: transaction.h:131
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:229
Mutex m_unlock_mutex
Definition: wallet.h:479
RecursiveMutex cs_wallet
Main wallet lock.
Definition: wallet.h:345
bool Unlock(const CKeyingMaterial &vMasterKeyIn, bool accept_no_keys=false)
Definition: wallet.cpp:2995
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:405
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
Definition: wallet.h:355
std::multimap< int64_t, CWalletTx * > TxItems
Definition: wallet.h:386
bool IsCrypted() const
Definition: wallet.cpp:2967
A transaction with a bunch of additional info that only the owner cares about.
Definition: transaction.h:47
mapValue_t mapValue
Key/value map with information about the transaction.
Definition: transaction.h:80
CTransactionRef tx
Definition: transaction.h:138
Confirmation m_confirm
Definition: transaction.h:169
const uint256 & GetHash() const
Definition: transaction.h:267
int64_t GetTxTime() const
Definition: transaction.cpp:21
bool IsCoinBase() const
Definition: transaction.h:268
unsigned int nTimeReceived
time received by this node
Definition: transaction.h:83
const SigningProvider *const provider
Definition: rpcwallet.cpp:3893
UniValue operator()(const WitnessV0KeyHash &id) const
Definition: rpcwallet.cpp:3955
UniValue operator()(const PKHash &pkhash) const
Definition: rpcwallet.cpp:3932
UniValue operator()(const ScriptHash &scripthash) const
Definition: rpcwallet.cpp:3944
UniValue operator()(const WitnessUnknown &id) const
Definition: rpcwallet.cpp:3979
void ProcessSubScript(const CScript &subscript, UniValue &obj) const
Definition: rpcwallet.cpp:3895
DescribeWalletAddressVisitor(const SigningProvider *_provider)
Definition: rpcwallet.cpp:3928
UniValue operator()(const WitnessV1Taproot &id) const
Definition: rpcwallet.cpp:3978
UniValue operator()(const WitnessV0ScriptHash &id) const
Definition: rpcwallet.cpp:3965
UniValue operator()(const CNoDestination &dest) const
Definition: rpcwallet.cpp:3930
bool GetDescriptorString(std::string &out, const bool priv) const
Fast randomness source.
Definition: random.h:120
RecursiveMutex cs_KeyStore
enum JSONRPCRequest::Mode mode
std::string URI
Definition: request.h:35
std::any context
Definition: request.h:38
const CHDChain & GetHDChain() const
void SetHDSeed(const CPubKey &key)
bool NewKeyPool()
Mark old keypool keys as used, and generate all new keys.
CPubKey DeriveNewSeed(const CKey &key)
virtual std::unique_ptr< CKeyMetadata > GetMetadata(const CTxDestination &dest) const
An interface to be implemented by keystores that support signing.
virtual bool GetCScript(const CScriptID &scriptid, CScript &script) const
virtual bool GetPubKey(const CKeyID &address, CPubKey &pubkey) const
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:93
const std::string & get_str() const
bool isTrue() const
Definition: univalue.h:76
@ VOBJ
Definition: univalue.h:19
@ VSTR
Definition: univalue.h:19
@ VARR
Definition: univalue.h:19
@ VNUM
Definition: univalue.h:19
@ VBOOL
Definition: univalue.h:19
bool isNull() const
Definition: univalue.h:75
const UniValue & get_obj() const
void __pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:127
size_t size() const
Definition: univalue.h:66
enum VType type() const
Definition: univalue.h:179
const std::vector< UniValue > & getValues() const
const std::vector< std::string > & getKeys() const
bool empty() const
Definition: univalue.h:64
bool pushKVs(const UniValue &obj)
Definition: univalue.cpp:146
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:73
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool get_bool() const
int get_int() const
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:890
unsigned char * begin()
Definition: uint256.h:58
bool IsNull() const
Definition: uint256.h:31
std::string GetHex() const
Definition: uint256.cpp:20
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:34
std::string u8string() const
Definition: fs.h:59
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:93
virtual void rpcRunLater(const std::string &name, std::function< void()> fn, int64_t seconds)=0
Run function after given number of seconds. Cancel any previous calls with same name.
virtual RBFTransactionState isRBFOptIn(const CTransaction &tx)=0
Check if transaction is RBF opt in.
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
Helper for findBlock to selectively return pieces of block data.
Definition: chain.h:42
void push_back(const T &value)
Definition: prevector.h:437
160-bit opaque blob.
Definition: uint256.h:113
256-bit opaque blob.
Definition: uint256.h:124
int ParseSighashString(const UniValue &sighash)
Definition: core_read.cpp:249
std::string EncodeHexTx(const CTransaction &tx, const int serializeFlags=0)
Definition: core_write.cpp:138
void TxToUniv(const CTransaction &tx, const uint256 &hashBlock, UniValue &entry, bool include_hex=true, int serialize_flags=0, const CTxUndo *txundo=nullptr, TxVerbosity verbosity=TxVerbosity::SHOW_DETAILS)
Definition: core_write.cpp:166
UniValue ValueFromAmount(const CAmount amount)
Definition: core_write.cpp:21
bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Definition: core_read.cpp:189
std::vector< fs::path > ListDatabases(const fs::path &wallet_dir)
Recursively list database paths in directory.
Definition: db.cpp:13
DatabaseStatus
Definition: db.h:212
static NodeId id
std::unique_ptr< Descriptor > InferDescriptor(const CScript &script, const SigningProvider &provider)
Find a descriptor for the specified script, using information from provider where possible.
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
TransactionError
Definition: error.h:22
const std::string CURRENCY_ATOM
Definition: feerate.h:15
const std::string CURRENCY_UNIT
Definition: feerate.h:14
@ SAT_VB
Use sat/vB fee rate unit.
bool DisplayAddress(const CTxDestination &dest) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Display address on an external signer.
Definition: wallet.cpp:2252
bool TopUpKeyPool(unsigned int kpSize=0)
Definition: wallet.cpp:2129
uint8_t isminefilter
Definition: wallet.h:36
@ SIGHASH_DEFAULT
Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL.
Definition: interpreter.h:32
isminetype
IsMine() return codes, which depend on ScriptPubKeyMan implementation.
Definition: ismine.h:39
@ ISMINE_SPENDABLE
Definition: ismine.h:42
@ ISMINE_WATCH_ONLY
Definition: ismine.h:41
bool IsValidDestinationString(const std::string &str, const CChainParams &params)
Definition: key_io.cpp:272
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:256
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:178
CTxDestination DecodeDestination(const std::string &str, std::string &error_msg)
Definition: key_io.cpp:261
SigningResult
Definition: message.h:42
@ OK
No error.
std::string FormatMoney(const CAmount n)
Money parsing/formatting utilities.
Definition: moneystr.cpp:15
Result CommitTransaction(CWallet &wallet, const uint256 &txid, CMutableTransaction &&mtx, std::vector< bilingual_str > &errors, uint256 &bumped_txid)
Commit the bumpfee transaction.
Definition: feebumper.cpp:250
Result CreateRateBumpTransaction(CWallet &wallet, const uint256 &txid, const CCoinControl &coin_control, std::vector< bilingual_str > &errors, CAmount &old_fee, CAmount &new_fee, CMutableTransaction &mtx)
Create bumpfee transaction based on feerate estimates.
Definition: feebumper.cpp:156
bool SignTransaction(CWallet &wallet, CMutableTransaction &mtx)
Sign the new transaction,.
Definition: feebumper.cpp:245
static path u8path(const std::string &string)
Definition: fs.h:63
static bool exists(const path &p)
Definition: fs.h:77
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:35
std::optional< OutputType > ParseOutputType(const std::string &type)
Definition: outputtype.cpp:24
OutputType
Definition: outputtype.h:18
RBFTransactionState
The rbf state of unconfirmed transactions.
Definition: rbf.h:20
@ UNKNOWN
Unconfirmed tx that does not signal rbf and is not in the mempool.
@ REPLACEABLE_BIP125
Either this tx or a mempool ancestor signals rbf.
static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE
Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP...
Definition: policy.h:34
static CTransactionRef MakeTransactionRef(Tx &&txIn)
Definition: transaction.h:387
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:386
bool DecodeBase64PSBT(PartiallySignedTransaction &psbt, const std::string &base64_tx, std::string &error)
Decode a base64ed PSBT into a PartiallySignedTransaction.
Definition: psbt.cpp:374
bool FinalizeAndExtractPSBT(PartiallySignedTransaction &psbtx, CMutableTransaction &result)
Finalizes a PSBT if possible, and extracts it to a CMutableTransaction if it could be finalized.
Definition: psbt.cpp:333
void SignTransactionResultToJSON(CMutableTransaction &mtx, bool complete, const std::map< COutPoint, Coin > &coins, const std::map< int, bilingual_str > &input_errors, UniValue &result)
CMutableTransaction ConstructTransaction(const UniValue &inputs_in, const UniValue &outputs_in, const UniValue &locktime, bool rbf)
Create a transaction from univalue parameters.
void ParsePrevouts(const UniValue &prevTxsUnival, FillableSigningProvider *keystore, std::map< COutPoint, Coin > &coins)
Parse a prevtxs UniValue array and get the map of coins from it.
bool CachedTxIsFromMe(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
Definition: receive.cpp:273
std::set< std::set< CTxDestination > > GetAddressGroupings(const CWallet &wallet)
Definition: receive.cpp:384
std::map< CTxDestination, CAmount > GetAddressBalances(const CWallet &wallet)
Definition: receive.cpp:346
bool ScriptIsChange(const CWallet &wallet, const CScript &script)
Definition: receive.cpp:65
void CachedTxGetAmounts(const CWallet &wallet, const CWalletTx &wtx, std::list< COutputEntry > &listReceived, std::list< COutputEntry > &listSent, CAmount &nFee, const isminefilter &filter)
Definition: receive.cpp:216
CAmount CachedTxGetDebit(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
filter decides which addresses will count towards the debit
Definition: receive.cpp:140
CAmount CachedTxGetCredit(const CWallet &wallet, const CWalletTx &wtx, const isminefilter &filter)
Definition: receive.cpp:123
Balance GetBalance(const CWallet &wallet, const int min_depth, bool avoid_reuse)
Definition: receive.cpp:317
bool CachedTxIsTrusted(const CWallet &wallet, const CWalletTx &wtx, std::set< uint256 > &trusted_parents)
Definition: receive.cpp:278
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:51
const char * name
Definition: rest.cpp:43
RPCErrorCode
Bitcoin RPC error codes.
Definition: protocol.h:24
@ RPC_WALLET_NOT_SPECIFIED
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:81
@ RPC_WALLET_INVALID_LABEL_NAME
Invalid label name.
Definition: protocol.h:73
@ RPC_WALLET_UNLOCK_NEEDED
Enter the wallet passphrase with walletpassphrase first.
Definition: protocol.h:75
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:39
@ RPC_WALLET_INSUFFICIENT_FUNDS
Not enough funds in wallet or account.
Definition: protocol.h:72
@ RPC_WALLET_WRONG_ENC_STATE
Command given in wrong wallet encryption state (encrypting an encrypted wallet etc....
Definition: protocol.h:77
@ RPC_WALLET_ENCRYPTION_FAILED
Failed to encrypt the wallet.
Definition: protocol.h:78
@ RPC_TYPE_ERROR
Unexpected type was passed as parameter.
Definition: protocol.h:40
@ RPC_METHOD_DEPRECATED
RPC method is deprecated.
Definition: protocol.h:50
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
@ RPC_WALLET_ERROR
Wallet errors.
Definition: protocol.h:71
@ RPC_WALLET_ALREADY_LOADED
This same wallet is already loaded.
Definition: protocol.h:82
@ RPC_WALLET_NOT_FOUND
Invalid wallet specified.
Definition: protocol.h:80
@ RPC_INTERNAL_ERROR
Definition: protocol.h:35
@ RPC_WALLET_KEYPOOL_RAN_OUT
Keypool ran out, call keypoolrefill first.
Definition: protocol.h:74
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:45
@ RPC_WALLET_PASSPHRASE_INCORRECT
The wallet passphrase entered was incorrect.
Definition: protocol.h:76
@ RPC_INVALID_REQUEST
Standard JSON-RPC 2.0 errors.
Definition: protocol.h:28
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:41
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:24
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:156
CTxDestination AddAndGetMultisigDestination(const int required, const std::vector< CPubKey > &pubkeys, OutputType type, FillableSigningProvider &keystore, CScript &script_out)
Definition: util.cpp:226
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:180
void RPCTypeCheckArgument(const UniValue &value, const UniValueType &typeExpected)
Type-check one argument; throws JSONRPCError if wrong type given.
Definition: util.cpp:41
UniValue JSONRPCTransactionError(TransactionError terr, const std::string &err_string)
Definition: util.cpp:359
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:174
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:21
CPubKey HexToPubKey(const std::string &hex_in)
Definition: util.cpp:192
uint256 ParseHashO(const UniValue &o, std::string strKey)
Definition: util.cpp:99
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:90
const std::string EXAMPLE_ADDRESS[2]
Example bech32 addresses for the RPCExamples help documentation.
Definition: util.cpp:22
unsigned int ParseConfirmTarget(const UniValue &value, unsigned int max_target)
Parse a confirm target option and raise an RPC error if it is invalid.
Definition: util.cpp:330
void RPCTypeCheckObj(const UniValue &o, const std::map< std::string, UniValueType > &typesExpected, bool fAllowNull, bool fStrict)
Definition: util.cpp:48
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:161
CPubKey AddrToPubKey(const FillableSigningProvider &keystore, const std::string &addr_in)
Definition: util.cpp:205
UniValue DescribeAddress(const CTxDestination &dest)
Definition: util.cpp:325
static RPCHelpMan createwallet()
Definition: rpcwallet.cpp:2763
static RPCHelpMan getnewaddress()
Definition: rpcwallet.cpp:240
static RPCHelpMan sethdseed()
Definition: rpcwallet.cpp:4456
RPCHelpMan importprivkey()
Definition: rpcdump.cpp:94
static RPCHelpMan walletlock()
Definition: rpcwallet.cpp:2068
static RPCHelpMan bumpfee_helper(std::string method_name)
Definition: rpcwallet.cpp:3633
static RPCHelpMan psbtbumpfee()
Definition: rpcwallet.cpp:3808
static RPCHelpMan listreceivedbylabel()
Definition: rpcwallet.cpp:1251
static void SetFeeEstimateMode(const CWallet &wallet, CCoinControl &cc, const UniValue &conf_target, const UniValue &estimate_mode, const UniValue &fee_rate, bool override_min_fee)
Update coin control with fee estimation based on the given parameters.
Definition: rpcwallet.cpp:216
static std::string LabelFromValue(const UniValue &value)
Definition: rpcwallet.cpp:195
static RPCHelpMan sendtoaddress()
Definition: rpcwallet.cpp:444
Span< const CRPCCommand > GetWalletRPCCommands()
Definition: rpcwallet.cpp:4855
static RPCHelpMan listunspent()
Definition: rpcwallet.cpp:2971
static RPCHelpMan getrawchangeaddress()
Definition: rpcwallet.cpp:295
static const std::vector< RPCResult > TransactionDescriptionString()
Definition: rpcwallet.cpp:1388
static RPCHelpMan rescanblockchain()
Definition: rpcwallet.cpp:3810
static RPCHelpMan walletprocesspsbt()
Definition: rpcwallet.cpp:4527
RPCHelpMan importdescriptors()
Definition: rpcdump.cpp:1608
static const std::string WALLET_ENDPOINT_BASE
Definition: rpcwallet.cpp:50
static RPCHelpMan fundrawtransaction()
Definition: rpcwallet.cpp:3434
static RPCHelpMan gettransaction()
Definition: rpcwallet.cpp:1665
RPCHelpMan listdescriptors()
Definition: rpcdump.cpp:1760
static RPCHelpMan restorewallet()
Definition: rpcwallet.cpp:2858
static UniValue AddressBookDataToJSON(const CAddressBookData &data, const bool verbose)
Convert CAddressBookData to JSON record.
Definition: rpcwallet.cpp:3995
RPCHelpMan importmulti()
Definition: rpcdump.cpp:1269
RPCHelpMan importaddress()
Definition: rpcdump.cpp:223
void FundTransaction(CWallet &wallet, CMutableTransaction &tx, CAmount &fee_out, int &change_position, const UniValue &options, CCoinControl &coinControl, bool override_min_fee)
Definition: rpcwallet.cpp:3235
static RPCHelpMan listaddressgroupings()
Definition: rpcwallet.cpp:546
RPCHelpMan importwallet()
Definition: rpcdump.cpp:509
static RPCHelpMan addmultisigaddress()
Definition: rpcwallet.cpp:958
static RPCHelpMan walletdisplayaddress()
Definition: rpcwallet.cpp:4800
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:99
static RPCHelpMan walletpassphrasechange()
Definition: rpcwallet.cpp:2020
static RPCHelpMan getaddressesbylabel()
Definition: rpcwallet.cpp:4146
static RPCHelpMan listtransactions()
Definition: rpcwallet.cpp:1415
static std::tuple< std::shared_ptr< CWallet >, std::vector< bilingual_str > > LoadWalletHelper(WalletContext &context, UniValue load_on_start_param, const std::string wallet_name)
Definition: rpcwallet.cpp:2628
static RPCHelpMan listlockunspent()
Definition: rpcwallet.cpp:2304
UniValue SendMoney(CWallet &wallet, const CCoinControl &coin_control, std::vector< CRecipient > &recipients, mapValue_t map_value, bool verbose)
Definition: rpcwallet.cpp:411
static RPCHelpMan send()
Definition: rpcwallet.cpp:4258
static RPCHelpMan getunconfirmedbalance()
Definition: rpcwallet.cpp:840
RPCHelpMan dumpwallet()
Definition: rpcdump.cpp:712
static RPCHelpMan listwallets()
Definition: rpcwallet.cpp:2597
static RPCHelpMan upgradewallet()
Definition: rpcwallet.cpp:4735
static RPCHelpMan unloadwallet()
Definition: rpcwallet.cpp:2920
void EnsureWalletIsUnlocked(const CWallet &wallet)
Definition: rpcwallet.cpp:124
RPCHelpMan importpubkey()
Definition: rpcdump.cpp:423
static RPCHelpMan walletcreatefundedpsbt()
Definition: rpcwallet.cpp:4601
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: rpcwallet.cpp:141
static RPCHelpMan getbalances()
Definition: rpcwallet.cpp:2398
static RPCHelpMan listwalletdir()
Definition: rpcwallet.cpp:2560
static RPCHelpMan keypoolrefill()
Definition: rpcwallet.cpp:1852
bool HaveKey(const SigningProvider &wallet, const CKey &key)
Checks if a CKey is in the given CWallet compressed or otherwise.
Definition: rpcwallet.cpp:82
static UniValue DescribeWalletAddress(const CWallet &wallet, const CTxDestination &dest)
Definition: rpcwallet.cpp:3982
static void ListTransactions(const CWallet &wallet, const CWalletTx &wtx, int nMinDepth, bool fLong, UniValue &ret, const isminefilter &filter_ismine, const std::string *filter_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
List transactions based on the given criteria.
Definition: rpcwallet.cpp:1311
static RPCHelpMan signmessage()
Definition: rpcwallet.cpp:606
static bool ParseIncludeWatchonly(const UniValue &include_watchonly, const CWallet &wallet)
Used by RPC commands that have an include_watchonly parameter.
Definition: rpcwallet.cpp:69
RPCHelpMan getaddressinfo()
Definition: rpcwallet.cpp:4005
static CAmount GetReceived(const CWallet &wallet, const UniValue &params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
Definition: rpcwallet.cpp:663
static RPCHelpMan getwalletinfo()
Definition: rpcwallet.cpp:2465
static RPCHelpMan lockunspent()
Definition: rpcwallet.cpp:2164
static RPCHelpMan listlabels()
Definition: rpcwallet.cpp:4204
RPCHelpMan importprunedfunds()
Definition: rpcdump.cpp:327
static RPCHelpMan setwalletflag()
Definition: rpcwallet.cpp:2696
static std::vector< RPCArg > FundTxDoc()
Definition: rpcwallet.cpp:3208
RPCHelpMan signrawtransactionwithwallet()
Definition: rpcwallet.cpp:3536
RPCHelpMan abortrescan()
Definition: rpcdump.cpp:196
static RPCHelpMan newkeypool()
Definition: rpcwallet.cpp:1897
static RPCHelpMan setlabel()
Definition: rpcwallet.cpp:343
static UniValue ListReceived(const CWallet &wallet, const UniValue &params, bool by_label) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
Definition: rpcwallet.cpp:1055
static RPCHelpMan getreceivedbyaddress()
Definition: rpcwallet.cpp:709
static RPCHelpMan getreceivedbylabel()
Definition: rpcwallet.cpp:747
static RPCHelpMan encryptwallet()
Definition: rpcwallet.cpp:2106
static RPCHelpMan backupwallet()
Definition: rpcwallet.cpp:1818
static void WalletTxToJSON(const CWallet &wallet, const CWalletTx &wtx, UniValue &entry)
Definition: rpcwallet.cpp:153
static void MaybePushAddress(UniValue &entry, const CTxDestination &dest)
Definition: rpcwallet.cpp:1293
void ParseRecipients(const UniValue &address_amounts, const UniValue &subtract_fee_outputs, std::vector< CRecipient > &recipients)
Definition: rpcwallet.cpp:381
RPCHelpMan dumpprivkey()
Definition: rpcdump.cpp:666
static RPCHelpMan getbalance()
Definition: rpcwallet.cpp:785
static RPCHelpMan loadwallet()
Definition: rpcwallet.cpp:2659
static bool GetAvoidReuseFlag(const CWallet &wallet, const UniValue &param)
Definition: rpcwallet.cpp:53
static RPCHelpMan listsinceblock()
Definition: rpcwallet.cpp:1526
static RPCHelpMan settxfee()
Definition: rpcwallet.cpp:2357
RPCHelpMan removeprunedfunds()
Definition: rpcdump.cpp:385
static RPCHelpMan listreceivedbyaddress()
Definition: rpcwallet.cpp:1202
static RPCHelpMan sendmany()
Definition: rpcwallet.cpp:864
WalletContext & EnsureWalletContext(const std::any &context)
Definition: rpcwallet.cpp:131
static RPCHelpMan walletpassphrase()
Definition: rpcwallet.cpp:1924
static RPCHelpMan bumpfee()
Definition: rpcwallet.cpp:3807
static const std::string HELP_REQUIRING_PASSPHRASE
Definition: rpcwallet.cpp:51
bool GetWalletNameFromJSONRPCRequest(const JSONRPCRequest &request, std::string &wallet_name)
Definition: rpcwallet.cpp:89
static RPCHelpMan abandontransaction()
Definition: rpcwallet.cpp:1776
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
std::basic_string< char, std::char_traits< char >, secure_allocator< char > > SecureString
Definition: secure.h:59
@ SER_NETWORK
Definition: serialize.h:138
bool IsSolvable(const SigningProvider &provider, const CScript &script)
Definition: sign.cpp:581
FlatSigningProvider Merge(const FlatSigningProvider &a, const FlatSigningProvider &b)
constexpr Span< A > MakeSpan(A(&a)[N])
MakeSpan for arrays:
Definition: span.h:222
void AvailableCoins(const CWallet &wallet, std::vector< COutput > &vCoins, const CCoinControl *coinControl, const CAmount &nMinimumAmount, const CAmount &nMaximumAmount, const CAmount &nMinimumSumAmount, const uint64_t nMaximumCount)
populate vCoins with vector of available COutputs.
Definition: spend.cpp:88
bool CreateTransaction(CWallet &wallet, const std::vector< CRecipient > &vecSend, CTransactionRef &tx, CAmount &nFeeRet, int &nChangePosInOut, bilingual_str &error, const CCoinControl &coin_control, FeeCalculation &fee_calc_out, bool sign)
Create a new transaction paying the recipients with a set of coins selected by SelectCoins(); Also cr...
Definition: spend.cpp:941
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:144
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:213
std::string GetTxnOutputType(TxoutType t)
Get the name of a TxoutType as a string.
Definition: standard.cpp:49
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:332
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:310
CKeyID ToKeyID(const PKHash &key_hash)
Definition: standard.cpp:34
TxoutType
Definition: standard.h:59
std::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessV1Taproot, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:157
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::string EncodeBase64(Span< const unsigned char > input)
std::vector< unsigned char > ParseHex(const char *psz)
bool IsHex(const std::string &str)
auto Join(const std::vector< T > &list, const BaseType &separator, UnaryOp unary_op) -> decltype(unary_op(list.at(0)))
Join a list of items.
Definition: string.h:44
CAmount m_mine_untrusted_pending
Untrusted, but in mempool (pending)
Definition: receive.h:53
A mutable version of CTransaction.
Definition: transaction.h:345
std::vector< CTxOut > vout
Definition: transaction.h:347
std::vector< CTxIn > vin
Definition: transaction.h:346
Definition: receive.h:38
std::optional< int > last_scanned_height
Definition: wallet.h:522
enum CWallet::ScanResult::@17 status
bool require_create
Definition: db.h:205
uint64_t create_flags
Definition: db.h:207
bool require_existing
Definition: db.h:204
SecureString create_passphrase
Definition: db.h:208
FeeReason reason
Definition: fees.h:78
std::map< CKeyID, CPubKey > pubkeys
std::map< CScriptID, CScript > scripts
A version of CTransaction with the PSBT format.
Definition: psbt.h:392
@ OBJ_USER_KEYS
Special type where the user must set the keys e.g. to define multiple addresses; as opposed to e....
@ STR_HEX
Special type that is a STR with only hex chars.
@ AMOUNT
Special type representing a floating point amount (can be either NUM or STR)
std::string DefaultHint
Definition: util.h:155
@ OMITTED_NAMED_ARG
Optional arg that is a named argument and has a default value of null.
@ OMITTED
Optional argument with default value omitted because they are implicitly clear.
@ NO
Required arg.
@ ELISION
Special type to denote elision (...)
@ NUM_TIME
Special numeric to denote unix epoch time.
@ ARR_FIXED
Special array that has a fixed number of entries.
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
Wrapper for UniValue::VType, which includes typeAny: Used to denote don't care type.
Definition: util.h:44
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:34
CTxDestination subtype to encode any future Witness version.
Definition: standard.h:126
Bilingual messages:
Definition: translation.h:16
std::vector< uint256 > txids
Definition: rpcwallet.cpp:1048
bool fIsWatchonly
Definition: rpcwallet.cpp:1049
CAmount nAmount
Definition: rpcwallet.cpp:1046
#define AssertLockNotHeld(cs)
Definition: sync.h:84
#define LOCK2(cs1, cs2)
Definition: sync.h:227
#define LOCK(cs)
Definition: sync.h:226
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:49
int64_t GetTime()
DEPRECATED Use either GetTimeSeconds (not mockable) or GetTime<T> (mockable)
Definition: time.cpp:26
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:46
const UniValue NullUniValue
Definition: univalue.cpp:13
const UniValue & find_value(const UniValue &obj, const std::string &name)
Definition: univalue.cpp:236
std::string FeeModes(const std::string &delimiter)
Definition: fees.cpp:47
bool FeeModeFromString(const std::string &mode_string, FeeEstimateMode &fee_estimate_mode)
Definition: fees.cpp:57
const std::string InvalidEstimateModeErrorMessage()
Definition: fees.cpp:52
std::string StringForFeeReason(FeeReason reason)
Definition: fees.cpp:17
std::string SigningResultString(const SigningResult res)
Definition: message.cpp:80
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by Boost's create_directories if the requested directory exists.
Definition: system.cpp:1081
V Cat(V v1, V &&v2)
Concatenate two vectors, moving elements.
Definition: vector.h:31
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
std::map< std::string, std::string > mapValue_t
Definition: transaction.h:20
const std::map< uint64_t, std::string > WALLET_FLAG_CAVEATS
Definition: wallet.cpp:51
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:117
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:189
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:143
std::shared_ptr< CWallet > GetWallet(WalletContext &context, const std::string &name)
Definition: wallet.cpp:149
std::shared_ptr< CWallet > CreateWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:258
std::shared_ptr< CWallet > LoadWallet(WalletContext &context, const std::string &name, std::optional< bool > load_on_start, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:245
static constexpr uint64_t MUTABLE_WALLET_FLAGS
Definition: wallet.h:127
static const std::map< std::string, WalletFlags > WALLET_FLAG_MAP
Definition: wallet.h:130
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:10
@ WALLET_FLAG_EXTERNAL_SIGNER
Indicates that the wallet needs an external signer.
Definition: walletutil.h:68
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:50
@ WALLET_FLAG_AVOID_REUSE
Definition: walletutil.h:41
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:65
@ WALLET_FLAG_BLANK_WALLET
Flag set when a wallet contains no HD seed and no private keys, scripts, addresses,...
Definition: walletutil.h:62
@ FEATURE_HD_SPLIT
Definition: walletutil.h:23
@ FEATURE_HD
Definition: walletutil.h:21
@ FEATURE_LATEST
Definition: walletutil.h:29