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