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