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