Bitcoin Core  0.20.99
P2P Digital Currency
rpcdump.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2020 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 <core_io.h>
7 #include <interfaces/chain.h>
8 #include <key_io.h>
9 #include <merkleblock.h>
10 #include <rpc/util.h>
11 #include <script/descriptor.h>
12 #include <script/script.h>
13 #include <script/standard.h>
14 #include <sync.h>
15 #include <util/bip32.h>
16 #include <util/system.h>
17 #include <util/time.h>
18 #include <util/translation.h>
19 #include <wallet/rpcwallet.h>
20 #include <wallet/wallet.h>
21 
22 #include <stdint.h>
23 #include <tuple>
24 
25 #include <boost/algorithm/string.hpp>
26 
27 #include <univalue.h>
28 
29 
30 
32 
33 std::string static EncodeDumpString(const std::string &str) {
34  std::stringstream ret;
35  for (const unsigned char c : str) {
36  if (c <= 32 || c >= 128 || c == '%') {
37  ret << '%' << HexStr(&c, &c + 1);
38  } else {
39  ret << c;
40  }
41  }
42  return ret.str();
43 }
44 
45 static std::string DecodeDumpString(const std::string &str) {
46  std::stringstream ret;
47  for (unsigned int pos = 0; pos < str.length(); pos++) {
48  unsigned char c = str[pos];
49  if (c == '%' && pos+2 < str.length()) {
50  c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
51  ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
52  pos += 2;
53  }
54  ret << c;
55  }
56  return ret.str();
57 }
58 
59 static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan* spk_man, const CWallet* const pwallet, const CKeyID& keyid, std::string& strAddr, std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
60 {
61  bool fLabelFound = false;
62  CKey key;
63  spk_man->GetKey(keyid, key);
64  for (const auto& dest : GetAllDestinationsForKey(key.GetPubKey())) {
65  const auto* address_book_entry = pwallet->FindAddressBookEntry(dest);
66  if (address_book_entry) {
67  if (!strAddr.empty()) {
68  strAddr += ",";
69  }
70  strAddr += EncodeDestination(dest);
71  strLabel = EncodeDumpString(address_book_entry->GetLabel());
72  fLabelFound = true;
73  }
74  }
75  if (!fLabelFound) {
76  strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), pwallet->m_default_address_type));
77  }
78  return fLabelFound;
79 }
80 
81 static const int64_t TIMESTAMP_MIN = 0;
82 
83 static void RescanWallet(CWallet& wallet, const WalletRescanReserver& reserver, int64_t time_begin = TIMESTAMP_MIN, bool update = true)
84 {
85  int64_t scanned_time = wallet.RescanFromTime(time_begin, reserver, update);
86  if (wallet.IsAbortingRescan()) {
87  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
88  } else if (scanned_time > time_begin) {
89  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan was unable to fully rescan the blockchain. Some transactions may be missing.");
90  }
91 }
92 
94 {
95  RPCHelpMan{"importprivkey",
96  "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
97  "Hint: use importmulti to import more than one private key.\n"
98  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
99  "may report that the imported key exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
100  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
101  {
102  {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
103  {"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"},
104  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
105  },
107  RPCExamples{
108  "\nDump a private key\n"
109  + HelpExampleCli("dumpprivkey", "\"myaddress\"") +
110  "\nImport the private key with rescan\n"
111  + HelpExampleCli("importprivkey", "\"mykey\"") +
112  "\nImport using a label and without rescan\n"
113  + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
114  "\nImport using default blank label and without rescan\n"
115  + HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
116  "\nAs a JSON-RPC call\n"
117  + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
118  },
119  }.Check(request);
120 
121  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
122  if (!wallet) return NullUniValue;
123  CWallet* const pwallet = wallet.get();
124 
126  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
127  }
128 
129  EnsureLegacyScriptPubKeyMan(*wallet, true);
130 
131  WalletRescanReserver reserver(*pwallet);
132  bool fRescan = true;
133  {
134  LOCK(pwallet->cs_wallet);
135 
136  EnsureWalletIsUnlocked(pwallet);
137 
138  std::string strSecret = request.params[0].get_str();
139  std::string strLabel = "";
140  if (!request.params[1].isNull())
141  strLabel = request.params[1].get_str();
142 
143  // Whether to perform rescan after import
144  if (!request.params[2].isNull())
145  fRescan = request.params[2].get_bool();
146 
147  if (fRescan && pwallet->chain().havePruned()) {
148  // Exit early and print an error.
149  // If a block is pruned after this check, we will import the key(s),
150  // but fail the rescan with a generic error.
151  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
152  }
153 
154  if (fRescan && !reserver.reserve()) {
155  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
156  }
157 
158  CKey key = DecodeSecret(strSecret);
159  if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
160 
161  CPubKey pubkey = key.GetPubKey();
162  CHECK_NONFATAL(key.VerifyPubKey(pubkey));
163  CKeyID vchAddress = pubkey.GetID();
164  {
165  pwallet->MarkDirty();
166 
167  // We don't know which corresponding address will be used;
168  // label all new addresses, and label existing addresses if a
169  // label was passed.
170  for (const auto& dest : GetAllDestinationsForKey(pubkey)) {
171  if (!request.params[1].isNull() || !pwallet->FindAddressBookEntry(dest)) {
172  pwallet->SetAddressBook(dest, strLabel, "receive");
173  }
174  }
175 
176  // Use timestamp of 1 to scan the whole chain
177  if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
178  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
179  }
180 
181  // Add the wpkh script for this key if possible
182  if (pubkey.IsCompressed()) {
183  pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, 0 /* timestamp */);
184  }
185  }
186  }
187  if (fRescan) {
188  RescanWallet(*pwallet, reserver);
189  }
190 
191  return NullUniValue;
192 }
193 
195 {
196  RPCHelpMan{"abortrescan",
197  "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
198  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
199  {},
200  RPCResult{RPCResult::Type::BOOL, "", "Whether the abort was successful"},
201  RPCExamples{
202  "\nImport a private key\n"
203  + HelpExampleCli("importprivkey", "\"mykey\"") +
204  "\nAbort the running wallet rescan\n"
205  + HelpExampleCli("abortrescan", "") +
206  "\nAs a JSON-RPC call\n"
207  + HelpExampleRpc("abortrescan", "")
208  },
209  }.Check(request);
210 
211  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
212  if (!wallet) return NullUniValue;
213  CWallet* const pwallet = wallet.get();
214 
215  if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
216  pwallet->AbortRescan();
217  return true;
218 }
219 
221 {
222  RPCHelpMan{"importaddress",
223  "\nAdds an address or script (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
224  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
225  "may report that the imported address exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
226  "If you have the full public key, you should call importpubkey instead of this.\n"
227  "Hint: use importmulti to import more than one address.\n"
228  "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
229  "as change, and not show up in many RPCs.\n"
230  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
231  {
232  {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
233  {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
234  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
235  {"p2sh", RPCArg::Type::BOOL, /* default */ "false", "Add the P2SH version of the script as well"},
236  },
238  RPCExamples{
239  "\nImport an address with rescan\n"
240  + HelpExampleCli("importaddress", "\"myaddress\"") +
241  "\nImport using a label without rescan\n"
242  + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") +
243  "\nAs a JSON-RPC call\n"
244  + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
245  },
246  }.Check(request);
247 
248  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
249  if (!wallet) return NullUniValue;
250  CWallet* const pwallet = wallet.get();
251 
252  EnsureLegacyScriptPubKeyMan(*pwallet, true);
253 
254  std::string strLabel;
255  if (!request.params[1].isNull())
256  strLabel = request.params[1].get_str();
257 
258  // Whether to perform rescan after import
259  bool fRescan = true;
260  if (!request.params[2].isNull())
261  fRescan = request.params[2].get_bool();
262 
263  if (fRescan && pwallet->chain().havePruned()) {
264  // Exit early and print an error.
265  // If a block is pruned after this check, we will import the key(s),
266  // but fail the rescan with a generic error.
267  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
268  }
269 
270  WalletRescanReserver reserver(*pwallet);
271  if (fRescan && !reserver.reserve()) {
272  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
273  }
274 
275  // Whether to import a p2sh version, too
276  bool fP2SH = false;
277  if (!request.params[3].isNull())
278  fP2SH = request.params[3].get_bool();
279 
280  {
281  LOCK(pwallet->cs_wallet);
282 
283  CTxDestination dest = DecodeDestination(request.params[0].get_str());
284  if (IsValidDestination(dest)) {
285  if (fP2SH) {
286  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
287  }
288 
289  pwallet->MarkDirty();
290 
291  pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
292  } else if (IsHex(request.params[0].get_str())) {
293  std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
294  CScript redeem_script(data.begin(), data.end());
295 
296  std::set<CScript> scripts = {redeem_script};
297  pwallet->ImportScripts(scripts, 0 /* timestamp */);
298 
299  if (fP2SH) {
300  scripts.insert(GetScriptForDestination(ScriptHash(redeem_script)));
301  }
302 
303  pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
304  } else {
305  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
306  }
307  }
308  if (fRescan)
309  {
310  RescanWallet(*pwallet, reserver);
311  {
312  LOCK(pwallet->cs_wallet);
313  pwallet->ReacceptWalletTransactions();
314  }
315  }
316 
317  return NullUniValue;
318 }
319 
321 {
322  RPCHelpMan{"importprunedfunds",
323  "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n",
324  {
325  {"rawtransaction", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A raw transaction in hex funding an already-existing address in wallet"},
326  {"txoutproof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex output from gettxoutproof that contains the transaction"},
327  },
329  RPCExamples{""},
330  }.Check(request);
331 
332  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
333  if (!wallet) return NullUniValue;
334  CWallet* const pwallet = wallet.get();
335 
337  if (!DecodeHexTx(tx, request.params[0].get_str()))
338  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
339  uint256 hashTx = tx.GetHash();
340 
341  CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
342  CMerkleBlock merkleBlock;
343  ssMB >> merkleBlock;
344 
345  //Search partial merkle tree in proof for our transaction and index in valid block
346  std::vector<uint256> vMatch;
347  std::vector<unsigned int> vIndex;
348  if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
349  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
350  }
351 
352  LOCK(pwallet->cs_wallet);
353  int height;
354  if (!pwallet->chain().findAncestorByHash(pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(), FoundBlock().height(height))) {
355  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
356  }
357 
358  std::vector<uint256>::const_iterator it;
359  if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
360  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
361  }
362 
363  unsigned int txnIndex = vIndex[it - vMatch.begin()];
364 
365  CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, height, merkleBlock.header.GetHash(), txnIndex);
366 
367  CTransactionRef tx_ref = MakeTransactionRef(tx);
368  if (pwallet->IsMine(*tx_ref)) {
369  pwallet->AddToWallet(std::move(tx_ref), confirm);
370  return NullUniValue;
371  }
372 
373  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
374 }
375 
377 {
378  RPCHelpMan{"removeprunedfunds",
379  "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n",
380  {
381  {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded id of the transaction you are deleting"},
382  },
384  RPCExamples{
385  HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
386  "\nAs a JSON-RPC call\n"
387  + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
388  },
389  }.Check(request);
390 
391  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
392  if (!wallet) return NullUniValue;
393  CWallet* const pwallet = wallet.get();
394 
395  LOCK(pwallet->cs_wallet);
396 
397  uint256 hash(ParseHashV(request.params[0], "txid"));
398  std::vector<uint256> vHash;
399  vHash.push_back(hash);
400  std::vector<uint256> vHashOut;
401 
402  if (pwallet->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
403  throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction.");
404  }
405 
406  if(vHashOut.empty()) {
407  throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
408  }
409 
410  return NullUniValue;
411 }
412 
414 {
415  RPCHelpMan{"importpubkey",
416  "\nAdds a public key (in hex) that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
417  "Hint: use importmulti to import more than one public key.\n"
418  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
419  "may report that the imported pubkey exists but related transactions are still missing, leading to temporarily incorrect/bogus balances and unspent outputs until rescan completes.\n"
420  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
421  {
422  {"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
423  {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
424  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
425  },
427  RPCExamples{
428  "\nImport a public key with rescan\n"
429  + HelpExampleCli("importpubkey", "\"mypubkey\"") +
430  "\nImport using a label without rescan\n"
431  + HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
432  "\nAs a JSON-RPC call\n"
433  + HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
434  },
435  }.Check(request);
436 
437  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
438  if (!wallet) return NullUniValue;
439  CWallet* const pwallet = wallet.get();
440 
441  EnsureLegacyScriptPubKeyMan(*wallet, true);
442 
443  std::string strLabel;
444  if (!request.params[1].isNull())
445  strLabel = request.params[1].get_str();
446 
447  // Whether to perform rescan after import
448  bool fRescan = true;
449  if (!request.params[2].isNull())
450  fRescan = request.params[2].get_bool();
451 
452  if (fRescan && pwallet->chain().havePruned()) {
453  // Exit early and print an error.
454  // If a block is pruned after this check, we will import the key(s),
455  // but fail the rescan with a generic error.
456  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
457  }
458 
459  WalletRescanReserver reserver(*pwallet);
460  if (fRescan && !reserver.reserve()) {
461  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
462  }
463 
464  if (!IsHex(request.params[0].get_str()))
465  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
466  std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
467  CPubKey pubKey(data.begin(), data.end());
468  if (!pubKey.IsFullyValid())
469  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
470 
471  {
472  LOCK(pwallet->cs_wallet);
473 
474  std::set<CScript> script_pub_keys;
475  for (const auto& dest : GetAllDestinationsForKey(pubKey)) {
476  script_pub_keys.insert(GetScriptForDestination(dest));
477  }
478 
479  pwallet->MarkDirty();
480 
481  pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
482 
483  pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */);
484  }
485  if (fRescan)
486  {
487  RescanWallet(*pwallet, reserver);
488  {
489  LOCK(pwallet->cs_wallet);
490  pwallet->ReacceptWalletTransactions();
491  }
492  }
493 
494  return NullUniValue;
495 }
496 
497 
499 {
500  RPCHelpMan{"importwallet",
501  "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
502  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
503  {
504  {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"},
505  },
507  RPCExamples{
508  "\nDump the wallet\n"
509  + HelpExampleCli("dumpwallet", "\"test\"") +
510  "\nImport the wallet\n"
511  + HelpExampleCli("importwallet", "\"test\"") +
512  "\nImport using the json rpc call\n"
513  + HelpExampleRpc("importwallet", "\"test\"")
514  },
515  }.Check(request);
516 
517  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
518  if (!wallet) return NullUniValue;
519  CWallet* const pwallet = wallet.get();
520 
521  EnsureLegacyScriptPubKeyMan(*wallet, true);
522 
523  if (pwallet->chain().havePruned()) {
524  // Exit early and print an error.
525  // If a block is pruned after this check, we will import the key(s),
526  // but fail the rescan with a generic error.
527  throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned");
528  }
529 
530  WalletRescanReserver reserver(*pwallet);
531  if (!reserver.reserve()) {
532  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
533  }
534 
535  int64_t nTimeBegin = 0;
536  bool fGood = true;
537  {
538  LOCK(pwallet->cs_wallet);
539 
540  EnsureWalletIsUnlocked(pwallet);
541 
542  fsbridge::ifstream file;
543  file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
544  if (!file.is_open()) {
545  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
546  }
547  CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(), FoundBlock().time(nTimeBegin)));
548 
549  int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
550  file.seekg(0, file.beg);
551 
552  // Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
553  // we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
554  pwallet->chain().showProgress(strprintf("%s " + _("Importing...").translated, pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
555  std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
556  std::vector<std::pair<CScript, int64_t>> scripts;
557  while (file.good()) {
558  pwallet->chain().showProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
559  std::string line;
560  std::getline(file, line);
561  if (line.empty() || line[0] == '#')
562  continue;
563 
564  std::vector<std::string> vstr;
565  boost::split(vstr, line, boost::is_any_of(" "));
566  if (vstr.size() < 2)
567  continue;
568  CKey key = DecodeSecret(vstr[0]);
569  if (key.IsValid()) {
570  int64_t nTime = ParseISO8601DateTime(vstr[1]);
571  std::string strLabel;
572  bool fLabel = true;
573  for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
574  if (vstr[nStr].front() == '#')
575  break;
576  if (vstr[nStr] == "change=1")
577  fLabel = false;
578  if (vstr[nStr] == "reserve=1")
579  fLabel = false;
580  if (vstr[nStr].substr(0,6) == "label=") {
581  strLabel = DecodeDumpString(vstr[nStr].substr(6));
582  fLabel = true;
583  }
584  }
585  keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
586  } else if(IsHex(vstr[0])) {
587  std::vector<unsigned char> vData(ParseHex(vstr[0]));
588  CScript script = CScript(vData.begin(), vData.end());
589  int64_t birth_time = ParseISO8601DateTime(vstr[1]);
590  scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
591  }
592  }
593  file.close();
594  // We now know whether we are importing private keys, so we can error if private keys are disabled
595  if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
596  pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
597  throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
598  }
599  double total = (double)(keys.size() + scripts.size());
600  double progress = 0;
601  for (const auto& key_tuple : keys) {
602  pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
603  const CKey& key = std::get<0>(key_tuple);
604  int64_t time = std::get<1>(key_tuple);
605  bool has_label = std::get<2>(key_tuple);
606  std::string label = std::get<3>(key_tuple);
607 
608  CPubKey pubkey = key.GetPubKey();
609  CHECK_NONFATAL(key.VerifyPubKey(pubkey));
610  CKeyID keyid = pubkey.GetID();
611 
612  pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid)));
613 
614  if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
615  pwallet->WalletLogPrintf("Error importing key for %s\n", EncodeDestination(PKHash(keyid)));
616  fGood = false;
617  continue;
618  }
619 
620  if (has_label)
621  pwallet->SetAddressBook(PKHash(keyid), label, "receive");
622 
623  nTimeBegin = std::min(nTimeBegin, time);
624  progress++;
625  }
626  for (const auto& script_pair : scripts) {
627  pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
628  const CScript& script = script_pair.first;
629  int64_t time = script_pair.second;
630 
631  if (!pwallet->ImportScripts({script}, time)) {
632  pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script));
633  fGood = false;
634  continue;
635  }
636  if (time > 0) {
637  nTimeBegin = std::min(nTimeBegin, time);
638  }
639 
640  progress++;
641  }
642  pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
643  }
644  pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
645  RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
646  pwallet->MarkDirty();
647 
648  if (!fGood)
649  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys/scripts to wallet");
650 
651  return NullUniValue;
652 }
653 
655 {
656  RPCHelpMan{"dumpprivkey",
657  "\nReveals the private key corresponding to 'address'.\n"
658  "Then the importprivkey can be used with this output\n",
659  {
660  {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for the private key"},
661  },
662  RPCResult{
663  RPCResult::Type::STR, "key", "The private key"
664  },
665  RPCExamples{
666  HelpExampleCli("dumpprivkey", "\"myaddress\"")
667  + HelpExampleCli("importprivkey", "\"mykey\"")
668  + HelpExampleRpc("dumpprivkey", "\"myaddress\"")
669  },
670  }.Check(request);
671 
672  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
673  if (!wallet) return NullUniValue;
674  const CWallet* const pwallet = wallet.get();
675 
677 
678  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
679 
680  EnsureWalletIsUnlocked(pwallet);
681 
682  std::string strAddress = request.params[0].get_str();
683  CTxDestination dest = DecodeDestination(strAddress);
684  if (!IsValidDestination(dest)) {
685  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
686  }
687  auto keyid = GetKeyForDestination(spk_man, dest);
688  if (keyid.IsNull()) {
689  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
690  }
691  CKey vchSecret;
692  if (!spk_man.GetKey(keyid, vchSecret)) {
693  throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
694  }
695  return EncodeSecret(vchSecret);
696 }
697 
698 
700 {
701  RPCHelpMan{"dumpwallet",
702  "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
703  "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
704  "Note that if your wallet contains keys which are not derived from your HD seed (e.g. imported keys), these are not covered by\n"
705  "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
706  {
707  {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The filename with path (absolute path recommended)"},
708  },
709  RPCResult{
710  RPCResult::Type::OBJ, "", "",
711  {
712  {RPCResult::Type::STR, "filename", "The filename with full absolute path"},
713  }
714  },
715  RPCExamples{
716  HelpExampleCli("dumpwallet", "\"test\"")
717  + HelpExampleRpc("dumpwallet", "\"test\"")
718  },
719  }.Check(request);
720 
721  std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
722  if (!pwallet) return NullUniValue;
723 
724  CWallet& wallet = *pwallet;
726 
727  // Make sure the results are valid at least up to the most recent block
728  // the user could have gotten from another RPC command prior to now
730 
731  LOCK2(wallet.cs_wallet, spk_man.cs_KeyStore);
732 
733  EnsureWalletIsUnlocked(&wallet);
734 
735  fs::path filepath = request.params[0].get_str();
736  filepath = fs::absolute(filepath);
737 
738  /* Prevent arbitrary files from being overwritten. There have been reports
739  * that users have overwritten wallet files this way:
740  * https://github.com/bitcoin/bitcoin/issues/9934
741  * It may also avoid other security issues.
742  */
743  if (fs::exists(filepath)) {
744  throw JSONRPCError(RPC_INVALID_PARAMETER, filepath.string() + " already exists. If you are sure this is what you want, move it out of the way first");
745  }
746 
747  fsbridge::ofstream file;
748  file.open(filepath);
749  if (!file.is_open())
750  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
751 
752  std::map<CKeyID, int64_t> mapKeyBirth;
753  const std::map<CKeyID, int64_t>& mapKeyPool = spk_man.GetAllReserveKeys();
754  wallet.GetKeyBirthTimes(mapKeyBirth);
755 
756  std::set<CScriptID> scripts = spk_man.GetCScripts();
757 
758  // sort time/key pairs
759  std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
760  for (const auto& entry : mapKeyBirth) {
761  vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
762  }
763  mapKeyBirth.clear();
764  std::sort(vKeyBirth.begin(), vKeyBirth.end());
765 
766  // produce output
767  file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
768  file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
769  file << strprintf("# * Best block at time of backup was %i (%s),\n", wallet.GetLastBlockHeight(), wallet.GetLastBlockHash().ToString());
770  int64_t block_time = 0;
771  CHECK_NONFATAL(wallet.chain().findBlock(wallet.GetLastBlockHash(), FoundBlock().time(block_time)));
772  file << strprintf("# mined on %s\n", FormatISO8601DateTime(block_time));
773  file << "\n";
774 
775  // add the base58check encoded extended master if the wallet uses HD
776  CKeyID seed_id = spk_man.GetHDChain().seed_id;
777  if (!seed_id.IsNull())
778  {
779  CKey seed;
780  if (spk_man.GetKey(seed_id, seed)) {
781  CExtKey masterKey;
782  masterKey.SetSeed(seed.begin(), seed.size());
783 
784  file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n\n";
785  }
786  }
787  for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
788  const CKeyID &keyid = it->second;
789  std::string strTime = FormatISO8601DateTime(it->first);
790  std::string strAddr;
791  std::string strLabel;
792  CKey key;
793  if (spk_man.GetKey(keyid, key)) {
794  file << strprintf("%s %s ", EncodeSecret(key), strTime);
795  if (GetWalletAddressesForKey(&spk_man, &wallet, keyid, strAddr, strLabel)) {
796  file << strprintf("label=%s", strLabel);
797  } else if (keyid == seed_id) {
798  file << "hdseed=1";
799  } else if (mapKeyPool.count(keyid)) {
800  file << "reserve=1";
801  } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
802  file << "inactivehdseed=1";
803  } else {
804  file << "change=1";
805  }
806  file << strprintf(" # addr=%s%s\n", strAddr, (spk_man.mapKeyMetadata[keyid].has_key_origin ? " hdkeypath="+WriteHDKeypath(spk_man.mapKeyMetadata[keyid].key_origin.path) : ""));
807  }
808  }
809  file << "\n";
810  for (const CScriptID &scriptid : scripts) {
811  CScript script;
812  std::string create_time = "0";
813  std::string address = EncodeDestination(ScriptHash(scriptid));
814  // get birth times for scripts with metadata
815  auto it = spk_man.m_script_metadata.find(scriptid);
816  if (it != spk_man.m_script_metadata.end()) {
817  create_time = FormatISO8601DateTime(it->second.nCreateTime);
818  }
819  if(spk_man.GetCScript(scriptid, script)) {
820  file << strprintf("%s %s script=1", HexStr(script), create_time);
821  file << strprintf(" # addr=%s\n", address);
822  }
823  }
824  file << "\n";
825  file << "# End of dump\n";
826  file.close();
827 
828  UniValue reply(UniValue::VOBJ);
829  reply.pushKV("filename", filepath.string());
830 
831  return reply;
832 }
833 
835 {
836  // Input data
837  std::unique_ptr<CScript> redeemscript;
838  std::unique_ptr<CScript> witnessscript;
839 
840  // Output data
841  std::set<CScript> import_scripts;
842  std::map<CKeyID, bool> used_keys;
843  std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
844 };
845 
846 enum class ScriptContext
847 {
848  TOP,
849  P2SH,
850  WITNESS_V0,
851 };
852 
853 // Analyse the provided scriptPubKey, determining which keys and which redeem scripts from the ImportData struct are needed to spend it, and mark them as used.
854 // Returns an error string, or the empty string for success.
855 static std::string RecurseImportData(const CScript& script, ImportData& import_data, const ScriptContext script_ctx)
856 {
857  // Use Solver to obtain script type and parsed pubkeys or hashes:
858  std::vector<std::vector<unsigned char>> solverdata;
859  TxoutType script_type = Solver(script, solverdata);
860 
861  switch (script_type) {
862  case TxoutType::PUBKEY: {
863  CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
864  import_data.used_keys.emplace(pubkey.GetID(), false);
865  return "";
866  }
867  case TxoutType::PUBKEYHASH: {
868  CKeyID id = CKeyID(uint160(solverdata[0]));
869  import_data.used_keys[id] = true;
870  return "";
871  }
872  case TxoutType::SCRIPTHASH: {
873  if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
874  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH");
875  CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
876  CScriptID id = CScriptID(uint160(solverdata[0]));
877  auto subscript = std::move(import_data.redeemscript); // Remove redeemscript from import_data to check for superfluous script later.
878  if (!subscript) return "missing redeemscript";
879  if (CScriptID(*subscript) != id) return "redeemScript does not match the scriptPubKey";
880  import_data.import_scripts.emplace(*subscript);
881  return RecurseImportData(*subscript, import_data, ScriptContext::P2SH);
882  }
883  case TxoutType::MULTISIG: {
884  for (size_t i = 1; i + 1< solverdata.size(); ++i) {
885  CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
886  import_data.used_keys.emplace(pubkey.GetID(), false);
887  }
888  return "";
889  }
891  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
892  uint256 fullid(solverdata[0]);
893  CScriptID id;
894  CRIPEMD160().Write(fullid.begin(), fullid.size()).Finalize(id.begin());
895  auto subscript = std::move(import_data.witnessscript); // Remove redeemscript from import_data to check for superfluous script later.
896  if (!subscript) return "missing witnessscript";
897  if (CScriptID(*subscript) != id) return "witnessScript does not match the scriptPubKey or redeemScript";
898  if (script_ctx == ScriptContext::TOP) {
899  import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WSH requires the TOP script imported (see script/ismine.cpp)
900  }
901  import_data.import_scripts.emplace(*subscript);
902  return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0);
903  }
905  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH");
906  CKeyID id = CKeyID(uint160(solverdata[0]));
907  import_data.used_keys[id] = true;
908  if (script_ctx == ScriptContext::TOP) {
909  import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WPKH requires the TOP script imported (see script/ismine.cpp)
910  }
911  return "";
912  }
914  return "unspendable script";
917  default:
918  return "unrecognized script";
919  }
920 }
921 
922 static UniValue ProcessImportLegacy(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)
923 {
924  UniValue warnings(UniValue::VARR);
925 
926  // First ensure scriptPubKey has either a script or JSON with "address" string
927  const UniValue& scriptPubKey = data["scriptPubKey"];
928  bool isScript = scriptPubKey.getType() == UniValue::VSTR;
929  if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
930  throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");
931  }
932  const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
933 
934  // Optional fields.
935  const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
936  const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
937  const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
938  const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
939  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
940  const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
941 
942  if (data.exists("range")) {
943  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for a non-descriptor import");
944  }
945 
946  // Generate the script and destination for the scriptPubKey provided
947  CScript script;
948  if (!isScript) {
949  CTxDestination dest = DecodeDestination(output);
950  if (!IsValidDestination(dest)) {
951  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
952  }
953  script = GetScriptForDestination(dest);
954  } else {
955  if (!IsHex(output)) {
956  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\"");
957  }
958  std::vector<unsigned char> vData(ParseHex(output));
959  script = CScript(vData.begin(), vData.end());
960  CTxDestination dest;
961  if (!ExtractDestination(script, dest) && !internal) {
962  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
963  }
964  }
965  script_pub_keys.emplace(script);
966 
967  // Parse all arguments
968  if (strRedeemScript.size()) {
969  if (!IsHex(strRedeemScript)) {
970  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
971  }
972  auto parsed_redeemscript = ParseHex(strRedeemScript);
973  import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
974  }
975  if (witness_script_hex.size()) {
976  if (!IsHex(witness_script_hex)) {
977  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
978  }
979  auto parsed_witnessscript = ParseHex(witness_script_hex);
980  import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
981  }
982  for (size_t i = 0; i < pubKeys.size(); ++i) {
983  const auto& str = pubKeys[i].get_str();
984  if (!IsHex(str)) {
985  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string");
986  }
987  auto parsed_pubkey = ParseHex(str);
988  CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
989  if (!pubkey.IsFullyValid()) {
990  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
991  }
992  pubkey_map.emplace(pubkey.GetID(), pubkey);
993  ordered_pubkeys.push_back(pubkey.GetID());
994  }
995  for (size_t i = 0; i < keys.size(); ++i) {
996  const auto& str = keys[i].get_str();
997  CKey key = DecodeSecret(str);
998  if (!key.IsValid()) {
999  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
1000  }
1001  CPubKey pubkey = key.GetPubKey();
1002  CKeyID id = pubkey.GetID();
1003  if (pubkey_map.count(id)) {
1004  pubkey_map.erase(id);
1005  }
1006  privkey_map.emplace(id, key);
1007  }
1008 
1009 
1010  // Verify and process input data
1011  have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size();
1012  if (have_solving_data) {
1013  // Match up data in import_data with the scriptPubKey in script.
1014  auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1015 
1016  // Verify whether the watchonly option corresponds to the availability of private keys.
1017  bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; });
1018  if (!watchOnly && !spendable) {
1019  warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1020  }
1021  if (watchOnly && spendable) {
1022  warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1023  }
1024 
1025  // Check that all required keys for solvability are provided.
1026  if (error.empty()) {
1027  for (const auto& require_key : import_data.used_keys) {
1028  if (!require_key.second) continue; // Not a required key
1029  if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1030  error = "some required keys are missing";
1031  }
1032  }
1033  }
1034 
1035  if (!error.empty()) {
1036  warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1037  import_data = ImportData();
1038  pubkey_map.clear();
1039  privkey_map.clear();
1040  have_solving_data = false;
1041  } else {
1042  // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
1043  if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script.");
1044  if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1045  for (auto it = privkey_map.begin(); it != privkey_map.end(); ) {
1046  auto oldit = it++;
1047  if (import_data.used_keys.count(oldit->first) == 0) {
1048  warnings.push_back("Ignoring irrelevant private key.");
1049  privkey_map.erase(oldit);
1050  }
1051  }
1052  for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
1053  auto oldit = it++;
1054  auto key_data_it = import_data.used_keys.find(oldit->first);
1055  if (key_data_it == import_data.used_keys.end() || !key_data_it->second) {
1056  warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH.");
1057  pubkey_map.erase(oldit);
1058  }
1059  }
1060  }
1061  }
1062 
1063  return warnings;
1064 }
1065 
1066 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)
1067 {
1068  UniValue warnings(UniValue::VARR);
1069 
1070  const std::string& descriptor = data["desc"].get_str();
1071  FlatSigningProvider keys;
1072  std::string error;
1073  auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true);
1074  if (!parsed_desc) {
1076  }
1077 
1078  have_solving_data = parsed_desc->IsSolvable();
1079  const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1080 
1081  int64_t range_start = 0, range_end = 0;
1082  if (!parsed_desc->IsRange() && data.exists("range")) {
1083  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
1084  } else if (parsed_desc->IsRange()) {
1085  if (!data.exists("range")) {
1086  throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
1087  }
1088  std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1089  }
1090 
1091  const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
1092 
1093  // Expand all descriptors to get public keys and scripts, and private keys if available.
1094  for (int i = range_start; i <= range_end; ++i) {
1095  FlatSigningProvider out_keys;
1096  std::vector<CScript> scripts_temp;
1097  parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1098  std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1099  for (const auto& key_pair : out_keys.pubkeys) {
1100  ordered_pubkeys.push_back(key_pair.first);
1101  }
1102 
1103  for (const auto& x : out_keys.scripts) {
1104  import_data.import_scripts.emplace(x.second);
1105  }
1106 
1107  parsed_desc->ExpandPrivate(i, keys, out_keys);
1108 
1109  std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1110  std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
1111  import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
1112  }
1113 
1114  for (size_t i = 0; i < priv_keys.size(); ++i) {
1115  const auto& str = priv_keys[i].get_str();
1116  CKey key = DecodeSecret(str);
1117  if (!key.IsValid()) {
1118  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
1119  }
1120  CPubKey pubkey = key.GetPubKey();
1121  CKeyID id = pubkey.GetID();
1122 
1123  // Check if this private key corresponds to a public key from the descriptor
1124  if (!pubkey_map.count(id)) {
1125  warnings.push_back("Ignoring irrelevant private key.");
1126  } else {
1127  privkey_map.emplace(id, key);
1128  }
1129  }
1130 
1131  // Check if all the public keys have corresponding private keys in the import for spendability.
1132  // This does not take into account threshold multisigs which could be spendable without all keys.
1133  // Thus, threshold multisigs without all keys will be considered not spendable here, even if they are,
1134  // perhaps triggering a false warning message. This is consistent with the current wallet IsMine check.
1135  bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1136  [&](const std::pair<CKeyID, CPubKey>& used_key) {
1137  return privkey_map.count(used_key.first) > 0;
1138  }) && std::all_of(import_data.key_origins.begin(), import_data.key_origins.end(),
1139  [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1140  return privkey_map.count(entry.first) > 0;
1141  });
1142  if (!watch_only && !spendable) {
1143  warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1144  }
1145  if (watch_only && spendable) {
1146  warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1147  }
1148 
1149  return warnings;
1150 }
1151 
1152 static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1153 {
1154  UniValue warnings(UniValue::VARR);
1155  UniValue result(UniValue::VOBJ);
1156 
1157  try {
1158  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
1159  // Internal addresses should not have a label
1160  if (internal && data.exists("label")) {
1161  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
1162  }
1163  const std::string& label = data.exists("label") ? data["label"].get_str() : "";
1164  const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false;
1165 
1166  // Add to keypool only works with privkeys disabled
1167  if (add_keypool && !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1168  throw JSONRPCError(RPC_INVALID_PARAMETER, "Keys can only be imported to the keypool when private keys are disabled");
1169  }
1170 
1171  ImportData import_data;
1172  std::map<CKeyID, CPubKey> pubkey_map;
1173  std::map<CKeyID, CKey> privkey_map;
1174  std::set<CScript> script_pub_keys;
1175  std::vector<CKeyID> ordered_pubkeys;
1176  bool have_solving_data;
1177 
1178  if (data.exists("scriptPubKey") && data.exists("desc")) {
1179  throw JSONRPCError(RPC_INVALID_PARAMETER, "Both a descriptor and a scriptPubKey should not be provided.");
1180  } else if (data.exists("scriptPubKey")) {
1181  warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1182  } else if (data.exists("desc")) {
1183  warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1184  } else {
1185  throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a descriptor or scriptPubKey must be provided.");
1186  }
1187 
1188  // If private keys are disabled, abort if private keys are being imported
1189  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) {
1190  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
1191  }
1192 
1193  // Check whether we have any work to do
1194  for (const CScript& script : script_pub_keys) {
1195  if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1196  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script) + "\")");
1197  }
1198  }
1199 
1200  // All good, time to import
1201  pwallet->MarkDirty();
1202  if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1203  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
1204  }
1205  if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1206  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1207  }
1208  if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
1209  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
1210  }
1211  if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
1212  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
1213  }
1214 
1215  result.pushKV("success", UniValue(true));
1216  } catch (const UniValue& e) {
1217  result.pushKV("success", UniValue(false));
1218  result.pushKV("error", e);
1219  } catch (...) {
1220  result.pushKV("success", UniValue(false));
1221 
1222  result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1223  }
1224  if (warnings.size()) result.pushKV("warnings", warnings);
1225  return result;
1226 }
1227 
1228 static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
1229 {
1230  if (data.exists("timestamp")) {
1231  const UniValue& timestamp = data["timestamp"];
1232  if (timestamp.isNum()) {
1233  return timestamp.get_int64();
1234  } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1235  return now;
1236  }
1237  throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
1238  }
1239  throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
1240 }
1241 
1243 {
1244  RPCHelpMan{"importmulti",
1245  "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n"
1246  "If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
1247  "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
1248  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
1249  "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
1250  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1251  {
1252  {"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
1253  {
1255  {
1256  {"desc", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Descriptor to import. If using descriptor, do not also provide address/scriptPubKey, scripts, or pubkeys"},
1257  {"scriptPubKey", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of scriptPubKey (string for script, json for address). Should not be provided if using a descriptor",
1258  /* oneline_description */ "", {"\"<script>\" | { \"address\":\"<address>\" }", "string / json"}
1259  },
1260  {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Creation time of the key expressed in " + UNIX_EPOCH_TIME + ",\n"
1261  " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
1262  " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
1263  " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
1264  " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
1265  " creation time of all keys being imported by the importmulti call will be scanned.",
1266  /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"}
1267  },
1268  {"redeemscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
1269  {"witnessscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
1270  {"pubkeys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving pubkeys to import. They must occur in P2PKH or P2WPKH scripts. They are not required when the private key is also provided (see the \"keys\" argument).",
1271  {
1273  }
1274  },
1275  {"keys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.",
1276  {
1278  }
1279  },
1280  {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"},
1281  {"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
1282  {"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watchonly."},
1283  {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
1284  {"keypool", RPCArg::Type::BOOL, /* default */ "false", "Stating whether imported public keys should be added to the keypool for when users request new addresses. Only allowed when wallet private keys are disabled"},
1285  },
1286  },
1287  },
1288  "\"requests\""},
1290  {
1291  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Stating if should rescan the blockchain after all imports"},
1292  },
1293  "\"options\""},
1294  },
1295  RPCResult{
1296  RPCResult::Type::ARR, "", "Response is an array with the same size as the input that has the execution result",
1297  {
1298  {RPCResult::Type::OBJ, "", "",
1299  {
1300  {RPCResult::Type::BOOL, "success", ""},
1301  {RPCResult::Type::ARR, "warnings", /* optional */ true, "",
1302  {
1303  {RPCResult::Type::STR, "", ""},
1304  }},
1305  {RPCResult::Type::OBJ, "error", /* optional */ true, "",
1306  {
1307  {RPCResult::Type::ELISION, "", "JSONRPC error"},
1308  }},
1309  }},
1310  }
1311  },
1312  RPCExamples{
1313  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1314  "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1315  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1316  },
1317  }.Check(mainRequest);
1318 
1319  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
1320  if (!wallet) return NullUniValue;
1321  CWallet* const pwallet = wallet.get();
1322 
1323  RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1324 
1325  EnsureLegacyScriptPubKeyMan(*wallet, true);
1326 
1327  const UniValue& requests = mainRequest.params[0];
1328 
1329  //Default options
1330  bool fRescan = true;
1331 
1332  if (!mainRequest.params[1].isNull()) {
1333  const UniValue& options = mainRequest.params[1];
1334 
1335  if (options.exists("rescan")) {
1336  fRescan = options["rescan"].get_bool();
1337  }
1338  }
1339 
1340  WalletRescanReserver reserver(*pwallet);
1341  if (fRescan && !reserver.reserve()) {
1342  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1343  }
1344 
1345  int64_t now = 0;
1346  bool fRunScan = false;
1347  int64_t nLowestTimestamp = 0;
1348  UniValue response(UniValue::VARR);
1349  {
1350  LOCK(pwallet->cs_wallet);
1351  EnsureWalletIsUnlocked(pwallet);
1352 
1353  // Verify all timestamps are present before importing any keys.
1354  CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(), FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1355  for (const UniValue& data : requests.getValues()) {
1356  GetImportTimestamp(data, now);
1357  }
1358 
1359  const int64_t minimumTimestamp = 1;
1360 
1361  for (const UniValue& data : requests.getValues()) {
1362  const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
1363  const UniValue result = ProcessImport(pwallet, data, timestamp);
1364  response.push_back(result);
1365 
1366  if (!fRescan) {
1367  continue;
1368  }
1369 
1370  // If at least one request was successful then allow rescan.
1371  if (result["success"].get_bool()) {
1372  fRunScan = true;
1373  }
1374 
1375  // Get the lowest timestamp.
1376  if (timestamp < nLowestTimestamp) {
1377  nLowestTimestamp = timestamp;
1378  }
1379  }
1380  }
1381  if (fRescan && fRunScan && requests.size()) {
1382  int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
1383  {
1384  LOCK(pwallet->cs_wallet);
1385  pwallet->ReacceptWalletTransactions();
1386  }
1387 
1388  if (pwallet->IsAbortingRescan()) {
1389  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
1390  }
1391  if (scannedTime > nLowestTimestamp) {
1392  std::vector<UniValue> results = response.getValues();
1393  response.clear();
1394  response.setArray();
1395  size_t i = 0;
1396  for (const UniValue& request : requests.getValues()) {
1397  // If key creation date is within the successfully scanned
1398  // range, or if the import result already has an error set, let
1399  // the result stand unmodified. Otherwise replace the result
1400  // with an error message.
1401  if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
1402  response.push_back(results.at(i));
1403  } else {
1404  UniValue result = UniValue(UniValue::VOBJ);
1405  result.pushKV("success", UniValue(false));
1406  result.pushKV(
1407  "error",
1408  JSONRPCError(
1410  strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a "
1411  "block from time %d, which is after or within %d seconds of key creation, and "
1412  "could contain transactions pertaining to the key. As a result, transactions "
1413  "and coins using this key may not appear in the wallet. This error could be "
1414  "caused by pruning or data corruption (see bitcoind log for details) and could "
1415  "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1416  "and -rescan options).",
1417  GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
1418  response.push_back(std::move(result));
1419  }
1420  ++i;
1421  }
1422  }
1423  }
1424 
1425  return response;
1426 }
1427 
1428 static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1429 {
1430  UniValue warnings(UniValue::VARR);
1431  UniValue result(UniValue::VOBJ);
1432 
1433  try {
1434  if (!data.exists("desc")) {
1435  throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor not found.");
1436  }
1437 
1438  const std::string& descriptor = data["desc"].get_str();
1439  const bool active = data.exists("active") ? data["active"].get_bool() : false;
1440  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
1441  const std::string& label = data.exists("label") ? data["label"].get_str() : "";
1442 
1443  // Parse descriptor string
1444  FlatSigningProvider keys;
1445  std::string error;
1446  auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true);
1447  if (!parsed_desc) {
1449  }
1450 
1451  // Range check
1452  int64_t range_start = 0, range_end = 1, next_index = 0;
1453  if (!parsed_desc->IsRange() && data.exists("range")) {
1454  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
1455  } else if (parsed_desc->IsRange()) {
1456  if (data.exists("range")) {
1457  auto range = ParseDescriptorRange(data["range"]);
1458  range_start = range.first;
1459  range_end = range.second + 1; // Specified range end is inclusive, but we need range end as exclusive
1460  } else {
1461  warnings.push_back("Range not given, using default keypool range");
1462  range_start = 0;
1463  range_end = gArgs.GetArg("-keypool", DEFAULT_KEYPOOL_SIZE);
1464  }
1465  next_index = range_start;
1466 
1467  if (data.exists("next_index")) {
1468  next_index = data["next_index"].get_int64();
1469  // bound checks
1470  if (next_index < range_start || next_index >= range_end) {
1471  throw JSONRPCError(RPC_INVALID_PARAMETER, "next_index is out of range");
1472  }
1473  }
1474  }
1475 
1476  // Active descriptors must be ranged
1477  if (active && !parsed_desc->IsRange()) {
1478  throw JSONRPCError(RPC_INVALID_PARAMETER, "Active descriptors must be ranged");
1479  }
1480 
1481  // Ranged descriptors should not have a label
1482  if (data.exists("range") && data.exists("label")) {
1483  throw JSONRPCError(RPC_INVALID_PARAMETER, "Ranged descriptors should not have a label");
1484  }
1485 
1486  // Internal addresses should not have a label either
1487  if (internal && data.exists("label")) {
1488  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
1489  }
1490 
1491  // Combo descriptor check
1492  if (active && !parsed_desc->IsSingleType()) {
1493  throw JSONRPCError(RPC_WALLET_ERROR, "Combo descriptors cannot be set to active");
1494  }
1495 
1496  // If the wallet disabled private keys, abort if private keys exist
1497  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !keys.keys.empty()) {
1498  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
1499  }
1500 
1501  // Need to ExpandPrivate to check if private keys are available for all pubkeys
1502  FlatSigningProvider expand_keys;
1503  std::vector<CScript> scripts;
1504  parsed_desc->Expand(0, keys, scripts, expand_keys);
1505  parsed_desc->ExpandPrivate(0, keys, expand_keys);
1506 
1507  // Check if all private keys are provided
1508  bool have_all_privkeys = !expand_keys.keys.empty();
1509  for (const auto& entry : expand_keys.origins) {
1510  const CKeyID& key_id = entry.first;
1511  CKey key;
1512  if (!expand_keys.GetKey(key_id, key)) {
1513  have_all_privkeys = false;
1514  break;
1515  }
1516  }
1517 
1518  // If private keys are enabled, check some things.
1519  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1520  if (keys.keys.empty()) {
1521  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import descriptor without private keys to a wallet with private keys enabled");
1522  }
1523  if (!have_all_privkeys) {
1524  warnings.push_back("Not all private keys provided. Some wallet functionality may return unexpected errors");
1525  }
1526  }
1527 
1528  WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
1529 
1530  // Check if the wallet already contains the descriptor
1531  auto existing_spk_manager = pwallet->GetDescriptorScriptPubKeyMan(w_desc);
1532  if (existing_spk_manager) {
1533  LOCK(existing_spk_manager->cs_desc_man);
1534  if (range_start > existing_spk_manager->GetWalletDescriptor().range_start) {
1535  throw JSONRPCError(RPC_INVALID_PARAMS, strprintf("range_start can only decrease; current range = [%d,%d]", existing_spk_manager->GetWalletDescriptor().range_start, existing_spk_manager->GetWalletDescriptor().range_end));
1536  }
1537  }
1538 
1539  // Add descriptor to the wallet
1540  auto spk_manager = pwallet->AddWalletDescriptor(w_desc, keys, label);
1541  if (spk_manager == nullptr) {
1542  throw JSONRPCError(RPC_WALLET_ERROR, strprintf("Could not add descriptor '%s'", descriptor));
1543  }
1544 
1545  // Set descriptor as active if necessary
1546  if (active) {
1547  if (!w_desc.descriptor->GetOutputType()) {
1548  warnings.push_back("Unknown output type, cannot set descriptor to active.");
1549  } else {
1550  pwallet->SetActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal);
1551  }
1552  }
1553 
1554  result.pushKV("success", UniValue(true));
1555  } catch (const UniValue& e) {
1556  result.pushKV("success", UniValue(false));
1557  result.pushKV("error", e);
1558  } catch (...) {
1559  result.pushKV("success", UniValue(false));
1560 
1561  result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1562  }
1563  if (warnings.size()) result.pushKV("warnings", warnings);
1564  return result;
1565 }
1566 
1568 {
1569  RPCHelpMan{"importdescriptors",
1570  "\nImport descriptors. This will trigger a rescan of the blockchain based on the earliest timestamp of all descriptors being imported. Requires a new wallet backup.\n"
1571  "\nNote: This call can take over an hour to complete if using an early timestamp; during that time, other rpc calls\n"
1572  "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n",
1573  {
1574  {"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
1575  {
1577  {
1578  {"desc", RPCArg::Type::STR, RPCArg::Optional::NO, "Descriptor to import."},
1579  {"active", RPCArg::Type::BOOL, /* default */ "false", "Set this descriptor to be the active descriptor for the corresponding output type/externality"},
1580  {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"},
1581  {"next_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "If a ranged descriptor is set to active, this specifies the next index to generate addresses from"},
1582  {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Time from which to start rescanning the blockchain for this descriptor, in " + UNIX_EPOCH_TIME + "\n"
1583  " Use the string \"now\" to substitute the current synced blockchain time.\n"
1584  " \"now\" can be specified to bypass scanning, for outputs which are known to never have been used, and\n"
1585  " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest timestamp\n"
1586  " of all descriptors being imported will be scanned.",
1587  /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"}
1588  },
1589  {"internal", RPCArg::Type::BOOL, /* default */ "false", "Whether matching outputs should be treated as not incoming payments (e.g. change)"},
1590  {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
1591  },
1592  },
1593  },
1594  "\"requests\""},
1595  },
1596  RPCResult{
1597  RPCResult::Type::ARR, "", "Response is an array with the same size as the input that has the execution result",
1598  {
1599  {RPCResult::Type::OBJ, "", "",
1600  {
1601  {RPCResult::Type::BOOL, "success", ""},
1602  {RPCResult::Type::ARR, "warnings", /* optional */ true, "",
1603  {
1604  {RPCResult::Type::STR, "", ""},
1605  }},
1606  {RPCResult::Type::OBJ, "error", /* optional */ true, "",
1607  {
1608  {RPCResult::Type::ELISION, "", "JSONRPC error"},
1609  }},
1610  }},
1611  }
1612  },
1613  RPCExamples{
1614  HelpExampleCli("importdescriptors", "'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"internal\": true }, "
1615  "{ \"desc\": \"<my desccriptor 2>\", \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1616  HelpExampleCli("importdescriptors", "'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, \"active\": true, \"range\": [0,100], \"label\": \"<my bech32 wallet>\" }]'")
1617  },
1618  }.Check(main_request);
1619 
1620  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(main_request);
1621  if (!wallet) return NullUniValue;
1622  CWallet* const pwallet = wallet.get();
1623 
1624  // Make sure wallet is a descriptor wallet
1625  if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
1626  throw JSONRPCError(RPC_WALLET_ERROR, "importdescriptors is not available for non-descriptor wallets");
1627  }
1628 
1629  RPCTypeCheck(main_request.params, {UniValue::VARR, UniValue::VOBJ});
1630 
1631  WalletRescanReserver reserver(*pwallet);
1632  if (!reserver.reserve()) {
1633  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1634  }
1635 
1636  const UniValue& requests = main_request.params[0];
1637  const int64_t minimum_timestamp = 1;
1638  int64_t now = 0;
1639  int64_t lowest_timestamp = 0;
1640  bool rescan = false;
1641  UniValue response(UniValue::VARR);
1642  {
1643  LOCK(pwallet->cs_wallet);
1644  EnsureWalletIsUnlocked(pwallet);
1645 
1646  CHECK_NONFATAL(pwallet->chain().findBlock(pwallet->GetLastBlockHash(), FoundBlock().time(lowest_timestamp).mtpTime(now)));
1647 
1648  // Get all timestamps and extract the lowest timestamp
1649  for (const UniValue& request : requests.getValues()) {
1650  // This throws an error if "timestamp" doesn't exist
1651  const int64_t timestamp = std::max(GetImportTimestamp(request, now), minimum_timestamp);
1652  const UniValue result = ProcessDescriptorImport(pwallet, request, timestamp);
1653  response.push_back(result);
1654 
1655  if (lowest_timestamp > timestamp ) {
1656  lowest_timestamp = timestamp;
1657  }
1658 
1659  // If we know the chain tip, and at least one request was successful then allow rescan
1660  if (!rescan && result["success"].get_bool()) {
1661  rescan = true;
1662  }
1663  }
1665  }
1666 
1667  // Rescan the blockchain using the lowest timestamp
1668  if (rescan) {
1669  int64_t scanned_time = pwallet->RescanFromTime(lowest_timestamp, reserver, true /* update */);
1670  {
1671  LOCK(pwallet->cs_wallet);
1672  pwallet->ReacceptWalletTransactions();
1673  }
1674 
1675  if (pwallet->IsAbortingRescan()) {
1676  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
1677  }
1678 
1679  if (scanned_time > lowest_timestamp) {
1680  std::vector<UniValue> results = response.getValues();
1681  response.clear();
1682  response.setArray();
1683 
1684  // Compose the response
1685  for (unsigned int i = 0; i < requests.size(); ++i) {
1686  const UniValue& request = requests.getValues().at(i);
1687 
1688  // If the descriptor timestamp is within the successfully scanned
1689  // range, or if the import result already has an error set, let
1690  // the result stand unmodified. Otherwise replace the result
1691  // with an error message.
1692  if (scanned_time <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
1693  response.push_back(results.at(i));
1694  } else {
1695  UniValue result = UniValue(UniValue::VOBJ);
1696  result.pushKV("success", UniValue(false));
1697  result.pushKV(
1698  "error",
1699  JSONRPCError(
1701  strprintf("Rescan failed for descriptor with timestamp %d. There was an error reading a "
1702  "block from time %d, which is after or within %d seconds of key creation, and "
1703  "could contain transactions pertaining to the desc. As a result, transactions "
1704  "and coins using this desc may not appear in the wallet. This error could be "
1705  "caused by pruning or data corruption (see bitcoind log for details) and could "
1706  "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1707  "and -rescan options).",
1708  GetImportTimestamp(request, now), scanned_time - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
1709  response.push_back(std::move(result));
1710  }
1711  }
1712  }
1713  }
1714 
1715  return response;
1716 }
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:387
static std::string EncodeDumpString(const std::string &str)
Definition: rpcdump.cpp:33
std::unique_ptr< CScript > witnessscript
Provided witnessScript; will be moved to import_scripts if relevant.
Definition: rpcdump.cpp:838
Top-level scriptPubKey.
Helper for findBlock to selectively return pieces of block data.
Definition: chain.h:37
UniValue abortrescan(const JSONRPCRequest &request)
Definition: rpcdump.cpp:194
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
Definition: wallet.cpp:1420
const CHDChain & GetHDChain() const
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:23
const std::vector< UniValue > & getValues() const
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:174
static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: rpcdump.cpp:1152
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
std::shared_ptr< Descriptor > descriptor
Definition: walletutil.h:94
bool get_bool() const
UniValue dumpprivkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:654
Required arg.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
RecursiveMutex cs_KeyStore
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:232
UniValue importmulti(const JSONRPCRequest &mainRequest)
Definition: rpcdump.cpp:1242
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:184
std::map< CKeyID, CKey > keys
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:102
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1773
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: rpcwallet.cpp:135
const std::string UNIX_EPOCH_TIME
String used to describe UNIX epoch time in documentation, factored out to a constant for consistency...
Definition: util.cpp:20
Definition: key.h:144
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
Definition: check.h:32
std::vector< unsigned char > ParseHex(const char *psz)
fs::ifstream ifstream
Definition: fs.h:90
void EnsureWalletIsUnlocked(const CWallet *pwallet)
Definition: rpcwallet.cpp:119
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:388
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:328
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:1195
UniValue dumpwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:699
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:78
const std::string & get_str() const
enum VType getType() const
Definition: univalue.h:64
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:82
const UniValue & get_array() const
bool isStr() const
Definition: univalue.h:81
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:201
int64_t get_int64() const
fs::ofstream ofstream
Definition: fs.h:91
isminetype IsMine(const CTxDestination &dest) const
Definition: wallet.cpp:1244
const unsigned char * begin() const
Definition: key.h:89
unsigned char * begin()
Definition: uint256.h:54
int64_t ParseISO8601DateTime(const std::string &str)
Definition: time.cpp:104
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
Definition: wallet.h:1231
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:30
unspendable OP_RETURN script that carries data
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:158
bool IsNull() const
Definition: uint256.h:30
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1483
static bool GetWalletAddressesForKey(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:59
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
Definition: outputtype.cpp:68
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3119
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:794
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:3185
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:855
void MarkDirty()
Definition: wallet.cpp:704
Special type that is a STR with only hex chars.
#define LOCK2(cs1, cs2)
Definition: sync.h:227
const char * uvTypeName(UniValue::VType t)
Definition: univalue.cpp:219
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:124
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:51
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
Definition: rpcdump.cpp:843
static UniValue ProcessImportLegacy(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:922
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:1192
UniValue params
Definition: request.h:36
std::map< CScriptID, CScript > scripts
P2WSH witnessScript.
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:1066
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3537
#define LOCK(cs)
Definition: sync.h:226
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
bool exists(const std::string &key) const
Definition: univalue.h:75
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:57
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:842
TxoutType
Definition: standard.h:119
static const int64_t TIMESTAMP_MIN
Definition: rpcdump.cpp:81
UniValue removeprunedfunds(const JSONRPCRequest &request)
Definition: rpcdump.cpp:376
An encapsulated public key.
Definition: pubkey.h:30
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:138
bool IsHex(const std::string &str)
std::map< CKeyID, CPubKey > pubkeys
static std::string DecodeDumpString(const std::string &str)
Definition: rpcdump.cpp:45
Unexpected type was passed as parameter.
Definition: protocol.h:40
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
uint256 GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.h:1237
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1493
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:1513
General application defined errors.
Definition: protocol.h:39
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:88
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
Definition: rpcdump.cpp:83
std::string ToString() const
Definition: uint256.cpp:60
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:1503
Invalid address or key.
Definition: protocol.h:41
unsigned int size() const
Definition: uint256.h:74
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true)
Definition: wallet.cpp:797
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:295
Descriptor with some wallet metadata.
Definition: walletutil.h:91
std::set< CScript > import_scripts
Definition: rpcdump.cpp:841
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:96
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
Definition: wallet.cpp:4378
bool isNull() const
Definition: univalue.h:77
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
Definition: key.cpp:301
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:1281
CRIPEMD160 & Write(const unsigned char *data, size_t len)
Definition: ripemd160.cpp:247
static UniValue ProcessDescriptorImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: rpcdump.cpp:1428
P2SH redeemScript.
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
Definition: rpcdump.cpp:837
Special type that is a NUM or [NUM,NUM].
256-bit opaque blob.
Definition: uint256.h:120
Optional argument with default value omitted because they are implicitly clear.
CTxDestination DecodeDestination(const std::string &str)
Definition: key_io.cpp:215
enum VType type() const
Definition: univalue.h:177
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:53
bool GetKey(const CKeyID &keyid, CKey &key) const override
bool setArray()
Definition: univalue.cpp:94
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:62
virtual bool findAncestorByHash(const uint256 &block_hash, const uint256 &ancestor_hash, const FoundBlock &ancestor_out={})=0
Return whether block descends from a specified ancestor, and optionally return ancestor information...
UniValue importdescriptors(const JSONRPCRequest &main_request)
Definition: rpcdump.cpp:1567
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:390
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:380
UniValue importpubkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:413
ScriptContext
Definition: rpcdump.cpp:846
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:20
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:109
Only for Witness versions not already defined above.
std::string HexStr(const T itbegin, const T itend)
Definition: strencodings.h:123
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:618
ArgsManager gArgs
Definition: system.cpp:77
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:1185
160-bit opaque blob.
Definition: uint256.h:109
const UniValue NullUniValue
Definition: univalue.cpp:13
UniValue importprivkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:93
void AbortRescan()
Definition: wallet.h:842
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:49
std::pair< int64_t, int64_t > ParseDescriptorRange(const UniValue &value)
Parse a JSON range specified as int64, or [int64, int64].
Definition: util.cpp:806
UniValue importwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:498
virtual void showProgress(const std::string &title, int progress, bool resume_possible)=0
Send progress indicator.
RecursiveMutex cs_wallet
Definition: wallet.h:727
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:85
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:133
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:210
bool IsScanning() const
Definition: wallet.h:844
UniValue importaddress(const JSONRPCRequest &request)
Definition: rpcdump.cpp:220
A mutable version of CTransaction.
Definition: transaction.h:345
Wallet errors.
Definition: protocol.h:70
void clear()
Definition: univalue.cpp:15
FoundBlock & height(int &height)
Definition: chain.h:41
size_t size() const
Definition: univalue.h:68
An encapsulated private key.
Definition: key.h:27
FoundBlock & mtpTime(int64_t &mtp_time)
Definition: chain.h:44
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:89
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: rpcdump.cpp:1228
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:132
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1634
boost::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:209
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:61
CKeyID seed_id
seed hash160
Definition: walletdb.h:94
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:23
auto it
Definition: validation.cpp:384
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:150
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:4064
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
const std::string CLIENT_BUILD
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:199
UniValue importprunedfunds(const JSONRPCRequest &request)
Definition: rpcdump.cpp:320
FoundBlock & time(int64_t &time)
Definition: chain.h:42
virtual bool havePruned()=0
Check if any block has been pruned.
Error parsing or validating structure in raw format.
Definition: protocol.h:45
A hasher class for RIPEMD-160.
Definition: ripemd160.h:12
Special type to denote elision (...)
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:93
bool IsAbortingRescan() const
Definition: wallet.h:843
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:183
NODISCARD bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Definition: core_read.cpp:120