Bitcoin Core  0.19.99
P2P Digital Currency
rpcdump.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2019 The Bitcoin Core developers
2 // Distributed under the MIT software license, see the accompanying
3 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4 
5 #include <chain.h>
6 #include <core_io.h>
7 #include <interfaces/chain.h>
8 #include <key_io.h>
9 #include <merkleblock.h>
10 #include <rpc/util.h>
11 #include <script/descriptor.h>
12 #include <script/script.h>
13 #include <script/standard.h>
14 #include <sync.h>
15 #include <util/bip32.h>
16 #include <util/system.h>
17 #include <util/time.h>
18 #include <util/translation.h>
19 #include <wallet/rpcwallet.h>
20 #include <wallet/wallet.h>
21 
22 #include <stdint.h>
23 #include <tuple>
24 
25 #include <boost/algorithm/string.hpp>
26 
27 #include <univalue.h>
28 
29 
30 
31 std::string static EncodeDumpString(const std::string &str) {
32  std::stringstream ret;
33  for (const unsigned char c : str) {
34  if (c <= 32 || c >= 128 || c == '%') {
35  ret << '%' << HexStr(&c, &c + 1);
36  } else {
37  ret << c;
38  }
39  }
40  return ret.str();
41 }
42 
43 static std::string DecodeDumpString(const std::string &str) {
44  std::stringstream ret;
45  for (unsigned int pos = 0; pos < str.length(); pos++) {
46  unsigned char c = str[pos];
47  if (c == '%' && pos+2 < str.length()) {
48  c = (((str[pos+1]>>6)*9+((str[pos+1]-'0')&15)) << 4) |
49  ((str[pos+2]>>6)*9+((str[pos+2]-'0')&15));
50  pos += 2;
51  }
52  ret << c;
53  }
54  return ret.str();
55 }
56 
57 static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan* spk_man, const CWallet* const pwallet, const CKeyID& keyid, std::string& strAddr, std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
58 {
59  bool fLabelFound = false;
60  CKey key;
61  spk_man->GetKey(keyid, key);
62  for (const auto& dest : GetAllDestinationsForKey(key.GetPubKey())) {
63  if (pwallet->mapAddressBook.count(dest)) {
64  if (!strAddr.empty()) {
65  strAddr += ",";
66  }
67  strAddr += EncodeDestination(dest);
68  strLabel = EncodeDumpString(pwallet->mapAddressBook.at(dest).name);
69  fLabelFound = true;
70  }
71  }
72  if (!fLabelFound) {
73  strAddr = EncodeDestination(GetDestinationForKey(key.GetPubKey(), pwallet->m_default_address_type));
74  }
75  return fLabelFound;
76 }
77 
78 static const int64_t TIMESTAMP_MIN = 0;
79 
80 static void RescanWallet(CWallet& wallet, const WalletRescanReserver& reserver, int64_t time_begin = TIMESTAMP_MIN, bool update = true)
81 {
82  int64_t scanned_time = wallet.RescanFromTime(time_begin, reserver, update);
83  if (wallet.IsAbortingRescan()) {
84  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
85  } else if (scanned_time > time_begin) {
86  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan was unable to fully rescan the blockchain. Some transactions may be missing.");
87  }
88 }
89 
91 {
92  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
93  CWallet* const pwallet = wallet.get();
94  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
95  return NullUniValue;
96  }
97 
98  RPCHelpMan{"importprivkey",
99  "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n"
100  "Hint: use importmulti to import more than one private key.\n"
101  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
102  "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"
103  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
104  {
105  {"privkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The private key (see dumpprivkey)"},
106  {"label", RPCArg::Type::STR, /* default */ "current label if address exists, otherwise \"\"", "An optional label"},
107  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
108  },
110  RPCExamples{
111  "\nDump a private key\n"
112  + HelpExampleCli("dumpprivkey", "\"myaddress\"") +
113  "\nImport the private key with rescan\n"
114  + HelpExampleCli("importprivkey", "\"mykey\"") +
115  "\nImport using a label and without rescan\n"
116  + HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
117  "\nImport using default blank label and without rescan\n"
118  + HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
119  "\nAs a JSON-RPC call\n"
120  + HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")
121  },
122  }.Check(request);
123 
125  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
126  }
127 
128  EnsureLegacyScriptPubKeyMan(*wallet, true);
129 
130  WalletRescanReserver reserver(pwallet);
131  bool fRescan = true;
132  {
133  auto locked_chain = pwallet->chain().lock();
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->mapAddressBook.count(dest) == 0) {
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 
195 {
196  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
197  CWallet* const pwallet = wallet.get();
198  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
199  return NullUniValue;
200  }
201 
202  RPCHelpMan{"abortrescan",
203  "\nStops current wallet rescan triggered by an RPC call, e.g. by an importprivkey call.\n"
204  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
205  {},
206  RPCResult{RPCResult::Type::BOOL, "", "Whether the abort was successful"},
207  RPCExamples{
208  "\nImport a private key\n"
209  + HelpExampleCli("importprivkey", "\"mykey\"") +
210  "\nAbort the running wallet rescan\n"
211  + HelpExampleCli("abortrescan", "") +
212  "\nAs a JSON-RPC call\n"
213  + HelpExampleRpc("abortrescan", "")
214  },
215  }.Check(request);
216 
217  if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
218  pwallet->AbortRescan();
219  return true;
220 }
221 
223 {
224  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
225  CWallet* const pwallet = wallet.get();
226  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
227  return NullUniValue;
228  }
229 
230  RPCHelpMan{"importaddress",
231  "\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"
232  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
233  "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"
234  "If you have the full public key, you should call importpubkey instead of this.\n"
235  "Hint: use importmulti to import more than one address.\n"
236  "\nNote: If you import a non-standard raw script in hex form, outputs sending to it will be treated\n"
237  "as change, and not show up in many RPCs.\n"
238  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
239  {
240  {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The Bitcoin address (or hex-encoded script)"},
241  {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
242  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
243  {"p2sh", RPCArg::Type::BOOL, /* default */ "false", "Add the P2SH version of the script as well"},
244  },
246  RPCExamples{
247  "\nImport an address with rescan\n"
248  + HelpExampleCli("importaddress", "\"myaddress\"") +
249  "\nImport using a label without rescan\n"
250  + HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") +
251  "\nAs a JSON-RPC call\n"
252  + HelpExampleRpc("importaddress", "\"myaddress\", \"testing\", false")
253  },
254  }.Check(request);
255 
256  EnsureLegacyScriptPubKeyMan(*pwallet, true);
257 
258  std::string strLabel;
259  if (!request.params[1].isNull())
260  strLabel = request.params[1].get_str();
261 
262  // Whether to perform rescan after import
263  bool fRescan = true;
264  if (!request.params[2].isNull())
265  fRescan = request.params[2].get_bool();
266 
267  if (fRescan && pwallet->chain().havePruned()) {
268  // Exit early and print an error.
269  // If a block is pruned after this check, we will import the key(s),
270  // but fail the rescan with a generic error.
271  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
272  }
273 
274  WalletRescanReserver reserver(pwallet);
275  if (fRescan && !reserver.reserve()) {
276  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
277  }
278 
279  // Whether to import a p2sh version, too
280  bool fP2SH = false;
281  if (!request.params[3].isNull())
282  fP2SH = request.params[3].get_bool();
283 
284  {
285  auto locked_chain = pwallet->chain().lock();
286  LOCK(pwallet->cs_wallet);
287 
288  CTxDestination dest = DecodeDestination(request.params[0].get_str());
289  if (IsValidDestination(dest)) {
290  if (fP2SH) {
291  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
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(CScriptID(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  auto locked_chain = pwallet->chain().lock();
318  LOCK(pwallet->cs_wallet);
319  pwallet->ReacceptWalletTransactions();
320  }
321  }
322 
323  return NullUniValue;
324 }
325 
327 {
328  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
329  CWallet* const pwallet = wallet.get();
330  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
331  return NullUniValue;
332  }
333 
334  RPCHelpMan{"importprunedfunds",
335  "\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",
336  {
337  {"rawtransaction", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A raw transaction in hex funding an already-existing address in wallet"},
338  {"txoutproof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex output from gettxoutproof that contains the transaction"},
339  },
341  RPCExamples{""},
342  }.Check(request);
343 
345  if (!DecodeHexTx(tx, request.params[0].get_str()))
346  throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
347  uint256 hashTx = tx.GetHash();
348  CWalletTx wtx(pwallet, MakeTransactionRef(std::move(tx)));
349 
350  CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
351  CMerkleBlock merkleBlock;
352  ssMB >> merkleBlock;
353 
354  //Search partial merkle tree in proof for our transaction and index in valid block
355  std::vector<uint256> vMatch;
356  std::vector<unsigned int> vIndex;
357  if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
358  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
359  }
360 
361  auto locked_chain = pwallet->chain().lock();
362  Optional<int> height = locked_chain->getBlockHeight(merkleBlock.header.GetHash());
363  if (height == nullopt) {
364  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
365  }
366 
367  std::vector<uint256>::const_iterator it;
368  if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
369  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
370  }
371 
372  unsigned int txnIndex = vIndex[it - vMatch.begin()];
373 
374  CWalletTx::Confirmation confirm(CWalletTx::Status::CONFIRMED, *height, merkleBlock.header.GetHash(), txnIndex);
375  wtx.m_confirm = confirm;
376 
377  LOCK(pwallet->cs_wallet);
378 
379  if (pwallet->IsMine(*wtx.tx)) {
380  pwallet->AddToWallet(wtx, false);
381  return NullUniValue;
382  }
383 
384  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
385 }
386 
388 {
389  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
390  CWallet* const pwallet = wallet.get();
391  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
392  return NullUniValue;
393  }
394 
395  RPCHelpMan{"removeprunedfunds",
396  "\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",
397  {
398  {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded id of the transaction you are deleting"},
399  },
401  RPCExamples{
402  HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
403  "\nAs a JSON-RPC call\n"
404  + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
405  },
406  }.Check(request);
407 
408  auto locked_chain = pwallet->chain().lock();
409  LOCK(pwallet->cs_wallet);
410 
411  uint256 hash(ParseHashV(request.params[0], "txid"));
412  std::vector<uint256> vHash;
413  vHash.push_back(hash);
414  std::vector<uint256> vHashOut;
415 
416  if (pwallet->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
417  throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction.");
418  }
419 
420  if(vHashOut.empty()) {
421  throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
422  }
423 
424  return NullUniValue;
425 }
426 
428 {
429  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
430  CWallet* const pwallet = wallet.get();
431  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
432  return NullUniValue;
433  }
434 
435  RPCHelpMan{"importpubkey",
436  "\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"
437  "Hint: use importmulti to import more than one public key.\n"
438  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
439  "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"
440  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
441  {
442  {"pubkey", RPCArg::Type::STR, RPCArg::Optional::NO, "The hex-encoded public key"},
443  {"label", RPCArg::Type::STR, /* default */ "\"\"", "An optional label"},
444  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Rescan the wallet for transactions"},
445  },
447  RPCExamples{
448  "\nImport a public key with rescan\n"
449  + HelpExampleCli("importpubkey", "\"mypubkey\"") +
450  "\nImport using a label without rescan\n"
451  + HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
452  "\nAs a JSON-RPC call\n"
453  + HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
454  },
455  }.Check(request);
456 
457  EnsureLegacyScriptPubKeyMan(*wallet, true);
458 
459  std::string strLabel;
460  if (!request.params[1].isNull())
461  strLabel = request.params[1].get_str();
462 
463  // Whether to perform rescan after import
464  bool fRescan = true;
465  if (!request.params[2].isNull())
466  fRescan = request.params[2].get_bool();
467 
468  if (fRescan && pwallet->chain().havePruned()) {
469  // Exit early and print an error.
470  // If a block is pruned after this check, we will import the key(s),
471  // but fail the rescan with a generic error.
472  throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
473  }
474 
475  WalletRescanReserver reserver(pwallet);
476  if (fRescan && !reserver.reserve()) {
477  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
478  }
479 
480  if (!IsHex(request.params[0].get_str()))
481  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
482  std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
483  CPubKey pubKey(data.begin(), data.end());
484  if (!pubKey.IsFullyValid())
485  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
486 
487  {
488  auto locked_chain = pwallet->chain().lock();
489  LOCK(pwallet->cs_wallet);
490 
491  std::set<CScript> script_pub_keys;
492  for (const auto& dest : GetAllDestinationsForKey(pubKey)) {
493  script_pub_keys.insert(GetScriptForDestination(dest));
494  }
495 
496  pwallet->MarkDirty();
497 
498  pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
499 
500  pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */);
501  }
502  if (fRescan)
503  {
504  RescanWallet(*pwallet, reserver);
505  {
506  auto locked_chain = pwallet->chain().lock();
507  LOCK(pwallet->cs_wallet);
508  pwallet->ReacceptWalletTransactions();
509  }
510  }
511 
512  return NullUniValue;
513 }
514 
515 
517 {
518  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
519  CWallet* const pwallet = wallet.get();
520  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
521  return NullUniValue;
522  }
523 
524  RPCHelpMan{"importwallet",
525  "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup to include imported keys.\n"
526  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
527  {
528  {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet file"},
529  },
531  RPCExamples{
532  "\nDump the wallet\n"
533  + HelpExampleCli("dumpwallet", "\"test\"") +
534  "\nImport the wallet\n"
535  + HelpExampleCli("importwallet", "\"test\"") +
536  "\nImport using the json rpc call\n"
537  + HelpExampleRpc("importwallet", "\"test\"")
538  },
539  }.Check(request);
540 
541  EnsureLegacyScriptPubKeyMan(*wallet, true);
542 
543  if (pwallet->chain().havePruned()) {
544  // Exit early and print an error.
545  // If a block is pruned after this check, we will import the key(s),
546  // but fail the rescan with a generic error.
547  throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned");
548  }
549 
550  WalletRescanReserver reserver(pwallet);
551  if (!reserver.reserve()) {
552  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
553  }
554 
555  int64_t nTimeBegin = 0;
556  bool fGood = true;
557  {
558  auto locked_chain = pwallet->chain().lock();
559  LOCK(pwallet->cs_wallet);
560 
561  EnsureWalletIsUnlocked(pwallet);
562 
563  fsbridge::ifstream file;
564  file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
565  if (!file.is_open()) {
566  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
567  }
568  Optional<int> tip_height = locked_chain->getHeight();
569  nTimeBegin = tip_height ? locked_chain->getBlockTime(*tip_height) : 0;
570 
571  int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
572  file.seekg(0, file.beg);
573 
574  // Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which
575  // we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button.
576  pwallet->chain().showProgress(strprintf("%s " + _("Importing...").translated, pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI
577  std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
578  std::vector<std::pair<CScript, int64_t>> scripts;
579  while (file.good()) {
580  pwallet->chain().showProgress("", std::max(1, std::min(50, (int)(((double)file.tellg() / (double)nFilesize) * 100))), false);
581  std::string line;
582  std::getline(file, line);
583  if (line.empty() || line[0] == '#')
584  continue;
585 
586  std::vector<std::string> vstr;
587  boost::split(vstr, line, boost::is_any_of(" "));
588  if (vstr.size() < 2)
589  continue;
590  CKey key = DecodeSecret(vstr[0]);
591  if (key.IsValid()) {
592  int64_t nTime = ParseISO8601DateTime(vstr[1]);
593  std::string strLabel;
594  bool fLabel = true;
595  for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
596  if (vstr[nStr].front() == '#')
597  break;
598  if (vstr[nStr] == "change=1")
599  fLabel = false;
600  if (vstr[nStr] == "reserve=1")
601  fLabel = false;
602  if (vstr[nStr].substr(0,6) == "label=") {
603  strLabel = DecodeDumpString(vstr[nStr].substr(6));
604  fLabel = true;
605  }
606  }
607  keys.push_back(std::make_tuple(key, nTime, fLabel, strLabel));
608  } else if(IsHex(vstr[0])) {
609  std::vector<unsigned char> vData(ParseHex(vstr[0]));
610  CScript script = CScript(vData.begin(), vData.end());
611  int64_t birth_time = ParseISO8601DateTime(vstr[1]);
612  scripts.push_back(std::pair<CScript, int64_t>(script, birth_time));
613  }
614  }
615  file.close();
616  // We now know whether we are importing private keys, so we can error if private keys are disabled
617  if (keys.size() > 0 && pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
618  pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
619  throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when private keys are disabled");
620  }
621  double total = (double)(keys.size() + scripts.size());
622  double progress = 0;
623  for (const auto& key_tuple : keys) {
624  pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
625  const CKey& key = std::get<0>(key_tuple);
626  int64_t time = std::get<1>(key_tuple);
627  bool has_label = std::get<2>(key_tuple);
628  std::string label = std::get<3>(key_tuple);
629 
630  CPubKey pubkey = key.GetPubKey();
631  CHECK_NONFATAL(key.VerifyPubKey(pubkey));
632  CKeyID keyid = pubkey.GetID();
633 
634  pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid)));
635 
636  if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
637  pwallet->WalletLogPrintf("Error importing key for %s\n", EncodeDestination(PKHash(keyid)));
638  fGood = false;
639  continue;
640  }
641 
642  if (has_label)
643  pwallet->SetAddressBook(PKHash(keyid), label, "receive");
644 
645  nTimeBegin = std::min(nTimeBegin, time);
646  progress++;
647  }
648  for (const auto& script_pair : scripts) {
649  pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false);
650  const CScript& script = script_pair.first;
651  int64_t time = script_pair.second;
652 
653  if (!pwallet->ImportScripts({script}, time)) {
654  pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script));
655  fGood = false;
656  continue;
657  }
658  if (time > 0) {
659  nTimeBegin = std::min(nTimeBegin, time);
660  }
661 
662  progress++;
663  }
664  pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
665  }
666  pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI
667  RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
668  pwallet->MarkDirty();
669 
670  if (!fGood)
671  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys/scripts to wallet");
672 
673  return NullUniValue;
674 }
675 
677 {
678  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
679  const CWallet* const pwallet = wallet.get();
680  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
681  return NullUniValue;
682  }
683 
684  RPCHelpMan{"dumpprivkey",
685  "\nReveals the private key corresponding to 'address'.\n"
686  "Then the importprivkey can be used with this output\n",
687  {
688  {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for the private key"},
689  },
690  RPCResult{
691  RPCResult::Type::STR, "key", "The private key"
692  },
693  RPCExamples{
694  HelpExampleCli("dumpprivkey", "\"myaddress\"")
695  + HelpExampleCli("importprivkey", "\"mykey\"")
696  + HelpExampleRpc("dumpprivkey", "\"myaddress\"")
697  },
698  }.Check(request);
699 
701 
702  auto locked_chain = pwallet->chain().lock();
703  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
704 
705  EnsureWalletIsUnlocked(pwallet);
706 
707  std::string strAddress = request.params[0].get_str();
708  CTxDestination dest = DecodeDestination(strAddress);
709  if (!IsValidDestination(dest)) {
710  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
711  }
712  auto keyid = GetKeyForDestination(spk_man, dest);
713  if (keyid.IsNull()) {
714  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
715  }
716  CKey vchSecret;
717  if (!spk_man.GetKey(keyid, vchSecret)) {
718  throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
719  }
720  return EncodeSecret(vchSecret);
721 }
722 
723 
725 {
726  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
727  const CWallet* const pwallet = wallet.get();
728  if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
729  return NullUniValue;
730  }
731 
732  RPCHelpMan{"dumpwallet",
733  "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
734  "Imported scripts are included in the dumpfile, but corresponding BIP173 addresses, etc. may not be added automatically by importwallet.\n"
735  "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"
736  "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n",
737  {
738  {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The filename with path (either absolute or relative to bitcoind)"},
739  },
740  RPCResult{
741  RPCResult::Type::OBJ, "", "",
742  {
743  {RPCResult::Type::STR, "filename", "The filename with full absolute path"},
744  }
745  },
746  RPCExamples{
747  HelpExampleCli("dumpwallet", "\"test\"")
748  + HelpExampleRpc("dumpwallet", "\"test\"")
749  },
750  }.Check(request);
751 
753 
754  auto locked_chain = pwallet->chain().lock();
755  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
756 
757  EnsureWalletIsUnlocked(pwallet);
758 
759  fs::path filepath = request.params[0].get_str();
760  filepath = fs::absolute(filepath);
761 
762  /* Prevent arbitrary files from being overwritten. There have been reports
763  * that users have overwritten wallet files this way:
764  * https://github.com/bitcoin/bitcoin/issues/9934
765  * It may also avoid other security issues.
766  */
767  if (fs::exists(filepath)) {
768  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");
769  }
770 
771  fsbridge::ofstream file;
772  file.open(filepath);
773  if (!file.is_open())
774  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
775 
776  std::map<CKeyID, int64_t> mapKeyBirth;
777  const std::map<CKeyID, int64_t>& mapKeyPool = spk_man.GetAllReserveKeys();
778  pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth);
779 
780  std::set<CScriptID> scripts = spk_man.GetCScripts();
781 
782  // sort time/key pairs
783  std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
784  for (const auto& entry : mapKeyBirth) {
785  vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
786  }
787  mapKeyBirth.clear();
788  std::sort(vKeyBirth.begin(), vKeyBirth.end());
789 
790  // produce output
791  file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
792  file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
793  const Optional<int> tip_height = locked_chain->getHeight();
794  file << strprintf("# * Best block at time of backup was %i (%s),\n", tip_height.get_value_or(-1), tip_height ? locked_chain->getBlockHash(*tip_height).ToString() : "(missing block hash)");
795  file << strprintf("# mined on %s\n", tip_height ? FormatISO8601DateTime(locked_chain->getBlockTime(*tip_height)) : "(missing block time)");
796  file << "\n";
797 
798  // add the base58check encoded extended master if the wallet uses HD
799  CKeyID seed_id = spk_man.GetHDChain().seed_id;
800  if (!seed_id.IsNull())
801  {
802  CKey seed;
803  if (spk_man.GetKey(seed_id, seed)) {
804  CExtKey masterKey;
805  masterKey.SetSeed(seed.begin(), seed.size());
806 
807  file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n\n";
808  }
809  }
810  for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
811  const CKeyID &keyid = it->second;
812  std::string strTime = FormatISO8601DateTime(it->first);
813  std::string strAddr;
814  std::string strLabel;
815  CKey key;
816  if (spk_man.GetKey(keyid, key)) {
817  file << strprintf("%s %s ", EncodeSecret(key), strTime);
818  if (GetWalletAddressesForKey(&spk_man, pwallet, keyid, strAddr, strLabel)) {
819  file << strprintf("label=%s", strLabel);
820  } else if (keyid == seed_id) {
821  file << "hdseed=1";
822  } else if (mapKeyPool.count(keyid)) {
823  file << "reserve=1";
824  } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
825  file << "inactivehdseed=1";
826  } else {
827  file << "change=1";
828  }
829  file << strprintf(" # addr=%s%s\n", strAddr, (spk_man.mapKeyMetadata[keyid].has_key_origin ? " hdkeypath="+WriteHDKeypath(spk_man.mapKeyMetadata[keyid].key_origin.path) : ""));
830  }
831  }
832  file << "\n";
833  for (const CScriptID &scriptid : scripts) {
834  CScript script;
835  std::string create_time = "0";
836  std::string address = EncodeDestination(ScriptHash(scriptid));
837  // get birth times for scripts with metadata
838  auto it = spk_man.m_script_metadata.find(scriptid);
839  if (it != spk_man.m_script_metadata.end()) {
840  create_time = FormatISO8601DateTime(it->second.nCreateTime);
841  }
842  if(spk_man.GetCScript(scriptid, script)) {
843  file << strprintf("%s %s script=1", HexStr(script.begin(), script.end()), create_time);
844  file << strprintf(" # addr=%s\n", address);
845  }
846  }
847  file << "\n";
848  file << "# End of dump\n";
849  file.close();
850 
851  UniValue reply(UniValue::VOBJ);
852  reply.pushKV("filename", filepath.string());
853 
854  return reply;
855 }
856 
858 {
859  // Input data
860  std::unique_ptr<CScript> redeemscript;
861  std::unique_ptr<CScript> witnessscript;
862 
863  // Output data
864  std::set<CScript> import_scripts;
865  std::map<CKeyID, bool> used_keys;
866  std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
867 };
868 
869 enum class ScriptContext
870 {
871  TOP,
872  P2SH,
873  WITNESS_V0,
874 };
875 
876 // 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.
877 // Returns an error string, or the empty string for success.
878 static std::string RecurseImportData(const CScript& script, ImportData& import_data, const ScriptContext script_ctx)
879 {
880  // Use Solver to obtain script type and parsed pubkeys or hashes:
881  std::vector<std::vector<unsigned char>> solverdata;
882  txnouttype script_type = Solver(script, solverdata);
883 
884  switch (script_type) {
885  case TX_PUBKEY: {
886  CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
887  import_data.used_keys.emplace(pubkey.GetID(), false);
888  return "";
889  }
890  case TX_PUBKEYHASH: {
891  CKeyID id = CKeyID(uint160(solverdata[0]));
892  import_data.used_keys[id] = true;
893  return "";
894  }
895  case TX_SCRIPTHASH: {
896  if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
897  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH");
898  CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
899  CScriptID id = CScriptID(uint160(solverdata[0]));
900  auto subscript = std::move(import_data.redeemscript); // Remove redeemscript from import_data to check for superfluous script later.
901  if (!subscript) return "missing redeemscript";
902  if (CScriptID(*subscript) != id) return "redeemScript does not match the scriptPubKey";
903  import_data.import_scripts.emplace(*subscript);
904  return RecurseImportData(*subscript, import_data, ScriptContext::P2SH);
905  }
906  case TX_MULTISIG: {
907  for (size_t i = 1; i + 1< solverdata.size(); ++i) {
908  CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
909  import_data.used_keys.emplace(pubkey.GetID(), false);
910  }
911  return "";
912  }
914  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
915  uint256 fullid(solverdata[0]);
916  CScriptID id;
917  CRIPEMD160().Write(fullid.begin(), fullid.size()).Finalize(id.begin());
918  auto subscript = std::move(import_data.witnessscript); // Remove redeemscript from import_data to check for superfluous script later.
919  if (!subscript) return "missing witnessscript";
920  if (CScriptID(*subscript) != id) return "witnessScript does not match the scriptPubKey or redeemScript";
921  if (script_ctx == ScriptContext::TOP) {
922  import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WSH requires the TOP script imported (see script/ismine.cpp)
923  }
924  import_data.import_scripts.emplace(*subscript);
925  return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0);
926  }
927  case TX_WITNESS_V0_KEYHASH: {
928  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH");
929  CKeyID id = CKeyID(uint160(solverdata[0]));
930  import_data.used_keys[id] = true;
931  if (script_ctx == ScriptContext::TOP) {
932  import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WPKH requires the TOP script imported (see script/ismine.cpp)
933  }
934  return "";
935  }
936  case TX_NULL_DATA:
937  return "unspendable script";
938  case TX_NONSTANDARD:
939  case TX_WITNESS_UNKNOWN:
940  default:
941  return "unrecognized script";
942  }
943 }
944 
945 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)
946 {
947  UniValue warnings(UniValue::VARR);
948 
949  // First ensure scriptPubKey has either a script or JSON with "address" string
950  const UniValue& scriptPubKey = data["scriptPubKey"];
951  bool isScript = scriptPubKey.getType() == UniValue::VSTR;
952  if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
953  throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");
954  }
955  const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
956 
957  // Optional fields.
958  const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
959  const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
960  const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
961  const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
962  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
963  const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
964 
965  if (data.exists("range")) {
966  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for a non-descriptor import");
967  }
968 
969  // Generate the script and destination for the scriptPubKey provided
970  CScript script;
971  if (!isScript) {
972  CTxDestination dest = DecodeDestination(output);
973  if (!IsValidDestination(dest)) {
974  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
975  }
976  script = GetScriptForDestination(dest);
977  } else {
978  if (!IsHex(output)) {
979  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\"");
980  }
981  std::vector<unsigned char> vData(ParseHex(output));
982  script = CScript(vData.begin(), vData.end());
983  CTxDestination dest;
984  if (!ExtractDestination(script, dest) && !internal) {
985  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
986  }
987  }
988  script_pub_keys.emplace(script);
989 
990  // Parse all arguments
991  if (strRedeemScript.size()) {
992  if (!IsHex(strRedeemScript)) {
993  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
994  }
995  auto parsed_redeemscript = ParseHex(strRedeemScript);
996  import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
997  }
998  if (witness_script_hex.size()) {
999  if (!IsHex(witness_script_hex)) {
1000  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
1001  }
1002  auto parsed_witnessscript = ParseHex(witness_script_hex);
1003  import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
1004  }
1005  for (size_t i = 0; i < pubKeys.size(); ++i) {
1006  const auto& str = pubKeys[i].get_str();
1007  if (!IsHex(str)) {
1008  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string");
1009  }
1010  auto parsed_pubkey = ParseHex(str);
1011  CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
1012  if (!pubkey.IsFullyValid()) {
1013  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
1014  }
1015  pubkey_map.emplace(pubkey.GetID(), pubkey);
1016  ordered_pubkeys.push_back(pubkey.GetID());
1017  }
1018  for (size_t i = 0; i < keys.size(); ++i) {
1019  const auto& str = keys[i].get_str();
1020  CKey key = DecodeSecret(str);
1021  if (!key.IsValid()) {
1022  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
1023  }
1024  CPubKey pubkey = key.GetPubKey();
1025  CKeyID id = pubkey.GetID();
1026  if (pubkey_map.count(id)) {
1027  pubkey_map.erase(id);
1028  }
1029  privkey_map.emplace(id, key);
1030  }
1031 
1032 
1033  // Verify and process input data
1034  have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size();
1035  if (have_solving_data) {
1036  // Match up data in import_data with the scriptPubKey in script.
1037  auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1038 
1039  // Verify whether the watchonly option corresponds to the availability of private keys.
1040  bool spendable = std::all_of(import_data.used_keys.begin(), import_data.used_keys.end(), [&](const std::pair<CKeyID, bool>& used_key){ return privkey_map.count(used_key.first) > 0; });
1041  if (!watchOnly && !spendable) {
1042  warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1043  }
1044  if (watchOnly && spendable) {
1045  warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1046  }
1047 
1048  // Check that all required keys for solvability are provided.
1049  if (error.empty()) {
1050  for (const auto& require_key : import_data.used_keys) {
1051  if (!require_key.second) continue; // Not a required key
1052  if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1053  error = "some required keys are missing";
1054  }
1055  }
1056  }
1057 
1058  if (!error.empty()) {
1059  warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1060  import_data = ImportData();
1061  pubkey_map.clear();
1062  privkey_map.clear();
1063  have_solving_data = false;
1064  } else {
1065  // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
1066  if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script.");
1067  if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1068  for (auto it = privkey_map.begin(); it != privkey_map.end(); ) {
1069  auto oldit = it++;
1070  if (import_data.used_keys.count(oldit->first) == 0) {
1071  warnings.push_back("Ignoring irrelevant private key.");
1072  privkey_map.erase(oldit);
1073  }
1074  }
1075  for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
1076  auto oldit = it++;
1077  auto key_data_it = import_data.used_keys.find(oldit->first);
1078  if (key_data_it == import_data.used_keys.end() || !key_data_it->second) {
1079  warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH.");
1080  pubkey_map.erase(oldit);
1081  }
1082  }
1083  }
1084  }
1085 
1086  return warnings;
1087 }
1088 
1089 static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys)
1090 {
1091  UniValue warnings(UniValue::VARR);
1092 
1093  const std::string& descriptor = data["desc"].get_str();
1094  FlatSigningProvider keys;
1095  std::string error;
1096  auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true);
1097  if (!parsed_desc) {
1099  }
1100 
1101  have_solving_data = parsed_desc->IsSolvable();
1102  const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1103 
1104  int64_t range_start = 0, range_end = 0;
1105  if (!parsed_desc->IsRange() && data.exists("range")) {
1106  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
1107  } else if (parsed_desc->IsRange()) {
1108  if (!data.exists("range")) {
1109  throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
1110  }
1111  std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1112  }
1113 
1114  const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
1115 
1116  // Expand all descriptors to get public keys and scripts, and private keys if available.
1117  for (int i = range_start; i <= range_end; ++i) {
1118  FlatSigningProvider out_keys;
1119  std::vector<CScript> scripts_temp;
1120  parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1121  std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1122  for (const auto& key_pair : out_keys.pubkeys) {
1123  ordered_pubkeys.push_back(key_pair.first);
1124  }
1125 
1126  for (const auto& x : out_keys.scripts) {
1127  import_data.import_scripts.emplace(x.second);
1128  }
1129 
1130  parsed_desc->ExpandPrivate(i, keys, out_keys);
1131 
1132  std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1133  std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
1134  import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
1135  }
1136 
1137  for (size_t i = 0; i < priv_keys.size(); ++i) {
1138  const auto& str = priv_keys[i].get_str();
1139  CKey key = DecodeSecret(str);
1140  if (!key.IsValid()) {
1141  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
1142  }
1143  CPubKey pubkey = key.GetPubKey();
1144  CKeyID id = pubkey.GetID();
1145 
1146  // Check if this private key corresponds to a public key from the descriptor
1147  if (!pubkey_map.count(id)) {
1148  warnings.push_back("Ignoring irrelevant private key.");
1149  } else {
1150  privkey_map.emplace(id, key);
1151  }
1152  }
1153 
1154  // Check if all the public keys have corresponding private keys in the import for spendability.
1155  // This does not take into account threshold multisigs which could be spendable without all keys.
1156  // Thus, threshold multisigs without all keys will be considered not spendable here, even if they are,
1157  // perhaps triggering a false warning message. This is consistent with the current wallet IsMine check.
1158  bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1159  [&](const std::pair<CKeyID, CPubKey>& used_key) {
1160  return privkey_map.count(used_key.first) > 0;
1161  }) && std::all_of(import_data.key_origins.begin(), import_data.key_origins.end(),
1162  [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1163  return privkey_map.count(entry.first) > 0;
1164  });
1165  if (!watch_only && !spendable) {
1166  warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1167  }
1168  if (watch_only && spendable) {
1169  warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1170  }
1171 
1172  return warnings;
1173 }
1174 
1175 static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1176 {
1177  UniValue warnings(UniValue::VARR);
1178  UniValue result(UniValue::VOBJ);
1179 
1180  try {
1181  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
1182  // Internal addresses should not have a label
1183  if (internal && data.exists("label")) {
1184  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
1185  }
1186  const std::string& label = data.exists("label") ? data["label"].get_str() : "";
1187  const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false;
1188 
1189  // Add to keypool only works with privkeys disabled
1190  if (add_keypool && !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1191  throw JSONRPCError(RPC_INVALID_PARAMETER, "Keys can only be imported to the keypool when private keys are disabled");
1192  }
1193 
1194  ImportData import_data;
1195  std::map<CKeyID, CPubKey> pubkey_map;
1196  std::map<CKeyID, CKey> privkey_map;
1197  std::set<CScript> script_pub_keys;
1198  std::vector<CKeyID> ordered_pubkeys;
1199  bool have_solving_data;
1200 
1201  if (data.exists("scriptPubKey") && data.exists("desc")) {
1202  throw JSONRPCError(RPC_INVALID_PARAMETER, "Both a descriptor and a scriptPubKey should not be provided.");
1203  } else if (data.exists("scriptPubKey")) {
1204  warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1205  } else if (data.exists("desc")) {
1206  warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1207  } else {
1208  throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a descriptor or scriptPubKey must be provided.");
1209  }
1210 
1211  // If private keys are disabled, abort if private keys are being imported
1212  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) {
1213  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
1214  }
1215 
1216  // Check whether we have any work to do
1217  for (const CScript& script : script_pub_keys) {
1218  if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1219  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script.begin(), script.end()) + "\")");
1220  }
1221  }
1222 
1223  // All good, time to import
1224  pwallet->MarkDirty();
1225  if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1226  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
1227  }
1228  if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1229  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1230  }
1231  if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
1232  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
1233  }
1234  if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
1235  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
1236  }
1237 
1238  result.pushKV("success", UniValue(true));
1239  } catch (const UniValue& e) {
1240  result.pushKV("success", UniValue(false));
1241  result.pushKV("error", e);
1242  } catch (...) {
1243  result.pushKV("success", UniValue(false));
1244 
1245  result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1246  }
1247  if (warnings.size()) result.pushKV("warnings", warnings);
1248  return result;
1249 }
1250 
1251 static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
1252 {
1253  if (data.exists("timestamp")) {
1254  const UniValue& timestamp = data["timestamp"];
1255  if (timestamp.isNum()) {
1256  return timestamp.get_int64();
1257  } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1258  return now;
1259  }
1260  throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
1261  }
1262  throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
1263 }
1264 
1266 {
1267  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
1268  CWallet* const pwallet = wallet.get();
1269  if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {
1270  return NullUniValue;
1271  }
1272 
1273  RPCHelpMan{"importmulti",
1274  "\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"
1275  "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"
1276  "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"
1277  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
1278  "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
1279  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1280  {
1281  {"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
1282  {
1284  {
1285  {"desc", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Descriptor to import. If using descriptor, do not also provide address/scriptPubKey, scripts, or pubkeys"},
1286  {"scriptPubKey", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of scriptPubKey (string for script, json for address). Should not be provided if using a descriptor",
1287  /* oneline_description */ "", {"\"<script>\" | { \"address\":\"<address>\" }", "string / json"}
1288  },
1289  {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Creation time of the key expressed in " + UNIX_EPOCH_TIME + ",\n"
1290  " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
1291  " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
1292  " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
1293  " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
1294  " creation time of all keys being imported by the importmulti call will be scanned.",
1295  /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"}
1296  },
1297  {"redeemscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
1298  {"witnessscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
1299  {"pubkeys", RPCArg::Type::ARR, /* default */ "empty array", "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).",
1300  {
1302  }
1303  },
1304  {"keys", RPCArg::Type::ARR, /* default */ "empty array", "Array of strings giving private keys to import. The corresponding public keys must occur in the output or redeemscript.",
1305  {
1307  }
1308  },
1309  {"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"},
1310  {"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
1311  {"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watchonly."},
1312  {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
1313  {"keypool", RPCArg::Type::BOOL, /* 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"},
1314  },
1315  },
1316  },
1317  "\"requests\""},
1319  {
1320  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Stating if should rescan the blockchain after all imports"},
1321  },
1322  "\"options\""},
1323  },
1324  RPCResult{
1325  RPCResult::Type::ARR, "", "Response is an array with the same size as the input that has the execution result",
1326  {
1327  {RPCResult::Type::OBJ, "", "",
1328  {
1329  {RPCResult::Type::BOOL, "success", ""},
1330  {RPCResult::Type::ARR, "warnings", /* optional */ true, "",
1331  {
1332  {RPCResult::Type::STR, "", ""},
1333  }},
1334  {RPCResult::Type::OBJ, "error", /* optional */ true, "",
1335  {
1336  {RPCResult::Type::ELISION, "", "JSONRPC error"},
1337  }},
1338  }},
1339  }
1340  },
1341  RPCExamples{
1342  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1343  "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1344  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1345  },
1346  }.Check(mainRequest);
1347 
1348 
1349  RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1350 
1351  EnsureLegacyScriptPubKeyMan(*wallet, 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  auto locked_chain = pwallet->chain().lock();
1377  LOCK(pwallet->cs_wallet);
1378  EnsureWalletIsUnlocked(pwallet);
1379 
1380  // Verify all timestamps are present before importing any keys.
1381  const Optional<int> tip_height = locked_chain->getHeight();
1382  now = tip_height ? locked_chain->getBlockMedianTimePast(*tip_height) : 0;
1383  for (const UniValue& data : requests.getValues()) {
1384  GetImportTimestamp(data, now);
1385  }
1386 
1387  const int64_t minimumTimestamp = 1;
1388 
1389  if (fRescan && tip_height) {
1390  nLowestTimestamp = locked_chain->getBlockTime(*tip_height);
1391  } else {
1392  fRescan = false;
1393  }
1394 
1395  for (const UniValue& data : requests.getValues()) {
1396  const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
1397  const UniValue result = ProcessImport(pwallet, data, timestamp);
1398  response.push_back(result);
1399 
1400  if (!fRescan) {
1401  continue;
1402  }
1403 
1404  // If at least one request was successful then allow rescan.
1405  if (result["success"].get_bool()) {
1406  fRunScan = true;
1407  }
1408 
1409  // Get the lowest timestamp.
1410  if (timestamp < nLowestTimestamp) {
1411  nLowestTimestamp = timestamp;
1412  }
1413  }
1414  }
1415  if (fRescan && fRunScan && requests.size()) {
1416  int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
1417  {
1418  auto locked_chain = pwallet->chain().lock();
1419  LOCK(pwallet->cs_wallet);
1420  pwallet->ReacceptWalletTransactions();
1421  }
1422 
1423  if (pwallet->IsAbortingRescan()) {
1424  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
1425  }
1426  if (scannedTime > nLowestTimestamp) {
1427  std::vector<UniValue> results = response.getValues();
1428  response.clear();
1429  response.setArray();
1430  size_t i = 0;
1431  for (const UniValue& request : requests.getValues()) {
1432  // If key creation date is within the successfully scanned
1433  // range, or if the import result already has an error set, let
1434  // the result stand unmodified. Otherwise replace the result
1435  // with an error message.
1436  if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
1437  response.push_back(results.at(i));
1438  } else {
1439  UniValue result = UniValue(UniValue::VOBJ);
1440  result.pushKV("success", UniValue(false));
1441  result.pushKV(
1442  "error",
1443  JSONRPCError(
1445  strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a "
1446  "block from time %d, which is after or within %d seconds of key creation, and "
1447  "could contain transactions pertaining to the key. As a result, transactions "
1448  "and coins using this key may not appear in the wallet. This error could be "
1449  "caused by pruning or data corruption (see bitcoind log for details) and could "
1450  "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1451  "and -rescan options).",
1452  GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
1453  response.push_back(std::move(result));
1454  }
1455  ++i;
1456  }
1457  }
1458  }
1459 
1460  return response;
1461 }
static std::string EncodeDumpString(const std::string &str)
Definition: rpcdump.cpp:31
std::unique_ptr< CScript > witnessscript
Provided witnessScript; will be moved to import_scripts if relevant.
Definition: rpcdump.cpp:861
Top-level scriptPubKey.
UniValue abortrescan(const JSONRPCRequest &request)
Definition: rpcdump.cpp:194
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
Definition: wallet.cpp:1377
const CHDChain & GetHDChain() const
void RPCTypeCheck(const UniValue &params, const std::list< UniValueType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: util.cpp:19
const std::vector< UniValue > & getValues() const
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:156
static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: rpcdump.cpp:1175
unspendable OP_RETURN script that carries data
Definition: standard.h:63
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
bool get_bool() const
UniValue dumpprivkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:676
Required arg.
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
RecursiveMutex cs_KeyStore
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:232
UniValue importmulti(const JSONRPCRequest &mainRequest)
Definition: rpcdump.cpp:1265
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:184
std::map< CKeyID, CKey > keys
std::vector< unsigned char > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:98
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1741
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: rpcwallet.cpp:122
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:16
Definition: key.h:144
#define CHECK_NONFATAL(condition)
Throw a NonFatalCheckError when the condition evaluates to false.
Definition: check.h:28
std::vector< unsigned char > ParseHex(const char *psz)
fs::ifstream ifstream
Definition: fs.h:90
void EnsureWalletIsUnlocked(const CWallet *pwallet)
Definition: rpcwallet.cpp:114
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:409
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:325
virtual std::set< CScriptID > GetCScripts() const
UniValue dumpwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:724
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:78
const std::string & get_str() const
static auto & nullopt
Substitute for C++17 std::nullopt.
Definition: optional.h:24
enum VType getType() const
Definition: univalue.h:64
static std::string WriteHDKeypath(std::vector< uint32_t > &keypath)
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
bool isNum() const
Definition: univalue.h:82
const UniValue & get_array() const
txnouttype Solver(const CScript &scriptPubKey, std::vector< std::vector< unsigned char >> &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:91
bool isStr() const
Definition: univalue.h:81
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:201
int64_t get_int64() const
fs::ofstream ofstream
Definition: fs.h:91
isminetype IsMine(const CTxDestination &dest) const
Definition: wallet.cpp:1203
const unsigned char * begin() const
Definition: key.h:89
unsigned char * begin()
Definition: uint256.h:54
int64_t ParseISO8601DateTime(const std::string &str)
Definition: time.cpp:104
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
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:155
bool IsNull() const
Definition: uint256.h:30
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1440
static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan *spk_man, const CWallet *const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: rpcdump.cpp:57
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
Invalid, missing or duplicate parameter.
Definition: protocol.h:43
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
Definition: outputtype.cpp:68
DBErrors ZapSelectTx(std::vector< uint256 > &vHashIn, std::vector< uint256 > &vHashOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3146
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:786
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:3212
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Definition: rpcdump.cpp:878
iterator end()
Definition: prevector.h:292
void MarkDirty()
Definition: wallet.cpp:682
Special type that is a STR with only hex chars.
#define LOCK2(cs1, cs2)
Definition: sync.h:219
const char * uvTypeName(UniValue::VType t)
Definition: univalue.cpp:219
Used to relay blocks as header + vector<merkle branch> to filtered nodes.
Definition: merkleblock.h:133
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:51
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
Only for Witness versions not already defined above.
Definition: standard.h:66
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
Definition: rpcdump.cpp:866
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:945
Confirmation m_confirm
Definition: wallet.h:382
void WalletLogPrintf(std::string fmt, Params... parameters) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
Definition: wallet.h:1161
UniValue params
Definition: request.h:32
std::map< CScriptID, CScript > scripts
P2WSH witnessScript.
static UniValue ProcessImportDescriptor(ImportData &import_data, std::map< CKeyID, CPubKey > &pubkey_map, std::map< CKeyID, CKey > &privkey_map, std::set< CScript > &script_pub_keys, bool &have_solving_data, const UniValue &data, std::vector< CKeyID > &ordered_pubkeys)
Definition: rpcdump.cpp:1089
#define LOCK(cs)
Definition: sync.h:218
bool exists(const std::string &key) const
Definition: univalue.h:75
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:36
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:865
static const int64_t TIMESTAMP_MIN
Definition: rpcdump.cpp:78
UniValue removeprunedfunds(const JSONRPCRequest &request)
Definition: rpcdump.cpp:387
An encapsulated public key.
Definition: pubkey.h:30
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:117
bool IsHex(const std::string &str)
std::map< CKeyID, CPubKey > pubkeys
static std::string DecodeDumpString(const std::string &str)
Definition: rpcdump.cpp:43
Unexpected type was passed as parameter.
Definition: protocol.h:40
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1450
bool GetKey(const CKeyID &address, CKey &keyOut) const override
bool ImportScriptPubKeys(const std::string &label, const std::set< CScript > &script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1470
General application defined errors.
Definition: protocol.h:39
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
unsigned int size() const
Simple read-only vector-like interface.
Definition: key.h:88
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
Definition: rpcdump.cpp:80
bool ImportPubKeys(const std::vector< CKeyID > &ordered_pubkeys, const std::map< CKeyID, CPubKey > &pubkey_map, const std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo >> &key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1460
Invalid address or key.
Definition: protocol.h:41
unsigned int size() const
Definition: uint256.h:74
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:289
virtual std::unique_ptr< Lock > lock(bool try_lock=false)=0
Return Lock interface.
std::set< CScript > import_scripts
Definition: rpcdump.cpp:864
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:89
bool isNull() const
Definition: univalue.h:77
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
Definition: key.cpp:301
bool AddToWallet(const CWalletTx &wtxIn, bool fFlushOnClose=true)
Definition: wallet.cpp:769
Optional arg that is a named argument and has a default value of null.
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1222
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:256
CRIPEMD160 & Write(const unsigned char *data, size_t len)
Definition: ripemd160.cpp:247
P2SH redeemScript.
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
Definition: rpcdump.cpp:860
Special type that is a NUM or [NUM,NUM].
bool fHelp
Definition: request.h:33
txnouttype
Definition: standard.h:55
256-bit opaque blob.
Definition: uint256.h:120
Optional argument with default value omitted because they are implicitly clear.
CTxDestination DecodeDestination(const std::string &str)
Definition: key_io.cpp:215
enum VType type() const
Definition: univalue.h:177
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:51
bool setArray()
Definition: univalue.cpp:94
uint256 GetHash() const
Compute the hash of this CMutableTransaction.
Definition: transaction.cpp:62
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:390
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:12
UniValue importpubkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:427
ScriptContext
Definition: rpcdump.cpp:869
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:20
std::string HexStr(const T itbegin, const T itend)
Definition: strencodings.h:123
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:609
const std::string GetDisplayName() const override
Returns a bracketed wallet name for displaying in logs, will return [default wallet] if the wallet ha...
Definition: wallet.h:1154
160-bit opaque blob.
Definition: uint256.h:109
const UniValue NullUniValue
Definition: univalue.cpp:13
UniValue importprivkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:90
void AbortRescan()
Definition: wallet.h:834
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:49
iterator begin()
Definition: prevector.h:290
std::pair< int64_t, int64_t > ParseDescriptorRange(const UniValue &value)
Parse a JSON range specified as int64, or [int64, int64].
Definition: util.cpp:770
UniValue importwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:516
virtual void showProgress(const std::string &title, int progress, bool resume_possible)=0
Send progress indicator.
RecursiveMutex cs_wallet
Definition: wallet.h:720
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:21
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:112
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:210
bool IsScanning() const
Definition: wallet.h:836
UniValue importaddress(const JSONRPCRequest &request)
Definition: rpcdump.cpp:222
A mutable version of CTransaction.
Definition: transaction.h:366
Wallet errors.
Definition: protocol.h:70
void clear()
Definition: univalue.cpp:15
size_t size() const
Definition: univalue.h:68
An encapsulated private key.
Definition: key.h:27
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:14
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded Values (throws error if not hex).
Definition: util.cpp:85
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: rpcdump.cpp:1251
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:132
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1591
boost::variant< CNoDestination, PKHash, ScriptHash, WitnessV0ScriptHash, WitnessV0KeyHash, WitnessUnknown > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:143
CKeyID seed_id
seed hash160
Definition: walletdb.h:87
int64_t GetTime()
Return system time (or mocked time, if set)
Definition: time.cpp:23
auto it
Definition: validation.cpp:361
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:150
void GetKeyBirthTimes(interfaces::Chain::Lock &locked_chain, std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3553
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
bool EnsureWalletIsAvailable(const CWallet *pwallet, bool avoidException)
Definition: rpcwallet.cpp:102
const std::string CLIENT_BUILD
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:199
CTransactionRef tx
Definition: wallet.h:352
UniValue importprunedfunds(const JSONRPCRequest &request)
Definition: rpcdump.cpp:326
virtual bool havePruned()=0
Check if any block has been pruned.
Error parsing or validating structure in raw format.
Definition: protocol.h:45
A hasher class for RIPEMD-160.
Definition: ripemd160.h:12
Special type to denote elision (...)
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:93
bool IsAbortingRescan() const
Definition: wallet.h:835
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:180
NODISCARD bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Definition: core_read.cpp:120