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