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