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