Bitcoin ABC  0.22.13
P2P Digital Currency
rpcwallet.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2019 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 <chainparams.h> // for GetConsensus.
8 #include <coins.h>
9 #include <config.h>
10 #include <consensus/validation.h>
11 #include <core_io.h>
12 #include <interfaces/chain.h>
13 #include <key_io.h>
14 #include <network.h>
15 #include <node/context.h>
16 #include <outputtype.h>
17 #include <policy/fees.h>
19 #include <rpc/server.h>
20 #include <rpc/util.h>
21 #include <script/descriptor.h>
22 #include <util/bip32.h>
23 #include <util/error.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/rpcwallet.h>
35 #include <wallet/wallet.h>
36 #include <wallet/walletdb.h>
37 #include <wallet/walletutil.h>
38 
39 #include <univalue.h>
40 
41 #include <event2/http.h>
42 
44 
45 static const std::string WALLET_ENDPOINT_BASE = "/wallet/";
46 static const std::string HELP_REQUIRING_PASSPHRASE{
47  "\nRequires wallet passphrase to be set with walletpassphrase call if "
48  "wallet is encrypted.\n"};
49 
50 static inline bool GetAvoidReuseFlag(const CWallet *const pwallet,
51  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(
58  "wallet does not have the \"avoid reuse\" feature enabled");
59  }
60 
61  return avoid_reuse;
62 }
63 
68 static bool ParseIncludeWatchonly(const UniValue &include_watchonly,
69  const CWallet &pwallet) {
70  if (include_watchonly.isNull()) {
71  // if include_watchonly isn't explicitly set, then check if we have a
72  // watchonly wallet
74  }
75 
76  // otherwise return whatever include_watchonly was set to
77  return include_watchonly.get_bool();
78 }
79 
83 bool HaveKey(const SigningProvider &wallet, const CKey &key) {
84  CKey key2;
85  key2.Set(key.begin(), key.end(), !key.IsCompressed());
86  return wallet.HaveKey(key.GetPubKey().GetID()) ||
87  wallet.HaveKey(key2.GetPubKey().GetID());
88 }
89 
91  std::string &wallet_name) {
92  if (request.URI.substr(0, WALLET_ENDPOINT_BASE.size()) ==
94  // wallet endpoint was used
95  wallet_name =
96  urlDecode(request.URI.substr(WALLET_ENDPOINT_BASE.size()));
97  return true;
98  }
99  return false;
100 }
101 
102 std::shared_ptr<CWallet>
104  std::string wallet_name;
105  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
106  std::shared_ptr<CWallet> pwallet = GetWallet(wallet_name);
107  if (!pwallet) {
108  throw JSONRPCError(
110  "Requested wallet does not exist or is not loaded");
111  }
112  return pwallet;
113  }
114 
115  std::vector<std::shared_ptr<CWallet>> wallets = GetWallets();
116  return wallets.size() == 1 || (request.fHelp && wallets.size() > 0)
117  ? wallets[0]
118  : nullptr;
119 }
120 
121 bool EnsureWalletIsAvailable(const CWallet *pwallet, bool avoidException) {
122  if (pwallet) {
123  return true;
124  }
125  if (avoidException) {
126  return false;
127  }
128  if (!HasWallets()) {
130  "Method not found (wallet method is disabled "
131  "because no wallet is loaded)");
132  }
133 
135  "Wallet file not specified (must request wallet RPC "
136  "through /wallet/<filename> uri-path).");
137 }
138 
139 void EnsureWalletIsUnlocked(const CWallet *pwallet) {
140  if (pwallet->IsLocked()) {
142  "Error: Please enter the wallet passphrase with "
143  "walletpassphrase first.");
144  }
145 }
146 
148  if (!context.Has<WalletContext>()) {
149  throw JSONRPCError(RPC_INTERNAL_ERROR, "Wallet context not found");
150  }
151  return context.Get<WalletContext>();
152 }
153 
154 // also_create should only be set to true only when the RPC is expected to add
155 // things to a blank wallet and make it no longer blank
157  bool also_create) {
159  if (!spk_man && also_create) {
160  spk_man = wallet.GetOrCreateLegacyScriptPubKeyMan();
161  }
162  if (!spk_man) {
164  "This type of wallet does not support this command");
165  }
166  return *spk_man;
167 }
168 
169 static void WalletTxToJSON(interfaces::Chain &chain, const CWalletTx &wtx,
170  UniValue &entry) {
171  int confirms = wtx.GetDepthInMainChain();
172  entry.pushKV("confirmations", confirms);
173  if (wtx.IsCoinBase()) {
174  entry.pushKV("generated", true);
175  }
176  if (confirms > 0) {
177  entry.pushKV("blockhash", wtx.m_confirm.hashBlock.GetHex());
178  entry.pushKV("blockheight", wtx.m_confirm.block_height);
179  entry.pushKV("blockindex", wtx.m_confirm.nIndex);
180  int64_t block_time;
182  FoundBlock().time(block_time)));
183  entry.pushKV("blocktime", block_time);
184  } else {
185  entry.pushKV("trusted", wtx.IsTrusted());
186  }
187  uint256 hash = wtx.GetId();
188  entry.pushKV("txid", hash.GetHex());
189  UniValue conflicts(UniValue::VARR);
190  for (const uint256 &conflict : wtx.GetConflicts()) {
191  conflicts.push_back(conflict.GetHex());
192  }
193  entry.pushKV("walletconflicts", conflicts);
194  entry.pushKV("time", wtx.GetTxTime());
195  entry.pushKV("timereceived", (int64_t)wtx.nTimeReceived);
196 
197  for (const std::pair<const std::string, std::string> &item : wtx.mapValue) {
198  entry.pushKV(item.first, item.second);
199  }
200 }
201 
202 static std::string LabelFromValue(const UniValue &value) {
203  std::string label = value.get_str();
204  if (label == "*") {
205  throw JSONRPCError(RPC_WALLET_INVALID_LABEL_NAME, "Invalid label name");
206  }
207  return label;
208 }
209 
210 static UniValue getnewaddress(const Config &config,
211  const JSONRPCRequest &request) {
212  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
213  CWallet *const pwallet = wallet.get();
214 
215  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
216  return NullUniValue;
217  }
218 
219  RPCHelpMan{
220  "getnewaddress",
221  "Returns a new Bitcoin address for receiving payments.\n"
222  "If 'label' is specified, it is added to the address book \n"
223  "so payments received with the address will be associated with "
224  "'label'.\n",
225  {
226  {"label", RPCArg::Type::STR, /* default */ "null",
227  "The label name for the address to be linked to. If not provided, "
228  "the default label \"\" is used. It can also be set to the empty "
229  "string \"\" to represent the default label. The label does not "
230  "need to exist, it will be created if there is no label by the "
231  "given name."},
232  {"address_type", RPCArg::Type::STR,
233  /* default */ "set by -addresstype",
234  "The address type to use. Options are \"legacy\"."},
235  },
236  RPCResult{RPCResult::Type::STR, "address", "The new bitcoin address"},
237  RPCExamples{HelpExampleCli("getnewaddress", "") +
238  HelpExampleRpc("getnewaddress", "")},
239  }
240  .Check(request);
241 
242  LOCK(pwallet->cs_wallet);
243 
244  if (!pwallet->CanGetAddresses()) {
246  "Error: This wallet has no available keys");
247  }
248 
249  // Parse the label first so we don't generate a key if there's an error
250  std::string label;
251  if (!request.params[0].isNull()) {
252  label = LabelFromValue(request.params[0]);
253  }
254 
255  OutputType output_type = pwallet->m_default_address_type;
256  if (!request.params[1].isNull()) {
257  if (!ParseOutputType(request.params[1].get_str(), output_type)) {
259  strprintf("Unknown address type '%s'",
260  request.params[1].get_str()));
261  }
262  }
263 
264  CTxDestination dest;
265  std::string error;
266  if (!pwallet->GetNewDestination(output_type, label, dest, error)) {
268  }
269 
270  return EncodeDestination(dest, config);
271 }
272 
273 static UniValue getrawchangeaddress(const Config &config,
274  const JSONRPCRequest &request) {
275  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
276  CWallet *const pwallet = wallet.get();
277 
278  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
279  return NullUniValue;
280  }
281 
282  RPCHelpMan{
283  "getrawchangeaddress",
284  "Returns a new Bitcoin address, for receiving change.\n"
285  "This is for use with raw transactions, NOT normal use.\n",
286  {},
287  RPCResult{RPCResult::Type::STR, "address", "The address"},
288  RPCExamples{HelpExampleCli("getrawchangeaddress", "") +
289  HelpExampleRpc("getrawchangeaddress", "")},
290  }
291  .Check(request);
292 
293  LOCK(pwallet->cs_wallet);
294 
295  if (!pwallet->CanGetAddresses(true)) {
297  "Error: This wallet has no available keys");
298  }
299 
300  OutputType output_type =
302  ? pwallet->m_default_change_type
303  : pwallet->m_default_address_type;
304  if (!request.params[0].isNull()) {
305  if (!ParseOutputType(request.params[0].get_str(), output_type)) {
307  strprintf("Unknown address type '%s'",
308  request.params[0].get_str()));
309  }
310  }
311 
312  CTxDestination dest;
313  std::string error;
314  if (!pwallet->GetNewChangeDestination(output_type, dest, error)) {
316  }
317  return EncodeDestination(dest, config);
318 }
319 
320 static UniValue setlabel(const Config &config, const JSONRPCRequest &request) {
321  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
322  CWallet *const pwallet = wallet.get();
323 
324  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
325  return NullUniValue;
326  }
327 
328  RPCHelpMan{
329  "setlabel",
330  "Sets the label associated with the given address.\n",
331  {
333  "The bitcoin address to be associated with a label."},
335  "The label to assign to the address."},
336  },
338  RPCExamples{
339  HelpExampleCli("setlabel",
340  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"tabby\"") +
342  "setlabel",
343  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"tabby\"")},
344  }
345  .Check(request);
346 
347  LOCK(pwallet->cs_wallet);
348 
349  CTxDestination dest = DecodeDestination(request.params[0].get_str(),
350  wallet->GetChainParams());
351  if (!IsValidDestination(dest)) {
353  "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 static CTransactionRef SendMoney(CWallet *const pwallet,
368  const CTxDestination &address, Amount nValue,
369  bool fSubtractFeeFromAmount,
370  const CCoinControl &coin_control,
371  mapValue_t mapValue) {
372  Amount curBalance =
373  pwallet->GetBalance(0, coin_control.m_avoid_address_reuse)
375 
376  // Check amount
377  if (nValue <= Amount::zero()) {
378  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid amount");
379  }
380 
381  if (nValue > curBalance) {
382  throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, "Insufficient funds");
383  }
384 
385  // Parse Bitcoin address
386  CScript scriptPubKey = GetScriptForDestination(address);
387 
388  // Create and send the transaction
389  Amount nFeeRequired = Amount::zero();
391  std::vector<CRecipient> vecSend;
392  int nChangePosRet = -1;
393  CRecipient recipient = {scriptPubKey, nValue, fSubtractFeeFromAmount};
394  vecSend.push_back(recipient);
395 
396  CTransactionRef tx;
397  if (!pwallet->CreateTransaction(vecSend, tx, nFeeRequired, nChangePosRet,
398  error, coin_control)) {
399  if (!fSubtractFeeFromAmount && nValue + nFeeRequired > curBalance) {
400  error = strprintf(Untranslated("Error: This transaction requires a "
401  "transaction fee of at least %s"),
402  FormatMoney(nFeeRequired));
403  }
404  throw JSONRPCError(RPC_WALLET_ERROR, error.original);
405  }
406  pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
407  return tx;
408 }
409 
410 static UniValue sendtoaddress(const Config &config,
411  const JSONRPCRequest &request) {
412  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
413  CWallet *const pwallet = wallet.get();
414 
415  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
416  return NullUniValue;
417  }
418 
419  RPCHelpMan{
420  "sendtoaddress",
421  "Send an amount to a given address.\n" + HELP_REQUIRING_PASSPHRASE,
422  {
424  "The bitcoin address to send to."},
426  "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
428  "A comment used to store what the transaction is for.\n"
429  " This is not part of the "
430  "transaction, just kept in your wallet."},
431  {"comment_to", RPCArg::Type::STR,
433  "A comment to store the name of the person or organization\n"
434  " to which you're sending the "
435  "transaction. This is not part of the \n"
436  " transaction, just kept in "
437  "your wallet."},
438  {"subtractfeefromamount", RPCArg::Type::BOOL,
439  /* default */ "false",
440  "The fee will be deducted from the amount being sent.\n"
441  " The recipient will receive "
442  "less bitcoins than you enter in the amount field."},
443  {"avoid_reuse", RPCArg::Type::BOOL,
444  /* default */ "true",
445  "(only available if avoid_reuse wallet flag is set) Avoid "
446  "spending from dirty addresses; addresses are considered\n"
447  " dirty if they have previously "
448  "been used in a transaction."},
449  },
450  RPCResult{RPCResult::Type::STR_HEX, "txid", "The transaction id."},
451  RPCExamples{
452  HelpExampleCli("sendtoaddress",
453  "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 0.1") +
454  HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvay"
455  "dd\" 0.1 \"donation\" \"seans "
456  "outpost\"") +
457  HelpExampleCli("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44"
458  "Jvaydd\" 0.1 \"\" \"\" true") +
459  HelpExampleRpc("sendtoaddress", "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvay"
460  "dd\", 0.1, \"donation\", \"seans "
461  "outpost\"")},
462  }
463  .Check(request);
464 
465  // Make sure the results are valid at least up to the most recent block
466  // the user could have gotten from another RPC command prior to now
468 
469  LOCK(pwallet->cs_wallet);
470 
471  CTxDestination dest = DecodeDestination(request.params[0].get_str(),
472  wallet->GetChainParams());
473  if (!IsValidDestination(dest)) {
474  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
475  }
476 
477  // Amount
478  Amount nAmount = AmountFromValue(request.params[1]);
479  if (nAmount <= Amount::zero()) {
480  throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
481  }
482 
483  // Wallet comments
484  mapValue_t mapValue;
485  if (!request.params[2].isNull() && !request.params[2].get_str().empty()) {
486  mapValue["comment"] = request.params[2].get_str();
487  }
488  if (!request.params[3].isNull() && !request.params[3].get_str().empty()) {
489  mapValue["to"] = request.params[3].get_str();
490  }
491 
492  bool fSubtractFeeFromAmount = false;
493  if (!request.params[4].isNull()) {
494  fSubtractFeeFromAmount = request.params[4].get_bool();
495  }
496 
497  CCoinControl coin_control;
498  coin_control.m_avoid_address_reuse =
499  GetAvoidReuseFlag(pwallet, request.params[5]);
500  // We also enable partial spend avoidance if reuse avoidance is set.
501  coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
502 
503  EnsureWalletIsUnlocked(pwallet);
504 
505  CTransactionRef tx =
506  SendMoney(pwallet, dest, nAmount, fSubtractFeeFromAmount, coin_control,
507  std::move(mapValue));
508  return tx->GetId().GetHex();
509 }
510 
511 static UniValue listaddressgroupings(const Config &config,
512  const JSONRPCRequest &request) {
513  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
514  const CWallet *const pwallet = wallet.get();
515 
516  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
517  return NullUniValue;
518  }
519 
520  RPCHelpMan{
521  "listaddressgroupings",
522  "Lists groups of addresses which have had their common ownership\n"
523  "made public by common use as inputs or as the resulting change\n"
524  "in past transactions\n",
525  {},
527  "",
528  "",
529  {
531  "",
532  "",
533  {
535  "",
536  "",
537  {
538  {RPCResult::Type::STR, "address",
539  "The bitcoin address"},
540  {RPCResult::Type::STR_AMOUNT, "amount",
541  "The amount in " + CURRENCY_UNIT},
542  {RPCResult::Type::STR, "label",
543  /* optional */ true, "The label"},
544  }},
545  }},
546  }},
547  RPCExamples{HelpExampleCli("listaddressgroupings", "") +
548  HelpExampleRpc("listaddressgroupings", "")},
549  }
550  .Check(request);
551 
552  // Make sure the results are valid at least up to the most recent block
553  // the user could have gotten from another RPC command prior to now
555 
556  LOCK(pwallet->cs_wallet);
557 
558  UniValue jsonGroupings(UniValue::VARR);
559  std::map<CTxDestination, Amount> balances = pwallet->GetAddressBalances();
560  for (const std::set<CTxDestination> &grouping :
561  pwallet->GetAddressGroupings()) {
562  UniValue jsonGrouping(UniValue::VARR);
563  for (const CTxDestination &address : grouping) {
564  UniValue addressInfo(UniValue::VARR);
565  addressInfo.push_back(EncodeDestination(address, config));
566  addressInfo.push_back(ValueFromAmount(balances[address]));
567 
568  const auto *address_book_entry =
569  pwallet->FindAddressBookEntry(address);
570  if (address_book_entry) {
571  addressInfo.push_back(address_book_entry->GetLabel());
572  }
573  jsonGrouping.push_back(addressInfo);
574  }
575  jsonGroupings.push_back(jsonGrouping);
576  }
577 
578  return jsonGroupings;
579 }
580 
581 static UniValue signmessage(const Config &config,
582  const JSONRPCRequest &request) {
583  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
584  const CWallet *const pwallet = wallet.get();
585 
586  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
587  return NullUniValue;
588  }
589 
590  RPCHelpMan{
591  "signmessage",
592  "Sign a message with the private key of an address" +
594  {
596  "The bitcoin address to use for the private key."},
598  "The message to create a signature of."},
599  },
600  RPCResult{RPCResult::Type::STR, "signature",
601  "The signature of the message encoded in base 64"},
602  RPCExamples{
603  "\nUnlock the wallet for 30 seconds\n" +
604  HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
605  "\nCreate the signature\n" +
607  "signmessage",
608  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
609  "\nVerify the signature\n" +
610  HelpExampleCli("verifymessage",
611  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" "
612  "\"signature\" \"my message\"") +
613  "\nAs a JSON-RPC call\n" +
615  "signmessage",
616  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"my message\"")},
617  }
618  .Check(request);
619 
620  LOCK(pwallet->cs_wallet);
621 
622  EnsureWalletIsUnlocked(pwallet);
623 
624  std::string strAddress = request.params[0].get_str();
625  std::string strMessage = request.params[1].get_str();
626 
627  CTxDestination dest =
628  DecodeDestination(strAddress, wallet->GetChainParams());
629  if (!IsValidDestination(dest)) {
630  throw JSONRPCError(RPC_TYPE_ERROR, "Invalid address");
631  }
632 
633  const PKHash *pkhash = boost::get<PKHash>(&dest);
634  if (!pkhash) {
635  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to key");
636  }
637 
638  std::string signature;
639  SigningResult err = pwallet->SignMessage(strMessage, *pkhash, signature);
640  if (err == SigningResult::SIGNING_FAILED) {
642  SigningResultString(err));
643  } else if (err != SigningResult::OK) {
645  }
646 
647  return signature;
648 }
649 
650 static Amount GetReceived(const CWallet &wallet, const UniValue &params,
651  bool by_label)
652  EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet) {
653  std::set<CTxDestination> address_set;
654 
655  if (by_label) {
656  // Get the set of addresses assigned to label
657  std::string label = LabelFromValue(params[0]);
658  address_set = wallet.GetLabelAddresses(label);
659  } else {
660  // Get the address
661  CTxDestination dest =
662  DecodeDestination(params[0].get_str(), wallet.GetChainParams());
663  if (!IsValidDestination(dest)) {
665  "Invalid Bitcoin address");
666  }
667  CScript script_pub_key = GetScriptForDestination(dest);
668  if (!wallet.IsMine(script_pub_key)) {
669  throw JSONRPCError(RPC_WALLET_ERROR, "Address not found in wallet");
670  }
671  address_set.insert(dest);
672  }
673 
674  // Minimum confirmations
675  int min_depth = 1;
676  if (!params[1].isNull()) {
677  min_depth = params[1].get_int();
678  }
679 
680  // Tally
681  Amount amount = Amount::zero();
682  for (const std::pair<const TxId, CWalletTx> &wtx_pair : wallet.mapWallet) {
683  const CWalletTx &wtx = wtx_pair.second;
684  TxValidationState txState;
685  if (wtx.IsCoinBase() ||
686  !wallet.chain().contextualCheckTransactionForCurrentBlock(
687  *wtx.tx, txState) ||
688  wtx.GetDepthInMainChain() < min_depth) {
689  continue;
690  }
691 
692  for (const CTxOut &txout : wtx.tx->vout) {
693  CTxDestination address;
694  if (ExtractDestination(txout.scriptPubKey, address) &&
695  wallet.IsMine(address) && address_set.count(address)) {
696  amount += txout.nValue;
697  }
698  }
699  }
700 
701  return amount;
702 }
703 
704 static UniValue getreceivedbyaddress(const Config &config,
705  const JSONRPCRequest &request) {
706  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
707  const CWallet *const pwallet = wallet.get();
708 
709  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
710  return NullUniValue;
711  }
712 
713  RPCHelpMan{
714  "getreceivedbyaddress",
715  "Returns the total amount received by the given address in "
716  "transactions with at least minconf confirmations.\n",
717  {
719  "The bitcoin address for transactions."},
720  {"minconf", RPCArg::Type::NUM, /* default */ "1",
721  "Only include transactions confirmed at least this many times."},
722  },
724  "The total amount in " + CURRENCY_UNIT +
725  " received at this address."},
726  RPCExamples{
727  "\nThe amount from transactions with at least 1 confirmation\n" +
728  HelpExampleCli("getreceivedbyaddress",
729  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\"") +
730  "\nThe amount including unconfirmed transactions, zero "
731  "confirmations\n" +
732  HelpExampleCli("getreceivedbyaddress",
733  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 0") +
734  "\nThe amount with at least 6 confirmations\n" +
735  HelpExampleCli("getreceivedbyaddress",
736  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" 6") +
737  "\nAs a JSON-RPC call\n" +
738  HelpExampleRpc("getreceivedbyaddress",
739  "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", 6")},
740  }
741  .Check(request);
742 
743  // Make sure the results are valid at least up to the most recent block
744  // the user could have gotten from another RPC command prior to now
746 
747  LOCK(pwallet->cs_wallet);
748 
749  return ValueFromAmount(GetReceived(*pwallet, request.params,
750  /* by_label */ false));
751 }
752 
753 static UniValue getreceivedbylabel(const Config &config,
754  const JSONRPCRequest &request) {
755  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
756  CWallet *const pwallet = wallet.get();
757 
758  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
759  return NullUniValue;
760  }
761 
762  RPCHelpMan{
763  "getreceivedbylabel",
764  "Returns the total amount received by addresses with <label> in "
765  "transactions with at least [minconf] confirmations.\n",
766  {
768  "The selected label, may be the default label using \"\"."},
769  {"minconf", RPCArg::Type::NUM, /* default */ "1",
770  "Only include transactions confirmed at least this many times."},
771  },
773  "The total amount in " + CURRENCY_UNIT +
774  " received for this label."},
775  RPCExamples{"\nAmount received by the default label with at least 1 "
776  "confirmation\n" +
777  HelpExampleCli("getreceivedbylabel", "\"\"") +
778  "\nAmount received at the tabby label including "
779  "unconfirmed amounts with zero confirmations\n" +
780  HelpExampleCli("getreceivedbylabel", "\"tabby\" 0") +
781  "\nThe amount with at least 6 confirmations\n" +
782  HelpExampleCli("getreceivedbylabel", "\"tabby\" 6") +
783  "\nAs a JSON-RPC call\n" +
784  HelpExampleRpc("getreceivedbylabel", "\"tabby\", 6")},
785  }
786  .Check(request);
787 
788  // Make sure the results are valid at least up to the most recent block
789  // the user could have gotten from another RPC command prior to now
791 
792  LOCK(pwallet->cs_wallet);
793 
794  return ValueFromAmount(GetReceived(*pwallet, request.params,
795  /* by_label */ true));
796 }
797 
798 static UniValue getbalance(const Config &config,
799  const JSONRPCRequest &request) {
800  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
801  const CWallet *const pwallet = wallet.get();
802 
803  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
804  return NullUniValue;
805  }
806 
807  RPCHelpMan{
808  "getbalance",
809  "Returns the total available balance.\n"
810  "The available balance is what the wallet considers currently "
811  "spendable, and is\n"
812  "thus affected by options which limit spendability such as "
813  "-spendzeroconfchange.\n",
814  {
816  "Remains for backward compatibility. Must be excluded or set to "
817  "\"*\"."},
818  {"minconf", RPCArg::Type::NUM, /* default */ "0",
819  "Only include transactions confirmed at least this many times."},
820  {"include_watchonly", RPCArg::Type::BOOL,
821  /* default */ "true for watch-only wallets, otherwise false",
822  "Also include balance in watch-only addresses (see "
823  "'importaddress')"},
824  {"avoid_reuse", RPCArg::Type::BOOL,
825  /* default */ "true",
826  "(only available if avoid_reuse wallet flag is set) Do not "
827  "include balance in dirty outputs; addresses are considered dirty "
828  "if they have previously been used in a transaction."},
829  },
831  "The total amount in " + CURRENCY_UNIT +
832  " received for this wallet."},
833  RPCExamples{
834  "\nThe total amount in the wallet with 0 or more confirmations\n" +
835  HelpExampleCli("getbalance", "") +
836  "\nThe total amount in the wallet with at least 6 confirmations\n" +
837  HelpExampleCli("getbalance", "\"*\" 6") + "\nAs a JSON-RPC call\n" +
838  HelpExampleRpc("getbalance", "\"*\", 6")},
839  }
840  .Check(request);
841 
842  // Make sure the results are valid at least up to the most recent block
843  // the user could have gotten from another RPC command prior to now
845 
846  LOCK(pwallet->cs_wallet);
847 
848  const UniValue &dummy_value = request.params[0];
849  if (!dummy_value.isNull() && dummy_value.get_str() != "*") {
850  throw JSONRPCError(
852  "dummy first argument must be excluded or set to \"*\".");
853  }
854 
855  int min_depth = 0;
856  if (!request.params[1].isNull()) {
857  min_depth = request.params[1].get_int();
858  }
859 
860  bool include_watchonly = ParseIncludeWatchonly(request.params[2], *pwallet);
861 
862  bool avoid_reuse = GetAvoidReuseFlag(pwallet, request.params[3]);
863 
864  const auto bal = pwallet->GetBalance(min_depth, avoid_reuse);
865 
866  return ValueFromAmount(bal.m_mine_trusted + (include_watchonly
867  ? bal.m_watchonly_trusted
868  : Amount::zero()));
869 }
870 
871 static UniValue getunconfirmedbalance(const Config &config,
872  const JSONRPCRequest &request) {
873  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
874  const CWallet *const pwallet = wallet.get();
875 
876  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
877  return NullUniValue;
878  }
879 
880  RPCHelpMan{
881  "getunconfirmedbalance",
882  "DEPRECATED\nIdentical to getbalances().mine.untrusted_pending\n",
883  {},
884  RPCResult{RPCResult::Type::NUM, "", "The balance"},
885  RPCExamples{""},
886  }
887  .Check(request);
888 
889  // Make sure the results are valid at least up to the most recent block
890  // the user could have gotten from another RPC command prior to now
892 
893  LOCK(pwallet->cs_wallet);
894 
896 }
897 
898 static UniValue sendmany(const Config &config, const JSONRPCRequest &request) {
899  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
900  CWallet *const pwallet = wallet.get();
901 
902  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
903  return NullUniValue;
904  }
905 
906  RPCHelpMan{
907  "sendmany",
908  "Send multiple times. Amounts are double-precision "
909  "floating point numbers." +
911  {
913  "Must be set to \"\" for backwards compatibility.", "\"\""},
914  {
915  "amounts",
918  "The addresses and amounts",
919  {
921  "The bitcoin address is the key, the numeric amount (can "
922  "be string) in " +
923  CURRENCY_UNIT + " is the value"},
924  },
925  },
926  {"minconf", RPCArg::Type::NUM, /* default */ "1",
927  "Only use the balance confirmed at least this many times."},
929  "A comment"},
930  {
931  "subtractfeefrom",
934  "The addresses.\n"
935  " The fee will be equally deducted "
936  "from the amount of each selected address.\n"
937  " Those recipients will receive less "
938  "bitcoins than you enter in their corresponding amount field.\n"
939  " If no addresses are specified "
940  "here, the sender pays the fee.",
941  {
943  "Subtract fee from this address"},
944  },
945  },
946  },
948  "The transaction id for the send. Only 1 transaction is "
949  "created regardless of the number of addresses."},
950  RPCExamples{
951  "\nSend two amounts to two different addresses:\n" +
953  "sendmany",
954  "\"\" "
955  "\"{\\\"bchtest:qplljx455cznj2yrtdhj0jcm7syxlzqnaqt0ku5kjl\\\":"
956  "0.01,"
957  "\\\"bchtest:qzmnuh8t24yrxq4mvjakt84r7j3f9tunlvm2p7qef9\\\":0."
958  "02}\"") +
959  "\nSend two amounts to two different addresses setting the "
960  "confirmation and comment:\n" +
962  "sendmany",
963  "\"\" "
964  "\"{\\\"bchtest:qplljx455cznj2yrtdhj0jcm7syxlzqnaqt0ku5kjl\\\":"
965  "0.01,"
966  "\\\"bchtest:qzmnuh8t24yrxq4mvjakt84r7j3f9tunlvm2p7qef9\\\":0."
967  "02}\" "
968  "6 \"testing\"") +
969  "\nSend two amounts to two different addresses, subtract fee "
970  "from amount:\n" +
972  "sendmany",
973  "\"\" "
974  "\"{\\\"bchtest:qplljx455cznj2yrtdhj0jcm7syxlzqnaqt0ku5kjl\\\":"
975  "0.01,"
976  "\\\"bchtest:qzmnuh8t24yrxq4mvjakt84r7j3f9tunlvm2p7qef9\\\":0."
977  "02}\" 1 \"\" "
978  "\"[\\\"bchtest:qplljx455cznj2yrtdhj0jcm7syxlzqnaqt0ku5kjl\\\","
979  "\\\"bchtest:qzmnuh8t24yrxq4mvjakt84r7j3f9tunlvm2p7qef9\\\"]"
980  "\"") +
981  "\nAs a JSON-RPC call\n" +
983  "sendmany",
984  "\"\", "
985  "{\"bchtest:qplljx455cznj2yrtdhj0jcm7syxlzqnaqt0ku5kjl\":0.01,"
986  "\"bchtest:qzmnuh8t24yrxq4mvjakt84r7j3f9tunlvm2p7qef9\":0.02}, "
987  "6, "
988  "\"testing\"")},
989  }
990  .Check(request);
991 
992  // Make sure the results are valid at least up to the most recent block
993  // the user could have gotten from another RPC command prior to now
995 
996  LOCK(pwallet->cs_wallet);
997 
998  if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
1000  "Dummy value must be set to \"\"");
1001  }
1002  UniValue sendTo = request.params[1].get_obj();
1003 
1004  mapValue_t mapValue;
1005  if (!request.params[3].isNull() && !request.params[3].get_str().empty()) {
1006  mapValue["comment"] = request.params[3].get_str();
1007  }
1008 
1009  UniValue subtractFeeFromAmount(UniValue::VARR);
1010  if (!request.params[4].isNull()) {
1011  subtractFeeFromAmount = request.params[4].get_array();
1012  }
1013 
1014  std::set<CTxDestination> destinations;
1015  std::vector<CRecipient> vecSend;
1016 
1017  std::vector<std::string> keys = sendTo.getKeys();
1018  for (const std::string &name_ : keys) {
1019  CTxDestination dest =
1020  DecodeDestination(name_, wallet->GetChainParams());
1021  if (!IsValidDestination(dest)) {
1023  std::string("Invalid Bitcoin address: ") +
1024  name_);
1025  }
1026 
1027  if (destinations.count(dest)) {
1028  throw JSONRPCError(
1030  std::string("Invalid parameter, duplicated address: ") + name_);
1031  }
1032  destinations.insert(dest);
1033 
1034  CScript scriptPubKey = GetScriptForDestination(dest);
1035  Amount nAmount = AmountFromValue(sendTo[name_]);
1036  if (nAmount <= Amount::zero()) {
1037  throw JSONRPCError(RPC_TYPE_ERROR, "Invalid amount for send");
1038  }
1039 
1040  bool fSubtractFeeFromAmount = false;
1041  for (size_t idx = 0; idx < subtractFeeFromAmount.size(); idx++) {
1042  const UniValue &addr = subtractFeeFromAmount[idx];
1043  if (addr.get_str() == name_) {
1044  fSubtractFeeFromAmount = true;
1045  }
1046  }
1047 
1048  CRecipient recipient = {scriptPubKey, nAmount, fSubtractFeeFromAmount};
1049  vecSend.push_back(recipient);
1050  }
1051 
1052  EnsureWalletIsUnlocked(pwallet);
1053 
1054  // Shuffle recipient list
1055  std::shuffle(vecSend.begin(), vecSend.end(), FastRandomContext());
1056 
1057  // Send
1058  Amount nFeeRequired = Amount::zero();
1059  int nChangePosRet = -1;
1061  CTransactionRef tx;
1062  CCoinControl coinControl;
1063  bool fCreated = pwallet->CreateTransaction(
1064  vecSend, tx, nFeeRequired, nChangePosRet, error, coinControl);
1065  if (!fCreated) {
1067  }
1068  pwallet->CommitTransaction(tx, std::move(mapValue), {} /* orderForm */);
1069  return tx->GetId().GetHex();
1070 }
1071 
1072 static UniValue addmultisigaddress(const Config &config,
1073  const JSONRPCRequest &request) {
1074  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1075  CWallet *const pwallet = wallet.get();
1076 
1077  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1078  return NullUniValue;
1079  }
1080 
1081  RPCHelpMan{
1082  "addmultisigaddress",
1083  "Add an nrequired-to-sign multisignature address to the wallet. "
1084  "Requires a new wallet backup.\n"
1085  "Each key is a Bitcoin address or hex-encoded public key.\n"
1086  "This functionality is only intended for use with non-watchonly "
1087  "addresses.\n"
1088  "See `importaddress` for watchonly p2sh address support.\n"
1089  "If 'label' is specified (DEPRECATED), assign address to that label.\n",
1090  {
1091  {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO,
1092  "The number of required signatures out of the n keys or "
1093  "addresses."},
1094  {
1095  "keys",
1098  "The bitcoin addresses or hex-encoded public keys",
1099  {
1101  "bitcoin address or hex-encoded public key"},
1102  },
1103  },
1105  "A label to assign the addresses to."},
1106  },
1108  "",
1109  "",
1110  {
1111  {RPCResult::Type::STR, "address",
1112  "The value of the new multisig address"},
1113  {RPCResult::Type::STR_HEX, "redeemScript",
1114  "The string value of the hex-encoded redemption script"},
1115  {RPCResult::Type::STR, "descriptor",
1116  "The descriptor for this multisig"},
1117  }},
1118  RPCExamples{
1119  "\nAdd a multisig address from 2 addresses\n" +
1120  HelpExampleCli("addmultisigaddress",
1121  "2 "
1122  "\"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\","
1123  "\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"") +
1124  "\nAs a JSON-RPC call\n" +
1125  HelpExampleRpc("addmultisigaddress",
1126  "2, "
1127  "\"[\\\"16sSauSf5pF2UkUwvKGq4qjNRzBZYqgEL5\\\","
1128  "\\\"171sgjn4YtPu27adkKGrdDwzRTxnRkBfKV\\\"]\"")},
1129  }
1130  .Check(request);
1131 
1133 
1134  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
1135 
1136  std::string label;
1137  if (!request.params[2].isNull()) {
1138  label = LabelFromValue(request.params[2]);
1139  }
1140 
1141  int required = request.params[0].get_int();
1142 
1143  // Get the public keys
1144  const UniValue &keys_or_addrs = request.params[1].get_array();
1145  std::vector<CPubKey> pubkeys;
1146  for (size_t i = 0; i < keys_or_addrs.size(); ++i) {
1147  if (IsHex(keys_or_addrs[i].get_str()) &&
1148  (keys_or_addrs[i].get_str().length() == 66 ||
1149  keys_or_addrs[i].get_str().length() == 130)) {
1150  pubkeys.push_back(HexToPubKey(keys_or_addrs[i].get_str()));
1151  } else {
1152  pubkeys.push_back(AddrToPubKey(wallet->GetChainParams(), spk_man,
1153  keys_or_addrs[i].get_str()));
1154  }
1155  }
1156 
1157  OutputType output_type = pwallet->m_default_address_type;
1158 
1159  // Construct using pay-to-script-hash:
1160  CScript inner;
1162  required, pubkeys, output_type, spk_man, inner);
1163  pwallet->SetAddressBook(dest, label, "send");
1164 
1165  // Make the descriptor
1166  std::unique_ptr<Descriptor> descriptor =
1167  InferDescriptor(GetScriptForDestination(dest), spk_man);
1168 
1169  UniValue result(UniValue::VOBJ);
1170  result.pushKV("address", EncodeDestination(dest, config));
1171  result.pushKV("redeemScript", HexStr(inner.begin(), inner.end()));
1172  result.pushKV("descriptor", descriptor->ToString());
1173  return result;
1174 }
1175 
1176 struct tallyitem {
1178  int nConf{std::numeric_limits<int>::max()};
1179  std::vector<uint256> txids;
1180  bool fIsWatchonly{false};
1182 };
1183 
1184 static UniValue ListReceived(const Config &config, const CWallet *const pwallet,
1185  const UniValue &params, bool by_label)
1186  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1187  // Minimum confirmations
1188  int nMinDepth = 1;
1189  if (!params[0].isNull()) {
1190  nMinDepth = params[0].get_int();
1191  }
1192 
1193  // Whether to include empty labels
1194  bool fIncludeEmpty = false;
1195  if (!params[1].isNull()) {
1196  fIncludeEmpty = params[1].get_bool();
1197  }
1198 
1199  isminefilter filter = ISMINE_SPENDABLE;
1200  if (ParseIncludeWatchonly(params[2], *pwallet)) {
1201  filter |= ISMINE_WATCH_ONLY;
1202  }
1203 
1204  bool has_filtered_address = false;
1205  CTxDestination filtered_address = CNoDestination();
1206  if (!by_label && params.size() > 3) {
1207  if (!IsValidDestinationString(params[3].get_str(),
1208  pwallet->GetChainParams())) {
1210  "address_filter parameter was invalid");
1211  }
1212  filtered_address =
1213  DecodeDestination(params[3].get_str(), pwallet->GetChainParams());
1214  has_filtered_address = true;
1215  }
1216 
1217  // Tally
1218  std::map<CTxDestination, tallyitem> mapTally;
1219  for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) {
1220  const CWalletTx &wtx = pairWtx.second;
1221 
1222  TxValidationState state;
1223  if (wtx.IsCoinBase() ||
1224  !pwallet->chain().contextualCheckTransactionForCurrentBlock(
1225  *wtx.tx, state)) {
1226  continue;
1227  }
1228 
1229  int nDepth = wtx.GetDepthInMainChain();
1230  if (nDepth < nMinDepth) {
1231  continue;
1232  }
1233 
1234  for (const CTxOut &txout : wtx.tx->vout) {
1235  CTxDestination address;
1236  if (!ExtractDestination(txout.scriptPubKey, address)) {
1237  continue;
1238  }
1239 
1240  if (has_filtered_address && !(filtered_address == address)) {
1241  continue;
1242  }
1243 
1244  isminefilter mine = pwallet->IsMine(address);
1245  if (!(mine & filter)) {
1246  continue;
1247  }
1248 
1249  tallyitem &item = mapTally[address];
1250  item.nAmount += txout.nValue;
1251  item.nConf = std::min(item.nConf, nDepth);
1252  item.txids.push_back(wtx.GetId());
1253  if (mine & ISMINE_WATCH_ONLY) {
1254  item.fIsWatchonly = true;
1255  }
1256  }
1257  }
1258 
1259  // Reply
1260  UniValue ret(UniValue::VARR);
1261  std::map<std::string, tallyitem> label_tally;
1262 
1263  // Create m_address_book iterator
1264  // If we aren't filtering, go from begin() to end()
1265  auto start = pwallet->m_address_book.begin();
1266  auto end = pwallet->m_address_book.end();
1267  // If we are filtering, find() the applicable entry
1268  if (has_filtered_address) {
1269  start = pwallet->m_address_book.find(filtered_address);
1270  if (start != end) {
1271  end = std::next(start);
1272  }
1273  }
1274 
1275  for (auto item_it = start; item_it != end; ++item_it) {
1276  if (item_it->second.IsChange()) {
1277  continue;
1278  }
1279  const CTxDestination &address = item_it->first;
1280  const std::string &label = item_it->second.GetLabel();
1281  std::map<CTxDestination, tallyitem>::iterator it =
1282  mapTally.find(address);
1283  if (it == mapTally.end() && !fIncludeEmpty) {
1284  continue;
1285  }
1286 
1288  int nConf = std::numeric_limits<int>::max();
1289  bool fIsWatchonly = false;
1290  if (it != mapTally.end()) {
1291  nAmount = (*it).second.nAmount;
1292  nConf = (*it).second.nConf;
1293  fIsWatchonly = (*it).second.fIsWatchonly;
1294  }
1295 
1296  if (by_label) {
1297  tallyitem &_item = label_tally[label];
1298  _item.nAmount += nAmount;
1299  _item.nConf = std::min(_item.nConf, nConf);
1300  _item.fIsWatchonly = fIsWatchonly;
1301  } else {
1302  UniValue obj(UniValue::VOBJ);
1303  if (fIsWatchonly) {
1304  obj.pushKV("involvesWatchonly", true);
1305  }
1306  obj.pushKV("address", EncodeDestination(address, config));
1307  obj.pushKV("amount", ValueFromAmount(nAmount));
1308  obj.pushKV("confirmations",
1309  (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
1310  obj.pushKV("label", label);
1311  UniValue transactions(UniValue::VARR);
1312  if (it != mapTally.end()) {
1313  for (const uint256 &_item : (*it).second.txids) {
1314  transactions.push_back(_item.GetHex());
1315  }
1316  }
1317  obj.pushKV("txids", transactions);
1318  ret.push_back(obj);
1319  }
1320  }
1321 
1322  if (by_label) {
1323  for (const auto &entry : label_tally) {
1324  Amount nAmount = entry.second.nAmount;
1325  int nConf = entry.second.nConf;
1326  UniValue obj(UniValue::VOBJ);
1327  if (entry.second.fIsWatchonly) {
1328  obj.pushKV("involvesWatchonly", true);
1329  }
1330  obj.pushKV("amount", ValueFromAmount(nAmount));
1331  obj.pushKV("confirmations",
1332  (nConf == std::numeric_limits<int>::max() ? 0 : nConf));
1333  obj.pushKV("label", entry.first);
1334  ret.push_back(obj);
1335  }
1336  }
1337 
1338  return ret;
1339 }
1340 
1342  const JSONRPCRequest &request) {
1343  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1344  const CWallet *const pwallet = wallet.get();
1345 
1346  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1347  return NullUniValue;
1348  }
1349 
1350  RPCHelpMan{
1351  "listreceivedbyaddress",
1352  "List balances by receiving address.\n",
1353  {
1354  {"minconf", RPCArg::Type::NUM, /* default */ "1",
1355  "The minimum number of confirmations before payments are "
1356  "included."},
1357  {"include_empty", RPCArg::Type::BOOL, /* default */ "false",
1358  "Whether to include addresses that haven't received any "
1359  "payments."},
1360  {"include_watchonly", RPCArg::Type::BOOL,
1361  /* default */ "true for watch-only wallets, otherwise false",
1362  "Whether to include watch-only addresses (see 'importaddress')."},
1363  {"address_filter", RPCArg::Type::STR,
1365  "If present, only return information on this address."},
1366  },
1367  RPCResult{
1369  "",
1370  "",
1371  {
1373  "",
1374  "",
1375  {
1376  {RPCResult::Type::BOOL, "involvesWatchonly",
1377  "Only returns true if imported addresses were involved "
1378  "in transaction"},
1379  {RPCResult::Type::STR, "address", "The receiving address"},
1380  {RPCResult::Type::STR_AMOUNT, "amount",
1381  "The total amount in " + CURRENCY_UNIT +
1382  " received by the address"},
1383  {RPCResult::Type::NUM, "confirmations",
1384  "The number of confirmations of the most recent "
1385  "transaction included"},
1386  {RPCResult::Type::STR, "label",
1387  "The label of the receiving address. The default label "
1388  "is \"\""},
1390  "txids",
1391  "",
1392  {
1393  {RPCResult::Type::STR_HEX, "txid",
1394  "The ids of transactions received with the address"},
1395  }},
1396  }},
1397  }},
1398  RPCExamples{
1399  HelpExampleCli("listreceivedbyaddress", "") +
1400  HelpExampleCli("listreceivedbyaddress", "6 true") +
1401  HelpExampleRpc("listreceivedbyaddress", "6, true, true") +
1403  "listreceivedbyaddress",
1404  "6, true, true, \"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\"")},
1405  }
1406  .Check(request);
1407 
1408  // Make sure the results are valid at least up to the most recent block
1409  // the user could have gotten from another RPC command prior to now
1410  pwallet->BlockUntilSyncedToCurrentChain();
1411 
1412  LOCK(pwallet->cs_wallet);
1413 
1414  return ListReceived(config, pwallet, request.params, false);
1415 }
1416 
1417 static UniValue listreceivedbylabel(const Config &config,
1418  const JSONRPCRequest &request) {
1419  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1420  const CWallet *const pwallet = wallet.get();
1421 
1422  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1423  return NullUniValue;
1424  }
1425 
1426  RPCHelpMan{
1427  "listreceivedbylabel",
1428  "List received transactions by label.\n",
1429  {
1430  {"minconf", RPCArg::Type::NUM, /* default */ "1",
1431  "The minimum number of confirmations before payments are "
1432  "included."},
1433  {"include_empty", RPCArg::Type::BOOL, /* default */ "false",
1434  "Whether to include labels that haven't received any payments."},
1435  {"include_watchonly", RPCArg::Type::BOOL,
1436  /* default */ "true for watch-only wallets, otherwise false",
1437  "Whether to include watch-only addresses (see 'importaddress')."},
1438  },
1439  RPCResult{
1441  "",
1442  "",
1443  {
1445  "",
1446  "",
1447  {
1448  {RPCResult::Type::BOOL, "involvesWatchonly",
1449  "Only returns true if imported addresses were involved "
1450  "in transaction"},
1451  {RPCResult::Type::STR_AMOUNT, "amount",
1452  "The total amount received by addresses with this label"},
1453  {RPCResult::Type::NUM, "confirmations",
1454  "The number of confirmations of the most recent "
1455  "transaction included"},
1456  {RPCResult::Type::STR, "label",
1457  "The label of the receiving address. The default label "
1458  "is \"\""},
1459  }},
1460  }},
1461  RPCExamples{HelpExampleCli("listreceivedbylabel", "") +
1462  HelpExampleCli("listreceivedbylabel", "6 true") +
1463  HelpExampleRpc("listreceivedbylabel", "6, true, true")},
1464  }
1465  .Check(request);
1466 
1467  // Make sure the results are valid at least up to the most recent block
1468  // the user could have gotten from another RPC command prior to now
1469  pwallet->BlockUntilSyncedToCurrentChain();
1470 
1471  LOCK(pwallet->cs_wallet);
1472 
1473  return ListReceived(config, pwallet, request.params, true);
1474 }
1475 
1476 static void MaybePushAddress(UniValue &entry, const CTxDestination &dest) {
1477  if (IsValidDestination(dest)) {
1478  entry.pushKV("address", EncodeDestination(dest, GetConfig()));
1479  }
1480 }
1481 
1494 static void ListTransactions(const CWallet *const pwallet, const CWalletTx &wtx,
1495  int nMinDepth, bool fLong, UniValue &ret,
1496  const isminefilter &filter_ismine,
1497  const std::string *filter_label)
1498  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1499  Amount nFee;
1500  std::list<COutputEntry> listReceived;
1501  std::list<COutputEntry> listSent;
1502 
1503  wtx.GetAmounts(listReceived, listSent, nFee, filter_ismine);
1504 
1505  bool involvesWatchonly = wtx.IsFromMe(ISMINE_WATCH_ONLY);
1506 
1507  // Sent
1508  if (!filter_label) {
1509  for (const COutputEntry &s : listSent) {
1510  UniValue entry(UniValue::VOBJ);
1511  if (involvesWatchonly ||
1512  (pwallet->IsMine(s.destination) & ISMINE_WATCH_ONLY)) {
1513  entry.pushKV("involvesWatchonly", true);
1514  }
1515  MaybePushAddress(entry, s.destination);
1516  entry.pushKV("category", "send");
1517  entry.pushKV("amount", ValueFromAmount(-s.amount));
1518  const auto *address_book_entry =
1519  pwallet->FindAddressBookEntry(s.destination);
1520  if (address_book_entry) {
1521  entry.pushKV("label", address_book_entry->GetLabel());
1522  }
1523  entry.pushKV("vout", s.vout);
1524  entry.pushKV("fee", ValueFromAmount(-1 * nFee));
1525  if (fLong) {
1526  WalletTxToJSON(pwallet->chain(), wtx, entry);
1527  }
1528  entry.pushKV("abandoned", wtx.isAbandoned());
1529  ret.push_back(entry);
1530  }
1531  }
1532 
1533  // Received
1534  if (listReceived.size() > 0 && wtx.GetDepthInMainChain() >= nMinDepth) {
1535  for (const COutputEntry &r : listReceived) {
1536  std::string label;
1537  const auto *address_book_entry =
1538  pwallet->FindAddressBookEntry(r.destination);
1539  if (address_book_entry) {
1540  label = address_book_entry->GetLabel();
1541  }
1542  if (filter_label && label != *filter_label) {
1543  continue;
1544  }
1545  UniValue entry(UniValue::VOBJ);
1546  if (involvesWatchonly ||
1547  (pwallet->IsMine(r.destination) & ISMINE_WATCH_ONLY)) {
1548  entry.pushKV("involvesWatchonly", true);
1549  }
1550  MaybePushAddress(entry, r.destination);
1551  if (wtx.IsCoinBase()) {
1552  if (wtx.GetDepthInMainChain() < 1) {
1553  entry.pushKV("category", "orphan");
1554  } else if (wtx.IsImmatureCoinBase()) {
1555  entry.pushKV("category", "immature");
1556  } else {
1557  entry.pushKV("category", "generate");
1558  }
1559  } else {
1560  entry.pushKV("category", "receive");
1561  }
1562  entry.pushKV("amount", ValueFromAmount(r.amount));
1563  if (address_book_entry) {
1564  entry.pushKV("label", label);
1565  }
1566  entry.pushKV("vout", r.vout);
1567  if (fLong) {
1568  WalletTxToJSON(pwallet->chain(), wtx, entry);
1569  }
1570  ret.push_back(entry);
1571  }
1572  }
1573 }
1574 
1575 static const std::vector<RPCResult> TransactionDescriptionString() {
1576  return {
1577  {RPCResult::Type::NUM, "confirmations",
1578  "The number of confirmations for the transaction. Negative "
1579  "confirmations means the\n"
1580  "transaction conflicted that many blocks ago."},
1581  {RPCResult::Type::BOOL, "generated",
1582  "Only present if transaction only input is a coinbase one."},
1583  {RPCResult::Type::BOOL, "trusted",
1584  "Only present if we consider transaction to be trusted and so safe to "
1585  "spend from."},
1586  {RPCResult::Type::STR_HEX, "blockhash",
1587  "The block hash containing the transaction."},
1588  {RPCResult::Type::NUM, "blockheight",
1589  "The block height containing the transaction."},
1590  {RPCResult::Type::NUM, "blockindex",
1591  "The index of the transaction in the block that includes it."},
1592  {RPCResult::Type::NUM_TIME, "blocktime",
1593  "The block time expressed in " + UNIX_EPOCH_TIME + "."},
1594  {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
1596  "walletconflicts",
1597  "Conflicting transaction ids.",
1598  {
1599  {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
1600  }},
1601  {RPCResult::Type::NUM_TIME, "time",
1602  "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
1603  {RPCResult::Type::NUM_TIME, "timereceived",
1604  "The time received expressed in " + UNIX_EPOCH_TIME + "."},
1605  {RPCResult::Type::STR, "comment",
1606  "If a comment is associated with the transaction, only present if not "
1607  "empty."},
1608  };
1609 }
1610 
1611 UniValue listtransactions(const Config &config, const JSONRPCRequest &request) {
1612  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1613  const CWallet *const pwallet = wallet.get();
1614 
1615  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1616  return NullUniValue;
1617  }
1618 
1619  RPCHelpMan{
1620  "listtransactions",
1621  "If a label name is provided, this will return only incoming "
1622  "transactions paying to addresses with the specified label.\n"
1623  "\nReturns up to 'count' most recent transactions skipping the first "
1624  "'from' transactions.\n",
1625  {
1626  {"label|dummy", RPCArg::Type::STR,
1628  "If set, should be a valid label name to return only incoming "
1629  "transactions with the specified label, or \"*\" to disable "
1630  "filtering and return all transactions."},
1631  {"count", RPCArg::Type::NUM, /* default */ "10",
1632  "The number of transactions to return"},
1633  {"skip", RPCArg::Type::NUM, /* default */ "0",
1634  "The number of transactions to skip"},
1635  {"include_watchonly", RPCArg::Type::BOOL,
1636  /* default */ "true for watch-only wallets, otherwise false",
1637  "Include transactions to watch-only addresses (see "
1638  "'importaddress')"},
1639  },
1640  RPCResult{
1642  "",
1643  "",
1644  {
1645  {RPCResult::Type::OBJ, "", "",
1646  Cat(Cat<std::vector<RPCResult>>(
1647  {
1648  {RPCResult::Type::BOOL, "involvesWatchonly",
1649  "Only returns true if imported addresses were "
1650  "involved in transaction."},
1651  {RPCResult::Type::STR, "address",
1652  "The bitcoin address of the transaction."},
1653  {RPCResult::Type::STR, "category",
1654  "The transaction category.\n"
1655  "\"send\" Transactions sent.\n"
1656  "\"receive\" Non-coinbase "
1657  "transactions received.\n"
1658  "\"generate\" Coinbase transactions "
1659  "received with more than 100 confirmations.\n"
1660  "\"immature\" Coinbase transactions "
1661  "received with 100 or fewer confirmations.\n"
1662  "\"orphan\" Orphaned coinbase "
1663  "transactions received."},
1664  {RPCResult::Type::STR_AMOUNT, "amount",
1665  "The amount in " + CURRENCY_UNIT +
1666  ". This is negative for the 'send' category, "
1667  "and is positive\n"
1668  "for all other categories"},
1669  {RPCResult::Type::STR, "label",
1670  "A comment for the address/transaction, if any"},
1671  {RPCResult::Type::NUM, "vout", "the vout value"},
1673  "The amount of the fee in " + CURRENCY_UNIT +
1674  ". This is negative and only available for "
1675  "the\n"
1676  "'send' category of transactions."},
1677  },
1679  {
1680  {RPCResult::Type::BOOL, "abandoned",
1681  "'true' if the transaction has been abandoned "
1682  "(inputs are respendable). Only available for the \n"
1683  "'send' category of transactions."},
1684  })},
1685  }},
1686  RPCExamples{"\nList the most recent 10 transactions in the systems\n" +
1687  HelpExampleCli("listtransactions", "") +
1688  "\nList transactions 100 to 120\n" +
1689  HelpExampleCli("listtransactions", "\"*\" 20 100") +
1690  "\nAs a JSON-RPC call\n" +
1691  HelpExampleRpc("listtransactions", "\"*\", 20, 100")},
1692  }
1693  .Check(request);
1694 
1695  // Make sure the results are valid at least up to the most recent block
1696  // the user could have gotten from another RPC command prior to now
1697  pwallet->BlockUntilSyncedToCurrentChain();
1698 
1699  const std::string *filter_label = nullptr;
1700  if (!request.params[0].isNull() && request.params[0].get_str() != "*") {
1701  filter_label = &request.params[0].get_str();
1702  if (filter_label->empty()) {
1703  throw JSONRPCError(
1705  "Label argument must be a valid label name or \"*\".");
1706  }
1707  }
1708  int nCount = 10;
1709  if (!request.params[1].isNull()) {
1710  nCount = request.params[1].get_int();
1711  }
1712 
1713  int nFrom = 0;
1714  if (!request.params[2].isNull()) {
1715  nFrom = request.params[2].get_int();
1716  }
1717 
1718  isminefilter filter = ISMINE_SPENDABLE;
1719  if (ParseIncludeWatchonly(request.params[3], *pwallet)) {
1720  filter |= ISMINE_WATCH_ONLY;
1721  }
1722 
1723  if (nCount < 0) {
1724  throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative count");
1725  }
1726  if (nFrom < 0) {
1727  throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative from");
1728  }
1729  UniValue ret(UniValue::VARR);
1730 
1731  {
1732  LOCK(pwallet->cs_wallet);
1733 
1734  const CWallet::TxItems &txOrdered = pwallet->wtxOrdered;
1735 
1736  // iterate backwards until we have nCount items to return:
1737  for (CWallet::TxItems::const_reverse_iterator it = txOrdered.rbegin();
1738  it != txOrdered.rend(); ++it) {
1739  CWalletTx *const pwtx = (*it).second;
1740  ListTransactions(pwallet, *pwtx, 0, true, ret, filter,
1741  filter_label);
1742  if (int(ret.size()) >= (nCount + nFrom)) {
1743  break;
1744  }
1745  }
1746  }
1747 
1748  // ret is newest to oldest
1749 
1750  if (nFrom > (int)ret.size()) {
1751  nFrom = ret.size();
1752  }
1753  if ((nFrom + nCount) > (int)ret.size()) {
1754  nCount = ret.size() - nFrom;
1755  }
1756 
1757  const std::vector<UniValue> &txs = ret.getValues();
1758  UniValue result{UniValue::VARR};
1759  // Return oldest to newest
1760  result.push_backV({txs.rend() - nFrom - nCount, txs.rend() - nFrom});
1761  return result;
1762 }
1763 
1764 static UniValue listsinceblock(const Config &config,
1765  const JSONRPCRequest &request) {
1766  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1767  const CWallet *const pwallet = wallet.get();
1768 
1769  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1770  return NullUniValue;
1771  }
1772 
1773  RPCHelpMan{
1774  "listsinceblock",
1775  "Get all transactions in blocks since block [blockhash], or all "
1776  "transactions if omitted.\n"
1777  "If \"blockhash\" is no longer a part of the main chain, transactions "
1778  "from the fork point onward are included.\n"
1779  "Additionally, if include_removed is set, transactions affecting the "
1780  "wallet which were removed are returned in the \"removed\" array.\n",
1781  {
1782  {"blockhash", RPCArg::Type::STR,
1784  "If set, the block hash to list transactions since, otherwise "
1785  "list all transactions."},
1786  {"target_confirmations", RPCArg::Type::NUM, /* default */ "1",
1787  "Return the nth block hash from the main chain. e.g. 1 would mean "
1788  "the best block hash. Note: this is not used as a filter, but "
1789  "only affects [lastblock] in the return value"},
1790  {"include_watchonly", RPCArg::Type::BOOL,
1791  /* default */ "true for watch-only wallets, otherwise false",
1792  "Include transactions to watch-only addresses (see "
1793  "'importaddress')"},
1794  {"include_removed", RPCArg::Type::BOOL, /* default */ "true",
1795  "Show transactions that were removed due to a reorg in the "
1796  "\"removed\" array\n"
1797  " (not "
1798  "guaranteed to work on pruned nodes)"},
1799  },
1800  RPCResult{
1802  "",
1803  "",
1804  {
1806  "transactions",
1807  "",
1808  {
1809  {RPCResult::Type::OBJ, "", "",
1810  Cat(Cat<std::vector<RPCResult>>(
1811  {
1812  {RPCResult::Type::BOOL, "involvesWatchonly",
1813  "Only returns true if imported addresses "
1814  "were involved in transaction."},
1815  {RPCResult::Type::STR, "address",
1816  "The bitcoin address of the transaction."},
1817  {RPCResult::Type::STR, "category",
1818  "The transaction category.\n"
1819  "\"send\" Transactions "
1820  "sent.\n"
1821  "\"receive\" Non-coinbase "
1822  "transactions received.\n"
1823  "\"generate\" Coinbase "
1824  "transactions received with more than 100 "
1825  "confirmations.\n"
1826  "\"immature\" Coinbase "
1827  "transactions received with 100 or fewer "
1828  "confirmations.\n"
1829  "\"orphan\" Orphaned "
1830  "coinbase transactions received."},
1831  {RPCResult::Type::STR_AMOUNT, "amount",
1832  "The amount in " + CURRENCY_UNIT +
1833  ". This is negative for the 'send' "
1834  "category, and is positive\n"
1835  "for all other categories"},
1836  {RPCResult::Type::NUM, "vout",
1837  "the vout value"},
1839  "The amount of the fee in " + CURRENCY_UNIT +
1840  ". This is negative and only available "
1841  "for the\n"
1842  "'send' category of transactions."},
1843  },
1845  {
1846  {RPCResult::Type::BOOL, "abandoned",
1847  "'true' if the transaction has been abandoned "
1848  "(inputs are respendable). Only available for "
1849  "the \n"
1850  "'send' category of transactions."},
1851  {RPCResult::Type::STR, "comment",
1852  "If a comment is associated with the "
1853  "transaction."},
1854  {RPCResult::Type::STR, "label",
1855  "A comment for the address/transaction, if any"},
1856  {RPCResult::Type::STR, "to",
1857  "If a comment to is associated with the "
1858  "transaction."},
1859  })},
1860  }},
1862  "removed",
1863  "<structure is the same as \"transactions\" above, only "
1864  "present if include_removed=true>\n"
1865  "Note: transactions that were re-added in the active chain "
1866  "will appear as-is in this array, and may thus have a "
1867  "positive confirmation count.",
1868  {
1869  {RPCResult::Type::ELISION, "", ""},
1870  }},
1871  {RPCResult::Type::STR_HEX, "lastblock",
1872  "The hash of the block (target_confirmations-1) from the best "
1873  "block on the main chain. This is typically used to feed back "
1874  "into listsinceblock the next time you call it. So you would "
1875  "generally use a target_confirmations of say 6, so you will "
1876  "be continually re-notified of transactions until they've "
1877  "reached 6 confirmations plus any new ones"},
1878  }},
1879  RPCExamples{HelpExampleCli("listsinceblock", "") +
1880  HelpExampleCli("listsinceblock",
1881  "\"000000000000000bacf66f7497b7dc45ef753ee9a"
1882  "7d38571037cdb1a57f663ad\" 6") +
1883  HelpExampleRpc("listsinceblock",
1884  "\"000000000000000bacf66f7497b7dc45ef753ee9a"
1885  "7d38571037cdb1a57f663ad\", 6")},
1886  }
1887  .Check(request);
1888 
1889  // Make sure the results are valid at least up to the most recent block
1890  // the user could have gotten from another RPC command prior to now
1891  pwallet->BlockUntilSyncedToCurrentChain();
1892 
1893  LOCK(pwallet->cs_wallet);
1894 
1895  // Height of the specified block or the common ancestor, if the block
1896  // provided was in a deactivated chain.
1897  std::optional<int> height;
1898 
1899  // Height of the specified block, even if it's in a deactivated chain.
1900  std::optional<int> altheight;
1901  int target_confirms = 1;
1902  isminefilter filter = ISMINE_SPENDABLE;
1903 
1904  BlockHash blockId;
1905  if (!request.params[0].isNull() && !request.params[0].get_str().empty()) {
1906  blockId = BlockHash(ParseHashV(request.params[0], "blockhash"));
1907  height.emplace();
1908  altheight.emplace();
1909  if (!pwallet->chain().findCommonAncestor(
1910  blockId, pwallet->GetLastBlockHash(),
1911  /* ancestor out */ FoundBlock().height(*height),
1912  /* blockId out */ FoundBlock().height(*altheight))) {
1913  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1914  }
1915  }
1916 
1917  if (!request.params[1].isNull()) {
1918  target_confirms = request.params[1].get_int();
1919 
1920  if (target_confirms < 1) {
1921  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter");
1922  }
1923  }
1924 
1925  if (ParseIncludeWatchonly(request.params[2], *pwallet)) {
1926  filter |= ISMINE_WATCH_ONLY;
1927  }
1928 
1929  bool include_removed =
1930  (request.params[3].isNull() || request.params[3].get_bool());
1931 
1932  int depth = height ? pwallet->GetLastBlockHeight() + 1 - *height : -1;
1933 
1934  UniValue transactions(UniValue::VARR);
1935 
1936  for (const std::pair<const TxId, CWalletTx> &pairWtx : pwallet->mapWallet) {
1937  const CWalletTx &tx = pairWtx.second;
1938 
1939  if (depth == -1 || tx.GetDepthInMainChain() < depth) {
1940  ListTransactions(pwallet, tx, 0, true, transactions, filter,
1941  nullptr /* filter_label */);
1942  }
1943  }
1944 
1945  // when a reorg'd block is requested, we also list any relevant transactions
1946  // in the blocks of the chain that was detached
1947  UniValue removed(UniValue::VARR);
1948  while (include_removed && altheight && *altheight > *height) {
1949  CBlock block;
1950  if (!pwallet->chain().findBlock(blockId, FoundBlock().data(block)) ||
1951  block.IsNull()) {
1953  "Can't read block from disk");
1954  }
1955  for (const CTransactionRef &tx : block.vtx) {
1956  auto it = pwallet->mapWallet.find(tx->GetId());
1957  if (it != pwallet->mapWallet.end()) {
1958  // We want all transactions regardless of confirmation count to
1959  // appear here, even negative confirmation ones, hence the big
1960  // negative.
1961  ListTransactions(pwallet, it->second, -100000000, true, removed,
1962  filter, nullptr /* filter_label */);
1963  }
1964  }
1965  blockId = block.hashPrevBlock;
1966  --*altheight;
1967  }
1968 
1969  BlockHash lastblock;
1971  pwallet->GetLastBlockHash(),
1972  pwallet->GetLastBlockHeight() + 1 - target_confirms,
1973  FoundBlock().hash(lastblock)));
1974 
1975  UniValue ret(UniValue::VOBJ);
1976  ret.pushKV("transactions", transactions);
1977  if (include_removed) {
1978  ret.pushKV("removed", removed);
1979  }
1980  ret.pushKV("lastblock", lastblock.GetHex());
1981 
1982  return ret;
1983 }
1984 
1985 static UniValue gettransaction(const Config &config,
1986  const JSONRPCRequest &request) {
1987  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
1988  const CWallet *const pwallet = wallet.get();
1989 
1990  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
1991  return NullUniValue;
1992  }
1993 
1994  RPCHelpMan{
1995  "gettransaction",
1996  "Get detailed information about in-wallet transaction <txid>\n",
1997  {
1999  "The transaction id"},
2000  {"include_watchonly", RPCArg::Type::BOOL,
2001  /* default */ "true for watch-only wallets, otherwise false",
2002  "Whether to include watch-only addresses in balance calculation "
2003  "and details[]"},
2004  {"verbose", RPCArg::Type::BOOL, /* default */ "false",
2005  "Whether to include a `decoded` field containing the decoded "
2006  "transaction (equivalent to RPC decoderawtransaction)"},
2007  },
2008  RPCResult{
2009  RPCResult::Type::OBJ, "", "",
2010  Cat(Cat<std::vector<RPCResult>>(
2011  {
2012  {RPCResult::Type::STR_AMOUNT, "amount",
2013  "The amount in " + CURRENCY_UNIT},
2015  "The amount of the fee in " + CURRENCY_UNIT +
2016  ". This is negative and only available for the\n"
2017  "'send' category of transactions."},
2018  },
2020  {
2022  "details",
2023  "",
2024  {
2026  "",
2027  "",
2028  {
2029  {RPCResult::Type::BOOL, "involvesWatchonly",
2030  "Only returns true if imported addresses were "
2031  "involved in transaction."},
2032  {RPCResult::Type::STR, "address",
2033  "The bitcoin address involved in the "
2034  "transaction."},
2035  {RPCResult::Type::STR, "category",
2036  "The transaction category.\n"
2037  "\"send\" Transactions sent.\n"
2038  "\"receive\" Non-coinbase "
2039  "transactions received.\n"
2040  "\"generate\" Coinbase "
2041  "transactions received with more than 100 "
2042  "confirmations.\n"
2043  "\"immature\" Coinbase "
2044  "transactions received with 100 or fewer "
2045  "confirmations.\n"
2046  "\"orphan\" Orphaned coinbase "
2047  "transactions received."},
2048  {RPCResult::Type::STR_AMOUNT, "amount",
2049  "The amount in " + CURRENCY_UNIT},
2050  {RPCResult::Type::STR, "label",
2051  "A comment for the address/transaction, if any"},
2052  {RPCResult::Type::NUM, "vout", "the vout value"},
2054  "The amount of the fee in " + CURRENCY_UNIT +
2055  ". This is negative and only available for "
2056  "the \n"
2057  "'send' category of transactions."},
2058  {RPCResult::Type::BOOL, "abandoned",
2059  "'true' if the transaction has been abandoned "
2060  "(inputs are respendable). Only available for "
2061  "the \n"
2062  "'send' category of transactions."},
2063  }},
2064  }},
2065  {RPCResult::Type::STR_HEX, "hex",
2066  "Raw data for transaction"},
2068  "decoded",
2069  "Optional, the decoded transaction (only present when "
2070  "`verbose` is passed)",
2071  {
2073  "Equivalent to the RPC decoderawtransaction method, "
2074  "or the RPC getrawtransaction method when `verbose` "
2075  "is passed."},
2076  }},
2077  })},
2078  RPCExamples{HelpExampleCli("gettransaction",
2079  "\"1075db55d416d3ca199f55b6084e2115b9345e16c"
2080  "5cf302fc80e9d5fbf5d48d\"") +
2081  HelpExampleCli("gettransaction",
2082  "\"1075db55d416d3ca199f55b6084e2115b9345e16c"
2083  "5cf302fc80e9d5fbf5d48d\" true") +
2084  HelpExampleCli("gettransaction",
2085  "\"1075db55d416d3ca199f55b6084e2115b9345e16c"
2086  "5cf302fc80e9d5fbf5d48d\" false true") +
2087  HelpExampleRpc("gettransaction",
2088  "\"1075db55d416d3ca199f55b6084e2115b9345e16c"
2089  "5cf302fc80e9d5fbf5d48d\"")},
2090  }
2091  .Check(request);
2092 
2093  // Make sure the results are valid at least up to the most recent block
2094  // the user could have gotten from another RPC command prior to now
2095  pwallet->BlockUntilSyncedToCurrentChain();
2096 
2097  LOCK(pwallet->cs_wallet);
2098 
2099  TxId txid(ParseHashV(request.params[0], "txid"));
2100 
2101  isminefilter filter = ISMINE_SPENDABLE;
2102  if (ParseIncludeWatchonly(request.params[1], *pwallet)) {
2103  filter |= ISMINE_WATCH_ONLY;
2104  }
2105 
2106  bool verbose =
2107  request.params[2].isNull() ? false : request.params[2].get_bool();
2108 
2109  UniValue entry(UniValue::VOBJ);
2110  auto it = pwallet->mapWallet.find(txid);
2111  if (it == pwallet->mapWallet.end()) {
2113  "Invalid or non-wallet transaction id");
2114  }
2115  const CWalletTx &wtx = it->second;
2116 
2117  Amount nCredit = wtx.GetCredit(filter);
2118  Amount nDebit = wtx.GetDebit(filter);
2119  Amount nNet = nCredit - nDebit;
2120  Amount nFee = (wtx.IsFromMe(filter) ? wtx.tx->GetValueOut() - nDebit
2121  : Amount::zero());
2122 
2123  entry.pushKV("amount", ValueFromAmount(nNet - nFee));
2124  if (wtx.IsFromMe(filter)) {
2125  entry.pushKV("fee", ValueFromAmount(nFee));
2126  }
2127 
2128  WalletTxToJSON(pwallet->chain(), wtx, entry);
2129 
2130  UniValue details(UniValue::VARR);
2131  ListTransactions(pwallet, wtx, 0, false, details, filter,
2132  nullptr /* filter_label */);
2133  entry.pushKV("details", details);
2134 
2135  std::string strHex =
2136  EncodeHexTx(*wtx.tx, pwallet->chain().rpcSerializationFlags());
2137  entry.pushKV("hex", strHex);
2138 
2139  if (verbose) {
2140  UniValue decoded(UniValue::VOBJ);
2141  TxToUniv(*wtx.tx, uint256(), decoded, false);
2142  entry.pushKV("decoded", decoded);
2143  }
2144 
2145  return entry;
2146 }
2147 
2148 static UniValue abandontransaction(const Config &config,
2149  const JSONRPCRequest &request) {
2150  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2151  CWallet *const pwallet = wallet.get();
2152 
2153  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2154  return NullUniValue;
2155  }
2156 
2157  RPCHelpMan{
2158  "abandontransaction",
2159  "Mark in-wallet transaction <txid> as abandoned\n"
2160  "This will mark this transaction and all its in-wallet descendants as "
2161  "abandoned which will allow\n"
2162  "for their inputs to be respent. It can be used to replace \"stuck\" "
2163  "or evicted transactions.\n"
2164  "It only works on transactions which are not included in a block and "
2165  "are not currently in the mempool.\n"
2166  "It has no effect on transactions which are already abandoned.\n",
2167  {
2169  "The transaction id"},
2170  },
2172  RPCExamples{HelpExampleCli("abandontransaction",
2173  "\"1075db55d416d3ca199f55b6084e2115b9345e16c"
2174  "5cf302fc80e9d5fbf5d48d\"") +
2175  HelpExampleRpc("abandontransaction",
2176  "\"1075db55d416d3ca199f55b6084e2115b9345e16c"
2177  "5cf302fc80e9d5fbf5d48d\"")},
2178  }
2179  .Check(request);
2180 
2181  // Make sure the results are valid at least up to the most recent block
2182  // the user could have gotten from another RPC command prior to now
2183  pwallet->BlockUntilSyncedToCurrentChain();
2184 
2185  LOCK(pwallet->cs_wallet);
2186 
2187  TxId txid(ParseHashV(request.params[0], "txid"));
2188 
2189  if (!pwallet->mapWallet.count(txid)) {
2191  "Invalid or non-wallet transaction id");
2192  }
2193 
2194  if (!pwallet->AbandonTransaction(txid)) {
2196  "Transaction not eligible for abandonment");
2197  }
2198 
2199  return NullUniValue;
2200 }
2201 
2202 static UniValue backupwallet(const Config &config,
2203  const JSONRPCRequest &request) {
2204  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2205  const CWallet *const pwallet = wallet.get();
2206 
2207  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2208  return NullUniValue;
2209  }
2210 
2211  RPCHelpMan{
2212  "backupwallet",
2213  "Safely copies current wallet file to destination, which can be a "
2214  "directory or a path with filename.\n",
2215  {
2216  {"destination", RPCArg::Type::STR, RPCArg::Optional::NO,
2217  "The destination directory or file"},
2218  },
2220  RPCExamples{HelpExampleCli("backupwallet", "\"backup.dat\"") +
2221  HelpExampleRpc("backupwallet", "\"backup.dat\"")},
2222  }
2223  .Check(request);
2224 
2225  // Make sure the results are valid at least up to the most recent block
2226  // the user could have gotten from another RPC command prior to now
2227  pwallet->BlockUntilSyncedToCurrentChain();
2228 
2229  LOCK(pwallet->cs_wallet);
2230 
2231  std::string strDest = request.params[0].get_str();
2232  if (!pwallet->BackupWallet(strDest)) {
2233  throw JSONRPCError(RPC_WALLET_ERROR, "Error: Wallet backup failed!");
2234  }
2235 
2236  return NullUniValue;
2237 }
2238 
2239 static UniValue keypoolrefill(const Config &config,
2240  const JSONRPCRequest &request) {
2241  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2242  CWallet *const pwallet = wallet.get();
2243 
2244  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2245  return NullUniValue;
2246  }
2247 
2248  RPCHelpMan{
2249  "keypoolrefill",
2250  "Fills the keypool." + HELP_REQUIRING_PASSPHRASE,
2251  {
2252  {"newsize", RPCArg::Type::NUM, /* default */ "100",
2253  "The new keypool size"},
2254  },
2256  RPCExamples{HelpExampleCli("keypoolrefill", "") +
2257  HelpExampleRpc("keypoolrefill", "")},
2258  }
2259  .Check(request);
2260 
2261  if (pwallet->IsLegacy() &&
2264  "Error: Private keys are disabled for this wallet");
2265  }
2266 
2267  LOCK(pwallet->cs_wallet);
2268 
2269  // 0 is interpreted by TopUpKeyPool() as the default keypool size given by
2270  // -keypool
2271  unsigned int kpSize = 0;
2272  if (!request.params[0].isNull()) {
2273  if (request.params[0].get_int() < 0) {
2275  "Invalid parameter, expected valid size.");
2276  }
2277  kpSize = (unsigned int)request.params[0].get_int();
2278  }
2279 
2280  EnsureWalletIsUnlocked(pwallet);
2281  pwallet->TopUpKeyPool(kpSize);
2282 
2283  if (pwallet->GetKeyPoolSize() < kpSize) {
2284  throw JSONRPCError(RPC_WALLET_ERROR, "Error refreshing keypool.");
2285  }
2286 
2287  return NullUniValue;
2288 }
2289 
2290 static UniValue walletpassphrase(const Config &config,
2291  const JSONRPCRequest &request) {
2292  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2293  CWallet *const pwallet = wallet.get();
2294 
2295  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2296  return NullUniValue;
2297  }
2298 
2299  RPCHelpMan{
2300  "walletpassphrase",
2301  "Stores the wallet decryption key in memory for 'timeout' seconds.\n"
2302  "This is needed prior to performing transactions related to private "
2303  "keys such as sending bitcoins\n"
2304  "\nNote:\n"
2305  "Issuing the walletpassphrase command while the wallet is already "
2306  "unlocked will set a new unlock\n"
2307  "time that overrides the old one.\n",
2308  {
2309  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO,
2310  "The wallet passphrase"},
2312  "The time to keep the decryption key in seconds; capped at "
2313  "100000000 (~3 years)."},
2314  },
2316  RPCExamples{
2317  "\nUnlock the wallet for 60 seconds\n" +
2318  HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
2319  "\nLock the wallet again (before 60 seconds)\n" +
2320  HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" +
2321  HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")},
2322  }
2323  .Check(request);
2324 
2325  int64_t nSleepTime;
2326  int64_t relock_time;
2327  // Prevent concurrent calls to walletpassphrase with the same wallet.
2328  LOCK(pwallet->m_unlock_mutex);
2329  {
2330  LOCK(pwallet->cs_wallet);
2331 
2332  if (!pwallet->IsCrypted()) {
2334  "Error: running with an unencrypted wallet, but "
2335  "walletpassphrase was called.");
2336  }
2337 
2338  // Note that the walletpassphrase is stored in request.params[0] which
2339  // is not mlock()ed
2340  SecureString strWalletPass;
2341  strWalletPass.reserve(100);
2342  // TODO: get rid of this .c_str() by implementing
2343  // SecureString::operator=(std::string)
2344  // Alternately, find a way to make request.params[0] mlock()'d to begin
2345  // with.
2346  strWalletPass = request.params[0].get_str().c_str();
2347 
2348  // Get the timeout
2349  nSleepTime = request.params[1].get_int64();
2350  // Timeout cannot be negative, otherwise it will relock immediately
2351  if (nSleepTime < 0) {
2353  "Timeout cannot be negative.");
2354  }
2355  // Clamp timeout
2356  // larger values trigger a macos/libevent bug?
2357  constexpr int64_t MAX_SLEEP_TIME = 100000000;
2358  if (nSleepTime > MAX_SLEEP_TIME) {
2359  nSleepTime = MAX_SLEEP_TIME;
2360  }
2361 
2362  if (strWalletPass.empty()) {
2364  "passphrase can not be empty");
2365  }
2366 
2367  if (!pwallet->Unlock(strWalletPass)) {
2368  throw JSONRPCError(
2370  "Error: The wallet passphrase entered was incorrect.");
2371  }
2372 
2373  pwallet->TopUpKeyPool();
2374 
2375  pwallet->nRelockTime = GetTime() + nSleepTime;
2376  relock_time = pwallet->nRelockTime;
2377  }
2378 
2379  // rpcRunLater must be called without cs_wallet held otherwise a deadlock
2380  // can occur. The deadlock would happen when RPCRunLater removes the
2381  // previous timer (and waits for the callback to finish if already running)
2382  // and the callback locks cs_wallet.
2383  AssertLockNotHeld(wallet->cs_wallet);
2384  // Keep a weak pointer to the wallet so that it is possible to unload the
2385  // wallet before the following callback is called. If a valid shared pointer
2386  // is acquired in the callback then the wallet is still loaded.
2387  std::weak_ptr<CWallet> weak_wallet = wallet;
2388  pwallet->chain().rpcRunLater(
2389  strprintf("lockwallet(%s)", pwallet->GetName()),
2390  [weak_wallet, relock_time] {
2391  if (auto shared_wallet = weak_wallet.lock()) {
2392  LOCK(shared_wallet->cs_wallet);
2393  // Skip if this is not the most recent rpcRunLater callback.
2394  if (shared_wallet->nRelockTime != relock_time) {
2395  return;
2396  }
2397  shared_wallet->Lock();
2398  shared_wallet->nRelockTime = 0;
2399  }
2400  },
2401  nSleepTime);
2402 
2403  return NullUniValue;
2404 }
2405 
2407  const JSONRPCRequest &request) {
2408  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2409  CWallet *const pwallet = wallet.get();
2410 
2411  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2412  return NullUniValue;
2413  }
2414 
2415  RPCHelpMan{
2416  "walletpassphrasechange",
2417  "Changes the wallet passphrase from 'oldpassphrase' to "
2418  "'newpassphrase'.\n",
2419  {
2420  {"oldpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO,
2421  "The current passphrase"},
2422  {"newpassphrase", RPCArg::Type::STR, RPCArg::Optional::NO,
2423  "The new passphrase"},
2424  },
2426  RPCExamples{HelpExampleCli("walletpassphrasechange",
2427  "\"old one\" \"new one\"") +
2428  HelpExampleRpc("walletpassphrasechange",
2429  "\"old one\", \"new one\"")},
2430  }
2431  .Check(request);
2432 
2433  LOCK(pwallet->cs_wallet);
2434 
2435  if (!pwallet->IsCrypted()) {
2437  "Error: running with an unencrypted wallet, but "
2438  "walletpassphrasechange was called.");
2439  }
2440 
2441  // TODO: get rid of these .c_str() calls by implementing
2442  // SecureString::operator=(std::string)
2443  // Alternately, find a way to make request.params[0] mlock()'d to begin
2444  // with.
2445  SecureString strOldWalletPass;
2446  strOldWalletPass.reserve(100);
2447  strOldWalletPass = request.params[0].get_str().c_str();
2448 
2449  SecureString strNewWalletPass;
2450  strNewWalletPass.reserve(100);
2451  strNewWalletPass = request.params[1].get_str().c_str();
2452 
2453  if (strOldWalletPass.empty() || strNewWalletPass.empty()) {
2455  "passphrase can not be empty");
2456  }
2457 
2458  if (!pwallet->ChangeWalletPassphrase(strOldWalletPass, strNewWalletPass)) {
2459  throw JSONRPCError(
2461  "Error: The wallet passphrase entered was incorrect.");
2462  }
2463 
2464  return NullUniValue;
2465 }
2466 
2467 static UniValue walletlock(const Config &config,
2468  const JSONRPCRequest &request) {
2469  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2470  CWallet *const pwallet = wallet.get();
2471 
2472  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2473  return NullUniValue;
2474  }
2475 
2476  RPCHelpMan{
2477  "walletlock",
2478  "Removes the wallet encryption key from memory, locking the wallet.\n"
2479  "After calling this method, you will need to call walletpassphrase "
2480  "again\n"
2481  "before being able to call any methods which require the wallet to be "
2482  "unlocked.\n",
2483  {},
2485  RPCExamples{
2486  "\nSet the passphrase for 2 minutes to perform a transaction\n" +
2487  HelpExampleCli("walletpassphrase", "\"my pass phrase\" 120") +
2488  "\nPerform a send (requires passphrase set)\n" +
2489  HelpExampleCli("sendtoaddress",
2490  "\"1M72Sfpbz1BPpXFHz9m3CdqATR44Jvaydd\" 1.0") +
2491  "\nClear the passphrase since we are done before 2 minutes is "
2492  "up\n" +
2493  HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" +
2494  HelpExampleRpc("walletlock", "")},
2495  }
2496  .Check(request);
2497 
2498  LOCK(pwallet->cs_wallet);
2499 
2500  if (!pwallet->IsCrypted()) {
2502  "Error: running with an unencrypted wallet, but "
2503  "walletlock was called.");
2504  }
2505 
2506  pwallet->Lock();
2507  pwallet->nRelockTime = 0;
2508 
2509  return NullUniValue;
2510 }
2511 
2512 static UniValue encryptwallet(const Config &config,
2513  const JSONRPCRequest &request) {
2514  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2515  CWallet *const pwallet = wallet.get();
2516 
2517  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2518  return NullUniValue;
2519  }
2520 
2521  RPCHelpMan{
2522  "encryptwallet",
2523  "Encrypts the wallet with 'passphrase'. This is for first time "
2524  "encryption.\n"
2525  "After this, any calls that interact with private keys such as sending "
2526  "or signing \n"
2527  "will require the passphrase to be set prior the making these calls.\n"
2528  "Use the walletpassphrase call for this, and then walletlock call.\n"
2529  "If the wallet is already encrypted, use the walletpassphrasechange "
2530  "call.\n",
2531  {
2532  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO,
2533  "The pass phrase to encrypt the wallet with. It must be at least "
2534  "1 character, but should be long."},
2535  },
2537  "A string with further instructions"},
2538  RPCExamples{
2539  "\nEncrypt your wallet\n" +
2540  HelpExampleCli("encryptwallet", "\"my pass phrase\"") +
2541  "\nNow set the passphrase to use the wallet, such as for signing "
2542  "or sending bitcoin\n" +
2543  HelpExampleCli("walletpassphrase", "\"my pass phrase\"") +
2544  "\nNow we can do something like sign\n" +
2545  HelpExampleCli("signmessage", "\"address\" \"test message\"") +
2546  "\nNow lock the wallet again by removing the passphrase\n" +
2547  HelpExampleCli("walletlock", "") + "\nAs a JSON-RPC call\n" +
2548  HelpExampleRpc("encryptwallet", "\"my pass phrase\"")},
2549  }
2550  .Check(request);
2551 
2552  LOCK(pwallet->cs_wallet);
2553 
2555  throw JSONRPCError(
2557  "Error: wallet does not contain private keys, nothing to encrypt.");
2558  }
2559 
2560  if (pwallet->IsCrypted()) {
2562  "Error: running with an encrypted wallet, but "
2563  "encryptwallet was called.");
2564  }
2565 
2566  // TODO: get rid of this .c_str() by implementing
2567  // SecureString::operator=(std::string)
2568  // Alternately, find a way to make request.params[0] mlock()'d to begin
2569  // with.
2570  SecureString strWalletPass;
2571  strWalletPass.reserve(100);
2572  strWalletPass = request.params[0].get_str().c_str();
2573 
2574  if (strWalletPass.empty()) {
2576  "passphrase can not be empty");
2577  }
2578 
2579  if (!pwallet->EncryptWallet(strWalletPass)) {
2581  "Error: Failed to encrypt the wallet.");
2582  }
2583 
2584  return "wallet encrypted; The keypool has been flushed and a new HD seed "
2585  "was generated (if you are using HD). You need to make a new "
2586  "backup.";
2587 }
2588 
2589 static UniValue lockunspent(const Config &config,
2590  const JSONRPCRequest &request) {
2591  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2592  CWallet *const pwallet = wallet.get();
2593 
2594  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2595  return NullUniValue;
2596  }
2597 
2598  RPCHelpMan{
2599  "lockunspent",
2600  "Updates list of temporarily unspendable outputs.\n"
2601  "Temporarily lock (unlock=false) or unlock (unlock=true) specified "
2602  "transaction outputs.\n"
2603  "If no transaction outputs are specified when unlocking then all "
2604  "current locked transaction outputs are unlocked.\n"
2605  "A locked transaction output will not be chosen by automatic coin "
2606  "selection, when spending bitcoins.\n"
2607  "Locks are stored in memory only. Nodes start with zero locked "
2608  "outputs, and the locked output list\n"
2609  "is always cleared (by virtue of process exit) when a node stops or "
2610  "fails.\n"
2611  "Also see the listunspent call\n",
2612  {
2614  "Whether to unlock (true) or lock (false) the specified "
2615  "transactions"},
2616  {
2617  "transactions",
2619  /* default */ "empty array",
2620  "The transaction outputs and within each, txid (string) vout "
2621  "(numeric).",
2622  {
2623  {
2624  "",
2627  "",
2628  {
2629  {"txid", RPCArg::Type::STR_HEX,
2630  RPCArg::Optional::NO, "The transaction id"},
2632  "The output number"},
2633  },
2634  },
2635  },
2636  },
2637  },
2639  "Whether the command was successful or not"},
2640  RPCExamples{
2641  "\nList the unspent transactions\n" +
2642  HelpExampleCli("listunspent", "") +
2643  "\nLock an unspent transaction\n" +
2644  HelpExampleCli("lockunspent", "false "
2645  "\"[{\\\"txid\\\":"
2646  "\\\"a08e6907dbbd3d809776dbfc5d82e371"
2647  "b764ed838b5655e72f463568df1aadf0\\\""
2648  ",\\\"vout\\\":1}]\"") +
2649  "\nList the locked transactions\n" +
2650  HelpExampleCli("listlockunspent", "") +
2651  "\nUnlock the transaction again\n" +
2652  HelpExampleCli("lockunspent", "true "
2653  "\"[{\\\"txid\\\":"
2654  "\\\"a08e6907dbbd3d809776dbfc5d82e371"
2655  "b764ed838b5655e72f463568df1aadf0\\\""
2656  ",\\\"vout\\\":1}]\"") +
2657  "\nAs a JSON-RPC call\n" +
2658  HelpExampleRpc("lockunspent", "false, "
2659  "\"[{\\\"txid\\\":"
2660  "\\\"a08e6907dbbd3d809776dbfc5d82e371"
2661  "b764ed838b5655e72f463568df1aadf0\\\""
2662  ",\\\"vout\\\":1}]\"")},
2663  }
2664  .Check(request);
2665 
2666  // Make sure the results are valid at least up to the most recent block
2667  // the user could have gotten from another RPC command prior to now
2668  pwallet->BlockUntilSyncedToCurrentChain();
2669 
2670  LOCK(pwallet->cs_wallet);
2671 
2673 
2674  bool fUnlock = request.params[0].get_bool();
2675 
2676  if (request.params[1].isNull()) {
2677  if (fUnlock) {
2678  pwallet->UnlockAllCoins();
2679  }
2680  return true;
2681  }
2682 
2684 
2685  const UniValue &output_params = request.params[1];
2686 
2687  // Create and validate the COutPoints first.
2688 
2689  std::vector<COutPoint> outputs;
2690  outputs.reserve(output_params.size());
2691 
2692  for (size_t idx = 0; idx < output_params.size(); idx++) {
2693  const UniValue &o = output_params[idx].get_obj();
2694 
2695  RPCTypeCheckObj(o, {
2696  {"txid", UniValueType(UniValue::VSTR)},
2697  {"vout", UniValueType(UniValue::VNUM)},
2698  });
2699 
2700  const int nOutput = find_value(o, "vout").get_int();
2701  if (nOutput < 0) {
2703  "Invalid parameter, vout must be positive");
2704  }
2705 
2706  const TxId txid(ParseHashO(o, "txid"));
2707  const auto it = pwallet->mapWallet.find(txid);
2708  if (it == pwallet->mapWallet.end()) {
2710  "Invalid parameter, unknown transaction");
2711  }
2712 
2713  const COutPoint output(txid, nOutput);
2714  const CWalletTx &trans = it->second;
2715  if (output.GetN() >= trans.tx->vout.size()) {
2717  "Invalid parameter, vout index out of bounds");
2718  }
2719 
2720  if (pwallet->IsSpent(output)) {
2722  "Invalid parameter, expected unspent output");
2723  }
2724 
2725  const bool is_locked = pwallet->IsLockedCoin(output);
2726  if (fUnlock && !is_locked) {
2728  "Invalid parameter, expected locked output");
2729  }
2730 
2731  if (!fUnlock && is_locked) {
2733  "Invalid parameter, output already locked");
2734  }
2735 
2736  outputs.push_back(output);
2737  }
2738 
2739  // Atomically set (un)locked status for the outputs.
2740  for (const COutPoint &output : outputs) {
2741  if (fUnlock) {
2742  pwallet->UnlockCoin(output);
2743  } else {
2744  pwallet->LockCoin(output);
2745  }
2746  }
2747 
2748  return true;
2749 }
2750 
2751 static UniValue listlockunspent(const Config &config,
2752  const JSONRPCRequest &request) {
2753  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2754  const CWallet *const pwallet = wallet.get();
2755 
2756  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2757  return NullUniValue;
2758  }
2759 
2760  RPCHelpMan{
2761  "listlockunspent",
2762  "Returns list of temporarily unspendable outputs.\n"
2763  "See the lockunspent call to lock and unlock transactions for "
2764  "spending.\n",
2765  {},
2767  "",
2768  "",
2769  {
2771  "",
2772  "",
2773  {
2774  {RPCResult::Type::STR_HEX, "txid",
2775  "The transaction id locked"},
2776  {RPCResult::Type::NUM, "vout", "The vout value"},
2777  }},
2778  }},
2779  RPCExamples{
2780  "\nList the unspent transactions\n" +
2781  HelpExampleCli("listunspent", "") +
2782  "\nLock an unspent transaction\n" +
2783  HelpExampleCli("lockunspent", "false "
2784  "\"[{\\\"txid\\\":"
2785  "\\\"a08e6907dbbd3d809776dbfc5d82e371"
2786  "b764ed838b5655e72f463568df1aadf0\\\""
2787  ",\\\"vout\\\":1}]\"") +
2788  "\nList the locked transactions\n" +
2789  HelpExampleCli("listlockunspent", "") +
2790  "\nUnlock the transaction again\n" +
2791  HelpExampleCli("lockunspent", "true "
2792  "\"[{\\\"txid\\\":"
2793  "\\\"a08e6907dbbd3d809776dbfc5d82e371"
2794  "b764ed838b5655e72f463568df1aadf0\\\""
2795  ",\\\"vout\\\":1}]\"") +
2796  "\nAs a JSON-RPC call\n" + HelpExampleRpc("listlockunspent", "")},
2797  }
2798  .Check(request);
2799 
2800  LOCK(pwallet->cs_wallet);
2801 
2802  std::vector<COutPoint> vOutpts;
2803  pwallet->ListLockedCoins(vOutpts);
2804 
2805  UniValue ret(UniValue::VARR);
2806 
2807  for (const COutPoint &output : vOutpts) {
2809 
2810  o.pushKV("txid", output.GetTxId().GetHex());
2811  o.pushKV("vout", int(output.GetN()));
2812  ret.push_back(o);
2813  }
2814 
2815  return ret;
2816 }
2817 
2818 static UniValue settxfee(const Config &config, const JSONRPCRequest &request) {
2819  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2820  CWallet *const pwallet = wallet.get();
2821 
2822  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2823  return NullUniValue;
2824  }
2825 
2826  RPCHelpMan{
2827  "settxfee",
2828  "Set the transaction fee per kB for this wallet. Overrides the "
2829  "global -paytxfee command line parameter.\n"
2830  "Can be deactivated by passing 0 as the fee. In that case automatic "
2831  "fee selection will be used by default.\n",
2832  {
2834  "The transaction fee in " + CURRENCY_UNIT + "/kB"},
2835  },
2836  RPCResult{RPCResult::Type::BOOL, "", "Returns true if successful"},
2837  RPCExamples{HelpExampleCli("settxfee", "0.00001") +
2838  HelpExampleRpc("settxfee", "0.00001")},
2839  }
2840  .Check(request);
2841 
2842  LOCK(pwallet->cs_wallet);
2843 
2844  Amount nAmount = AmountFromValue(request.params[0]);
2845  CFeeRate tx_fee_rate(nAmount, 1000);
2846  CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
2847  if (tx_fee_rate == CFeeRate()) {
2848  // automatic selection
2849  } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
2850  throw JSONRPCError(
2852  strprintf("txfee cannot be less than min relay tx fee (%s)",
2853  pwallet->chain().relayMinFee().ToString()));
2854  } else if (tx_fee_rate < pwallet->m_min_fee) {
2855  throw JSONRPCError(
2857  strprintf("txfee cannot be less than wallet min fee (%s)",
2858  pwallet->m_min_fee.ToString()));
2859  } else if (tx_fee_rate > max_tx_fee_rate) {
2860  throw JSONRPCError(
2862  strprintf("txfee cannot be more than wallet max tx fee (%s)",
2863  max_tx_fee_rate.ToString()));
2864  }
2865 
2866  pwallet->m_pay_tx_fee = tx_fee_rate;
2867  return true;
2868 }
2869 
2870 static UniValue getbalances(const Config &config,
2871  const JSONRPCRequest &request) {
2872  std::shared_ptr<CWallet> const rpc_wallet =
2873  GetWalletForJSONRPCRequest(request);
2874  if (!EnsureWalletIsAvailable(rpc_wallet.get(), request.fHelp)) {
2875  return NullUniValue;
2876  }
2877  CWallet &wallet = *rpc_wallet;
2878 
2879  RPCHelpMan{
2880  "getbalances",
2881  "Returns an object with all balances in " + CURRENCY_UNIT + ".\n",
2882  {},
2884  "",
2885  "",
2886  {
2888  "mine",
2889  "balances from outputs that the wallet can sign",
2890  {
2891  {RPCResult::Type::STR_AMOUNT, "trusted",
2892  "trusted balance (outputs created by the wallet or "
2893  "confirmed outputs)"},
2894  {RPCResult::Type::STR_AMOUNT, "untrusted_pending",
2895  "untrusted pending balance (outputs created by "
2896  "others that are in the mempool)"},
2897  {RPCResult::Type::STR_AMOUNT, "immature",
2898  "balance from immature coinbase outputs"},
2899  {RPCResult::Type::STR_AMOUNT, "used",
2900  "(only present if avoid_reuse is set) balance from "
2901  "coins sent to addresses that were previously "
2902  "spent from (potentially privacy violating)"},
2903  }},
2905  "watchonly",
2906  "watchonly balances (not present if wallet does not "
2907  "watch anything)",
2908  {
2909  {RPCResult::Type::STR_AMOUNT, "trusted",
2910  "trusted balance (outputs created by the wallet or "
2911  "confirmed outputs)"},
2912  {RPCResult::Type::STR_AMOUNT, "untrusted_pending",
2913  "untrusted pending balance (outputs created by "
2914  "others that are in the mempool)"},
2915  {RPCResult::Type::STR_AMOUNT, "immature",
2916  "balance from immature coinbase outputs"},
2917  }},
2918  }},
2919  RPCExamples{HelpExampleCli("getbalances", "") +
2920  HelpExampleRpc("getbalances", "")},
2921  }
2922  .Check(request);
2923 
2924  // Make sure the results are valid at least up to the most recent block
2925  // the user could have gotten from another RPC command prior to now
2927 
2928  LOCK(wallet.cs_wallet);
2929 
2930  const auto bal = wallet.GetBalance();
2931  UniValue balances{UniValue::VOBJ};
2932  {
2933  UniValue balances_mine{UniValue::VOBJ};
2934  balances_mine.pushKV("trusted", ValueFromAmount(bal.m_mine_trusted));
2935  balances_mine.pushKV("untrusted_pending",
2936  ValueFromAmount(bal.m_mine_untrusted_pending));
2937  balances_mine.pushKV("immature", ValueFromAmount(bal.m_mine_immature));
2939  // If the AVOID_REUSE flag is set, bal has been set to just the
2940  // un-reused address balance. Get the total balance, and then
2941  // subtract bal to get the reused address balance.
2942  const auto full_bal = wallet.GetBalance(0, false);
2943  balances_mine.pushKV(
2944  "used", ValueFromAmount(full_bal.m_mine_trusted +
2945  full_bal.m_mine_untrusted_pending -
2946  bal.m_mine_trusted -
2947  bal.m_mine_untrusted_pending));
2948  }
2949  balances.pushKV("mine", balances_mine);
2950  }
2951  auto spk_man = wallet.GetLegacyScriptPubKeyMan();
2952  if (spk_man && spk_man->HaveWatchOnly()) {
2953  UniValue balances_watchonly{UniValue::VOBJ};
2954  balances_watchonly.pushKV("trusted",
2955  ValueFromAmount(bal.m_watchonly_trusted));
2956  balances_watchonly.pushKV(
2957  "untrusted_pending",
2958  ValueFromAmount(bal.m_watchonly_untrusted_pending));
2959  balances_watchonly.pushKV("immature",
2960  ValueFromAmount(bal.m_watchonly_immature));
2961  balances.pushKV("watchonly", balances_watchonly);
2962  }
2963  return balances;
2964 }
2965 
2966 static UniValue getwalletinfo(const Config &config,
2967  const JSONRPCRequest &request) {
2968  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
2969  const CWallet *const pwallet = wallet.get();
2970 
2971  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
2972  return NullUniValue;
2973  }
2974 
2975  RPCHelpMan{
2976  "getwalletinfo",
2977  "Returns an object containing various wallet state info.\n",
2978  {},
2979  RPCResult{
2981  "",
2982  "",
2983  {{
2984  {RPCResult::Type::STR, "walletname", "the wallet name"},
2985  {RPCResult::Type::NUM, "walletversion", "the wallet version"},
2986  {RPCResult::Type::STR_AMOUNT, "balance",
2987  "DEPRECATED. Identical to getbalances().mine.trusted"},
2988  {RPCResult::Type::STR_AMOUNT, "unconfirmed_balance",
2989  "DEPRECATED. Identical to "
2990  "getbalances().mine.untrusted_pending"},
2991  {RPCResult::Type::STR_AMOUNT, "immature_balance",
2992  "DEPRECATED. Identical to getbalances().mine.immature"},
2993  {RPCResult::Type::NUM, "txcount",
2994  "the total number of transactions in the wallet"},
2995  {RPCResult::Type::NUM_TIME, "keypoololdest",
2996  "the " + UNIX_EPOCH_TIME +
2997  " of the oldest pre-generated key in the key pool. Legacy "
2998  "wallets only."},
2999  {RPCResult::Type::NUM, "keypoolsize",
3000  "how many new keys are pre-generated (only counts external "
3001  "keys)"},
3002  {RPCResult::Type::NUM, "keypoolsize_hd_internal",
3003  "how many new keys are pre-generated for internal use (used "
3004  "for change outputs, only appears if the wallet is using this "
3005  "feature, otherwise external keys are used)"},
3006  {RPCResult::Type::NUM_TIME, "unlocked_until",
3007  "the " + UNIX_EPOCH_TIME +
3008  " until which the wallet is unlocked for transfers, or 0 "
3009  "if the wallet is locked"},
3010  {RPCResult::Type::STR_AMOUNT, "paytxfee",
3011  "the transaction fee configuration, set in " + CURRENCY_UNIT +
3012  "/kB"},
3013  {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true,
3014  "the Hash160 of the HD seed (only present when HD is "
3015  "enabled)"},
3016  {RPCResult::Type::BOOL, "private_keys_enabled",
3017  "false if privatekeys are disabled for this wallet (enforced "
3018  "watch-only wallet)"},
3020  "scanning",
3021  "current scanning details, or false if no scan is in progress",
3022  {
3023  {RPCResult::Type::NUM, "duration",
3024  "elapsed seconds since scan start"},
3025  {RPCResult::Type::NUM, "progress",
3026  "scanning progress percentage [0.0, 1.0]"},
3027  }},
3028  {RPCResult::Type::BOOL, "avoid_reuse",
3029  "whether this wallet tracks clean/dirty coins in terms of "
3030  "reuse"},
3031  {RPCResult::Type::BOOL, "descriptors",
3032  "whether this wallet uses descriptors for scriptPubKey "
3033  "management"},
3034  }},
3035  },
3036  RPCExamples{HelpExampleCli("getwalletinfo", "") +
3037  HelpExampleRpc("getwalletinfo", "")},
3038  }
3039  .Check(request);
3040 
3041  // Make sure the results are valid at least up to the most recent block
3042  // the user could have gotten from another RPC command prior to now
3043  pwallet->BlockUntilSyncedToCurrentChain();
3044 
3045  LOCK(pwallet->cs_wallet);
3046 
3047  UniValue obj(UniValue::VOBJ);
3048 
3049  size_t kpExternalSize = pwallet->KeypoolCountExternalKeys();
3050  const auto bal = pwallet->GetBalance();
3051  int64_t kp_oldest = pwallet->GetOldestKeyPoolTime();
3052  obj.pushKV("walletname", pwallet->GetName());
3053  obj.pushKV("walletversion", pwallet->GetVersion());
3054  obj.pushKV("balance", ValueFromAmount(bal.m_mine_trusted));
3055  obj.pushKV("unconfirmed_balance",
3056  ValueFromAmount(bal.m_mine_untrusted_pending));
3057  obj.pushKV("immature_balance", ValueFromAmount(bal.m_mine_immature));
3058  obj.pushKV("txcount", (int)pwallet->mapWallet.size());
3059  if (kp_oldest > 0) {
3060  obj.pushKV("keypoololdest", kp_oldest);
3061  }
3062  obj.pushKV("keypoolsize", (int64_t)kpExternalSize);
3063 
3064  LegacyScriptPubKeyMan *spk_man = pwallet->GetLegacyScriptPubKeyMan();
3065  if (spk_man) {
3066  CKeyID seed_id = spk_man->GetHDChain().seed_id;
3067  if (!seed_id.IsNull()) {
3068  obj.pushKV("hdseedid", seed_id.GetHex());
3069  }
3070  }
3071 
3072  if (pwallet->CanSupportFeature(FEATURE_HD_SPLIT)) {
3073  obj.pushKV("keypoolsize_hd_internal",
3074  int64_t(pwallet->GetKeyPoolSize() - kpExternalSize));
3075  }
3076  if (pwallet->IsCrypted()) {
3077  obj.pushKV("unlocked_until", pwallet->nRelockTime);
3078  }
3079  obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
3080  obj.pushKV("private_keys_enabled",
3082  if (pwallet->IsScanning()) {
3083  UniValue scanning(UniValue::VOBJ);
3084  scanning.pushKV("duration", pwallet->ScanningDuration() / 1000);
3085  scanning.pushKV("progress", pwallet->ScanningProgress());
3086  obj.pushKV("scanning", scanning);
3087  } else {
3088  obj.pushKV("scanning", false);
3089  }
3090  obj.pushKV("avoid_reuse",
3092  obj.pushKV("descriptors",
3094  return obj;
3095 }
3096 
3097 static UniValue listwalletdir(const Config &config,
3098  const JSONRPCRequest &request) {
3099  RPCHelpMan{
3100  "listwalletdir",
3101  "Returns a list of wallets in the wallet directory.\n",
3102  {},
3103  RPCResult{
3105  "",
3106  "",
3107  {
3109  "wallets",
3110  "",
3111  {
3113  "",
3114  "",
3115  {
3116  {RPCResult::Type::STR, "name", "The wallet name"},
3117  }},
3118  }},
3119  }},
3120  RPCExamples{HelpExampleCli("listwalletdir", "") +
3121  HelpExampleRpc("listwalletdir", "")},
3122  }
3123  .Check(request);
3124 
3125  UniValue wallets(UniValue::VARR);
3126  for (const auto &path : ListWalletDir()) {
3127  UniValue wallet(UniValue::VOBJ);
3128  wallet.pushKV("name", path.string());
3129  wallets.push_back(wallet);
3130  }
3131 
3132  UniValue result(UniValue::VOBJ);
3133  result.pushKV("wallets", wallets);
3134  return result;
3135 }
3136 
3137 static UniValue listwallets(const Config &config,
3138  const JSONRPCRequest &request) {
3139  RPCHelpMan{
3140  "listwallets",
3141  "Returns a list of currently loaded wallets.\n"
3142  "For full information on the wallet, use \"getwalletinfo\"\n",
3143  {},
3145  "",
3146  "",
3147  {
3148  {RPCResult::Type::STR, "walletname", "the wallet name"},
3149  }},
3150  RPCExamples{HelpExampleCli("listwallets", "") +
3151  HelpExampleRpc("listwallets", "")},
3152  }
3153  .Check(request);
3154 
3155  UniValue obj(UniValue::VARR);
3156 
3157  for (const std::shared_ptr<CWallet> &wallet : GetWallets()) {
3158  if (!EnsureWalletIsAvailable(wallet.get(), request.fHelp)) {
3159  return NullUniValue;
3160  }
3161 
3162  LOCK(wallet->cs_wallet);
3163 
3164  obj.push_back(wallet->GetName());
3165  }
3166 
3167  return obj;
3168 }
3169 
3170 static UniValue loadwallet(const Config &config,
3171  const JSONRPCRequest &request) {
3172  RPCHelpMan{
3173  "loadwallet",
3174  "Loads a wallet from a wallet file or directory."
3175  "\nNote that all wallet command-line options used when starting "
3176  "bitcoind will be"
3177  "\napplied to the new wallet (eg -zapwallettxes, rescan, etc).\n",
3178  {
3180  "The wallet directory or .dat file."},
3181  },
3183  "",
3184  "",
3185  {
3186  {RPCResult::Type::STR, "name",
3187  "The wallet name if loaded successfully."},
3188  {RPCResult::Type::STR, "warning",
3189  "Warning message if wallet was not loaded cleanly."},
3190  }},
3191  RPCExamples{HelpExampleCli("loadwallet", "\"test.dat\"") +
3192  HelpExampleRpc("loadwallet", "\"test.dat\"")},
3193  }
3194  .Check(request);
3195 
3196  const CChainParams &chainParams = config.GetChainParams();
3197 
3198  WalletContext &context = EnsureWalletContext(request.context);
3199  WalletLocation location(request.params[0].get_str());
3200 
3201  if (!location.Exists()) {
3203  "Wallet " + location.GetName() + " not found.");
3204  } else if (fs::is_directory(location.GetPath())) {
3205  // The given filename is a directory. Check that there's a wallet.dat
3206  // file.
3207  fs::path wallet_dat_file = location.GetPath() / "wallet.dat";
3208  if (fs::symlink_status(wallet_dat_file).type() == fs::file_not_found) {
3210  "Directory " + location.GetName() +
3211  " does not contain a wallet.dat file.");
3212  }
3213  }
3214 
3216  std::vector<bilingual_str> warnings;
3217  std::shared_ptr<CWallet> const wallet =
3218  LoadWallet(chainParams, *context.chain, location, error, warnings);
3219  if (!wallet) {
3220  throw JSONRPCError(RPC_WALLET_ERROR, error.original);
3221  }
3222 
3223  UniValue obj(UniValue::VOBJ);
3224  obj.pushKV("name", wallet->GetName());
3225  obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
3226 
3227  return obj;
3228 }
3229 
3230 static UniValue setwalletflag(const Config &config,
3231  const JSONRPCRequest &request) {
3232  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3233  CWallet *const pwallet = wallet.get();
3234 
3235  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3236  return NullUniValue;
3237  }
3238 
3239  std::string flags = "";
3240  for (auto &it : WALLET_FLAG_MAP) {
3241  if (it.second & MUTABLE_WALLET_FLAGS) {
3242  flags += (flags == "" ? "" : ", ") + it.first;
3243  }
3244  }
3245  RPCHelpMan{
3246  "setwalletflag",
3247  "Change the state of the given wallet flag for a wallet.\n",
3248  {
3250  "The name of the flag to change. Current available flags: " +
3251  flags},
3252  {"value", RPCArg::Type::BOOL, /* default */ "true",
3253  "The new state."},
3254  },
3256  "",
3257  "",
3258  {
3259  {RPCResult::Type::STR, "flag_name",
3260  "The name of the flag that was modified"},
3261  {RPCResult::Type::BOOL, "flag_state",
3262  "The new state of the flag"},
3263  {RPCResult::Type::STR, "warnings",
3264  "Any warnings associated with the change"},
3265  }},
3266  RPCExamples{HelpExampleCli("setwalletflag", "avoid_reuse") +
3267  HelpExampleRpc("setwalletflag", "\"avoid_reuse\"")},
3268  }
3269  .Check(request);
3270 
3271  std::string flag_str = request.params[0].get_str();
3272  bool value = request.params[1].isNull() || request.params[1].get_bool();
3273 
3274  if (!WALLET_FLAG_MAP.count(flag_str)) {
3276  strprintf("Unknown wallet flag: %s", flag_str));
3277  }
3278 
3279  auto flag = WALLET_FLAG_MAP.at(flag_str);
3280 
3281  if (!(flag & MUTABLE_WALLET_FLAGS)) {
3283  strprintf("Wallet flag is immutable: %s", flag_str));
3284  }
3285 
3286  UniValue res(UniValue::VOBJ);
3287 
3288  if (pwallet->IsWalletFlagSet(flag) == value) {
3290  strprintf("Wallet flag is already set to %s: %s",
3291  value ? "true" : "false", flag_str));
3292  }
3293 
3294  res.pushKV("flag_name", flag_str);
3295  res.pushKV("flag_state", value);
3296 
3297  if (value) {
3298  pwallet->SetWalletFlag(flag);
3299  } else {
3300  pwallet->UnsetWalletFlag(flag);
3301  }
3302 
3303  if (flag && value && WALLET_FLAG_CAVEATS.count(flag)) {
3304  res.pushKV("warnings", WALLET_FLAG_CAVEATS.at(flag));
3305  }
3306 
3307  return res;
3308 }
3309 
3310 static UniValue createwallet(const Config &config,
3311  const JSONRPCRequest &request) {
3312  RPCHelpMan{
3313  "createwallet",
3314  "Creates and loads a new wallet.\n",
3315  {
3316  {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO,
3317  "The name for the new wallet. If this is a path, the wallet will "
3318  "be created at the path location."},
3319  {"disable_private_keys", RPCArg::Type::BOOL, /* default */ "false",
3320  "Disable the possibility of private keys (only watchonlys are "
3321  "possible in this mode)."},
3322  {"blank", RPCArg::Type::BOOL, /* default */ "false",
3323  "Create a blank wallet. A blank wallet has no keys or HD seed. "
3324  "One can be set using sethdseed."},
3326  "Encrypt the wallet with this passphrase."},
3327  {"avoid_reuse", RPCArg::Type::BOOL, /* default */ "false",
3328  "Keep track of coin reuse, and treat dirty and clean coins "
3329  "differently with privacy considerations in mind."},
3330  {"descriptors", RPCArg::Type::BOOL, /* default */ "false",
3331  "Create a native descriptor wallet. The wallet will use "
3332  "descriptors internally to handle address creation"},
3333  },
3335  "",
3336  "",
3337  {
3338  {RPCResult::Type::STR, "name",
3339  "The wallet name if created successfully. If the wallet "
3340  "was created using a full path, the wallet_name will be "
3341  "the full path."},
3342  {RPCResult::Type::STR, "warning",
3343  "Warning message if wallet was not loaded cleanly."},
3344  }},
3345  RPCExamples{HelpExampleCli("createwallet", "\"testwallet\"") +
3346  HelpExampleRpc("createwallet", "\"testwallet\"")},
3347  }
3348  .Check(request);
3349 
3350  WalletContext &context = EnsureWalletContext(request.context);
3351  uint64_t flags = 0;
3352  if (!request.params[1].isNull() && request.params[1].get_bool()) {
3354  }
3355 
3356  if (!request.params[2].isNull() && request.params[2].get_bool()) {
3357  flags |= WALLET_FLAG_BLANK_WALLET;
3358  }
3359 
3360  SecureString passphrase;
3361  passphrase.reserve(100);
3362  std::vector<bilingual_str> warnings;
3363  if (!request.params[3].isNull()) {
3364  passphrase = request.params[3].get_str().c_str();
3365  if (passphrase.empty()) {
3366  // Empty string means unencrypted
3367  warnings.emplace_back(
3368  Untranslated("Empty string given as passphrase, wallet will "
3369  "not be encrypted."));
3370  }
3371  }
3372 
3373  if (!request.params[4].isNull() && request.params[4].get_bool()) {
3374  flags |= WALLET_FLAG_AVOID_REUSE;
3375  }
3376  if (!request.params[5].isNull() && request.params[5].get_bool()) {
3377  flags |= WALLET_FLAG_DESCRIPTORS;
3378  }
3379 
3381  std::shared_ptr<CWallet> wallet;
3382  WalletCreationStatus status =
3383  CreateWallet(config.GetChainParams(), *context.chain, passphrase, flags,
3384  request.params[0].get_str(), error, warnings, wallet);
3385  switch (status) {
3387  throw JSONRPCError(RPC_WALLET_ERROR, error.original);
3391  break;
3392  // no default case, so the compiler can warn about missing cases
3393  }
3394 
3395  UniValue obj(UniValue::VOBJ);
3396  obj.pushKV("name", wallet->GetName());
3397  obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
3398 
3399  return obj;
3400 }
3401 
3402 static UniValue unloadwallet(const Config &config,
3403  const JSONRPCRequest &request) {
3404  RPCHelpMan{
3405  "unloadwallet",
3406  "Unloads the wallet referenced by the request endpoint otherwise "
3407  "unloads the wallet specified in the argument.\n"
3408  "Specifying the wallet name on a wallet endpoint is invalid.",
3409  {
3410  {"wallet_name", RPCArg::Type::STR,
3411  /* default */ "the wallet name from the RPC request",
3412  "The name of the wallet to unload."},
3413  },
3415  RPCExamples{HelpExampleCli("unloadwallet", "wallet_name") +
3416  HelpExampleRpc("unloadwallet", "wallet_name")},
3417  }
3418  .Check(request);
3419 
3420  std::string wallet_name;
3421  if (GetWalletNameFromJSONRPCRequest(request, wallet_name)) {
3422  if (!request.params[0].isNull()) {
3424  "Cannot unload the requested wallet");
3425  }
3426  } else {
3427  wallet_name = request.params[0].get_str();
3428  }
3429 
3430  std::shared_ptr<CWallet> wallet = GetWallet(wallet_name);
3431  if (!wallet) {
3433  "Requested wallet does not exist or is not loaded");
3434  }
3435 
3436  // Release the "main" shared pointer and prevent further notifications.
3437  // Note that any attempt to load the same wallet would fail until the wallet
3438  // is destroyed (see CheckUniqueFileid).
3439  if (!RemoveWallet(wallet)) {
3440  throw JSONRPCError(RPC_MISC_ERROR, "Requested wallet already unloaded");
3441  }
3442 
3443  UnloadWallet(std::move(wallet));
3444 
3445  return NullUniValue;
3446 }
3447 
3448 static UniValue listunspent(const Config &config,
3449  const JSONRPCRequest &request) {
3450  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3451  const CWallet *const pwallet = wallet.get();
3452 
3453  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3454  return NullUniValue;
3455  }
3456 
3457  RPCHelpMan{
3458  "listunspent",
3459  "Returns array of unspent transaction outputs\n"
3460  "with between minconf and maxconf (inclusive) confirmations.\n"
3461  "Optionally filter to only include txouts paid to specified "
3462  "addresses.\n",
3463  {
3464  {"minconf", RPCArg::Type::NUM, /* default */ "1",
3465  "The minimum confirmations to filter"},
3466  {"maxconf", RPCArg::Type::NUM, /* default */ "9999999",
3467  "The maximum confirmations to filter"},
3468  {
3469  "addresses",
3471  /* default */ "empty array",
3472  "The bitcoin addresses to filter",
3473  {
3475  "bitcoin address"},
3476  },
3477  },
3478  {"include_unsafe", RPCArg::Type::BOOL, /* default */ "true",
3479  "Include outputs that are not safe to spend\n"
3480  " See description of \"safe\" attribute below."},
3481  {"query_options",
3484  "JSON with query options",
3485  {
3486  {"minimumAmount", RPCArg::Type::AMOUNT, /* default */ "0",
3487  "Minimum value of each UTXO in " + CURRENCY_UNIT + ""},
3488  {"maximumAmount", RPCArg::Type::AMOUNT,
3489  /* default */ "unlimited",
3490  "Maximum value of each UTXO in " + CURRENCY_UNIT + ""},
3491  {"maximumCount", RPCArg::Type::NUM, /* default */ "unlimited",
3492  "Maximum number of UTXOs"},
3493  {"minimumSumAmount", RPCArg::Type::AMOUNT,
3494  /* default */ "unlimited",
3495  "Minimum sum value of all UTXOs in " + CURRENCY_UNIT + ""},
3496  },
3497  "query_options"},
3498  },
3499  RPCResult{
3501  "",
3502  "",
3503  {
3505  "",
3506  "",
3507  {
3508  {RPCResult::Type::STR_HEX, "txid", "the transaction id"},
3509  {RPCResult::Type::NUM, "vout", "the vout value"},
3510  {RPCResult::Type::STR, "address", "the bitcoin address"},
3511  {RPCResult::Type::STR, "label",
3512  "The associated label, or \"\" for the default label"},
3513  {RPCResult::Type::STR, "scriptPubKey", "the script key"},
3514  {RPCResult::Type::STR_AMOUNT, "amount",
3515  "the transaction output amount in " + CURRENCY_UNIT},
3516  {RPCResult::Type::NUM, "confirmations",
3517  "The number of confirmations"},
3518  {RPCResult::Type::STR_HEX, "redeemScript",
3519  "The redeemScript if scriptPubKey is P2SH"},
3520  {RPCResult::Type::BOOL, "spendable",
3521  "Whether we have the private keys to spend this output"},
3522  {RPCResult::Type::BOOL, "solvable",
3523  "Whether we know how to spend this output, ignoring the "
3524  "lack of keys"},
3525  {RPCResult::Type::BOOL, "reused",
3526  "(only present if avoid_reuse is set) Whether this "
3527  "output is reused/dirty (sent to an address that was "
3528  "previously spent from)"},
3529  {RPCResult::Type::STR, "desc",
3530  "(only when solvable) A descriptor for spending this "
3531  "output"},
3532  {RPCResult::Type::BOOL, "safe",
3533  "Whether this output is considered safe to spend. "
3534  "Unconfirmed transactions\n"
3535  "from outside keys and unconfirmed replacement "
3536  "transactions are considered unsafe\n"
3537  "and are not eligible for spending by fundrawtransaction "
3538  "and sendtoaddress."},
3539  }},
3540  }},
3541  RPCExamples{
3542  HelpExampleCli("listunspent", "") +
3543  HelpExampleCli("listunspent",
3544  "6 9999999 "
3545  "\"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\","
3546  "\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") +
3547  HelpExampleRpc("listunspent",
3548  "6, 9999999 "
3549  "\"[\\\"1PGFqEzfmQch1gKD3ra4k18PNj3tTUUSqg\\\","
3550  "\\\"1LtvqCaApEdUGFkpKMM4MstjcaL4dKg8SP\\\"]\"") +
3552  "listunspent",
3553  "6 9999999 '[]' true '{ \"minimumAmount\": 0.005 }'") +
3555  "listunspent",
3556  "6, 9999999, [] , true, { \"minimumAmount\": 0.005 } ")},
3557  }
3558  .Check(request);
3559 
3560  int nMinDepth = 1;
3561  if (!request.params[0].isNull()) {
3563  nMinDepth = request.params[0].get_int();
3564  }
3565 
3566  int nMaxDepth = 9999999;
3567  if (!request.params[1].isNull()) {
3569  nMaxDepth = request.params[1].get_int();
3570  }
3571 
3572  std::set<CTxDestination> destinations;
3573  if (!request.params[2].isNull()) {
3575  UniValue inputs = request.params[2].get_array();
3576  for (size_t idx = 0; idx < inputs.size(); idx++) {
3577  const UniValue &input = inputs[idx];
3578  CTxDestination dest =
3579  DecodeDestination(input.get_str(), wallet->GetChainParams());
3580  if (!IsValidDestination(dest)) {
3582  std::string("Invalid Bitcoin address: ") +
3583  input.get_str());
3584  }
3585  if (!destinations.insert(dest).second) {
3586  throw JSONRPCError(
3588  std::string("Invalid parameter, duplicated address: ") +
3589  input.get_str());
3590  }
3591  }
3592  }
3593 
3594  bool include_unsafe = true;
3595  if (!request.params[3].isNull()) {
3597  include_unsafe = request.params[3].get_bool();
3598  }
3599 
3600  Amount nMinimumAmount = Amount::zero();
3601  Amount nMaximumAmount = MAX_MONEY;
3602  Amount nMinimumSumAmount = MAX_MONEY;
3603  uint64_t nMaximumCount = 0;
3604 
3605  if (!request.params[4].isNull()) {
3606  const UniValue &options = request.params[4].get_obj();
3607 
3608  if (options.exists("minimumAmount")) {
3609  nMinimumAmount = AmountFromValue(options["minimumAmount"]);
3610  }
3611 
3612  if (options.exists("maximumAmount")) {
3613  nMaximumAmount = AmountFromValue(options["maximumAmount"]);
3614  }
3615 
3616  if (options.exists("minimumSumAmount")) {
3617  nMinimumSumAmount = AmountFromValue(options["minimumSumAmount"]);
3618  }
3619 
3620  if (options.exists("maximumCount")) {
3621  nMaximumCount = options["maximumCount"].get_int64();
3622  }
3623  }
3624 
3625  // Make sure the results are valid at least up to the most recent block
3626  // the user could have gotten from another RPC command prior to now
3627  pwallet->BlockUntilSyncedToCurrentChain();
3628 
3629  UniValue results(UniValue::VARR);
3630  std::vector<COutput> vecOutputs;
3631  {
3632  CCoinControl cctl;
3633  cctl.m_avoid_address_reuse = false;
3634  cctl.m_min_depth = nMinDepth;
3635  cctl.m_max_depth = nMaxDepth;
3636  LOCK(pwallet->cs_wallet);
3637  pwallet->AvailableCoins(vecOutputs, !include_unsafe, &cctl,
3638  nMinimumAmount, nMaximumAmount,
3639  nMinimumSumAmount, nMaximumCount);
3640  }
3641 
3642  LOCK(pwallet->cs_wallet);
3643 
3644  const bool avoid_reuse = pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE);
3645 
3646  for (const COutput &out : vecOutputs) {
3647  CTxDestination address;
3648  const CScript &scriptPubKey = out.tx->tx->vout[out.i].scriptPubKey;
3649  bool fValidAddress = ExtractDestination(scriptPubKey, address);
3650  bool reused =
3651  avoid_reuse && pwallet->IsSpentKey(out.tx->GetId(), out.i);
3652 
3653  if (destinations.size() &&
3654  (!fValidAddress || !destinations.count(address))) {
3655  continue;
3656  }
3657 
3658  UniValue entry(UniValue::VOBJ);
3659  entry.pushKV("txid", out.tx->GetId().GetHex());
3660  entry.pushKV("vout", out.i);
3661 
3662  if (fValidAddress) {
3663  entry.pushKV("address", EncodeDestination(address, config));
3664 
3665  const auto *address_book_entry =
3666  pwallet->FindAddressBookEntry(address);
3667  if (address_book_entry) {
3668  entry.pushKV("label", address_book_entry->GetLabel());
3669  }
3670 
3671  std::unique_ptr<SigningProvider> provider =
3672  pwallet->GetSolvingProvider(scriptPubKey);
3673  if (provider) {
3674  if (scriptPubKey.IsPayToScriptHash()) {
3675  const CScriptID &hash =
3676  CScriptID(boost::get<ScriptHash>(address));
3677  CScript redeemScript;
3678  if (provider->GetCScript(hash, redeemScript)) {
3679  entry.pushKV(
3680  "redeemScript",
3681  HexStr(redeemScript.begin(), redeemScript.end()));
3682  }
3683  }
3684  }
3685  }
3686 
3687  entry.pushKV("scriptPubKey",
3688  HexStr(scriptPubKey.begin(), scriptPubKey.end()));
3689  entry.pushKV("amount", ValueFromAmount(out.tx->tx->vout[out.i].nValue));
3690  entry.pushKV("confirmations", out.nDepth);
3691  entry.pushKV("spendable", out.fSpendable);
3692  entry.pushKV("solvable", out.fSolvable);
3693  if (out.fSolvable) {
3694  std::unique_ptr<SigningProvider> provider =
3695  pwallet->GetSolvingProvider(scriptPubKey);
3696  if (provider) {
3697  auto descriptor = InferDescriptor(scriptPubKey, *provider);
3698  entry.pushKV("desc", descriptor->ToString());
3699  }
3700  }
3701  if (avoid_reuse) {
3702  entry.pushKV("reused", reused);
3703  }
3704  entry.pushKV("safe", out.fSafe);
3705  results.push_back(entry);
3706  }
3707 
3708  return results;
3709 }
3710 
3712  Amount &fee_out, int &change_position, UniValue options,
3713  CCoinControl &coinControl) {
3714  // Make sure the results are valid at least up to the most recent block
3715  // the user could have gotten from another RPC command prior to now
3716  pwallet->BlockUntilSyncedToCurrentChain();
3717 
3718  change_position = -1;
3719  bool lockUnspents = false;
3720  UniValue subtractFeeFromOutputs;
3721  std::set<int> setSubtractFeeFromOutputs;
3722 
3723  if (!options.isNull()) {
3724  if (options.type() == UniValue::VBOOL) {
3725  // backward compatibility bool only fallback
3726  coinControl.fAllowWatchOnly = options.get_bool();
3727  } else {
3730  options,
3731  {
3732  {"add_inputs", UniValueType(UniValue::VBOOL)},
3733  {"changeAddress", UniValueType(UniValue::VSTR)},
3734  {"changePosition", UniValueType(UniValue::VNUM)},
3735  {"includeWatching", UniValueType(UniValue::VBOOL)},
3736  {"lockUnspents", UniValueType(UniValue::VBOOL)},
3737  // will be checked below
3738  {"feeRate", UniValueType()},
3739  {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
3740  },
3741  true, true);
3742 
3743  if (options.exists("add_inputs")) {
3744  coinControl.m_add_inputs = options["add_inputs"].get_bool();
3745  }
3746 
3747  if (options.exists("changeAddress")) {
3748  CTxDestination dest =
3749  DecodeDestination(options["changeAddress"].get_str(),
3750  pwallet->GetChainParams());
3751 
3752  if (!IsValidDestination(dest)) {
3753  throw JSONRPCError(
3755  "changeAddress must be a valid bitcoin address");
3756  }
3757 
3758  coinControl.destChange = dest;
3759  }
3760 
3761  if (options.exists("changePosition")) {
3762  change_position = options["changePosition"].get_int();
3763  }
3764 
3765  coinControl.fAllowWatchOnly =
3766  ParseIncludeWatchonly(options["includeWatching"], *pwallet);
3767 
3768  if (options.exists("lockUnspents")) {
3769  lockUnspents = options["lockUnspents"].get_bool();
3770  }
3771 
3772  if (options.exists("feeRate")) {
3773  coinControl.m_feerate =
3774  CFeeRate(AmountFromValue(options["feeRate"]));
3775  coinControl.fOverrideFeeRate = true;
3776  }
3777 
3778  if (options.exists("subtractFeeFromOutputs")) {
3779  subtractFeeFromOutputs =
3780  options["subtractFeeFromOutputs"].get_array();
3781  }
3782  }
3783  } else {
3784  // if options is null and not a bool
3785  coinControl.fAllowWatchOnly =
3787  }
3788 
3789  if (tx.vout.size() == 0) {
3791  "TX must have at least one output");
3792  }
3793 
3794  if (change_position != -1 &&
3795  (change_position < 0 ||
3796  (unsigned int)change_position > tx.vout.size())) {
3798  "changePosition out of bounds");
3799  }
3800 
3801  for (size_t idx = 0; idx < subtractFeeFromOutputs.size(); idx++) {
3802  int pos = subtractFeeFromOutputs[idx].get_int();
3803  if (setSubtractFeeFromOutputs.count(pos)) {
3804  throw JSONRPCError(
3806  strprintf("Invalid parameter, duplicated position: %d", pos));
3807  }
3808  if (pos < 0) {
3809  throw JSONRPCError(
3811  strprintf("Invalid parameter, negative position: %d", pos));
3812  }
3813  if (pos >= int(tx.vout.size())) {
3814  throw JSONRPCError(
3816  strprintf("Invalid parameter, position too large: %d", pos));
3817  }
3818  setSubtractFeeFromOutputs.insert(pos);
3819  }
3820 
3822 
3823  if (!pwallet->FundTransaction(tx, fee_out, change_position, error,
3824  lockUnspents, setSubtractFeeFromOutputs,
3825  coinControl)) {
3826  throw JSONRPCError(RPC_WALLET_ERROR, error.original);
3827  }
3828 }
3829 
3830 static UniValue fundrawtransaction(const Config &config,
3831  const JSONRPCRequest &request) {
3832  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3833  CWallet *const pwallet = wallet.get();
3834 
3835  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3836  return NullUniValue;
3837  }
3838 
3839  RPCHelpMan{
3840  "fundrawtransaction",
3841  "If the transaction has no inputs, they will be automatically selected "
3842  "to meet its out value.\n"
3843  "It will add at most one change output to the outputs.\n"
3844  "No existing outputs will be modified unless "
3845  "\"subtractFeeFromOutputs\" is specified.\n"
3846  "Note that inputs which were signed may need to be resigned after "
3847  "completion since in/outputs have been added.\n"
3848  "The inputs added will not be signed, use signrawtransactionwithkey or "
3849  "signrawtransactionwithwallet for that.\n"
3850  "Note that all existing inputs must have their previous output "
3851  "transaction be in the wallet.\n"
3852  "Note that all inputs selected must be of standard form and P2SH "
3853  "scripts must be\n"
3854  "in the wallet using importaddress or addmultisigaddress (to calculate "
3855  "fees).\n"
3856  "You can see whether this is the case by checking the \"solvable\" "
3857  "field in the listunspent output.\n"
3858  "Only pay-to-pubkey, multisig, and P2SH versions thereof are currently "
3859  "supported for watch-only\n",
3860  {
3862  "The hex string of the raw transaction"},
3863  {"options",
3866  "for backward compatibility: passing in a true instead of an "
3867  "object will result in {\"includeWatching\":true}",
3868  {
3869  {"add_inputs", RPCArg::Type::BOOL, /* default */ "true",
3870  "For a transaction with existing inputs, automatically "
3871  "include more if they are not enough."},
3872  {"changeAddress", RPCArg::Type::STR,
3873  /* default */ "pool address",
3874  "The bitcoin address to receive the change"},
3875  {"changePosition", RPCArg::Type::NUM, /* default */ "",
3876  "The index of the change output"},
3877  {"includeWatching", RPCArg::Type::BOOL,
3878  /* default */ "true for watch-only wallets, otherwise false",
3879  "Also select inputs which are watch only.\n"
3880  "Only solvable inputs can be used. Watch-only destinations "
3881  "are solvable if the public key and/or output script was "
3882  "imported,\n"
3883  "e.g. with 'importpubkey' or 'importmulti' with the "
3884  "'pubkeys' or 'desc' field."},
3885  {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false",
3886  "Lock selected unspent outputs"},
3887  {"feeRate", RPCArg::Type::AMOUNT, /* default */
3888  "not set: makes wallet determine the fee",
3889  "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
3890  {
3891  "subtractFeeFromOutputs",
3893  /* default */ "empty array",
3894  "The integers.\n"
3895  " The fee will be equally "
3896  "deducted from the amount of each specified output.\n"
3897  " Those recipients will "
3898  "receive less bitcoins than you enter in their "
3899  "corresponding amount field.\n"
3900  " If no outputs are "
3901  "specified here, the sender pays the fee.",
3902  {
3903  {"vout_index", RPCArg::Type::NUM,
3905  "The zero-based output index, before a change output "
3906  "is added."},
3907  },
3908  },
3909  },
3910  "options"},
3911  },
3912  RPCResult{
3914  "",
3915  "",
3916  {
3917  {RPCResult::Type::STR_HEX, "hex",
3918  "The resulting raw transaction (hex-encoded string)"},
3920  "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
3921  {RPCResult::Type::NUM, "changepos",
3922  "The position of the added change output, or -1"},
3923  }},
3924  RPCExamples{
3925  "\nCreate a transaction with no inputs\n" +
3926  HelpExampleCli("createrawtransaction",
3927  "\"[]\" \"{\\\"myaddress\\\":0.01}\"") +
3928  "\nAdd sufficient unsigned inputs to meet the output value\n" +
3929  HelpExampleCli("fundrawtransaction", "\"rawtransactionhex\"") +
3930  "\nSign the transaction\n" +
3931  HelpExampleCli("signrawtransactionwithwallet",
3932  "\"fundedtransactionhex\"") +
3933  "\nSend the transaction\n" +
3934  HelpExampleCli("sendrawtransaction", "\"signedtransactionhex\"")},
3935  }
3936  .Check(request);
3937 
3938  RPCTypeCheck(request.params, {UniValue::VSTR, UniValueType()});
3939 
3940  // parse hex string from parameter
3942  if (!DecodeHexTx(tx, request.params[0].get_str())) {
3943  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
3944  }
3945 
3946  Amount fee;
3947  int change_position;
3948  CCoinControl coin_control;
3949  // Automatically select (additional) coins. Can be overridden by
3950  // options.add_inputs.
3951  coin_control.m_add_inputs = true;
3952  FundTransaction(pwallet, tx, fee, change_position, request.params[1],
3953  coin_control);
3954 
3955  UniValue result(UniValue::VOBJ);
3956  result.pushKV("hex", EncodeHexTx(CTransaction(tx)));
3957  result.pushKV("fee", ValueFromAmount(fee));
3958  result.pushKV("changepos", change_position);
3959 
3960  return result;
3961 }
3962 
3964  const JSONRPCRequest &request) {
3965  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
3966  const CWallet *const pwallet = wallet.get();
3967 
3968  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
3969  return NullUniValue;
3970  }
3971 
3972  RPCHelpMan{
3973  "signrawtransactionwithwallet",
3974  "Sign inputs for raw transaction (serialized, hex-encoded).\n"
3975  "The second optional argument (may be null) is an array of previous "
3976  "transaction outputs that\n"
3977  "this transaction depends on but may not yet be in the block chain.\n" +
3979  {
3980  {"hexstring", RPCArg::Type::STR, RPCArg::Optional::NO,
3981  "The transaction hex string"},
3982  {
3983  "prevtxs",
3986  "The previous dependent transaction outputs",
3987  {
3988  {
3989  "",
3992  "",
3993  {
3994  {"txid", RPCArg::Type::STR_HEX,
3995  RPCArg::Optional::NO, "The transaction id"},
3997  "The output number"},
3998  {"scriptPubKey", RPCArg::Type::STR_HEX,
3999  RPCArg::Optional::NO, "script key"},
4000  {"redeemScript", RPCArg::Type::STR_HEX,
4001  RPCArg::Optional::OMITTED, "(required for P2SH)"},
4002  {"amount", RPCArg::Type::AMOUNT,
4003  RPCArg::Optional::NO, "The amount spent"},
4004  },
4005  },
4006  },
4007  },
4008  {"sighashtype", RPCArg::Type::STR, /* default */ "ALL|FORKID",
4009  "The signature hash type. Must be one of\n"
4010  " \"ALL|FORKID\"\n"
4011  " \"NONE|FORKID\"\n"
4012  " \"SINGLE|FORKID\"\n"
4013  " \"ALL|FORKID|ANYONECANPAY\"\n"
4014  " \"NONE|FORKID|ANYONECANPAY\"\n"
4015  " \"SINGLE|FORKID|ANYONECANPAY\""},
4016  },
4017  RPCResult{
4019  "",
4020  "",
4021  {
4022  {RPCResult::Type::STR_HEX, "hex",
4023  "The hex-encoded raw transaction with signature(s)"},
4024  {RPCResult::Type::BOOL, "complete",
4025  "If the transaction has a complete set of signatures"},
4027  "errors",
4028  "Script verification errors (if there are any)",
4029  {
4031  "",
4032  "",
4033  {
4034  {RPCResult::Type::STR_HEX, "txid",
4035  "The hash of the referenced, previous transaction"},
4036  {RPCResult::Type::NUM, "vout",
4037  "The index of the output to spent and used as "
4038  "input"},
4039  {RPCResult::Type::STR_HEX, "scriptSig",
4040  "The hex-encoded signature script"},
4041  {RPCResult::Type::NUM, "sequence",
4042  "Script sequence number"},
4043  {RPCResult::Type::STR, "error",
4044  "Verification or signing error related to the "
4045  "input"},
4046  }},
4047  }},
4048  }},
4049  RPCExamples{
4050  HelpExampleCli("signrawtransactionwithwallet", "\"myhex\"") +
4051  HelpExampleRpc("signrawtransactionwithwallet", "\"myhex\"")},
4052  }
4053  .Check(request);
4054 
4055  RPCTypeCheck(request.params,
4056  {UniValue::VSTR, UniValue::VARR, UniValue::VSTR}, true);
4057 
4058  CMutableTransaction mtx;
4059  if (!DecodeHexTx(mtx, request.params[0].get_str())) {
4060  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
4061  }
4062 
4063  // Sign the transaction
4064  LOCK(pwallet->cs_wallet);
4065  EnsureWalletIsUnlocked(pwallet);
4066 
4067  // Fetch previous transactions (inputs):
4068  std::map<COutPoint, Coin> coins;
4069  for (const CTxIn &txin : mtx.vin) {
4070  // Create empty map entry keyed by prevout.
4071  coins[txin.prevout];
4072  }
4073  pwallet->chain().findCoins(coins);
4074 
4075  // Parse the prevtxs array
4076  ParsePrevouts(request.params[1], nullptr, coins);
4077 
4078  SigHashType nHashType = ParseSighashString(request.params[2]);
4079  if (!nHashType.hasForkId()) {
4081  "Signature must use SIGHASH_FORKID");
4082  }
4083 
4084  // Script verification errors
4085  std::map<int, std::string> input_errors;
4086 
4087  bool complete =
4088  pwallet->SignTransaction(mtx, coins, nHashType, input_errors);
4089  UniValue result(UniValue::VOBJ);
4090  SignTransactionResultToJSON(mtx, complete, coins, input_errors, result);
4091  return result;
4092 }
4093 
4094 UniValue rescanblockchain(const Config &config, const JSONRPCRequest &request) {
4095  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4096  CWallet *const pwallet = wallet.get();
4097 
4098  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4099  return NullUniValue;
4100  }
4101 
4102  RPCHelpMan{
4103  "rescanblockchain",
4104  "Rescan the local blockchain for wallet related transactions.\n"
4105  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
4106  {
4107  {"start_height", RPCArg::Type::NUM, /* default */ "0",
4108  "block height where the rescan should start"},
4109  {"stop_height", RPCArg::Type::NUM,
4111  "the last block height that should be scanned"},
4112  },
4113  RPCResult{
4115  "",
4116  "",
4117  {
4118  {RPCResult::Type::NUM, "start_height",
4119  "The block height where the rescan started (the requested "
4120  "height or 0)"},
4121  {RPCResult::Type::NUM, "stop_height",
4122  "The height of the last rescanned block. May be null in rare "
4123  "cases if there was a reorg and the call didn't scan any "
4124  "blocks because they were already scanned in the background."},
4125  }},
4126  RPCExamples{HelpExampleCli("rescanblockchain", "100000 120000") +
4127  HelpExampleRpc("rescanblockchain", "100000, 120000")},
4128  }
4129  .Check(request);
4130 
4131  WalletRescanReserver reserver(*pwallet);
4132  if (!reserver.reserve()) {
4133  throw JSONRPCError(
4135  "Wallet is currently rescanning. Abort existing rescan or wait.");
4136  }
4137 
4138  int start_height = 0;
4139  std::optional<int> stop_height;
4140  BlockHash start_block;
4141  {
4142  LOCK(pwallet->cs_wallet);
4143  int tip_height = pwallet->GetLastBlockHeight();
4144 
4145  if (!request.params[0].isNull()) {
4146  start_height = request.params[0].get_int();
4147  if (start_height < 0 || start_height > tip_height) {
4149  "Invalid start_height");
4150  }
4151  }
4152 
4153  if (!request.params[1].isNull()) {
4154  stop_height = request.params[1].get_int();
4155  if (*stop_height < 0 || *stop_height > tip_height) {
4157  "Invalid stop_height");
4158  } else if (*stop_height < start_height) {
4159  throw JSONRPCError(
4161  "stop_height must be greater than start_height");
4162  }
4163  }
4164 
4165  // We can't rescan beyond non-pruned blocks, stop and throw an error
4166  if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(),
4167  start_height, stop_height)) {
4168  throw JSONRPCError(
4170  "Can't rescan beyond pruned data. Use RPC call "
4171  "getblockchaininfo to determine your pruned height.");
4172  }
4173 
4175  pwallet->GetLastBlockHash(), start_height,
4176  FoundBlock().hash(start_block)));
4177  }
4178 
4180  start_block, start_height, stop_height, reserver, true /* fUpdate */);
4181  switch (result.status) {
4183  break;
4185  throw JSONRPCError(
4187  "Rescan failed. Potentially corrupted data files.");
4189  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted.");
4190  // no default case, so the compiler can warn about missing cases
4191  }
4193  response.pushKV("start_height", start_height);
4194  response.pushKV("stop_height", result.last_scanned_height
4195  ? *result.last_scanned_height
4196  : UniValue());
4197  return response;
4198 }
4199 
4200 class DescribeWalletAddressVisitor : public boost::static_visitor<UniValue> {
4201 public:
4203 
4204  void ProcessSubScript(const CScript &subscript, UniValue &obj) const {
4205  // Always present: script type and redeemscript
4206  std::vector<std::vector<uint8_t>> solutions_data;
4207  txnouttype which_type = Solver(subscript, solutions_data);
4208  obj.pushKV("script", GetTxnOutputType(which_type));
4209  obj.pushKV("hex", HexStr(subscript.begin(), subscript.end()));
4210 
4211  CTxDestination embedded;
4212  if (ExtractDestination(subscript, embedded)) {
4213  // Only when the script corresponds to an address.
4214  UniValue subobj(UniValue::VOBJ);
4215  UniValue detail = DescribeAddress(embedded);
4216  subobj.pushKVs(detail);
4217  UniValue wallet_detail = boost::apply_visitor(*this, embedded);
4218  subobj.pushKVs(wallet_detail);
4219  subobj.pushKV("address", EncodeDestination(embedded, GetConfig()));
4220  subobj.pushKV("scriptPubKey",
4221  HexStr(subscript.begin(), subscript.end()));
4222  // Always report the pubkey at the top level, so that
4223  // `getnewaddress()['pubkey']` always works.
4224  if (subobj.exists("pubkey")) {
4225  obj.pushKV("pubkey", subobj["pubkey"]);
4226  }
4227  obj.pushKV("embedded", std::move(subobj));
4228  } else if (which_type == TX_MULTISIG) {
4229  // Also report some information on multisig scripts (which do not
4230  // have a corresponding address).
4231  // TODO: abstract out the common functionality between this logic
4232  // and ExtractDestinations.
4233  obj.pushKV("sigsrequired", solutions_data[0][0]);
4234  UniValue pubkeys(UniValue::VARR);
4235  for (size_t i = 1; i < solutions_data.size() - 1; ++i) {
4236  CPubKey key(solutions_data[i].begin(), solutions_data[i].end());
4237  pubkeys.push_back(HexStr(key.begin(), key.end()));
4238  }
4239  obj.pushKV("pubkeys", std::move(pubkeys));
4240  }
4241  }
4242 
4244  : provider(_provider) {}
4245 
4246  UniValue operator()(const CNoDestination &dest) const {
4247  return UniValue(UniValue::VOBJ);
4248  }
4249 
4250  UniValue operator()(const PKHash &pkhash) const {
4251  CKeyID keyID(pkhash);
4252  UniValue obj(UniValue::VOBJ);
4253  CPubKey vchPubKey;
4254  if (provider && provider->GetPubKey(keyID, vchPubKey)) {
4255  obj.pushKV("pubkey", HexStr(vchPubKey));
4256  obj.pushKV("iscompressed", vchPubKey.IsCompressed());
4257  }
4258  return obj;
4259  }
4260 
4261  UniValue operator()(const ScriptHash &scripthash) const {
4262  CScriptID scriptID(scripthash);
4263  UniValue obj(UniValue::VOBJ);
4264  CScript subscript;
4265  if (provider && provider->GetCScript(scriptID, subscript)) {
4266  ProcessSubScript(subscript, obj);
4267  }
4268  return obj;
4269  }
4270 };
4271 
4272 static UniValue DescribeWalletAddress(const CWallet *const pwallet,
4273  const CTxDestination &dest) {
4274  UniValue ret(UniValue::VOBJ);
4275  UniValue detail = DescribeAddress(dest);
4276  CScript script = GetScriptForDestination(dest);
4277  std::unique_ptr<SigningProvider> provider = nullptr;
4278  if (pwallet) {
4279  provider = pwallet->GetSolvingProvider(script);
4280  }
4281  ret.pushKVs(detail);
4282  ret.pushKVs(boost::apply_visitor(
4283  DescribeWalletAddressVisitor(provider.get()), dest));
4284  return ret;
4285 }
4286 
4289  const bool verbose) {
4290  UniValue ret(UniValue::VOBJ);
4291  if (verbose) {
4292  ret.pushKV("name", data.GetLabel());
4293  }
4294  ret.pushKV("purpose", data.purpose);
4295  return ret;
4296 }
4297 
4298 UniValue getaddressinfo(const Config &config, const JSONRPCRequest &request) {
4299  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4300  const CWallet *const pwallet = wallet.get();
4301 
4302  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4303  return NullUniValue;
4304  }
4305 
4306  RPCHelpMan{
4307  "getaddressinfo",
4308  "\nReturn information about the given bitcoin address.\n"
4309  "Some of the information will only be present if the address is in the "
4310  "active wallet.\n",
4311  {
4313  "The bitcoin address for which to get information."},
4314  },
4315  RPCResult{
4317  "",
4318  "",
4319  {
4320  {RPCResult::Type::STR, "address",
4321  "The bitcoin address validated."},
4322  {RPCResult::Type::STR_HEX, "scriptPubKey",
4323  "The hex-encoded scriptPubKey generated by the address."},
4324  {RPCResult::Type::BOOL, "ismine", "If the address is yours."},
4325  {RPCResult::Type::BOOL, "iswatchonly",
4326  "If the address is watchonly."},
4327  {RPCResult::Type::BOOL, "solvable",
4328  "If we know how to spend coins sent to this address, ignoring "
4329  "the possible lack of private keys."},
4330  {RPCResult::Type::STR, "desc", /* optional */ true,
4331  "A descriptor for spending coins sent to this address (only "
4332  "when solvable)."},
4333  {RPCResult::Type::BOOL, "isscript", "If the key is a script."},
4334  {RPCResult::Type::BOOL, "ischange",
4335  "If the address was used for change output."},
4336  {RPCResult::Type::STR, "script", /* optional */ true,
4337  "The output script type. Only if isscript is true and the "
4338  "redeemscript is known. Possible\n"
4339  " "
4340  "types: nonstandard, pubkey, pubkeyhash, scripthash, "
4341  "multisig, nulldata."},
4342  {RPCResult::Type::STR_HEX, "hex", /* optional */ true,
4343  "The redeemscript for the p2sh address."},
4345  "pubkeys",
4346  /* optional */ true,
4347  "Array of pubkeys associated with the known redeemscript "
4348  "(only if script is multisig).",
4349  {
4350  {RPCResult::Type::STR, "pubkey", ""},
4351  }},
4352  {RPCResult::Type::NUM, "sigsrequired", /* optional */ true,
4353  "The number of signatures required to spend multisig output "
4354  "(only if script is multisig)."},
4355  {RPCResult::Type::STR_HEX, "pubkey", /* optional */ true,
4356  "The hex value of the raw public key for single-key addresses "
4357  "(possibly embedded in P2SH)."},
4359  "embedded",
4360  /* optional */ true,
4361  "Information about the address embedded in P2SH, if "
4362  "relevant and known.",
4363  {
4365  "Includes all\n"
4366  " "
4367  " getaddressinfo output fields for the embedded address, "
4368  "excluding metadata (timestamp, hdkeypath,\n"
4369  "hdseedid) and relation to the wallet (ismine, "
4370  "iswatchonly)."},
4371  }},
4372  {RPCResult::Type::BOOL, "iscompressed", /* optional */ true,
4373  "If the pubkey is compressed."},
4374  {RPCResult::Type::STR, "label",
4375  "DEPRECATED. The label associated with the address. Defaults "
4376  "to \"\". Replaced by the labels array below."},
4377  {RPCResult::Type::NUM_TIME, "timestamp", /* optional */ true,
4378  "The creation time of the key, if available, expressed in " +
4379  UNIX_EPOCH_TIME + "."},
4380  {RPCResult::Type::STR, "hdkeypath", /* optional */ true,
4381  "The HD keypath, if the key is HD and available."},
4382  {RPCResult::Type::STR_HEX, "hdseedid", /* optional */ true,
4383  "The Hash160 of the HD seed."},
4384  {RPCResult::Type::STR_HEX, "hdmasterfingerprint",
4385  /* optional */ true, "The fingerprint of the master key."},
4387  "labels",
4388  "Array of labels associated with the address. Currently "
4389  "limited to one label but returned\n"
4390  "as an array to keep the API stable if multiple labels are "
4391  "enabled in the future.",
4392  {
4393  {RPCResult::Type::STR, "label name",
4394  "The label name. Defaults to \"\"."},
4396  "",
4397  "DEPRECATED, will be removed in a future version. To "
4398  "re-enable, launch bitcoind with "
4399  "`-deprecatedrpc=labelspurpose`",
4400  {
4401  {RPCResult::Type::STR, "name",
4402  "The label name. Defaults to \"\"."},
4403  {RPCResult::Type::STR, "purpose",
4404  "The purpose of the associated address (send or "
4405  "receive)."},
4406  }},
4407  }},
4408  }},
4409  RPCExamples{HelpExampleCli("getaddressinfo", EXAMPLE_ADDRESS) +
4410  HelpExampleRpc("getaddressinfo", EXAMPLE_ADDRESS)},
4411  }
4412  .Check(request);
4413 
4414  LOCK(pwallet->cs_wallet);
4415 
4416  UniValue ret(UniValue::VOBJ);
4417  CTxDestination dest = DecodeDestination(request.params[0].get_str(),
4418  wallet->GetChainParams());
4419  // Make sure the destination is valid
4420  if (!IsValidDestination(dest)) {
4421  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
4422  }
4423 
4424  std::string currentAddress = EncodeDestination(dest, config);
4425  ret.pushKV("address", currentAddress);
4426 
4427  CScript scriptPubKey = GetScriptForDestination(dest);
4428  ret.pushKV("scriptPubKey",
4429  HexStr(scriptPubKey.begin(), scriptPubKey.end()));
4430 
4431  std::unique_ptr<SigningProvider> provider =
4432  pwallet->GetSolvingProvider(scriptPubKey);
4433 
4434  isminetype mine = pwallet->IsMine(dest);
4435  ret.pushKV("ismine", bool(mine & ISMINE_SPENDABLE));
4436 
4437  bool solvable = provider && IsSolvable(*provider, scriptPubKey);
4438  ret.pushKV("solvable", solvable);
4439 
4440  if (solvable) {
4441  ret.pushKV("desc",
4442  InferDescriptor(scriptPubKey, *provider)->ToString());
4443  }
4444 
4445  ret.pushKV("iswatchonly", bool(mine & ISMINE_WATCH_ONLY));
4446 
4447  UniValue detail = DescribeWalletAddress(pwallet, dest);
4448  ret.pushKVs(detail);
4449 
4450  // DEPRECATED: Return label field if existing. Currently only one label can
4451  // be associated with an address, so the label should be equivalent to the
4452  // value of the name key/value pair in the labels array below.
4453  const auto *address_book_entry = pwallet->FindAddressBookEntry(dest);
4454  if (pwallet->chain().rpcEnableDeprecated("label") && address_book_entry) {
4455  ret.pushKV("label", address_book_entry->GetLabel());
4456  }
4457 
4458  ret.pushKV("ischange", pwallet->IsChange(scriptPubKey));
4459 
4460  ScriptPubKeyMan *spk_man = pwallet->GetScriptPubKeyMan(scriptPubKey);
4461  if (spk_man) {
4462  if (const std::unique_ptr<CKeyMetadata> meta =
4463  spk_man->GetMetadata(dest)) {
4464  ret.pushKV("timestamp", meta->nCreateTime);
4465  if (meta->has_key_origin) {
4466  ret.pushKV("hdkeypath", WriteHDKeypath(meta->key_origin.path));
4467  ret.pushKV("hdseedid", meta->hd_seed_id.GetHex());
4468  ret.pushKV("hdmasterfingerprint",
4469  HexStr(meta->key_origin.fingerprint,
4470  meta->key_origin.fingerprint + 4));
4471  }
4472  }
4473  }
4474 
4475  // Return a `labels` array containing the label associated with the address,
4476  // equivalent to the `label` field above. Currently only one label can be
4477  // associated with an address, but we return an array so the API remains
4478  // stable if we allow multiple labels to be associated with an address in
4479  // the future.
4480  UniValue labels(UniValue::VARR);
4481  if (address_book_entry) {
4482  // DEPRECATED: The previous behavior of returning an array containing a
4483  // JSON object of `name` and `purpose` key/value pairs is deprecated.
4484  if (pwallet->chain().rpcEnableDeprecated("labelspurpose")) {
4485  labels.push_back(AddressBookDataToJSON(*address_book_entry, true));
4486  } else {
4487  labels.push_back(address_book_entry->GetLabel());
4488  }
4489  }
4490  ret.pushKV("labels", std::move(labels));
4491 
4492  return ret;
4493 }
4494 
4496  const JSONRPCRequest &request) {
4497  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4498  const CWallet *const pwallet = wallet.get();
4499 
4500  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4501  return NullUniValue;
4502  }
4503 
4504  RPCHelpMan{
4505  "getaddressesbylabel",
4506  "Returns the list of addresses assigned the specified label.\n",
4507  {
4508  {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label."},
4509  },
4511  "",
4512  "json object with addresses as keys",
4513  {
4515  "address",
4516  "Information about address",
4517  {
4518  {RPCResult::Type::STR, "purpose",
4519  "Purpose of address (\"send\" for sending address, "
4520  "\"receive\" for receiving address)"},
4521  }},
4522  }},
4523  RPCExamples{HelpExampleCli("getaddressesbylabel", "\"tabby\"") +
4524  HelpExampleRpc("getaddressesbylabel", "\"tabby\"")},
4525  }
4526  .Check(request);
4527 
4528  LOCK(pwallet->cs_wallet);
4529 
4530  std::string label = LabelFromValue(request.params[0]);
4531 
4532  // Find all addresses that have the given label
4533  UniValue ret(UniValue::VOBJ);
4534  std::set<std::string> addresses;
4535  for (const std::pair<const CTxDestination, CAddressBookData> &item :
4536  pwallet->m_address_book) {
4537  if (item.second.IsChange()) {
4538  continue;
4539  }
4540  if (item.second.GetLabel() == label) {
4541  std::string address = EncodeDestination(item.first, config);
4542  // CWallet::m_address_book is not expected to contain duplicate
4543  // address strings, but build a separate set as a precaution just in
4544  // case it does.
4545  bool unique = addresses.emplace(address).second;
4546  CHECK_NONFATAL(unique);
4547  // UniValue::pushKV checks if the key exists in O(N)
4548  // and since duplicate addresses are unexpected (checked with
4549  // std::set in O(log(N))), UniValue::__pushKV is used instead,
4550  // which currently is O(1).
4551  ret.__pushKV(address, AddressBookDataToJSON(item.second, false));
4552  }
4553  }
4554 
4555  if (ret.empty()) {
4557  std::string("No addresses with label " + label));
4558  }
4559 
4560  return ret;
4561 }
4562 
4563 UniValue listlabels(const Config &config, const JSONRPCRequest &request) {
4564  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4565  const CWallet *const pwallet = wallet.get();
4566 
4567  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4568  return NullUniValue;
4569  }
4570 
4571  RPCHelpMan{
4572  "listlabels",
4573  "Returns the list of all labels, or labels that are assigned to "
4574  "addresses with a specific purpose.\n",
4575  {
4577  "Address purpose to list labels for ('send','receive'). An empty "
4578  "string is the same as not providing this argument."},
4579  },
4581  "",
4582  "",
4583  {
4584  {RPCResult::Type::STR, "label", "Label name"},
4585  }},
4586  RPCExamples{"\nList all labels\n" + HelpExampleCli("listlabels", "") +
4587  "\nList labels that have receiving addresses\n" +
4588  HelpExampleCli("listlabels", "receive") +
4589  "\nList labels that have sending addresses\n" +
4590  HelpExampleCli("listlabels", "send") +
4591  "\nAs a JSON-RPC call\n" +
4592  HelpExampleRpc("listlabels", "receive")},
4593  }
4594  .Check(request);
4595 
4596  LOCK(pwallet->cs_wallet);
4597 
4598  std::string purpose;
4599  if (!request.params[0].isNull()) {
4600  purpose = request.params[0].get_str();
4601  }
4602 
4603  // Add to a set to sort by label name, then insert into Univalue array
4604  std::set<std::string> label_set;
4605  for (const std::pair<const CTxDestination, CAddressBookData> &entry :
4606  pwallet->m_address_book) {
4607  if (entry.second.IsChange()) {
4608  continue;
4609  }
4610  if (purpose.empty() || entry.second.purpose == purpose) {
4611  label_set.insert(entry.second.GetLabel());
4612  }
4613  }
4614 
4615  UniValue ret(UniValue::VARR);
4616  for (const std::string &name : label_set) {
4617  ret.push_back(name);
4618  }
4619 
4620  return ret;
4621 }
4622 
4623 static UniValue sethdseed(const Config &config, const JSONRPCRequest &request) {
4624  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4625  CWallet *const pwallet = wallet.get();
4626 
4627  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4628  return NullUniValue;
4629  }
4630 
4631  RPCHelpMan{
4632  "sethdseed",
4633  "Set or generate a new HD wallet seed. Non-HD wallets will not be "
4634  "upgraded to being a HD wallet. Wallets that are already\n"
4635  "HD will have a new HD seed set so that new keys added to the keypool "
4636  "will be derived from this new seed.\n"
4637  "\nNote that you will need to MAKE A NEW BACKUP of your wallet after "
4638  "setting the HD wallet seed.\n" +
4640  {
4641  {"newkeypool", RPCArg::Type::BOOL, /* default */ "true",
4642  "Whether to flush old unused addresses, including change "
4643  "addresses, from the keypool and regenerate it.\n"
4644  " If true, the next address from "
4645  "getnewaddress and change address from getrawchangeaddress will "
4646  "be from this new seed.\n"
4647  " If false, addresses (including "
4648  "change addresses if the wallet already had HD Chain Split "
4649  "enabled) from the existing\n"
4650  " keypool will be used until it has "
4651  "been depleted."},
4652  {"seed", RPCArg::Type::STR, /* default */ "random seed",
4653  "The WIF private key to use as the new HD seed.\n"
4654  " The seed value can be retrieved "
4655  "using the dumpwallet command. It is the private key marked "
4656  "hdseed=1"},
4657  },
4659  RPCExamples{HelpExampleCli("sethdseed", "") +
4660  HelpExampleCli("sethdseed", "false") +
4661  HelpExampleCli("sethdseed", "true \"wifkey\"") +
4662  HelpExampleRpc("sethdseed", "true, \"wifkey\"")},
4663  }
4664  .Check(request);
4665 
4666  LegacyScriptPubKeyMan &spk_man =
4667  EnsureLegacyScriptPubKeyMan(*pwallet, true);
4668 
4669  if (pwallet->chain().isInitialBlockDownload()) {
4670  throw JSONRPCError(
4672  "Cannot set a new HD seed while still in Initial Block Download");
4673  }
4674 
4676  throw JSONRPCError(
4678  "Cannot set a HD seed to a wallet with private keys disabled");
4679  }
4680 
4681  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
4682 
4683  // Do not do anything to non-HD wallets
4684  if (!pwallet->CanSupportFeature(FEATURE_HD)) {
4685  throw JSONRPCError(
4687  "Cannot set a HD seed on a non-HD wallet. Use the upgradewallet "
4688  "RPC in order to upgrade a non-HD wallet to HD");
4689  }
4690 
4691  EnsureWalletIsUnlocked(pwallet);
4692 
4693  bool flush_key_pool = true;
4694  if (!request.params[0].isNull()) {
4695  flush_key_pool = request.params[0].get_bool();
4696  }
4697 
4698  CPubKey master_pub_key;
4699  if (request.params[1].isNull()) {
4700  master_pub_key = spk_man.GenerateNewSeed();
4701  } else {
4702  CKey key = DecodeSecret(request.params[1].get_str());
4703  if (!key.IsValid()) {
4705  "Invalid private key");
4706  }
4707 
4708  if (HaveKey(spk_man, key)) {
4710  "Already have this key (either as an HD seed or "
4711  "as a loose private key)");
4712  }
4713 
4714  master_pub_key = spk_man.DeriveNewSeed(key);
4715  }
4716 
4717  spk_man.SetHDSeed(master_pub_key);
4718  if (flush_key_pool) {
4719  spk_man.NewKeyPool();
4720  }
4721 
4722  return NullUniValue;
4723 }
4724 
4725 static UniValue walletprocesspsbt(const Config &config,
4726  const JSONRPCRequest &request) {
4727  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4728  const CWallet *const pwallet = wallet.get();
4729 
4730  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4731  return NullUniValue;
4732  }
4733 
4734  RPCHelpMan{
4735  "walletprocesspsbt",
4736  "Update a PSBT with input information from our wallet and then sign "
4737  "inputs that we can sign for." +
4739  {
4741  "The transaction base64 string"},
4742  {"sign", RPCArg::Type::BOOL, /* default */ "true",
4743  "Also sign the transaction when updating"},
4744  {"sighashtype", RPCArg::Type::STR, /* default */ "ALL|FORKID",
4745  "The signature hash type to sign with if not specified by "
4746  "the PSBT. Must be one of\n"
4747  " \"ALL|FORKID\"\n"
4748  " \"NONE|FORKID\"\n"
4749  " \"SINGLE|FORKID\"\n"
4750  " \"ALL|FORKID|ANYONECANPAY\"\n"
4751  " \"NONE|FORKID|ANYONECANPAY\"\n"
4752  " \"SINGLE|FORKID|ANYONECANPAY\""},
4753  {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true",
4754  "Includes the BIP 32 derivation paths for public keys if we know "
4755  "them"},
4756  },
4758  "",
4759  "",
4760  {
4761  {RPCResult::Type::STR, "psbt",
4762  "The base64-encoded partially signed transaction"},
4763  {RPCResult::Type::BOOL, "complete",
4764  "If the transaction has a complete set of signatures"},
4765  }},
4766  RPCExamples{HelpExampleCli("walletprocesspsbt", "\"psbt\"")},
4767  }
4768  .Check(request);
4769 
4770  RPCTypeCheck(request.params,
4771  {UniValue::VSTR, UniValue::VBOOL, UniValue::VSTR});
4772 
4773  // Unserialize the transaction
4775  std::string error;
4776  if (!DecodeBase64PSBT(psbtx, request.params[0].get_str(), error)) {
4778  strprintf("TX decode failed %s", error));
4779  }
4780 
4781  // Get the sighash type
4782  SigHashType nHashType = ParseSighashString(request.params[2]);
4783  if (!nHashType.hasForkId()) {
4785  "Signature must use SIGHASH_FORKID");
4786  }
4787 
4788  // Fill transaction with our data and also sign
4789  bool sign =
4790  request.params[1].isNull() ? true : request.params[1].get_bool();
4791  bool bip32derivs =
4792  request.params[3].isNull() ? true : request.params[3].get_bool();
4793  bool complete = true;
4794  const TransactionError err =
4795  pwallet->FillPSBT(psbtx, complete, nHashType, sign, bip32derivs);
4796  if (err != TransactionError::OK) {
4797  throw JSONRPCTransactionError(err);
4798  }
4799 
4800  UniValue result(UniValue::VOBJ);
4802  ssTx << psbtx;
4803  result.pushKV("psbt", EncodeBase64(ssTx.str()));
4804  result.pushKV("complete", complete);
4805 
4806  return result;
4807 }
4808 
4810  const JSONRPCRequest &request) {
4811  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
4812  CWallet *const pwallet = wallet.get();
4813 
4814  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
4815  return NullUniValue;
4816  }
4817 
4818  RPCHelpMan{
4819  "walletcreatefundedpsbt",
4820  "Creates and funds a transaction in the Partially Signed Transaction "
4821  "format.\n"
4822  "Implements the Creator and Updater roles.\n",
4823  {
4824  {
4825  "inputs",
4828  "The inputs. Leave empty to add inputs automatically. See "
4829  "add_inputs option.",
4830  {
4831  {
4832  "",
4835  "",
4836  {
4837  {"txid", RPCArg::Type::STR_HEX,
4838  RPCArg::Optional::NO, "The transaction id"},
4840  "The output number"},
4841  {"sequence", RPCArg::Type::NUM,
4842  RPCArg::Optional::NO, "The sequence number"},
4843  },
4844  },
4845  },
4846  },
4847  {
4848  "outputs",
4851  "The outputs (key-value pairs), where none of "
4852  "the keys are duplicated.\n"
4853  "That is, each address can only appear once and there can only "
4854  "be one 'data' object.\n"
4855  "For compatibility reasons, a dictionary, which holds the "
4856  "key-value pairs directly, is also\n"
4857  " accepted as second parameter.",
4858  {
4859  {
4860  "",
4863  "",
4864  {
4865  {"address", RPCArg::Type::AMOUNT,
4867  "A key-value pair. The key (string) is the "
4868  "bitcoin address, the value (float or string) is "
4869  "the amount in " +
4870  CURRENCY_UNIT + ""},
4871  },
4872  },
4873  {
4874  "",
4877  "",
4878  {
4879  {"data", RPCArg::Type::STR_HEX,
4881  "A key-value pair. The key must be \"data\", the "
4882  "value is hex-encoded data"},
4883  },
4884  },
4885  },
4886  },
4887  {"locktime", RPCArg::Type::NUM, /* default */ "0",
4888  "Raw locktime. Non-0 value also locktime-activates inputs\n"
4889  " Allows this transaction to be "
4890  "replaced by a transaction with higher fees. If provided, it is "
4891  "an error if explicit sequence numbers are incompatible."},
4892  {"options",
4895  "",
4896  {
4897  {"add_inputs", RPCArg::Type::BOOL, /* default */ "false",
4898  "If inputs are specified, automatically include more if they "
4899  "are not enough."},
4900  {"changeAddress", RPCArg::Type::STR_HEX,
4901  /* default */ "pool address",
4902  "The bitcoin address to receive the change"},
4903  {"changePosition", RPCArg::Type::NUM,
4904  /* default */ "random", "The index of the change output"},
4905  {"includeWatching", RPCArg::Type::BOOL,
4906  /* default */ "true for watch-only wallets, otherwise false",
4907  "Also select inputs which are watch only"},
4908  {"lockUnspents", RPCArg::Type::BOOL, /* default */ "false",
4909  "Lock selected unspent outputs"},
4910  {"feeRate", RPCArg::Type::AMOUNT, /* default */
4911  "not set: makes wallet determine the fee",
4912  "Set a specific fee rate in " + CURRENCY_UNIT + "/kB"},
4913  {
4914  "subtractFeeFromOutputs",
4916  /* default */ "empty array",
4917  "The outputs to subtract the fee from.\n"
4918  " The fee will be equally "
4919  "deducted from the amount of each specified output.\n"
4920  " Those recipients will "
4921  "receive less bitcoins than you enter in their "
4922  "corresponding amount field.\n"
4923  " If no outputs are "
4924  "specified here, the sender pays the fee.",
4925  {
4926  {"vout_index", RPCArg::Type::NUM,
4928  "The zero-based output index, before a change output "
4929  "is added."},
4930  },
4931  },
4932  },
4933  "options"},
4934  {"bip32derivs", RPCArg::Type::BOOL, /* default */ "true",
4935  "Includes the BIP 32 derivation paths for public keys if we know "
4936  "them"},
4937  },
4938  RPCResult{
4940  "",
4941  "",
4942  {
4943  {RPCResult::Type::STR, "psbt",
4944  "The resulting raw transaction (base64-encoded string)"},
4946  "Fee in " + CURRENCY_UNIT + " the resulting transaction pays"},
4947  {RPCResult::Type::NUM, "changepos",
4948  "The position of the added change output, or -1"},
4949  }},
4950  RPCExamples{
4951  "\nCreate a transaction with no inputs\n" +
4952  HelpExampleCli("walletcreatefundedpsbt",
4953  "\"[{\\\"txid\\\":\\\"myid\\\",\\\"vout\\\":0}]\" "
4954  "\"[{\\\"data\\\":\\\"00010203\\\"}]\"")},
4955  }
4956  .Check(request);
4957 
4958  RPCTypeCheck(request.params,
4959  {UniValue::VARR,
4960  UniValueType(), // ARR or OBJ, checked later
4961  UniValue::VNUM, UniValue::VOBJ},
4962  true);
4963 
4964  Amount fee;
4965  int change_position;
4966  CMutableTransaction rawTx =
4967  ConstructTransaction(wallet->GetChainParams(), request.params[0],
4968  request.params[1], request.params[2]);
4969  CCoinControl coin_control;
4970  // Automatically select coins, unless at least one is manually selected. Can
4971  // be overridden by options.add_inputs.
4972  coin_control.m_add_inputs = rawTx.vin.size() == 0;
4973  FundTransaction(pwallet, rawTx, fee, change_position, request.params[3],
4974  coin_control);
4975 
4976  // Make a blank psbt
4977  PartiallySignedTransaction psbtx(rawTx);
4978 
4979  // Fill transaction with out data but don't sign
4980  bool bip32derivs =
4981  request.params[4].isNull() ? true : request.params[4].get_bool();
4982  bool complete = true;
4983  const TransactionError err = pwallet->FillPSBT(
4984  psbtx, complete, SigHashType().withForkId(), false, bip32derivs);
4985  if (err != TransactionError::OK) {
4986  throw JSONRPCTransactionError(err);
4987  }
4988 
4989  // Serialize the PSBT
4991  ssTx << psbtx;
4992 
4993  UniValue result(UniValue::VOBJ);
4994  result.pushKV("psbt", EncodeBase64(ssTx.str()));
4995  result.pushKV("fee", ValueFromAmount(fee));
4996  result.pushKV("changepos", change_position);
4997  return result;
4998 }
4999 
5000 static UniValue upgradewallet(const Config &config,
5001  const JSONRPCRequest &request) {
5002  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
5003  CWallet *const pwallet = wallet.get();
5004 
5005  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
5006  return NullUniValue;
5007  }
5008 
5009  RPCHelpMan{"upgradewallet",
5010  "\nUpgrade the wallet. Upgrades to the latest version if no "
5011  "version number is specified\n"
5012  "New keys may be generated and a new wallet backup will need to "
5013  "be made.",
5014  {{"version", RPCArg::Type::NUM,
5015  /* default */ strprintf("%d", FEATURE_LATEST),
5016  "The version number to upgrade to. Default is the latest "
5017  "wallet version"}},
5019  RPCExamples{HelpExampleCli("upgradewallet", "200300") +
5020  HelpExampleRpc("upgradewallet", "200300")}}
5021  .Check(request);
5022 
5023  RPCTypeCheck(request.params, {UniValue::VNUM}, true);
5024 
5025  EnsureWalletIsUnlocked(pwallet);
5026 
5027  int version = 0;
5028  if (!request.params[0].isNull()) {
5029  version = request.params[0].get_int();
5030  }
5031 
5033  std::vector<bilingual_str> warnings;
5034  if (!pwallet->UpgradeWallet(version, error, warnings)) {
5035  throw JSONRPCError(RPC_WALLET_ERROR, error.original);
5036  }
5037  return error.original;
5038 }
5039 
5041  // clang-format off
5042  static const CRPCCommand commands[] = {
5043  // category name actor (function) argNames
5044  // ------------------- ------------------------ ---------------------- ----------
5045  { "rawtransactions", "fundrawtransaction", fundrawtransaction, {"hexstring","options"} },
5046  { "wallet", "abandontransaction", abandontransaction, {"txid"} },
5047  { "wallet", "addmultisigaddress", addmultisigaddress, {"nrequired","keys","label"} },
5048  { "wallet", "backupwallet", backupwallet, {"destination"} },
5049  { "wallet", "createwallet", createwallet, {"wallet_name", "disable_private_keys", "blank", "passphrase", "avoid_reuse", "descriptors"} },
5050  { "wallet", "encryptwallet", encryptwallet, {"passphrase"} },
5051  { "wallet", "getaddressesbylabel", getaddressesbylabel, {"label"} },
5052  { "wallet", "getaddressinfo", getaddressinfo, {"address"} },
5053  { "wallet", "getbalance", getbalance, {"dummy","minconf","include_watchonly","avoid_reuse"} },
5054  { "wallet", "getnewaddress", getnewaddress, {"label", "address_type"} },
5055  { "wallet", "getrawchangeaddress", getrawchangeaddress, {"address_type"} },
5056  { "wallet", "getreceivedbyaddress", getreceivedbyaddress, {"address","minconf"} },
5057  { "wallet", "getreceivedbylabel", getreceivedbylabel, {"label","minconf"} },
5058  { "wallet", "gettransaction", gettransaction, {"txid","include_watchonly","verbose"} },
5059  { "wallet", "getunconfirmedbalance", getunconfirmedbalance, {} },
5060  { "wallet", "getbalances", getbalances, {} },
5061  { "wallet", "getwalletinfo", getwalletinfo, {} },
5062  { "wallet", "keypoolrefill", keypoolrefill, {"newsize"} },
5063  { "wallet", "listaddressgroupings", listaddressgroupings, {} },
5064  { "wallet", "listlabels", listlabels, {"purpose"} },
5065  { "wallet", "listlockunspent", listlockunspent, {} },
5066  { "wallet", "listreceivedbyaddress", listreceivedbyaddress, {"minconf","include_empty","include_watchonly","address_filter"} },
5067  { "wallet", "listreceivedbylabel", listreceivedbylabel, {"minconf","include_empty","include_watchonly"} },
5068  { "wallet", "listsinceblock", listsinceblock, {"blockhash","target_confirmations","include_watchonly","include_removed"} },
5069  { "wallet", "listtransactions", listtransactions, {"label|dummy","count","skip","include_watchonly"} },
5070  { "wallet", "listunspent", listunspent, {"minconf","maxconf","addresses","include_unsafe","query_options"} },
5071  { "wallet", "listwalletdir", listwalletdir, {} },
5072  { "wallet", "listwallets", listwallets, {} },
5073  { "wallet", "loadwallet", loadwallet, {"filename"} },
5074  { "wallet", "lockunspent", lockunspent, {"unlock","transactions"} },
5075  { "wallet", "rescanblockchain", rescanblockchain, {"start_height", "stop_height"} },
5076  { "wallet", "sendmany", sendmany, {"dummy","amounts","minconf","comment","subtractfeefrom"} },
5077  { "wallet", "sendtoaddress", sendtoaddress, {"address","amount","comment","comment_to","subtractfeefromamount","avoid_reuse"} },
5078  { "wallet", "sethdseed", sethdseed, {"newkeypool","seed"} },
5079  { "wallet", "setlabel", setlabel, {"address","label"} },
5080  { "wallet", "settxfee", settxfee, {"amount"} },
5081  { "wallet", "setwalletflag", setwalletflag, {"flag","value"} },
5082  { "wallet", "signmessage", signmessage, {"address","message"} },
5083  { "wallet", "signrawtransactionwithwallet", signrawtransactionwithwallet, {"hextring","prevtxs","sighashtype"} },
5084  { "wallet", "unloadwallet", unloadwallet, {"wallet_name"} },
5085  { "wallet", "upgradewallet", upgradewallet, {"version"} },
5086  { "wallet", "walletcreatefundedpsbt", walletcreatefundedpsbt, {"inputs","outputs","locktime","options","bip32derivs"} },
5087  { "wallet", "walletlock", walletlock, {} },
5088  { "wallet", "walletpassphrase", walletpassphrase, {"passphrase","timeout"} },
5089  { "wallet", "walletpassphrasechange", walletpassphrasechange, {"oldpassphrase","newpassphrase"} },
5090  { "wallet", "walletprocesspsbt", walletprocesspsbt, {"psbt","sign","sighashtype","bip32derivs"} },
5091  };
5092  // clang-format on
5093 
5094  return MakeSpan(commands);
5095 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:336
uint32_t GetN() const
Definition: transaction.h:44
static UniValue listwalletdir(const Config &config, const JSONRPCRequest &request)
Definition: rpcwallet.cpp:3097
txnouttype Solver(const CScript &scriptPubKey, std::vector< std::vector< uint8_t >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:102
No wallet specified (error when there are multiple wallets loaded)
Definition: protocol.h:109
static UniValue sendmany(const Config &config, const JSONRPCRequest &request)
Definition: rpcwallet.cpp:898
UniValue getaddressinfo(const Config &config, const JSONRPCRequest &request)
Definition: rpcwallet.cpp:4298
Helper for findBlock to selectively return pieces of block data.
Definition: chain.h:43
static UniValue getnewaddress(const Config &config, const JSONRPCRequest &request)
Definition: rpcwallet.cpp:210
WalletCreationStatus CreateWallet(const CChainParams &chainParams, interfaces::Chain &chain, const SecureString &passphrase, uint64_t wallet_creation_flags, const std::string &name, bilingual_str &error, std::vector< bilingual_str > &warnings, std::shared_ptr< CWallet > &result)
Definition: dummywallet.cpp:65
bool NewKeyPool()
Mark old keypool keys as used, and generate all new keys.
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
Definition: wallet.cpp:1494
static UniValue DescribeWalletAddress(const CWallet *const pwallet, const CTxDestination &dest)
Definition: rpcwallet.cpp:4272
const util::Ref & context
Definition: request.h:42
NODISCARD bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:191
virtual void findCoins(std::map< COutPoint, Coin > &coins)=0
Look up unspent output information.
static UniValue getreceivedbylabel(const Config &config, const JSONRPCRequest &request)
Definition: rpcwallet.cpp:753
Amount m_mine_untrusted_pending
Untrusted, but in mempool (pending)
Definition: wallet.h:1099
const CHDChain & GetHDChain() const
OutputType m_default_change_type
Definition: wallet.h:1221