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