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