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, 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[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  },
109  RPCResults{},
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  RPCResults{},
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  },
245  RPCResults{},
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  },
340  RPCResults{},
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  },
400  RPCResults{},
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  },
446  RPCResults{},
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  },
530  RPCResults{},
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  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  "\"key\" (string) The private key\n"
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  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  "{ (json object)\n"
742  " \"filename\" : { (string) The filename with full absolute path\n"
743  "}\n"
744  },
745  RPCExamples{
746  HelpExampleCli("dumpwallet", "\"test\"")
747  + HelpExampleRpc("dumpwallet", "\"test\"")
748  },
749  }.Check(request);
750 
752 
753  auto locked_chain = pwallet->chain().lock();
754  LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
755 
756  EnsureWalletIsUnlocked(pwallet);
757 
758  fs::path filepath = request.params[0].get_str();
759  filepath = fs::absolute(filepath);
760 
761  /* Prevent arbitrary files from being overwritten. There have been reports
762  * that users have overwritten wallet files this way:
763  * https://github.com/bitcoin/bitcoin/issues/9934
764  * It may also avoid other security issues.
765  */
766  if (fs::exists(filepath)) {
767  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");
768  }
769 
770  fsbridge::ofstream file;
771  file.open(filepath);
772  if (!file.is_open())
773  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
774 
775  std::map<CKeyID, int64_t> mapKeyBirth;
776  const std::map<CKeyID, int64_t>& mapKeyPool = spk_man.GetAllReserveKeys();
777  pwallet->GetKeyBirthTimes(*locked_chain, mapKeyBirth);
778 
779  std::set<CScriptID> scripts = spk_man.GetCScripts();
780 
781  // sort time/key pairs
782  std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
783  for (const auto& entry : mapKeyBirth) {
784  vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
785  }
786  mapKeyBirth.clear();
787  std::sort(vKeyBirth.begin(), vKeyBirth.end());
788 
789  // produce output
790  file << strprintf("# Wallet dump created by Bitcoin %s\n", CLIENT_BUILD);
791  file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
792  const Optional<int> tip_height = locked_chain->getHeight();
793  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)");
794  file << strprintf("# mined on %s\n", tip_height ? FormatISO8601DateTime(locked_chain->getBlockTime(*tip_height)) : "(missing block time)");
795  file << "\n";
796 
797  // add the base58check encoded extended master if the wallet uses HD
798  CKeyID seed_id = spk_man.GetHDChain().seed_id;
799  if (!seed_id.IsNull())
800  {
801  CKey seed;
802  if (spk_man.GetKey(seed_id, seed)) {
803  CExtKey masterKey;
804  masterKey.SetSeed(seed.begin(), seed.size());
805 
806  file << "# extended private masterkey: " << EncodeExtKey(masterKey) << "\n\n";
807  }
808  }
809  for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
810  const CKeyID &keyid = it->second;
811  std::string strTime = FormatISO8601DateTime(it->first);
812  std::string strAddr;
813  std::string strLabel;
814  CKey key;
815  if (spk_man.GetKey(keyid, key)) {
816  file << strprintf("%s %s ", EncodeSecret(key), strTime);
817  if (GetWalletAddressesForKey(&spk_man, pwallet, keyid, strAddr, strLabel)) {
818  file << strprintf("label=%s", strLabel);
819  } else if (keyid == seed_id) {
820  file << "hdseed=1";
821  } else if (mapKeyPool.count(keyid)) {
822  file << "reserve=1";
823  } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
824  file << "inactivehdseed=1";
825  } else {
826  file << "change=1";
827  }
828  file << strprintf(" # addr=%s%s\n", strAddr, (spk_man.mapKeyMetadata[keyid].has_key_origin ? " hdkeypath="+WriteHDKeypath(spk_man.mapKeyMetadata[keyid].key_origin.path) : ""));
829  }
830  }
831  file << "\n";
832  for (const CScriptID &scriptid : scripts) {
833  CScript script;
834  std::string create_time = "0";
835  std::string address = EncodeDestination(ScriptHash(scriptid));
836  // get birth times for scripts with metadata
837  auto it = spk_man.m_script_metadata.find(scriptid);
838  if (it != spk_man.m_script_metadata.end()) {
839  create_time = FormatISO8601DateTime(it->second.nCreateTime);
840  }
841  if(spk_man.GetCScript(scriptid, script)) {
842  file << strprintf("%s %s script=1", HexStr(script.begin(), script.end()), create_time);
843  file << strprintf(" # addr=%s\n", address);
844  }
845  }
846  file << "\n";
847  file << "# End of dump\n";
848  file.close();
849 
850  UniValue reply(UniValue::VOBJ);
851  reply.pushKV("filename", filepath.string());
852 
853  return reply;
854 }
855 
857 {
858  // Input data
859  std::unique_ptr<CScript> redeemscript;
860  std::unique_ptr<CScript> witnessscript;
861 
862  // Output data
863  std::set<CScript> import_scripts;
864  std::map<CKeyID, bool> used_keys;
865  std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
866 };
867 
868 enum class ScriptContext
869 {
870  TOP,
871  P2SH,
872  WITNESS_V0,
873 };
874 
875 // 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.
876 // Returns an error string, or the empty string for success.
877 static std::string RecurseImportData(const CScript& script, ImportData& import_data, const ScriptContext script_ctx)
878 {
879  // Use Solver to obtain script type and parsed pubkeys or hashes:
880  std::vector<std::vector<unsigned char>> solverdata;
881  txnouttype script_type = Solver(script, solverdata);
882 
883  switch (script_type) {
884  case TX_PUBKEY: {
885  CPubKey pubkey(solverdata[0].begin(), solverdata[0].end());
886  import_data.used_keys.emplace(pubkey.GetID(), false);
887  return "";
888  }
889  case TX_PUBKEYHASH: {
890  CKeyID id = CKeyID(uint160(solverdata[0]));
891  import_data.used_keys[id] = true;
892  return "";
893  }
894  case TX_SCRIPTHASH: {
895  if (script_ctx == ScriptContext::P2SH) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside another P2SH");
896  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2SH inside a P2WSH");
897  CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
898  CScriptID id = CScriptID(uint160(solverdata[0]));
899  auto subscript = std::move(import_data.redeemscript); // Remove redeemscript from import_data to check for superfluous script later.
900  if (!subscript) return "missing redeemscript";
901  if (CScriptID(*subscript) != id) return "redeemScript does not match the scriptPubKey";
902  import_data.import_scripts.emplace(*subscript);
903  return RecurseImportData(*subscript, import_data, ScriptContext::P2SH);
904  }
905  case TX_MULTISIG: {
906  for (size_t i = 1; i + 1< solverdata.size(); ++i) {
907  CPubKey pubkey(solverdata[i].begin(), solverdata[i].end());
908  import_data.used_keys.emplace(pubkey.GetID(), false);
909  }
910  return "";
911  }
913  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WSH inside another P2WSH");
914  uint256 fullid(solverdata[0]);
915  CScriptID id;
916  CRIPEMD160().Write(fullid.begin(), fullid.size()).Finalize(id.begin());
917  auto subscript = std::move(import_data.witnessscript); // Remove redeemscript from import_data to check for superfluous script later.
918  if (!subscript) return "missing witnessscript";
919  if (CScriptID(*subscript) != id) return "witnessScript does not match the scriptPubKey or redeemScript";
920  if (script_ctx == ScriptContext::TOP) {
921  import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WSH requires the TOP script imported (see script/ismine.cpp)
922  }
923  import_data.import_scripts.emplace(*subscript);
924  return RecurseImportData(*subscript, import_data, ScriptContext::WITNESS_V0);
925  }
926  case TX_WITNESS_V0_KEYHASH: {
927  if (script_ctx == ScriptContext::WITNESS_V0) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Trying to nest P2WPKH inside P2WSH");
928  CKeyID id = CKeyID(uint160(solverdata[0]));
929  import_data.used_keys[id] = true;
930  if (script_ctx == ScriptContext::TOP) {
931  import_data.import_scripts.emplace(script); // Special rule for IsMine: native P2WPKH requires the TOP script imported (see script/ismine.cpp)
932  }
933  return "";
934  }
935  case TX_NULL_DATA:
936  return "unspendable script";
937  case TX_NONSTANDARD:
938  case TX_WITNESS_UNKNOWN:
939  default:
940  return "unrecognized script";
941  }
942 }
943 
944 static UniValue ProcessImportLegacy(ImportData& import_data, std::map<CKeyID, CPubKey>& pubkey_map, std::map<CKeyID, CKey>& privkey_map, std::set<CScript>& script_pub_keys, bool& have_solving_data, const UniValue& data, std::vector<CKeyID>& ordered_pubkeys)
945 {
946  UniValue warnings(UniValue::VARR);
947 
948  // First ensure scriptPubKey has either a script or JSON with "address" string
949  const UniValue& scriptPubKey = data["scriptPubKey"];
950  bool isScript = scriptPubKey.getType() == UniValue::VSTR;
951  if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address"))) {
952  throw JSONRPCError(RPC_INVALID_PARAMETER, "scriptPubKey must be string with script or JSON with address string");
953  }
954  const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
955 
956  // Optional fields.
957  const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
958  const std::string& witness_script_hex = data.exists("witnessscript") ? data["witnessscript"].get_str() : "";
959  const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
960  const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
961  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
962  const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
963 
964  if (data.exists("range")) {
965  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for a non-descriptor import");
966  }
967 
968  // Generate the script and destination for the scriptPubKey provided
969  CScript script;
970  if (!isScript) {
971  CTxDestination dest = DecodeDestination(output);
972  if (!IsValidDestination(dest)) {
973  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address \"" + output + "\"");
974  }
975  script = GetScriptForDestination(dest);
976  } else {
977  if (!IsHex(output)) {
978  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey \"" + output + "\"");
979  }
980  std::vector<unsigned char> vData(ParseHex(output));
981  script = CScript(vData.begin(), vData.end());
982  CTxDestination dest;
983  if (!ExtractDestination(script, dest) && !internal) {
984  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set to true for nonstandard scriptPubKey imports.");
985  }
986  }
987  script_pub_keys.emplace(script);
988 
989  // Parse all arguments
990  if (strRedeemScript.size()) {
991  if (!IsHex(strRedeemScript)) {
992  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script \"" + strRedeemScript + "\": must be hex string");
993  }
994  auto parsed_redeemscript = ParseHex(strRedeemScript);
995  import_data.redeemscript = MakeUnique<CScript>(parsed_redeemscript.begin(), parsed_redeemscript.end());
996  }
997  if (witness_script_hex.size()) {
998  if (!IsHex(witness_script_hex)) {
999  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid witness script \"" + witness_script_hex + "\": must be hex string");
1000  }
1001  auto parsed_witnessscript = ParseHex(witness_script_hex);
1002  import_data.witnessscript = MakeUnique<CScript>(parsed_witnessscript.begin(), parsed_witnessscript.end());
1003  }
1004  for (size_t i = 0; i < pubKeys.size(); ++i) {
1005  const auto& str = pubKeys[i].get_str();
1006  if (!IsHex(str)) {
1007  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" must be a hex string");
1008  }
1009  auto parsed_pubkey = ParseHex(str);
1010  CPubKey pubkey(parsed_pubkey.begin(), parsed_pubkey.end());
1011  if (!pubkey.IsFullyValid()) {
1012  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey \"" + str + "\" is not a valid public key");
1013  }
1014  pubkey_map.emplace(pubkey.GetID(), pubkey);
1015  ordered_pubkeys.push_back(pubkey.GetID());
1016  }
1017  for (size_t i = 0; i < keys.size(); ++i) {
1018  const auto& str = keys[i].get_str();
1019  CKey key = DecodeSecret(str);
1020  if (!key.IsValid()) {
1021  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
1022  }
1023  CPubKey pubkey = key.GetPubKey();
1024  CKeyID id = pubkey.GetID();
1025  if (pubkey_map.count(id)) {
1026  pubkey_map.erase(id);
1027  }
1028  privkey_map.emplace(id, key);
1029  }
1030 
1031 
1032  // Verify and process input data
1033  have_solving_data = import_data.redeemscript || import_data.witnessscript || pubkey_map.size() || privkey_map.size();
1034  if (have_solving_data) {
1035  // Match up data in import_data with the scriptPubKey in script.
1036  auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1037 
1038  // Verify whether the watchonly option corresponds to the availability of private keys.
1039  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; });
1040  if (!watchOnly && !spendable) {
1041  warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1042  }
1043  if (watchOnly && spendable) {
1044  warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1045  }
1046 
1047  // Check that all required keys for solvability are provided.
1048  if (error.empty()) {
1049  for (const auto& require_key : import_data.used_keys) {
1050  if (!require_key.second) continue; // Not a required key
1051  if (pubkey_map.count(require_key.first) == 0 && privkey_map.count(require_key.first) == 0) {
1052  error = "some required keys are missing";
1053  }
1054  }
1055  }
1056 
1057  if (!error.empty()) {
1058  warnings.push_back("Importing as non-solvable: " + error + ". If this is intentional, don't provide any keys, pubkeys, witnessscript, or redeemscript.");
1059  import_data = ImportData();
1060  pubkey_map.clear();
1061  privkey_map.clear();
1062  have_solving_data = false;
1063  } else {
1064  // RecurseImportData() removes any relevant redeemscript/witnessscript from import_data, so we can use that to discover if a superfluous one was provided.
1065  if (import_data.redeemscript) warnings.push_back("Ignoring redeemscript as this is not a P2SH script.");
1066  if (import_data.witnessscript) warnings.push_back("Ignoring witnessscript as this is not a (P2SH-)P2WSH script.");
1067  for (auto it = privkey_map.begin(); it != privkey_map.end(); ) {
1068  auto oldit = it++;
1069  if (import_data.used_keys.count(oldit->first) == 0) {
1070  warnings.push_back("Ignoring irrelevant private key.");
1071  privkey_map.erase(oldit);
1072  }
1073  }
1074  for (auto it = pubkey_map.begin(); it != pubkey_map.end(); ) {
1075  auto oldit = it++;
1076  auto key_data_it = import_data.used_keys.find(oldit->first);
1077  if (key_data_it == import_data.used_keys.end() || !key_data_it->second) {
1078  warnings.push_back("Ignoring public key \"" + HexStr(oldit->first) + "\" as it doesn't appear inside P2PKH or P2WPKH.");
1079  pubkey_map.erase(oldit);
1080  }
1081  }
1082  }
1083  }
1084 
1085  return warnings;
1086 }
1087 
1088 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)
1089 {
1090  UniValue warnings(UniValue::VARR);
1091 
1092  const std::string& descriptor = data["desc"].get_str();
1093  FlatSigningProvider keys;
1094  std::string error;
1095  auto parsed_desc = Parse(descriptor, keys, error, /* require_checksum = */ true);
1096  if (!parsed_desc) {
1098  }
1099 
1100  have_solving_data = parsed_desc->IsSolvable();
1101  const bool watch_only = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1102 
1103  int64_t range_start = 0, range_end = 0;
1104  if (!parsed_desc->IsRange() && data.exists("range")) {
1105  throw JSONRPCError(RPC_INVALID_PARAMETER, "Range should not be specified for an un-ranged descriptor");
1106  } else if (parsed_desc->IsRange()) {
1107  if (!data.exists("range")) {
1108  throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor is ranged, please specify the range");
1109  }
1110  std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1111  }
1112 
1113  const UniValue& priv_keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
1114 
1115  // Expand all descriptors to get public keys and scripts, and private keys if available.
1116  for (int i = range_start; i <= range_end; ++i) {
1117  FlatSigningProvider out_keys;
1118  std::vector<CScript> scripts_temp;
1119  parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1120  std::copy(scripts_temp.begin(), scripts_temp.end(), std::inserter(script_pub_keys, script_pub_keys.end()));
1121  for (const auto& key_pair : out_keys.pubkeys) {
1122  ordered_pubkeys.push_back(key_pair.first);
1123  }
1124 
1125  for (const auto& x : out_keys.scripts) {
1126  import_data.import_scripts.emplace(x.second);
1127  }
1128 
1129  parsed_desc->ExpandPrivate(i, keys, out_keys);
1130 
1131  std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(), std::inserter(pubkey_map, pubkey_map.end()));
1132  std::copy(out_keys.keys.begin(), out_keys.keys.end(), std::inserter(privkey_map, privkey_map.end()));
1133  import_data.key_origins.insert(out_keys.origins.begin(), out_keys.origins.end());
1134  }
1135 
1136  for (size_t i = 0; i < priv_keys.size(); ++i) {
1137  const auto& str = priv_keys[i].get_str();
1138  CKey key = DecodeSecret(str);
1139  if (!key.IsValid()) {
1140  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
1141  }
1142  CPubKey pubkey = key.GetPubKey();
1143  CKeyID id = pubkey.GetID();
1144 
1145  // Check if this private key corresponds to a public key from the descriptor
1146  if (!pubkey_map.count(id)) {
1147  warnings.push_back("Ignoring irrelevant private key.");
1148  } else {
1149  privkey_map.emplace(id, key);
1150  }
1151  }
1152 
1153  // Check if all the public keys have corresponding private keys in the import for spendability.
1154  // This does not take into account threshold multisigs which could be spendable without all keys.
1155  // Thus, threshold multisigs without all keys will be considered not spendable here, even if they are,
1156  // perhaps triggering a false warning message. This is consistent with the current wallet IsMine check.
1157  bool spendable = std::all_of(pubkey_map.begin(), pubkey_map.end(),
1158  [&](const std::pair<CKeyID, CPubKey>& used_key) {
1159  return privkey_map.count(used_key.first) > 0;
1160  }) && std::all_of(import_data.key_origins.begin(), import_data.key_origins.end(),
1161  [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& entry) {
1162  return privkey_map.count(entry.first) > 0;
1163  });
1164  if (!watch_only && !spendable) {
1165  warnings.push_back("Some private keys are missing, outputs will be considered watchonly. If this is intentional, specify the watchonly flag.");
1166  }
1167  if (watch_only && spendable) {
1168  warnings.push_back("All private keys are provided, outputs will be considered spendable. If this is intentional, do not specify the watchonly flag.");
1169  }
1170 
1171  return warnings;
1172 }
1173 
1174 static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet)
1175 {
1176  UniValue warnings(UniValue::VARR);
1177  UniValue result(UniValue::VOBJ);
1178 
1179  try {
1180  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
1181  // Internal addresses should not have a label
1182  if (internal && data.exists("label")) {
1183  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal addresses should not have a label");
1184  }
1185  const std::string& label = data.exists("label") ? data["label"].get_str() : "";
1186  const bool add_keypool = data.exists("keypool") ? data["keypool"].get_bool() : false;
1187 
1188  // Add to keypool only works with privkeys disabled
1189  if (add_keypool && !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1190  throw JSONRPCError(RPC_INVALID_PARAMETER, "Keys can only be imported to the keypool when private keys are disabled");
1191  }
1192 
1193  ImportData import_data;
1194  std::map<CKeyID, CPubKey> pubkey_map;
1195  std::map<CKeyID, CKey> privkey_map;
1196  std::set<CScript> script_pub_keys;
1197  std::vector<CKeyID> ordered_pubkeys;
1198  bool have_solving_data;
1199 
1200  if (data.exists("scriptPubKey") && data.exists("desc")) {
1201  throw JSONRPCError(RPC_INVALID_PARAMETER, "Both a descriptor and a scriptPubKey should not be provided.");
1202  } else if (data.exists("scriptPubKey")) {
1203  warnings = ProcessImportLegacy(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1204  } else if (data.exists("desc")) {
1205  warnings = ProcessImportDescriptor(import_data, pubkey_map, privkey_map, script_pub_keys, have_solving_data, data, ordered_pubkeys);
1206  } else {
1207  throw JSONRPCError(RPC_INVALID_PARAMETER, "Either a descriptor or scriptPubKey must be provided.");
1208  }
1209 
1210  // If private keys are disabled, abort if private keys are being imported
1211  if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !privkey_map.empty()) {
1212  throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import private keys to a wallet with private keys disabled");
1213  }
1214 
1215  // Check whether we have any work to do
1216  for (const CScript& script : script_pub_keys) {
1217  if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1218  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script (\"" + HexStr(script.begin(), script.end()) + "\")");
1219  }
1220  }
1221 
1222  // All good, time to import
1223  pwallet->MarkDirty();
1224  if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1225  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet");
1226  }
1227  if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1228  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1229  }
1230  if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) {
1231  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
1232  }
1233  if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) {
1234  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
1235  }
1236 
1237  result.pushKV("success", UniValue(true));
1238  } catch (const UniValue& e) {
1239  result.pushKV("success", UniValue(false));
1240  result.pushKV("error", e);
1241  } catch (...) {
1242  result.pushKV("success", UniValue(false));
1243 
1244  result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1245  }
1246  if (warnings.size()) result.pushKV("warnings", warnings);
1247  return result;
1248 }
1249 
1250 static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
1251 {
1252  if (data.exists("timestamp")) {
1253  const UniValue& timestamp = data["timestamp"];
1254  if (timestamp.isNum()) {
1255  return timestamp.get_int64();
1256  } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1257  return now;
1258  }
1259  throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
1260  }
1261  throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
1262 }
1263 
1265 {
1266  std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(mainRequest);
1267  CWallet* const pwallet = wallet.get();
1268  if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp)) {
1269  return NullUniValue;
1270  }
1271 
1272  RPCHelpMan{"importmulti",
1273  "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), optionally rescanning the blockchain from the earliest creation time of the imported scripts. Requires a new wallet backup.\n"
1274  "If an address/script is imported without all of the private keys required to spend from that address, it will be watchonly. The 'watchonly' option must be set to true in this case or a warning will be returned.\n"
1275  "Conversely, if all the private keys are provided and the address/script is spendable, the watchonly option must be set to false, or a warning will be returned.\n"
1276  "\nNote: This call can take over an hour to complete if rescan is true, during that time, other rpc calls\n"
1277  "may report that the imported keys, addresses or scripts exist but related transactions are still missing.\n"
1278  "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
1279  {
1280  {"requests", RPCArg::Type::ARR, RPCArg::Optional::NO, "Data to be imported",
1281  {
1283  {
1284  {"desc", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Descriptor to import. If using descriptor, do not also provide address/scriptPubKey, scripts, or pubkeys"},
1285  {"scriptPubKey", RPCArg::Type::STR, RPCArg::Optional::NO, "Type of scriptPubKey (string for script, json for address). Should not be provided if using a descriptor",
1286  /* oneline_description */ "", {"\"<script>\" | { \"address\":\"<address>\" }", "string / json"}
1287  },
1288  {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::NO, "Creation time of the key expressed in " + UNIX_EPOCH_TIME + ",\n"
1289  " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
1290  " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
1291  " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
1292  " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
1293  " creation time of all keys being imported by the importmulti call will be scanned.",
1294  /* oneline_description */ "", {"timestamp | \"now\"", "integer / string"}
1295  },
1296  {"redeemscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH or P2SH-P2WSH address/scriptPubKey"},
1297  {"witnessscript", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Allowed only if the scriptPubKey is a P2SH-P2WSH or P2WSH address/scriptPubKey"},
1298  {"pubkeys", RPCArg::Type::ARR, /* 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).",
1299  {
1301  }
1302  },
1303  {"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.",
1304  {
1306  }
1307  },
1308  {"range", RPCArg::Type::RANGE, RPCArg::Optional::OMITTED, "If a ranged descriptor is used, this specifies the end or the range (in the form [begin,end]) to import"},
1309  {"internal", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be treated as not incoming payments (also known as change)"},
1310  {"watchonly", RPCArg::Type::BOOL, /* default */ "false", "Stating whether matching outputs should be considered watchonly."},
1311  {"label", RPCArg::Type::STR, /* default */ "''", "Label to assign to the address, only allowed with internal=false"},
1312  {"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"},
1313  },
1314  },
1315  },
1316  "\"requests\""},
1318  {
1319  {"rescan", RPCArg::Type::BOOL, /* default */ "true", "Stating if should rescan the blockchain after all imports"},
1320  },
1321  "\"options\""},
1322  },
1323  RPCResult{
1324  "[ (json array) Response is an array with the same size as the input that has the execution result\n"
1325  " { (json object)\n"
1326  " \"success\" : true|false, (boolean)\n"
1327  " \"warnings\" : [ (json array, optional)\n"
1328  " \"str\", (string)\n"
1329  " ...\n"
1330  " ],\n"
1331  " \"error\" : { (json object, optional)\n"
1332  " ... JSONRPC error\n"
1333  " },\n"
1334  " },\n"
1335  " ...\n"
1336  "]\n"
1337  },
1338  RPCExamples{
1339  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1340  "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1341  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1342  },
1343  }.Check(mainRequest);
1344 
1345 
1346  RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1347 
1348  EnsureLegacyScriptPubKeyMan(*wallet, true);
1349 
1350  const UniValue& requests = mainRequest.params[0];
1351 
1352  //Default options
1353  bool fRescan = true;
1354 
1355  if (!mainRequest.params[1].isNull()) {
1356  const UniValue& options = mainRequest.params[1];
1357 
1358  if (options.exists("rescan")) {
1359  fRescan = options["rescan"].get_bool();
1360  }
1361  }
1362 
1363  WalletRescanReserver reserver(pwallet);
1364  if (fRescan && !reserver.reserve()) {
1365  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1366  }
1367 
1368  int64_t now = 0;
1369  bool fRunScan = false;
1370  int64_t nLowestTimestamp = 0;
1371  UniValue response(UniValue::VARR);
1372  {
1373  auto locked_chain = pwallet->chain().lock();
1374  LOCK(pwallet->cs_wallet);
1375  EnsureWalletIsUnlocked(pwallet);
1376 
1377  // Verify all timestamps are present before importing any keys.
1378  const Optional<int> tip_height = locked_chain->getHeight();
1379  now = tip_height ? locked_chain->getBlockMedianTimePast(*tip_height) : 0;
1380  for (const UniValue& data : requests.getValues()) {
1381  GetImportTimestamp(data, now);
1382  }
1383 
1384  const int64_t minimumTimestamp = 1;
1385 
1386  if (fRescan && tip_height) {
1387  nLowestTimestamp = locked_chain->getBlockTime(*tip_height);
1388  } else {
1389  fRescan = false;
1390  }
1391 
1392  for (const UniValue& data : requests.getValues()) {
1393  const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
1394  const UniValue result = ProcessImport(pwallet, data, timestamp);
1395  response.push_back(result);
1396 
1397  if (!fRescan) {
1398  continue;
1399  }
1400 
1401  // If at least one request was successful then allow rescan.
1402  if (result["success"].get_bool()) {
1403  fRunScan = true;
1404  }
1405 
1406  // Get the lowest timestamp.
1407  if (timestamp < nLowestTimestamp) {
1408  nLowestTimestamp = timestamp;
1409  }
1410  }
1411  }
1412  if (fRescan && fRunScan && requests.size()) {
1413  int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
1414  {
1415  auto locked_chain = pwallet->chain().lock();
1416  LOCK(pwallet->cs_wallet);
1417  pwallet->ReacceptWalletTransactions();
1418  }
1419 
1420  if (pwallet->IsAbortingRescan()) {
1421  throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
1422  }
1423  if (scannedTime > nLowestTimestamp) {
1424  std::vector<UniValue> results = response.getValues();
1425  response.clear();
1426  response.setArray();
1427  size_t i = 0;
1428  for (const UniValue& request : requests.getValues()) {
1429  // If key creation date is within the successfully scanned
1430  // range, or if the import result already has an error set, let
1431  // the result stand unmodified. Otherwise replace the result
1432  // with an error message.
1433  if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
1434  response.push_back(results.at(i));
1435  } else {
1436  UniValue result = UniValue(UniValue::VOBJ);
1437  result.pushKV("success", UniValue(false));
1438  result.pushKV(
1439  "error",
1440  JSONRPCError(
1442  strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a "
1443  "block from time %d, which is after or within %d seconds of key creation, and "
1444  "could contain transactions pertaining to the key. As a result, transactions "
1445  "and coins using this key may not appear in the wallet. This error could be "
1446  "caused by pruning or data corruption (see bitcoind log for details) and could "
1447  "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1448  "and -rescan options).",
1449  GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
1450  response.push_back(std::move(result));
1451  }
1452  ++i;
1453  }
1454  }
1455  }
1456 
1457  return response;
1458 }
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:860
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:18
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:1174
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:1264
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:97
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1741
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: rpcwallet.cpp:128
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:120
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:93
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:115
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
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:3024
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:3090
std::unique_ptr< Descriptor > Parse(const std::string &descriptor, FlatSigningProvider &out, std::string &error, bool require_checksum)
Parse a descriptor string.
Definition: descriptor.cpp:990
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Definition: rpcdump.cpp:877
iterator end()
Definition: prevector.h:292
void MarkDirty()
Definition: wallet.cpp:679
Special type that is a STR with only hex chars.
#define LOCK2(cs1, cs2)
Definition: sync.h:180
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:865
static UniValue ProcessImportLegacy(ImportData &import_data, std::map< CKeyID, CPubKey > &pubkey_map, std::map< CKeyID, CKey > &privkey_map, std::set< CScript > &script_pub_keys, bool &have_solving_data, const UniValue &data, std::vector< CKeyID > &ordered_pubkeys)
Definition: rpcdump.cpp:944
Confirmation m_confirm
Definition: wallet.h:379
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:1138
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:1088
#define LOCK(cs)
Definition: sync.h:179
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:864
static const int64_t TIMESTAMP_MIN
Definition: rpcdump.cpp:78
static bool GetWalletAddressesForKey(LegacyScriptPubKeyMan *spk_man, CWallet *const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: rpcdump.cpp:57
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:116
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:863
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:88
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:766
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:1196
A transaction with a bunch of additional info that only the owner cares about.
Definition: wallet.h:253
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:859
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:60
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:868
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:125
bool IsScanning()
Definition: wallet.h:836
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:606
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:1131
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:683
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:717
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:111
std::string EncodeDestination(const CTxDestination &dest)
Definition: key_io.cpp:210
UniValue importaddress(const JSONRPCRequest &request)
Definition: rpcdump.cpp:222
A mutable version of CTransaction.
Definition: transaction.h:366
Wallet errors.
Definition: protocol.h:70
bool IsAbortingRescan()
Definition: wallet.h:835
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:84
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: rpcdump.cpp:1250
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:20
auto it
Definition: validation.cpp:362
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:3431
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
bool EnsureWalletIsAvailable(const CWallet *pwallet, bool avoidException)
Definition: rpcwallet.cpp:108
const std::string CLIENT_BUILD
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:199
CTransactionRef tx
Definition: wallet.h:349
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
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:93
bool IsCompressed() const
Check whether this is a compressed public key.
Definition: pubkey.h:180
NODISCARD bool DecodeHexTx(CMutableTransaction &tx, const std::string &hex_tx, bool try_no_witness=false, bool try_witness=true)
Definition: core_read.cpp:112