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