Bitcoin ABC  0.26.3
P2P Digital Currency
backup.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2016 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <wallet/rpc/backup.h>
6 
7 #include <chain.h>
8 #include <config.h>
9 #include <core_io.h>
10 #include <fs.h>
11 #include <interfaces/chain.h>
12 #include <key_io.h>
13 #include <merkleblock.h>
14 #include <rpc/server.h>
15 #include <rpc/util.h>
16 #include <script/descriptor.h>
17 #include <script/script.h>
18 #include <script/standard.h>
19 #include <sync.h>
20 #include <util/bip32.h>
21 #include <util/system.h>
22 #include <util/time.h>
23 #include <util/translation.h>
24 #include <wallet/rpc/util.h>
25 #include <wallet/rpcwallet.h>
26 #include <wallet/spend.h>
27 #include <wallet/wallet.h>
28 
29 #include <boost/algorithm/string.hpp>
30 
31 #include <algorithm>
32 #include <cstdint>
33 #include <fstream>
34 #include <string>
35 #include <tuple>
36 #include <utility>
37 #include <vector>
38 
40 
41 static std::string EncodeDumpString(const std::string &str) {
42  std::stringstream ret;
43  for (const uint8_t c : str) {
44  if (c <= 32 || c >= 128 || c == '%') {
45  ret << '%' << HexStr(Span<const uint8_t>(&c, 1));
46  } else {
47  ret << c;
48  }
49  }
50  return ret.str();
51 }
52 
53 static std::string DecodeDumpString(const std::string &str) {
54  std::stringstream ret;
55  for (unsigned int pos = 0; pos < str.length(); pos++) {
56  uint8_t c = str[pos];
57  if (c == '%' && pos + 2 < str.length()) {
58  c = (((str[pos + 1] >> 6) * 9 + ((str[pos + 1] - '0') & 15)) << 4) |
59  ((str[pos + 2] >> 6) * 9 + ((str[pos + 2] - '0') & 15));
60  pos += 2;
61  }
62  ret << c;
63  }
64  return ret.str();
65 }
66 
67 static bool
69  const CWallet *const pwallet, const CKeyID &keyid,
70  std::string &strAddr, std::string &strLabel)
71  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
72  bool fLabelFound = false;
73  CKey key;
74  spk_man->GetKey(keyid, key);
75  for (const auto &dest : GetAllDestinationsForKey(key.GetPubKey())) {
76  const auto *address_book_entry = pwallet->FindAddressBookEntry(dest);
77  if (address_book_entry) {
78  if (!strAddr.empty()) {
79  strAddr += ",";
80  }
81  strAddr += EncodeDestination(dest, config);
82  strLabel = EncodeDumpString(address_book_entry->GetLabel());
83  fLabelFound = true;
84  }
85  }
86  if (!fLabelFound) {
87  strAddr = EncodeDestination(
89  pwallet->m_default_address_type),
90  config);
91  }
92  return fLabelFound;
93 }
94 
95 static const int64_t TIMESTAMP_MIN = 0;
96 
97 static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver,
98  int64_t time_begin = TIMESTAMP_MIN,
99  bool update = true) {
100  int64_t scanned_time = wallet.RescanFromTime(time_begin, reserver, update);
101  if (wallet.IsAbortingRescan()) {
102  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
103  } else if (scanned_time > time_begin) {
105  "Rescan was unable to fully rescan the blockchain. "
106  "Some transactions may be missing.");
107  }
108 }
109 
111  return RPCHelpMan{
112  "importprivkey",
113  "Adds a private key (as returned by dumpprivkey) to your wallet. "
114  "Requires a new wallet backup.\n"
115  "Hint: use importmulti to import more than one private key.\n"
116  "\nNote: This call can take minutes to complete if rescan is true, "
117  "during that time, other rpc calls\n"
118  "may report that the imported key exists but related transactions are "
119  "still missing, leading to temporarily incorrect/bogus balances and "
120  "unspent outputs until rescan completes.\n"
121  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
122  {
124  "The private key (see dumpprivkey)"},
125  {"label", RPCArg::Type::STR, /* default */
126  "current label if address exists, otherwise \"\"",
127  "An optional label"},
128  {"rescan", RPCArg::Type::BOOL, /* default */ "true",
129  "Rescan the wallet for transactions"},
130  },
132  RPCExamples{
133  "\nDump a private key\n" +
134  HelpExampleCli("dumpprivkey", "\"myaddress\"") +
135  "\nImport the private key with rescan\n" +
136  HelpExampleCli("importprivkey", "\"mykey\"") +
137  "\nImport using a label and without rescan\n" +
138  HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
139  "\nImport using default blank label and without rescan\n" +
140  HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
141  "\nAs a JSON-RPC call\n" +
142  HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")},
143  [&](const RPCHelpMan &self, const Config &config,
144  const JSONRPCRequest &request) -> UniValue {
145  std::shared_ptr<CWallet> const wallet =
147  if (!wallet) {
148  return NullUniValue;
149  }
150  CWallet *const pwallet = wallet.get();
151 
153  throw JSONRPCError(
155  "Cannot import private keys to a wallet with "
156  "private keys disabled");
157  }
158 
160 
161  WalletRescanReserver reserver(*pwallet);
162  bool fRescan = true;
163  {
164  LOCK(pwallet->cs_wallet);
165 
166  EnsureWalletIsUnlocked(pwallet);
167 
168  std::string strSecret = request.params[0].get_str();
169  std::string strLabel = "";
170  if (!request.params[1].isNull()) {
171  strLabel = request.params[1].get_str();
172  }
173 
174  // Whether to perform rescan after import
175  if (!request.params[2].isNull()) {
176  fRescan = request.params[2].get_bool();
177  }
178 
179  if (fRescan && pwallet->chain().havePruned()) {
180  // Exit early and print an error.
181  // If a block is pruned after this check, we will import the
182  // key(s), but fail the rescan with a generic error.
183  throw JSONRPCError(
185  "Rescan is disabled when blocks are pruned");
186  }
187 
188  if (fRescan && !reserver.reserve()) {
189  throw JSONRPCError(
191  "Wallet is currently rescanning. Abort existing "
192  "rescan or wait.");
193  }
194 
195  CKey key = DecodeSecret(strSecret);
196  if (!key.IsValid()) {
198  "Invalid private key encoding");
199  }
200 
201  CPubKey pubkey = key.GetPubKey();
202  CHECK_NONFATAL(key.VerifyPubKey(pubkey));
203  CKeyID vchAddress = pubkey.GetID();
204  {
205  pwallet->MarkDirty();
206 
207  // We don't know which corresponding address will be used;
208  // label all new addresses, and label existing addresses if
209  // a label was passed.
210  for (const auto &dest : GetAllDestinationsForKey(pubkey)) {
211  if (!request.params[1].isNull() ||
212  !pwallet->FindAddressBookEntry(dest)) {
213  pwallet->SetAddressBook(dest, strLabel, "receive");
214  }
215  }
216 
217  // Use timestamp of 1 to scan the whole chain
218  if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
220  "Error adding key to wallet");
221  }
222  }
223  }
224  if (fRescan) {
225  RescanWallet(*pwallet, reserver);
226  }
227 
228  return NullUniValue;
229  },
230  };
231 }
232 
234  return RPCHelpMan{
235  "abortrescan",
236  "Stops current wallet rescan triggered by an RPC call, e.g. by an "
237  "importprivkey call.\n"
238  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
239  {},
241  "Whether the abort was successful"},
242  RPCExamples{"\nImport a private key\n" +
243  HelpExampleCli("importprivkey", "\"mykey\"") +
244  "\nAbort the running wallet rescan\n" +
245  HelpExampleCli("abortrescan", "") +
246  "\nAs a JSON-RPC call\n" +
247  HelpExampleRpc("abortrescan", "")},
248  [&](const RPCHelpMan &self, const Config &config,
249  const JSONRPCRequest &request) -> UniValue {
250  std::shared_ptr<CWallet> const wallet =
252  if (!wallet) {
253  return NullUniValue;
254  }
255  CWallet *const pwallet = wallet.get();
256 
257  if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) {
258  return false;
259  }
260  pwallet->AbortRescan();
261  return true;
262  },
263  };
264 }
265 
267  return RPCHelpMan{
268  "importaddress",
269  "Adds an address or script (in hex) that can be watched as if it "
270  "were in your wallet but cannot be used to spend. Requires a new "
271  "wallet backup.\n"
272  "\nNote: This call can take minutes to complete if rescan is true, "
273  "during that time, other rpc calls\n"
274  "may report that the imported address exists but related transactions "
275  "are still missing, leading to temporarily incorrect/bogus balances "
276  "and unspent outputs until rescan completes.\n"
277  "If you have the full public key, you should call importpubkey instead "
278  "of this.\n"
279  "Hint: use importmulti to import more than one address.\n"
280  "\nNote: If you import a non-standard raw script in hex form, outputs "
281  "sending to it will be treated\n"
282  "as change, and not show up in many RPCs.\n"
283  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
284  {
286  "The Bitcoin address (or hex-encoded script)"},
287  {"label", RPCArg::Type::STR, /* default */ "\"\"",
288  "An optional label"},
289  {"rescan", RPCArg::Type::BOOL, /* default */ "true",
290  "Rescan the wallet for transactions"},
291  {"p2sh", RPCArg::Type::BOOL, /* default */ "false",
292  "Add the P2SH version of the script as well"},
293  },
295  RPCExamples{
296  "\nImport an address with rescan\n" +
297  HelpExampleCli("importaddress", "\"myaddress\"") +
298  "\nImport using a label without rescan\n" +
299  HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") +
300  "\nAs a JSON-RPC call\n" +
301  HelpExampleRpc("importaddress",
302  "\"myaddress\", \"testing\", false")},
303  [&](const RPCHelpMan &self, const Config &config,
304  const JSONRPCRequest &request) -> UniValue {
305  std::shared_ptr<CWallet> const wallet =
307  if (!wallet) {
308  return NullUniValue;
309  }
310  CWallet *const pwallet = wallet.get();
311 
312  EnsureLegacyScriptPubKeyMan(*pwallet, true);
313 
314  std::string strLabel;
315  if (!request.params[1].isNull()) {
316  strLabel = request.params[1].get_str();
317  }
318 
319  // Whether to perform rescan after import
320  bool fRescan = true;
321  if (!request.params[2].isNull()) {
322  fRescan = request.params[2].get_bool();
323  }
324 
325  if (fRescan && pwallet->chain().havePruned()) {
326  // Exit early and print an error.
327  // If a block is pruned after this check, we will import the
328  // key(s), but fail the rescan with a generic error.
330  "Rescan is disabled when blocks are pruned");
331  }
332 
333  WalletRescanReserver reserver(*pwallet);
334  if (fRescan && !reserver.reserve()) {
336  "Wallet is currently rescanning. Abort "
337  "existing rescan or wait.");
338  }
339 
340  // Whether to import a p2sh version, too
341  bool fP2SH = false;
342  if (!request.params[3].isNull()) {
343  fP2SH = request.params[3].get_bool();
344  }
345 
346  {
347  LOCK(pwallet->cs_wallet);
348 
350  request.params[0].get_str(), wallet->GetChainParams());
351  if (IsValidDestination(dest)) {
352  if (fP2SH) {
353  throw JSONRPCError(
355  "Cannot use the p2sh flag with an address - "
356  "use a script instead");
357  }
358 
359  pwallet->MarkDirty();
360 
361  pwallet->ImportScriptPubKeys(
362  strLabel, {GetScriptForDestination(dest)},
363  false /* have_solving_data */, true /* apply_label */,
364  1 /* timestamp */);
365  } else if (IsHex(request.params[0].get_str())) {
366  std::vector<uint8_t> data(
367  ParseHex(request.params[0].get_str()));
368  CScript redeem_script(data.begin(), data.end());
369 
370  std::set<CScript> scripts = {redeem_script};
371  pwallet->ImportScripts(scripts, 0 /* timestamp */);
372 
373  if (fP2SH) {
374  scripts.insert(
375  GetScriptForDestination(ScriptHash(redeem_script)));
376  }
377 
378  pwallet->ImportScriptPubKeys(
379  strLabel, scripts, false /* have_solving_data */,
380  true /* apply_label */, 1 /* timestamp */);
381  } else {
383  "Invalid Bitcoin address or script");
384  }
385  }
386  if (fRescan) {
387  RescanWallet(*pwallet, reserver);
388  {
389  LOCK(pwallet->cs_wallet);
390  pwallet->ReacceptWalletTransactions();
391  }
392  }
393 
394  return NullUniValue;
395  },
396  };
397 }
398 
400  return RPCHelpMan{
401  "importprunedfunds",
402  "Imports funds without rescan. Corresponding address or script must "
403  "previously be included in wallet. Aimed towards pruned wallets. The "
404  "end-user is responsible to import additional transactions that "
405  "subsequently spend the imported outputs or rescan after the point in "
406  "the blockchain the transaction is included.\n",
407  {
408  {"rawtransaction", RPCArg::Type::STR_HEX, RPCArg::Optional::NO,
409  "A raw transaction in hex funding an already-existing address in "
410  "wallet"},
412  "The hex output from gettxoutproof that contains the transaction"},
413  },
415  RPCExamples{""},
416  [&](const RPCHelpMan &self, const Config &config,
417  const JSONRPCRequest &request) -> UniValue {
418  std::shared_ptr<CWallet> const wallet =
420  if (!wallet) {
421  return NullUniValue;
422  }
423  CWallet *const pwallet = wallet.get();
424 
426  if (!DecodeHexTx(tx, request.params[0].get_str())) {
428  "TX decode failed");
429  }
430  uint256 txid = tx.GetId();
431 
432  CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK,
434  CMerkleBlock merkleBlock;
435  ssMB >> merkleBlock;
436 
437  // Search partial merkle tree in proof for our transaction and index
438  // in valid block
439  std::vector<uint256> vMatch;
440  std::vector<size_t> vIndex;
441  if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) !=
442  merkleBlock.header.hashMerkleRoot) {
444  "Something wrong with merkleblock");
445  }
446 
447  LOCK(pwallet->cs_wallet);
448  int height;
449  if (!pwallet->chain().findAncestorByHash(
450  pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(),
451  FoundBlock().height(height))) {
453  "Block not found in chain");
454  }
455 
456  std::vector<uint256>::const_iterator it;
457  if ((it = std::find(vMatch.begin(), vMatch.end(), txid)) ==
458  vMatch.end()) {
460  "Transaction given doesn't exist in proof");
461  }
462 
463  size_t txnIndex = vIndex[it - vMatch.begin()];
464 
465  CWalletTx::Confirmation confirm(
466  CWalletTx::Status::CONFIRMED, height,
467  merkleBlock.header.GetHash(), txnIndex);
468 
469  CTransactionRef tx_ref = MakeTransactionRef(tx);
470  if (pwallet->IsMine(*tx_ref)) {
471  pwallet->AddToWallet(std::move(tx_ref), confirm);
472  return NullUniValue;
473  }
474 
475  throw JSONRPCError(
477  "No addresses in wallet correspond to included transaction");
478  },
479  };
480 }
481 
483  return RPCHelpMan{
484  "removeprunedfunds",
485  "Deletes the specified transaction from the wallet. Meant for use "
486  "with pruned wallets and as a companion to importprunedfunds. This "
487  "will affect wallet balances.\n",
488  {
490  "The hex-encoded id of the transaction you are deleting"},
491  },
493  RPCExamples{HelpExampleCli("removeprunedfunds",
494  "\"a8d0c0184dde994a09ec054286f1ce581bebf4644"
495  "6a512166eae7628734ea0a5\"") +
496  "\nAs a JSON-RPC call\n" +
497  HelpExampleRpc("removeprunedfunds",
498  "\"a8d0c0184dde994a09ec054286f1ce581bebf4644"
499  "6a512166eae7628734ea0a5\"")},
500  [&](const RPCHelpMan &self, const Config &config,
501  const JSONRPCRequest &request) -> UniValue {
502  std::shared_ptr<CWallet> const wallet =
504  if (!wallet) {
505  return NullUniValue;
506  }
507  CWallet *const pwallet = wallet.get();
508 
509  LOCK(pwallet->cs_wallet);
510 
511  TxId txid(ParseHashV(request.params[0], "txid"));
512  std::vector<TxId> txIds;
513  txIds.push_back(txid);
514  std::vector<TxId> txIdsOut;
515 
516  if (pwallet->ZapSelectTx(txIds, txIdsOut) != DBErrors::LOAD_OK) {
517  throw JSONRPCError(
519  "Could not properly delete the transaction.");
520  }
521 
522  if (txIdsOut.empty()) {
524  "Transaction does not exist in wallet.");
525  }
526 
527  return NullUniValue;
528  },
529  };
530 }
531 
533  return RPCHelpMan{
534  "importpubkey",
535  "Adds a public key (in hex) that can be watched as if it were in "
536  "your wallet but cannot be used to spend. Requires a new wallet "
537  "backup.\n"
538  "Hint: use importmulti to import more than one public key.\n"
539  "\nNote: This call can take minutes to complete if rescan is true, "
540  "during that time, other rpc calls\n"
541  "may report that the imported pubkey exists but related transactions "
542  "are still missing, leading to temporarily incorrect/bogus balances "
543  "and unspent outputs until rescan completes.\n"
544  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
545  {
547  "The hex-encoded public key"},
548  {"label", RPCArg::Type::STR, /* default */ "\"\"",
549  "An optional label"},
550  {"rescan", RPCArg::Type::BOOL, /* default */ "true",
551  "Rescan the wallet for transactions"},
552  },
554  RPCExamples{
555  "\nImport a public key with rescan\n" +
556  HelpExampleCli("importpubkey", "\"mypubkey\"") +
557  "\nImport using a label without rescan\n" +
558  HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
559  "\nAs a JSON-RPC call\n" +
560  HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")},
561  [&](const RPCHelpMan &self, const Config &config,
562  const JSONRPCRequest &request) -> UniValue {
563  std::shared_ptr<CWallet> const wallet =
565  if (!wallet) {
566  return NullUniValue;
567  }
568  CWallet *const pwallet = wallet.get();
569 
571 
572  std::string strLabel;
573  if (!request.params[1].isNull()) {
574  strLabel = request.params[1].get_str();
575  }
576 
577  // Whether to perform rescan after import
578  bool fRescan = true;
579  if (!request.params[2].isNull()) {
580  fRescan = request.params[2].get_bool();
581  }
582 
583  if (fRescan && pwallet->chain().havePruned()) {
584  // Exit early and print an error.
585  // If a block is pruned after this check, we will import the
586  // key(s), but fail the rescan with a generic error.
588  "Rescan is disabled when blocks are pruned");
589  }
590 
591  WalletRescanReserver reserver(*pwallet);
592  if (fRescan && !reserver.reserve()) {
594  "Wallet is currently rescanning. Abort "
595  "existing rescan or wait.");
596  }
597 
598  if (!IsHex(request.params[0].get_str())) {
600  "Pubkey must be a hex string");
601  }
602  std::vector<uint8_t> data(ParseHex(request.params[0].get_str()));
603  CPubKey pubKey(data.begin(), data.end());
604  if (!pubKey.IsFullyValid()) {
606  "Pubkey is not a valid public key");
607  }
608 
609  {
610  LOCK(pwallet->cs_wallet);
611 
612  std::set<CScript> script_pub_keys;
613  for (const auto &dest : GetAllDestinationsForKey(pubKey)) {
614  script_pub_keys.insert(GetScriptForDestination(dest));
615  }
616 
617  pwallet->MarkDirty();
618 
619  pwallet->ImportScriptPubKeys(
620  strLabel, script_pub_keys, true /* have_solving_data */,
621  true /* apply_label */, 1 /* timestamp */);
622 
623  pwallet->ImportPubKeys(
624  {pubKey.GetID()}, {{pubKey.GetID(), pubKey}},
625  {} /* key_origins */, false /* add_keypool */,
626  false /* internal */, 1 /* timestamp */);
627  }
628  if (fRescan) {
629  RescanWallet(*pwallet, reserver);
630  {
631  LOCK(pwallet->cs_wallet);
632  pwallet->ReacceptWalletTransactions();
633  }
634  }
635 
636  return NullUniValue;
637  },
638  };
639 }
640 
642  return RPCHelpMan{
643  "importwallet",
644  "Imports keys from a wallet dump file (see dumpwallet). Requires a "
645  "new wallet backup to include imported keys.\n"
646  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
647  {
649  "The wallet file"},
650  },
652  RPCExamples{"\nDump the wallet\n" +
653  HelpExampleCli("dumpwallet", "\"test\"") +
654  "\nImport the wallet\n" +
655  HelpExampleCli("importwallet", "\"test\"") +
656  "\nImport using the json rpc call\n" +
657  HelpExampleRpc("importwallet", "\"test\"")},
658  [&](const RPCHelpMan &self, const Config &config,
659  const JSONRPCRequest &request) -> UniValue {
660  std::shared_ptr<CWallet> const wallet =
662  if (!wallet) {
663  return NullUniValue;
664  }
665  CWallet *const pwallet = wallet.get();
666 
668 
669  if (pwallet->chain().havePruned()) {
670  // Exit early and print an error.
671  // If a block is pruned after this check, we will import the
672  // key(s), but fail the rescan with a generic error.
673  throw JSONRPCError(
675  "Importing wallets is disabled when blocks are pruned");
676  }
677 
678  WalletRescanReserver reserver(*pwallet);
679  if (!reserver.reserve()) {
681  "Wallet is currently rescanning. Abort "
682  "existing rescan or wait.");
683  }
684 
685  int64_t nTimeBegin = 0;
686  bool fGood = true;
687  {
688  LOCK(pwallet->cs_wallet);
689 
690  EnsureWalletIsUnlocked(pwallet);
691 
692  std::ifstream file;
693  file.open(fs::u8path(request.params[0].get_str()),
694  std::ios::in | std::ios::ate);
695  if (!file.is_open()) {
697  "Cannot open wallet dump file");
698  }
700  pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
701  FoundBlock().time(nTimeBegin)));
702 
703  int64_t nFilesize = std::max<int64_t>(1, file.tellg());
704  file.seekg(0, file.beg);
705 
706  // Use uiInterface.ShowProgress instead of pwallet.ShowProgress
707  // because pwallet.ShowProgress has a cancel button tied to
708  // AbortRescan which we don't want for this progress bar showing
709  // the import progress. uiInterface.ShowProgress does not have a
710  // cancel button.
711 
712  // show progress dialog in GUI
713  pwallet->chain().showProgress(
714  strprintf("%s " + _("Importing...").translated,
715  pwallet->GetDisplayName()),
716  0, false);
717  std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
718  std::vector<std::pair<CScript, int64_t>> scripts;
719  while (file.good()) {
720  pwallet->chain().showProgress(
721  "",
722  std::max(1,
723  std::min<int>(50, 100 * double(file.tellg()) /
724  double(nFilesize))),
725  false);
726  std::string line;
727  std::getline(file, line);
728  if (line.empty() || line[0] == '#') {
729  continue;
730  }
731 
732  std::vector<std::string> vstr;
733  boost::split(vstr, line, boost::is_any_of(" "));
734  if (vstr.size() < 2) {
735  continue;
736  }
737  CKey key = DecodeSecret(vstr[0]);
738  if (key.IsValid()) {
739  int64_t nTime = ParseISO8601DateTime(vstr[1]);
740  std::string strLabel;
741  bool fLabel = true;
742  for (size_t nStr = 2; nStr < vstr.size(); nStr++) {
743  if (vstr[nStr].front() == '#') {
744  break;
745  }
746  if (vstr[nStr] == "change=1") {
747  fLabel = false;
748  }
749  if (vstr[nStr] == "reserve=1") {
750  fLabel = false;
751  }
752  if (vstr[nStr].substr(0, 6) == "label=") {
753  strLabel =
754  DecodeDumpString(vstr[nStr].substr(6));
755  fLabel = true;
756  }
757  }
758  keys.push_back(
759  std::make_tuple(key, nTime, fLabel, strLabel));
760  } else if (IsHex(vstr[0])) {
761  std::vector<uint8_t> vData(ParseHex(vstr[0]));
762  CScript script = CScript(vData.begin(), vData.end());
763  int64_t birth_time = ParseISO8601DateTime(vstr[1]);
764  scripts.push_back(
765  std::pair<CScript, int64_t>(script, birth_time));
766  }
767  }
768  file.close();
769  // We now know whether we are importing private keys, so we can
770  // error if private keys are disabled
771  if (keys.size() > 0 && pwallet->IsWalletFlagSet(
773  // hide progress dialog in GUI
774  pwallet->chain().showProgress("", 100, false);
776  "Importing wallets is disabled when "
777  "private keys are disabled");
778  }
779  double total = double(keys.size() + scripts.size());
780  double progress = 0;
781  for (const auto &key_tuple : keys) {
782  pwallet->chain().showProgress(
783  "",
784  std::max(50, std::min<int>(75, 100 * progress / total) +
785  50),
786  false);
787  const CKey &key = std::get<0>(key_tuple);
788  int64_t time = std::get<1>(key_tuple);
789  bool has_label = std::get<2>(key_tuple);
790  std::string label = std::get<3>(key_tuple);
791 
792  CPubKey pubkey = key.GetPubKey();
793  CHECK_NONFATAL(key.VerifyPubKey(pubkey));
794  CKeyID keyid = pubkey.GetID();
795 
796  pwallet->WalletLogPrintf(
797  "Importing %s...\n",
798  EncodeDestination(PKHash(keyid), config));
799 
800  if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
801  pwallet->WalletLogPrintf(
802  "Error importing key for %s\n",
803  EncodeDestination(PKHash(keyid), config));
804  fGood = false;
805  continue;
806  }
807 
808  if (has_label) {
809  pwallet->SetAddressBook(PKHash(keyid), label,
810  "receive");
811  }
812 
813  nTimeBegin = std::min(nTimeBegin, time);
814  progress++;
815  }
816  for (const auto &script_pair : scripts) {
817  pwallet->chain().showProgress(
818  "",
819  std::max(50, std::min<int>(75, 100 * progress / total) +
820  50),
821  false);
822  const CScript &script = script_pair.first;
823  int64_t time = script_pair.second;
824 
825  if (!pwallet->ImportScripts({script}, time)) {
826  pwallet->WalletLogPrintf("Error importing script %s\n",
827  HexStr(script));
828  fGood = false;
829  continue;
830  }
831  if (time > 0) {
832  nTimeBegin = std::min(nTimeBegin, time);
833  }
834 
835  progress++;
836  }
837 
838  // hide progress dialog in GUI
839  pwallet->chain().showProgress("", 100, false);
840  }
841  // hide progress dialog in GUI
842  pwallet->chain().showProgress("", 100, false);
843  RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
844  pwallet->MarkDirty();
845 
846  if (!fGood) {
848  "Error adding some keys/scripts to wallet");
849  }
850 
851  return NullUniValue;
852  },
853  };
854 }
855 
857  return RPCHelpMan{
858  "dumpprivkey",
859  "Reveals the private key corresponding to 'address'.\n"
860  "Then the importprivkey can be used with this output\n",
861  {
863  "The bitcoin address for the private key"},
864  },
865  RPCResult{RPCResult::Type::STR, "key", "The private key"},
866  RPCExamples{HelpExampleCli("dumpprivkey", "\"myaddress\"") +
867  HelpExampleCli("importprivkey", "\"mykey\"") +
868  HelpExampleRpc("dumpprivkey", "\"myaddress\"")},
869  [&](const RPCHelpMan &self, const Config &config,
870  const JSONRPCRequest &request) -> UniValue {
871  std::shared_ptr<CWallet> const wallet =
873  if (!wallet) {
874  return NullUniValue;
875  }
876  const CWallet *const pwallet = wallet.get();
877 
878  LegacyScriptPubKeyMan &spk_man =
880 
881  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
882 
883  EnsureWalletIsUnlocked(pwallet);
884 
885  std::string strAddress = request.params[0].get_str();
886  CTxDestination dest =
887  DecodeDestination(strAddress, wallet->GetChainParams());
888  if (!IsValidDestination(dest)) {
890  "Invalid Bitcoin address");
891  }
892  auto keyid = GetKeyForDestination(spk_man, dest);
893  if (keyid.IsNull()) {
895  "Address does not refer to a key");
896  }
897  CKey vchSecret;
898  if (!spk_man.GetKey(keyid, vchSecret)) {
900  "Private key for address " + strAddress +
901  " is not known");
902  }
903  return EncodeSecret(vchSecret);
904  },
905  };
906 }
907 
909  return RPCHelpMan{
910  "dumpwallet",
911  "Dumps all wallet keys in a human-readable format to a server-side "
912  "file. This does not allow overwriting existing files.\n"
913  "Imported scripts are included in the dumpsfile, but corresponding "
914  "addresses may not be added automatically by importwallet.\n"
915  "Note that if your wallet contains keys which are not derived from "
916  "your HD seed (e.g. imported keys), these are not covered by\n"
917  "only backing up the seed itself, and must be backed up too (e.g. "
918  "ensure you back up the whole dumpfile).\n",
919  {
921  "The filename with path (absolute path recommended)"},
922  },
924  "",
925  "",
926  {
927  {RPCResult::Type::STR, "filename",
928  "The filename with full absolute path"},
929  }},
930  RPCExamples{HelpExampleCli("dumpwallet", "\"test\"") +
931  HelpExampleRpc("dumpwallet", "\"test\"")},
932  [&](const RPCHelpMan &self, const Config &config,
933  const JSONRPCRequest &request) -> UniValue {
934  std::shared_ptr<CWallet> const pwallet =
936  if (!pwallet) {
937  return NullUniValue;
938  }
939 
940  CWallet &wallet = *pwallet;
941  LegacyScriptPubKeyMan &spk_man =
943 
944  // Make sure the results are valid at least up to the most recent
945  // block the user could have gotten from another RPC command prior
946  // to now
947  wallet.BlockUntilSyncedToCurrentChain();
948 
949  LOCK(wallet.cs_wallet);
950 
952 
953  fs::path filepath = fs::u8path(request.params[0].get_str());
954  filepath = fs::absolute(filepath);
955 
962  if (fs::exists(filepath)) {
964  filepath.u8string() +
965  " already exists. If you are "
966  "sure this is what you want, "
967  "move it out of the way first");
968  }
969 
970  std::ofstream file;
971  file.open(filepath);
972  if (!file.is_open()) {
974  "Cannot open wallet dump file");
975  }
976 
977  std::map<CKeyID, int64_t> mapKeyBirth;
978  wallet.GetKeyBirthTimes(mapKeyBirth);
979 
980  int64_t block_time = 0;
981  CHECK_NONFATAL(wallet.chain().findBlock(
982  wallet.GetLastBlockHash(), FoundBlock().time(block_time)));
983 
984  // Note: To avoid a lock order issue, access to cs_main must be
985  // locked before cs_KeyStore. So we do the two things in this
986  // function that lock cs_main first: GetKeyBirthTimes, and
987  // findBlock.
988  LOCK(spk_man.cs_KeyStore);
989 
990  const std::map<CKeyID, int64_t> &mapKeyPool =
991  spk_man.GetAllReserveKeys();
992  std::set<CScriptID> scripts = spk_man.GetCScripts();
993 
994  // sort time/key pairs
995  std::vector<std::pair<int64_t, CKeyID>> vKeyBirth;
996  for (const auto &entry : mapKeyBirth) {
997  vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
998  }
999  mapKeyBirth.clear();
1000  std::sort(vKeyBirth.begin(), vKeyBirth.end());
1001 
1002  // produce output
1003  file << strprintf("# Wallet dump created by %s %s\n", CLIENT_NAME,
1004  CLIENT_BUILD);
1005  file << strprintf("# * Created on %s\n",
1007  file << strprintf("# * Best block at time of backup was %i (%s),\n",
1008  wallet.GetLastBlockHeight(),
1009  wallet.GetLastBlockHash().ToString());
1010  file << strprintf("# mined on %s\n",
1011  FormatISO8601DateTime(block_time));
1012  file << "\n";
1013 
1014  // add the base58check encoded extended master if the wallet uses HD
1015  CKeyID seed_id = spk_man.GetHDChain().seed_id;
1016  if (!seed_id.IsNull()) {
1017  CKey seed;
1018  if (spk_man.GetKey(seed_id, seed)) {
1019  CExtKey masterKey;
1020  masterKey.SetSeed(seed.begin(), seed.size());
1021 
1022  file << "# extended private masterkey: "
1023  << EncodeExtKey(masterKey) << "\n\n";
1024  }
1025  }
1026  for (std::vector<std::pair<int64_t, CKeyID>>::const_iterator it =
1027  vKeyBirth.begin();
1028  it != vKeyBirth.end(); it++) {
1029  const CKeyID &keyid = it->second;
1030  std::string strTime = FormatISO8601DateTime(it->first);
1031  std::string strAddr;
1032  std::string strLabel;
1033  CKey key;
1034  if (spk_man.GetKey(keyid, key)) {
1035  file << strprintf("%s %s ", EncodeSecret(key), strTime);
1036  if (GetWalletAddressesForKey(config, &spk_man, &wallet,
1037  keyid, strAddr, strLabel)) {
1038  file << strprintf("label=%s", strLabel);
1039  } else if (keyid == seed_id) {
1040  file << "hdseed=1";
1041  } else if (mapKeyPool.count(keyid)) {
1042  file << "reserve=1";
1043  } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
1044  file << "inactivehdseed=1";
1045  } else {
1046  file << "change=1";
1047  }
1048  file << strprintf(
1049  " # addr=%s%s\n", strAddr,
1050  (spk_man.mapKeyMetadata[keyid].has_key_origin
1051  ? " hdkeypath=" +
1052  WriteHDKeypath(spk_man.mapKeyMetadata[keyid]
1053  .key_origin.path)
1054  : ""));
1055  }
1056  }
1057  file << "\n";
1058  for (const CScriptID &scriptid : scripts) {
1059  CScript script;
1060  std::string create_time = "0";
1061  std::string address =
1062  EncodeDestination(ScriptHash(scriptid), config);
1063  // get birth times for scripts with metadata
1064  auto it = spk_man.m_script_metadata.find(scriptid);
1065  if (it != spk_man.m_script_metadata.end()) {
1066  create_time = FormatISO8601DateTime(it->second.nCreateTime);
1067  }
1068  if (spk_man.GetCScript(scriptid, script)) {
1069  file << strprintf("%s %s script=1", HexStr(script),
1070  create_time);
1071  file << strprintf(" # addr=%s\n", address);
1072  }
1073  }
1074  file << "\n";
1075  file << "# End of dump\n";
1076  file.close();
1077 
1078  UniValue reply(UniValue::VOBJ);
1079  reply.pushKV("filename", filepath.u8string());
1080 
1081  return reply;
1082  },
1083  };
1084 }
1085 
1087  return RPCHelpMan{
1088  "dumpcoins",
1089  "dump all the UTXO tracked by the wallet.\n",
1090  {},
1091  RPCResult{
1093  "",
1094  "",
1095  {{
1097  "address",
1098  "The list of UTXO corresponding to this address.",
1099  {{
1101  "",
1102  "",
1103  {
1104  {RPCResult::Type::STR_HEX, "txid",
1105  "The transaction id"},
1106  {RPCResult::Type::NUM, "vout", "The output number"},
1107  {RPCResult::Type::NUM, "depth", "The output's depth"},
1108  {RPCResult::Type::STR_AMOUNT, "value",
1109  "The output's amount"},
1110  },
1111  }},
1112  }},
1113  },
1114  RPCExamples{HelpExampleCli("dumpcoins", "") +
1115  HelpExampleRpc("dumpcoins", "")},
1116  [&](const RPCHelpMan &self, const Config &config,
1117  const JSONRPCRequest &request) -> UniValue {
1118  std::shared_ptr<CWallet> const pwallet =
1119  GetWalletForJSONRPCRequest(request);
1120  if (!pwallet) {
1121  return NullUniValue;
1122  }
1123 
1124  CWallet &wallet = *pwallet;
1125 
1126  // Make sure the results are valid at least up to the most recent
1127  // block the user could have gotten from another RPC command prior
1128  // to now
1129  wallet.BlockUntilSyncedToCurrentChain();
1130 
1131  LOCK(wallet.cs_wallet);
1132 
1134 
1135  UniValue result(UniValue::VOBJ);
1136  for (const auto &p : ListCoins(wallet)) {
1137  UniValue coins(UniValue::VARR);
1138  for (const auto &o : p.second) {
1139  UniValue utxo(UniValue::VOBJ);
1140  utxo.pushKV("txid", o.tx->GetId().ToString());
1141  utxo.pushKV("vout", o.i);
1142  utxo.pushKV("depth", o.nDepth);
1143  utxo.pushKV("value", o.tx->tx->vout[o.i].nValue);
1144 
1145  coins.push_back(std::move(utxo));
1146  }
1147 
1148  result.pushKV(EncodeDestination(p.first, config), coins);
1149  }
1150 
1151  return result;
1152  },
1153  };
1154 }
1155 
1156 struct ImportData {
1157  // Input data
1159  std::unique_ptr<CScript> redeemscript;
1160 
1161  // Output data
1162  std::set<CScript> import_scripts;
1165  std::map<CKeyID, bool> used_keys;
1166  std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
1167 };
1168 
1169 enum class ScriptContext {
1171  TOP,
1173  P2SH,
1174 };
1175 
1176 // Analyse the provided scriptPubKey, determining which keys and which redeem
1177 // scripts from the ImportData struct are needed to spend it, and mark them as
1178 // used. Returns an error string, or the empty string for success.
1179 static std::string RecurseImportData(const CScript &script,
1180  ImportData &import_data,
1181  const ScriptContext script_ctx) {
1182  // Use Solver to obtain script type and parsed pubkeys or hashes:
1183  std::vector<std::vector<uint8_t>> solverdata;
1184  TxoutType script_type = Solver(script, solverdata);
1185 
1186  switch (script_type) {
1187  case TxoutType::PUBKEY: {
1188  CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
1189  import_data.used_keys.emplace(pubkey.GetID(), false);
1190  return "";
1191  }
1192  case TxoutType::PUBKEYHASH: {
1193  CKeyID id = CKeyID(uint160(solverdata[0]));
1194  import_data.used_keys[id] = true;
1195  return "";
1196  }
1197  case TxoutType::SCRIPTHASH: {
1198  if (script_ctx == ScriptContext::P2SH) {
1200  "Trying to nest P2SH inside another P2SH");
1201  }
1202  CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
1203  CScriptID id = CScriptID(uint160(solverdata[0]));
1204  // Remove redeemscript from import_data to check for superfluous
1205  // script later.
1206  auto subscript = std::move(import_data.redeemscript);
1207  if (!subscript) {
1208  return "missing redeemscript";
1209  }
1210  if (CScriptID(*subscript) != id) {
1211  return "redeemScript does not match the scriptPubKey";
1212  }
1213  import_data.import_scripts.emplace(*subscript);
1214  return RecurseImportData(*subscript, import_data,
1216  }
1217  case TxoutType::MULTISIG: {
1218  for (size_t i = 1; i + 1 < solverdata.size(); ++i) {
1219  CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
1220  import_data.used_keys.emplace(pubkey.GetID(), false);
1221  }
1222  return "";
1223  }
1224  case TxoutType::NULL_DATA:
1225  return "unspendable script";
1227  default:
1228  return "unrecognized script";
1229  }
1230 }
1231 
1233  CWallet *const pwallet, ImportData &import_data,
1234  std::map<CKeyID, CPubKey> &pubkey_map, std::map<CKeyID, CKey> &privkey_map,
1235  std::set<CScript> &script_pub_keys, bool &have_solving_data,
1236  const UniValue &data, std::vector<CKeyID> &ordered_pubkeys) {
1237  UniValue warnings(UniValue::VARR);
1238 
1239  // First ensure scriptPubKey has either a script or JSON with "address"
1240  // string
1241  const UniValue &scriptPubKey = data["scriptPubKey"];
1242  bool isScript = scriptPubKey.getType() == UniValue::VSTR;
1243  if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ &&
1244  scriptPubKey.exists("address"))) {
1246  "scriptPubKey must be string with script or JSON "
1247  "with address string");
1248  }
1249  const std::string &output =
1250  isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
1251 
1252  // Optional fields.
1253  const std::string &strRedeemScript =
1254  data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
1255  const UniValue &pubKeys =
1256  data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
1257  const UniValue &keys =
1258  data.exists("keys") ? data["keys"].get_array() : UniValue();
1259  const bool internal =
1260  data.exists("internal") ? data["internal"].get_bool() : false;
1261  const bool watchOnly =
1262  data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1263 
1264  if (data.exists("range")) {
1265  throw JSONRPCError(
1267  "Range should not be specified for a non-descriptor import");
1268  }
1269 
1270  // Generate the script and destination for the scriptPubKey provided
1271  CScript script;
1272  if (!isScript) {
1273  CTxDestination dest =
1274  DecodeDestination(output, pwallet->GetChainParams());
1275  if (!IsValidDestination(dest)) {
1277  "Invalid address \"" + output + "\"");
1278  }
1279  script = GetScriptForDestination(dest);
1280  } else {
1281  if (!IsHex(output)) {
1283  "Invalid scriptPubKey \"" + output + "\"");
1284  }
1285  std::vector<uint8_t> vData(ParseHex(output));
1286  script = CScript(vData.begin(), vData.end());
1287  CTxDestination dest;
1288  if (!ExtractDestination(script, dest) && !internal) {
1290  "Internal must be set to true for "
1291  "nonstandard scriptPubKey imports.");
1292  }
1293  }
1294  script_pub_keys.emplace(script);
1295 
1296  // Parse all arguments
1297  if (strRedeemScript.size()) {
1298  if (!IsHex(strRedeemScript)) {
1300  "Invalid redeem script \"" + strRedeemScript +
1301  "\": must be hex string");
1302  }
1303  auto parsed_redeemscript = ParseHex(strRedeemScript);
1304  import_data.redeemscript = std::make_unique<CScript>(
1305  parsed_redeemscript.begin(), parsed_redeemscript.end());
1306  }
1307  for (size_t i = 0; i < pubKeys.size(); ++i) {
1308  const auto &str = pubKeys[i].get_str();
1309  if (!IsHex(str)) {
1311  "Pubkey \"" + str + "\" must be a hex string");
1312  }
1313  auto parsed_pubkey = ParseHex(str);
1314  CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
1315  if (!pubkey.IsFullyValid()) {
1317  "Pubkey \"" + str +
1318  "\" is not a valid public key");
1319  }
1320  pubkey_map.emplace(pubkey.GetID(), pubkey);
1321  ordered_pubkeys.push_back(pubkey.GetID());
1322  }
1323  for (size_t i = 0; i < keys.size(); ++i) {
1324  const auto &str = keys[i].get_str();
1325  CKey key = DecodeSecret(str);
1326  if (!key.IsValid()) {
1328  "Invalid private key encoding");
1329  }
1330  CPubKey pubkey = key.GetPubKey();
1331  CKeyID id = pubkey.GetID();
1332  if (pubkey_map.count(id)) {
1333  pubkey_map.erase(id);
1334  }
1335  privkey_map.emplace(id, key);
1336  }
1337 
1338  // Verify and process input data
1339  have_solving_data =
1340  import_data.redeemscript || pubkey_map.size() || privkey_map.size();
1341  if (have_solving_data) {
1342  // Match up data in import_data with the scriptPubKey in script.
1343  auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1344 
1345  // Verify whether the watchonly option corresponds to the
1346  // availability of private keys.
1347  bool spendable = std::all_of(
1348  import_data.used_keys.begin(), import_data.used_keys.end(),
1349  [&](const std::pair<CKeyID, bool> &used_key) {
1350  return privkey_map.count(used_key.first) > 0;
1351  });
1352  if (!watchOnly && !spendable) {
1353  warnings.push_back("Some private keys are missing, outputs "
1354  "will be considered watchonly. If this is "
1355  "intentional, specify the watchonly flag.");
1356  }
1357  if (watchOnly && spendable) {
1358  warnings.push_back(
1359  "All private keys are provided, outputs will be considered "
1360  "spendable. If this is intentional, do not specify the "
1361  "watchonly flag.");
1362  }
1363 
1364  // Check that all required keys for solvability are provided.
1365  if (error.empty()) {
1366  for (const auto &require_key : import_data.used_keys) {
1367  if (!require_key.second) {
1368  // Not a required key
1369  continue;
1370  }
1371 
1372  if (pubkey_map.count(require_key.first) == 0 &&
1373  privkey_map.count(require_key.first) == 0) {
1374  error = "some required keys are missing";
1375  }
1376  }
1377  }
1378 
1379  if (!error.empty()) {
1380  warnings.push_back("Importing as non-solvable: " + error +
1381  ". If this is intentional, don't provide "
1382  "any keys, pubkeys or redeemscript.");
1383  import_data = ImportData();
1384  pubkey_map.clear();
1385  privkey_map.clear();
1386  have_solving_data = false;
1387  } else {
1388  // RecurseImportData() removes any relevant redeemscript from
1389  // import_data, so we can use that to discover if a superfluous
1390  // one was provided.
1391  if (import_data.redeemscript) {
1392  warnings.push_back(
1393  "Ignoring redeemscript as this is not a P2SH script.");
1394  }
1395  for (auto it = privkey_map.begin(); it != privkey_map.end();) {
1396  auto oldit = it++;
1397  if (import_data.used_keys.count(oldit->first) == 0) {
1398  warnings.push_back("Ignoring irrelevant private key.");
1399  privkey_map.erase(oldit);
1400  }
1401  }
1402  for (auto it = pubkey_map.begin(); it != pubkey_map.end();) {
1403  auto oldit = it++;
1404  auto key_data_it = import_data.used_keys.find(oldit->first);
1405  if (key_data_it == import_data.used_keys.end() ||
1406  !key_data_it->second) {
1407  warnings.push_back("Ignoring public key \"" +
1408  HexStr(oldit->first) +
1409  "\" as it doesn't appear inside P2PKH.");
1410  pubkey_map.erase(oldit);
1411  }
1412  }
1413  }
1414  }
1415 
1416  return warnings;
1417 }
1418 
1420  std::map<CKeyID, CPubKey> &pubkey_map,
1421  std::map<CKeyID, CKey> &privkey_map,
1422  std::set<CScript> &script_pub_keys,
1423  bool &have_solving_data,
1424  const UniValue &data,
1425  std::vector<CKeyID> &ordered_pubkeys) {
1426  UniValue warnings(UniValue::VARR);
1427 
1428  const std::string &descriptor = data["desc"].get_str();
1429  FlatSigningProvider keys;
1430  std::string error;
1431  auto parsed_desc =
1432  Parse(descriptor, keys, error, /* require_checksum = */ true);
1433  if (!parsed_desc) {
1435  }
1436 
1437  have_solving_data = parsed_desc->IsSolvable();
1438  const bool watch_only =
1439  data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1440 
1441  int64_t range_start = 0, range_end = 0;
1442  if (!parsed_desc->IsRange() && data.exists("range")) {
1443  throw JSONRPCError(
1445  "Range should not be specified for an un-ranged descriptor");
1446  } else if (parsed_desc->IsRange()) {
1447  if (!data.exists("range")) {
1448  throw JSONRPCError(
1450  "Descriptor is ranged, please specify the range");
1451  }
1452  std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1453  }
1454 
1455  const UniValue &priv_keys =
1456  data.exists("keys") ? data["keys"].get_array() : UniValue();
1457 
1458  // Expand all descriptors to get public keys and scripts, and private keys
1459  // if available.
1460  for (int i = range_start; i <= range_end; ++i) {
1461  FlatSigningProvider out_keys;
1462  std::vector<CScript> scripts_temp;
1463  parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1464  std::copy(scripts_temp.begin(), scripts_temp.end(),
1465  std::inserter(script_pub_keys, script_pub_keys.end()));
1466  for (const auto &key_pair : out_keys.pubkeys) {
1467  ordered_pubkeys.push_back(key_pair.first);
1468  }
1469 
1470  for (const auto &x : out_keys.scripts) {
1471  import_data.import_scripts.emplace(x.second);
1472  }
1473 
1474  parsed_desc->ExpandPrivate(i, keys, out_keys);
1475 
1476  std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(),
1477  std::inserter(pubkey_map, pubkey_map.end()));
1478  std::copy(out_keys.keys.begin(), out_keys.keys.end(),
1479  std::inserter(privkey_map, privkey_map.end()));
1480  import_data.key_origins.insert(out_keys.origins.begin(),
1481  out_keys.origins.end());
1482  }
1483 
1484  for (size_t i = 0; i < priv_keys.size(); ++i) {
1485  const auto &str = priv_keys[i].get_str();
1486  CKey key = DecodeSecret(str);
1487  if (!key.IsValid()) {
1489  "Invalid private key encoding");
1490  }
1491  CPubKey pubkey = key.GetPubKey();
1492  CKeyID id = pubkey.GetID();
1493 
1494  // Check if this private key corresponds to a public key from the
1495  // descriptor
1496  if (!pubkey_map.count(id)) {
1497  warnings.push_back("Ignoring irrelevant private key.");
1498  } else {
1499  privkey_map.emplace(id, key);
1500  }
1501  }
1502 
1503  // Check if all the public keys have corresponding private keys in the
1504  // import for spendability. This does not take into account threshold
1505  // multisigs which could be spendable without all keys. Thus, threshold
1506  // multisigs without all keys will be considered not spendable here, even if
1507  // they are, perhaps triggering a false warning message. This is consistent
1508  // with the current wallet IsMine check.
1509  bool spendable =
1510  std::all_of(pubkey_map.begin(), pubkey_map.end(),
1511  [&](const std::pair<CKeyID, CPubKey> &used_key) {
1512  return privkey_map.count(used_key.first) > 0;
1513  }) &&
1514  std::all_of(
1515  import_data.key_origins.begin(), import_data.key_origins.end(),
1516  [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>
1517  &entry) { return privkey_map.count(entry.first) > 0; });
1518  if (!watch_only && !spendable) {
1519  warnings.push_back(
1520  "Some private keys are missing, outputs will be considered "
1521  "watchonly. If this is intentional, specify the watchonly flag.");
1522  }
1523  if (watch_only && spendable) {
1524  warnings.push_back("All private keys are provided, outputs will be "
1525  "considered spendable. If this is intentional, do "
1526  "not specify the watchonly flag.");
1527  }
1528 
1529  return warnings;
1530 }
1531 
1532 static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data,
1533  const int64_t timestamp)
1534  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1535  UniValue warnings(UniValue::VARR);
1536  UniValue result(UniValue::VOBJ);
1537 
1538  try {
1539  const bool internal =
1540  data.exists("internal") ? data["internal"].get_bool() : false;
1541  // Internal addresses should not have a label
1542  if (internal && data.exists("label")) {
1544  "Internal addresses should not have a label");
1545  }
1546  const std::string &label =
1547  data.exists("label") ? data["label"].get_str() : "";
1548  const bool add_keypool =
1549  data.exists("keypool") ? data["keypool"].get_bool() : false;
1550 
1551  // Add to keypool only works with privkeys disabled
1552  if (add_keypool &&
1553  !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1555  "Keys can only be imported to the keypool when "
1556  "private keys are disabled");
1557  }
1558 
1559  ImportData import_data;
1560  std::map<CKeyID, CPubKey> pubkey_map;
1561  std::map<CKeyID, CKey> privkey_map;
1562  std::set<CScript> script_pub_keys;
1563  std::vector<CKeyID> ordered_pubkeys;
1564  bool have_solving_data;
1565 
1566  if (data.exists("scriptPubKey") && data.exists("desc")) {
1567  throw JSONRPCError(
1569  "Both a descriptor and a scriptPubKey should not be provided.");
1570  } else if (data.exists("scriptPubKey")) {
1571  warnings = ProcessImportLegacy(
1572  pwallet, import_data, pubkey_map, privkey_map, script_pub_keys,
1573  have_solving_data, data, ordered_pubkeys);
1574  } else if (data.exists("desc")) {
1575  warnings = ProcessImportDescriptor(
1576  import_data, pubkey_map, privkey_map, script_pub_keys,
1577  have_solving_data, data, ordered_pubkeys);
1578  } else {
1579  throw JSONRPCError(
1581  "Either a descriptor or scriptPubKey must be provided.");
1582  }
1583 
1584  // If private keys are disabled, abort if private keys are being
1585  // imported
1586  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
1587  !privkey_map.empty()) {
1589  "Cannot import private keys to a wallet with "
1590  "private keys disabled");
1591  }
1592 
1593  // Check whether we have any work to do
1594  for (const CScript &script : script_pub_keys) {
1595  if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1597  "The wallet already contains the private "
1598  "key for this address or script (\"" +
1599  HexStr(script) + "\")");
1600  }
1601  }
1602 
1603  // All good, time to import
1604  pwallet->MarkDirty();
1605  if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1607  "Error adding script to wallet");
1608  }
1609  if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1610  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1611  }
1612  if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map,
1613  import_data.key_origins, add_keypool,
1614  internal, timestamp)) {
1616  "Error adding address to wallet");
1617  }
1618  if (!pwallet->ImportScriptPubKeys(label, script_pub_keys,
1619  have_solving_data, !internal,
1620  timestamp)) {
1622  "Error adding address to wallet");
1623  }
1624 
1625  result.pushKV("success", UniValue(true));
1626  } catch (const UniValue &e) {
1627  result.pushKV("success", UniValue(false));
1628  result.pushKV("error", e);
1629  } catch (...) {
1630  result.pushKV("success", UniValue(false));
1631  result.pushKV("error",
1632  JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1633  }
1634 
1635  if (warnings.size()) {
1636  result.pushKV("warnings", warnings);
1637  }
1638  return result;
1639 }
1640 
1641 static int64_t GetImportTimestamp(const UniValue &data, int64_t now) {
1642  if (data.exists("timestamp")) {
1643  const UniValue &timestamp = data["timestamp"];
1644  if (timestamp.isNum()) {
1645  return timestamp.get_int64();
1646  } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1647  return now;
1648  }
1650  strprintf("Expected number or \"now\" timestamp "
1651  "value for key. got type %s",
1652  uvTypeName(timestamp.type())));
1653  }
1655  "Missing required timestamp field for key");
1656 }
1657 
1658 static std::string GetRescanErrorMessage(const std::string &object,
1659  const int64_t objectTimestamp,
1660  const int64_t blockTimestamp) {
1661  return strprintf(
1662  "Rescan failed for %s with creation timestamp %d. There was an error "
1663  "reading a block from time %d, which is after or within %d seconds of "
1664  "key creation, and could contain transactions pertaining to the %s. As "
1665  "a result, transactions and coins using this %s may not appear in "
1666  "the wallet. This error could be caused by pruning or data corruption "
1667  "(see bitcoind log for details) and could be dealt with by downloading "
1668  "and rescanning the relevant blocks (see -reindex and -rescan "
1669  "options).",
1670  object, objectTimestamp, blockTimestamp, TIMESTAMP_WINDOW, object,
1671  object);
1672 }
1673 
1675  return RPCHelpMan{
1676  "importmulti",
1677  "Import addresses/scripts (with private or public keys, redeem "
1678  "script (P2SH)), optionally rescanning the blockchain from the "
1679  "earliest creation time of the imported scripts. Requires a new wallet "
1680  "backup.\n"
1681  "If an address/script is imported without all of the private keys "
1682  "required to spend from that address, it will be watchonly. The "
1683  "'watchonly' option must be set to true in this case or a warning will "
1684  "be returned.\n"
1685  "Conversely, if all the private keys are provided and the "
1686  "address/script is spendable, the watchonly option must be set to "
1687  "false, or a warning will be returned.\n"
1688  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1689  {
1690  {"requests",
1693  "Data to be imported",
1694  {
1695  {
1696  "",
1699  "",
1700  {
1702  "Descriptor to import. If using descriptor, do not "
1703  "also provide address/scriptPubKey, scripts, or "
1704  "pubkeys"},
1705  {"scriptPubKey",
1708  "Type of scriptPubKey (string for script, json for "
1709  "address). Should not be provided if using a "
1710  "descriptor",
1711  /* oneline_description */ "",
1712  {"\"<script>\" | { \"address\":\"<address>\" }",
1713  "string / json"}},
1714  {"timestamp",
1717  "Creation time of the key expressed in " +
1718  UNIX_EPOCH_TIME +
1719  ",\n"
1720  " "
1721  " or the string \"now\" to "
1722  "substitute the current synced blockchain time. "
1723  "The "
1724  "timestamp of the oldest\n"
1725  " "
1726  " key will determine how far "
1727  "back "
1728  "blockchain rescans need to begin for missing "
1729  "wallet "
1730  "transactions.\n"
1731  " "
1732  " \"now\" can be specified to "
1733  "bypass scanning, for keys which are known to "
1734  "never "
1735  "have been used, and\n"
1736  " "
1737  " 0 can be specified to scan "
1738  "the "
1739  "entire blockchain. Blocks up to 2 hours before "
1740  "the "
1741  "earliest key\n"
1742  " "
1743  " creation time of all keys "
1744  "being "
1745  "imported by the importmulti call will be "
1746  "scanned.",
1747  /* oneline_description */ "",
1748  {"timestamp | \"now\"", "integer / string"}},
1749  {"redeemscript", RPCArg::Type::STR,
1751  "Allowed only if the scriptPubKey is a P2SH "
1752  "address/scriptPubKey"},
1753  {"pubkeys",
1755  /* default */ "empty array",
1756  "Array of strings giving pubkeys to import. They "
1757  "must occur in P2PKH scripts. They are not required "
1758  "when the private key is also provided (see the "
1759  "\"keys\" argument).",
1760  {
1761  {"pubKey", RPCArg::Type::STR,
1763  }},
1764  {"keys",
1766  /* default */ "empty array",
1767  "Array of strings giving private keys to import. The "
1768  "corresponding public keys must occur in the output "
1769  "or redeemscript.",
1770  {
1771  {"key", RPCArg::Type::STR,
1773  }},
1774  {"range", RPCArg::Type::RANGE,
1776  "If a ranged descriptor is used, this specifies the "
1777  "end or the range (in the form [begin,end]) to "
1778  "import"},
1779  {"internal", RPCArg::Type::BOOL,
1780  /* default */ "false",
1781  "Stating whether matching outputs should be treated "
1782  "as not incoming payments (also known as change)"},
1783  {"watchonly", RPCArg::Type::BOOL,
1784  /* default */ "false",
1785  "Stating whether matching outputs should be "
1786  "considered watchonly."},
1787  {"label", RPCArg::Type::STR, /* default */ "''",
1788  "Label to assign to the address, only allowed with "
1789  "internal=false"},
1790  {"keypool", RPCArg::Type::BOOL, /* default */ "false",
1791  "Stating whether imported public keys should be "
1792  "added to the keypool for when users request new "
1793  "addresses. Only allowed when wallet private keys "
1794  "are disabled"},
1795  },
1796  },
1797  },
1798  "\"requests\""},
1799  {"options",
1802  "",
1803  {
1804  {"rescan", RPCArg::Type::BOOL, /* default */ "true",
1805  "Stating if should rescan the blockchain after all imports"},
1806  },
1807  "\"options\""},
1808  },
1810  "",
1811  "Response is an array with the same size as the input that "
1812  "has the execution result",
1813  {
1815  "",
1816  "",
1817  {
1818  {RPCResult::Type::BOOL, "success", ""},
1820  "warnings",
1821  /* optional */ true,
1822  "",
1823  {
1824  {RPCResult::Type::STR, "", ""},
1825  }},
1827  "error",
1828  /* optional */ true,
1829  "",
1830  {
1831  {RPCResult::Type::ELISION, "", "JSONRPC error"},
1832  }},
1833  }},
1834  }},
1835  RPCExamples{
1837  "importmulti",
1838  "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1839  "\"timestamp\":1455191478 }, "
1840  "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" "
1841  "}, "
1842  "\"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1844  "importmulti",
1845  "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1846  "\"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1847 
1848  },
1849  [&](const RPCHelpMan &self, const Config &config,
1850  const JSONRPCRequest &mainRequest) -> UniValue {
1851  std::shared_ptr<CWallet> const wallet =
1852  GetWalletForJSONRPCRequest(mainRequest);
1853  if (!wallet) {
1854  return NullUniValue;
1855  }
1856  CWallet *const pwallet = wallet.get();
1857 
1858  RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1859 
1861 
1862  const UniValue &requests = mainRequest.params[0];
1863 
1864  // Default options
1865  bool fRescan = true;
1866 
1867  if (!mainRequest.params[1].isNull()) {
1868  const UniValue &options = mainRequest.params[1];
1869 
1870  if (options.exists("rescan")) {
1871  fRescan = options["rescan"].get_bool();
1872  }
1873  }
1874 
1875  WalletRescanReserver reserver(*pwallet);
1876  if (fRescan && !reserver.reserve()) {
1878  "Wallet is currently rescanning. Abort "
1879  "existing rescan or wait.");
1880  }
1881 
1882  int64_t now = 0;
1883  bool fRunScan = false;
1884  int64_t nLowestTimestamp = 0;
1886  {
1887  LOCK(pwallet->cs_wallet);
1888  EnsureWalletIsUnlocked(pwallet);
1889 
1890  // Verify all timestamps are present before importing any keys.
1891  CHECK_NONFATAL(pwallet->chain().findBlock(
1892  pwallet->GetLastBlockHash(),
1893  FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1894  for (const UniValue &data : requests.getValues()) {
1895  GetImportTimestamp(data, now);
1896  }
1897 
1898  const int64_t minimumTimestamp = 1;
1899 
1900  for (const UniValue &data : requests.getValues()) {
1901  const int64_t timestamp = std::max(
1902  GetImportTimestamp(data, now), minimumTimestamp);
1903  const UniValue result =
1904  ProcessImport(pwallet, data, timestamp);
1905  response.push_back(result);
1906 
1907  if (!fRescan) {
1908  continue;
1909  }
1910 
1911  // If at least one request was successful then allow rescan.
1912  if (result["success"].get_bool()) {
1913  fRunScan = true;
1914  }
1915 
1916  // Get the lowest timestamp.
1917  if (timestamp < nLowestTimestamp) {
1918  nLowestTimestamp = timestamp;
1919  }
1920  }
1921  }
1922  if (fRescan && fRunScan && requests.size()) {
1923  int64_t scannedTime = pwallet->RescanFromTime(
1924  nLowestTimestamp, reserver, true /* update */);
1925  {
1926  LOCK(pwallet->cs_wallet);
1927  pwallet->ReacceptWalletTransactions();
1928  }
1929 
1930  if (pwallet->IsAbortingRescan()) {
1932  "Rescan aborted by user.");
1933  }
1934  if (scannedTime > nLowestTimestamp) {
1935  std::vector<UniValue> results = response.getValues();
1936  response.clear();
1937  response.setArray();
1938  size_t i = 0;
1939  for (const UniValue &request : requests.getValues()) {
1940  // If key creation date is within the successfully
1941  // scanned range, or if the import result already has an
1942  // error set, let the result stand unmodified. Otherwise
1943  // replace the result with an error message.
1944  if (scannedTime <= GetImportTimestamp(request, now) ||
1945  results.at(i).exists("error")) {
1946  response.push_back(results.at(i));
1947  } else {
1948  UniValue result = UniValue(UniValue::VOBJ);
1949  result.pushKV("success", UniValue(false));
1950  result.pushKV(
1951  "error",
1952  JSONRPCError(
1955  "key", GetImportTimestamp(request, now),
1956  scannedTime - TIMESTAMP_WINDOW - 1)));
1957  response.push_back(std::move(result));
1958  }
1959  ++i;
1960  }
1961  }
1962  }
1963 
1964  return response;
1965  },
1966  };
1967 }
1968 
1970  const UniValue &data,
1971  const int64_t timestamp)
1972  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1973  UniValue warnings(UniValue::VARR);
1974  UniValue result(UniValue::VOBJ);
1975 
1976  try {
1977  if (!data.exists("desc")) {
1978  throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor not found.");
1979  }
1980 
1981  const std::string &descriptor = data["desc"].get_str();
1982  const bool active =
1983  data.exists("active") ? data["active"].get_bool() : false;
1984  const bool internal =
1985  data.exists("internal") ? data["internal"].get_bool() : false;
1986  const std::string &label =
1987  data.exists("label") ? data["label"].get_str() : "";
1988 
1989  // Parse descriptor string
1990  FlatSigningProvider keys;
1991  std::string error;
1992  auto parsed_desc =
1993  Parse(descriptor, keys, error, /* require_checksum = */ true);
1994  if (!parsed_desc) {
1996  }
1997 
1998  // Range check
1999  int64_t range_start = 0, range_end = 1, next_index = 0;
2000  if (!parsed_desc->IsRange() && data.exists("range")) {
2001  throw JSONRPCError(
2003  "Range should not be specified for an un-ranged descriptor");
2004  } else if (parsed_desc->IsRange()) {
2005  if (data.exists("range")) {
2006  auto range = ParseDescriptorRange(data["range"]);
2007  range_start = range.first;
2008  // Specified range end is inclusive, but we need range end as
2009  // exclusive
2010  range_end = range.second + 1;
2011  } else {
2012  warnings.push_back(
2013  "Range not given, using default keypool range");
2014  range_start = 0;
2015  range_end = gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE);
2016  }
2017  next_index = range_start;
2018 
2019  if (data.exists("next_index")) {
2020  next_index = data["next_index"].get_int64();
2021  // bound checks
2022  if (next_index < range_start || next_index >= range_end) {
2024  "next_index is out of range");
2025  }
2026  }
2027  }
2028 
2029  // Active descriptors must be ranged
2030  if (active && !parsed_desc->IsRange()) {
2032  "Active descriptors must be ranged");
2033  }
2034 
2035  // Ranged descriptors should not have a label
2036  if (data.exists("range") && data.exists("label")) {
2038  "Ranged descriptors should not have a label");
2039  }
2040 
2041  // Internal addresses should not have a label either
2042  if (internal && data.exists("label")) {
2044  "Internal addresses should not have a label");
2045  }
2046 
2047  // Combo descriptor check
2048  if (active && !parsed_desc->IsSingleType()) {
2050  "Combo descriptors cannot be set to active");
2051  }
2052 
2053  // If the wallet disabled private keys, abort if private keys exist
2054  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
2055  !keys.keys.empty()) {
2057  "Cannot import private keys to a wallet with "
2058  "private keys disabled");
2059  }
2060 
2061  // Need to ExpandPrivate to check if private keys are available for all
2062  // pubkeys
2063  FlatSigningProvider expand_keys;
2064  std::vector<CScript> scripts;
2065  if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
2066  throw JSONRPCError(
2068  "Cannot expand descriptor. Probably because of hardened "
2069  "derivations without private keys provided");
2070  }
2071  parsed_desc->ExpandPrivate(0, keys, expand_keys);
2072 
2073  // Check if all private keys are provided
2074  bool have_all_privkeys = !expand_keys.keys.empty();
2075  for (const auto &entry : expand_keys.origins) {
2076  const CKeyID &key_id = entry.first;
2077  CKey key;
2078  if (!expand_keys.GetKey(key_id, key)) {
2079  have_all_privkeys = false;
2080  break;
2081  }
2082  }
2083 
2084  // If private keys are enabled, check some things.
2085  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
2086  if (keys.keys.empty()) {
2087  throw JSONRPCError(
2089  "Cannot import descriptor without private keys to a wallet "
2090  "with private keys enabled");
2091  }
2092  if (!have_all_privkeys) {
2093  warnings.push_back(
2094  "Not all private keys provided. Some wallet functionality "
2095  "may return unexpected errors");
2096  }
2097  }
2098 
2099  WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start,
2100  range_end, next_index);
2101 
2102  // Check if the wallet already contains the descriptor
2103  auto existing_spk_manager =
2104  pwallet->GetDescriptorScriptPubKeyMan(w_desc);
2105  if (existing_spk_manager) {
2106  LOCK(existing_spk_manager->cs_desc_man);
2107  if (range_start >
2108  existing_spk_manager->GetWalletDescriptor().range_start) {
2109  throw JSONRPCError(
2111  strprintf(
2112  "range_start can only decrease; current range = "
2113  "[%d,%d]",
2114  existing_spk_manager->GetWalletDescriptor().range_start,
2115  existing_spk_manager->GetWalletDescriptor().range_end));
2116  }
2117  }
2118 
2119  // Add descriptor to the wallet
2120  auto spk_manager =
2121  pwallet->AddWalletDescriptor(w_desc, keys, label, internal);
2122  if (spk_manager == nullptr) {
2123  throw JSONRPCError(
2125  strprintf("Could not add descriptor '%s'", descriptor));
2126  }
2127 
2128  // Set descriptor as active if necessary
2129  if (active) {
2130  if (!w_desc.descriptor->GetOutputType()) {
2131  warnings.push_back(
2132  "Unknown output type, cannot set descriptor to active.");
2133  } else {
2134  pwallet->AddActiveScriptPubKeyMan(
2135  spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2136  internal);
2137  }
2138  }
2139 
2140  result.pushKV("success", UniValue(true));
2141  } catch (const UniValue &e) {
2142  result.pushKV("success", UniValue(false));
2143  result.pushKV("error", e);
2144  } catch (...) {
2145  result.pushKV("success", UniValue(false));
2146 
2147  result.pushKV("error",
2148  JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
2149  }
2150  if (warnings.size()) {
2151  result.pushKV("warnings", warnings);
2152  }
2153  return result;
2154 }
2155 
2157  return RPCHelpMan{
2158  "importdescriptors",
2159  "Import descriptors. This will trigger a rescan of the blockchain "
2160  "based on the earliest timestamp of all descriptors being imported. "
2161  "Requires a new wallet backup.\n"
2162  "\nNote: This call can take over an hour to complete if using an early "
2163  "timestamp; during that time, other rpc calls\n"
2164  "may report that the imported keys, addresses or scripts exist but "
2165  "related transactions are still missing.\n",
2166  {
2167  {"requests",
2170  "Data to be imported",
2171  {
2172  {
2173  "",
2176  "",
2177  {
2179  "Descriptor to import."},
2180  {"active", RPCArg::Type::BOOL, /* default */ "false",
2181  "Set this descriptor to be the active descriptor for "
2182  "the corresponding output type/externality"},
2183  {"range", RPCArg::Type::RANGE,
2185  "If a ranged descriptor is used, this specifies the "
2186  "end or the range (in the form [begin,end]) to "
2187  "import"},
2188  {"next_index", RPCArg::Type::NUM,
2190  "If a ranged descriptor is set to active, this "
2191  "specifies the next index to generate addresses "
2192  "from"},
2193  {"timestamp",
2196  "Time from which to start rescanning the blockchain "
2197  "for this descriptor, in " +
2198  UNIX_EPOCH_TIME +
2199  "\n"
2200  " "
2201  " Use the string \"now\" to "
2202  "substitute the current synced blockchain time.\n"
2203  " "
2204  " \"now\" can be specified to "
2205  "bypass scanning, for outputs which are known to "
2206  "never have been used, and\n"
2207  " "
2208  " 0 can be specified to scan the "
2209  "entire blockchain. Blocks up to 2 hours before "
2210  "the earliest timestamp\n"
2211  " "
2212  " of all descriptors being imported "
2213  "will be scanned.",
2214  /* oneline_description */ "",
2215  {"timestamp | \"now\"", "integer / string"}},
2216  {"internal", RPCArg::Type::BOOL, /* default */ "false",
2217  "Whether matching outputs should be treated as not "
2218  "incoming payments (e.g. change)"},
2219  {"label", RPCArg::Type::STR, /* default */ "''",
2220  "Label to assign to the address, only allowed with "
2221  "internal=false"},
2222  },
2223  },
2224  },
2225  "\"requests\""},
2226  },
2228  "",
2229  "Response is an array with the same size as the input that "
2230  "has the execution result",
2231  {
2233  "",
2234  "",
2235  {
2236  {RPCResult::Type::BOOL, "success", ""},
2238  "warnings",
2239  /* optional */ true,
2240  "",
2241  {
2242  {RPCResult::Type::STR, "", ""},
2243  }},
2245  "error",
2246  /* optional */ true,
2247  "",
2248  {
2249  {RPCResult::Type::ELISION, "", "JSONRPC error"},
2250  }},
2251  }},
2252  }},
2253  RPCExamples{
2254  HelpExampleCli("importdescriptors",
2255  "'[{ \"desc\": \"<my descriptor>\", "
2256  "\"timestamp\":1455191478, \"internal\": true }, "
2257  "{ \"desc\": \"<my desccriptor 2>\", \"label\": "
2258  "\"example 2\", \"timestamp\": 1455191480 }]'") +
2260  "importdescriptors",
2261  "'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, "
2262  "\"active\": true, \"range\": [0,100], \"label\": \"<my "
2263  "cashaddr wallet>\" }]'")},
2264  [&](const RPCHelpMan &self, const Config &config,
2265  const JSONRPCRequest &main_request) -> UniValue {
2266  std::shared_ptr<CWallet> const wallet =
2267  GetWalletForJSONRPCRequest(main_request);
2268  if (!wallet) {
2269  return NullUniValue;
2270  }
2271  CWallet *const pwallet = wallet.get();
2272 
2273  // Make sure wallet is a descriptor wallet
2274  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
2276  "importdescriptors is not available for "
2277  "non-descriptor wallets");
2278  }
2279 
2280  RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
2281 
2282  WalletRescanReserver reserver(*pwallet);
2283  if (!reserver.reserve()) {
2285  "Wallet is currently rescanning. Abort "
2286  "existing rescan or wait.");
2287  }
2288 
2289  const UniValue &requests = main_request.params[0];
2290  const int64_t minimum_timestamp = 1;
2291  int64_t now = 0;
2292  int64_t lowest_timestamp = 0;
2293  bool rescan = false;
2295  {
2296  LOCK(pwallet->cs_wallet);
2297  EnsureWalletIsUnlocked(pwallet);
2298 
2299  CHECK_NONFATAL(pwallet->chain().findBlock(
2300  pwallet->GetLastBlockHash(),
2301  FoundBlock().time(lowest_timestamp).mtpTime(now)));
2302 
2303  // Get all timestamps and extract the lowest timestamp
2304  for (const UniValue &request : requests.getValues()) {
2305  // This throws an error if "timestamp" doesn't exist
2306  const int64_t timestamp = std::max(
2307  GetImportTimestamp(request, now), minimum_timestamp);
2308  const UniValue result =
2309  ProcessDescriptorImport(pwallet, request, timestamp);
2310  response.push_back(result);
2311 
2312  if (lowest_timestamp > timestamp) {
2313  lowest_timestamp = timestamp;
2314  }
2315 
2316  // If we know the chain tip, and at least one request was
2317  // successful then allow rescan
2318  if (!rescan && result["success"].get_bool()) {
2319  rescan = true;
2320  }
2321  }
2323  }
2324 
2325  // Rescan the blockchain using the lowest timestamp
2326  if (rescan) {
2327  int64_t scanned_time = pwallet->RescanFromTime(
2328  lowest_timestamp, reserver, true /* update */);
2329  {
2330  LOCK(pwallet->cs_wallet);
2331  pwallet->ReacceptWalletTransactions();
2332  }
2333 
2334  if (pwallet->IsAbortingRescan()) {
2336  "Rescan aborted by user.");
2337  }
2338 
2339  if (scanned_time > lowest_timestamp) {
2340  std::vector<UniValue> results = response.getValues();
2341  response.clear();
2342  response.setArray();
2343 
2344  // Compose the response
2345  for (unsigned int i = 0; i < requests.size(); ++i) {
2346  const UniValue &request = requests.getValues().at(i);
2347 
2348  // If the descriptor timestamp is within the
2349  // successfully scanned range, or if the import result
2350  // already has an error set, let the result stand
2351  // unmodified. Otherwise replace the result with an
2352  // error message.
2353  if (scanned_time <= GetImportTimestamp(request, now) ||
2354  results.at(i).exists("error")) {
2355  response.push_back(results.at(i));
2356  } else {
2357  UniValue result = UniValue(UniValue::VOBJ);
2358  result.pushKV("success", UniValue(false));
2359  result.pushKV(
2360  "error",
2361  JSONRPCError(
2364  "descriptor",
2365  GetImportTimestamp(request, now),
2366  scanned_time - TIMESTAMP_WINDOW - 1)));
2367  response.push_back(std::move(result));
2368  }
2369  }
2370  }
2371  }
2372 
2373  return response;
2374  },
2375  };
2376 }
2377 
2379  return RPCHelpMan{
2380  "backupwallet",
2381  "Safely copies current wallet file to destination, which can be a "
2382  "directory or a path with filename.\n",
2383  {
2384  {"destination", RPCArg::Type::STR, RPCArg::Optional::NO,
2385  "The destination directory or file"},
2386  },
2388  RPCExamples{HelpExampleCli("backupwallet", "\"backup.dat\"") +
2389  HelpExampleRpc("backupwallet", "\"backup.dat\"")},
2390  [&](const RPCHelpMan &self, const Config &config,
2391  const JSONRPCRequest &request) -> UniValue {
2392  std::shared_ptr<CWallet> const wallet =
2393  GetWalletForJSONRPCRequest(request);
2394  if (!wallet) {
2395  return NullUniValue;
2396  }
2397  const CWallet *const pwallet = wallet.get();
2398 
2399  // Make sure the results are valid at least up to the most recent
2400  // block the user could have gotten from another RPC command prior
2401  // to now
2402  pwallet->BlockUntilSyncedToCurrentChain();
2403 
2404  LOCK(pwallet->cs_wallet);
2405 
2406  std::string strDest = request.params[0].get_str();
2407  if (!pwallet->BackupWallet(strDest)) {
2409  "Error: Wallet backup failed!");
2410  }
2411 
2412  return NullUniValue;
2413  },
2414  };
2415 }
2416 
2418  return RPCHelpMan{
2419  "restorewallet",
2420  "\nRestore and loads a wallet from backup.\n",
2421  {
2422  {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO,
2423  "The name that will be applied to the restored wallet"},
2424  {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO,
2425  "The backup file that will be used to restore the wallet."},
2426  {"load_on_startup", RPCArg::Type::BOOL,
2428  "Save wallet name to persistent settings and load on startup. "
2429  "True to add wallet to startup list, false to remove, null to "
2430  "leave unchanged."},
2431  },
2433  "",
2434  "",
2435  {
2436  {RPCResult::Type::STR, "name",
2437  "The wallet name if restored successfully."},
2438  {RPCResult::Type::STR, "warning",
2439  "Warning message if wallet was not loaded cleanly."},
2440  }},
2442  "restorewallet",
2443  "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2445  "restorewallet",
2446  "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2448  "restorewallet",
2449  {{"wallet_name", "testwallet"},
2450  {"backup_file", "home\\backups\\backup-file.bak\""},
2451  {"load_on_startup", true}}) +
2453  "restorewallet",
2454  {{"wallet_name", "testwallet"},
2455  {"backup_file", "home\\backups\\backup-file.bak\""},
2456  {"load_on_startup", true}})},
2457  [&](const RPCHelpMan &self, const Config &config,
2458  const JSONRPCRequest &request) -> UniValue {
2459  WalletContext &context = EnsureWalletContext(request.context);
2460 
2461  fs::path backup_file =
2462  fs::PathFromString(request.params[1].get_str());
2463 
2464  if (!fs::exists(backup_file)) {
2466  "Backup file does not exist");
2467  }
2468 
2469  std::string wallet_name = request.params[0].get_str();
2470 
2471  const fs::path wallet_path = fsbridge::AbsPathJoin(
2472  GetWalletDir(), fs::PathFromString(wallet_name));
2473 
2474  if (fs::exists(wallet_path)) {
2476  "Wallet name already exists.");
2477  }
2478 
2479  if (!TryCreateDirectories(wallet_path)) {
2481  strprintf("Failed to create database path "
2482  "'%s'. Database already exists.",
2483  fs::PathToString(wallet_path)));
2484  }
2485 
2486  auto wallet_file = wallet_path / "wallet.dat";
2487 
2488  fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
2489 
2490  auto [wallet, warnings] =
2491  LoadWalletHelper(context, request.params[2], wallet_name);
2492 
2493  UniValue obj(UniValue::VOBJ);
2494  obj.pushKV("name", wallet->GetName());
2495  obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2496 
2497  return obj;
2498  },
2499  };
2500 }
2501 
2503  // clang-format off
2504  static const CRPCCommand commands[] = {
2505  // category actor (function)
2506  // ------------------ ----------------------
2507  { "wallet", abortrescan, },
2508  { "wallet", backupwallet, },
2509  { "wallet", dumpprivkey, },
2510  { "wallet", dumpwallet, },
2511  { "wallet", dumpcoins, },
2512  { "wallet", importdescriptors, },
2513  { "wallet", importmulti, },
2514  { "wallet", importprivkey, },
2515  { "wallet", importwallet, },
2516  { "wallet", importaddress, },
2517  { "wallet", importprunedfunds, },
2518  { "wallet", importpubkey, },
2519  { "wallet", removeprunedfunds, },
2520  { "wallet", restorewallet, },
2521  };
2522  // clang-format on
2523 
2524  return MakeSpan(commands);
2525 }
static RPCHelpMan dumpcoins()
Definition: backup.cpp:1086
RPCHelpMan importprivkey()
Definition: backup.cpp:110
static const int64_t TIMESTAMP_MIN
Definition: backup.cpp:95
RPCHelpMan importdescriptors()
Definition: backup.cpp:2156
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
Definition: backup.cpp:97
RPCHelpMan importmulti()
Definition: backup.cpp:1674
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Definition: backup.cpp:1179
RPCHelpMan importaddress()
Definition: backup.cpp:266
RPCHelpMan importwallet()
Definition: backup.cpp:641
RPCHelpMan dumpwallet()
Definition: backup.cpp:908
static UniValue ProcessImportLegacy(CWallet *const pwallet, ImportData &import_data, std::map< CKeyID, CPubKey > &pubkey_map, std::map< CKeyID, CKey > &privkey_map, std::set< CScript > &script_pub_keys, bool &have_solving_data, const UniValue &data, std::vector< CKeyID > &ordered_pubkeys)
Definition: backup.cpp:1232
RPCHelpMan importpubkey()
Definition: backup.cpp:532
static std::string EncodeDumpString(const std::string &str)
Definition: backup.cpp:41
static bool GetWalletAddressesForKey(const Config &config, LegacyScriptPubKeyMan *spk_man, const CWallet *const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:68
static std::string DecodeDumpString(const std::string &str)
Definition: backup.cpp:53
RPCHelpMan importprunedfunds()
Definition: backup.cpp:399
Span< const CRPCCommand > GetWalletDumpRPCCommands()
Definition: backup.cpp:2502
RPCHelpMan restorewallet()
Definition: backup.cpp:2417
static UniValue ProcessImportDescriptor(ImportData &import_data, std::map< CKeyID, CPubKey > &pubkey_map, std::map< CKeyID, CKey > &privkey_map, std::set< CScript > &script_pub_keys, bool &have_solving_data, const UniValue &data, std::vector< CKeyID > &ordered_pubkeys)
Definition: backup.cpp:1419
RPCHelpMan abortrescan()
Definition: backup.cpp:233
ScriptContext
Definition: backup.cpp:1169
@ P2SH
P2SH redeemScript.
@ TOP
Top-level scriptPubKey.
static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:1532
RPCHelpMan backupwallet()
Definition: backup.cpp:2378
RPCHelpMan dumpprivkey()
Definition: backup.cpp:856
static UniValue ProcessDescriptorImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:1969
RPCHelpMan removeprunedfunds()
Definition: backup.cpp:482
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: backup.cpp:1641
static std::string GetRescanErrorMessage(const std::string &object, const int64_t objectTimestamp, const int64_t blockTimestamp)
Definition: backup.cpp:1658
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath)
Write HD keypaths as strings.
Definition: bip32.cpp:66
static constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
Definition: chain.h:36
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:52
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: system.cpp:591
BlockHash GetHash() const
Definition: block.cpp:11
uint256 hashMerkleRoot
Definition: block.h:27
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:197
CKeyID seed_id
seed hash160
Definition: walletdb.h:92
An encapsulated secp256k1 private key.
Definition: key.h:28
const uint8_t * begin() const
Definition: key.h:90
unsigned int size() const
Simple read-only vector-like interface.
Definition: key.h:89
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:94
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:210
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:302
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:22
Used to create a Merkle proof (usually from a subset of transactions), which consists of a block head...
Definition: merkleblock.h:147
CBlockHeader header
Public only for unit testing.
Definition: merkleblock.h:150
CPartialMerkleTree txn
Definition: merkleblock.h:151
A mutable version of CTransaction.
Definition: transaction.h:280
TxId GetId() const
Compute the id and hash of this CMutableTransaction.
Definition: transaction.cpp:51
uint256 ExtractMatches(std::vector< uint256 > &vMatch, std::vector< size_t > &vnIndex)
Extract the matching txid's represented by this partial merkle tree and their respective indices with...
An encapsulated public key.
Definition: pubkey.h:31
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:140
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:256
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:431
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:26
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:251
BlockHash GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.h:1022
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
Definition: wallet.cpp:3310
const std::string GetDisplayName() const override
Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet ha...
Definition: wallet.h:951
RecursiveMutex cs_wallet
Definition: wallet.h:386
void WalletLogPrintf(std::string fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
Definition: wallet.h:962
bool IsAbortingRescan() const
Definition: wallet.h:512
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:445
bool BackupWallet(const std::string &strDest) const
Definition: wallet.cpp:3094
bool IsScanning() const
Definition: wallet.h:513
void AbortRescan()
Definition: wallet.h:511
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3028
Definition: config.h:17
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
virtual std::set< CScriptID > GetCScripts() const
RecursiveMutex cs_KeyStore
const CHDChain & GetHDChain() const
bool GetKey(const CKeyID &address, CKey &keyOut) const override
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:93
const std::string & get_str() const
enum VType getType() const
Definition: univalue.h:76
@ VOBJ
Definition: univalue.h:27
@ VSTR
Definition: univalue.h:27
@ VARR
Definition: univalue.h:27
int64_t get_int64() const
size_t size() const
Definition: univalue.h:80
enum VType type() const
Definition: univalue.h:135
const std::vector< UniValue > & getValues() const
bool isStr() const
Definition: univalue.h:93
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:87
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool isNum() const
Definition: univalue.h:94
bool get_bool() const
Descriptor with some wallet metadata.
Definition: walletutil.h:80
std::shared_ptr< Descriptor > descriptor
Definition: walletutil.h:82
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1084
bool IsNull() const
Definition: uint256.h:30
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:29
virtual bool findAncestorByHash(const BlockHash &block_hash, const BlockHash &ancestor_hash, const FoundBlock &ancestor_out={})=0
Return whether block descends from a specified ancestor, and optionally return ancestor information.
virtual bool findBlock(const BlockHash &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
virtual void showProgress(const std::string &title, int progress, bool resume_possible)=0
Send progress indicator.
virtual bool havePruned()=0
Check if any block has been pruned.
Helper for findBlock to selectively return pieces of block data.
Definition: chain.h:48
160-bit opaque blob.
Definition: uint256.h:115
256-bit opaque blob.
Definition: uint256.h:127
const std::string CLIENT_BUILD
const std::string CLIENT_NAME
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:197
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:2257
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:2198
bool ImportPubKeys(const std::vector< CKeyID > &ordered_pubkeys, const std::map< CKeyID, CPubKey > &pubkey_map, const std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo >> &key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1604
void MarkDirty()
Definition: wallet.cpp:891
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1584
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true)
Definition: wallet.cpp:949
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1594
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1421
bool ImportScriptPubKeys(const std::string &label, const std::set< CScript > &script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1618
const CChainParams & GetChainParams() const override
Definition: wallet.cpp:383
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1845
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
Definition: wallet.cpp:1514
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1653
@ ISMINE_SPENDABLE
Definition: ismine.h:21
std::string EncodeDestination(const CTxDestination &dest, const Config &config)
Definition: key_io.cpp:170
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:159
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:105
CTxDestination DecodeDestination(const std::string &addr, const CChainParams &params)
Definition: key_io.cpp:177
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:80
static path absolute(const path &p)
Definition: fs.h:83
static bool exists(const path &p)
Definition: fs.h:89
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:106
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:136
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:149
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:37
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:35
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
Definition: outputtype.cpp:43
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:322
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:321
Response response
Definition: processor.cpp:441
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:57
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_INVALID_PARAMS
Definition: protocol.h:30
@ RPC_TYPE_ERROR
Unexpected type was passed as parameter.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_WALLET_ERROR
Wallet errors Unspecified problem with wallet (key not found etc.)
Definition: protocol.h:90
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:50
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::pair< int64_t, int64_t > ParseDescriptorRange(const UniValue &value)
Parse a JSON range specified as int64, or [int64, int64].
Definition: util.cpp:1013
std::vector< uint8_t > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:122
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:27
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:178
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:204
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:195
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency.
Definition: util.cpp:23
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:101
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:183
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
@ SER_NETWORK
Definition: serialize.h:166
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
constexpr Span< A > MakeSpan(A(&a)[N])
MakeSpan for arrays:
Definition: span.h:259
std::map< CTxDestination, std::vector< COutput > > ListCoins(const CWallet &wallet)
Return list of available coins and locked coins grouped by non-change output address.
Definition: spend.cpp:247
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:161
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< uint8_t >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:111
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:263
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:243
boost::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:93
TxoutType
Definition: standard.h:46
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
bool IsHex(const std::string &str)
Returns true if each character in str is a hex character, and has an even number of hex digits.
std::vector< uint8_t > ParseHex(const char *psz)
auto Join(const std::vector< T > &list, const BaseType &separator, UnaryOp unary_op) -> decltype(unary_op(list.at(0)))
Join a list of items.
Definition: string.h:46
Definition: key.h:164
void SetSeed(const uint8_t *seed, unsigned int nSeedLen)
Definition: key.cpp:382
Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} at which...
Definition: transaction.h:181
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
bool GetKey(const CKeyID &keyid, CKey &key) const override
std::map< CKeyID, CPubKey > pubkeys
std::map< CKeyID, CKey > keys
std::map< CScriptID, CScript > scripts
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
Definition: backup.cpp:1159
std::map< CKeyID, bool > used_keys
Import these private keys if available (the value indicates whether if the key is required for solvab...
Definition: backup.cpp:1165
std::set< CScript > import_scripts
Definition: backup.cpp:1162
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
Definition: backup.cpp:1166
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OMITTED_NAMED_ARG
Optional arg that is a named argument and has a default value of null.
@ OMITTED
Optional argument with default value omitted because they are implicitly clear.
@ NO
Required arg.
@ ELISION
Special type to denote elision (...)
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
A TxId is the identifier of a transaction.
Definition: txid.h:14
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:23
#define LOCK2(cs1, cs2)
Definition: sync.h:246
#define LOCK(cs)
Definition: sync.h:243
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
Definition: system.cpp:1135
ArgsManager gArgs
Definition: system.cpp:79
bool error(const char *fmt, const Args &...args)
Definition: system.h:45
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
int64_t ParseISO8601DateTime(const std::string &str)
Definition: time.cpp:151
T GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:71
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:122
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:55
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:36
const char * uvTypeName(UniValue::VType t)
Definition: univalue.cpp:219
const UniValue NullUniValue
Definition: univalue.cpp:13
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
void EnsureWalletIsUnlocked(const CWallet *pwallet)
Definition: util.cpp:93
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:62
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:111
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:101
std::tuple< std::shared_ptr< CWallet >, std::vector< bilingual_str > > LoadWalletHelper(WalletContext &context, UniValue load_on_start_param, const std::string wallet_name)
Definition: util.cpp:133
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:55
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:70