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