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