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