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 <common/args.h>
9 #include <config.h>
10 #include <core_io.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/fs.h>
22 #include <util/fs_helpers.h>
23 #include <util/time.h>
24 #include <util/translation.h>
25 #include <wallet/rpc/util.h>
26 #include <wallet/rpcwallet.h>
27 #include <wallet/spend.h>
28 #include <wallet/wallet.h>
29 
30 #include <algorithm>
31 #include <cstdint>
32 #include <fstream>
33 #include <string>
34 #include <tuple>
35 #include <utility>
36 #include <vector>
37 
39 
40 static std::string EncodeDumpString(const std::string &str) {
41  std::stringstream ret;
42  for (const uint8_t c : str) {
43  if (c <= 32 || c >= 128 || c == '%') {
44  ret << '%' << HexStr({&c, 1});
45  } else {
46  ret << c;
47  }
48  }
49  return ret.str();
50 }
51 
52 static std::string DecodeDumpString(const std::string &str) {
53  std::stringstream ret;
54  for (unsigned int pos = 0; pos < str.length(); pos++) {
55  uint8_t c = str[pos];
56  if (c == '%' && pos + 2 < str.length()) {
57  c = (((str[pos + 1] >> 6) * 9 + ((str[pos + 1] - '0') & 15)) << 4) |
58  ((str[pos + 2] >> 6) * 9 + ((str[pos + 2] - '0') & 15));
59  pos += 2;
60  }
61  ret << c;
62  }
63  return ret.str();
64 }
65 
66 static bool
68  const CWallet *const pwallet, const CKeyID &keyid,
69  std::string &strAddr, std::string &strLabel)
70  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
71  bool fLabelFound = false;
72  CKey key;
73  spk_man->GetKey(keyid, key);
74  for (const auto &dest : GetAllDestinationsForKey(key.GetPubKey())) {
75  const auto *address_book_entry = pwallet->FindAddressBookEntry(dest);
76  if (address_book_entry) {
77  if (!strAddr.empty()) {
78  strAddr += ",";
79  }
80  strAddr += EncodeDestination(dest, config);
81  strLabel = EncodeDumpString(address_book_entry->GetLabel());
82  fLabelFound = true;
83  }
84  }
85  if (!fLabelFound) {
86  strAddr = EncodeDestination(
88  pwallet->m_default_address_type),
89  config);
90  }
91  return fLabelFound;
92 }
93 
94 static const int64_t TIMESTAMP_MIN = 0;
95 
96 static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver,
97  int64_t time_begin = TIMESTAMP_MIN,
98  bool update = true) {
99  int64_t scanned_time = wallet.RescanFromTime(time_begin, reserver, update);
100  if (wallet.IsAbortingRescan()) {
101  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
102  } else if (scanned_time > time_begin) {
104  "Rescan was unable to fully rescan the blockchain. "
105  "Some transactions may be missing.");
106  }
107 }
108 
110  return RPCHelpMan{
111  "importprivkey",
112  "Adds a private key (as returned by dumpprivkey) to your wallet. "
113  "Requires a new wallet backup.\n"
114  "Hint: use importmulti to import more than one private key.\n"
115  "\nNote: This call can take minutes to complete if rescan is true, "
116  "during that time, other rpc calls\n"
117  "may report that the imported key exists but related transactions are "
118  "still missing, leading to temporarily incorrect/bogus balances and "
119  "unspent outputs until rescan completes.\n"
120  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
121  {
123  "The private key (see dumpprivkey)"},
124  {"label", RPCArg::Type::STR,
126  "current label if address exists, otherwise \"\""},
127  "An optional label"},
128  {"rescan", RPCArg::Type::BOOL, RPCArg::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, RPCArg::Default{""},
288  "An optional label"},
289  {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
290  "Rescan the wallet for transactions"},
291  {"p2sh", RPCArg::Type::BOOL, RPCArg::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, RPCArg::Default{""},
549  "An optional label"},
550  {"rescan", RPCArg::Type::BOOL, RPCArg::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);
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 = SplitString(line, ' ');
733  if (vstr.size() < 2) {
734  continue;
735  }
736  CKey key = DecodeSecret(vstr[0]);
737  if (key.IsValid()) {
738  int64_t nTime = ParseISO8601DateTime(vstr[1]);
739  std::string strLabel;
740  bool fLabel = true;
741  for (size_t nStr = 2; nStr < vstr.size(); nStr++) {
742  if (vstr[nStr].front() == '#') {
743  break;
744  }
745  if (vstr[nStr] == "change=1") {
746  fLabel = false;
747  }
748  if (vstr[nStr] == "reserve=1") {
749  fLabel = false;
750  }
751  if (vstr[nStr].substr(0, 6) == "label=") {
752  strLabel =
753  DecodeDumpString(vstr[nStr].substr(6));
754  fLabel = true;
755  }
756  }
757  keys.push_back(
758  std::make_tuple(key, nTime, fLabel, strLabel));
759  } else if (IsHex(vstr[0])) {
760  std::vector<uint8_t> vData(ParseHex(vstr[0]));
761  CScript script = CScript(vData.begin(), vData.end());
762  int64_t birth_time = ParseISO8601DateTime(vstr[1]);
763  scripts.push_back(
764  std::pair<CScript, int64_t>(script, birth_time));
765  }
766  }
767  file.close();
768  // We now know whether we are importing private keys, so we can
769  // error if private keys are disabled
770  if (keys.size() > 0 && pwallet->IsWalletFlagSet(
772  // hide progress dialog in GUI
773  pwallet->chain().showProgress("", 100, false);
775  "Importing wallets is disabled when "
776  "private keys are disabled");
777  }
778  double total = double(keys.size() + scripts.size());
779  double progress = 0;
780  for (const auto &key_tuple : keys) {
781  pwallet->chain().showProgress(
782  "",
783  std::max(50, std::min<int>(75, 100 * progress / total) +
784  50),
785  false);
786  const CKey &key = std::get<0>(key_tuple);
787  int64_t time = std::get<1>(key_tuple);
788  bool has_label = std::get<2>(key_tuple);
789  std::string label = std::get<3>(key_tuple);
790 
791  CPubKey pubkey = key.GetPubKey();
792  CHECK_NONFATAL(key.VerifyPubKey(pubkey));
793  CKeyID keyid = pubkey.GetID();
794 
795  pwallet->WalletLogPrintf(
796  "Importing %s...\n",
797  EncodeDestination(PKHash(keyid), config));
798 
799  if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
800  pwallet->WalletLogPrintf(
801  "Error importing key for %s\n",
802  EncodeDestination(PKHash(keyid), config));
803  fGood = false;
804  continue;
805  }
806 
807  if (has_label) {
808  pwallet->SetAddressBook(PKHash(keyid), label,
809  "receive");
810  }
811 
812  nTimeBegin = std::min(nTimeBegin, time);
813  progress++;
814  }
815  for (const auto &script_pair : scripts) {
816  pwallet->chain().showProgress(
817  "",
818  std::max(50, std::min<int>(75, 100 * progress / total) +
819  50),
820  false);
821  const CScript &script = script_pair.first;
822  int64_t time = script_pair.second;
823 
824  if (!pwallet->ImportScripts({script}, time)) {
825  pwallet->WalletLogPrintf("Error importing script %s\n",
826  HexStr(script));
827  fGood = false;
828  continue;
829  }
830  if (time > 0) {
831  nTimeBegin = std::min(nTimeBegin, time);
832  }
833 
834  progress++;
835  }
836 
837  // hide progress dialog in GUI
838  pwallet->chain().showProgress("", 100, false);
839  }
840  // hide progress dialog in GUI
841  pwallet->chain().showProgress("", 100, false);
842  RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
843  pwallet->MarkDirty();
844 
845  if (!fGood) {
847  "Error adding some keys/scripts to wallet");
848  }
849 
850  return NullUniValue;
851  },
852  };
853 }
854 
856  return RPCHelpMan{
857  "dumpprivkey",
858  "Reveals the private key corresponding to 'address'.\n"
859  "Then the importprivkey can be used with this output\n",
860  {
862  "The bitcoin address for the private key"},
863  },
864  RPCResult{RPCResult::Type::STR, "key", "The private key"},
865  RPCExamples{HelpExampleCli("dumpprivkey", "\"myaddress\"") +
866  HelpExampleCli("importprivkey", "\"mykey\"") +
867  HelpExampleRpc("dumpprivkey", "\"myaddress\"")},
868  [&](const RPCHelpMan &self, const Config &config,
869  const JSONRPCRequest &request) -> UniValue {
870  std::shared_ptr<CWallet> const wallet =
872  if (!wallet) {
873  return NullUniValue;
874  }
875  const CWallet *const pwallet = wallet.get();
876 
877  LegacyScriptPubKeyMan &spk_man =
879 
880  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
881 
882  EnsureWalletIsUnlocked(pwallet);
883 
884  std::string strAddress = request.params[0].get_str();
885  CTxDestination dest =
886  DecodeDestination(strAddress, wallet->GetChainParams());
887  if (!IsValidDestination(dest)) {
889  "Invalid Bitcoin address");
890  }
891  auto keyid = GetKeyForDestination(spk_man, dest);
892  if (keyid.IsNull()) {
894  "Address does not refer to a key");
895  }
896  CKey vchSecret;
897  if (!spk_man.GetKey(keyid, vchSecret)) {
899  "Private key for address " + strAddress +
900  " is not known");
901  }
902  return EncodeSecret(vchSecret);
903  },
904  };
905 }
906 
908  return RPCHelpMan{
909  "dumpwallet",
910  "Dumps all wallet keys in a human-readable format to a server-side "
911  "file. This does not allow overwriting existing files.\n"
912  "Imported scripts are included in the dumpsfile, but corresponding "
913  "addresses may not be added automatically by importwallet.\n"
914  "Note that if your wallet contains keys which are not derived from "
915  "your HD seed (e.g. imported keys), these are not covered by\n"
916  "only backing up the seed itself, and must be backed up too (e.g. "
917  "ensure you back up the whole dumpfile).\n",
918  {
920  "The filename with path (absolute path recommended)"},
921  },
923  "",
924  "",
925  {
926  {RPCResult::Type::STR, "filename",
927  "The filename with full absolute path"},
928  }},
929  RPCExamples{HelpExampleCli("dumpwallet", "\"test\"") +
930  HelpExampleRpc("dumpwallet", "\"test\"")},
931  [&](const RPCHelpMan &self, const Config &config,
932  const JSONRPCRequest &request) -> UniValue {
933  std::shared_ptr<CWallet> const pwallet =
935  if (!pwallet) {
936  return NullUniValue;
937  }
938 
939  CWallet &wallet = *pwallet;
940  LegacyScriptPubKeyMan &spk_man =
942 
943  // Make sure the results are valid at least up to the most recent
944  // block the user could have gotten from another RPC command prior
945  // to now
946  wallet.BlockUntilSyncedToCurrentChain();
947 
948  LOCK(wallet.cs_wallet);
949 
951 
952  fs::path filepath = fs::u8path(request.params[0].get_str());
953  filepath = fs::absolute(filepath);
954 
961  if (fs::exists(filepath)) {
963  filepath.u8string() +
964  " already exists. If you are "
965  "sure this is what you want, "
966  "move it out of the way first");
967  }
968 
969  std::ofstream file;
970  file.open(filepath);
971  if (!file.is_open()) {
973  "Cannot open wallet dump file");
974  }
975 
976  std::map<CKeyID, int64_t> mapKeyBirth;
977  wallet.GetKeyBirthTimes(mapKeyBirth);
978 
979  int64_t block_time = 0;
980  CHECK_NONFATAL(wallet.chain().findBlock(
981  wallet.GetLastBlockHash(), FoundBlock().time(block_time)));
982 
983  // Note: To avoid a lock order issue, access to cs_main must be
984  // locked before cs_KeyStore. So we do the two things in this
985  // function that lock cs_main first: GetKeyBirthTimes, and
986  // findBlock.
987  LOCK(spk_man.cs_KeyStore);
988 
989  const std::map<CKeyID, int64_t> &mapKeyPool =
990  spk_man.GetAllReserveKeys();
991  std::set<CScriptID> scripts = spk_man.GetCScripts();
992 
993  // sort time/key pairs
994  std::vector<std::pair<int64_t, CKeyID>> vKeyBirth;
995  for (const auto &entry : mapKeyBirth) {
996  vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
997  }
998  mapKeyBirth.clear();
999  std::sort(vKeyBirth.begin(), vKeyBirth.end());
1000 
1001  // produce output
1002  file << strprintf("# Wallet dump created by %s %s\n", CLIENT_NAME,
1003  CLIENT_BUILD);
1004  file << strprintf("# * Created on %s\n",
1006  file << strprintf("# * Best block at time of backup was %i (%s),\n",
1007  wallet.GetLastBlockHeight(),
1008  wallet.GetLastBlockHash().ToString());
1009  file << strprintf("# mined on %s\n",
1010  FormatISO8601DateTime(block_time));
1011  file << "\n";
1012 
1013  // add the base58check encoded extended master if the wallet uses HD
1014  CKeyID seed_id = spk_man.GetHDChain().seed_id;
1015  if (!seed_id.IsNull()) {
1016  CKey seed;
1017  if (spk_man.GetKey(seed_id, seed)) {
1018  CExtKey masterKey;
1019  masterKey.SetSeed(seed.begin(), seed.size());
1020 
1021  file << "# extended private masterkey: "
1022  << EncodeExtKey(masterKey) << "\n\n";
1023  }
1024  }
1025  for (std::vector<std::pair<int64_t, CKeyID>>::const_iterator it =
1026  vKeyBirth.begin();
1027  it != vKeyBirth.end(); it++) {
1028  const CKeyID &keyid = it->second;
1029  std::string strTime = FormatISO8601DateTime(it->first);
1030  std::string strAddr;
1031  std::string strLabel;
1032  CKey key;
1033  if (spk_man.GetKey(keyid, key)) {
1034  file << strprintf("%s %s ", EncodeSecret(key), strTime);
1035  if (GetWalletAddressesForKey(config, &spk_man, &wallet,
1036  keyid, strAddr, strLabel)) {
1037  file << strprintf("label=%s", strLabel);
1038  } else if (keyid == seed_id) {
1039  file << "hdseed=1";
1040  } else if (mapKeyPool.count(keyid)) {
1041  file << "reserve=1";
1042  } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
1043  file << "inactivehdseed=1";
1044  } else {
1045  file << "change=1";
1046  }
1047  file << strprintf(
1048  " # addr=%s%s\n", strAddr,
1049  (spk_man.mapKeyMetadata[keyid].has_key_origin
1050  ? " hdkeypath=" +
1051  WriteHDKeypath(spk_man.mapKeyMetadata[keyid]
1052  .key_origin.path)
1053  : ""));
1054  }
1055  }
1056  file << "\n";
1057  for (const CScriptID &scriptid : scripts) {
1058  CScript script;
1059  std::string create_time = "0";
1060  std::string address =
1061  EncodeDestination(ScriptHash(scriptid), config);
1062  // get birth times for scripts with metadata
1063  auto it = spk_man.m_script_metadata.find(scriptid);
1064  if (it != spk_man.m_script_metadata.end()) {
1065  create_time = FormatISO8601DateTime(it->second.nCreateTime);
1066  }
1067  if (spk_man.GetCScript(scriptid, script)) {
1068  file << strprintf("%s %s script=1", HexStr(script),
1069  create_time);
1070  file << strprintf(" # addr=%s\n", address);
1071  }
1072  }
1073  file << "\n";
1074  file << "# End of dump\n";
1075  file.close();
1076 
1077  UniValue reply(UniValue::VOBJ);
1078  reply.pushKV("filename", filepath.u8string());
1079 
1080  return reply;
1081  },
1082  };
1083 }
1084 
1086  return RPCHelpMan{
1087  "dumpcoins",
1088  "dump all the UTXO tracked by the wallet.\n",
1089  {},
1090  RPCResult{
1092  "",
1093  "",
1094  {{
1096  "address",
1097  "The list of UTXO corresponding to this address.",
1098  {{
1100  "",
1101  "",
1102  {
1103  {RPCResult::Type::STR_HEX, "txid",
1104  "The transaction id"},
1105  {RPCResult::Type::NUM, "vout", "The output number"},
1106  {RPCResult::Type::NUM, "depth", "The output's depth"},
1107  {RPCResult::Type::STR_AMOUNT, "value",
1108  "The output's amount"},
1109  },
1110  }},
1111  }},
1112  },
1113  RPCExamples{HelpExampleCli("dumpcoins", "") +
1114  HelpExampleRpc("dumpcoins", "")},
1115  [&](const RPCHelpMan &self, const Config &config,
1116  const JSONRPCRequest &request) -> UniValue {
1117  std::shared_ptr<CWallet> const pwallet =
1118  GetWalletForJSONRPCRequest(request);
1119  if (!pwallet) {
1120  return NullUniValue;
1121  }
1122 
1123  CWallet &wallet = *pwallet;
1124 
1125  // Make sure the results are valid at least up to the most recent
1126  // block the user could have gotten from another RPC command prior
1127  // to now
1128  wallet.BlockUntilSyncedToCurrentChain();
1129 
1130  LOCK(wallet.cs_wallet);
1131 
1133 
1134  UniValue result(UniValue::VOBJ);
1135  for (const auto &p : ListCoins(wallet)) {
1136  UniValue coins(UniValue::VARR);
1137  for (const auto &o : p.second) {
1138  UniValue utxo(UniValue::VOBJ);
1139  utxo.pushKV("txid", o.tx->GetId().ToString());
1140  utxo.pushKV("vout", o.i);
1141  utxo.pushKV("depth", o.nDepth);
1142  utxo.pushKV("value", o.tx->tx->vout[o.i].nValue);
1143 
1144  coins.push_back(std::move(utxo));
1145  }
1146 
1147  result.pushKV(EncodeDestination(p.first, config), coins);
1148  }
1149 
1150  return result;
1151  },
1152  };
1153 }
1154 
1155 struct ImportData {
1156  // Input data
1158  std::unique_ptr<CScript> redeemscript;
1159 
1160  // Output data
1161  std::set<CScript> import_scripts;
1164  std::map<CKeyID, bool> used_keys;
1165  std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
1166 };
1167 
1168 enum class ScriptContext {
1170  TOP,
1172  P2SH,
1173 };
1174 
1175 // Analyse the provided scriptPubKey, determining which keys and which redeem
1176 // scripts from the ImportData struct are needed to spend it, and mark them as
1177 // used. Returns an error string, or the empty string for success.
1178 static std::string RecurseImportData(const CScript &script,
1179  ImportData &import_data,
1180  const ScriptContext script_ctx) {
1181  // Use Solver to obtain script type and parsed pubkeys or hashes:
1182  std::vector<std::vector<uint8_t>> solverdata;
1183  TxoutType script_type = Solver(script, solverdata);
1184 
1185  switch (script_type) {
1186  case TxoutType::PUBKEY: {
1187  CPubKey pubkey(solverdata[0]);
1188  import_data.used_keys.emplace(pubkey.GetID(), false);
1189  return "";
1190  }
1191  case TxoutType::PUBKEYHASH: {
1192  CKeyID id = CKeyID(uint160(solverdata[0]));
1193  import_data.used_keys[id] = true;
1194  return "";
1195  }
1196  case TxoutType::SCRIPTHASH: {
1197  if (script_ctx == ScriptContext::P2SH) {
1199  "Trying to nest P2SH inside another P2SH");
1200  }
1201  CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
1202  CScriptID id = CScriptID(uint160(solverdata[0]));
1203  // Remove redeemscript from import_data to check for superfluous
1204  // script later.
1205  auto subscript = std::move(import_data.redeemscript);
1206  if (!subscript) {
1207  return "missing redeemscript";
1208  }
1209  if (CScriptID(*subscript) != id) {
1210  return "redeemScript does not match the scriptPubKey";
1211  }
1212  import_data.import_scripts.emplace(*subscript);
1213  return RecurseImportData(*subscript, import_data,
1215  }
1216  case TxoutType::MULTISIG: {
1217  for (size_t i = 1; i + 1 < solverdata.size(); ++i) {
1218  CPubKey pubkey(solverdata[i]);
1219  import_data.used_keys.emplace(pubkey.GetID(), false);
1220  }
1221  return "";
1222  }
1223  case TxoutType::NULL_DATA:
1224  return "unspendable script";
1226  default:
1227  return "unrecognized script";
1228  }
1229 }
1230 
1232  CWallet *const pwallet, ImportData &import_data,
1233  std::map<CKeyID, CPubKey> &pubkey_map, std::map<CKeyID, CKey> &privkey_map,
1234  std::set<CScript> &script_pub_keys, bool &have_solving_data,
1235  const UniValue &data, std::vector<CKeyID> &ordered_pubkeys) {
1236  UniValue warnings(UniValue::VARR);
1237 
1238  // First ensure scriptPubKey has either a script or JSON with "address"
1239  // string
1240  const UniValue &scriptPubKey = data["scriptPubKey"];
1241  bool isScript = scriptPubKey.getType() == UniValue::VSTR;
1242  if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ &&
1243  scriptPubKey.exists("address"))) {
1245  "scriptPubKey must be string with script or JSON "
1246  "with address string");
1247  }
1248  const std::string &output =
1249  isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
1250 
1251  // Optional fields.
1252  const std::string &strRedeemScript =
1253  data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
1254  const UniValue &pubKeys =
1255  data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
1256  const UniValue &keys =
1257  data.exists("keys") ? data["keys"].get_array() : UniValue();
1258  const bool internal =
1259  data.exists("internal") ? data["internal"].get_bool() : false;
1260  const bool watchOnly =
1261  data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1262 
1263  if (data.exists("range")) {
1264  throw JSONRPCError(
1266  "Range should not be specified for a non-descriptor import");
1267  }
1268 
1269  // Generate the script and destination for the scriptPubKey provided
1270  CScript script;
1271  if (!isScript) {
1272  CTxDestination dest =
1273  DecodeDestination(output, pwallet->GetChainParams());
1274  if (!IsValidDestination(dest)) {
1276  "Invalid address \"" + output + "\"");
1277  }
1278  script = GetScriptForDestination(dest);
1279  } else {
1280  if (!IsHex(output)) {
1282  "Invalid scriptPubKey \"" + output + "\"");
1283  }
1284  std::vector<uint8_t> vData(ParseHex(output));
1285  script = CScript(vData.begin(), vData.end());
1286  CTxDestination dest;
1287  if (!ExtractDestination(script, dest) && !internal) {
1289  "Internal must be set to true for "
1290  "nonstandard scriptPubKey imports.");
1291  }
1292  }
1293  script_pub_keys.emplace(script);
1294 
1295  // Parse all arguments
1296  if (strRedeemScript.size()) {
1297  if (!IsHex(strRedeemScript)) {
1299  "Invalid redeem script \"" + strRedeemScript +
1300  "\": must be hex string");
1301  }
1302  auto parsed_redeemscript = ParseHex(strRedeemScript);
1303  import_data.redeemscript = std::make_unique<CScript>(
1304  parsed_redeemscript.begin(), parsed_redeemscript.end());
1305  }
1306  for (size_t i = 0; i < pubKeys.size(); ++i) {
1307  const auto &str = pubKeys[i].get_str();
1308  if (!IsHex(str)) {
1310  "Pubkey \"" + str + "\" must be a hex string");
1311  }
1312  auto parsed_pubkey = ParseHex(str);
1313  CPubKey pubkey(parsed_pubkey);
1314  if (!pubkey.IsFullyValid()) {
1316  "Pubkey \"" + str +
1317  "\" is not a valid public key");
1318  }
1319  pubkey_map.emplace(pubkey.GetID(), pubkey);
1320  ordered_pubkeys.push_back(pubkey.GetID());
1321  }
1322  for (size_t i = 0; i < keys.size(); ++i) {
1323  const auto &str = keys[i].get_str();
1324  CKey key = DecodeSecret(str);
1325  if (!key.IsValid()) {
1327  "Invalid private key encoding");
1328  }
1329  CPubKey pubkey = key.GetPubKey();
1330  CKeyID id = pubkey.GetID();
1331  if (pubkey_map.count(id)) {
1332  pubkey_map.erase(id);
1333  }
1334  privkey_map.emplace(id, key);
1335  }
1336 
1337  // Verify and process input data
1338  have_solving_data =
1339  import_data.redeemscript || pubkey_map.size() || privkey_map.size();
1340  if (have_solving_data) {
1341  // Match up data in import_data with the scriptPubKey in script.
1342  auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1343 
1344  // Verify whether the watchonly option corresponds to the
1345  // availability of private keys.
1346  bool spendable = std::all_of(
1347  import_data.used_keys.begin(), import_data.used_keys.end(),
1348  [&](const std::pair<CKeyID, bool> &used_key) {
1349  return privkey_map.count(used_key.first) > 0;
1350  });
1351  if (!watchOnly && !spendable) {
1352  warnings.push_back("Some private keys are missing, outputs "
1353  "will be considered watchonly. If this is "
1354  "intentional, specify the watchonly flag.");
1355  }
1356  if (watchOnly && spendable) {
1357  warnings.push_back(
1358  "All private keys are provided, outputs will be considered "
1359  "spendable. If this is intentional, do not specify the "
1360  "watchonly flag.");
1361  }
1362 
1363  // Check that all required keys for solvability are provided.
1364  if (error.empty()) {
1365  for (const auto &require_key : import_data.used_keys) {
1366  if (!require_key.second) {
1367  // Not a required key
1368  continue;
1369  }
1370 
1371  if (pubkey_map.count(require_key.first) == 0 &&
1372  privkey_map.count(require_key.first) == 0) {
1373  error = "some required keys are missing";
1374  }
1375  }
1376  }
1377 
1378  if (!error.empty()) {
1379  warnings.push_back("Importing as non-solvable: " + error +
1380  ". If this is intentional, don't provide "
1381  "any keys, pubkeys or redeemscript.");
1382  import_data = ImportData();
1383  pubkey_map.clear();
1384  privkey_map.clear();
1385  have_solving_data = false;
1386  } else {
1387  // RecurseImportData() removes any relevant redeemscript from
1388  // import_data, so we can use that to discover if a superfluous
1389  // one was provided.
1390  if (import_data.redeemscript) {
1391  warnings.push_back(
1392  "Ignoring redeemscript as this is not a P2SH script.");
1393  }
1394  for (auto it = privkey_map.begin(); it != privkey_map.end();) {
1395  auto oldit = it++;
1396  if (import_data.used_keys.count(oldit->first) == 0) {
1397  warnings.push_back("Ignoring irrelevant private key.");
1398  privkey_map.erase(oldit);
1399  }
1400  }
1401  for (auto it = pubkey_map.begin(); it != pubkey_map.end();) {
1402  auto oldit = it++;
1403  auto key_data_it = import_data.used_keys.find(oldit->first);
1404  if (key_data_it == import_data.used_keys.end() ||
1405  !key_data_it->second) {
1406  warnings.push_back("Ignoring public key \"" +
1407  HexStr(oldit->first) +
1408  "\" as it doesn't appear inside P2PKH.");
1409  pubkey_map.erase(oldit);
1410  }
1411  }
1412  }
1413  }
1414 
1415  return warnings;
1416 }
1417 
1419  std::map<CKeyID, CPubKey> &pubkey_map,
1420  std::map<CKeyID, CKey> &privkey_map,
1421  std::set<CScript> &script_pub_keys,
1422  bool &have_solving_data,
1423  const UniValue &data,
1424  std::vector<CKeyID> &ordered_pubkeys) {
1425  UniValue warnings(UniValue::VARR);
1426 
1427  const std::string &descriptor = data["desc"].get_str();
1428  FlatSigningProvider keys;
1429  std::string error;
1430  auto parsed_desc =
1431  Parse(descriptor, keys, error, /* require_checksum = */ true);
1432  if (!parsed_desc) {
1434  }
1435 
1436  have_solving_data = parsed_desc->IsSolvable();
1437  const bool watch_only =
1438  data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1439 
1440  int64_t range_start = 0, range_end = 0;
1441  if (!parsed_desc->IsRange() && data.exists("range")) {
1442  throw JSONRPCError(
1444  "Range should not be specified for an un-ranged descriptor");
1445  } else if (parsed_desc->IsRange()) {
1446  if (!data.exists("range")) {
1447  throw JSONRPCError(
1449  "Descriptor is ranged, please specify the range");
1450  }
1451  std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1452  }
1453 
1454  const UniValue &priv_keys =
1455  data.exists("keys") ? data["keys"].get_array() : UniValue();
1456 
1457  // Expand all descriptors to get public keys and scripts, and private keys
1458  // if available.
1459  for (int i = range_start; i <= range_end; ++i) {
1460  FlatSigningProvider out_keys;
1461  std::vector<CScript> scripts_temp;
1462  parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1463  std::copy(scripts_temp.begin(), scripts_temp.end(),
1464  std::inserter(script_pub_keys, script_pub_keys.end()));
1465  for (const auto &key_pair : out_keys.pubkeys) {
1466  ordered_pubkeys.push_back(key_pair.first);
1467  }
1468 
1469  for (const auto &x : out_keys.scripts) {
1470  import_data.import_scripts.emplace(x.second);
1471  }
1472 
1473  parsed_desc->ExpandPrivate(i, keys, out_keys);
1474 
1475  std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(),
1476  std::inserter(pubkey_map, pubkey_map.end()));
1477  std::copy(out_keys.keys.begin(), out_keys.keys.end(),
1478  std::inserter(privkey_map, privkey_map.end()));
1479  import_data.key_origins.insert(out_keys.origins.begin(),
1480  out_keys.origins.end());
1481  }
1482 
1483  for (size_t i = 0; i < priv_keys.size(); ++i) {
1484  const auto &str = priv_keys[i].get_str();
1485  CKey key = DecodeSecret(str);
1486  if (!key.IsValid()) {
1488  "Invalid private key encoding");
1489  }
1490  CPubKey pubkey = key.GetPubKey();
1491  CKeyID id = pubkey.GetID();
1492 
1493  // Check if this private key corresponds to a public key from the
1494  // descriptor
1495  if (!pubkey_map.count(id)) {
1496  warnings.push_back("Ignoring irrelevant private key.");
1497  } else {
1498  privkey_map.emplace(id, key);
1499  }
1500  }
1501 
1502  // Check if all the public keys have corresponding private keys in the
1503  // import for spendability. This does not take into account threshold
1504  // multisigs which could be spendable without all keys. Thus, threshold
1505  // multisigs without all keys will be considered not spendable here, even if
1506  // they are, perhaps triggering a false warning message. This is consistent
1507  // with the current wallet IsMine check.
1508  bool spendable =
1509  std::all_of(pubkey_map.begin(), pubkey_map.end(),
1510  [&](const std::pair<CKeyID, CPubKey> &used_key) {
1511  return privkey_map.count(used_key.first) > 0;
1512  }) &&
1513  std::all_of(
1514  import_data.key_origins.begin(), import_data.key_origins.end(),
1515  [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>
1516  &entry) { return privkey_map.count(entry.first) > 0; });
1517  if (!watch_only && !spendable) {
1518  warnings.push_back(
1519  "Some private keys are missing, outputs will be considered "
1520  "watchonly. If this is intentional, specify the watchonly flag.");
1521  }
1522  if (watch_only && spendable) {
1523  warnings.push_back("All private keys are provided, outputs will be "
1524  "considered spendable. If this is intentional, do "
1525  "not specify the watchonly flag.");
1526  }
1527 
1528  return warnings;
1529 }
1530 
1531 static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data,
1532  const int64_t timestamp)
1533  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1534  UniValue warnings(UniValue::VARR);
1535  UniValue result(UniValue::VOBJ);
1536 
1537  try {
1538  const bool internal =
1539  data.exists("internal") ? data["internal"].get_bool() : false;
1540  // Internal addresses should not have a label
1541  if (internal && data.exists("label")) {
1543  "Internal addresses should not have a label");
1544  }
1545  const std::string &label =
1546  data.exists("label") ? data["label"].get_str() : "";
1547  const bool add_keypool =
1548  data.exists("keypool") ? data["keypool"].get_bool() : false;
1549 
1550  // Add to keypool only works with privkeys disabled
1551  if (add_keypool &&
1552  !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1554  "Keys can only be imported to the keypool when "
1555  "private keys are disabled");
1556  }
1557 
1558  ImportData import_data;
1559  std::map<CKeyID, CPubKey> pubkey_map;
1560  std::map<CKeyID, CKey> privkey_map;
1561  std::set<CScript> script_pub_keys;
1562  std::vector<CKeyID> ordered_pubkeys;
1563  bool have_solving_data;
1564 
1565  if (data.exists("scriptPubKey") && data.exists("desc")) {
1566  throw JSONRPCError(
1568  "Both a descriptor and a scriptPubKey should not be provided.");
1569  } else if (data.exists("scriptPubKey")) {
1570  warnings = ProcessImportLegacy(
1571  pwallet, import_data, pubkey_map, privkey_map, script_pub_keys,
1572  have_solving_data, data, ordered_pubkeys);
1573  } else if (data.exists("desc")) {
1574  warnings = ProcessImportDescriptor(
1575  import_data, pubkey_map, privkey_map, script_pub_keys,
1576  have_solving_data, data, ordered_pubkeys);
1577  } else {
1578  throw JSONRPCError(
1580  "Either a descriptor or scriptPubKey must be provided.");
1581  }
1582 
1583  // If private keys are disabled, abort if private keys are being
1584  // imported
1585  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
1586  !privkey_map.empty()) {
1588  "Cannot import private keys to a wallet with "
1589  "private keys disabled");
1590  }
1591 
1592  // Check whether we have any work to do
1593  for (const CScript &script : script_pub_keys) {
1594  if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1596  "The wallet already contains the private "
1597  "key for this address or script (\"" +
1598  HexStr(script) + "\")");
1599  }
1600  }
1601 
1602  // All good, time to import
1603  pwallet->MarkDirty();
1604  if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1606  "Error adding script to wallet");
1607  }
1608  if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1609  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1610  }
1611  if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map,
1612  import_data.key_origins, add_keypool,
1613  internal, timestamp)) {
1615  "Error adding address to wallet");
1616  }
1617  if (!pwallet->ImportScriptPubKeys(label, script_pub_keys,
1618  have_solving_data, !internal,
1619  timestamp)) {
1621  "Error adding address to wallet");
1622  }
1623 
1624  result.pushKV("success", UniValue(true));
1625  } catch (const UniValue &e) {
1626  result.pushKV("success", UniValue(false));
1627  result.pushKV("error", e);
1628  } catch (...) {
1629  result.pushKV("success", UniValue(false));
1630  result.pushKV("error",
1631  JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1632  }
1633 
1634  if (warnings.size()) {
1635  result.pushKV("warnings", warnings);
1636  }
1637  return result;
1638 }
1639 
1640 static int64_t GetImportTimestamp(const UniValue &data, int64_t now) {
1641  if (data.exists("timestamp")) {
1642  const UniValue &timestamp = data["timestamp"];
1643  if (timestamp.isNum()) {
1644  return timestamp.getInt<int64_t>();
1645  } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1646  return now;
1647  }
1649  strprintf("Expected number or \"now\" timestamp "
1650  "value for key. got type %s",
1651  uvTypeName(timestamp.type())));
1652  }
1654  "Missing required timestamp field for key");
1655 }
1656 
1657 static std::string GetRescanErrorMessage(const std::string &object,
1658  const int64_t objectTimestamp,
1659  const int64_t blockTimestamp) {
1660  return strprintf(
1661  "Rescan failed for %s with creation timestamp %d. There was an error "
1662  "reading a block from time %d, which is after or within %d seconds of "
1663  "key creation, and could contain transactions pertaining to the %s. As "
1664  "a result, transactions and coins using this %s may not appear in "
1665  "the wallet. This error could be caused by pruning or data corruption "
1666  "(see bitcoind log for details) and could be dealt with by downloading "
1667  "and rescanning the relevant blocks (see -reindex and -rescan "
1668  "options).",
1669  object, objectTimestamp, blockTimestamp, TIMESTAMP_WINDOW, object,
1670  object);
1671 }
1672 
1674  return RPCHelpMan{
1675  "importmulti",
1676  "Import addresses/scripts (with private or public keys, redeem "
1677  "script (P2SH)), optionally rescanning the blockchain from the "
1678  "earliest creation time of the imported scripts. Requires a new wallet "
1679  "backup.\n"
1680  "If an address/script is imported without all of the private keys "
1681  "required to spend from that address, it will be watchonly. The "
1682  "'watchonly' option must be set to true in this case or a warning will "
1683  "be returned.\n"
1684  "Conversely, if all the private keys are provided and the "
1685  "address/script is spendable, the watchonly option must be set to "
1686  "false, or a warning will be returned.\n"
1687  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1688  {
1689  {"requests",
1692  "Data to be imported",
1693  {
1694  {
1695  "",
1698  "",
1699  {
1701  "Descriptor to import. If using descriptor, do not "
1702  "also provide address/scriptPubKey, scripts, or "
1703  "pubkeys"},
1704  {"scriptPubKey", RPCArg::Type::STR,
1706  "Type of scriptPubKey (string for script, json for "
1707  "address). Should not be provided if using a "
1708  "descriptor",
1709  RPCArgOptions{
1710  .type_str = {"\"<script>\" | { "
1711  "\"address\":\"<address>\" }",
1712  "string / json"}}},
1713  {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO,
1714  "Creation time of the key expressed in " +
1715  UNIX_EPOCH_TIME +
1716  ",\n"
1717  "or the string \"now\" to substitute the current "
1718  "synced blockchain time. The timestamp of the "
1719  "oldest\n"
1720  "key will determine how far back blockchain "
1721  "rescans need to begin for missing wallet "
1722  "transactions.\n"
1723  "\"now\" can be specified to bypass scanning, "
1724  "for keys which are known to never have been "
1725  "used, and\n"
1726  "0 can be specified to scan the entire "
1727  "blockchain. Blocks up to 2 hours before the "
1728  "earliest key\n"
1729  "creation time of all keys being imported by the "
1730  "importmulti call will be scanned.",
1731  RPCArgOptions{.type_str = {"timestamp | \"now\"",
1732  "integer / string"}}},
1733  {"redeemscript", RPCArg::Type::STR,
1735  "Allowed only if the scriptPubKey is a P2SH "
1736  "address/scriptPubKey"},
1737  {"pubkeys",
1740  "Array of strings giving pubkeys to import. They "
1741  "must occur in P2PKH scripts. They are not required "
1742  "when the private key is also provided (see the "
1743  "\"keys\" argument).",
1744  {
1745  {"pubKey", RPCArg::Type::STR,
1747  }},
1748  {"keys",
1751  "Array of strings giving private keys to import. The "
1752  "corresponding public keys must occur in the output "
1753  "or redeemscript.",
1754  {
1755  {"key", RPCArg::Type::STR,
1757  }},
1758  {"range", RPCArg::Type::RANGE,
1760  "If a ranged descriptor is used, this specifies the "
1761  "end or the range (in the form [begin,end]) to "
1762  "import"},
1763  {"internal", RPCArg::Type::BOOL,
1764  RPCArg::Default{false},
1765  "Stating whether matching outputs should be treated "
1766  "as not incoming payments (also known as change)"},
1767  {"watchonly", RPCArg::Type::BOOL,
1768  RPCArg::Default{false},
1769  "Stating whether matching outputs should be "
1770  "considered watchonly."},
1771  {"label", RPCArg::Type::STR, RPCArg::Default{""},
1772  "Label to assign to the address, only allowed with "
1773  "internal=false"},
1774  {"keypool", RPCArg::Type::BOOL, RPCArg::Default{false},
1775  "Stating whether imported public keys should be "
1776  "added to the keypool for when users request new "
1777  "addresses. Only allowed when wallet private keys "
1778  "are disabled"},
1779  },
1780  },
1781  },
1782  RPCArgOptions{.oneline_description = "\"requests\""}},
1783  {"options",
1786  "",
1787  {
1788  {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
1789  "Stating if should rescan the blockchain after all imports"},
1790  },
1791  RPCArgOptions{.oneline_description = "\"options\""}},
1792  },
1794  "",
1795  "Response is an array with the same size as the input that "
1796  "has the execution result",
1797  {
1799  "",
1800  "",
1801  {
1802  {RPCResult::Type::BOOL, "success", ""},
1804  "warnings",
1805  /* optional */ true,
1806  "",
1807  {
1808  {RPCResult::Type::STR, "", ""},
1809  }},
1811  "error",
1812  /* optional */ true,
1813  "",
1814  {
1815  {RPCResult::Type::ELISION, "", "JSONRPC error"},
1816  }},
1817  }},
1818  }},
1819  RPCExamples{
1821  "importmulti",
1822  "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1823  "\"timestamp\":1455191478 }, "
1824  "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" "
1825  "}, "
1826  "\"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1828  "importmulti",
1829  "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1830  "\"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1831 
1832  },
1833  [&](const RPCHelpMan &self, const Config &config,
1834  const JSONRPCRequest &mainRequest) -> UniValue {
1835  std::shared_ptr<CWallet> const wallet =
1836  GetWalletForJSONRPCRequest(mainRequest);
1837  if (!wallet) {
1838  return NullUniValue;
1839  }
1840  CWallet *const pwallet = wallet.get();
1841 
1843 
1844  const UniValue &requests = mainRequest.params[0];
1845 
1846  // Default options
1847  bool fRescan = true;
1848 
1849  if (!mainRequest.params[1].isNull()) {
1850  const UniValue &options = mainRequest.params[1];
1851 
1852  if (options.exists("rescan")) {
1853  fRescan = options["rescan"].get_bool();
1854  }
1855  }
1856 
1857  WalletRescanReserver reserver(*pwallet);
1858  if (fRescan && !reserver.reserve()) {
1860  "Wallet is currently rescanning. Abort "
1861  "existing rescan or wait.");
1862  }
1863 
1864  int64_t now = 0;
1865  bool fRunScan = false;
1866  int64_t nLowestTimestamp = 0;
1868  {
1869  LOCK(pwallet->cs_wallet);
1870  EnsureWalletIsUnlocked(pwallet);
1871 
1872  // Verify all timestamps are present before importing any keys.
1873  CHECK_NONFATAL(pwallet->chain().findBlock(
1874  pwallet->GetLastBlockHash(),
1875  FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1876  for (const UniValue &data : requests.getValues()) {
1877  GetImportTimestamp(data, now);
1878  }
1879 
1880  const int64_t minimumTimestamp = 1;
1881 
1882  for (const UniValue &data : requests.getValues()) {
1883  const int64_t timestamp = std::max(
1884  GetImportTimestamp(data, now), minimumTimestamp);
1885  const UniValue result =
1886  ProcessImport(pwallet, data, timestamp);
1887  response.push_back(result);
1888 
1889  if (!fRescan) {
1890  continue;
1891  }
1892 
1893  // If at least one request was successful then allow rescan.
1894  if (result["success"].get_bool()) {
1895  fRunScan = true;
1896  }
1897 
1898  // Get the lowest timestamp.
1899  if (timestamp < nLowestTimestamp) {
1900  nLowestTimestamp = timestamp;
1901  }
1902  }
1903  }
1904  if (fRescan && fRunScan && requests.size()) {
1905  int64_t scannedTime = pwallet->RescanFromTime(
1906  nLowestTimestamp, reserver, true /* update */);
1907  {
1908  LOCK(pwallet->cs_wallet);
1909  pwallet->ReacceptWalletTransactions();
1910  }
1911 
1912  if (pwallet->IsAbortingRescan()) {
1914  "Rescan aborted by user.");
1915  }
1916  if (scannedTime > nLowestTimestamp) {
1917  std::vector<UniValue> results = response.getValues();
1918  response.clear();
1919  response.setArray();
1920  size_t i = 0;
1921  for (const UniValue &request : requests.getValues()) {
1922  // If key creation date is within the successfully
1923  // scanned range, or if the import result already has an
1924  // error set, let the result stand unmodified. Otherwise
1925  // replace the result with an error message.
1926  if (scannedTime <= GetImportTimestamp(request, now) ||
1927  results.at(i).exists("error")) {
1928  response.push_back(results.at(i));
1929  } else {
1930  UniValue result = UniValue(UniValue::VOBJ);
1931  result.pushKV("success", UniValue(false));
1932  result.pushKV(
1933  "error",
1934  JSONRPCError(
1937  "key", GetImportTimestamp(request, now),
1938  scannedTime - TIMESTAMP_WINDOW - 1)));
1939  response.push_back(std::move(result));
1940  }
1941  ++i;
1942  }
1943  }
1944  }
1945 
1946  return response;
1947  },
1948  };
1949 }
1950 
1952  const UniValue &data,
1953  const int64_t timestamp)
1954  EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1955  UniValue warnings(UniValue::VARR);
1956  UniValue result(UniValue::VOBJ);
1957 
1958  try {
1959  if (!data.exists("desc")) {
1960  throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor not found.");
1961  }
1962 
1963  const std::string &descriptor = data["desc"].get_str();
1964  const bool active =
1965  data.exists("active") ? data["active"].get_bool() : false;
1966  const bool internal =
1967  data.exists("internal") ? data["internal"].get_bool() : false;
1968  const std::string &label =
1969  data.exists("label") ? data["label"].get_str() : "";
1970 
1971  // Parse descriptor string
1972  FlatSigningProvider keys;
1973  std::string error;
1974  auto parsed_desc =
1975  Parse(descriptor, keys, error, /* require_checksum = */ true);
1976  if (!parsed_desc) {
1978  }
1979 
1980  // Range check
1981  int64_t range_start = 0, range_end = 1, next_index = 0;
1982  if (!parsed_desc->IsRange() && data.exists("range")) {
1983  throw JSONRPCError(
1985  "Range should not be specified for an un-ranged descriptor");
1986  } else if (parsed_desc->IsRange()) {
1987  if (data.exists("range")) {
1988  auto range = ParseDescriptorRange(data["range"]);
1989  range_start = range.first;
1990  // Specified range end is inclusive, but we need range end as
1991  // exclusive
1992  range_end = range.second + 1;
1993  } else {
1994  warnings.push_back(
1995  "Range not given, using default keypool range");
1996  range_start = 0;
1997  range_end = gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE);
1998  }
1999  next_index = range_start;
2000 
2001  if (data.exists("next_index")) {
2002  next_index = data["next_index"].getInt<int64_t>();
2003  // bound checks
2004  if (next_index < range_start || next_index >= range_end) {
2006  "next_index is out of range");
2007  }
2008  }
2009  }
2010 
2011  // Active descriptors must be ranged
2012  if (active && !parsed_desc->IsRange()) {
2014  "Active descriptors must be ranged");
2015  }
2016 
2017  // Ranged descriptors should not have a label
2018  if (data.exists("range") && data.exists("label")) {
2020  "Ranged descriptors should not have a label");
2021  }
2022 
2023  // Internal addresses should not have a label either
2024  if (internal && data.exists("label")) {
2026  "Internal addresses should not have a label");
2027  }
2028 
2029  // Combo descriptor check
2030  if (active && !parsed_desc->IsSingleType()) {
2032  "Combo descriptors cannot be set to active");
2033  }
2034 
2035  // If the wallet disabled private keys, abort if private keys exist
2036  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
2037  !keys.keys.empty()) {
2039  "Cannot import private keys to a wallet with "
2040  "private keys disabled");
2041  }
2042 
2043  // Need to ExpandPrivate to check if private keys are available for all
2044  // pubkeys
2045  FlatSigningProvider expand_keys;
2046  std::vector<CScript> scripts;
2047  if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
2048  throw JSONRPCError(
2050  "Cannot expand descriptor. Probably because of hardened "
2051  "derivations without private keys provided");
2052  }
2053  parsed_desc->ExpandPrivate(0, keys, expand_keys);
2054 
2055  // Check if all private keys are provided
2056  bool have_all_privkeys = !expand_keys.keys.empty();
2057  for (const auto &entry : expand_keys.origins) {
2058  const CKeyID &key_id = entry.first;
2059  CKey key;
2060  if (!expand_keys.GetKey(key_id, key)) {
2061  have_all_privkeys = false;
2062  break;
2063  }
2064  }
2065 
2066  // If private keys are enabled, check some things.
2067  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
2068  if (keys.keys.empty()) {
2069  throw JSONRPCError(
2071  "Cannot import descriptor without private keys to a wallet "
2072  "with private keys enabled");
2073  }
2074  if (!have_all_privkeys) {
2075  warnings.push_back(
2076  "Not all private keys provided. Some wallet functionality "
2077  "may return unexpected errors");
2078  }
2079  }
2080 
2081  WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start,
2082  range_end, next_index);
2083 
2084  // Check if the wallet already contains the descriptor
2085  auto existing_spk_manager =
2086  pwallet->GetDescriptorScriptPubKeyMan(w_desc);
2087  if (existing_spk_manager &&
2088  !existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) {
2090  }
2091 
2092  // Add descriptor to the wallet
2093  auto spk_manager =
2094  pwallet->AddWalletDescriptor(w_desc, keys, label, internal);
2095  if (spk_manager == nullptr) {
2096  throw JSONRPCError(
2098  strprintf("Could not add descriptor '%s'", descriptor));
2099  }
2100 
2101  // Set descriptor as active if necessary
2102  if (active) {
2103  if (!w_desc.descriptor->GetOutputType()) {
2104  warnings.push_back(
2105  "Unknown output type, cannot set descriptor to active.");
2106  } else {
2107  pwallet->AddActiveScriptPubKeyMan(
2108  spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2109  internal);
2110  }
2111  } else {
2112  if (w_desc.descriptor->GetOutputType()) {
2113  pwallet->DeactivateScriptPubKeyMan(
2114  spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2115  internal);
2116  }
2117  }
2118 
2119  result.pushKV("success", UniValue(true));
2120  } catch (const UniValue &e) {
2121  result.pushKV("success", UniValue(false));
2122  result.pushKV("error", e);
2123  }
2124  if (warnings.size()) {
2125  result.pushKV("warnings", warnings);
2126  }
2127  return result;
2128 }
2129 
2131  return RPCHelpMan{
2132  "importdescriptors",
2133  "Import descriptors. This will trigger a rescan of the blockchain "
2134  "based on the earliest timestamp of all descriptors being imported. "
2135  "Requires a new wallet backup.\n"
2136  "\nNote: This call can take over an hour to complete if using an early "
2137  "timestamp; during that time, other rpc calls\n"
2138  "may report that the imported keys, addresses or scripts exist but "
2139  "related transactions are still missing.\n",
2140  {
2141  {"requests",
2144  "Data to be imported",
2145  {
2146  {
2147  "",
2150  "",
2151  {
2153  "Descriptor to import."},
2154  {"active", RPCArg::Type::BOOL, RPCArg::Default{false},
2155  "Set this descriptor to be the active descriptor for "
2156  "the corresponding output type/externality"},
2157  {"range", RPCArg::Type::RANGE,
2159  "If a ranged descriptor is used, this specifies the "
2160  "end or the range (in the form [begin,end]) to "
2161  "import"},
2162  {"next_index", RPCArg::Type::NUM,
2164  "If a ranged descriptor is set to active, this "
2165  "specifies the next index to generate addresses "
2166  "from"},
2167  {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO,
2168  "Time from which to start rescanning the blockchain "
2169  "for this descriptor, in " +
2170  UNIX_EPOCH_TIME +
2171  "\n"
2172  "Use the string \"now\" to substitute the "
2173  "current synced blockchain time.\n"
2174  "\"now\" can be specified to bypass scanning, "
2175  "for outputs which are known to never have been "
2176  "used, and\n"
2177  "0 can be specified to scan the entire "
2178  "blockchain. Blocks up to 2 hours before the "
2179  "earliest timestamp\n"
2180  "of all descriptors being imported will be "
2181  "scanned.",
2182  RPCArgOptions{.type_str = {"timestamp | \"now\"",
2183  "integer / string"}}},
2184  {"internal", RPCArg::Type::BOOL,
2185  RPCArg::Default{false},
2186  "Whether matching outputs should be treated as not "
2187  "incoming payments (e.g. change)"},
2188  {"label", RPCArg::Type::STR, RPCArg::Default{""},
2189  "Label to assign to the address, only allowed with "
2190  "internal=false"},
2191  },
2192  },
2193  },
2194  RPCArgOptions{.oneline_description = "\"requests\""}},
2195  },
2197  "",
2198  "Response is an array with the same size as the input that "
2199  "has the execution result",
2200  {
2202  "",
2203  "",
2204  {
2205  {RPCResult::Type::BOOL, "success", ""},
2207  "warnings",
2208  /* optional */ true,
2209  "",
2210  {
2211  {RPCResult::Type::STR, "", ""},
2212  }},
2214  "error",
2215  /* optional */ true,
2216  "",
2217  {
2218  {RPCResult::Type::ELISION, "", "JSONRPC error"},
2219  }},
2220  }},
2221  }},
2222  RPCExamples{
2223  HelpExampleCli("importdescriptors",
2224  "'[{ \"desc\": \"<my descriptor>\", "
2225  "\"timestamp\":1455191478, \"internal\": true }, "
2226  "{ \"desc\": \"<my desccriptor 2>\", \"label\": "
2227  "\"example 2\", \"timestamp\": 1455191480 }]'") +
2229  "importdescriptors",
2230  "'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, "
2231  "\"active\": true, \"range\": [0,100], \"label\": \"<my "
2232  "cashaddr wallet>\" }]'")},
2233  [&](const RPCHelpMan &self, const Config &config,
2234  const JSONRPCRequest &main_request) -> UniValue {
2235  std::shared_ptr<CWallet> const wallet =
2236  GetWalletForJSONRPCRequest(main_request);
2237  if (!wallet) {
2238  return NullUniValue;
2239  }
2240  CWallet *const pwallet = wallet.get();
2241 
2242  // Make sure wallet is a descriptor wallet
2243  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
2245  "importdescriptors is not available for "
2246  "non-descriptor wallets");
2247  }
2248 
2249  WalletRescanReserver reserver(*pwallet);
2250  if (!reserver.reserve()) {
2252  "Wallet is currently rescanning. Abort "
2253  "existing rescan or wait.");
2254  }
2255 
2256  const UniValue &requests = main_request.params[0];
2257  const int64_t minimum_timestamp = 1;
2258  int64_t now = 0;
2259  int64_t lowest_timestamp = 0;
2260  bool rescan = false;
2262  {
2263  LOCK(pwallet->cs_wallet);
2264  EnsureWalletIsUnlocked(pwallet);
2265 
2266  CHECK_NONFATAL(pwallet->chain().findBlock(
2267  pwallet->GetLastBlockHash(),
2268  FoundBlock().time(lowest_timestamp).mtpTime(now)));
2269 
2270  // Get all timestamps and extract the lowest timestamp
2271  for (const UniValue &request : requests.getValues()) {
2272  // This throws an error if "timestamp" doesn't exist
2273  const int64_t timestamp = std::max(
2274  GetImportTimestamp(request, now), minimum_timestamp);
2275  const UniValue result =
2276  ProcessDescriptorImport(pwallet, request, timestamp);
2277  response.push_back(result);
2278 
2279  if (lowest_timestamp > timestamp) {
2280  lowest_timestamp = timestamp;
2281  }
2282 
2283  // If we know the chain tip, and at least one request was
2284  // successful then allow rescan
2285  if (!rescan && result["success"].get_bool()) {
2286  rescan = true;
2287  }
2288  }
2290  }
2291 
2292  // Rescan the blockchain using the lowest timestamp
2293  if (rescan) {
2294  int64_t scanned_time = pwallet->RescanFromTime(
2295  lowest_timestamp, reserver, true /* update */);
2296  {
2297  LOCK(pwallet->cs_wallet);
2298  pwallet->ReacceptWalletTransactions();
2299  }
2300 
2301  if (pwallet->IsAbortingRescan()) {
2303  "Rescan aborted by user.");
2304  }
2305 
2306  if (scanned_time > lowest_timestamp) {
2307  std::vector<UniValue> results = response.getValues();
2308  response.clear();
2309  response.setArray();
2310 
2311  // Compose the response
2312  for (unsigned int i = 0; i < requests.size(); ++i) {
2313  const UniValue &request = requests.getValues().at(i);
2314 
2315  // If the descriptor timestamp is within the
2316  // successfully scanned range, or if the import result
2317  // already has an error set, let the result stand
2318  // unmodified. Otherwise replace the result with an
2319  // error message.
2320  if (scanned_time <= GetImportTimestamp(request, now) ||
2321  results.at(i).exists("error")) {
2322  response.push_back(results.at(i));
2323  } else {
2324  UniValue result = UniValue(UniValue::VOBJ);
2325  result.pushKV("success", UniValue(false));
2326  result.pushKV(
2327  "error",
2328  JSONRPCError(
2331  "descriptor",
2332  GetImportTimestamp(request, now),
2333  scanned_time - TIMESTAMP_WINDOW - 1)));
2334  response.push_back(std::move(result));
2335  }
2336  }
2337  }
2338  }
2339 
2340  return response;
2341  },
2342  };
2343 }
2344 
2346  return RPCHelpMan{
2347  "backupwallet",
2348  "Safely copies current wallet file to destination, which can be a "
2349  "directory or a path with filename.\n",
2350  {
2351  {"destination", RPCArg::Type::STR, RPCArg::Optional::NO,
2352  "The destination directory or file"},
2353  },
2355  RPCExamples{HelpExampleCli("backupwallet", "\"backup.dat\"") +
2356  HelpExampleRpc("backupwallet", "\"backup.dat\"")},
2357  [&](const RPCHelpMan &self, const Config &config,
2358  const JSONRPCRequest &request) -> UniValue {
2359  std::shared_ptr<CWallet> const wallet =
2360  GetWalletForJSONRPCRequest(request);
2361  if (!wallet) {
2362  return NullUniValue;
2363  }
2364  const CWallet *const pwallet = wallet.get();
2365 
2366  // Make sure the results are valid at least up to the most recent
2367  // block the user could have gotten from another RPC command prior
2368  // to now
2369  pwallet->BlockUntilSyncedToCurrentChain();
2370 
2371  LOCK(pwallet->cs_wallet);
2372 
2373  std::string strDest = request.params[0].get_str();
2374  if (!pwallet->BackupWallet(strDest)) {
2376  "Error: Wallet backup failed!");
2377  }
2378 
2379  return NullUniValue;
2380  },
2381  };
2382 }
2383 
2385  return RPCHelpMan{
2386  "restorewallet",
2387  "\nRestore and loads a wallet from backup.\n",
2388  {
2389  {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO,
2390  "The name that will be applied to the restored wallet"},
2391  {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO,
2392  "The backup file that will be used to restore the wallet."},
2393  {"load_on_startup", RPCArg::Type::BOOL,
2395  "Save wallet name to persistent settings and load on startup. "
2396  "True to add wallet to startup list, false to remove, null to "
2397  "leave unchanged."},
2398  },
2400  "",
2401  "",
2402  {
2403  {RPCResult::Type::STR, "name",
2404  "The wallet name if restored successfully."},
2405  {RPCResult::Type::STR, "warning",
2406  "Warning message if wallet was not loaded cleanly."},
2407  }},
2409  "restorewallet",
2410  "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2412  "restorewallet",
2413  "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2415  "restorewallet",
2416  {{"wallet_name", "testwallet"},
2417  {"backup_file", "home\\backups\\backup-file.bak\""},
2418  {"load_on_startup", true}}) +
2420  "restorewallet",
2421  {{"wallet_name", "testwallet"},
2422  {"backup_file", "home\\backups\\backup-file.bak\""},
2423  {"load_on_startup", true}})},
2424  [&](const RPCHelpMan &self, const Config &config,
2425  const JSONRPCRequest &request) -> UniValue {
2426  WalletContext &context = EnsureWalletContext(request.context);
2427 
2428  fs::path backup_file =
2429  fs::PathFromString(request.params[1].get_str());
2430 
2431  if (!fs::exists(backup_file)) {
2433  "Backup file does not exist");
2434  }
2435 
2436  std::string wallet_name = request.params[0].get_str();
2437 
2438  const fs::path wallet_path = fsbridge::AbsPathJoin(
2439  GetWalletDir(), fs::PathFromString(wallet_name));
2440 
2441  if (fs::exists(wallet_path)) {
2443  "Wallet name already exists.");
2444  }
2445 
2446  if (!TryCreateDirectories(wallet_path)) {
2448  strprintf("Failed to create database path "
2449  "'%s'. Database already exists.",
2450  fs::PathToString(wallet_path)));
2451  }
2452 
2453  auto wallet_file = wallet_path / "wallet.dat";
2454 
2455  fs::copy_file(backup_file, wallet_file, fs::copy_options::none);
2456 
2457  auto [wallet, warnings] =
2458  LoadWalletHelper(context, request.params[2], wallet_name);
2459 
2460  UniValue obj(UniValue::VOBJ);
2461  obj.pushKV("name", wallet->GetName());
2462  obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2463 
2464  return obj;
2465  },
2466  };
2467 }
2468 
2470  // clang-format off
2471  static const CRPCCommand commands[] = {
2472  // category actor (function)
2473  // ------------------ ----------------------
2474  { "wallet", abortrescan, },
2475  { "wallet", backupwallet, },
2476  { "wallet", dumpprivkey, },
2477  { "wallet", dumpwallet, },
2478  { "wallet", dumpcoins, },
2479  { "wallet", importdescriptors, },
2480  { "wallet", importmulti, },
2481  { "wallet", importprivkey, },
2482  { "wallet", importwallet, },
2483  { "wallet", importaddress, },
2484  { "wallet", importprunedfunds, },
2485  { "wallet", importpubkey, },
2486  { "wallet", removeprunedfunds, },
2487  { "wallet", restorewallet, },
2488  };
2489  // clang-format on
2490 
2491  return commands;
2492 }
ArgsManager gArgs
Definition: args.cpp:38
static RPCHelpMan dumpcoins()
Definition: backup.cpp:1085
RPCHelpMan importprivkey()
Definition: backup.cpp:109
static const int64_t TIMESTAMP_MIN
Definition: backup.cpp:94
RPCHelpMan importdescriptors()
Definition: backup.cpp:2130
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
Definition: backup.cpp:96
RPCHelpMan importmulti()
Definition: backup.cpp:1673
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Definition: backup.cpp:1178
RPCHelpMan importaddress()
Definition: backup.cpp:266
RPCHelpMan importwallet()
Definition: backup.cpp:641
RPCHelpMan dumpwallet()
Definition: backup.cpp:907
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:1231
RPCHelpMan importpubkey()
Definition: backup.cpp:532
static std::string EncodeDumpString(const std::string &str)
Definition: backup.cpp:40
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:67
static std::string DecodeDumpString(const std::string &str)
Definition: backup.cpp:52
RPCHelpMan importprunedfunds()
Definition: backup.cpp:399
Span< const CRPCCommand > GetWalletDumpRPCCommands()
Definition: backup.cpp:2469
RPCHelpMan restorewallet()
Definition: backup.cpp:2384
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:1418
RPCHelpMan abortrescan()
Definition: backup.cpp:233
ScriptContext
Definition: backup.cpp:1168
@ 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:1531
RPCHelpMan backupwallet()
Definition: backup.cpp:2345
RPCHelpMan dumpprivkey()
Definition: backup.cpp:855
static UniValue ProcessDescriptorImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:1951
RPCHelpMan removeprunedfunds()
Definition: backup.cpp:482
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: backup.cpp:1640
static std::string GetRescanErrorMessage(const std::string &object, const int64_t objectTimestamp, const int64_t blockTimestamp)
Definition: backup.cpp:1657
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:53
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:526
BlockHash GetHash() const
Definition: block.cpp:11
uint256 hashMerkleRoot
Definition: block.h:28
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
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:274
TxId GetId() const
Compute the id and hash of this CMutableTransaction.
Definition: transaction.cpp:52
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:137
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:24
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:254
BlockHash GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.h:1026
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
Definition: wallet.cpp:3313
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:955
RecursiveMutex cs_wallet
Definition: wallet.h:389
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:966
bool IsAbortingRescan() const
Definition: wallet.h:515
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:448
bool BackupWallet(const std::string &strDest) const
Definition: wallet.cpp:3097
bool IsScanning() const
Definition: wallet.h:516
void AbortRescan()
Definition: wallet.h:514
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3031
Definition: config.h:19
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
void push_back(UniValue val)
Definition: univalue.cpp:96
const std::string & get_str() const
enum VType getType() const
Definition: univalue.h:88
@ VOBJ
Definition: univalue.h:31
@ VSTR
Definition: univalue.h:33
@ VARR
Definition: univalue.h:32
size_t size() const
Definition: univalue.h:92
enum VType type() const
Definition: univalue.h:147
const std::vector< UniValue > & getValues() const
bool isStr() const
Definition: univalue.h:108
Int getInt() const
Definition: univalue.h:157
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:99
bool isNum() const
Definition: univalue.h:109
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:115
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:1099
bool IsNull() const
Definition: uint256.h:32
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::string u8string() const
Definition: fs.h:72
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:117
256-bit opaque blob.
Definition: uint256.h:129
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:222
const std::string CLIENT_BUILD
const std::string CLIENT_NAME
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:197
bool TryCreateDirectories(const fs::path &p)
Ignores exceptions thrown by create_directories if the requested directory exists.
Definition: fs_helpers.cpp:287
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:2260
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:2201
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:1607
void MarkDirty()
Definition: wallet.cpp:894
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1587
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true)
Definition: wallet.cpp:952
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1597
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1424
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:1621
const CChainParams & GetChainParams() const override
Definition: wallet.cpp:386
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1848
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
Definition: wallet.cpp:1517
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1656
@ ISMINE_SPENDABLE
Definition: ismine.h:21
std::string EncodeDestination(const CTxDestination &dest, const Config &config)
Definition: key_io.cpp:167
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:156
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:102
CTxDestination DecodeDestination(const std::string &addr, const CChainParams &params)
Definition: key_io.cpp:174
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:77
bool error(const char *fmt, const Args &...args)
Definition: logging.h:226
static path absolute(const path &p)
Definition: fs.h:96
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:102
static bool copy_file(const path &from, const path &to, copy_options options)
Definition: fs.h:119
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:165
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:39
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:316
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
Response response
Definition: processor.cpp:487
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ 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:1273
std::vector< uint8_t > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:94
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:150
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:176
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:167
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:22
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:73
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:155
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
@ SER_NETWORK
Definition: serialize.h:152
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
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:252
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
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:108
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:260
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:240
TxoutType
Definition: standard.h:38
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:85
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:53
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:22
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:1158
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:1164
std::set< CScript > import_scripts
Definition: backup.cpp:1161
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
Definition: backup.cpp:1165
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OBJ_NAMED_PARAMS
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::string DefaultHint
Hint for default value.
Definition: util.h:195
@ OMITTED
The arg is optional for one of two reasons:
@ NO
Required arg.
std::vector< std::string > type_str
Should be empty unless it is supposed to override the auto-generated type strings.
Definition: util.h:134
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:128
@ 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:309
#define LOCK(cs)
Definition: sync.h:306
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
int64_t GetTime()
Definition: time.cpp:109
int64_t ParseISO8601DateTime(const std::string &str)
Definition: time.cpp:142
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:113
#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:68
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:209
const UniValue NullUniValue
Definition: univalue.cpp:16
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
void EnsureWalletIsUnlocked(const CWallet *pwallet)
Definition: util.cpp:94
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:63
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:112
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:102
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:134
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