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