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