Bitcoin ABC 0.31.2
P2P Digital Currency
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Modules Pages
backup.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2016 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 <wallet/rpc/backup.h>
6
7#include <chain.h>
8#include <common/args.h>
9#include <config.h>
10#include <core_io.h>
11#include <interfaces/chain.h>
12#include <key_io.h>
13#include <merkleblock.h>
14#include <rpc/server.h>
15#include <rpc/util.h>
16#include <script/descriptor.h>
17#include <script/script.h>
18#include <script/standard.h>
19#include <sync.h>
20#include <util/bip32.h>
21#include <util/fs.h>
22#include <util/fs_helpers.h>
23#include <util/time.h>
24#include <util/translation.h>
25#include <wallet/rpc/util.h>
26#include <wallet/rpcwallet.h>
27#include <wallet/spend.h>
28#include <wallet/wallet.h>
29
30#include <algorithm>
31#include <cstdint>
32#include <fstream>
33#include <string>
34#include <tuple>
35#include <utility>
36#include <vector>
37
39
40static std::string EncodeDumpString(const std::string &str) {
41 std::stringstream ret;
42 for (const uint8_t c : str) {
43 if (c <= 32 || c >= 128 || c == '%') {
44 ret << '%' << HexStr({&c, 1});
45 } else {
46 ret << c;
47 }
48 }
49 return ret.str();
50}
51
52static std::string DecodeDumpString(const std::string &str) {
53 std::stringstream ret;
54 for (unsigned int pos = 0; pos < str.length(); pos++) {
55 uint8_t c = str[pos];
56 if (c == '%' && pos + 2 < str.length()) {
57 c = (((str[pos + 1] >> 6) * 9 + ((str[pos + 1] - '0') & 15)) << 4) |
58 ((str[pos + 2] >> 6) * 9 + ((str[pos + 2] - '0') & 15));
59 pos += 2;
60 }
61 ret << c;
62 }
63 return ret.str();
64}
65
66static bool
68 const CWallet *const pwallet, const CKeyID &keyid,
69 std::string &strAddr, std::string &strLabel)
70 EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
71 bool fLabelFound = false;
72 CKey key;
73 spk_man->GetKey(keyid, key);
74 for (const auto &dest : GetAllDestinationsForKey(key.GetPubKey())) {
75 const auto *address_book_entry = pwallet->FindAddressBookEntry(dest);
76 if (address_book_entry) {
77 if (!strAddr.empty()) {
78 strAddr += ",";
79 }
80 strAddr += EncodeDestination(dest, config);
81 strLabel = EncodeDumpString(address_book_entry->GetLabel());
82 fLabelFound = true;
83 }
84 }
85 if (!fLabelFound) {
86 strAddr = EncodeDestination(
88 pwallet->m_default_address_type),
89 config);
90 }
91 return fLabelFound;
92}
93
94static const int64_t TIMESTAMP_MIN = 0;
95
96static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver,
97 int64_t time_begin = TIMESTAMP_MIN,
98 bool update = true) {
99 int64_t scanned_time = wallet.RescanFromTime(time_begin, reserver, update);
100 if (wallet.IsAbortingRescan()) {
101 throw JSONRPCError(RPC_MISC_ERROR, "Rescan aborted by user.");
102 } else if (scanned_time > time_begin) {
104 "Rescan was unable to fully rescan the blockchain. "
105 "Some transactions may be missing.");
106 }
107}
108
109static void EnsureBlockDataFromTime(const CWallet &wallet, int64_t timestamp) {
110 auto &chain{wallet.chain()};
111 if (!chain.havePruned()) {
112 return;
113 }
114
115 int height{0};
116 const bool found{chain.findFirstBlockWithTimeAndHeight(
117 timestamp - TIMESTAMP_WINDOW, 0, FoundBlock().height(height))};
118
119 BlockHash tip_hash{
120 WITH_LOCK(wallet.cs_wallet, return wallet.GetLastBlockHash())};
121 if (found && !chain.hasBlocks(tip_hash, height)) {
122 throw JSONRPCError(
124 strprintf(
125 "Pruned blocks from height %d required to import keys. Use RPC "
126 "call getblockchaininfo to determine your pruned height.",
127 height));
128 }
129}
130
132 return RPCHelpMan{
133 "importprivkey",
134 "Adds a private key (as returned by dumpprivkey) to your wallet. "
135 "Requires a new wallet backup.\n"
136 "Hint: use importmulti to import more than one private key.\n"
137 "\nNote: This call can take minutes to complete if rescan is true, "
138 "during that time, other rpc calls\n"
139 "may report that the imported key exists but related transactions are "
140 "still missing, leading to temporarily incorrect/bogus balances and "
141 "unspent outputs until rescan completes.\n"
142 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
143 "Note: This command is only compatible with legacy wallets. Use "
144 "\"importdescriptors\" with \"combo(X)\" for descriptor wallets.\n",
145 {
147 "The private key (see dumpprivkey)"},
148 {"label", RPCArg::Type::STR,
150 "current label if address exists, otherwise \"\""},
151 "An optional label"},
152 {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
153 "Rescan the wallet for transactions"},
154 },
157 "\nDump a private key\n" +
158 HelpExampleCli("dumpprivkey", "\"myaddress\"") +
159 "\nImport the private key with rescan\n" +
160 HelpExampleCli("importprivkey", "\"mykey\"") +
161 "\nImport using a label and without rescan\n" +
162 HelpExampleCli("importprivkey", "\"mykey\" \"testing\" false") +
163 "\nImport using default blank label and without rescan\n" +
164 HelpExampleCli("importprivkey", "\"mykey\" \"\" false") +
165 "\nAs a JSON-RPC call\n" +
166 HelpExampleRpc("importprivkey", "\"mykey\", \"testing\", false")},
167 [&](const RPCHelpMan &self, const Config &config,
168 const JSONRPCRequest &request) -> UniValue {
169 std::shared_ptr<CWallet> const wallet =
171 if (!wallet) {
172 return NullUniValue;
173 }
174 CWallet *const pwallet = wallet.get();
175
177 throw JSONRPCError(
179 "Cannot import private keys to a wallet with "
180 "private keys disabled");
181 }
182
184
185 WalletRescanReserver reserver(*pwallet);
186 bool fRescan = true;
187 {
188 LOCK(pwallet->cs_wallet);
189
190 EnsureWalletIsUnlocked(pwallet);
191
192 std::string strSecret = request.params[0].get_str();
193 std::string strLabel = "";
194 if (!request.params[1].isNull()) {
195 strLabel = request.params[1].get_str();
196 }
197
198 // Whether to perform rescan after import
199 if (!request.params[2].isNull()) {
200 fRescan = request.params[2].get_bool();
201 }
202
203 if (fRescan && pwallet->chain().havePruned()) {
204 // Exit early and print an error.
205 // If a block is pruned after this check, we will import the
206 // key(s), but fail the rescan with a generic error.
207 throw JSONRPCError(
209 "Rescan is disabled when blocks are pruned");
210 }
211
212 if (fRescan && !reserver.reserve()) {
213 throw JSONRPCError(
215 "Wallet is currently rescanning. Abort existing "
216 "rescan or wait.");
217 }
218
219 CKey key = DecodeSecret(strSecret);
220 if (!key.IsValid()) {
222 "Invalid private key encoding");
223 }
224
225 CPubKey pubkey = key.GetPubKey();
226 CHECK_NONFATAL(key.VerifyPubKey(pubkey));
227 CKeyID vchAddress = pubkey.GetID();
228 {
229 pwallet->MarkDirty();
230
231 // We don't know which corresponding address will be used;
232 // label all new addresses, and label existing addresses if
233 // a label was passed.
234 for (const auto &dest : GetAllDestinationsForKey(pubkey)) {
235 if (!request.params[1].isNull() ||
236 !pwallet->FindAddressBookEntry(dest)) {
237 pwallet->SetAddressBook(dest, strLabel, "receive");
238 }
239 }
240
241 // Use timestamp of 1 to scan the whole chain
242 if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) {
244 "Error adding key to wallet");
245 }
246 }
247 }
248 if (fRescan) {
249 RescanWallet(*pwallet, reserver);
250 }
251
252 return NullUniValue;
253 },
254 };
255}
256
258 return RPCHelpMan{
259 "abortrescan",
260 "Stops current wallet rescan triggered by an RPC call, e.g. by an "
261 "importprivkey call.\n"
262 "Note: Use \"getwalletinfo\" to query the scanning progress.\n",
263 {},
265 "Whether the abort was successful"},
266 RPCExamples{"\nImport a private key\n" +
267 HelpExampleCli("importprivkey", "\"mykey\"") +
268 "\nAbort the running wallet rescan\n" +
269 HelpExampleCli("abortrescan", "") +
270 "\nAs a JSON-RPC call\n" +
271 HelpExampleRpc("abortrescan", "")},
272 [&](const RPCHelpMan &self, const Config &config,
273 const JSONRPCRequest &request) -> UniValue {
274 std::shared_ptr<CWallet> const wallet =
276 if (!wallet) {
277 return NullUniValue;
278 }
279 CWallet *const pwallet = wallet.get();
280
281 if (!pwallet->IsScanning() || pwallet->IsAbortingRescan()) {
282 return false;
283 }
284 pwallet->AbortRescan();
285 return true;
286 },
287 };
288}
289
291 return RPCHelpMan{
292 "importaddress",
293 "Adds an address or script (in hex) that can be watched as if it "
294 "were in your wallet but cannot be used to spend. Requires a new "
295 "wallet backup.\n"
296 "\nNote: This call can take minutes to complete if rescan is true, "
297 "during that time, other rpc calls\n"
298 "may report that the imported address exists but related transactions "
299 "are still missing, leading to temporarily incorrect/bogus balances "
300 "and unspent outputs until rescan completes.\n"
301 "If you have the full public key, you should call importpubkey instead "
302 "of this.\n"
303 "Hint: use importmulti to import more than one address.\n"
304 "\nNote: If you import a non-standard raw script in hex form, outputs "
305 "sending to it will be treated\n"
306 "as change, and not show up in many RPCs.\n"
307 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
308 "Note: This command is only compatible with legacy wallets. Use "
309 "\"importdescriptors\" for descriptor wallets.\n",
310 {
312 "The Bitcoin address (or hex-encoded script)"},
313 {"label", RPCArg::Type::STR, RPCArg::Default{""},
314 "An optional label"},
315 {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
316 "Rescan the wallet for transactions"},
317 {"p2sh", RPCArg::Type::BOOL, RPCArg::Default{false},
318 "Add the P2SH version of the script as well"},
319 },
322 "\nImport an address with rescan\n" +
323 HelpExampleCli("importaddress", "\"myaddress\"") +
324 "\nImport using a label without rescan\n" +
325 HelpExampleCli("importaddress", "\"myaddress\" \"testing\" false") +
326 "\nAs a JSON-RPC call\n" +
327 HelpExampleRpc("importaddress",
328 "\"myaddress\", \"testing\", false")},
329 [&](const RPCHelpMan &self, const Config &config,
330 const JSONRPCRequest &request) -> UniValue {
331 std::shared_ptr<CWallet> const wallet =
333 if (!wallet) {
334 return NullUniValue;
335 }
336 CWallet *const pwallet = wallet.get();
337
338 EnsureLegacyScriptPubKeyMan(*pwallet, true);
339
340 std::string strLabel;
341 if (!request.params[1].isNull()) {
342 strLabel = request.params[1].get_str();
343 }
344
345 // Whether to perform rescan after import
346 bool fRescan = true;
347 if (!request.params[2].isNull()) {
348 fRescan = request.params[2].get_bool();
349 }
350
351 if (fRescan && pwallet->chain().havePruned()) {
352 // Exit early and print an error.
353 // If a block is pruned after this check, we will import the
354 // key(s), but fail the rescan with a generic error.
356 "Rescan is disabled when blocks are pruned");
357 }
358
359 WalletRescanReserver reserver(*pwallet);
360 if (fRescan && !reserver.reserve()) {
362 "Wallet is currently rescanning. Abort "
363 "existing rescan or wait.");
364 }
365
366 // Whether to import a p2sh version, too
367 bool fP2SH = false;
368 if (!request.params[3].isNull()) {
369 fP2SH = request.params[3].get_bool();
370 }
371
372 {
373 LOCK(pwallet->cs_wallet);
374
376 request.params[0].get_str(), wallet->GetChainParams());
377 if (IsValidDestination(dest)) {
378 if (fP2SH) {
379 throw JSONRPCError(
381 "Cannot use the p2sh flag with an address - "
382 "use a script instead");
383 }
384
385 pwallet->MarkDirty();
386
387 pwallet->ImportScriptPubKeys(
388 strLabel, {GetScriptForDestination(dest)},
389 false /* have_solving_data */, true /* apply_label */,
390 1 /* timestamp */);
391 } else if (IsHex(request.params[0].get_str())) {
392 std::vector<uint8_t> data(
393 ParseHex(request.params[0].get_str()));
394 CScript redeem_script(data.begin(), data.end());
395
396 std::set<CScript> scripts = {redeem_script};
397 pwallet->ImportScripts(scripts, 0 /* timestamp */);
398
399 if (fP2SH) {
400 scripts.insert(
401 GetScriptForDestination(ScriptHash(redeem_script)));
402 }
403
404 pwallet->ImportScriptPubKeys(
405 strLabel, scripts, false /* have_solving_data */,
406 true /* apply_label */, 1 /* timestamp */);
407 } else {
409 "Invalid Bitcoin address or script");
410 }
411 }
412 if (fRescan) {
413 RescanWallet(*pwallet, reserver);
414 {
415 LOCK(pwallet->cs_wallet);
417 }
418 }
419
420 return NullUniValue;
421 },
422 };
423}
424
426 return RPCHelpMan{
427 "importprunedfunds",
428 "Imports funds without rescan. Corresponding address or script must "
429 "previously be included in wallet. Aimed towards pruned wallets. The "
430 "end-user is responsible to import additional transactions that "
431 "subsequently spend the imported outputs or rescan after the point in "
432 "the blockchain the transaction is included.\n",
433 {
435 "A raw transaction in hex funding an already-existing address in "
436 "wallet"},
438 "The hex output from gettxoutproof that contains the transaction"},
439 },
441 RPCExamples{""},
442 [&](const RPCHelpMan &self, const Config &config,
443 const JSONRPCRequest &request) -> UniValue {
444 std::shared_ptr<CWallet> const wallet =
446 if (!wallet) {
447 return NullUniValue;
448 }
449 CWallet *const pwallet = wallet.get();
450
452 if (!DecodeHexTx(tx, request.params[0].get_str())) {
454 "TX decode failed");
455 }
456 uint256 txid = tx.GetId();
457
458 CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK,
460 CMerkleBlock merkleBlock;
461 ssMB >> merkleBlock;
462
463 // Search partial merkle tree in proof for our transaction and index
464 // in valid block
465 std::vector<uint256> vMatch;
466 std::vector<size_t> vIndex;
467 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) !=
468 merkleBlock.header.hashMerkleRoot) {
470 "Something wrong with merkleblock");
471 }
472
473 LOCK(pwallet->cs_wallet);
474 int height;
475 if (!pwallet->chain().findAncestorByHash(
476 pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(),
477 FoundBlock().height(height))) {
479 "Block not found in chain");
480 }
481
482 std::vector<uint256>::const_iterator it;
483 if ((it = std::find(vMatch.begin(), vMatch.end(), txid)) ==
484 vMatch.end()) {
486 "Transaction given doesn't exist in proof");
487 }
488
489 size_t txnIndex = vIndex[it - vMatch.begin()];
490
492 CWalletTx::Status::CONFIRMED, height,
493 merkleBlock.header.GetHash(), txnIndex);
494
496 if (pwallet->IsMine(*tx_ref)) {
497 pwallet->AddToWallet(std::move(tx_ref), confirm);
498 return NullUniValue;
499 }
500
501 throw JSONRPCError(
503 "No addresses in wallet correspond to included transaction");
504 },
505 };
506}
507
509 return RPCHelpMan{
510 "removeprunedfunds",
511 "Deletes the specified transaction from the wallet. Meant for use "
512 "with pruned wallets and as a companion to importprunedfunds. This "
513 "will affect wallet balances.\n",
514 {
516 "The hex-encoded id of the transaction you are deleting"},
517 },
519 RPCExamples{HelpExampleCli("removeprunedfunds",
520 "\"a8d0c0184dde994a09ec054286f1ce581bebf4644"
521 "6a512166eae7628734ea0a5\"") +
522 "\nAs a JSON-RPC call\n" +
523 HelpExampleRpc("removeprunedfunds",
524 "\"a8d0c0184dde994a09ec054286f1ce581bebf4644"
525 "6a512166eae7628734ea0a5\"")},
526 [&](const RPCHelpMan &self, const Config &config,
527 const JSONRPCRequest &request) -> UniValue {
528 std::shared_ptr<CWallet> const wallet =
530 if (!wallet) {
531 return NullUniValue;
532 }
533 CWallet *const pwallet = wallet.get();
534
535 LOCK(pwallet->cs_wallet);
536
537 TxId txid(ParseHashV(request.params[0], "txid"));
538 std::vector<TxId> txIds;
539 txIds.push_back(txid);
540 std::vector<TxId> txIdsOut;
541
542 if (pwallet->ZapSelectTx(txIds, txIdsOut) != DBErrors::LOAD_OK) {
543 throw JSONRPCError(
545 "Could not properly delete the transaction.");
546 }
547
548 if (txIdsOut.empty()) {
550 "Transaction does not exist in wallet.");
551 }
552
553 return NullUniValue;
554 },
555 };
556}
557
559 return RPCHelpMan{
560 "importpubkey",
561 "Adds a public key (in hex) that can be watched as if it were in "
562 "your wallet but cannot be used to spend. Requires a new wallet "
563 "backup.\n"
564 "Hint: use importmulti to import more than one public key.\n"
565 "\nNote: This call can take minutes to complete if rescan is true, "
566 "during that time, other rpc calls\n"
567 "may report that the imported pubkey exists but related transactions "
568 "are still missing, leading to temporarily incorrect/bogus balances "
569 "and unspent outputs until rescan completes.\n"
570 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
571 "Note: This command is only compatible with legacy wallets. Use "
572 "\"importdescriptors\" with \"combo(X)\" for descriptor wallets.\n",
573 {
575 "The hex-encoded public key"},
576 {"label", RPCArg::Type::STR, RPCArg::Default{""},
577 "An optional label"},
578 {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
579 "Rescan the wallet for transactions"},
580 },
583 "\nImport a public key with rescan\n" +
584 HelpExampleCli("importpubkey", "\"mypubkey\"") +
585 "\nImport using a label without rescan\n" +
586 HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
587 "\nAs a JSON-RPC call\n" +
588 HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")},
589 [&](const RPCHelpMan &self, const Config &config,
590 const JSONRPCRequest &request) -> UniValue {
591 std::shared_ptr<CWallet> const wallet =
593 if (!wallet) {
594 return NullUniValue;
595 }
596 CWallet *const pwallet = wallet.get();
597
599
600 std::string strLabel;
601 if (!request.params[1].isNull()) {
602 strLabel = request.params[1].get_str();
603 }
604
605 // Whether to perform rescan after import
606 bool fRescan = true;
607 if (!request.params[2].isNull()) {
608 fRescan = request.params[2].get_bool();
609 }
610
611 if (fRescan && pwallet->chain().havePruned()) {
612 // Exit early and print an error.
613 // If a block is pruned after this check, we will import the
614 // key(s), but fail the rescan with a generic error.
616 "Rescan is disabled when blocks are pruned");
617 }
618
619 WalletRescanReserver reserver(*pwallet);
620 if (fRescan && !reserver.reserve()) {
622 "Wallet is currently rescanning. Abort "
623 "existing rescan or wait.");
624 }
625
626 if (!IsHex(request.params[0].get_str())) {
628 "Pubkey must be a hex string");
629 }
630 std::vector<uint8_t> data(ParseHex(request.params[0].get_str()));
631 CPubKey pubKey(data);
632 if (!pubKey.IsFullyValid()) {
634 "Pubkey is not a valid public key");
635 }
636
637 {
638 LOCK(pwallet->cs_wallet);
639
640 std::set<CScript> script_pub_keys;
641 for (const auto &dest : GetAllDestinationsForKey(pubKey)) {
642 script_pub_keys.insert(GetScriptForDestination(dest));
643 }
644
645 pwallet->MarkDirty();
646
647 pwallet->ImportScriptPubKeys(
648 strLabel, script_pub_keys, true /* have_solving_data */,
649 true /* apply_label */, 1 /* timestamp */);
650
651 pwallet->ImportPubKeys(
652 {pubKey.GetID()}, {{pubKey.GetID(), pubKey}},
653 {} /* key_origins */, false /* add_keypool */,
654 false /* internal */, 1 /* timestamp */);
655 }
656 if (fRescan) {
657 RescanWallet(*pwallet, reserver);
658 {
659 LOCK(pwallet->cs_wallet);
661 }
662 }
663
664 return NullUniValue;
665 },
666 };
667}
668
670 return RPCHelpMan{
671 "importwallet",
672 "Imports keys from a wallet dump file (see dumpwallet). Requires a "
673 "new wallet backup to include imported keys.\n"
674 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
675 "Note: This command is only compatible with legacy wallets.\n",
676 {
678 "The wallet file"},
679 },
681 RPCExamples{"\nDump the wallet\n" +
682 HelpExampleCli("dumpwallet", "\"test\"") +
683 "\nImport the wallet\n" +
684 HelpExampleCli("importwallet", "\"test\"") +
685 "\nImport using the json rpc call\n" +
686 HelpExampleRpc("importwallet", "\"test\"")},
687 [&](const RPCHelpMan &self, const Config &config,
688 const JSONRPCRequest &request) -> UniValue {
689 std::shared_ptr<CWallet> const wallet =
691 if (!wallet) {
692 return NullUniValue;
693 }
694 CWallet *const pwallet = wallet.get();
695
697
698 WalletRescanReserver reserver(*pwallet);
699 if (!reserver.reserve()) {
701 "Wallet is currently rescanning. Abort "
702 "existing rescan or wait.");
703 }
704
705 int64_t nTimeBegin = 0;
706 bool fGood = true;
707 {
708 LOCK(pwallet->cs_wallet);
709
710 EnsureWalletIsUnlocked(pwallet);
711
712 std::ifstream file;
713 file.open(fs::u8path(request.params[0].get_str()),
714 std::ios::in | std::ios::ate);
715 if (!file.is_open()) {
717 "Cannot open wallet dump file");
718 }
720 pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
721 FoundBlock().time(nTimeBegin)));
722
723 int64_t nFilesize = std::max<int64_t>(1, file.tellg());
724 file.seekg(0, file.beg);
725
726 // Use uiInterface.ShowProgress instead of pwallet.ShowProgress
727 // because pwallet.ShowProgress has a cancel button tied to
728 // AbortRescan which we don't want for this progress bar showing
729 // the import progress. uiInterface.ShowProgress does not have a
730 // cancel button.
731
732 // show progress dialog in GUI
733 pwallet->chain().showProgress(
734 strprintf("%s " + _("Importing...").translated,
735 pwallet->GetDisplayName()),
736 0, false);
737 std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
738 std::vector<std::pair<CScript, int64_t>> scripts;
739 while (file.good()) {
740 pwallet->chain().showProgress(
741 "",
742 std::max(1,
743 std::min<int>(50, 100 * double(file.tellg()) /
744 double(nFilesize))),
745 false);
746 std::string line;
747 std::getline(file, line);
748 if (line.empty() || line[0] == '#') {
749 continue;
750 }
751
752 std::vector<std::string> vstr = SplitString(line, ' ');
753 if (vstr.size() < 2) {
754 continue;
755 }
756 CKey key = DecodeSecret(vstr[0]);
757 if (key.IsValid()) {
758 int64_t nTime = ParseISO8601DateTime(vstr[1]);
759 std::string strLabel;
760 bool fLabel = true;
761 for (size_t nStr = 2; nStr < vstr.size(); nStr++) {
762 if (vstr[nStr].front() == '#') {
763 break;
764 }
765 if (vstr[nStr] == "change=1") {
766 fLabel = false;
767 }
768 if (vstr[nStr] == "reserve=1") {
769 fLabel = false;
770 }
771 if (vstr[nStr].substr(0, 6) == "label=") {
772 strLabel =
773 DecodeDumpString(vstr[nStr].substr(6));
774 fLabel = true;
775 }
776 }
777 nTimeBegin = std::min(nTimeBegin, nTime);
778 keys.push_back(
779 std::make_tuple(key, nTime, fLabel, strLabel));
780 } else if (IsHex(vstr[0])) {
781 std::vector<uint8_t> vData(ParseHex(vstr[0]));
782 CScript script = CScript(vData.begin(), vData.end());
783 int64_t birth_time = ParseISO8601DateTime(vstr[1]);
784 if (birth_time > 0) {
785 nTimeBegin = std::min(nTimeBegin, birth_time);
786 }
787 scripts.push_back(
788 std::pair<CScript, int64_t>(script, birth_time));
789 }
790 }
791 file.close();
792 EnsureBlockDataFromTime(*pwallet, nTimeBegin);
793 // We now know whether we are importing private keys, so we can
794 // error if private keys are disabled
795 if (keys.size() > 0 && pwallet->IsWalletFlagSet(
797 // hide progress dialog in GUI
798 pwallet->chain().showProgress("", 100, false);
800 "Importing wallets is disabled when "
801 "private keys are disabled");
802 }
803 double total = double(keys.size() + scripts.size());
804 double progress = 0;
805 for (const auto &key_tuple : keys) {
806 pwallet->chain().showProgress(
807 "",
808 std::max(50, std::min<int>(75, 100 * progress / total) +
809 50),
810 false);
811 const CKey &key = std::get<0>(key_tuple);
812 int64_t time = std::get<1>(key_tuple);
813 bool has_label = std::get<2>(key_tuple);
814 std::string label = std::get<3>(key_tuple);
815
816 CPubKey pubkey = key.GetPubKey();
817 CHECK_NONFATAL(key.VerifyPubKey(pubkey));
818 CKeyID keyid = pubkey.GetID();
819
820 pwallet->WalletLogPrintf(
821 "Importing %s...\n",
822 EncodeDestination(PKHash(keyid), config));
823
824 if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
825 pwallet->WalletLogPrintf(
826 "Error importing key for %s\n",
827 EncodeDestination(PKHash(keyid), config));
828 fGood = false;
829 continue;
830 }
831
832 if (has_label) {
833 pwallet->SetAddressBook(PKHash(keyid), label,
834 "receive");
835 }
836 progress++;
837 }
838 for (const auto &script_pair : scripts) {
839 pwallet->chain().showProgress(
840 "",
841 std::max(50, std::min<int>(75, 100 * progress / total) +
842 50),
843 false);
844 const CScript &script = script_pair.first;
845 int64_t time = script_pair.second;
846
847 if (!pwallet->ImportScripts({script}, time)) {
848 pwallet->WalletLogPrintf("Error importing script %s\n",
849 HexStr(script));
850 fGood = false;
851 continue;
852 }
853
854 progress++;
855 }
856
857 // hide progress dialog in GUI
858 pwallet->chain().showProgress("", 100, false);
859 }
860 // hide progress dialog in GUI
861 pwallet->chain().showProgress("", 100, false);
862 RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
863 pwallet->MarkDirty();
864
865 if (!fGood) {
867 "Error adding some keys/scripts to wallet");
868 }
869
870 return NullUniValue;
871 },
872 };
873}
874
876 return RPCHelpMan{
877 "dumpprivkey",
878 "Reveals the private key corresponding to 'address'.\n"
879 "Then the importprivkey can be used with this output\n"
880 "Note: This command is only compatible with legacy wallets.\n",
881 {
883 "The bitcoin address for the private key"},
884 },
885 RPCResult{RPCResult::Type::STR, "key", "The private key"},
886 RPCExamples{HelpExampleCli("dumpprivkey", "\"myaddress\"") +
887 HelpExampleCli("importprivkey", "\"mykey\"") +
888 HelpExampleRpc("dumpprivkey", "\"myaddress\"")},
889 [&](const RPCHelpMan &self, const Config &config,
890 const JSONRPCRequest &request) -> UniValue {
891 std::shared_ptr<CWallet> const wallet =
893 if (!wallet) {
894 return NullUniValue;
895 }
896 const CWallet *const pwallet = wallet.get();
897
898 LegacyScriptPubKeyMan &spk_man =
900
901 LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
902
903 EnsureWalletIsUnlocked(pwallet);
904
905 std::string strAddress = request.params[0].get_str();
906 CTxDestination dest =
907 DecodeDestination(strAddress, wallet->GetChainParams());
908 if (!IsValidDestination(dest)) {
910 "Invalid Bitcoin address");
911 }
912 auto keyid = GetKeyForDestination(spk_man, dest);
913 if (keyid.IsNull()) {
915 "Address does not refer to a key");
916 }
917 CKey vchSecret;
918 if (!spk_man.GetKey(keyid, vchSecret)) {
920 "Private key for address " + strAddress +
921 " is not known");
922 }
923 return EncodeSecret(vchSecret);
924 },
925 };
926}
927
929 return RPCHelpMan{
930 "dumpwallet",
931 "Dumps all wallet keys in a human-readable format to a server-side "
932 "file. This does not allow overwriting existing files.\n"
933 "Imported scripts are included in the dumpsfile, but corresponding "
934 "addresses may not be added automatically by importwallet.\n"
935 "Note that if your wallet contains keys which are not derived from "
936 "your HD seed (e.g. imported keys), these are not covered by\n"
937 "only backing up the seed itself, and must be backed up too (e.g. "
938 "ensure you back up the whole dumpfile).\n"
939 "Note: This command is only compatible with legacy wallets.\n",
940 {
942 "The filename with path (absolute path recommended)"},
943 },
945 "",
946 "",
947 {
948 {RPCResult::Type::STR, "filename",
949 "The filename with full absolute path"},
950 }},
951 RPCExamples{HelpExampleCli("dumpwallet", "\"test\"") +
952 HelpExampleRpc("dumpwallet", "\"test\"")},
953 [&](const RPCHelpMan &self, const Config &config,
954 const JSONRPCRequest &request) -> UniValue {
955 std::shared_ptr<CWallet> const pwallet =
957 if (!pwallet) {
958 return NullUniValue;
959 }
960
961 CWallet &wallet = *pwallet;
962 LegacyScriptPubKeyMan &spk_man =
964
965 // Make sure the results are valid at least up to the most recent
966 // block the user could have gotten from another RPC command prior
967 // to now
968 wallet.BlockUntilSyncedToCurrentChain();
969
970 LOCK(wallet.cs_wallet);
971
973
974 fs::path filepath = fs::u8path(request.params[0].get_str());
975 filepath = fs::absolute(filepath);
976
983 if (fs::exists(filepath)) {
985 filepath.u8string() +
986 " already exists. If you are "
987 "sure this is what you want, "
988 "move it out of the way first");
989 }
990
991 std::ofstream file;
992 file.open(filepath);
993 if (!file.is_open()) {
995 "Cannot open wallet dump file");
996 }
997
998 std::map<CKeyID, int64_t> mapKeyBirth;
999 wallet.GetKeyBirthTimes(mapKeyBirth);
1000
1001 int64_t block_time = 0;
1002 CHECK_NONFATAL(wallet.chain().findBlock(
1003 wallet.GetLastBlockHash(), FoundBlock().time(block_time)));
1004
1005 // Note: To avoid a lock order issue, access to cs_main must be
1006 // locked before cs_KeyStore. So we do the two things in this
1007 // function that lock cs_main first: GetKeyBirthTimes, and
1008 // findBlock.
1009 LOCK(spk_man.cs_KeyStore);
1010
1011 const std::map<CKeyID, int64_t> &mapKeyPool =
1012 spk_man.GetAllReserveKeys();
1013 std::set<CScriptID> scripts = spk_man.GetCScripts();
1014
1015 // sort time/key pairs
1016 std::vector<std::pair<int64_t, CKeyID>> vKeyBirth;
1017 for (const auto &entry : mapKeyBirth) {
1018 vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
1019 }
1020 mapKeyBirth.clear();
1021 std::sort(vKeyBirth.begin(), vKeyBirth.end());
1022
1023 // produce output
1024 file << strprintf("# Wallet dump created by %s %s\n", CLIENT_NAME,
1025 CLIENT_BUILD);
1026 file << strprintf("# * Created on %s\n",
1028 file << strprintf("# * Best block at time of backup was %i (%s),\n",
1029 wallet.GetLastBlockHeight(),
1030 wallet.GetLastBlockHash().ToString());
1031 file << strprintf("# mined on %s\n",
1032 FormatISO8601DateTime(block_time));
1033 file << "\n";
1034
1035 // add the base58check encoded extended master if the wallet uses HD
1036 CKeyID seed_id = spk_man.GetHDChain().seed_id;
1037 if (!seed_id.IsNull()) {
1038 CKey seed;
1039 if (spk_man.GetKey(seed_id, seed)) {
1040 CExtKey masterKey;
1041 masterKey.SetSeed(seed);
1042
1043 file << "# extended private masterkey: "
1044 << EncodeExtKey(masterKey) << "\n\n";
1045 }
1046 }
1047 for (std::vector<std::pair<int64_t, CKeyID>>::const_iterator it =
1048 vKeyBirth.begin();
1049 it != vKeyBirth.end(); it++) {
1050 const CKeyID &keyid = it->second;
1051 std::string strTime = FormatISO8601DateTime(it->first);
1052 std::string strAddr;
1053 std::string strLabel;
1054 CKey key;
1055 if (spk_man.GetKey(keyid, key)) {
1056 file << strprintf("%s %s ", EncodeSecret(key), strTime);
1057 if (GetWalletAddressesForKey(config, &spk_man, &wallet,
1058 keyid, strAddr, strLabel)) {
1059 file << strprintf("label=%s", strLabel);
1060 } else if (keyid == seed_id) {
1061 file << "hdseed=1";
1062 } else if (mapKeyPool.count(keyid)) {
1063 file << "reserve=1";
1064 } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
1065 file << "inactivehdseed=1";
1066 } else {
1067 file << "change=1";
1068 }
1069 file << strprintf(
1070 " # addr=%s%s\n", strAddr,
1071 (spk_man.mapKeyMetadata[keyid].has_key_origin
1072 ? " hdkeypath=" +
1073 WriteHDKeypath(spk_man.mapKeyMetadata[keyid]
1074 .key_origin.path)
1075 : ""));
1076 }
1077 }
1078 file << "\n";
1079 for (const CScriptID &scriptid : scripts) {
1080 CScript script;
1081 std::string create_time = "0";
1082 std::string address =
1083 EncodeDestination(ScriptHash(scriptid), config);
1084 // get birth times for scripts with metadata
1085 auto it = spk_man.m_script_metadata.find(scriptid);
1086 if (it != spk_man.m_script_metadata.end()) {
1087 create_time = FormatISO8601DateTime(it->second.nCreateTime);
1088 }
1089 if (spk_man.GetCScript(scriptid, script)) {
1090 file << strprintf("%s %s script=1", HexStr(script),
1091 create_time);
1092 file << strprintf(" # addr=%s\n", address);
1093 }
1094 }
1095 file << "\n";
1096 file << "# End of dump\n";
1097 file.close();
1098
1099 UniValue reply(UniValue::VOBJ);
1100 reply.pushKV("filename", filepath.u8string());
1101
1102 return reply;
1103 },
1104 };
1105}
1106
1108 return RPCHelpMan{
1109 "dumpcoins",
1110 "dump all the UTXO tracked by the wallet.\n",
1111 {},
1112 RPCResult{
1114 "",
1115 "",
1116 {{
1118 "address",
1119 "The list of UTXO corresponding to this address.",
1120 {{
1122 "",
1123 "",
1124 {
1125 {RPCResult::Type::STR_HEX, "txid",
1126 "The transaction id"},
1127 {RPCResult::Type::NUM, "vout", "The output number"},
1128 {RPCResult::Type::NUM, "depth", "The output's depth"},
1130 "The output's amount"},
1131 },
1132 }},
1133 }},
1134 },
1135 RPCExamples{HelpExampleCli("dumpcoins", "") +
1136 HelpExampleRpc("dumpcoins", "")},
1137 [&](const RPCHelpMan &self, const Config &config,
1138 const JSONRPCRequest &request) -> UniValue {
1139 std::shared_ptr<CWallet> const pwallet =
1141 if (!pwallet) {
1142 return NullUniValue;
1143 }
1144
1145 CWallet &wallet = *pwallet;
1146
1147 // Make sure the results are valid at least up to the most recent
1148 // block the user could have gotten from another RPC command prior
1149 // to now
1150 wallet.BlockUntilSyncedToCurrentChain();
1151
1152 LOCK(wallet.cs_wallet);
1153
1155
1156 UniValue result(UniValue::VOBJ);
1157 for (const auto &p : ListCoins(wallet)) {
1158 UniValue coins(UniValue::VARR);
1159 for (const auto &o : p.second) {
1161 utxo.pushKV("txid", o.tx->GetId().ToString());
1162 utxo.pushKV("vout", o.i);
1163 utxo.pushKV("depth", o.nDepth);
1164 utxo.pushKV("value", o.tx->tx->vout[o.i].nValue);
1165
1166 coins.push_back(std::move(utxo));
1167 }
1168
1169 result.pushKV(EncodeDestination(p.first, config), coins);
1170 }
1171
1172 return result;
1173 },
1174 };
1175}
1176
1178 // Input data
1180 std::unique_ptr<CScript> redeemscript;
1181
1182 // Output data
1183 std::set<CScript> import_scripts;
1186 std::map<CKeyID, bool> used_keys;
1187 std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
1188};
1189
1190enum class ScriptContext {
1192 TOP,
1194 P2SH,
1195};
1196
1197// Analyse the provided scriptPubKey, determining which keys and which redeem
1198// scripts from the ImportData struct are needed to spend it, and mark them as
1199// used. Returns an error string, or the empty string for success.
1200static std::string RecurseImportData(const CScript &script,
1201 ImportData &import_data,
1202 const ScriptContext script_ctx) {
1203 // Use Solver to obtain script type and parsed pubkeys or hashes:
1204 std::vector<std::vector<uint8_t>> solverdata;
1205 TxoutType script_type = Solver(script, solverdata);
1206
1207 switch (script_type) {
1208 case TxoutType::PUBKEY: {
1209 CPubKey pubkey(solverdata[0]);
1210 import_data.used_keys.emplace(pubkey.GetID(), false);
1211 return "";
1212 }
1213 case TxoutType::PUBKEYHASH: {
1214 CKeyID id = CKeyID(uint160(solverdata[0]));
1215 import_data.used_keys[id] = true;
1216 return "";
1217 }
1218 case TxoutType::SCRIPTHASH: {
1219 if (script_ctx == ScriptContext::P2SH) {
1221 "Trying to nest P2SH inside another P2SH");
1222 }
1223 CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
1224 CScriptID id = CScriptID(uint160(solverdata[0]));
1225 // Remove redeemscript from import_data to check for superfluous
1226 // script later.
1227 auto subscript = std::move(import_data.redeemscript);
1228 if (!subscript) {
1229 return "missing redeemscript";
1230 }
1231 if (CScriptID(*subscript) != id) {
1232 return "redeemScript does not match the scriptPubKey";
1233 }
1234 import_data.import_scripts.emplace(*subscript);
1235 return RecurseImportData(*subscript, import_data,
1237 }
1238 case TxoutType::MULTISIG: {
1239 for (size_t i = 1; i + 1 < solverdata.size(); ++i) {
1240 CPubKey pubkey(solverdata[i]);
1241 import_data.used_keys.emplace(pubkey.GetID(), false);
1242 }
1243 return "";
1244 }
1246 return "unspendable script";
1248 default:
1249 return "unrecognized script";
1250 }
1251}
1252
1254 CWallet *const pwallet, ImportData &import_data,
1255 std::map<CKeyID, CPubKey> &pubkey_map, std::map<CKeyID, CKey> &privkey_map,
1256 std::set<CScript> &script_pub_keys, bool &have_solving_data,
1257 const UniValue &data, std::vector<CKeyID> &ordered_pubkeys) {
1258 UniValue warnings(UniValue::VARR);
1259
1260 // First ensure scriptPubKey has either a script or JSON with "address"
1261 // string
1262 const UniValue &scriptPubKey = data["scriptPubKey"];
1263 bool isScript = scriptPubKey.getType() == UniValue::VSTR;
1264 if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ &&
1265 scriptPubKey.exists("address"))) {
1267 "scriptPubKey must be string with script or JSON "
1268 "with address string");
1269 }
1270 const std::string &output =
1271 isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
1272
1273 // Optional fields.
1274 const std::string &strRedeemScript =
1275 data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
1276 const UniValue &pubKeys =
1277 data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
1278 const UniValue &keys =
1279 data.exists("keys") ? data["keys"].get_array() : UniValue();
1280 const bool internal =
1281 data.exists("internal") ? data["internal"].get_bool() : false;
1282 const bool watchOnly =
1283 data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1284
1285 if (data.exists("range")) {
1286 throw JSONRPCError(
1288 "Range should not be specified for a non-descriptor import");
1289 }
1290
1291 // Generate the script and destination for the scriptPubKey provided
1292 CScript script;
1293 if (!isScript) {
1294 CTxDestination dest =
1295 DecodeDestination(output, pwallet->GetChainParams());
1296 if (!IsValidDestination(dest)) {
1298 "Invalid address \"" + output + "\"");
1299 }
1300 script = GetScriptForDestination(dest);
1301 } else {
1302 if (!IsHex(output)) {
1304 "Invalid scriptPubKey \"" + output + "\"");
1305 }
1306 std::vector<uint8_t> vData(ParseHex(output));
1307 script = CScript(vData.begin(), vData.end());
1308 CTxDestination dest;
1309 if (!ExtractDestination(script, dest) && !internal) {
1311 "Internal must be set to true for "
1312 "nonstandard scriptPubKey imports.");
1313 }
1314 }
1315 script_pub_keys.emplace(script);
1316
1317 // Parse all arguments
1318 if (strRedeemScript.size()) {
1319 if (!IsHex(strRedeemScript)) {
1321 "Invalid redeem script \"" + strRedeemScript +
1322 "\": must be hex string");
1323 }
1324 auto parsed_redeemscript = ParseHex(strRedeemScript);
1325 import_data.redeemscript = std::make_unique<CScript>(
1326 parsed_redeemscript.begin(), parsed_redeemscript.end());
1327 }
1328 for (size_t i = 0; i < pubKeys.size(); ++i) {
1329 const auto &str = pubKeys[i].get_str();
1330 if (!IsHex(str)) {
1332 "Pubkey \"" + str + "\" must be a hex string");
1333 }
1334 auto parsed_pubkey = ParseHex(str);
1335 CPubKey pubkey(parsed_pubkey);
1336 if (!pubkey.IsFullyValid()) {
1338 "Pubkey \"" + str +
1339 "\" is not a valid public key");
1340 }
1341 pubkey_map.emplace(pubkey.GetID(), pubkey);
1342 ordered_pubkeys.push_back(pubkey.GetID());
1343 }
1344 for (size_t i = 0; i < keys.size(); ++i) {
1345 const auto &str = keys[i].get_str();
1346 CKey key = DecodeSecret(str);
1347 if (!key.IsValid()) {
1349 "Invalid private key encoding");
1350 }
1351 CPubKey pubkey = key.GetPubKey();
1352 CKeyID id = pubkey.GetID();
1353 if (pubkey_map.count(id)) {
1354 pubkey_map.erase(id);
1355 }
1356 privkey_map.emplace(id, key);
1357 }
1358
1359 // Verify and process input data
1360 have_solving_data =
1361 import_data.redeemscript || pubkey_map.size() || privkey_map.size();
1362 if (have_solving_data) {
1363 // Match up data in import_data with the scriptPubKey in script.
1364 auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1365
1366 // Verify whether the watchonly option corresponds to the
1367 // availability of private keys.
1368 bool spendable = std::all_of(
1369 import_data.used_keys.begin(), import_data.used_keys.end(),
1370 [&](const std::pair<CKeyID, bool> &used_key) {
1371 return privkey_map.count(used_key.first) > 0;
1372 });
1373 if (!watchOnly && !spendable) {
1374 warnings.push_back("Some private keys are missing, outputs "
1375 "will be considered watchonly. If this is "
1376 "intentional, specify the watchonly flag.");
1377 }
1378 if (watchOnly && spendable) {
1379 warnings.push_back(
1380 "All private keys are provided, outputs will be considered "
1381 "spendable. If this is intentional, do not specify the "
1382 "watchonly flag.");
1383 }
1384
1385 // Check that all required keys for solvability are provided.
1386 if (error.empty()) {
1387 for (const auto &require_key : import_data.used_keys) {
1388 if (!require_key.second) {
1389 // Not a required key
1390 continue;
1391 }
1392
1393 if (pubkey_map.count(require_key.first) == 0 &&
1394 privkey_map.count(require_key.first) == 0) {
1395 error = "some required keys are missing";
1396 }
1397 }
1398 }
1399
1400 if (!error.empty()) {
1401 warnings.push_back("Importing as non-solvable: " + error +
1402 ". If this is intentional, don't provide "
1403 "any keys, pubkeys or redeemscript.");
1404 import_data = ImportData();
1405 pubkey_map.clear();
1406 privkey_map.clear();
1407 have_solving_data = false;
1408 } else {
1409 // RecurseImportData() removes any relevant redeemscript from
1410 // import_data, so we can use that to discover if a superfluous
1411 // one was provided.
1412 if (import_data.redeemscript) {
1413 warnings.push_back(
1414 "Ignoring redeemscript as this is not a P2SH script.");
1415 }
1416 for (auto it = privkey_map.begin(); it != privkey_map.end();) {
1417 auto oldit = it++;
1418 if (import_data.used_keys.count(oldit->first) == 0) {
1419 warnings.push_back("Ignoring irrelevant private key.");
1420 privkey_map.erase(oldit);
1421 }
1422 }
1423 for (auto it = pubkey_map.begin(); it != pubkey_map.end();) {
1424 auto oldit = it++;
1425 auto key_data_it = import_data.used_keys.find(oldit->first);
1426 if (key_data_it == import_data.used_keys.end() ||
1427 !key_data_it->second) {
1428 warnings.push_back("Ignoring public key \"" +
1429 HexStr(oldit->first) +
1430 "\" as it doesn't appear inside P2PKH.");
1431 pubkey_map.erase(oldit);
1432 }
1433 }
1434 }
1435 }
1436
1437 return warnings;
1438}
1439
1441 std::map<CKeyID, CPubKey> &pubkey_map,
1442 std::map<CKeyID, CKey> &privkey_map,
1443 std::set<CScript> &script_pub_keys,
1444 bool &have_solving_data,
1445 const UniValue &data,
1446 std::vector<CKeyID> &ordered_pubkeys) {
1447 UniValue warnings(UniValue::VARR);
1448
1449 const std::string &descriptor = data["desc"].get_str();
1451 std::string error;
1452 auto parsed_desc =
1453 Parse(descriptor, keys, error, /* require_checksum = */ true);
1454 if (!parsed_desc) {
1456 }
1457
1458 have_solving_data = parsed_desc->IsSolvable();
1459 const bool watch_only =
1460 data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1461
1462 int64_t range_start = 0, range_end = 0;
1463 if (!parsed_desc->IsRange() && data.exists("range")) {
1464 throw JSONRPCError(
1466 "Range should not be specified for an un-ranged descriptor");
1467 } else if (parsed_desc->IsRange()) {
1468 if (!data.exists("range")) {
1469 throw JSONRPCError(
1471 "Descriptor is ranged, please specify the range");
1472 }
1473 std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1474 }
1475
1476 const UniValue &priv_keys =
1477 data.exists("keys") ? data["keys"].get_array() : UniValue();
1478
1479 // Expand all descriptors to get public keys and scripts, and private keys
1480 // if available.
1481 for (int i = range_start; i <= range_end; ++i) {
1482 FlatSigningProvider out_keys;
1483 std::vector<CScript> scripts_temp;
1484 parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1485 std::copy(scripts_temp.begin(), scripts_temp.end(),
1486 std::inserter(script_pub_keys, script_pub_keys.end()));
1487 for (const auto &key_pair : out_keys.pubkeys) {
1488 ordered_pubkeys.push_back(key_pair.first);
1489 }
1490
1491 for (const auto &x : out_keys.scripts) {
1492 import_data.import_scripts.emplace(x.second);
1493 }
1494
1495 parsed_desc->ExpandPrivate(i, keys, out_keys);
1496
1497 std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(),
1498 std::inserter(pubkey_map, pubkey_map.end()));
1499 std::copy(out_keys.keys.begin(), out_keys.keys.end(),
1500 std::inserter(privkey_map, privkey_map.end()));
1501 import_data.key_origins.insert(out_keys.origins.begin(),
1502 out_keys.origins.end());
1503 }
1504
1505 for (size_t i = 0; i < priv_keys.size(); ++i) {
1506 const auto &str = priv_keys[i].get_str();
1507 CKey key = DecodeSecret(str);
1508 if (!key.IsValid()) {
1510 "Invalid private key encoding");
1511 }
1512 CPubKey pubkey = key.GetPubKey();
1513 CKeyID id = pubkey.GetID();
1514
1515 // Check if this private key corresponds to a public key from the
1516 // descriptor
1517 if (!pubkey_map.count(id)) {
1518 warnings.push_back("Ignoring irrelevant private key.");
1519 } else {
1520 privkey_map.emplace(id, key);
1521 }
1522 }
1523
1524 // Check if all the public keys have corresponding private keys in the
1525 // import for spendability. This does not take into account threshold
1526 // multisigs which could be spendable without all keys. Thus, threshold
1527 // multisigs without all keys will be considered not spendable here, even if
1528 // they are, perhaps triggering a false warning message. This is consistent
1529 // with the current wallet IsMine check.
1530 bool spendable =
1531 std::all_of(pubkey_map.begin(), pubkey_map.end(),
1532 [&](const std::pair<CKeyID, CPubKey> &used_key) {
1533 return privkey_map.count(used_key.first) > 0;
1534 }) &&
1535 std::all_of(
1536 import_data.key_origins.begin(), import_data.key_origins.end(),
1537 [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>
1538 &entry) { return privkey_map.count(entry.first) > 0; });
1539 if (!watch_only && !spendable) {
1540 warnings.push_back(
1541 "Some private keys are missing, outputs will be considered "
1542 "watchonly. If this is intentional, specify the watchonly flag.");
1543 }
1544 if (watch_only && spendable) {
1545 warnings.push_back("All private keys are provided, outputs will be "
1546 "considered spendable. If this is intentional, do "
1547 "not specify the watchonly flag.");
1548 }
1549
1550 return warnings;
1551}
1552
1553static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data,
1554 const int64_t timestamp)
1555 EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1556 UniValue warnings(UniValue::VARR);
1557 UniValue result(UniValue::VOBJ);
1558
1559 try {
1560 const bool internal =
1561 data.exists("internal") ? data["internal"].get_bool() : false;
1562 // Internal addresses should not have a label
1563 if (internal && data.exists("label")) {
1565 "Internal addresses should not have a label");
1566 }
1567 const std::string &label =
1568 data.exists("label") ? data["label"].get_str() : "";
1569 const bool add_keypool =
1570 data.exists("keypool") ? data["keypool"].get_bool() : false;
1571
1572 // Add to keypool only works with privkeys disabled
1573 if (add_keypool &&
1574 !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1576 "Keys can only be imported to the keypool when "
1577 "private keys are disabled");
1578 }
1579
1580 ImportData import_data;
1581 std::map<CKeyID, CPubKey> pubkey_map;
1582 std::map<CKeyID, CKey> privkey_map;
1583 std::set<CScript> script_pub_keys;
1584 std::vector<CKeyID> ordered_pubkeys;
1585 bool have_solving_data;
1586
1587 if (data.exists("scriptPubKey") && data.exists("desc")) {
1588 throw JSONRPCError(
1590 "Both a descriptor and a scriptPubKey should not be provided.");
1591 } else if (data.exists("scriptPubKey")) {
1592 warnings = ProcessImportLegacy(
1593 pwallet, import_data, pubkey_map, privkey_map, script_pub_keys,
1594 have_solving_data, data, ordered_pubkeys);
1595 } else if (data.exists("desc")) {
1596 warnings = ProcessImportDescriptor(
1597 import_data, pubkey_map, privkey_map, script_pub_keys,
1598 have_solving_data, data, ordered_pubkeys);
1599 } else {
1600 throw JSONRPCError(
1602 "Either a descriptor or scriptPubKey must be provided.");
1603 }
1604
1605 // If private keys are disabled, abort if private keys are being
1606 // imported
1607 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
1608 !privkey_map.empty()) {
1610 "Cannot import private keys to a wallet with "
1611 "private keys disabled");
1612 }
1613
1614 // Check whether we have any work to do
1615 for (const CScript &script : script_pub_keys) {
1616 if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1618 "The wallet already contains the private "
1619 "key for this address or script (\"" +
1620 HexStr(script) + "\")");
1621 }
1622 }
1623
1624 // All good, time to import
1625 pwallet->MarkDirty();
1626 if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1628 "Error adding script to wallet");
1629 }
1630 if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1631 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1632 }
1633 if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map,
1634 import_data.key_origins, add_keypool,
1635 internal, timestamp)) {
1637 "Error adding address to wallet");
1638 }
1639 if (!pwallet->ImportScriptPubKeys(label, script_pub_keys,
1640 have_solving_data, !internal,
1641 timestamp)) {
1643 "Error adding address to wallet");
1644 }
1645
1646 result.pushKV("success", UniValue(true));
1647 } catch (const UniValue &e) {
1648 result.pushKV("success", UniValue(false));
1649 result.pushKV("error", e);
1650 } catch (...) {
1651 result.pushKV("success", UniValue(false));
1652 result.pushKV("error",
1653 JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1654 }
1655
1656 if (warnings.size()) {
1657 result.pushKV("warnings", warnings);
1658 }
1659 return result;
1660}
1661
1662static int64_t GetImportTimestamp(const UniValue &data, int64_t now) {
1663 if (data.exists("timestamp")) {
1664 const UniValue &timestamp = data["timestamp"];
1665 if (timestamp.isNum()) {
1666 return timestamp.getInt<int64_t>();
1667 } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1668 return now;
1669 }
1671 strprintf("Expected number or \"now\" timestamp "
1672 "value for key. got type %s",
1673 uvTypeName(timestamp.type())));
1674 }
1676 "Missing required timestamp field for key");
1677}
1678
1679static std::string GetRescanErrorMessage(const std::string &object,
1680 const int64_t objectTimestamp,
1681 const int64_t blockTimestamp,
1682 const bool have_pruned,
1683 const bool has_assumed_valid_chain) {
1684 std::string error_msg{
1685 strprintf("Rescan failed for %s with creation timestamp %d. There "
1686 "was an error reading a block from time %d, which is after "
1687 "or within %d seconds of key creation, and could contain "
1688 "transactions pertaining to the %s. As a result, "
1689 "transactions and coins using this %s may not appear "
1690 "in the wallet. ",
1691 object, objectTimestamp, blockTimestamp, TIMESTAMP_WINDOW,
1692 object, object)};
1693 if (have_pruned) {
1694 error_msg += strprintf(
1695 "This error could be caused by pruning or data corruption "
1696 "(see bitcoind log for details) and could be dealt with by "
1697 "downloading and rescanning the relevant blocks (see -reindex "
1698 "option and rescanblockchain RPC).");
1699 } else if (has_assumed_valid_chain) {
1700 error_msg += strprintf(
1701 "This error is likely caused by an in-progress assumeutxo "
1702 "background sync. Check logs or getchainstates RPC for assumeutxo "
1703 "background sync progress and try again later.");
1704 } else {
1705 error_msg += strprintf(
1706 "This error could potentially be caused by data corruption. If "
1707 "the issue persists you may want to reindex (see -reindex "
1708 "option).");
1709 }
1710 return error_msg;
1711}
1712
1714 return RPCHelpMan{
1715 "importmulti",
1716 "Import addresses/scripts (with private or public keys, redeem "
1717 "script (P2SH)), optionally rescanning the blockchain from the "
1718 "earliest creation time of the imported scripts. Requires a new wallet "
1719 "backup.\n"
1720 "If an address/script is imported without all of the private keys "
1721 "required to spend from that address, it will be watchonly. The "
1722 "'watchonly' option must be set to true in this case or a warning will "
1723 "be returned.\n"
1724 "Conversely, if all the private keys are provided and the "
1725 "address/script is spendable, the watchonly option must be set to "
1726 "false, or a warning will be returned.\n"
1727 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
1728 "Note: This command is only compatible with legacy wallets. Use "
1729 "\"importdescriptors\" for descriptor wallets.\n",
1730 {
1731 {"requests",
1734 "Data to be imported",
1735 {
1736 {
1737 "",
1740 "",
1741 {
1743 "Descriptor to import. If using descriptor, do not "
1744 "also provide address/scriptPubKey, scripts, or "
1745 "pubkeys"},
1746 {"scriptPubKey", RPCArg::Type::STR,
1748 "Type of scriptPubKey (string for script, json for "
1749 "address). Should not be provided if using a "
1750 "descriptor",
1752 .type_str = {"\"<script>\" | { "
1753 "\"address\":\"<address>\" }",
1754 "string / json"}}},
1756 "Creation time of the key expressed in " +
1758 ",\n"
1759 "or the string \"now\" to substitute the current "
1760 "synced blockchain time. The timestamp of the "
1761 "oldest\n"
1762 "key will determine how far back blockchain "
1763 "rescans need to begin for missing wallet "
1764 "transactions.\n"
1765 "\"now\" can be specified to bypass scanning, "
1766 "for keys which are known to never have been "
1767 "used, and\n"
1768 "0 can be specified to scan the entire "
1769 "blockchain. Blocks up to 2 hours before the "
1770 "earliest key\n"
1771 "creation time of all keys being imported by the "
1772 "importmulti call will be scanned.",
1773 RPCArgOptions{.type_str = {"timestamp | \"now\"",
1774 "integer / string"}}},
1775 {"redeemscript", RPCArg::Type::STR,
1777 "Allowed only if the scriptPubKey is a P2SH "
1778 "address/scriptPubKey"},
1779 {"pubkeys",
1782 "Array of strings giving pubkeys to import. They "
1783 "must occur in P2PKH scripts. They are not required "
1784 "when the private key is also provided (see the "
1785 "\"keys\" argument).",
1786 {
1787 {"pubKey", RPCArg::Type::STR,
1789 }},
1790 {"keys",
1793 "Array of strings giving private keys to import. The "
1794 "corresponding public keys must occur in the output "
1795 "or redeemscript.",
1796 {
1797 {"key", RPCArg::Type::STR,
1799 }},
1800 {"range", RPCArg::Type::RANGE,
1802 "If a ranged descriptor is used, this specifies the "
1803 "end or the range (in the form [begin,end]) to "
1804 "import"},
1805 {"internal", RPCArg::Type::BOOL,
1806 RPCArg::Default{false},
1807 "Stating whether matching outputs should be treated "
1808 "as not incoming payments (also known as change)"},
1809 {"watchonly", RPCArg::Type::BOOL,
1810 RPCArg::Default{false},
1811 "Stating whether matching outputs should be "
1812 "considered watchonly."},
1813 {"label", RPCArg::Type::STR, RPCArg::Default{""},
1814 "Label to assign to the address, only allowed with "
1815 "internal=false"},
1816 {"keypool", RPCArg::Type::BOOL, RPCArg::Default{false},
1817 "Stating whether imported public keys should be "
1818 "added to the keypool for when users request new "
1819 "addresses. Only allowed when wallet private keys "
1820 "are disabled"},
1821 },
1822 },
1823 },
1824 RPCArgOptions{.oneline_description = "\"requests\""}},
1825 {"options",
1828 "",
1829 {
1830 {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
1831 "Stating if should rescan the blockchain after all imports"},
1832 },
1833 RPCArgOptions{.oneline_description = "\"options\""}},
1834 },
1836 "",
1837 "Response is an array with the same size as the input that "
1838 "has the execution result",
1839 {
1841 "",
1842 "",
1843 {
1844 {RPCResult::Type::BOOL, "success", ""},
1846 "warnings",
1847 /* optional */ true,
1848 "",
1849 {
1850 {RPCResult::Type::STR, "", ""},
1851 }},
1853 "error",
1854 /* optional */ true,
1855 "",
1856 {
1857 {RPCResult::Type::ELISION, "", "JSONRPC error"},
1858 }},
1859 }},
1860 }},
1863 "importmulti",
1864 "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1865 "\"timestamp\":1455191478 }, "
1866 "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" "
1867 "}, "
1868 "\"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1870 "importmulti",
1871 "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1872 "\"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1873
1874 },
1875 [&](const RPCHelpMan &self, const Config &config,
1876 const JSONRPCRequest &mainRequest) -> UniValue {
1877 std::shared_ptr<CWallet> const wallet =
1878 GetWalletForJSONRPCRequest(mainRequest);
1879 if (!wallet) {
1880 return NullUniValue;
1881 }
1882 CWallet *const pwallet = wallet.get();
1883
1885
1886 const UniValue &requests = mainRequest.params[0];
1887
1888 // Default options
1889 bool fRescan = true;
1890
1891 if (!mainRequest.params[1].isNull()) {
1892 const UniValue &options = mainRequest.params[1];
1893
1894 if (options.exists("rescan")) {
1895 fRescan = options["rescan"].get_bool();
1896 }
1897 }
1898
1899 WalletRescanReserver reserver(*pwallet);
1900 if (fRescan && !reserver.reserve()) {
1902 "Wallet is currently rescanning. Abort "
1903 "existing rescan or wait.");
1904 }
1905
1906 int64_t now = 0;
1907 bool fRunScan = false;
1908 int64_t nLowestTimestamp = 0;
1910 {
1911 LOCK(pwallet->cs_wallet);
1912 EnsureWalletIsUnlocked(pwallet);
1913
1914 // Verify all timestamps are present before importing any keys.
1915 CHECK_NONFATAL(pwallet->chain().findBlock(
1916 pwallet->GetLastBlockHash(),
1917 FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1918 for (const UniValue &data : requests.getValues()) {
1919 GetImportTimestamp(data, now);
1920 }
1921
1922 const int64_t minimumTimestamp = 1;
1923
1924 for (const UniValue &data : requests.getValues()) {
1925 const int64_t timestamp = std::max(
1926 GetImportTimestamp(data, now), minimumTimestamp);
1927 const UniValue result =
1928 ProcessImport(pwallet, data, timestamp);
1929 response.push_back(result);
1930
1931 if (!fRescan) {
1932 continue;
1933 }
1934
1935 // If at least one request was successful then allow rescan.
1936 if (result["success"].get_bool()) {
1937 fRunScan = true;
1938 }
1939
1940 // Get the lowest timestamp.
1941 if (timestamp < nLowestTimestamp) {
1942 nLowestTimestamp = timestamp;
1943 }
1944 }
1945 }
1946 if (fRescan && fRunScan && requests.size()) {
1947 int64_t scannedTime = pwallet->RescanFromTime(
1948 nLowestTimestamp, reserver, true /* update */);
1949 {
1950 LOCK(pwallet->cs_wallet);
1951 pwallet->ReacceptWalletTransactions();
1952 }
1953
1954 if (pwallet->IsAbortingRescan()) {
1956 "Rescan aborted by user.");
1957 }
1958 if (scannedTime > nLowestTimestamp) {
1959 std::vector<UniValue> results = response.getValues();
1960 response.clear();
1961 response.setArray();
1962 size_t i = 0;
1963 for (const UniValue &request : requests.getValues()) {
1964 // If key creation date is within the successfully
1965 // scanned range, or if the import result already has an
1966 // error set, let the result stand unmodified. Otherwise
1967 // replace the result with an error message.
1968 if (scannedTime <= GetImportTimestamp(request, now) ||
1969 results.at(i).exists("error")) {
1970 response.push_back(results.at(i));
1971 } else {
1973 result.pushKV("success", UniValue(false));
1974 result.pushKV(
1975 "error",
1979 "key", GetImportTimestamp(request, now),
1980 scannedTime - TIMESTAMP_WINDOW - 1,
1981 pwallet->chain().havePruned(),
1982 pwallet->chain()
1984 response.push_back(std::move(result));
1985 }
1986 ++i;
1987 }
1988 }
1989 }
1990
1991 return response;
1992 },
1993 };
1994}
1995
1997 const UniValue &data,
1998 const int64_t timestamp)
1999 EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
2000 UniValue warnings(UniValue::VARR);
2001 UniValue result(UniValue::VOBJ);
2002
2003 try {
2004 if (!data.exists("desc")) {
2005 throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor not found.");
2006 }
2007
2008 const std::string &descriptor = data["desc"].get_str();
2009 const bool active =
2010 data.exists("active") ? data["active"].get_bool() : false;
2011 const bool internal =
2012 data.exists("internal") ? data["internal"].get_bool() : false;
2013 const std::string &label =
2014 data.exists("label") ? data["label"].get_str() : "";
2015
2016 // Parse descriptor string
2018 std::string error;
2019 auto parsed_desc =
2020 Parse(descriptor, keys, error, /* require_checksum = */ true);
2021 if (!parsed_desc) {
2023 }
2024
2025 // Range check
2026 int64_t range_start = 0, range_end = 1, next_index = 0;
2027 if (!parsed_desc->IsRange() && data.exists("range")) {
2028 throw JSONRPCError(
2030 "Range should not be specified for an un-ranged descriptor");
2031 } else if (parsed_desc->IsRange()) {
2032 if (data.exists("range")) {
2033 auto range = ParseDescriptorRange(data["range"]);
2034 range_start = range.first;
2035 // Specified range end is inclusive, but we need range end as
2036 // exclusive
2037 range_end = range.second + 1;
2038 } else {
2039 warnings.push_back(
2040 "Range not given, using default keypool range");
2041 range_start = 0;
2042 range_end = gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE);
2043 }
2044 next_index = range_start;
2045
2046 if (data.exists("next_index")) {
2047 next_index = data["next_index"].getInt<int64_t>();
2048 // bound checks
2049 if (next_index < range_start || next_index >= range_end) {
2051 "next_index is out of range");
2052 }
2053 }
2054 }
2055
2056 // Active descriptors must be ranged
2057 if (active && !parsed_desc->IsRange()) {
2059 "Active descriptors must be ranged");
2060 }
2061
2062 // Ranged descriptors should not have a label
2063 if (data.exists("range") && data.exists("label")) {
2065 "Ranged descriptors should not have a label");
2066 }
2067
2068 // Internal addresses should not have a label either
2069 if (internal && data.exists("label")) {
2071 "Internal addresses should not have a label");
2072 }
2073
2074 // Combo descriptor check
2075 if (active && !parsed_desc->IsSingleType()) {
2077 "Combo descriptors cannot be set to active");
2078 }
2079
2080 // If the wallet disabled private keys, abort if private keys exist
2081 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
2082 !keys.keys.empty()) {
2084 "Cannot import private keys to a wallet with "
2085 "private keys disabled");
2086 }
2087
2088 // Need to ExpandPrivate to check if private keys are available for all
2089 // pubkeys
2090 FlatSigningProvider expand_keys;
2091 std::vector<CScript> scripts;
2092 if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
2093 throw JSONRPCError(
2095 "Cannot expand descriptor. Probably because of hardened "
2096 "derivations without private keys provided");
2097 }
2098 parsed_desc->ExpandPrivate(0, keys, expand_keys);
2099
2100 // Check if all private keys are provided
2101 bool have_all_privkeys = !expand_keys.keys.empty();
2102 for (const auto &entry : expand_keys.origins) {
2103 const CKeyID &key_id = entry.first;
2104 CKey key;
2105 if (!expand_keys.GetKey(key_id, key)) {
2106 have_all_privkeys = false;
2107 break;
2108 }
2109 }
2110
2111 // If private keys are enabled, check some things.
2112 if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
2113 if (keys.keys.empty()) {
2114 throw JSONRPCError(
2116 "Cannot import descriptor without private keys to a wallet "
2117 "with private keys enabled");
2118 }
2119 if (!have_all_privkeys) {
2120 warnings.push_back(
2121 "Not all private keys provided. Some wallet functionality "
2122 "may return unexpected errors");
2123 }
2124 }
2125
2126 WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start,
2127 range_end, next_index);
2128
2129 // Check if the wallet already contains the descriptor
2130 auto existing_spk_manager =
2131 pwallet->GetDescriptorScriptPubKeyMan(w_desc);
2132 if (existing_spk_manager &&
2133 !existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) {
2135 }
2136
2137 // Add descriptor to the wallet
2138 auto spk_manager =
2139 pwallet->AddWalletDescriptor(w_desc, keys, label, internal);
2140 if (spk_manager == nullptr) {
2141 throw JSONRPCError(
2143 strprintf("Could not add descriptor '%s'", descriptor));
2144 }
2145
2146 // Set descriptor as active if necessary
2147 if (active) {
2148 if (!w_desc.descriptor->GetOutputType()) {
2149 warnings.push_back(
2150 "Unknown output type, cannot set descriptor to active.");
2151 } else {
2152 pwallet->AddActiveScriptPubKeyMan(
2153 spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2154 internal);
2155 }
2156 } else {
2157 if (w_desc.descriptor->GetOutputType()) {
2158 pwallet->DeactivateScriptPubKeyMan(
2159 spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2160 internal);
2161 }
2162 }
2163
2164 result.pushKV("success", UniValue(true));
2165 } catch (const UniValue &e) {
2166 result.pushKV("success", UniValue(false));
2167 result.pushKV("error", e);
2168 }
2169 if (warnings.size()) {
2170 result.pushKV("warnings", warnings);
2171 }
2172 return result;
2173}
2174
2176 return RPCHelpMan{
2177 "importdescriptors",
2178 "Import descriptors. This will trigger a rescan of the blockchain "
2179 "based on the earliest timestamp of all descriptors being imported. "
2180 "Requires a new wallet backup.\n"
2181 "\nNote: This call can take over an hour to complete if using an early "
2182 "timestamp; during that time, other rpc calls\n"
2183 "may report that the imported keys, addresses or scripts exist but "
2184 "related transactions are still missing.\n",
2185 {
2186 {"requests",
2189 "Data to be imported",
2190 {
2191 {
2192 "",
2195 "",
2196 {
2198 "Descriptor to import."},
2199 {"active", RPCArg::Type::BOOL, RPCArg::Default{false},
2200 "Set this descriptor to be the active descriptor for "
2201 "the corresponding output type/externality"},
2202 {"range", RPCArg::Type::RANGE,
2204 "If a ranged descriptor is used, this specifies the "
2205 "end or the range (in the form [begin,end]) to "
2206 "import"},
2207 {"next_index", RPCArg::Type::NUM,
2209 "If a ranged descriptor is set to active, this "
2210 "specifies the next index to generate addresses "
2211 "from"},
2213 "Time from which to start rescanning the blockchain "
2214 "for this descriptor, in " +
2216 "\n"
2217 "Use the string \"now\" to substitute the "
2218 "current synced blockchain time.\n"
2219 "\"now\" can be specified to bypass scanning, "
2220 "for outputs which are known to never have been "
2221 "used, and\n"
2222 "0 can be specified to scan the entire "
2223 "blockchain. Blocks up to 2 hours before the "
2224 "earliest timestamp\n"
2225 "of all descriptors being imported will be "
2226 "scanned.",
2227 RPCArgOptions{.type_str = {"timestamp | \"now\"",
2228 "integer / string"}}},
2229 {"internal", RPCArg::Type::BOOL,
2230 RPCArg::Default{false},
2231 "Whether matching outputs should be treated as not "
2232 "incoming payments (e.g. change)"},
2233 {"label", RPCArg::Type::STR, RPCArg::Default{""},
2234 "Label to assign to the address, only allowed with "
2235 "internal=false"},
2236 },
2237 },
2238 },
2239 RPCArgOptions{.oneline_description = "\"requests\""}},
2240 },
2242 "",
2243 "Response is an array with the same size as the input that "
2244 "has the execution result",
2245 {
2247 "",
2248 "",
2249 {
2250 {RPCResult::Type::BOOL, "success", ""},
2252 "warnings",
2253 /* optional */ true,
2254 "",
2255 {
2256 {RPCResult::Type::STR, "", ""},
2257 }},
2259 "error",
2260 /* optional */ true,
2261 "",
2262 {
2263 {RPCResult::Type::ELISION, "", "JSONRPC error"},
2264 }},
2265 }},
2266 }},
2268 HelpExampleCli("importdescriptors",
2269 "'[{ \"desc\": \"<my descriptor>\", "
2270 "\"timestamp\":1455191478, \"internal\": true }, "
2271 "{ \"desc\": \"<my desccriptor 2>\", \"label\": "
2272 "\"example 2\", \"timestamp\": 1455191480 }]'") +
2274 "importdescriptors",
2275 "'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, "
2276 "\"active\": true, \"range\": [0,100], \"label\": \"<my "
2277 "cashaddr wallet>\" }]'")},
2278 [&](const RPCHelpMan &self, const Config &config,
2279 const JSONRPCRequest &main_request) -> UniValue {
2280 std::shared_ptr<CWallet> const wallet =
2281 GetWalletForJSONRPCRequest(main_request);
2282 if (!wallet) {
2283 return NullUniValue;
2284 }
2285 CWallet *const pwallet = wallet.get();
2286
2287 // Make sure wallet is a descriptor wallet
2290 "importdescriptors is not available for "
2291 "non-descriptor wallets");
2292 }
2293
2294 WalletRescanReserver reserver(*pwallet);
2295 if (!reserver.reserve()) {
2297 "Wallet is currently rescanning. Abort "
2298 "existing rescan or wait.");
2299 }
2300
2301 const UniValue &requests = main_request.params[0];
2302 const int64_t minimum_timestamp = 1;
2303 int64_t now = 0;
2304 int64_t lowest_timestamp = 0;
2305 bool rescan = false;
2307 {
2308 LOCK(pwallet->cs_wallet);
2309 EnsureWalletIsUnlocked(pwallet);
2310
2311 CHECK_NONFATAL(pwallet->chain().findBlock(
2312 pwallet->GetLastBlockHash(),
2313 FoundBlock().time(lowest_timestamp).mtpTime(now)));
2314
2315 // Get all timestamps and extract the lowest timestamp
2316 for (const UniValue &request : requests.getValues()) {
2317 // This throws an error if "timestamp" doesn't exist
2318 const int64_t timestamp = std::max(
2319 GetImportTimestamp(request, now), minimum_timestamp);
2320 const UniValue result =
2321 ProcessDescriptorImport(pwallet, request, timestamp);
2322 response.push_back(result);
2323
2324 if (lowest_timestamp > timestamp) {
2325 lowest_timestamp = timestamp;
2326 }
2327
2328 // If we know the chain tip, and at least one request was
2329 // successful then allow rescan
2330 if (!rescan && result["success"].get_bool()) {
2331 rescan = true;
2332 }
2333 }
2335 }
2336
2337 // Rescan the blockchain using the lowest timestamp
2338 if (rescan) {
2339 int64_t scanned_time = pwallet->RescanFromTime(
2340 lowest_timestamp, reserver, true /* update */);
2341 {
2342 LOCK(pwallet->cs_wallet);
2343 pwallet->ReacceptWalletTransactions();
2344 }
2345
2346 if (pwallet->IsAbortingRescan()) {
2348 "Rescan aborted by user.");
2349 }
2350
2351 if (scanned_time > lowest_timestamp) {
2352 std::vector<UniValue> results = response.getValues();
2353 response.clear();
2354 response.setArray();
2355
2356 // Compose the response
2357 for (unsigned int i = 0; i < requests.size(); ++i) {
2358 const UniValue &request = requests.getValues().at(i);
2359
2360 // If the descriptor timestamp is within the
2361 // successfully scanned range, or if the import result
2362 // already has an error set, let the result stand
2363 // unmodified. Otherwise replace the result with an
2364 // error message.
2365 if (scanned_time <= GetImportTimestamp(request, now) ||
2366 results.at(i).exists("error")) {
2367 response.push_back(results.at(i));
2368 } else {
2370 result.pushKV("success", UniValue(false));
2371 result.pushKV(
2372 "error",
2376 "descriptor",
2377 GetImportTimestamp(request, now),
2378 scanned_time - TIMESTAMP_WINDOW - 1,
2379 pwallet->chain().havePruned(),
2380 pwallet->chain()
2382 response.push_back(std::move(result));
2383 }
2384 }
2385 }
2386 }
2387
2388 return response;
2389 },
2390 };
2391}
2392
2394 return RPCHelpMan{
2395 "backupwallet",
2396 "Safely copies current wallet file to destination, which can be a "
2397 "directory or a path with filename.\n",
2398 {
2399 {"destination", RPCArg::Type::STR, RPCArg::Optional::NO,
2400 "The destination directory or file"},
2401 },
2403 RPCExamples{HelpExampleCli("backupwallet", "\"backup.dat\"") +
2404 HelpExampleRpc("backupwallet", "\"backup.dat\"")},
2405 [&](const RPCHelpMan &self, const Config &config,
2406 const JSONRPCRequest &request) -> UniValue {
2407 std::shared_ptr<CWallet> const wallet =
2409 if (!wallet) {
2410 return NullUniValue;
2411 }
2412 const CWallet *const pwallet = wallet.get();
2413
2414 // Make sure the results are valid at least up to the most recent
2415 // block the user could have gotten from another RPC command prior
2416 // to now
2417 pwallet->BlockUntilSyncedToCurrentChain();
2418
2419 LOCK(pwallet->cs_wallet);
2420
2421 std::string strDest = request.params[0].get_str();
2422 if (!pwallet->BackupWallet(strDest)) {
2424 "Error: Wallet backup failed!");
2425 }
2426
2427 return NullUniValue;
2428 },
2429 };
2430}
2431
2433 return RPCHelpMan{
2434 "restorewallet",
2435 "\nRestore and loads a wallet from backup.\n",
2436 {
2437 {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO,
2438 "The name that will be applied to the restored wallet"},
2439 {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO,
2440 "The backup file that will be used to restore the wallet."},
2441 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED,
2442 "Save wallet name to persistent settings and load on startup. "
2443 "True to add wallet to startup list, false to remove, null to "
2444 "leave unchanged."},
2445 },
2447 "",
2448 "",
2449 {
2450 {RPCResult::Type::STR, "name",
2451 "The wallet name if restored successfully."},
2452 {RPCResult::Type::STR, "warning",
2453 "Warning message if wallet was not loaded cleanly."},
2454 }},
2456 "restorewallet",
2457 "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2459 "restorewallet",
2460 "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2462 "restorewallet",
2463 {{"wallet_name", "testwallet"},
2464 {"backup_file", "home\\backups\\backup-file.bak\""},
2465 {"load_on_startup", true}}) +
2467 "restorewallet",
2468 {{"wallet_name", "testwallet"},
2469 {"backup_file", "home\\backups\\backup-file.bak\""},
2470 {"load_on_startup", true}})},
2471 [&](const RPCHelpMan &self, const Config &config,
2472 const JSONRPCRequest &request) -> UniValue {
2473 WalletContext &context = EnsureWalletContext(request.context);
2474
2475 fs::path backup_file =
2476 fs::PathFromString(request.params[1].get_str());
2477
2478 std::string wallet_name = request.params[0].get_str();
2479
2480 std::optional<bool> load_on_start =
2481 request.params[2].isNull()
2482 ? std::nullopt
2483 : std::optional<bool>(request.params[2].get_bool());
2484
2485 DatabaseStatus status;
2487 std::vector<bilingual_str> warnings;
2488
2489 const std::shared_ptr<CWallet> wallet =
2490 RestoreWallet(context, backup_file, wallet_name, load_on_start,
2491 status, error, warnings);
2492
2493 HandleWalletError(wallet, status, error);
2494
2496 obj.pushKV("name", wallet->GetName());
2497 obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2498
2499 return obj;
2500 },
2501 };
2502}
2503
2505 // clang-format off
2506 static const CRPCCommand commands[] = {
2507 // category actor (function)
2508 // ------------------ ----------------------
2509 { "wallet", abortrescan, },
2510 { "wallet", backupwallet, },
2511 { "wallet", dumpprivkey, },
2512 { "wallet", dumpwallet, },
2513 { "wallet", dumpcoins, },
2514 { "wallet", importdescriptors, },
2515 { "wallet", importmulti, },
2516 { "wallet", importprivkey, },
2517 { "wallet", importwallet, },
2518 { "wallet", importaddress, },
2519 { "wallet", importprunedfunds, },
2520 { "wallet", importpubkey, },
2521 { "wallet", removeprunedfunds, },
2522 { "wallet", restorewallet, },
2523 };
2524 // clang-format on
2525
2526 return commands;
2527}
ArgsManager gArgs
Definition: args.cpp:38
static RPCHelpMan dumpcoins()
Definition: backup.cpp:1107
RPCHelpMan importprivkey()
Definition: backup.cpp:131
static const int64_t TIMESTAMP_MIN
Definition: backup.cpp:94
RPCHelpMan importdescriptors()
Definition: backup.cpp:2175
static void RescanWallet(CWallet &wallet, const WalletRescanReserver &reserver, int64_t time_begin=TIMESTAMP_MIN, bool update=true)
Definition: backup.cpp:96
RPCHelpMan importmulti()
Definition: backup.cpp:1713
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Definition: backup.cpp:1200
RPCHelpMan importaddress()
Definition: backup.cpp:290
RPCHelpMan importwallet()
Definition: backup.cpp:669
Span< const CRPCCommand > GetWalletDumpRPCCommands()
Definition: backup.cpp:2504
static std::string GetRescanErrorMessage(const std::string &object, const int64_t objectTimestamp, const int64_t blockTimestamp, const bool have_pruned, const bool has_assumed_valid_chain)
Definition: backup.cpp:1679
RPCHelpMan dumpwallet()
Definition: backup.cpp:928
static UniValue ProcessImportLegacy(CWallet *const pwallet, 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: backup.cpp:1253
RPCHelpMan importpubkey()
Definition: backup.cpp:558
static std::string EncodeDumpString(const std::string &str)
Definition: backup.cpp:40
static bool GetWalletAddressesForKey(const Config &config, LegacyScriptPubKeyMan *spk_man, const CWallet *const pwallet, const CKeyID &keyid, std::string &strAddr, std::string &strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:67
static std::string DecodeDumpString(const std::string &str)
Definition: backup.cpp:52
RPCHelpMan importprunedfunds()
Definition: backup.cpp:425
RPCHelpMan restorewallet()
Definition: backup.cpp:2432
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: backup.cpp:1440
RPCHelpMan abortrescan()
Definition: backup.cpp:257
ScriptContext
Definition: backup.cpp:1190
@ P2SH
P2SH redeemScript.
@ TOP
Top-level scriptPubKey.
static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:1553
static void EnsureBlockDataFromTime(const CWallet &wallet, int64_t timestamp)
Definition: backup.cpp:109
RPCHelpMan backupwallet()
Definition: backup.cpp:2393
RPCHelpMan dumpprivkey()
Definition: backup.cpp:875
static UniValue ProcessDescriptorImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:1996
RPCHelpMan removeprunedfunds()
Definition: backup.cpp:508
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: backup.cpp:1662
std::string WriteHDKeypath(const std::vector< uint32_t > &keypath)
Write HD keypaths as strings.
Definition: bip32.cpp:66
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:36
#define CHECK_NONFATAL(condition)
Identity function.
Definition: check.h:53
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: args.cpp:526
BlockHash GetHash() const
Definition: block.cpp:11
uint256 hashMerkleRoot
Definition: block.h:28
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:177
CKeyID seed_id
seed hash160
Definition: walletdb.h:93
An encapsulated secp256k1 private key.
Definition: key.h:28
bool IsValid() const
Check whether this private key is valid.
Definition: key.h:97
CPubKey GetPubKey() const
Compute the public key from a private key.
Definition: key.cpp:210
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:302
A reference to a CKey: the Hash160 of its serialized public key.
Definition: pubkey.h:22
Used to create a Merkle proof (usually from a subset of transactions), which consists of a block head...
Definition: merkleblock.h:147
CBlockHeader header
Public only for unit testing.
Definition: merkleblock.h:150
CPartialMerkleTree txn
Definition: merkleblock.h:151
A mutable version of CTransaction.
Definition: transaction.h:274
TxId GetId() const
Compute the id and hash of this CMutableTransaction.
Definition: transaction.cpp:52
uint256 ExtractMatches(std::vector< uint256 > &vMatch, std::vector< size_t > &vnIndex)
Extract the matching txid's represented by this partial merkle tree and their respective indices with...
An encapsulated public key.
Definition: pubkey.h:31
CKeyID GetID() const
Get the KeyID of this public key (hash of its serialization)
Definition: pubkey.h:137
bool IsFullyValid() const
fully validate whether this is a valid public key (more expensive than IsValid())
Definition: pubkey.cpp:256
A reference to a CScript: the Hash160 of its serialization (see script.h)
Definition: standard.h:24
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:269
BlockHash GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.h:1054
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
Definition: wallet.cpp:3428
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:981
RecursiveMutex cs_wallet
Definition: wallet.h:414
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:992
bool IsAbortingRescan() const
Definition: wallet.h:540
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:473
bool BackupWallet(const std::string &strDest) const
Definition: wallet.cpp:3201
bool IsScanning() const
Definition: wallet.h:541
void AbortRescan()
Definition: wallet.h:539
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3135
Definition: config.h:19
virtual bool GetCScript(const CScriptID &hash, CScript &redeemScriptOut) const override
virtual std::set< CScriptID > GetCScripts() const
RecursiveMutex cs_KeyStore
const CHDChain & GetHDChain() const
bool GetKey(const CKeyID &address, CKey &keyOut) const override
const std::map< CKeyID, int64_t > & GetAllReserveKeys() const
A Span is an object that can refer to a contiguous sequence of objects.
Definition: span.h:93
void push_back(UniValue val)
Definition: univalue.cpp:96
const std::string & get_str() const
enum VType getType() const
Definition: univalue.h:88
@ VOBJ
Definition: univalue.h:31
@ VSTR
Definition: univalue.h:33
@ VARR
Definition: univalue.h:32
size_t size() const
Definition: univalue.h:92
enum VType type() const
Definition: univalue.h:147
const std::vector< UniValue > & getValues() const
bool isStr() const
Definition: univalue.h:108
Int getInt() const
Definition: univalue.h:157
const UniValue & get_array() const
bool exists(const std::string &key) const
Definition: univalue.h:99
bool isNum() const
Definition: univalue.h:109
void pushKV(std::string key, UniValue val)
Definition: univalue.cpp:115
bool get_bool() const
Descriptor with some wallet metadata.
Definition: walletutil.h:80
std::shared_ptr< Descriptor > descriptor
Definition: walletutil.h:82
RAII object to check and reserve a wallet rescan.
Definition: wallet.h:1127
bool IsNull() const
Definition: uint256.h:32
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
std::string u8string() const
Definition: fs.h:72
virtual bool findAncestorByHash(const BlockHash &block_hash, const BlockHash &ancestor_hash, const FoundBlock &ancestor_out={})=0
Return whether block descends from a specified ancestor, and optionally return ancestor information.
virtual bool findBlock(const BlockHash &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
virtual void showProgress(const std::string &title, int progress, bool resume_possible)=0
Send progress indicator.
virtual bool havePruned()=0
Check if any block has been pruned.
virtual bool hasAssumedValidChain()=0
Return true if an assumed-valid chain is in use.
Helper for findBlock to selectively return pieces of block data.
Definition: chain.h:55
160-bit opaque blob.
Definition: uint256.h:117
256-bit opaque blob.
Definition: uint256.h:129
static UniValue Parse(std::string_view raw)
Parse string to UniValue or throw runtime_error if string contains invalid JSON.
Definition: client.cpp:226
const std::string CLIENT_BUILD
const std::string CLIENT_NAME
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:197
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:2324
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:2265
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:1677
void MarkDirty()
Definition: wallet.cpp:960
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1657
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true)
Definition: wallet.cpp:1018
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1667
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1494
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:1691
const CChainParams & GetChainParams() const override
Definition: wallet.cpp:447
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1918
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
Definition: wallet.cpp:1587
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1726
@ ISMINE_SPENDABLE
Definition: ismine.h:21
std::string EncodeDestination(const CTxDestination &dest, const Config &config)
Definition: key_io.cpp:167
std::string EncodeExtKey(const CExtKey &key)
Definition: key_io.cpp:156
std::string EncodeSecret(const CKey &key)
Definition: key_io.cpp:102
CTxDestination DecodeDestination(const std::string &addr, const CChainParams &params)
Definition: key_io.cpp:174
CKey DecodeSecret(const std::string &str)
Definition: key_io.cpp:77
bool error(const char *fmt, const Args &...args)
Definition: logging.h:263
static path absolute(const path &p)
Definition: fs.h:96
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:102
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:165
CTxDestination GetDestinationForKey(const CPubKey &key, OutputType type)
Get a destination of the requested type (if possible) to the specified key.
Definition: outputtype.cpp:35
std::vector< CTxDestination > GetAllDestinationsForKey(const CPubKey &key)
Get all destinations (potentially) supported by the wallet for the given key.
Definition: outputtype.cpp:43
static CTransactionRef MakeTransactionRef()
Definition: transaction.h:316
std::shared_ptr< const CTransaction > CTransactionRef
Definition: transaction.h:315
Response response
Definition: processor.cpp:510
UniValue JSONRPCError(int code, const std::string &message)
Definition: request.cpp:58
@ RPC_MISC_ERROR
General application defined errors std::exception thrown in command handling.
Definition: protocol.h:38
@ RPC_TYPE_ERROR
Unexpected type was passed as parameter.
Definition: protocol.h:40
@ RPC_INVALID_PARAMETER
Invalid, missing or duplicate parameter.
Definition: protocol.h:46
@ RPC_WALLET_ERROR
Wallet errors Unspecified problem with wallet (key not found etc.)
Definition: protocol.h:90
@ RPC_DESERIALIZATION_ERROR
Error parsing or validating structure in raw format.
Definition: protocol.h:50
@ RPC_INVALID_ADDRESS_OR_KEY
Invalid address or key.
Definition: protocol.h:42
std::pair< int64_t, int64_t > ParseDescriptorRange(const UniValue &value)
Parse a JSON range specified as int64, or [int64, int64].
Definition: util.cpp:1345
std::string HelpExampleCli(const std::string &methodname, const std::string &args)
Definition: util.cpp:153
std::string HelpExampleRpcNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:179
std::vector< uint8_t > ParseHexV(const UniValue &v, std::string strName)
Definition: util.cpp:97
std::string HelpExampleRpc(const std::string &methodname, const std::string &args)
Definition: util.cpp:170
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:25
uint256 ParseHashV(const UniValue &v, std::string strName)
Utilities: convert hex-encoded values (throws error if not hex).
Definition: util.cpp:76
std::string HelpExampleCliNamed(const std::string &methodname, const RPCArgList &args)
Definition: util.cpp:158
static const unsigned int DEFAULT_KEYPOOL_SIZE
Default for -keypool.
@ SER_NETWORK
Definition: serialize.h:152
CKeyID GetKeyForDestination(const SigningProvider &store, const CTxDestination &dest)
Return the CKeyID of the key involved in a script (if there is a unique one).
std::map< CTxDestination, std::vector< COutput > > ListCoins(const CWallet &wallet)
Return list of available coins and locked coins grouped by non-change output address.
Definition: spend.cpp:252
bool ExtractDestination(const CScript &scriptPubKey, CTxDestination &addressRet)
Parse a standard scriptPubKey for the destination address.
Definition: standard.cpp:158
TxoutType Solver(const CScript &scriptPubKey, std::vector< std::vector< uint8_t > > &vSolutionsRet)
Parse a scriptPubKey and identify script type for standard scripts.
Definition: standard.cpp:108
bool IsValidDestination(const CTxDestination &dest)
Check whether a CTxDestination is a CNoDestination.
Definition: standard.cpp:260
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
Definition: standard.cpp:240
TxoutType
Definition: standard.h:38
std::variant< CNoDestination, PKHash, ScriptHash > CTxDestination
A txout script template with a specific destination.
Definition: standard.h:85
auto Join(const std::vector< T > &list, const BaseType &separator, UnaryOp unary_op) -> decltype(unary_op(list.at(0)))
Join a list of items.
Definition: string.h:63
std::vector< std::string > SplitString(std::string_view str, char sep)
Definition: string.h:22
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
Definition: key.h:167
void SetSeed(Span< const std::byte > seed)
Definition: key.cpp:382
Confirmation includes tx status and a triplet of {block height/block hash/tx index in block} at which...
Definition: transaction.h:181
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > origins
bool GetKey(const CKeyID &keyid, CKey &key) const override
std::map< CKeyID, CPubKey > pubkeys
std::map< CKeyID, CKey > keys
std::map< CScriptID, CScript > scripts
std::unique_ptr< CScript > redeemscript
Provided redeemScript; will be moved to import_scripts if relevant.
Definition: backup.cpp:1180
std::map< CKeyID, bool > used_keys
Import these private keys if available (the value indicates whether if the key is required for solvab...
Definition: backup.cpp:1186
std::set< CScript > import_scripts
Definition: backup.cpp:1183
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
Definition: backup.cpp:1187
@ RANGE
Special type that is a NUM or [NUM,NUM].
@ STR_HEX
Special type that is a STR with only hex chars.
@ OBJ_NAMED_PARAMS
Special type that behaves almost exactly like OBJ, defining an options object with a list of pre-defi...
std::string DefaultHint
Hint for default value.
Definition: util.h:206
@ OMITTED
Optional argument for which the default value is omitted from help text for one of two reasons:
@ NO
Required arg.
std::vector< std::string > type_str
Should be empty unless it is supposed to override the auto-generated type strings.
Definition: util.h:149
std::string oneline_description
Should be empty unless it is supposed to override the auto-generated summary line.
Definition: util.h:143
@ ELISION
Special type to denote elision (...)
@ OBJ_DYN
Special dictionary with keys that are not literals.
@ STR_HEX
Special string with only hex chars.
@ STR_AMOUNT
Special string to represent a floating point amount.
A TxId is the identifier of a transaction.
Definition: txid.h:14
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:35
Bilingual messages:
Definition: translation.h:17
#define LOCK2(cs1, cs2)
Definition: sync.h:309
#define LOCK(cs)
Definition: sync.h:306
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:357
#define EXCLUSIVE_LOCKS_REQUIRED(...)
Definition: threadsafety.h:56
int64_t GetTime()
DEPRECATED Use either ClockType::now() or Now<TimePointType>() if a cast is needed.
Definition: time.cpp:109
int64_t ParseISO8601DateTime(const std::string &str)
Definition: time.cpp:142
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:113
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:36
const UniValue NullUniValue
Definition: univalue.cpp:16
const char * uvTypeName(UniValue::VType t)
Definition: univalue.cpp:209
std::string HexStr(const Span< const uint8_t > s)
Convert a span of bytes to a lower-case hexadecimal string.
template std::vector< std::byte > ParseHex(std::string_view)
bool IsHex(std::string_view str)
Returns true if each character in str is a hex character, and has an even number of hex digits.
static const int PROTOCOL_VERSION
network protocol versioning
Definition: version.h:11
DatabaseStatus
Definition: db.h:229
void EnsureWalletIsUnlocked(const CWallet *pwallet)
Definition: util.cpp:96
std::shared_ptr< CWallet > GetWalletForJSONRPCRequest(const JSONRPCRequest &request)
Figures out what wallet, if any, to use for a JSONRPCRequest.
Definition: util.cpp:63
LegacyScriptPubKeyMan & EnsureLegacyScriptPubKeyMan(CWallet &wallet, bool also_create)
Definition: util.cpp:114
void HandleWalletError(const std::shared_ptr< CWallet > wallet, DatabaseStatus &status, bilingual_str &error)
Definition: util.cpp:135
WalletContext & EnsureWalletContext(const std::any &context)
Definition: util.cpp:104
std::shared_ptr< CWallet > RestoreWallet(WalletContext &context, const fs::path &backup_file, const std::string &wallet_name, std::optional< bool > load_on_start, DatabaseStatus &status, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:397
@ WALLET_FLAG_DISABLE_PRIVATE_KEYS
Definition: walletutil.h:55
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:70