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