PIVX Core  5.6.99
P2P Digital Currency
rpcdump.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2014 The Bitcoin developers
2 // Copyright (c) 2014-2015 The Dash developers
3 // Copyright (c) 2015-2021 The PIVX Core developers
4 // Distributed under the MIT software license, see the accompanying
5 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
6 
7 #include "bip38.h"
8 #include "key_io.h"
9 #include "destination_io.h"
10 #include "rpc/server.h"
11 #include "sapling/key_io_sapling.h"
12 #include "script/script.h"
13 #include "script/standard.h"
14 #include "sync.h"
15 #include "util/system.h"
16 #include "utilstrencodings.h"
17 #include "utiltime.h"
18 #include "wallet/rpcwallet.h"
19 #include "wallet.h"
20 #include "validation.h"
21 
22 #include <secp256k1.h>
23 #include <stdint.h>
24 
25 #include <boost/algorithm/string.hpp>
26 #include <boost/date_time/posix_time/posix_time.hpp>
27 
28 #include <univalue.h>
29 
30 
31 int64_t static DecodeDumpTime(const std::string& str)
32 {
33  static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
34  static const std::locale loc(std::locale::classic(),
35  new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
36  std::istringstream iss(str);
37  iss.imbue(loc);
38  boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
39  iss >> ptime;
40  if (ptime.is_not_a_date_time())
41  return 0;
42  return (ptime - epoch).total_seconds();
43 }
44 
45 std::string static EncodeDumpString(const std::string& str)
46 {
47  std::stringstream ret;
48  for (unsigned char c : str) {
49  if (c <= 32 || c >= 128 || c == '%') {
50  ret << '%' << HexStr(Span<const unsigned char>(&c, 1));
51  } else {
52  ret << c;
53  }
54  }
55  return ret.str();
56 }
57 
58 std::string DecodeDumpString(const std::string& str)
59 {
60  std::stringstream ret;
61  for (unsigned int pos = 0; pos < str.length(); pos++) {
62  unsigned char c = str[pos];
63  if (c == '%' && pos + 2 < str.length()) {
64  c = (((str[pos + 1] >> 6) * 9 + ((str[pos + 1] - '0') & 15)) << 4) |
65  ((str[pos + 2] >> 6) * 9 + ((str[pos + 2] - '0') & 15));
66  pos += 2;
67  }
68  ret << c;
69  }
70  return ret.str();
71 }
72 
74 {
75  return keyOrigin.path.size() > 3 && keyOrigin.path[3] == (2 | BIP32_HARDENED_KEY_LIMIT);
76 }
77 
79 {
80  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
81 
82  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
83  return NullUniValue;
84 
85  if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
86  throw std::runtime_error(
87  "importprivkey \"privkey\" ( \"label\" rescan is_staking_address )\n"
88  "\nAdds a private key (as returned by dumpprivkey) to your wallet. Requires a new wallet backup.\n" +
89  HelpRequiringPassphrase(pwallet) + "\n"
90  "\nArguments:\n"
91  "1. \"privkey\" (string, required) The private key (see dumpprivkey)\n"
92  "2. \"label\" (string, optional, default=\"\") An optional label\n"
93  "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
94  "4. is_staking_address (boolean, optional, default=false) Whether this key refers to a (cold) staking address\n"
95  "\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\n"
96  "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"
97  "\nExamples:\n"
98  "\nDump a private key\n" +
99  HelpExampleCli("dumpprivkey", "\"myaddress\"") +
100  "\nImport the private key with rescan\n" +
101  HelpExampleCli("importprivkey", "\"mykey\"") +
102  "\nImport using a label and without rescan\n" +
103  HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
104  "\nAs a JSON-RPC call\n" +
105  HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false"));
106 
107  const std::string strSecret = request.params[0].get_str();
108  const std::string strLabel = (request.params.size() > 1 ? request.params[1].get_str() : "");
109  const bool fRescan = (request.params.size() > 2 ? request.params[2].get_bool() : true);
110 
111  WalletRescanReserver reserver(pwallet);
112  if (fRescan && !reserver.reserve()) {
113  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
114  }
115 
116  const bool fStakingAddress = (request.params.size() > 3 ? request.params[3].get_bool() : false);
117 
118  CKey key = KeyIO::DecodeSecret(strSecret);
119  if (!key.IsValid()) throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
120 
121  CPubKey pubkey = key.GetPubKey();
122  assert(key.VerifyPubKey(pubkey));
123  CKeyID vchAddress = pubkey.GetID();
124  {
125  LOCK2(cs_main, pwallet->cs_wallet);
126  EnsureWalletIsUnlocked(pwallet);
127 
128  pwallet->MarkDirty();
129  pwallet->SetAddressBook(vchAddress, strLabel, (
130  fStakingAddress ?
133 
134  // Don't throw error in case a key is already there
135  if (pwallet->HaveKey(vchAddress))
136  return NullUniValue;
137 
138  // whenever a key is imported, we need to scan the whole chain
139  pwallet->UpdateTimeFirstKey(1);
140  pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;
141 
142  if (!pwallet->AddKeyPubKey(key, pubkey))
143  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
144  }
145  if (fRescan) {
146  pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
147  }
148 
149  return NullUniValue;
150 }
151 
153 {
154  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
155 
156  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
157  return NullUniValue;
158 
159  if (request.fHelp || request.params.size() > 0)
160  throw std::runtime_error(
161  "abortrescan\n"
162  "\nStops current wallet rescan triggered e.g. by an importprivkey call.\n"
163  "\nExamples:\n"
164  "\nImport a private key\n"
165  + HelpExampleCli("importprivkey", "\"mykey\"") +
166  "\nAbort the running wallet rescan\n"
167  + HelpExampleCli("abortrescan", "") +
168  "\nAs a JSON-RPC call\n"
169  + HelpExampleRpc("abortrescan", "")
170  );
171 
172  if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) return false;
173  pwallet->AbortRescan();
174  return true;
175 }
176 
177 static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel, const std::string& strPurpose);
178 
179 static void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript)
180 {
181  if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE)
182  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
183 
184  pwallet->MarkDirty();
185 
186  if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script))
187  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
188 
189  if (isRedeemScript) {
190  if (!pwallet->HaveCScript(script) && !pwallet->AddCScript(script))
191  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
192  ImportAddress(pwallet, CScriptID(script), strLabel, "receive");
193  }
194 }
195 
196 static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel, const std::string& strPurpose)
197 {
198  CScript script = GetScriptForDestination(dest);
199  ImportScript(pwallet, script, strLabel, false);
200  // add to address book or update label
201  if (IsValidDestination(dest)) {
202  pwallet->SetAddressBook(dest, strLabel, strPurpose);
203  }
204 }
205 
207 {
208  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
209 
210  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
211  return NullUniValue;
212 
213  if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
214  throw std::runtime_error(
215  "importaddress \"script\" ( \"label\" rescan )\n"
216  "\nAdds a script (in hex), or address, that can be watched as if it were in your wallet but cannot be used to spend. Requires a new wallet backup.\n"
217  "\nArguments:\n"
218  "1. \"script\" (string, required) hex-encoded script (or address)\n"
219  "2. \"label\" (string, optional, default=\"\") An optional label\n"
220  "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
221  "4. p2sh (boolean, optional, default=false) Add the P2SH version of the script as well\n"
222  "\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\n"
223  "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"
224  "\nExamples:\n"
225  "\nImport a script with rescan\n" +
226  HelpExampleCli("importaddress", "\"myscript\"") +
227  "\nImport using a label without rescan\n" +
228  HelpExampleCli("importaddress", "\"myscript\" \"testing\" false") +
229  "\nAs a JSON-RPC call\n" +
230  HelpExampleRpc("importaddress", "\"myscript\", \"testing\", false"));
231 
232  const std::string strLabel = (request.params.size() > 1 ? request.params[1].get_str() : "");
233  // Whether to perform rescan after import
234  const bool fRescan = (request.params.size() > 2 ? request.params[2].get_bool() : true);
235 
236  WalletRescanReserver reserver(pwallet);
237  if (fRescan && !reserver.reserve()) {
238  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
239  }
240 
241  // Whether to import a p2sh version, too
242  const bool fP2SH = (request.params.size() > 3 ? request.params[3].get_bool() : false);
243 
244  {
245  LOCK2(cs_main, pwallet->cs_wallet);
246 
247  bool isStaking = false;
248  bool isExchange = false;
249  CTxDestination dest = DecodeDestination(request.params[0].get_str(), isStaking, isExchange);
250 
251  if (IsValidDestination(dest)) {
252  if (fP2SH)
253  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead");
254  ImportAddress(pwallet, dest, strLabel, isStaking ?
257 
258  } else if (IsHex(request.params[0].get_str())) {
259  std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
260  ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH);
261  } else {
262  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address or script");
263  }
264  }
265  if (fRescan) {
266  pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
267  pwallet->ReacceptWalletTransactions();
268  }
269 
270  return NullUniValue;
271 }
272 
274 {
275  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
276 
277  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
278  return NullUniValue;
279 
280  if (request.fHelp || request.params.size() < 1 || request.params.size() > 4)
281  throw std::runtime_error(
282  "importpubkey \"pubkey\" ( \"label\" rescan )\n"
283  "\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"
284  "\nArguments:\n"
285  "1. \"pubkey\" (string, required) The hex-encoded public key\n"
286  "2. \"label\" (string, optional, default=\"\") An optional label\n"
287  "3. rescan (boolean, optional, default=true) Rescan the wallet for transactions\n"
288  "\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\n"
289  "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"
290  "\nExamples:\n"
291  "\nImport a public key with rescan\n"
292  + HelpExampleCli("importpubkey", "\"mypubkey\"") +
293  "\nImport using a label without rescan\n"
294  + HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
295  "\nAs a JSON-RPC call\n"
296  + HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")
297  );
298 
299  const std::string strLabel = (request.params.size() > 1 ? request.params[1].get_str() : "");
300  // Whether to perform rescan after import
301  const bool fRescan = (request.params.size() > 2 ? request.params[2].get_bool() : true);
302 
303  WalletRescanReserver reserver(pwallet);
304  if (fRescan && !reserver.reserve()) {
305  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
306  }
307 
308  if (!IsHex(request.params[0].get_str()))
309  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
310  std::vector<unsigned char> data(ParseHex(request.params[0].get_str()));
311  CPubKey pubKey(data.begin(), data.end());
312  if (!pubKey.IsFullyValid())
313  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
314 
315  {
316  LOCK2(cs_main, pwallet->cs_wallet);
317 
318  ImportAddress(pwallet, pubKey.GetID(), strLabel, "receive");
319  ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false);
320  }
321  if (fRescan) {
322  pwallet->RescanFromTime(TIMESTAMP_MIN, reserver, true /* update */);
323  pwallet->ReacceptWalletTransactions();
324  }
325 
326  return NullUniValue;
327 }
328 
329 // TODO: Needs further review over the HD flow, staking addresses and multisig import.
331 {
332  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
333 
334  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
335  return NullUniValue;
336 
337  if (request.fHelp || request.params.size() != 1)
338  throw std::runtime_error(
339  "importwallet \"filename\"\n"
340  "\nImports keys from a wallet dump file (see dumpwallet). Requires a new wallet backup.\n" +
341  HelpRequiringPassphrase(pwallet) + "\n"
342  "\nArguments:\n"
343  "1. \"filename\" (string, required) The wallet file\n"
344 
345  "\nExamples:\n"
346  "\nDump the wallet\n" +
347  HelpExampleCli("dumpwallet", "\"test\"") +
348  "\nImport the wallet\n" +
349  HelpExampleCli("importwallet", "\"test\"") +
350  "\nImport using the json rpc call\n" +
351  HelpExampleRpc("importwallet", "\"test\""));
352 
353  fsbridge::ifstream file;
354  file.open(request.params[0].get_str(), std::ios::in | std::ios::ate);
355  if (!file.is_open()) {
356  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
357  }
358 
359  WalletRescanReserver reserver(pwallet);
360  if (!reserver.reserve()) {
361  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
362  }
363 
364  int64_t nTimeBegin = 0;
365  bool fGood = true;
366  {
367  LOCK2(cs_main, pwallet->cs_wallet);
368  EnsureWalletIsUnlocked(pwallet);
369 
370  nTimeBegin = chainActive.Tip()->GetBlockTime();
371  int64_t nFilesize = std::max((int64_t)1, (int64_t)file.tellg());
372  file.seekg(0, file.beg);
373 
374  pwallet->ShowProgress(_("Importing..."), 0); // show progress dialog in GUI
375  while (file.good()) {
376  pwallet->ShowProgress("", std::max(1, std::min(99, (int)(((double)file.tellg() / (double)nFilesize) * 100))));
377  std::string line;
378  std::getline(file, line);
379  if (line.empty() || line[0] == '#')
380  continue;
381 
382  std::vector<std::string> vstr;
383  boost::split(vstr, line, boost::is_any_of(" "));
384  if (vstr.size() < 2)
385  continue;
386 
387  // Sapling keys
388  // Let's see if the address is a valid PIVX spending key
389  if (pwallet->HasSaplingSPKM()) {
390  libzcash::SpendingKey spendingkey = KeyIO::DecodeSpendingKey(vstr[0]);
391  int64_t nTime = DecodeDumpTime(vstr[1]);
392  if (IsValidSpendingKey(spendingkey)) {
393  libzcash::SaplingExtendedSpendingKey saplingSpendingKey = *boost::get<libzcash::SaplingExtendedSpendingKey>(&spendingkey);
394  auto addResult = pwallet->GetSaplingScriptPubKeyMan()->AddSpendingKeyToWallet(
395  Params().GetConsensus(), saplingSpendingKey, nTime);
396  if (addResult == KeyAlreadyExists) {
397  LogPrint(BCLog::SAPLING, "Skipping import of shielded addr (key already present)\n");
398  } else if (addResult == KeyNotAdded) {
399  // Something went wrong
400  fGood = false;
401  }
402  continue;
403  }
404  }
405 
406  CKey key = KeyIO::DecodeSecret(vstr[0]);
407  if (!key.IsValid())
408  continue;
409  CPubKey pubkey = key.GetPubKey();
410  assert(key.VerifyPubKey(pubkey));
411  CKeyID keyid = pubkey.GetID();
412  if (pwallet->HaveKey(keyid)) {
413  LogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(keyid));
414  continue;
415  }
416  int64_t nTime = DecodeDumpTime(vstr[1]);
417  std::string strLabel;
418  bool fLabel = true;
419  for (unsigned int nStr = 2; nStr < vstr.size(); nStr++) {
420  const std::string& type = vstr[nStr];
421  if (boost::algorithm::starts_with(type, "#"))
422  break;
423  if (type == "change=1")
424  fLabel = false;
425  else if (type == "reserve=1")
426  fLabel = false;
427  else if (type == "hdseed")
428  fLabel = false;
429  if (boost::algorithm::starts_with(type, "label=")) {
430  strLabel = DecodeDumpString(vstr[nStr].substr(6));
431  fLabel = true;
432  }
433  }
434  LogPrintf("Importing %s...\n", EncodeDestination(keyid));
435  if (!pwallet->AddKeyPubKey(key, pubkey)) {
436  fGood = false;
437  continue;
438  }
439  pwallet->mapKeyMetadata[keyid].nCreateTime = nTime;
440  if (fLabel) // TODO: This is not entirely true.. needs to be reviewed properly.
441  pwallet->SetAddressBook(keyid, strLabel, AddressBook::AddressBookPurpose::RECEIVE);
442  nTimeBegin = std::min(nTimeBegin, nTime);
443  }
444  file.close();
445  pwallet->ShowProgress("", 100); // hide progress dialog in GUI
446  pwallet->UpdateTimeFirstKey(nTimeBegin);
447  }
448  pwallet->RescanFromTime(nTimeBegin, reserver, false /* update */);
449  pwallet->MarkDirty();
450 
451  if (!fGood)
452  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding some keys to wallet");
453 
454  return NullUniValue;
455 }
456 
458 {
459  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
460 
461  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
462  return NullUniValue;
463 
464  if (request.fHelp || request.params.size() != 1)
465  throw std::runtime_error(
466  "dumpprivkey \"address\"\n"
467  "\nReveals the private key corresponding to 'address'.\n"
468  "Then the importprivkey can be used with this output\n" +
469  HelpRequiringPassphrase(pwallet) + "\n"
470 
471  "\nArguments:\n"
472  "1. \"address\" (string, required) The pivx address for the private key\n"
473 
474  "\nResult:\n"
475  "\"key\" (string) The private key\n"
476 
477  "\nExamples:\n" +
478  HelpExampleCli("dumpprivkey", "\"myaddress\"") + HelpExampleCli("importprivkey", "\"mykey\"") + HelpExampleRpc("dumpprivkey", "\"myaddress\""));
479 
480  LOCK2(cs_main, pwallet->cs_wallet);
481 
482  EnsureWalletIsUnlocked(pwallet);
483 
484  std::string strAddress = request.params[0].get_str();
485  CTxDestination dest = DecodeDestination(strAddress);
486  if (!IsValidDestination(dest))
487  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
488  const CKeyID* keyID = boost::get<CKeyID>(&dest);
489  if (!keyID)
490  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
491  CKey vchSecret;
492  if (!pwallet->GetKey(*keyID, vchSecret))
493  throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
494  return KeyIO::EncodeSecret(vchSecret);
495 }
496 
498 {
499  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
500 
501  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
502  return NullUniValue;
503 
504  if (request.fHelp || request.params.size() != 1)
505  throw std::runtime_error(
506  "dumpwallet \"filename\"\n"
507  "\nDumps all wallet keys in a human-readable format to a server-side file. This does not allow overwriting existing files.\n"
508  "Imported scripts are not currently included in wallet dumps, these must be backed up separately.\n"
509  "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"
510  "only backing up the seed itself, and must be backed up too (e.g. ensure you back up the whole dumpfile).\n" +
511  HelpRequiringPassphrase(pwallet) + "\n"
512  "\nArguments:\n"
513  "1. \"filename\" (string, required) The filename\n"
514 
515  "\nResult:\n"
516  "{\n"
517  " \"filename\": \"xxxx\", (string) The full path to the wallet dump file.\n"
518  " \"warning\": \"xxxx\" (string) A warning message about the exact contents of this file.\n"
519  "}\n"
520 
521  "\nExamples:\n" +
522  HelpExampleCli("dumpwallet", "\"test\"") + HelpExampleRpc("dumpwallet", "\"test\""));
523 
524  if (request.params[0].get_str().find("bug") != std::string::npos ||
525  request.params[0].get_str().find("log") != std::string::npos) {
526  throw JSONRPCError(RPC_MISC_ERROR, "Scam attempt detected!");
527  }
528 
529  // Make sure the results are valid at least up to the most recent block
530  // the user could have gotten from another RPC command prior to now
532 
533  LOCK2(cs_main, pwallet->cs_wallet);
534 
535  EnsureWalletIsUnlocked(pwallet);
536 
537  ScriptPubKeyMan* spk_man = pwallet->GetScriptPubKeyMan();
538 
539  fs::path filepath = request.params[0].get_str().c_str();
540  filepath = fs::absolute(filepath);
541 
542  /* Prevent arbitrary files from being overwritten. There have been reports
543  * that users have overwritten wallet files this way:
544  * https://github.com/bitcoin/bitcoin/issues/9934
545  * It may also avoid other security issues.
546  */
547  if (fs::exists(filepath)) {
548  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");
549  }
550 
551  fsbridge::ofstream file;
552  file.open(filepath);
553  if (!file.is_open())
554  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot open wallet dump file");
555 
556  std::map<CKeyID, int64_t> mapKeyBirth;
557  pwallet->GetKeyBirthTimes(mapKeyBirth);
558  const std::map<CKeyID, int64_t>& mapKeyPool = spk_man->GetAllReserveKeys();
559 
560 
561  // sort time/key pairs
562  std::vector<std::pair<int64_t, CKeyID> > vKeyBirth;
563  for (const auto& entry : mapKeyBirth) {
564  vKeyBirth.emplace_back(entry.second, entry.first);
565  }
566  mapKeyBirth.clear();
567  std::sort(vKeyBirth.begin(), vKeyBirth.end());
568 
569  CBlockIndex* tip = chainActive.Tip();
570  // produce output
571  file << strprintf("# Wallet dump created by PIVX %s\n", CLIENT_BUILD);
572  file << strprintf("# * Created on %s\n", FormatISO8601DateTime(GetTime()));
573  if (tip) {
574  file << strprintf("# * Best block at time of backup was %i (%s),\n", tip->nHeight,
575  tip->GetBlockHash().ToString());
576  file << strprintf("# mined on %s\n", FormatISO8601DateTime(tip->GetBlockTime()));
577  } else {
578  file << "# Missing tip information\n";
579  }
580  file << "\n";
581 
582  // Add the base58check encoded extended master if the wallet uses HD
583  CKeyID seed_id = spk_man->GetHDChain().GetID();
584  if (!seed_id.IsNull())
585  {
586  CKey seed;
587  if (pwallet->GetKey(seed_id, seed)) {
588  CExtKey masterKey;
589  masterKey.SetSeed(seed.begin(), seed.size());
590 
591  file << "# extended private masterkey: " << KeyIO::EncodeExtKey(masterKey) << "\n\n";
592  }
593  }
594 
595  for (std::vector<std::pair<int64_t, CKeyID> >::const_iterator it = vKeyBirth.begin(); it != vKeyBirth.end(); it++) {
596  const CKeyID& keyid = it->second;
597  std::string strTime = FormatISO8601DateTime(it->first);
598  CKey key;
599  if (pwallet->GetKey(keyid, key)) {
600  const CKeyMetadata& metadata = pwallet->mapKeyMetadata[keyid];
601  std::string strAddr = EncodeDestination(keyid, (metadata.HasKeyOrigin() && IsStakingDerPath(metadata.key_origin) ?
604 
605  file << strprintf("%s %s ", KeyIO::EncodeSecret(key), strTime);
606  if (pwallet->HasAddressBook(keyid)) {
607  file << strprintf("label=%s", EncodeDumpString(pwallet->GetNameForAddressBookEntry(keyid)));
608  } else if (keyid == seed_id) {
609  file << "hdseed=1";
610  } else if (mapKeyPool.count(keyid)) {
611  file << "reserve=1";
612  } else {
613  file << "change=1";
614  }
615  file << strprintf(" # addr=%s%s\n", strAddr, (metadata.HasKeyOrigin() ? " hdkeypath="+metadata.key_origin.pathToString() : ""));
616  }
617  }
618 
619  // Sapling
620  file << "# Sapling keys\n";
621  file << "\n";
622  std::set<libzcash::SaplingPaymentAddress> saplingAddresses;
623  pwallet->GetSaplingPaymentAddresses(saplingAddresses);
624  file << "\n";
625  for (const auto& addr : saplingAddresses) {
627  if (pwallet->GetSaplingExtendedSpendingKey(addr, extsk)) {
628  auto ivk = extsk.expsk.full_viewing_key().in_viewing_key();
630  std::string strTime = FormatISO8601DateTime(keyMeta.nCreateTime);
631  // Keys imported with importsaplingkey do not have key origin metadata
632  file << strprintf("%s %s # shielded_addr=%s%s\n",
634  strTime,
636  (keyMeta.HasKeyOrigin() ? " hdkeypath=" + keyMeta.key_origin.pathToString() : "")
637  );
638  }
639  }
640 
641  file << "\n";
642  file << "# End of dump\n";
643  file.close();
644 
645  UniValue reply(UniValue::VOBJ);
646  reply.pushKV("filename", filepath.string());
647  reply.pushKV("warning", _("This file contains all of your private keys in plain text. DO NOT send this file to anyone!"));
648 
649  return reply;
650 }
651 
652 static UniValue processImport(CWallet* const pwallet, const UniValue& data, const int64_t timestamp)
653 {
654  try {
655  bool success = false;
656 
657  // Required fields.
658  const UniValue& scriptPubKey = data["scriptPubKey"];
659 
660  // Should have script or JSON with "address".
661  if (!(scriptPubKey.getType() == UniValue::VOBJ && scriptPubKey.exists("address")) && !(scriptPubKey.getType() == UniValue::VSTR)) {
662  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid scriptPubKey");
663  }
664 
665  // Optional fields.
666  const std::string& strRedeemScript = data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
667  const UniValue& pubKeys = data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
668  const UniValue& keys = data.exists("keys") ? data["keys"].get_array() : UniValue();
669  const bool internal = data.exists("internal") ? data["internal"].get_bool() : false;
670  const bool watchOnly = data.exists("watchonly") ? data["watchonly"].get_bool() : false;
671  const std::string& label = data.exists("label") && !internal ? data["label"].get_str() : "";
672 
673  bool isScript = scriptPubKey.getType() == UniValue::VSTR;
674  bool isP2SH = strRedeemScript.length() > 0;
675  const std::string& output = isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
676 
677  // Parse the output.
678  CScript script;
679  CTxDestination dest;
680 
681  if (!isScript) {
682  dest = DecodeDestination(output);
683  if (!IsValidDestination(dest)) {
684  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid address");
685  }
686  script = GetScriptForDestination(dest);
687  } else {
688  if (!IsHex(output)) {
689  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid scriptPubKey");
690  }
691  std::vector<unsigned char> vData(ParseHex(output));
692  script = CScript(vData.begin(), vData.end());
693  }
694 
695  // Watchonly and private keys
696  if (watchOnly && keys.size()) {
697  throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between watchonly and keys");
698  }
699 
700  // Internal + Label
701  if (internal && data.exists("label")) {
702  throw JSONRPCError(RPC_INVALID_PARAMETER, "Incompatibility found between internal and label");
703  }
704 
705  // Not having Internal + Script
706  if (!internal && isScript) {
707  throw JSONRPCError(RPC_INVALID_PARAMETER, "Internal must be set for hex scriptPubKey");
708  }
709 
710  // Keys / PubKeys size check.
711  if (!isP2SH && (keys.size() > 1 || pubKeys.size() > 1)) { // Address / scriptPubKey
712  throw JSONRPCError(RPC_INVALID_PARAMETER, "More than private key given for one address");
713  }
714 
715  // Invalid P2SH redeemScript
716  if (isP2SH && !IsHex(strRedeemScript)) {
717  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid redeem script");
718  }
719 
720  // Process. //
721 
722  // P2SH
723  if (isP2SH) {
724  // Import redeem script.
725  std::vector<unsigned char> vData(ParseHex(strRedeemScript));
726  CScript redeemScript = CScript(vData.begin(), vData.end());
727 
728  // Invalid P2SH address
729  if (!script.IsPayToScriptHash()) {
730  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid P2SH address / script");
731  }
732 
733  pwallet->MarkDirty();
734 
735  if (!pwallet->HaveWatchOnly(redeemScript) && !pwallet->AddWatchOnly(redeemScript)) {
736  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
737  }
738 
739  if (!pwallet->HaveCScript(redeemScript) && !pwallet->AddCScript(redeemScript)) {
740  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet");
741  }
742 
743  CTxDestination redeem_dest = CScriptID(redeemScript);
744  CScript redeemDestination = GetScriptForDestination(redeem_dest);
745 
746  if (::IsMine(*pwallet, redeemDestination) == ISMINE_SPENDABLE) {
747  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
748  }
749 
750  pwallet->MarkDirty();
751 
752  if (!pwallet->HaveWatchOnly(redeemDestination) && !pwallet->AddWatchOnly(redeemDestination)) {
753  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
754  }
755 
756  // add to address book or update label
757  if (IsValidDestination(dest)) {
758  pwallet->SetAddressBook(dest, label, "receive");
759  }
760 
761  // Import private keys.
762  if (keys.size()) {
763  for (size_t i = 0; i < keys.size(); i++) {
764  const std::string& privkey = keys[i].get_str();
765  CKey key = KeyIO::DecodeSecret(privkey);
766 
767  if (!key.IsValid()) {
768  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
769  }
770 
771  CPubKey pubkey = key.GetPubKey();
772  assert(key.VerifyPubKey(pubkey));
773 
774  CKeyID vchAddress = pubkey.GetID();
775  pwallet->MarkDirty();
776  pwallet->SetAddressBook(vchAddress, label, "receive");
777 
778  if (pwallet->HaveKey(vchAddress)) {
779  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Already have this key");
780  }
781 
782  pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
783 
784  if (!pwallet->AddKeyPubKey(key, pubkey)) {
785  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
786  }
787 
788  if (timestamp < pwallet->nTimeFirstKey) {
789  pwallet->nTimeFirstKey = timestamp;
790  }
791  }
792  }
793 
794  success = true;
795  } else {
796  // Import public keys.
797  if (pubKeys.size() && keys.size() == 0) {
798  const std::string& strPubKey = pubKeys[0].get_str();
799 
800  if (!IsHex(strPubKey)) {
801  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey must be a hex string");
802  }
803 
804  std::vector<unsigned char> vData(ParseHex(strPubKey));
805  CPubKey pubKey(vData.begin(), vData.end());
806 
807  if (!pubKey.IsFullyValid()) {
808  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Pubkey is not a valid public key");
809  }
810 
811  CTxDestination pubkey_dest = pubKey.GetID();
812 
813  // Consistency check.
814  if (!isScript && !(pubkey_dest == dest)) {
815  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
816  }
817 
818  // Consistency check.
819  if (isScript) {
820  CTxDestination destination;
821  if (ExtractDestination(script, destination) && !(destination == pubkey_dest)) {
822  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
823  }
824  }
825 
826  CScript pubKeyScript = GetScriptForDestination(pubkey_dest);
827 
828  if (::IsMine(*pwallet, pubKeyScript) == ISMINE_SPENDABLE) {
829  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
830  }
831 
832  pwallet->MarkDirty();
833 
834  if (!pwallet->HaveWatchOnly(pubKeyScript) && !pwallet->AddWatchOnly(pubKeyScript)) {
835  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
836  }
837 
838  // add to address book or update label
839  if (IsValidDestination(pubkey_dest)) {
840  pwallet->SetAddressBook(pubkey_dest, label, "receive");
841  }
842 
843  // TODO Is this necessary?
844  CScript scriptRawPubKey = GetScriptForRawPubKey(pubKey);
845 
846  if (::IsMine(*pwallet, scriptRawPubKey) == ISMINE_SPENDABLE) {
847  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
848  }
849 
850  pwallet->MarkDirty();
851 
852  if (!pwallet->HaveWatchOnly(scriptRawPubKey) && !pwallet->AddWatchOnly(scriptRawPubKey)) {
853  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
854  }
855 
856  success = true;
857  }
858 
859  // Import private keys.
860  if (keys.size()) {
861  const std::string& strPrivkey = keys[0].get_str();
862  CKey key = KeyIO::DecodeSecret(strPrivkey);
863 
864  if (!key.IsValid()) {
865  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid private key encoding");
866  }
867 
868  CPubKey pubKey = key.GetPubKey();
869  assert(key.VerifyPubKey(pubKey));
870 
871  CTxDestination pubkey_dest = pubKey.GetID();
872 
873  // Consistency check.
874  if (!isScript && !(pubkey_dest == dest)) {
875  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
876  }
877 
878  // Consistency check.
879  if (isScript) {
880  CTxDestination destination;
881  if (ExtractDestination(script, destination) && !(destination == pubkey_dest)) {
882  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Consistency check failed");
883  }
884  }
885 
886  CKeyID vchAddress = pubKey.GetID();
887  pwallet->MarkDirty();
888  pwallet->SetAddressBook(vchAddress, label, "receive");
889 
890  if (pwallet->HaveKey(vchAddress)) {
891  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
892  }
893 
894  pwallet->mapKeyMetadata[vchAddress].nCreateTime = timestamp;
895 
896  if (!pwallet->AddKeyPubKey(key, pubKey)) {
897  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
898  }
899 
900  if (timestamp < pwallet->nTimeFirstKey) {
901  pwallet->nTimeFirstKey = timestamp;
902  }
903 
904  success = true;
905  }
906 
907  // Import scriptPubKey only.
908  if (pubKeys.size() == 0 && keys.size() == 0) {
909  if (::IsMine(*pwallet, script) == ISMINE_SPENDABLE) {
910  throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script");
911  }
912 
913  pwallet->MarkDirty();
914 
915  if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script)) {
916  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet");
917  }
918 
919  if (scriptPubKey.getType() == UniValue::VOBJ) {
920  // add to address book or update label
921  if (IsValidDestination(dest)) {
922  pwallet->SetAddressBook(dest, label, "receive");
923  }
924  }
925 
926  success = true;
927  }
928  }
929 
930  UniValue result = UniValue(UniValue::VOBJ);
931  result.pushKV("success", UniValue(success));
932  return result;
933  } catch (const UniValue& e) {
934  UniValue result = UniValue(UniValue::VOBJ);
935  result.pushKV("success", UniValue(false));
936  result.pushKV("error", e);
937  return result;
938  } catch (...) {
939  UniValue result = UniValue(UniValue::VOBJ);
940  result.pushKV("success", UniValue(false));
941  result.pushKV("error", JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
942  return result;
943  }
944 }
945 
946 static int64_t GetImportTimestamp(const UniValue& data, int64_t now)
947 {
948  if (data.exists("timestamp")) {
949  const UniValue& timestamp = data["timestamp"];
950  if (timestamp.isNum()) {
951  return timestamp.get_int64();
952  } else if (timestamp.isStr() && timestamp.get_str() == "now") {
953  return now;
954  }
955  throw JSONRPCError(RPC_TYPE_ERROR, strprintf("Expected number or \"now\" timestamp value for key. got type %s", uvTypeName(timestamp.type())));
956  }
957  throw JSONRPCError(RPC_TYPE_ERROR, "Missing required timestamp field for key");
958 }
959 
961 {
962  CWallet * const pwallet = GetWalletForJSONRPCRequest(mainRequest);
963 
964  if (!EnsureWalletIsAvailable(pwallet, mainRequest.fHelp))
965  return NullUniValue;
966 
967  if (mainRequest.fHelp || mainRequest.params.size() < 1 || mainRequest.params.size() > 2)
968  throw std::runtime_error(
969  "importmulti \"requests\" ( \"options\" )\n"
970  "\nImport addresses/scripts (with private or public keys, redeem script (P2SH)), rescanning all addresses in one-shot-only (rescan can be disabled via options). Requires a new wallet backup.\n" +
971  HelpRequiringPassphrase(pwallet) + "\n"
972 
973  "\nArguments:\n"
974  "1. requests (array, required) Data to be imported\n"
975  " [ (array of json objects)\n"
976  " {\n"
977  " \"scriptPubKey\": \"script\" | { \"address\":\"address\" }, (string / JSON, required) Type of scriptPubKey (string for script, json for address)\n"
978  " \"timestamp\": timestamp | \"now\" (integer / string, required) Creation time of the key in seconds since epoch (Jan 1 1970 GMT),\n"
979  " or the string \"now\" to substitute the current synced blockchain time. The timestamp of the oldest\n"
980  " key will determine how far back blockchain rescans need to begin for missing wallet transactions.\n"
981  " \"now\" can be specified to bypass scanning, for keys which are known to never have been used, and\n"
982  " 0 can be specified to scan the entire blockchain. Blocks up to 2 hours before the earliest key\n"
983  " creation time of all keys being imported by the importmulti call will be scanned.\n"
984  " \"redeemscript\": \"script\", (string, optional) Allowed only if the scriptPubKey is a P2SH address or a P2SH scriptPubKey\n"
985  " \"pubkeys\": [\"pubKey\", ... ], (array, optional) Array of strings giving pubkeys that must occur in the output or redeemscript\n"
986  " \"keys\": [\"key\", ... ], (array, optional) Array of strings giving private keys whose corresponding public keys must occur in the output or redeemscript\n"
987  " \"internal\": true|false, (boolean, optional, default: false) Stating whether matching outputs should be be treated as not incoming payments\n"
988  " \"watchonly\": true|false, (boolean, optional, default: false) Stating whether matching outputs should be considered watched even when they're not spendable, only allowed if keys are empty\n"
989  " \"label\": label, (string, optional, default: '') Label to assign to the address, only allowed with internal=false\n"
990  " }\n"
991  " ,...\n"
992  " ]\n"
993  "2. options (JSON, optional)\n"
994  " {\n"
995  " \"rescan\": true|false, (boolean, optional, default: true) Stating if should rescan the blockchain after all imports\n"
996  " }\n"
997 
998  "\nResult:\n"
999  "[ (Array) An array with the same size as the input that has the execution result\n"
1000  " {\n"
1001  " \"success\": true|false, (boolean) True if import succeeded, otherwise false\n"
1002  " \"error\": { (JSON Object) Object containing error information. Only present when import fails\n"
1003  " \"code\": n, (numeric) The error code\n"
1004  " \"message\": xxxx (string) The error message\n"
1005  " }\n"
1006  " }\n"
1007  " ,...\n"
1008  "]\n"
1009  "\nNote: This call can take minutes to complete if rescan is true, during that time, other rpc calls\n"
1010  "may report that the imported keys, addresses or scripts exists but related transactions are still missing.\n"
1011  "\nExamples:\n" +
1012  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }, "
1013  "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" }, \"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1014  HelpExampleCli("importmulti", "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, \"timestamp\":1455191478 }]' '{ \"rescan\": false}'"));
1015 
1016  RPCTypeCheck(mainRequest.params, {UniValue::VARR, UniValue::VOBJ});
1017  const UniValue& requests = mainRequest.params[0];
1018 
1019  //Default options
1020  bool fRescan = true;
1021 
1022  if (mainRequest.params.size() > 1) {
1023  const UniValue& options = mainRequest.params[1];
1024 
1025  if (options.exists("rescan")) {
1026  fRescan = options["rescan"].get_bool();
1027  }
1028  }
1029 
1030  WalletRescanReserver reserver(pwallet);
1031  if (fRescan && !reserver.reserve()) {
1032  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1033  }
1034 
1035  int64_t now = 0;
1036  bool fRunScan = false;
1037  int64_t nLowestTimestamp = 0;
1038 
1039  UniValue response(UniValue::VARR);
1040  {
1041  LOCK2(cs_main, pwallet->cs_wallet);
1042  EnsureWalletIsUnlocked(pwallet);
1043 
1044  // Verify all timestamps are present before importing any keys.
1045  int64_t now = chainActive.Tip() ? chainActive.Tip()->GetMedianTimePast() : 0;
1046  for (const UniValue& data : requests.getValues()) {
1047  GetImportTimestamp(data, now);
1048  }
1049 
1050  const int64_t minimumTimestamp = 1;
1051 
1052  if (fRescan && chainActive.Tip()) {
1053  nLowestTimestamp = chainActive.Tip()->GetBlockTime();
1054  } else {
1055  fRescan = false;
1056  }
1057 
1058  for (const UniValue& data: requests.getValues()) {
1059  const int64_t timestamp = std::max(GetImportTimestamp(data, now), minimumTimestamp);
1060  const UniValue result = processImport(pwallet, data, timestamp);
1061  response.push_back(result);
1062 
1063  if (!fRescan) {
1064  continue;
1065  }
1066 
1067  // If at least one request was successful then allow rescan.
1068  if (result["success"].get_bool()) {
1069  fRunScan = true;
1070  }
1071 
1072  // Get the lowest timestamp.
1073  if (timestamp < nLowestTimestamp) {
1074  nLowestTimestamp = timestamp;
1075  }
1076  }
1077  }
1078  if (fRescan && fRunScan && requests.size()) {
1079  int64_t scannedTime = pwallet->RescanFromTime(nLowestTimestamp, reserver, true /* update */);
1080  pwallet->ReacceptWalletTransactions();
1081 
1082  if (scannedTime > nLowestTimestamp) {
1083  std::vector<UniValue> results = response.getValues();
1084  response.clear();
1085  response.setArray();
1086  size_t i = 0;
1087  for (const UniValue& request : requests.getValues()) {
1088  // If key creation date is within the successfully scanned
1089  // range, or if the import result already has an error set, let
1090  // the result stand unmodified. Otherwise replace the result
1091  // with an error message.
1092  if (scannedTime <= GetImportTimestamp(request, now) || results.at(i).exists("error")) {
1093  response.push_back(results.at(i));
1094  } else {
1095  UniValue result = UniValue(UniValue::VOBJ);
1096  result.pushKV("success", UniValue(false));
1097  result.pushKV("error", JSONRPCError(RPC_MISC_ERROR,
1098  strprintf("Rescan failed for key with creation timestamp %d. There was an error reading a "
1099  "block from time %d, which is after or within %d seconds of key creation, and "
1100  "could contain transactions pertaining to the key. As a result, transactions "
1101  "and coins using this key may not appear in the wallet. This error could be "
1102  "caused by pruning or data corruption (see pivxd log for details) and could "
1103  "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1104  "and -rescan options).",
1105  GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
1106  response.push_back(std::move(result));
1107  }
1108  ++i;
1109  }
1110  }
1111  }
1112 
1113  return response;
1114 }
1115 
1117 {
1118  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
1119 
1120  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
1121  return NullUniValue;
1122 
1123  if (request.fHelp || request.params.size() != 2)
1124  throw std::runtime_error(
1125  "bip38encrypt \"address\" \"passphrase\"\n"
1126  "\nEncrypts a private key corresponding to 'address'.\n" +
1127  HelpRequiringPassphrase(pwallet) + "\n"
1128 
1129  "\nArguments:\n"
1130  "1. \"address\" (string, required) The pivx address for the private key (you must hold the key already)\n"
1131  "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with - Valid special chars: !#$%&'()*+,-./:;<=>?`{|}~ \n"
1132 
1133  "\nResult:\n"
1134  "\"key\" (string) The encrypted private key\n"
1135 
1136  "\nExamples:\n" +
1137  HelpExampleCli("bip38encrypt", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" \"mypasphrase\"") +
1138  HelpExampleRpc("bip38encrypt", "\"DMJRSsuU9zfyrvxVaAEFQqK4MxZg6vgeS6\" \"mypasphrase\""));
1139 
1140  LOCK2(cs_main, pwallet->cs_wallet);
1141 
1142  EnsureWalletIsUnlocked(pwallet);
1143 
1144  std::string strAddress = request.params[0].get_str();
1145  std::string strPassphrase = request.params[1].get_str();
1146 
1147  CTxDestination address = DecodeDestination(strAddress);
1148  if (!IsValidDestination(address))
1149  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid PIVX address");
1150  const CKeyID* keyID = boost::get<CKeyID>(&address);
1151  if (!keyID)
1152  throw JSONRPCError(RPC_TYPE_ERROR, "Address does not refer to a key");
1153  CKey vchSecret;
1154  if (!pwallet->GetKey(*keyID, vchSecret))
1155  throw JSONRPCError(RPC_WALLET_ERROR, "Private key for address " + strAddress + " is not known");
1156 
1157  uint256 privKey = vchSecret.GetPrivKey_256();
1158  std::string encryptedOut = BIP38_Encrypt(strAddress, strPassphrase, privKey, vchSecret.IsCompressed());
1159 
1160  UniValue result(UniValue::VOBJ);
1161  result.pushKV("Address", strAddress);
1162  result.pushKV("Encrypted Key", encryptedOut);
1163 
1164  return result;
1165 }
1166 
1168 {
1169  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
1170 
1171  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
1172  return NullUniValue;
1173 
1174  if (request.fHelp || request.params.size() != 2)
1175  throw std::runtime_error(
1176  "bip38decrypt \"encrypted_key\" \"passphrase\"\n"
1177  "\nDecrypts and then imports password protected private key.\n" +
1178  HelpRequiringPassphrase(pwallet) + "\n"
1179 
1180  "\nArguments:\n"
1181  "1. \"encrypted_key\" (string, required) The encrypted private key\n"
1182  "2. \"passphrase\" (string, required) The passphrase you want the private key to be encrypted with\n"
1183 
1184  "\nResult:\n"
1185  "\"key\" (string) The decrypted private key\n"
1186 
1187  "\nExamples:\n" +
1188  HelpExampleCli("bip38decrypt", "\"encryptedkey\" \"mypassphrase\"") +
1189  HelpExampleRpc("bip38decrypt", "\"encryptedkey\" \"mypassphrase\""));
1190 
1191 
1193  std::string strKey = request.params[0].get_str();
1194  std::string strPassphrase = request.params[1].get_str();
1195 
1196  uint256 privKey;
1197  bool fCompressed;
1198  if (!BIP38_Decrypt(strPassphrase, strKey, privKey, fCompressed))
1199  throw JSONRPCError(RPC_WALLET_ERROR, "Failed To Decrypt");
1200 
1201  UniValue result(UniValue::VOBJ);
1202  result.pushKV("privatekey", HexStr(privKey));
1203 
1204  CKey key;
1205  key.Set(privKey.begin(), privKey.end(), fCompressed);
1206 
1207  if (!key.IsValid())
1208  throw JSONRPCError(RPC_WALLET_ERROR, "Private Key Not Valid");
1209 
1210  WalletRescanReserver reserver(pwallet);
1211  if (!reserver.reserve()) {
1212  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1213  }
1214 
1215  CPubKey pubkey = key.GetPubKey();
1216  assert(key.VerifyPubKey(pubkey));
1217  result.pushKV("Address", EncodeDestination(pubkey.GetID()));
1218  CKeyID vchAddress = pubkey.GetID();
1219  {
1220  LOCK2(cs_main, pwallet->cs_wallet);
1221  EnsureWalletIsUnlocked(pwallet);
1222  pwallet->MarkDirty();
1223  pwallet->SetAddressBook(vchAddress, "", AddressBook::AddressBookPurpose::RECEIVE);
1224 
1225  // Don't throw error in case a key is already there
1226  if (pwallet->HaveKey(vchAddress))
1227  throw JSONRPCError(RPC_WALLET_ERROR, "Key already held by wallet");
1228 
1229  pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1;
1230 
1231  if (!pwallet->AddKeyPubKey(key, pubkey))
1232  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1233  }
1234 
1235  // whenever a key is imported, we need to scan the whole chain
1236  pwallet->ScanForWalletTransactions(chainActive.Genesis(), nullptr, reserver, true);
1237 
1238  return result;
1239 }
1240 
1241 // Sapling
1242 
1244 {
1245  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
1246 
1247  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
1248  return NullUniValue;
1249 
1250  if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
1251  throw std::runtime_error(
1252  "importsaplingkey \"key\" ( rescan height )\n"
1253  "\nAdds a key (as returned by exportsaplingkey) to your wallet.\n"
1254  + HelpRequiringPassphrase(pwallet) + "\n"
1255 
1256  "\nArguments:\n"
1257  "1. \"key\" (string, required) The zkey (see exportsaplingkey)\n"
1258  "2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n"
1259  "3. height (numeric, optional, default=0) Block height to start rescan from\n"
1260  "\nNote: This call can take minutes to complete if rescan is true.\n"
1261 
1262  "\nResult:\n"
1263  "{\n"
1264  " \"address\" : \"address|DefaultAddress\", (string) The address corresponding to the spending key (the default address).\n"
1265  "}\n"
1266 
1267  "\nExamples:\n"
1268  "\nExport a zkey\n"
1269  + HelpExampleCli("exportsaplingkey", "\"myaddress\"") +
1270  "\nImport the key with rescan\n"
1271  + HelpExampleCli("importsaplingkey", "\"mykey\"") +
1272  "\nImport the key with partial rescan\n"
1273  + HelpExampleCli("importsaplingkey", "\"mykey\" whenkeyisnew 30000") +
1274  "\nRe-import the key with longer partial rescan\n"
1275  + HelpExampleCli("importsaplingkey", "\"mykey\" yes 20000") +
1276  "\nAs a JSON-RPC call\n"
1277  + HelpExampleRpc("importsaplingkey", "\"mykey\", \"no\"")
1278  );
1279 
1280  // Whether to perform rescan after import
1281  bool fRescan = true;
1282  bool fIgnoreExistingKey = true;
1283  if (request.params.size() > 1) {
1284  auto rescan = request.params[1].get_str();
1285  if (rescan.compare("whenkeyisnew") != 0) {
1286  fIgnoreExistingKey = false;
1287  if (rescan.compare("yes") == 0) {
1288  fRescan = true;
1289  } else if (rescan.compare("no") == 0) {
1290  fRescan = false;
1291  } else {
1292  throw JSONRPCError(RPC_INVALID_PARAMETER, "rescan must be \"yes\", \"no\" or \"whenkeyisnew\"");
1293  }
1294  }
1295  }
1296 
1297  WalletRescanReserver reserver(pwallet);
1298  if (fRescan && !reserver.reserve()) {
1299  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1300  }
1301 
1302  UniValue result(UniValue::VOBJ);
1303  CBlockIndex* pindexRescan{nullptr};
1304  {
1305  LOCK2(cs_main, pwallet->cs_wallet);
1306  EnsureWalletIsUnlocked(pwallet);
1307 
1308  // Height to rescan from
1309  int nRescanHeight = 0;
1310  if (request.params.size() > 2)
1311  nRescanHeight = request.params[2].get_int();
1312  if (nRescanHeight < 0 || nRescanHeight > chainActive.Height()) {
1313  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
1314  }
1315 
1316  std::string strSecret = request.params[0].get_str();
1317  auto spendingkey = KeyIO::DecodeSpendingKey(strSecret);
1318  if (!IsValidSpendingKey(spendingkey)) {
1319  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid spending key");
1320  }
1321 
1322  libzcash::SaplingExtendedSpendingKey saplingSpendingKey = *boost::get<libzcash::SaplingExtendedSpendingKey>(&spendingkey);
1323  result.pushKV("address", KeyIO::EncodePaymentAddress( saplingSpendingKey.DefaultAddress()));
1324 
1325  // Sapling support
1326  auto addResult = pwallet->GetSaplingScriptPubKeyMan()->AddSpendingKeyToWallet(Params().GetConsensus(), saplingSpendingKey, -1);
1327  if (addResult == KeyAlreadyExists && fIgnoreExistingKey) {
1328  return result;
1329  }
1330  pwallet->MarkDirty();
1331  if (addResult == KeyNotAdded) {
1332  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding spending key to wallet");
1333  }
1334  pindexRescan = chainActive[nRescanHeight];
1335  }
1336 
1337  // We want to scan for transactions and notes
1338  if (fRescan) {
1339  pwallet->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
1340  }
1341 
1342  return result;
1343 }
1344 
1346 {
1347  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
1348 
1349  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
1350  return NullUniValue;
1351 
1352  if (request.fHelp || request.params.size() < 1 || request.params.size() > 3)
1353  throw std::runtime_error(
1354  "importsaplingviewingkey \"vkey\" ( rescan height )\n"
1355  "\nAdds a viewing key (as returned by exportsaplingviewingkey) to your wallet.\n"
1356  + HelpRequiringPassphrase(pwallet) + "\n"
1357 
1358  "\nArguments:\n"
1359  "1. \"vkey\" (string, required) The viewing key (see exportsaplingviewingkey)\n"
1360  "2. rescan (string, optional, default=\"whenkeyisnew\") Rescan the wallet for transactions - can be \"yes\", \"no\" or \"whenkeyisnew\"\n"
1361  "3. height (numeric, optional, default=0) Block height to start rescan from\n"
1362  "\nNote: This call can take minutes to complete if rescan is true.\n"
1363 
1364  "\nResult:\n"
1365  "{\n"
1366  " \"address\" : \"address|DefaultAddress\", (string) The address corresponding to the viewing key (for Sapling, this is the default address).\n"
1367  "}\n"
1368 
1369  "\nExamples:\n"
1370  "\nImport a viewing key\n"
1371  + HelpExampleCli("importsaplingviewingkey", "\"vkey\"") +
1372  "\nImport the viewing key without rescan\n"
1373  + HelpExampleCli("importsaplingviewingkey", "\"vkey\", no") +
1374  "\nImport the viewing key with partial rescan\n"
1375  + HelpExampleCli("importsaplingviewingkey", "\"vkey\" whenkeyisnew 30000") +
1376  "\nRe-import the viewing key with longer partial rescan\n"
1377  + HelpExampleCli("importsaplingviewingkey", "\"vkey\" yes 20000") +
1378  "\nAs a JSON-RPC call\n"
1379  + HelpExampleRpc("importsaplingviewingkey", "\"vkey\", \"no\"")
1380  );
1381 
1382  // Whether to perform rescan after import
1383  bool fRescan = true;
1384  bool fIgnoreExistingKey = true;
1385  if (request.params.size() > 1) {
1386  auto rescan = request.params[1].get_str();
1387  if (rescan.compare("whenkeyisnew") != 0) {
1388  fIgnoreExistingKey = false;
1389  if (rescan.compare("no") == 0) {
1390  fRescan = false;
1391  } else if (rescan.compare("yes") != 0) {
1392  throw JSONRPCError(
1394  "rescan must be \"yes\", \"no\" or \"whenkeyisnew\"");
1395  }
1396  }
1397  }
1398 
1399  WalletRescanReserver reserver(pwallet);
1400  if (fRescan && !reserver.reserve()) {
1401  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
1402  }
1403 
1404  UniValue result(UniValue::VOBJ);
1405  CBlockIndex* pindexRescan{nullptr};
1406  {
1407  LOCK2(cs_main, pwallet->cs_wallet);
1408  EnsureWalletIsUnlocked(pwallet);
1409 
1410  // Height to rescan from
1411  int nRescanHeight = 0;
1412  if (request.params.size() > 2) {
1413  nRescanHeight = request.params[2].get_int();
1414  }
1415  if (nRescanHeight < 0 || nRescanHeight > chainActive.Height()) {
1416  throw JSONRPCError(RPC_INVALID_PARAMETER, "Block height out of range");
1417  }
1418 
1419  std::string strVKey = request.params[0].get_str();
1420  libzcash::ViewingKey viewingkey = KeyIO::DecodeViewingKey(strVKey);
1421  if (!IsValidViewingKey(viewingkey)) {
1422  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid viewing key");
1423  }
1424  libzcash::SaplingExtendedFullViewingKey efvk = *boost::get<libzcash::SaplingExtendedFullViewingKey>(&viewingkey);
1425  result.pushKV("address", KeyIO::EncodePaymentAddress(efvk.DefaultAddress()));
1426 
1427  auto addResult = pwallet->GetSaplingScriptPubKeyMan()->AddViewingKeyToWallet(efvk);
1428  if (addResult == SpendingKeyExists) {
1429  throw JSONRPCError(
1431  "The wallet already contains the private key for this viewing key");
1432  } else if (addResult == KeyAlreadyExists && fIgnoreExistingKey) {
1433  return result;
1434  }
1435  pwallet->MarkDirty();
1436  if (addResult == KeyNotAdded) {
1437  throw JSONRPCError(RPC_WALLET_ERROR, "Error adding viewing key to wallet");
1438  }
1439 
1440  pindexRescan = chainActive[nRescanHeight];
1441  }
1442 
1443  // We want to scan for transactions and notes
1444  if (fRescan) {
1445  pwallet->ScanForWalletTransactions(pindexRescan, nullptr, reserver, true);
1446  }
1447 
1448  return result;
1449 }
1450 
1452 {
1453  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
1454 
1455  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
1456  return NullUniValue;
1457 
1458  if (request.fHelp || request.params.size() != 1)
1459  throw std::runtime_error(
1460  "exportsaplingviewingkey \"shield_addr\"\n"
1461  "\nReveals the viewing key corresponding to 'shield_addr'.\n"
1462  "Then the importsaplingviewingkey can be used with this output\n"
1463  + HelpRequiringPassphrase(pwallet) + "\n"
1464 
1465  "\nArguments:\n"
1466  "1. \"shield_addr\" (string, required) The shield addr for the viewing key\n"
1467 
1468  "\nResult:\n"
1469  "\"vkey\" (string) The viewing key\n"
1470 
1471  "\nExamples:\n"
1472  + HelpExampleCli("exportsaplingviewingkey", "\"myaddress\"")
1473  + HelpExampleRpc("exportsaplingviewingkey", "\"myaddress\"")
1474  );
1475 
1476  LOCK2(cs_main, pwallet->cs_wallet);
1477 
1478  EnsureWalletIsUnlocked(pwallet);
1479 
1480  std::string strAddress = request.params[0].get_str();
1481  auto address = KeyIO::DecodePaymentAddress(strAddress);
1482  if (!IsValidPaymentAddress(address)) {
1483  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid shield addr");
1484  }
1485  const libzcash::SaplingPaymentAddress &sapAddr = *boost::get<libzcash::SaplingPaymentAddress>(&address);
1486  auto vk = pwallet->GetSaplingScriptPubKeyMan()->GetViewingKeyForPaymentAddress(sapAddr);
1487  if (vk) {
1488  return KeyIO::EncodeViewingKey(vk.get());
1489  } else {
1490  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key or viewing key for this shield addr");
1491  }
1492 }
1493 
1495 {
1496  CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
1497 
1498  if (!EnsureWalletIsAvailable(pwallet, request.fHelp))
1499  return NullUniValue;
1500 
1501  if (request.fHelp || request.params.size() != 1)
1502  throw std::runtime_error(
1503  "exportsaplingkey \"shield_addr\"\n"
1504  "\nReveals the key corresponding to the 'shield_addr'.\n"
1505  "Then the importsaplingkey can be used with this output\n"
1506  + HelpRequiringPassphrase(pwallet) + "\n"
1507 
1508  "\nArguments:\n"
1509  "1. \"addr\" (string, required) The shield addr for the private key\n"
1510 
1511  "\nResult:\n"
1512  "\"key\" (string) The private key\n"
1513 
1514  "\nExamples:\n"
1515  + HelpExampleCli("exportsaplingkey", "\"myaddress\"")
1516  + HelpExampleRpc("exportsaplingkey", "\"myaddress\"")
1517  );
1518 
1519  LOCK2(cs_main, pwallet->cs_wallet);
1520 
1521  EnsureWalletIsUnlocked(pwallet);
1522 
1523  std::string strAddress = request.params[0].get_str();
1524 
1525  auto address = KeyIO::DecodePaymentAddress(strAddress);
1526  if (!IsValidPaymentAddress(address)) {
1527  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid shield addr");
1528  }
1529  libzcash::SaplingPaymentAddress addr = *boost::get<libzcash::SaplingPaymentAddress>(&address);
1530 
1531  // Sapling support
1533  if (!sk) {
1534  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet does not hold private key for this shield addr");
1535  }
1537 }
bool IsValidPaymentAddress(const libzcash::PaymentAddress &zaddr)
Check whether a PaymentAddress is not an InvalidEncoding.
Definition: address.cpp:92
bool BIP38_Decrypt(std::string strPassphrase, std::string strEncryptedKey, uint256 &privKey, bool &fCompressed)
Definition: bip38.cpp:169
std::string BIP38_Encrypt(std::string strAddress, std::string strPassphrase, uint256 privKey, bool fCompressed)
Definition: bip38.cpp:119
const CChainParams & Params()
Return the currently selected parameters.
virtual bool HaveWatchOnly(const CScript &dest) const
Definition: keystore.cpp:104
void GetSaplingPaymentAddresses(std::set< libzcash::SaplingPaymentAddress > &setAddress) const
Definition: keystore.cpp:252
virtual bool HaveCScript(const CScriptID &hash) const
Definition: keystore.cpp:51
bool GetSaplingExtendedSpendingKey(const libzcash::SaplingPaymentAddress &addr, libzcash::SaplingExtendedSpendingKey &extskOut) const
Definition: keystore.cpp:240
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:139
uint256 GetBlockHash() const
Definition: chain.h:215
int64_t GetBlockTime() const
Definition: chain.h:216
int64_t GetMedianTimePast() const
Definition: chain.cpp:204
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:151
CBlockIndex * Genesis() const
Returns the index entry for the genesis block of this chain, or nullptr if none.
Definition: chain.h:399
CBlockIndex * Tip(bool fProofOfStake=false) const
Returns the index entry for the tip of this chain, or nullptr if none.
Definition: chain.h:405
int Height() const
Return the maximal height in the chain.
Definition: chain.h:450
bool GetKey(const CKeyID &address, CKey &keyOut) const override
Definition: crypter.cpp:199
bool HaveKey(const CKeyID &address) const override
Check whether a key corresponding to a given address is present in the store.
Definition: crypter.cpp:179
CKeyID GetID() const
Definition: hdchain.h:52
An encapsulated private key.
Definition: key.h:30
uint256 GetPrivKey_256()
Definition: key.cpp:167
unsigned int size() const
Simple read-only vector-like interface.
Definition: key.h:90
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:95
bool IsCompressed() const
Check whether the public key corresponding to this private key is (to be) compressed.
Definition: key.h:98
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:186
void Set(const T pbegin, const T pend, bool fCompressedIn)
Initialize using begin and end iterators to byte data.
Definition: key.h:76
const unsigned char * begin() const
Definition: key.h:91
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:216
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:21
KeyOriginInfo key_origin
Definition: walletdb.h:71
bool HasKeyOrigin() const
Definition: walletdb.h:100
int64_t nCreateTime
Definition: walletdb.h:69
An encapsulated public key.
Definition: pubkey.h:44
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:167
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:210
Serialized script, used inside transaction inputs and outputs.
Definition: script.h:381
bool IsPayToScriptHash() const
Definition: script.cpp:223
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:24
A CWallet is an extension of a keystore, which also maintains a set of transactions and balances,...
Definition: wallet.h:577
void GetKeyBirthTimes(std::map< CKeyID, int64_t > &mapKeyBirth) const EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Definition: wallet.cpp:4026
RecursiveMutex cs_wallet
Definition: wallet.h:720
bool IsAbortingRescan()
Definition: wallet.h:886
bool IsScanning()
Definition: wallet.h:887
int64_t nTimeFirstKey
Definition: wallet.h:776
SaplingScriptPubKeyMan * GetSaplingScriptPubKeyMan() const
Definition: wallet.h:712
std::map< CKeyID, CKeyMetadata > mapKeyMetadata
Definition: wallet.h:726
void AbortRescan()
Definition: wallet.h:885
boost::signals2::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
Definition: wallet.h:1242
UniValue params
Definition: server.h:47
bool fHelp
Definition: server.h:48
std::map< libzcash::SaplingIncomingViewingKey, CKeyMetadata > mapSaplingZKeyMetadata
Optional< libzcash::SaplingExtendedFullViewingKey > GetViewingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &addr) const
Return the full viewing key for the shielded address.
Optional< libzcash::SaplingExtendedSpendingKey > GetSpendingKeyForPaymentAddress(const libzcash::SaplingPaymentAddress &addr) const
Return the spending key for the payment address (nullopt if the wallet has no spending key for such a...
KeyAddResult AddViewingKeyToWallet(const libzcash::SaplingExtendedFullViewingKey &extfvk) const
KeyAddResult AddSpendingKeyToWallet(const Consensus::Params &params, const libzcash::SaplingExtendedSpendingKey &sk, int64_t nTime)
const CHDChain & GetHDChain() const
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
bool setArray()
Definition: univalue.cpp:94
const std::string & get_str() const
enum VType getType() const
Definition: univalue.h:64
@ VOBJ
Definition: univalue.h:21
@ VSTR
Definition: univalue.h:21
@ VARR
Definition: univalue.h:21
int64_t get_int64() const
void clear()
Definition: univalue.cpp:15
size_t size() const
Definition: univalue.h:68
enum VType type() const
Definition: univalue.h:177
const std::vector< UniValue > & getValues() const
bool isStr() const
Definition: univalue.h:81
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:75
bool pushKV(const std::string &key, const UniValue &val)
Definition: univalue.cpp:133
bool isNum() const
Definition: univalue.h:82
bool get_bool() const
int get_int() const
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1324
std::string ToString() const
Definition: uint256.cpp:65
unsigned char * end()
Definition: uint256.h:68
bool IsNull() const
Definition: uint256.h:36
unsigned char * begin()
Definition: uint256.h:63
SaplingFullViewingKey full_viewing_key() const
Definition: address.cpp:29
SaplingIncomingViewingKey in_viewing_key() const
Definition: address.cpp:45
Sapling functions.
Definition: address.h:30
256-bit opaque blob.
Definition: uint256.h:138
const std::string CLIENT_BUILD
std::string GetNameForAddressBookEntry(const CWDestination &address) const
Definition: wallet.cpp:3686
bool HasAddressBook(const CWDestination &address) const
Definition: wallet.cpp:3710
bool SetAddressBook(const CWDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:3642
bool AddCScript(const CScript &redeemScript) override
Support for BIP 0013 : see https://github.com/bitcoin/bips/blob/master/bip-0013.mediawiki.
Definition: wallet.cpp:327
ScriptPubKeyMan * GetScriptPubKeyMan() const
Get spkm.
Definition: wallet.cpp:701
void MarkDirty()
Definition: wallet.cpp:892
bool AddWatchOnly(const CScript &dest) override
Adds a watch-only address to the store, and saves it to disk.
Definition: wallet.cpp:349
CBlockIndex * ScanForWalletTransactions(CBlockIndex *pindexStart, CBlockIndex *pindexStop, const WalletRescanReserver &reserver, bool fUpdate=false, bool fromStartup=false)
Scan the block chain (starting in pindexStart) for transactions from or to us.
Definition: wallet.cpp:1896
void BlockUntilSyncedToCurrentChain()
Blocks until the wallet state is up-to-date to /at least/ the current chain at the time this function...
Definition: wallet.cpp:1383
void UpdateTimeFirstKey(int64_t nCreateTime)
Update wallet first key creation time.
Definition: wallet.cpp:315
void ReacceptWalletTransactions(bool fFirstLoad=false)
Definition: wallet.cpp:2000
bool HasSaplingSPKM() const
Definition: wallet.cpp:706
bool AddKeyPubKey(const CKey &key, const CPubKey &pubkey) override
Adds a key to the store, and saves it to disk.
Definition: wallet.cpp:252
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1859
isminetype IsMine(const CKeyStore &keystore, const CTxDestination &dest)
Definition: ismine.cpp:29
@ ISMINE_SPENDABLE
Definition: ismine.h:22
#define LogPrint(category,...)
Definition: logging.h:163
const std::string COLD_STAKING
Definition: addressbook.cpp:15
@ SAPLING
Definition: logging.h:63
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:145
libzcash::SpendingKey DecodeSpendingKey(const std::string &str)
std::string EncodePaymentAddress(const libzcash::PaymentAddress &zaddr)
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:127
libzcash::ViewingKey DecodeViewingKey(const std::string &str)
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:170
std::string EncodeViewingKey(const libzcash::ViewingKey &vk)
libzcash::PaymentAddress DecodePaymentAddress(const std::string &str)
std::string EncodeSpendingKey(const libzcash::SpendingKey &zkey)
bool IsValidDestination(const CWDestination &address)
std::string EncodeDestination(const CWDestination &address, const CChainParams::Base58Type addrType)
CWDestination DecodeDestination(const std::string &strAddress)
fs::ofstream ofstream
Definition: fs.h:93
fs::ifstream ifstream
Definition: fs.h:92
boost::variant< InvalidEncoding, SaplingExtendedSpendingKey > SpendingKey
Definition: zip32.h:116
boost::variant< InvalidEncoding, SaplingExtendedFullViewingKey > ViewingKey
Definition: zip32.h:117
RecursiveMutex cs_main
Global state.
Definition: validation.cpp:80
boost::optional< T > Optional
Substitute for C++17 std::optional.
Definition: optional.h:12
UniValue JSONRPCError(int code, const std::string &message)
Definition: protocol.cpp:53
@ RPC_MISC_ERROR
General application defined errors.
Definition: protocol.h:41
@ RPC_TYPE_ERROR
Server is in safe mode, and command is not allowed in safe mode.
Definition: protocol.h:43
@ RPC_INVALID_PARAMETER
Ran out of memory during operation.
Definition: protocol.h:46
@ RPC_WALLET_ERROR
No valid connection manager instance found.
Definition: protocol.h:70
@ RPC_INVALID_ADDRESS_OR_KEY
Unexpected type was passed as parameter.
Definition: protocol.h:44
bool IsStakingDerPath(KeyOriginInfo keyOrigin)
Definition: rpcdump.cpp:73
UniValue importpubkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:273
UniValue importprivkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:78
UniValue bip38decrypt(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1167
UniValue exportsaplingkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1494
UniValue dumpwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:497
UniValue exportsaplingviewingkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1451
UniValue importwallet(const JSONRPCRequest &request)
Definition: rpcdump.cpp:330
UniValue abortrescan(const JSONRPCRequest &request)
Definition: rpcdump.cpp:152
std::string DecodeDumpString(const std::string &str)
Definition: rpcdump.cpp:58
UniValue dumpprivkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:457
UniValue importaddress(const JSONRPCRequest &request)
Definition: rpcdump.cpp:206
UniValue importsaplingkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1243
UniValue importsaplingviewingkey(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1345
UniValue bip38encrypt(const JSONRPCRequest &request)
Definition: rpcdump.cpp:1116
UniValue importmulti(const JSONRPCRequest &mainRequest)
Definition: rpcdump.cpp:960
CWallet * GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: rpcwallet.cpp:39
std::string HelpRequiringPassphrase(CWallet *const pwallet)
Definition: rpcwallet.cpp:54
void EnsureWalletIsUnlocked(CWallet *const pwallet, bool fAllowAnonOnly)
Definition: rpcwallet.cpp:71
bool EnsureWalletIsAvailable(CWallet *const pwallet, bool avoidException)
Definition: rpcwallet.cpp:59
@ KeyAlreadyExists
@ SpendingKeyExists
std::string HelpExampleCli(std::string methodname, std::string args)
Definition: server.cpp:527
void RPCTypeCheck(const UniValue &params, const std::list< UniValue::VType > &typesExpected, bool fAllowNull)
Type-check arguments; throws JSONRPCError if wrong type given.
Definition: server.cpp:63
std::string HelpExampleRpc(std::string methodname, std::string args)
Definition: server.cpp:532
CScript GetScriptForRawPubKey(const CPubKey &pubKey)
Generate a P2PK script for the given pubkey.
Definition: standard.cpp:286
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a PIVX scriptPubKey for the given CTxDestination.
Definition: standard.cpp:278
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet, bool fColdStake)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:162
boost::variant< CNoDestination, CKeyID, CScriptID, CExchangeKeyID > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:72
Definition: key.h:148
void SetSeed(const unsigned char *seed, unsigned int nSeedLen)
Definition: key.cpp:290
std::vector< uint32_t > path
Definition: keyorigin.h:14
std::string pathToString() const
Definition: keyorigin.h:29
libzcash::SaplingPaymentAddress DefaultAddress() const
Definition: zip32.cpp:106
libzcash::SaplingExpandedSpendingKey expsk
Definition: zip32.h:92
libzcash::SaplingPaymentAddress DefaultAddress() const
Definition: zip32.cpp:162
#define LOCK2(cs1, cs2)
Definition: sync.h:221
std::string _(const char *psz)
Translation function: Call Translate signal on UI interface, which returns a Optional result.
Definition: system.h:65
#define strprintf
Definition: tinyformat.h:1056
const char * uvTypeName(UniValue::VType t)
Definition: univalue.cpp:219
const UniValue NullUniValue
Definition: univalue.cpp:13
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
std::vector< unsigned char > ParseHex(const char *psz)
bool IsHex(const std::string &str)
int64_t GetTime()
DEPRECATED Use either GetSystemTimeInSeconds (not mockable) or GetTime<T> (mockable)
Definition: utiltime.cpp:27
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: utiltime.cpp:102
CChain chainActive
The currently-connected chain of blocks (protected by cs_main).
Definition: validation.cpp:84
bool IsValidSpendingKey(const libzcash::SpendingKey &zkey)
Check whether a SpendingKey is not an InvalidEncoding.
Definition: zip32.cpp:169
bool IsValidViewingKey(const libzcash::ViewingKey &vk)
Check whether a ViewingKey is not an InvalidEncoding.
Definition: zip32.cpp:173