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