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