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