Bitcoin ABC 0.32.11
P2P Digital Currency
backup.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-present 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 DataStream ssMB{ParseHexV(request.params[1], "proof")};
459 CMerkleBlock merkleBlock;
460 ssMB >> merkleBlock;
461
462 // Search partial merkle tree in proof for our transaction and index
463 // in valid block
464 std::vector<uint256> vMatch;
465 std::vector<size_t> vIndex;
466 if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) !=
467 merkleBlock.header.hashMerkleRoot) {
469 "Something wrong with merkleblock");
470 }
471
472 LOCK(pwallet->cs_wallet);
473 int height;
474 if (!pwallet->chain().findAncestorByHash(
475 pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(),
476 FoundBlock().height(height))) {
478 "Block not found in chain");
479 }
480
481 std::vector<uint256>::const_iterator it;
482 if ((it = std::find(vMatch.begin(), vMatch.end(), txid)) ==
483 vMatch.end()) {
485 "Transaction given doesn't exist in proof");
486 }
487
488 size_t txnIndex = vIndex[it - vMatch.begin()];
489
491 CWalletTx::Status::CONFIRMED, height,
492 merkleBlock.header.GetHash(), txnIndex);
493
495 if (pwallet->IsMine(*tx_ref)) {
496 pwallet->AddToWallet(std::move(tx_ref), confirm);
497 return NullUniValue;
498 }
499
500 throw JSONRPCError(
502 "No addresses in wallet correspond to included transaction");
503 },
504 };
505}
506
508 return RPCHelpMan{
509 "removeprunedfunds",
510 "Deletes the specified transaction from the wallet. Meant for use "
511 "with pruned wallets and as a companion to importprunedfunds. This "
512 "will affect wallet balances.\n",
513 {
515 "The hex-encoded id of the transaction you are deleting"},
516 },
518 RPCExamples{HelpExampleCli("removeprunedfunds",
519 "\"a8d0c0184dde994a09ec054286f1ce581bebf4644"
520 "6a512166eae7628734ea0a5\"") +
521 "\nAs a JSON-RPC call\n" +
522 HelpExampleRpc("removeprunedfunds",
523 "\"a8d0c0184dde994a09ec054286f1ce581bebf4644"
524 "6a512166eae7628734ea0a5\"")},
525 [&](const RPCHelpMan &self, const Config &config,
526 const JSONRPCRequest &request) -> UniValue {
527 std::shared_ptr<CWallet> const wallet =
529 if (!wallet) {
530 return NullUniValue;
531 }
532 CWallet *const pwallet = wallet.get();
533
534 LOCK(pwallet->cs_wallet);
535
536 TxId txid(ParseHashV(request.params[0], "txid"));
537 std::vector<TxId> txIds;
538 txIds.push_back(txid);
539 std::vector<TxId> txIdsOut;
540
541 if (pwallet->ZapSelectTx(txIds, txIdsOut) != DBErrors::LOAD_OK) {
542 throw JSONRPCError(
544 "Could not properly delete the transaction.");
545 }
546
547 if (txIdsOut.empty()) {
549 "Transaction does not exist in wallet.");
550 }
551
552 return NullUniValue;
553 },
554 };
555}
556
558 return RPCHelpMan{
559 "importpubkey",
560 "Adds a public key (in hex) that can be watched as if it were in "
561 "your wallet but cannot be used to spend. Requires a new wallet "
562 "backup.\n"
563 "Hint: use importmulti to import more than one public key.\n"
564 "\nNote: This call can take minutes to complete if rescan is true, "
565 "during that time, other rpc calls\n"
566 "may report that the imported pubkey exists but related transactions "
567 "are still missing, leading to temporarily incorrect/bogus balances "
568 "and unspent outputs until rescan completes.\n"
569 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
570 "Note: This command is only compatible with legacy wallets. Use "
571 "\"importdescriptors\" with \"combo(X)\" for descriptor wallets.\n",
572 {
574 "The hex-encoded public key"},
575 {"label", RPCArg::Type::STR, RPCArg::Default{""},
576 "An optional label"},
577 {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
578 "Rescan the wallet for transactions"},
579 },
582 "\nImport a public key with rescan\n" +
583 HelpExampleCli("importpubkey", "\"mypubkey\"") +
584 "\nImport using a label without rescan\n" +
585 HelpExampleCli("importpubkey", "\"mypubkey\" \"testing\" false") +
586 "\nAs a JSON-RPC call\n" +
587 HelpExampleRpc("importpubkey", "\"mypubkey\", \"testing\", false")},
588 [&](const RPCHelpMan &self, const Config &config,
589 const JSONRPCRequest &request) -> UniValue {
590 std::shared_ptr<CWallet> const wallet =
592 if (!wallet) {
593 return NullUniValue;
594 }
595 CWallet *const pwallet = wallet.get();
596
598
599 std::string strLabel;
600 if (!request.params[1].isNull()) {
601 strLabel = request.params[1].get_str();
602 }
603
604 // Whether to perform rescan after import
605 bool fRescan = true;
606 if (!request.params[2].isNull()) {
607 fRescan = request.params[2].get_bool();
608 }
609
610 if (fRescan && pwallet->chain().havePruned()) {
611 // Exit early and print an error.
612 // If a block is pruned after this check, we will import the
613 // key(s), but fail the rescan with a generic error.
615 "Rescan is disabled when blocks are pruned");
616 }
617
618 WalletRescanReserver reserver(*pwallet);
619 if (fRescan && !reserver.reserve()) {
621 "Wallet is currently rescanning. Abort "
622 "existing rescan or wait.");
623 }
624
625 if (!IsHex(request.params[0].get_str())) {
627 "Pubkey must be a hex string");
628 }
629 std::vector<uint8_t> data(ParseHex(request.params[0].get_str()));
630 CPubKey pubKey(data);
631 if (!pubKey.IsFullyValid()) {
633 "Pubkey is not a valid public key");
634 }
635
636 {
637 LOCK(pwallet->cs_wallet);
638
639 std::set<CScript> script_pub_keys;
640 for (const auto &dest : GetAllDestinationsForKey(pubKey)) {
641 script_pub_keys.insert(GetScriptForDestination(dest));
642 }
643
644 pwallet->MarkDirty();
645
646 pwallet->ImportScriptPubKeys(
647 strLabel, script_pub_keys, true /* have_solving_data */,
648 true /* apply_label */, 1 /* timestamp */);
649
650 pwallet->ImportPubKeys(
651 {pubKey.GetID()}, {{pubKey.GetID(), pubKey}},
652 {} /* key_origins */, false /* add_keypool */,
653 false /* internal */, 1 /* timestamp */);
654 }
655 if (fRescan) {
656 RescanWallet(*pwallet, reserver);
657 {
658 LOCK(pwallet->cs_wallet);
660 }
661 }
662
663 return NullUniValue;
664 },
665 };
666}
667
669 return RPCHelpMan{
670 "importwallet",
671 "Imports keys from a wallet dump file (see dumpwallet). Requires a "
672 "new wallet backup to include imported keys.\n"
673 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
674 "Note: This command is only compatible with legacy wallets.\n",
675 {
677 "The wallet file"},
678 },
680 RPCExamples{"\nDump the wallet\n" +
681 HelpExampleCli("dumpwallet", "\"test\"") +
682 "\nImport the wallet\n" +
683 HelpExampleCli("importwallet", "\"test\"") +
684 "\nImport using the json rpc call\n" +
685 HelpExampleRpc("importwallet", "\"test\"")},
686 [&](const RPCHelpMan &self, const Config &config,
687 const JSONRPCRequest &request) -> UniValue {
688 std::shared_ptr<CWallet> const wallet =
690 if (!wallet) {
691 return NullUniValue;
692 }
693 CWallet *const pwallet = wallet.get();
694
696
697 WalletRescanReserver reserver(*pwallet);
698 if (!reserver.reserve()) {
700 "Wallet is currently rescanning. Abort "
701 "existing rescan or wait.");
702 }
703
704 int64_t nTimeBegin = 0;
705 bool fGood = true;
706 {
707 LOCK(pwallet->cs_wallet);
708
709 EnsureWalletIsUnlocked(pwallet);
710
711 std::ifstream file;
712 file.open(fs::u8path(request.params[0].get_str()),
713 std::ios::in | std::ios::ate);
714 if (!file.is_open()) {
716 "Cannot open wallet dump file");
717 }
719 pwallet->chain().findBlock(pwallet->GetLastBlockHash(),
720 FoundBlock().time(nTimeBegin)));
721
722 int64_t nFilesize = std::max<int64_t>(1, file.tellg());
723 file.seekg(0, file.beg);
724
725 // Use uiInterface.ShowProgress instead of pwallet.ShowProgress
726 // because pwallet.ShowProgress has a cancel button tied to
727 // AbortRescan which we don't want for this progress bar showing
728 // the import progress. uiInterface.ShowProgress does not have a
729 // cancel button.
730
731 // show progress dialog in GUI
732 pwallet->chain().showProgress(
733 strprintf("%s " + _("Importing...").translated,
734 pwallet->GetDisplayName()),
735 0, false);
736 std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys;
737 std::vector<std::pair<CScript, int64_t>> scripts;
738 while (file.good()) {
739 pwallet->chain().showProgress(
740 "",
741 std::max(1,
742 std::min<int>(50, 100 * double(file.tellg()) /
743 double(nFilesize))),
744 false);
745 std::string line;
746 std::getline(file, line);
747 if (line.empty() || line[0] == '#') {
748 continue;
749 }
750
751 std::vector<std::string> vstr = SplitString(line, ' ');
752 if (vstr.size() < 2) {
753 continue;
754 }
755 CKey key = DecodeSecret(vstr[0]);
756 if (key.IsValid()) {
757 int64_t nTime{
758 ParseISO8601DateTime(vstr[1]).value_or(0)};
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{
784 ParseISO8601DateTime(vstr[1]).value_or(0)};
785 if (birth_time > 0) {
786 nTimeBegin = std::min(nTimeBegin, birth_time);
787 }
788 scripts.push_back(
789 std::pair<CScript, int64_t>(script, birth_time));
790 }
791 }
792 file.close();
793 EnsureBlockDataFromTime(*pwallet, nTimeBegin);
794 // We now know whether we are importing private keys, so we can
795 // error if private keys are disabled
796 if (keys.size() > 0 && pwallet->IsWalletFlagSet(
798 // hide progress dialog in GUI
799 pwallet->chain().showProgress("", 100, false);
801 "Importing wallets is disabled when "
802 "private keys are disabled");
803 }
804 double total = double(keys.size() + scripts.size());
805 double progress = 0;
806 for (const auto &key_tuple : keys) {
807 pwallet->chain().showProgress(
808 "",
809 std::max(50, std::min<int>(75, 100 * progress / total) +
810 50),
811 false);
812 const CKey &key = std::get<0>(key_tuple);
813 int64_t time = std::get<1>(key_tuple);
814 bool has_label = std::get<2>(key_tuple);
815 std::string label = std::get<3>(key_tuple);
816
817 CPubKey pubkey = key.GetPubKey();
818 CHECK_NONFATAL(key.VerifyPubKey(pubkey));
819 CKeyID keyid = pubkey.GetID();
820
821 pwallet->WalletLogPrintf(
822 "Importing %s...\n",
823 EncodeDestination(PKHash(keyid), config));
824
825 if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) {
826 pwallet->WalletLogPrintf(
827 "Error importing key for %s\n",
828 EncodeDestination(PKHash(keyid), config));
829 fGood = false;
830 continue;
831 }
832
833 if (has_label) {
834 pwallet->SetAddressBook(PKHash(keyid), label,
835 "receive");
836 }
837 progress++;
838 }
839 for (const auto &script_pair : scripts) {
840 pwallet->chain().showProgress(
841 "",
842 std::max(50, std::min<int>(75, 100 * progress / total) +
843 50),
844 false);
845 const CScript &script = script_pair.first;
846 int64_t time = script_pair.second;
847
848 if (!pwallet->ImportScripts({script}, time)) {
849 pwallet->WalletLogPrintf("Error importing script %s\n",
850 HexStr(script));
851 fGood = false;
852 continue;
853 }
854
855 progress++;
856 }
857
858 // hide progress dialog in GUI
859 pwallet->chain().showProgress("", 100, false);
860 }
861 // hide progress dialog in GUI
862 pwallet->chain().showProgress("", 100, false);
863 RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */);
864 pwallet->MarkDirty();
865
866 if (!fGood) {
868 "Error adding some keys/scripts to wallet");
869 }
870
871 return NullUniValue;
872 },
873 };
874}
875
877 return RPCHelpMan{
878 "dumpprivkey",
879 "Reveals the private key corresponding to 'address'.\n"
880 "Then the importprivkey can be used with this output\n"
881 "Note: This command is only compatible with legacy wallets.\n",
882 {
884 "The bitcoin address for the private key"},
885 },
886 RPCResult{RPCResult::Type::STR, "key", "The private key"},
887 RPCExamples{HelpExampleCli("dumpprivkey", "\"myaddress\"") +
888 HelpExampleCli("importprivkey", "\"mykey\"") +
889 HelpExampleRpc("dumpprivkey", "\"myaddress\"")},
890 [&](const RPCHelpMan &self, const Config &config,
891 const JSONRPCRequest &request) -> UniValue {
892 std::shared_ptr<CWallet> const wallet =
894 if (!wallet) {
895 return NullUniValue;
896 }
897 const CWallet *const pwallet = wallet.get();
898
899 LegacyScriptPubKeyMan &spk_man =
901
902 LOCK2(pwallet->cs_wallet, spk_man.cs_KeyStore);
903
904 EnsureWalletIsUnlocked(pwallet);
905
906 std::string strAddress = request.params[0].get_str();
907 CTxDestination dest =
908 DecodeDestination(strAddress, wallet->GetChainParams());
909 if (!IsValidDestination(dest)) {
911 "Invalid Bitcoin address");
912 }
913 auto keyid = GetKeyForDestination(spk_man, dest);
914 if (keyid.IsNull()) {
916 "Address does not refer to a key");
917 }
918 CKey vchSecret;
919 if (!spk_man.GetKey(keyid, vchSecret)) {
921 "Private key for address " + strAddress +
922 " is not known");
923 }
924 return EncodeSecret(vchSecret);
925 },
926 };
927}
928
930 return RPCHelpMan{
931 "dumpwallet",
932 "Dumps all wallet keys in a human-readable format to a server-side "
933 "file. This does not allow overwriting existing files.\n"
934 "Imported scripts are included in the dumpsfile, but corresponding "
935 "addresses may not be added automatically by importwallet.\n"
936 "Note that if your wallet contains keys which are not derived from "
937 "your HD seed (e.g. imported keys), these are not covered by\n"
938 "only backing up the seed itself, and must be backed up too (e.g. "
939 "ensure you back up the whole dumpfile).\n"
940 "Note: This command is only compatible with legacy wallets.\n",
941 {
943 "The filename with path (absolute path recommended)"},
944 },
946 "",
947 "",
948 {
949 {RPCResult::Type::STR, "filename",
950 "The filename with full absolute path"},
951 }},
952 RPCExamples{HelpExampleCli("dumpwallet", "\"test\"") +
953 HelpExampleRpc("dumpwallet", "\"test\"")},
954 [&](const RPCHelpMan &self, const Config &config,
955 const JSONRPCRequest &request) -> UniValue {
956 std::shared_ptr<CWallet> const pwallet =
958 if (!pwallet) {
959 return NullUniValue;
960 }
961
962 CWallet &wallet = *pwallet;
963 LegacyScriptPubKeyMan &spk_man =
965
966 // Make sure the results are valid at least up to the most recent
967 // block the user could have gotten from another RPC command prior
968 // to now
969 wallet.BlockUntilSyncedToCurrentChain();
970
971 LOCK(wallet.cs_wallet);
972
974
975 fs::path filepath = fs::u8path(request.params[0].get_str());
976 filepath = fs::absolute(filepath);
977
984 if (fs::exists(filepath)) {
986 filepath.u8string() +
987 " already exists. If you are "
988 "sure this is what you want, "
989 "move it out of the way first");
990 }
991
992 std::ofstream file;
993 file.open(filepath);
994 if (!file.is_open()) {
996 "Cannot open wallet dump file");
997 }
998
999 std::map<CKeyID, int64_t> mapKeyBirth;
1000 wallet.GetKeyBirthTimes(mapKeyBirth);
1001
1002 int64_t block_time = 0;
1003 CHECK_NONFATAL(wallet.chain().findBlock(
1004 wallet.GetLastBlockHash(), FoundBlock().time(block_time)));
1005
1006 // Note: To avoid a lock order issue, access to cs_main must be
1007 // locked before cs_KeyStore. So we do the two things in this
1008 // function that lock cs_main first: GetKeyBirthTimes, and
1009 // findBlock.
1010 LOCK(spk_man.cs_KeyStore);
1011
1012 const std::map<CKeyID, int64_t> &mapKeyPool =
1013 spk_man.GetAllReserveKeys();
1014 std::set<CScriptID> scripts = spk_man.GetCScripts();
1015
1016 // sort time/key pairs
1017 std::vector<std::pair<int64_t, CKeyID>> vKeyBirth;
1018 vKeyBirth.reserve(mapKeyBirth.size());
1019 for (const auto &entry : mapKeyBirth) {
1020 vKeyBirth.push_back(std::make_pair(entry.second, entry.first));
1021 }
1022 mapKeyBirth.clear();
1023 std::sort(vKeyBirth.begin(), vKeyBirth.end());
1024
1025 // produce output
1026 file << strprintf("# Wallet dump created by %s %s\n", CLIENT_NAME,
1027 CLIENT_BUILD);
1028 file << strprintf("# * Created on %s\n",
1030 file << strprintf("# * Best block at time of backup was %i (%s),\n",
1031 wallet.GetLastBlockHeight(),
1032 wallet.GetLastBlockHash().ToString());
1033 file << strprintf("# mined on %s\n",
1034 FormatISO8601DateTime(block_time));
1035 file << "\n";
1036
1037 // add the base58check encoded extended master if the wallet uses HD
1038 CKeyID seed_id = spk_man.GetHDChain().seed_id;
1039 if (!seed_id.IsNull()) {
1040 CKey seed;
1041 if (spk_man.GetKey(seed_id, seed)) {
1042 CExtKey masterKey;
1043 masterKey.SetSeed(seed);
1044
1045 file << "# extended private masterkey: "
1046 << EncodeExtKey(masterKey) << "\n\n";
1047 }
1048 }
1049 for (std::vector<std::pair<int64_t, CKeyID>>::const_iterator it =
1050 vKeyBirth.begin();
1051 it != vKeyBirth.end(); it++) {
1052 const CKeyID &keyid = it->second;
1053 std::string strTime = FormatISO8601DateTime(it->first);
1054 std::string strAddr;
1055 std::string strLabel;
1056 CKey key;
1057 if (spk_man.GetKey(keyid, key)) {
1058 file << strprintf("%s %s ", EncodeSecret(key), strTime);
1059 if (GetWalletAddressesForKey(config, &spk_man, &wallet,
1060 keyid, strAddr, strLabel)) {
1061 file << strprintf("label=%s", strLabel);
1062 } else if (keyid == seed_id) {
1063 file << "hdseed=1";
1064 } else if (mapKeyPool.count(keyid)) {
1065 file << "reserve=1";
1066 } else if (spk_man.mapKeyMetadata[keyid].hdKeypath == "s") {
1067 file << "inactivehdseed=1";
1068 } else {
1069 file << "change=1";
1070 }
1071 file << strprintf(
1072 " # addr=%s%s\n", strAddr,
1073 (spk_man.mapKeyMetadata[keyid].has_key_origin
1074 ? " hdkeypath=" +
1075 WriteHDKeypath(spk_man.mapKeyMetadata[keyid]
1076 .key_origin.path)
1077 : ""));
1078 }
1079 }
1080 file << "\n";
1081 for (const CScriptID &scriptid : scripts) {
1082 CScript script;
1083 std::string create_time = "0";
1084 std::string address =
1085 EncodeDestination(ScriptHash(scriptid), config);
1086 // get birth times for scripts with metadata
1087 auto it = spk_man.m_script_metadata.find(scriptid);
1088 if (it != spk_man.m_script_metadata.end()) {
1089 create_time = FormatISO8601DateTime(it->second.nCreateTime);
1090 }
1091 if (spk_man.GetCScript(scriptid, script)) {
1092 file << strprintf("%s %s script=1", HexStr(script),
1093 create_time);
1094 file << strprintf(" # addr=%s\n", address);
1095 }
1096 }
1097 file << "\n";
1098 file << "# End of dump\n";
1099 file.close();
1100
1101 UniValue reply(UniValue::VOBJ);
1102 reply.pushKV("filename", filepath.u8string());
1103
1104 return reply;
1105 },
1106 };
1107}
1108
1110 return RPCHelpMan{
1111 "dumpcoins",
1112 "dump all the UTXO tracked by the wallet.\n",
1113 {},
1114 RPCResult{
1116 "",
1117 "",
1118 {{
1120 "address",
1121 "The list of UTXO corresponding to this address.",
1122 {{
1124 "",
1125 "",
1126 {
1127 {RPCResult::Type::STR_HEX, "txid",
1128 "The transaction id"},
1129 {RPCResult::Type::NUM, "vout", "The output number"},
1130 {RPCResult::Type::NUM, "depth", "The output's depth"},
1132 "The output's amount"},
1133 },
1134 }},
1135 }},
1136 },
1137 RPCExamples{HelpExampleCli("dumpcoins", "") +
1138 HelpExampleRpc("dumpcoins", "")},
1139 [&](const RPCHelpMan &self, const Config &config,
1140 const JSONRPCRequest &request) -> UniValue {
1141 std::shared_ptr<CWallet> const pwallet =
1143 if (!pwallet) {
1144 return NullUniValue;
1145 }
1146
1147 CWallet &wallet = *pwallet;
1148
1149 // Make sure the results are valid at least up to the most recent
1150 // block the user could have gotten from another RPC command prior
1151 // to now
1152 wallet.BlockUntilSyncedToCurrentChain();
1153
1154 LOCK(wallet.cs_wallet);
1155
1157
1158 UniValue result(UniValue::VOBJ);
1159 for (const auto &p : ListCoins(wallet)) {
1160 UniValue coins(UniValue::VARR);
1161 for (const auto &o : p.second) {
1163 utxo.pushKV("txid", o.tx->GetId().ToString());
1164 utxo.pushKV("vout", o.i);
1165 utxo.pushKV("depth", o.nDepth);
1166 utxo.pushKV("value", o.tx->tx->vout[o.i].nValue);
1167
1168 coins.push_back(std::move(utxo));
1169 }
1170
1171 result.pushKV(EncodeDestination(p.first, config), coins);
1172 }
1173
1174 return result;
1175 },
1176 };
1177}
1178
1180 // Input data
1182 std::unique_ptr<CScript> redeemscript;
1183
1184 // Output data
1185 std::set<CScript> import_scripts;
1188 std::map<CKeyID, bool> used_keys;
1189 std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>> key_origins;
1190};
1191
1192enum class ScriptContext {
1194 TOP,
1196 P2SH,
1197};
1198
1199// Analyse the provided scriptPubKey, determining which keys and which redeem
1200// scripts from the ImportData struct are needed to spend it, and mark them as
1201// used. Returns an error string, or the empty string for success.
1202static std::string RecurseImportData(const CScript &script,
1203 ImportData &import_data,
1204 const ScriptContext script_ctx) {
1205 // Use Solver to obtain script type and parsed pubkeys or hashes:
1206 std::vector<std::vector<uint8_t>> solverdata;
1207 TxoutType script_type = Solver(script, solverdata);
1208
1209 switch (script_type) {
1210 case TxoutType::PUBKEY: {
1211 CPubKey pubkey(solverdata[0]);
1212 import_data.used_keys.emplace(pubkey.GetID(), false);
1213 return "";
1214 }
1215 case TxoutType::PUBKEYHASH: {
1216 CKeyID id = CKeyID(uint160(solverdata[0]));
1217 import_data.used_keys[id] = true;
1218 return "";
1219 }
1220 case TxoutType::SCRIPTHASH: {
1221 if (script_ctx == ScriptContext::P2SH) {
1223 "Trying to nest P2SH inside another P2SH");
1224 }
1225 CHECK_NONFATAL(script_ctx == ScriptContext::TOP);
1226 CScriptID id = CScriptID(uint160(solverdata[0]));
1227 // Remove redeemscript from import_data to check for superfluous
1228 // script later.
1229 auto subscript = std::move(import_data.redeemscript);
1230 if (!subscript) {
1231 return "missing redeemscript";
1232 }
1233 if (CScriptID(*subscript) != id) {
1234 return "redeemScript does not match the scriptPubKey";
1235 }
1236 import_data.import_scripts.emplace(*subscript);
1237 return RecurseImportData(*subscript, import_data,
1239 }
1240 case TxoutType::MULTISIG: {
1241 for (size_t i = 1; i + 1 < solverdata.size(); ++i) {
1242 CPubKey pubkey(solverdata[i]);
1243 import_data.used_keys.emplace(pubkey.GetID(), false);
1244 }
1245 return "";
1246 }
1248 return "unspendable script";
1250 default:
1251 return "unrecognized script";
1252 }
1253}
1254
1256 CWallet *const pwallet, ImportData &import_data,
1257 std::map<CKeyID, CPubKey> &pubkey_map, std::map<CKeyID, CKey> &privkey_map,
1258 std::set<CScript> &script_pub_keys, bool &have_solving_data,
1259 const UniValue &data, std::vector<CKeyID> &ordered_pubkeys) {
1260 UniValue warnings(UniValue::VARR);
1261
1262 // First ensure scriptPubKey has either a script or JSON with "address"
1263 // string
1264 const UniValue &scriptPubKey = data["scriptPubKey"];
1265 bool isScript = scriptPubKey.getType() == UniValue::VSTR;
1266 if (!isScript && !(scriptPubKey.getType() == UniValue::VOBJ &&
1267 scriptPubKey.exists("address"))) {
1269 "scriptPubKey must be string with script or JSON "
1270 "with address string");
1271 }
1272 const std::string &output =
1273 isScript ? scriptPubKey.get_str() : scriptPubKey["address"].get_str();
1274
1275 // Optional fields.
1276 const std::string &strRedeemScript =
1277 data.exists("redeemscript") ? data["redeemscript"].get_str() : "";
1278 const UniValue &pubKeys =
1279 data.exists("pubkeys") ? data["pubkeys"].get_array() : UniValue();
1280 const UniValue &keys =
1281 data.exists("keys") ? data["keys"].get_array() : UniValue();
1282 const bool internal =
1283 data.exists("internal") ? data["internal"].get_bool() : false;
1284 const bool watchOnly =
1285 data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1286
1287 if (data.exists("range")) {
1288 throw JSONRPCError(
1290 "Range should not be specified for a non-descriptor import");
1291 }
1292
1293 // Generate the script and destination for the scriptPubKey provided
1294 CScript script;
1295 if (!isScript) {
1296 CTxDestination dest =
1297 DecodeDestination(output, pwallet->GetChainParams());
1298 if (!IsValidDestination(dest)) {
1300 "Invalid address \"" + output + "\"");
1301 }
1302 script = GetScriptForDestination(dest);
1303 } else {
1304 if (!IsHex(output)) {
1306 "Invalid scriptPubKey \"" + output + "\"");
1307 }
1308 std::vector<uint8_t> vData(ParseHex(output));
1309 script = CScript(vData.begin(), vData.end());
1310 CTxDestination dest;
1311 if (!ExtractDestination(script, dest) && !internal) {
1313 "Internal must be set to true for "
1314 "nonstandard scriptPubKey imports.");
1315 }
1316 }
1317 script_pub_keys.emplace(script);
1318
1319 // Parse all arguments
1320 if (strRedeemScript.size()) {
1321 if (!IsHex(strRedeemScript)) {
1323 "Invalid redeem script \"" + strRedeemScript +
1324 "\": must be hex string");
1325 }
1326 auto parsed_redeemscript = ParseHex(strRedeemScript);
1327 import_data.redeemscript = std::make_unique<CScript>(
1328 parsed_redeemscript.begin(), parsed_redeemscript.end());
1329 }
1330 for (size_t i = 0; i < pubKeys.size(); ++i) {
1331 const auto &str = pubKeys[i].get_str();
1332 if (!IsHex(str)) {
1334 "Pubkey \"" + str + "\" must be a hex string");
1335 }
1336 auto parsed_pubkey = ParseHex(str);
1337 CPubKey pubkey(parsed_pubkey);
1338 if (!pubkey.IsFullyValid()) {
1340 "Pubkey \"" + str +
1341 "\" is not a valid public key");
1342 }
1343 pubkey_map.emplace(pubkey.GetID(), pubkey);
1344 ordered_pubkeys.push_back(pubkey.GetID());
1345 }
1346 for (size_t i = 0; i < keys.size(); ++i) {
1347 const auto &str = keys[i].get_str();
1348 CKey key = DecodeSecret(str);
1349 if (!key.IsValid()) {
1351 "Invalid private key encoding");
1352 }
1353 CPubKey pubkey = key.GetPubKey();
1354 CKeyID id = pubkey.GetID();
1355 if (pubkey_map.count(id)) {
1356 pubkey_map.erase(id);
1357 }
1358 privkey_map.emplace(id, key);
1359 }
1360
1361 // Verify and process input data
1362 have_solving_data =
1363 import_data.redeemscript || pubkey_map.size() || privkey_map.size();
1364 if (have_solving_data) {
1365 // Match up data in import_data with the scriptPubKey in script.
1366 auto error = RecurseImportData(script, import_data, ScriptContext::TOP);
1367
1368 // Verify whether the watchonly option corresponds to the
1369 // availability of private keys.
1370 bool spendable = std::all_of(
1371 import_data.used_keys.begin(), import_data.used_keys.end(),
1372 [&](const std::pair<CKeyID, bool> &used_key) {
1373 return privkey_map.count(used_key.first) > 0;
1374 });
1375 if (!watchOnly && !spendable) {
1376 warnings.push_back("Some private keys are missing, outputs "
1377 "will be considered watchonly. If this is "
1378 "intentional, specify the watchonly flag.");
1379 }
1380 if (watchOnly && spendable) {
1381 warnings.push_back(
1382 "All private keys are provided, outputs will be considered "
1383 "spendable. If this is intentional, do not specify the "
1384 "watchonly flag.");
1385 }
1386
1387 // Check that all required keys for solvability are provided.
1388 if (error.empty()) {
1389 for (const auto &require_key : import_data.used_keys) {
1390 if (!require_key.second) {
1391 // Not a required key
1392 continue;
1393 }
1394
1395 if (pubkey_map.count(require_key.first) == 0 &&
1396 privkey_map.count(require_key.first) == 0) {
1397 error = "some required keys are missing";
1398 }
1399 }
1400 }
1401
1402 if (!error.empty()) {
1403 warnings.push_back("Importing as non-solvable: " + error +
1404 ". If this is intentional, don't provide "
1405 "any keys, pubkeys or redeemscript.");
1406 import_data = ImportData();
1407 pubkey_map.clear();
1408 privkey_map.clear();
1409 have_solving_data = false;
1410 } else {
1411 // RecurseImportData() removes any relevant redeemscript from
1412 // import_data, so we can use that to discover if a superfluous
1413 // one was provided.
1414 if (import_data.redeemscript) {
1415 warnings.push_back(
1416 "Ignoring redeemscript as this is not a P2SH script.");
1417 }
1418 for (auto it = privkey_map.begin(); it != privkey_map.end();) {
1419 auto oldit = it++;
1420 if (import_data.used_keys.count(oldit->first) == 0) {
1421 warnings.push_back("Ignoring irrelevant private key.");
1422 privkey_map.erase(oldit);
1423 }
1424 }
1425 for (auto it = pubkey_map.begin(); it != pubkey_map.end();) {
1426 auto oldit = it++;
1427 auto key_data_it = import_data.used_keys.find(oldit->first);
1428 if (key_data_it == import_data.used_keys.end() ||
1429 !key_data_it->second) {
1430 warnings.push_back("Ignoring public key \"" +
1431 HexStr(oldit->first) +
1432 "\" as it doesn't appear inside P2PKH.");
1433 pubkey_map.erase(oldit);
1434 }
1435 }
1436 }
1437 }
1438
1439 return warnings;
1440}
1441
1443 std::map<CKeyID, CPubKey> &pubkey_map,
1444 std::map<CKeyID, CKey> &privkey_map,
1445 std::set<CScript> &script_pub_keys,
1446 bool &have_solving_data,
1447 const UniValue &data,
1448 std::vector<CKeyID> &ordered_pubkeys) {
1449 UniValue warnings(UniValue::VARR);
1450
1451 const std::string &descriptor = data["desc"].get_str();
1453 std::string error;
1454 auto parsed_desc =
1455 Parse(descriptor, keys, error, /* require_checksum = */ true);
1456 if (!parsed_desc) {
1458 }
1459
1460 have_solving_data = parsed_desc->IsSolvable();
1461 const bool watch_only =
1462 data.exists("watchonly") ? data["watchonly"].get_bool() : false;
1463
1464 int64_t range_start = 0, range_end = 0;
1465 if (!parsed_desc->IsRange() && data.exists("range")) {
1466 throw JSONRPCError(
1468 "Range should not be specified for an un-ranged descriptor");
1469 } else if (parsed_desc->IsRange()) {
1470 if (!data.exists("range")) {
1471 throw JSONRPCError(
1473 "Descriptor is ranged, please specify the range");
1474 }
1475 std::tie(range_start, range_end) = ParseDescriptorRange(data["range"]);
1476 }
1477
1478 const UniValue &priv_keys =
1479 data.exists("keys") ? data["keys"].get_array() : UniValue();
1480
1481 // Expand all descriptors to get public keys and scripts, and private keys
1482 // if available.
1483 for (int i = range_start; i <= range_end; ++i) {
1484 FlatSigningProvider out_keys;
1485 std::vector<CScript> scripts_temp;
1486 parsed_desc->Expand(i, keys, scripts_temp, out_keys);
1487 std::copy(scripts_temp.begin(), scripts_temp.end(),
1488 std::inserter(script_pub_keys, script_pub_keys.end()));
1489 for (const auto &key_pair : out_keys.pubkeys) {
1490 ordered_pubkeys.push_back(key_pair.first);
1491 }
1492
1493 for (const auto &x : out_keys.scripts) {
1494 import_data.import_scripts.emplace(x.second);
1495 }
1496
1497 parsed_desc->ExpandPrivate(i, keys, out_keys);
1498
1499 std::copy(out_keys.pubkeys.begin(), out_keys.pubkeys.end(),
1500 std::inserter(pubkey_map, pubkey_map.end()));
1501 std::copy(out_keys.keys.begin(), out_keys.keys.end(),
1502 std::inserter(privkey_map, privkey_map.end()));
1503 import_data.key_origins.insert(out_keys.origins.begin(),
1504 out_keys.origins.end());
1505 }
1506
1507 for (size_t i = 0; i < priv_keys.size(); ++i) {
1508 const auto &str = priv_keys[i].get_str();
1509 CKey key = DecodeSecret(str);
1510 if (!key.IsValid()) {
1512 "Invalid private key encoding");
1513 }
1514 CPubKey pubkey = key.GetPubKey();
1515 CKeyID id = pubkey.GetID();
1516
1517 // Check if this private key corresponds to a public key from the
1518 // descriptor
1519 if (!pubkey_map.count(id)) {
1520 warnings.push_back("Ignoring irrelevant private key.");
1521 } else {
1522 privkey_map.emplace(id, key);
1523 }
1524 }
1525
1526 // Check if all the public keys have corresponding private keys in the
1527 // import for spendability. This does not take into account threshold
1528 // multisigs which could be spendable without all keys. Thus, threshold
1529 // multisigs without all keys will be considered not spendable here, even if
1530 // they are, perhaps triggering a false warning message. This is consistent
1531 // with the current wallet IsMine check.
1532 bool spendable =
1533 std::all_of(pubkey_map.begin(), pubkey_map.end(),
1534 [&](const std::pair<CKeyID, CPubKey> &used_key) {
1535 return privkey_map.count(used_key.first) > 0;
1536 }) &&
1537 std::all_of(
1538 import_data.key_origins.begin(), import_data.key_origins.end(),
1539 [&](const std::pair<CKeyID, std::pair<CPubKey, KeyOriginInfo>>
1540 &entry) { return privkey_map.count(entry.first) > 0; });
1541 if (!watch_only && !spendable) {
1542 warnings.push_back(
1543 "Some private keys are missing, outputs will be considered "
1544 "watchonly. If this is intentional, specify the watchonly flag.");
1545 }
1546 if (watch_only && spendable) {
1547 warnings.push_back("All private keys are provided, outputs will be "
1548 "considered spendable. If this is intentional, do "
1549 "not specify the watchonly flag.");
1550 }
1551
1552 return warnings;
1553}
1554
1555static UniValue ProcessImport(CWallet *const pwallet, const UniValue &data,
1556 const int64_t timestamp)
1557 EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
1558 UniValue warnings(UniValue::VARR);
1559 UniValue result(UniValue::VOBJ);
1560
1561 try {
1562 const bool internal =
1563 data.exists("internal") ? data["internal"].get_bool() : false;
1564 // Internal addresses should not have a label
1565 if (internal && data.exists("label")) {
1567 "Internal addresses should not have a label");
1568 }
1569 const std::string &label =
1570 data.exists("label") ? data["label"].get_str() : "";
1571 const bool add_keypool =
1572 data.exists("keypool") ? data["keypool"].get_bool() : false;
1573
1574 // Add to keypool only works with privkeys disabled
1575 if (add_keypool &&
1576 !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
1578 "Keys can only be imported to the keypool when "
1579 "private keys are disabled");
1580 }
1581
1582 ImportData import_data;
1583 std::map<CKeyID, CPubKey> pubkey_map;
1584 std::map<CKeyID, CKey> privkey_map;
1585 std::set<CScript> script_pub_keys;
1586 std::vector<CKeyID> ordered_pubkeys;
1587 bool have_solving_data;
1588
1589 if (data.exists("scriptPubKey") && data.exists("desc")) {
1590 throw JSONRPCError(
1592 "Both a descriptor and a scriptPubKey should not be provided.");
1593 } else if (data.exists("scriptPubKey")) {
1594 warnings = ProcessImportLegacy(
1595 pwallet, import_data, pubkey_map, privkey_map, script_pub_keys,
1596 have_solving_data, data, ordered_pubkeys);
1597 } else if (data.exists("desc")) {
1598 warnings = ProcessImportDescriptor(
1599 import_data, pubkey_map, privkey_map, script_pub_keys,
1600 have_solving_data, data, ordered_pubkeys);
1601 } else {
1602 throw JSONRPCError(
1604 "Either a descriptor or scriptPubKey must be provided.");
1605 }
1606
1607 // If private keys are disabled, abort if private keys are being
1608 // imported
1609 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
1610 !privkey_map.empty()) {
1612 "Cannot import private keys to a wallet with "
1613 "private keys disabled");
1614 }
1615
1616 // Check whether we have any work to do
1617 for (const CScript &script : script_pub_keys) {
1618 if (pwallet->IsMine(script) & ISMINE_SPENDABLE) {
1620 "The wallet already contains the private "
1621 "key for this address or script (\"" +
1622 HexStr(script) + "\")");
1623 }
1624 }
1625
1626 // All good, time to import
1627 pwallet->MarkDirty();
1628 if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) {
1630 "Error adding script to wallet");
1631 }
1632 if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) {
1633 throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet");
1634 }
1635 if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map,
1636 import_data.key_origins, add_keypool,
1637 internal, timestamp)) {
1639 "Error adding address to wallet");
1640 }
1641 if (!pwallet->ImportScriptPubKeys(label, script_pub_keys,
1642 have_solving_data, !internal,
1643 timestamp)) {
1645 "Error adding address to wallet");
1646 }
1647
1648 result.pushKV("success", UniValue(true));
1649 } catch (const UniValue &e) {
1650 result.pushKV("success", UniValue(false));
1651 result.pushKV("error", e);
1652 } catch (...) {
1653 result.pushKV("success", UniValue(false));
1654 result.pushKV("error",
1655 JSONRPCError(RPC_MISC_ERROR, "Missing required fields"));
1656 }
1657
1658 if (warnings.size()) {
1659 result.pushKV("warnings", warnings);
1660 }
1661 return result;
1662}
1663
1664static int64_t GetImportTimestamp(const UniValue &data, int64_t now) {
1665 if (data.exists("timestamp")) {
1666 const UniValue &timestamp = data["timestamp"];
1667 if (timestamp.isNum()) {
1668 return timestamp.getInt<int64_t>();
1669 } else if (timestamp.isStr() && timestamp.get_str() == "now") {
1670 return now;
1671 }
1673 strprintf("Expected number or \"now\" timestamp "
1674 "value for key. got type %s",
1675 uvTypeName(timestamp.type())));
1676 }
1678 "Missing required timestamp field for key");
1679}
1680
1681static std::string GetRescanErrorMessage(const std::string &object,
1682 const int64_t objectTimestamp,
1683 const int64_t blockTimestamp,
1684 const bool have_pruned,
1685 const bool has_assumed_valid_chain) {
1686 std::string error_msg{
1687 strprintf("Rescan failed for %s with creation timestamp %d. There "
1688 "was an error reading a block from time %d, which is after "
1689 "or within %d seconds of key creation, and could contain "
1690 "transactions pertaining to the %s. As a result, "
1691 "transactions and coins using this %s may not appear "
1692 "in the wallet. ",
1693 object, objectTimestamp, blockTimestamp, TIMESTAMP_WINDOW,
1694 object, object)};
1695 if (have_pruned) {
1696 error_msg += strprintf(
1697 "This error could be caused by pruning or data corruption "
1698 "(see bitcoind log for details) and could be dealt with by "
1699 "downloading and rescanning the relevant blocks (see -reindex "
1700 "option and rescanblockchain RPC).");
1701 } else if (has_assumed_valid_chain) {
1702 error_msg += strprintf(
1703 "This error is likely caused by an in-progress assumeutxo "
1704 "background sync. Check logs or getchainstates RPC for assumeutxo "
1705 "background sync progress and try again later.");
1706 } else {
1707 error_msg += strprintf(
1708 "This error could potentially be caused by data corruption. If "
1709 "the issue persists you may want to reindex (see -reindex "
1710 "option).");
1711 }
1712 return error_msg;
1713}
1714
1716 return RPCHelpMan{
1717 "importmulti",
1718 "Import addresses/scripts (with private or public keys, redeem "
1719 "script (P2SH)), optionally rescanning the blockchain from the "
1720 "earliest creation time of the imported scripts. Requires a new wallet "
1721 "backup.\n"
1722 "If an address/script is imported without all of the private keys "
1723 "required to spend from that address, it will be watchonly. The "
1724 "'watchonly' option must be set to true in this case or a warning will "
1725 "be returned.\n"
1726 "Conversely, if all the private keys are provided and the "
1727 "address/script is spendable, the watchonly option must be set to "
1728 "false, or a warning will be returned.\n"
1729 "Note: Use \"getwalletinfo\" to query the scanning progress.\n"
1730 "Note: This command is only compatible with legacy wallets. Use "
1731 "\"importdescriptors\" for descriptor wallets.\n",
1732 {
1733 {"requests",
1736 "Data to be imported",
1737 {
1738 {
1739 "",
1742 "",
1743 {
1745 "Descriptor to import. If using descriptor, do not "
1746 "also provide address/scriptPubKey, scripts, or "
1747 "pubkeys"},
1748 {"scriptPubKey", RPCArg::Type::STR,
1750 "Type of scriptPubKey (string for script, json for "
1751 "address). Should not be provided if using a "
1752 "descriptor",
1754 .type_str = {"\"<script>\" | { "
1755 "\"address\":\"<address>\" }",
1756 "string / json"}}},
1758 "Creation time of the key expressed in " +
1760 ",\n"
1761 "or the string \"now\" to substitute the current "
1762 "synced blockchain time. The timestamp of the "
1763 "oldest\n"
1764 "key will determine how far back blockchain "
1765 "rescans need to begin for missing wallet "
1766 "transactions.\n"
1767 "\"now\" can be specified to bypass scanning, "
1768 "for keys which are known to never have been "
1769 "used, and\n"
1770 "0 can be specified to scan the entire "
1771 "blockchain. Blocks up to 2 hours before the "
1772 "earliest key\n"
1773 "creation time of all keys being imported by the "
1774 "importmulti call will be scanned.",
1775 RPCArgOptions{.type_str = {"timestamp | \"now\"",
1776 "integer / string"}}},
1777 {"redeemscript", RPCArg::Type::STR,
1779 "Allowed only if the scriptPubKey is a P2SH "
1780 "address/scriptPubKey"},
1781 {"pubkeys",
1784 "Array of strings giving pubkeys to import. They "
1785 "must occur in P2PKH scripts. They are not required "
1786 "when the private key is also provided (see the "
1787 "\"keys\" argument).",
1788 {
1789 {"pubKey", RPCArg::Type::STR,
1791 }},
1792 {"keys",
1795 "Array of strings giving private keys to import. The "
1796 "corresponding public keys must occur in the output "
1797 "or redeemscript.",
1798 {
1799 {"key", RPCArg::Type::STR,
1801 }},
1802 {"range", RPCArg::Type::RANGE,
1804 "If a ranged descriptor is used, this specifies the "
1805 "end or the range (in the form [begin,end]) to "
1806 "import"},
1807 {"internal", RPCArg::Type::BOOL,
1808 RPCArg::Default{false},
1809 "Stating whether matching outputs should be treated "
1810 "as not incoming payments (also known as change)"},
1811 {"watchonly", RPCArg::Type::BOOL,
1812 RPCArg::Default{false},
1813 "Stating whether matching outputs should be "
1814 "considered watchonly."},
1815 {"label", RPCArg::Type::STR, RPCArg::Default{""},
1816 "Label to assign to the address, only allowed with "
1817 "internal=false"},
1818 {"keypool", RPCArg::Type::BOOL, RPCArg::Default{false},
1819 "Stating whether imported public keys should be "
1820 "added to the keypool for when users request new "
1821 "addresses. Only allowed when wallet private keys "
1822 "are disabled"},
1823 },
1824 },
1825 },
1826 RPCArgOptions{.oneline_description = "\"requests\""}},
1827 {"options",
1830 "",
1831 {
1832 {"rescan", RPCArg::Type::BOOL, RPCArg::Default{true},
1833 "Stating if should rescan the blockchain after all imports"},
1834 },
1835 RPCArgOptions{.oneline_description = "\"options\""}},
1836 },
1838 "",
1839 "Response is an array with the same size as the input that "
1840 "has the execution result",
1841 {
1843 "",
1844 "",
1845 {
1846 {RPCResult::Type::BOOL, "success", ""},
1848 "warnings",
1849 /* optional */ true,
1850 "",
1851 {
1852 {RPCResult::Type::STR, "", ""},
1853 }},
1855 "error",
1856 /* optional */ true,
1857 "",
1858 {
1859 {RPCResult::Type::ELISION, "", "JSONRPC error"},
1860 }},
1861 }},
1862 }},
1865 "importmulti",
1866 "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1867 "\"timestamp\":1455191478 }, "
1868 "{ \"scriptPubKey\": { \"address\": \"<my 2nd address>\" "
1869 "}, "
1870 "\"label\": \"example 2\", \"timestamp\": 1455191480 }]'") +
1872 "importmulti",
1873 "'[{ \"scriptPubKey\": { \"address\": \"<my address>\" }, "
1874 "\"timestamp\":1455191478 }]' '{ \"rescan\": false}'")
1875
1876 },
1877 [&](const RPCHelpMan &self, const Config &config,
1878 const JSONRPCRequest &mainRequest) -> UniValue {
1879 std::shared_ptr<CWallet> const wallet =
1880 GetWalletForJSONRPCRequest(mainRequest);
1881 if (!wallet) {
1882 return NullUniValue;
1883 }
1884 CWallet *const pwallet = wallet.get();
1885
1887
1888 const UniValue &requests = mainRequest.params[0];
1889
1890 // Default options
1891 bool fRescan = true;
1892
1893 if (!mainRequest.params[1].isNull()) {
1894 const UniValue &options = mainRequest.params[1];
1895
1896 if (options.exists("rescan")) {
1897 fRescan = options["rescan"].get_bool();
1898 }
1899 }
1900
1901 WalletRescanReserver reserver(*pwallet);
1902 if (fRescan && !reserver.reserve()) {
1904 "Wallet is currently rescanning. Abort "
1905 "existing rescan or wait.");
1906 }
1907
1908 int64_t now = 0;
1909 bool fRunScan = false;
1910 int64_t nLowestTimestamp = 0;
1912 {
1913 LOCK(pwallet->cs_wallet);
1914 EnsureWalletIsUnlocked(pwallet);
1915
1916 // Verify all timestamps are present before importing any keys.
1917 CHECK_NONFATAL(pwallet->chain().findBlock(
1918 pwallet->GetLastBlockHash(),
1919 FoundBlock().time(nLowestTimestamp).mtpTime(now)));
1920 for (const UniValue &data : requests.getValues()) {
1921 GetImportTimestamp(data, now);
1922 }
1923
1924 const int64_t minimumTimestamp = 1;
1925
1926 for (const UniValue &data : requests.getValues()) {
1927 const int64_t timestamp = std::max(
1928 GetImportTimestamp(data, now), minimumTimestamp);
1929 const UniValue result =
1930 ProcessImport(pwallet, data, timestamp);
1931 response.push_back(result);
1932
1933 if (!fRescan) {
1934 continue;
1935 }
1936
1937 // If at least one request was successful then allow rescan.
1938 if (result["success"].get_bool()) {
1939 fRunScan = true;
1940 }
1941
1942 // Get the lowest timestamp.
1943 if (timestamp < nLowestTimestamp) {
1944 nLowestTimestamp = timestamp;
1945 }
1946 }
1947 }
1948 if (fRescan && fRunScan && requests.size()) {
1949 int64_t scannedTime = pwallet->RescanFromTime(
1950 nLowestTimestamp, reserver, true /* update */);
1951 {
1952 LOCK(pwallet->cs_wallet);
1953 pwallet->ReacceptWalletTransactions();
1954 }
1955
1956 if (pwallet->IsAbortingRescan()) {
1958 "Rescan aborted by user.");
1959 }
1960 if (scannedTime > nLowestTimestamp) {
1961 std::vector<UniValue> results = response.getValues();
1962 response.clear();
1963 response.setArray();
1964 size_t i = 0;
1965 for (const UniValue &request : requests.getValues()) {
1966 // If key creation date is within the successfully
1967 // scanned range, or if the import result already has an
1968 // error set, let the result stand unmodified. Otherwise
1969 // replace the result with an error message.
1970 if (scannedTime <= GetImportTimestamp(request, now) ||
1971 results.at(i).exists("error")) {
1972 response.push_back(results.at(i));
1973 } else {
1975 result.pushKV("success", UniValue(false));
1976 result.pushKV(
1977 "error",
1981 "key", GetImportTimestamp(request, now),
1982 scannedTime - TIMESTAMP_WINDOW - 1,
1983 pwallet->chain().havePruned(),
1984 pwallet->chain()
1986 response.push_back(std::move(result));
1987 }
1988 ++i;
1989 }
1990 }
1991 }
1992
1993 return response;
1994 },
1995 };
1996}
1997
1999 const UniValue &data,
2000 const int64_t timestamp)
2001 EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) {
2002 UniValue warnings(UniValue::VARR);
2003 UniValue result(UniValue::VOBJ);
2004
2005 try {
2006 if (!data.exists("desc")) {
2007 throw JSONRPCError(RPC_INVALID_PARAMETER, "Descriptor not found.");
2008 }
2009
2010 const std::string &descriptor = data["desc"].get_str();
2011 const bool active =
2012 data.exists("active") ? data["active"].get_bool() : false;
2013 const bool internal =
2014 data.exists("internal") ? data["internal"].get_bool() : false;
2015 const std::string &label =
2016 data.exists("label") ? data["label"].get_str() : "";
2017
2018 // Parse descriptor string
2020 std::string error;
2021 auto parsed_desc =
2022 Parse(descriptor, keys, error, /* require_checksum = */ true);
2023 if (!parsed_desc) {
2025 }
2026
2027 // Range check
2028 int64_t range_start = 0, range_end = 1, next_index = 0;
2029 if (!parsed_desc->IsRange() && data.exists("range")) {
2030 throw JSONRPCError(
2032 "Range should not be specified for an un-ranged descriptor");
2033 } else if (parsed_desc->IsRange()) {
2034 if (data.exists("range")) {
2035 auto range = ParseDescriptorRange(data["range"]);
2036 range_start = range.first;
2037 // Specified range end is inclusive, but we need range end as
2038 // exclusive
2039 range_end = range.second + 1;
2040 } else {
2041 warnings.push_back(
2042 "Range not given, using default keypool range");
2043 range_start = 0;
2044 range_end = gArgs.GetIntArg("-keypool", DEFAULT_KEYPOOL_SIZE);
2045 }
2046 next_index = range_start;
2047
2048 if (data.exists("next_index")) {
2049 next_index = data["next_index"].getInt<int64_t>();
2050 // bound checks
2051 if (next_index < range_start || next_index >= range_end) {
2053 "next_index is out of range");
2054 }
2055 }
2056 }
2057
2058 // Active descriptors must be ranged
2059 if (active && !parsed_desc->IsRange()) {
2061 "Active descriptors must be ranged");
2062 }
2063
2064 // Ranged descriptors should not have a label
2065 if (data.exists("range") && data.exists("label")) {
2067 "Ranged descriptors should not have a label");
2068 }
2069
2070 // Internal addresses should not have a label either
2071 if (internal && data.exists("label")) {
2073 "Internal addresses should not have a label");
2074 }
2075
2076 // Combo descriptor check
2077 if (active && !parsed_desc->IsSingleType()) {
2079 "Combo descriptors cannot be set to active");
2080 }
2081
2082 // If the wallet disabled private keys, abort if private keys exist
2083 if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) &&
2084 !keys.keys.empty()) {
2086 "Cannot import private keys to a wallet with "
2087 "private keys disabled");
2088 }
2089
2090 // Need to ExpandPrivate to check if private keys are available for all
2091 // pubkeys
2092 FlatSigningProvider expand_keys;
2093 std::vector<CScript> scripts;
2094 if (!parsed_desc->Expand(0, keys, scripts, expand_keys)) {
2095 throw JSONRPCError(
2097 "Cannot expand descriptor. Probably because of hardened "
2098 "derivations without private keys provided");
2099 }
2100 parsed_desc->ExpandPrivate(0, keys, expand_keys);
2101
2102 // Check if all private keys are provided
2103 bool have_all_privkeys = !expand_keys.keys.empty();
2104 for (const auto &entry : expand_keys.origins) {
2105 const CKeyID &key_id = entry.first;
2106 CKey key;
2107 if (!expand_keys.GetKey(key_id, key)) {
2108 have_all_privkeys = false;
2109 break;
2110 }
2111 }
2112
2113 // If private keys are enabled, check some things.
2114 if (!pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) {
2115 if (keys.keys.empty()) {
2116 throw JSONRPCError(
2118 "Cannot import descriptor without private keys to a wallet "
2119 "with private keys enabled");
2120 }
2121 if (!have_all_privkeys) {
2122 warnings.push_back(
2123 "Not all private keys provided. Some wallet functionality "
2124 "may return unexpected errors");
2125 }
2126 }
2127
2128 WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start,
2129 range_end, next_index);
2130
2131 // Check if the wallet already contains the descriptor
2132 auto existing_spk_manager =
2133 pwallet->GetDescriptorScriptPubKeyMan(w_desc);
2134 if (existing_spk_manager &&
2135 !existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) {
2136 throw JSONRPCError(RPC_INVALID_PARAMETER, error);
2137 }
2138
2139 // Add descriptor to the wallet
2140 auto spk_manager =
2141 pwallet->AddWalletDescriptor(w_desc, keys, label, internal);
2142 if (spk_manager == nullptr) {
2143 throw JSONRPCError(
2145 strprintf("Could not add descriptor '%s'", descriptor));
2146 }
2147
2148 // Set descriptor as active if necessary
2149 if (active) {
2150 if (!w_desc.descriptor->GetOutputType()) {
2151 warnings.push_back(
2152 "Unknown output type, cannot set descriptor to active.");
2153 } else {
2154 pwallet->AddActiveScriptPubKeyMan(
2155 spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2156 internal);
2157 }
2158 } else {
2159 if (w_desc.descriptor->GetOutputType()) {
2160 pwallet->DeactivateScriptPubKeyMan(
2161 spk_manager->GetID(), *w_desc.descriptor->GetOutputType(),
2162 internal);
2163 }
2164 }
2165
2166 result.pushKV("success", UniValue(true));
2167 } catch (const UniValue &e) {
2168 result.pushKV("success", UniValue(false));
2169 result.pushKV("error", e);
2170 }
2171 if (warnings.size()) {
2172 result.pushKV("warnings", warnings);
2173 }
2174 return result;
2175}
2176
2178 return RPCHelpMan{
2179 "importdescriptors",
2180 "Import descriptors. This will trigger a rescan of the blockchain "
2181 "based on the earliest timestamp of all descriptors being imported. "
2182 "Requires a new wallet backup.\n"
2183 "\nNote: This call can take over an hour to complete if using an early "
2184 "timestamp; during that time, other rpc calls\n"
2185 "may report that the imported keys, addresses or scripts exist but "
2186 "related transactions are still missing.\n",
2187 {
2188 {"requests",
2191 "Data to be imported",
2192 {
2193 {
2194 "",
2197 "",
2198 {
2200 "Descriptor to import."},
2201 {"active", RPCArg::Type::BOOL, RPCArg::Default{false},
2202 "Set this descriptor to be the active descriptor for "
2203 "the corresponding output type/externality"},
2204 {"range", RPCArg::Type::RANGE,
2206 "If a ranged descriptor is used, this specifies the "
2207 "end or the range (in the form [begin,end]) to "
2208 "import"},
2209 {"next_index", RPCArg::Type::NUM,
2211 "If a ranged descriptor is set to active, this "
2212 "specifies the next index to generate addresses "
2213 "from"},
2215 "Time from which to start rescanning the blockchain "
2216 "for this descriptor, in " +
2218 "\n"
2219 "Use the string \"now\" to substitute the "
2220 "current synced blockchain time.\n"
2221 "\"now\" can be specified to bypass scanning, "
2222 "for outputs which are known to never have been "
2223 "used, and\n"
2224 "0 can be specified to scan the entire "
2225 "blockchain. Blocks up to 2 hours before the "
2226 "earliest timestamp\n"
2227 "of all descriptors being imported will be "
2228 "scanned.",
2229 RPCArgOptions{.type_str = {"timestamp | \"now\"",
2230 "integer / string"}}},
2231 {"internal", RPCArg::Type::BOOL,
2232 RPCArg::Default{false},
2233 "Whether matching outputs should be treated as not "
2234 "incoming payments (e.g. change)"},
2235 {"label", RPCArg::Type::STR, RPCArg::Default{""},
2236 "Label to assign to the address, only allowed with "
2237 "internal=false"},
2238 },
2239 },
2240 },
2241 RPCArgOptions{.oneline_description = "\"requests\""}},
2242 },
2244 "",
2245 "Response is an array with the same size as the input that "
2246 "has the execution result",
2247 {
2249 "",
2250 "",
2251 {
2252 {RPCResult::Type::BOOL, "success", ""},
2254 "warnings",
2255 /* optional */ true,
2256 "",
2257 {
2258 {RPCResult::Type::STR, "", ""},
2259 }},
2261 "error",
2262 /* optional */ true,
2263 "",
2264 {
2265 {RPCResult::Type::ELISION, "", "JSONRPC error"},
2266 }},
2267 }},
2268 }},
2270 HelpExampleCli("importdescriptors",
2271 "'[{ \"desc\": \"<my descriptor>\", "
2272 "\"timestamp\":1455191478, \"internal\": true }, "
2273 "{ \"desc\": \"<my desccriptor 2>\", \"label\": "
2274 "\"example 2\", \"timestamp\": 1455191480 }]'") +
2276 "importdescriptors",
2277 "'[{ \"desc\": \"<my descriptor>\", \"timestamp\":1455191478, "
2278 "\"active\": true, \"range\": [0,100], \"label\": \"<my "
2279 "cashaddr wallet>\" }]'")},
2280 [&](const RPCHelpMan &self, const Config &config,
2281 const JSONRPCRequest &main_request) -> UniValue {
2282 std::shared_ptr<CWallet> const wallet =
2283 GetWalletForJSONRPCRequest(main_request);
2284 if (!wallet) {
2285 return NullUniValue;
2286 }
2287 CWallet *const pwallet = wallet.get();
2288
2289 // Make sure wallet is a descriptor wallet
2292 "importdescriptors is not available for "
2293 "non-descriptor wallets");
2294 }
2295
2296 WalletRescanReserver reserver(*pwallet);
2297 if (!reserver.reserve()) {
2299 "Wallet is currently rescanning. Abort "
2300 "existing rescan or wait.");
2301 }
2302
2303 const UniValue &requests = main_request.params[0];
2304 const int64_t minimum_timestamp = 1;
2305 int64_t now = 0;
2306 int64_t lowest_timestamp = 0;
2307 bool rescan = false;
2309 {
2310 LOCK(pwallet->cs_wallet);
2311 EnsureWalletIsUnlocked(pwallet);
2312
2313 CHECK_NONFATAL(pwallet->chain().findBlock(
2314 pwallet->GetLastBlockHash(),
2315 FoundBlock().time(lowest_timestamp).mtpTime(now)));
2316
2317 // Get all timestamps and extract the lowest timestamp
2318 for (const UniValue &request : requests.getValues()) {
2319 // This throws an error if "timestamp" doesn't exist
2320 const int64_t timestamp = std::max(
2321 GetImportTimestamp(request, now), minimum_timestamp);
2322 const UniValue result =
2323 ProcessDescriptorImport(pwallet, request, timestamp);
2324 response.push_back(result);
2325
2326 if (lowest_timestamp > timestamp) {
2327 lowest_timestamp = timestamp;
2328 }
2329
2330 // If we know the chain tip, and at least one request was
2331 // successful then allow rescan
2332 if (!rescan && result["success"].get_bool()) {
2333 rescan = true;
2334 }
2335 }
2337 }
2338
2339 // Rescan the blockchain using the lowest timestamp
2340 if (rescan) {
2341 int64_t scanned_time = pwallet->RescanFromTime(
2342 lowest_timestamp, reserver, true /* update */);
2343 {
2344 LOCK(pwallet->cs_wallet);
2345 pwallet->ReacceptWalletTransactions();
2346 }
2347
2348 if (pwallet->IsAbortingRescan()) {
2350 "Rescan aborted by user.");
2351 }
2352
2353 if (scanned_time > lowest_timestamp) {
2354 std::vector<UniValue> results = response.getValues();
2355 response.clear();
2356 response.setArray();
2357
2358 // Compose the response
2359 for (unsigned int i = 0; i < requests.size(); ++i) {
2360 const UniValue &request = requests.getValues().at(i);
2361
2362 // If the descriptor timestamp is within the
2363 // successfully scanned range, or if the import result
2364 // already has an error set, let the result stand
2365 // unmodified. Otherwise replace the result with an
2366 // error message.
2367 if (scanned_time <= GetImportTimestamp(request, now) ||
2368 results.at(i).exists("error")) {
2369 response.push_back(results.at(i));
2370 } else {
2372 result.pushKV("success", UniValue(false));
2373 result.pushKV(
2374 "error",
2378 "descriptor",
2379 GetImportTimestamp(request, now),
2380 scanned_time - TIMESTAMP_WINDOW - 1,
2381 pwallet->chain().havePruned(),
2382 pwallet->chain()
2384 response.push_back(std::move(result));
2385 }
2386 }
2387 }
2388 }
2389
2390 return response;
2391 },
2392 };
2393}
2394
2396 return RPCHelpMan{
2397 "backupwallet",
2398 "Safely copies current wallet file to destination, which can be a "
2399 "directory or a path with filename.\n",
2400 {
2401 {"destination", RPCArg::Type::STR, RPCArg::Optional::NO,
2402 "The destination directory or file"},
2403 },
2405 RPCExamples{HelpExampleCli("backupwallet", "\"backup.dat\"") +
2406 HelpExampleRpc("backupwallet", "\"backup.dat\"")},
2407 [&](const RPCHelpMan &self, const Config &config,
2408 const JSONRPCRequest &request) -> UniValue {
2409 std::shared_ptr<CWallet> const wallet =
2411 if (!wallet) {
2412 return NullUniValue;
2413 }
2414 const CWallet *const pwallet = wallet.get();
2415
2416 // Make sure the results are valid at least up to the most recent
2417 // block the user could have gotten from another RPC command prior
2418 // to now
2419 pwallet->BlockUntilSyncedToCurrentChain();
2420
2421 LOCK(pwallet->cs_wallet);
2422
2423 std::string strDest = request.params[0].get_str();
2424 if (!pwallet->BackupWallet(strDest)) {
2426 "Error: Wallet backup failed!");
2427 }
2428
2429 return NullUniValue;
2430 },
2431 };
2432}
2433
2435 return RPCHelpMan{
2436 "restorewallet",
2437 "\nRestore and loads a wallet from backup.\n",
2438 {
2439 {"wallet_name", RPCArg::Type::STR, RPCArg::Optional::NO,
2440 "The name that will be applied to the restored wallet"},
2441 {"backup_file", RPCArg::Type::STR, RPCArg::Optional::NO,
2442 "The backup file that will be used to restore the wallet."},
2443 {"load_on_startup", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED,
2444 "Save wallet name to persistent settings and load on startup. "
2445 "True to add wallet to startup list, false to remove, null to "
2446 "leave unchanged."},
2447 },
2449 "",
2450 "",
2451 {
2452 {RPCResult::Type::STR, "name",
2453 "The wallet name if restored successfully."},
2454 {RPCResult::Type::STR, "warning",
2455 "Warning message if wallet was not loaded cleanly."},
2456 }},
2458 "restorewallet",
2459 "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2461 "restorewallet",
2462 "\"testwallet\" \"home\\backups\\backup-file.bak\"") +
2464 "restorewallet",
2465 {{"wallet_name", "testwallet"},
2466 {"backup_file", "home\\backups\\backup-file.bak\""},
2467 {"load_on_startup", true}}) +
2469 "restorewallet",
2470 {{"wallet_name", "testwallet"},
2471 {"backup_file", "home\\backups\\backup-file.bak\""},
2472 {"load_on_startup", true}})},
2473 [&](const RPCHelpMan &self, const Config &config,
2474 const JSONRPCRequest &request) -> UniValue {
2475 WalletContext &context = EnsureWalletContext(request.context);
2476
2477 fs::path backup_file =
2478 fs::PathFromString(request.params[1].get_str());
2479
2480 std::string wallet_name = request.params[0].get_str();
2481
2482 std::optional<bool> load_on_start =
2483 request.params[2].isNull()
2484 ? std::nullopt
2485 : std::optional<bool>(request.params[2].get_bool());
2486
2487 DatabaseStatus status;
2488 bilingual_str error;
2489 std::vector<bilingual_str> warnings;
2490
2491 const std::shared_ptr<CWallet> wallet =
2492 RestoreWallet(context, backup_file, wallet_name, load_on_start,
2493 status, error, warnings);
2494
2495 HandleWalletError(wallet, status, error);
2496
2498 obj.pushKV("name", wallet->GetName());
2499 obj.pushKV("warning", Join(warnings, Untranslated("\n")).original);
2500
2501 return obj;
2502 },
2503 };
2504}
2505
2507 // clang-format off
2508 static const CRPCCommand commands[] = {
2509 // category actor (function)
2510 // ------------------ ----------------------
2511 { "wallet", abortrescan, },
2512 { "wallet", backupwallet, },
2513 { "wallet", dumpprivkey, },
2514 { "wallet", dumpwallet, },
2515 { "wallet", dumpcoins, },
2516 { "wallet", importdescriptors, },
2517 { "wallet", importmulti, },
2518 { "wallet", importprivkey, },
2519 { "wallet", importwallet, },
2520 { "wallet", importaddress, },
2521 { "wallet", importprunedfunds, },
2522 { "wallet", importpubkey, },
2523 { "wallet", removeprunedfunds, },
2524 { "wallet", restorewallet, },
2525 };
2526 // clang-format on
2527
2528 return commands;
2529}
ArgsManager gArgs
Definition: args.cpp:39
static RPCHelpMan dumpcoins()
Definition: backup.cpp:1109
RPCHelpMan importprivkey()
Definition: backup.cpp:131
static const int64_t TIMESTAMP_MIN
Definition: backup.cpp:94
RPCHelpMan importdescriptors()
Definition: backup.cpp:2177
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:1715
static std::string RecurseImportData(const CScript &script, ImportData &import_data, const ScriptContext script_ctx)
Definition: backup.cpp:1202
RPCHelpMan importaddress()
Definition: backup.cpp:290
RPCHelpMan importwallet()
Definition: backup.cpp:668
Span< const CRPCCommand > GetWalletDumpRPCCommands()
Definition: backup.cpp:2506
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:1681
RPCHelpMan dumpwallet()
Definition: backup.cpp:929
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:1255
RPCHelpMan importpubkey()
Definition: backup.cpp:557
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:2434
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:1442
RPCHelpMan abortrescan()
Definition: backup.cpp:257
ScriptContext
Definition: backup.cpp:1192
@ 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:1555
static void EnsureBlockDataFromTime(const CWallet &wallet, int64_t timestamp)
Definition: backup.cpp:109
RPCHelpMan backupwallet()
Definition: backup.cpp:2395
RPCHelpMan dumpprivkey()
Definition: backup.cpp:876
static UniValue ProcessDescriptorImport(CWallet *const pwallet, const UniValue &data, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(pwallet -> cs_wallet)
Definition: backup.cpp:1998
RPCHelpMan removeprunedfunds()
Definition: backup.cpp:507
static int64_t GetImportTimestamp(const UniValue &data, int64_t now)
Definition: backup.cpp:1664
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:494
BlockHash GetHash() const
Definition: block.cpp:11
uint256 hashMerkleRoot
Definition: block.h:28
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:209
bool VerifyPubKey(const CPubKey &vchPubKey) const
Verify thoroughly whether a private key and a public key match.
Definition: key.cpp:301
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:261
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:1056
void ConnectScriptPubKeyManNotifiers()
Connect the signals from ScriptPubKeyMans to the signals in CWallet.
Definition: wallet.cpp:3431
RecursiveMutex cs_wallet
Definition: wallet.h:415
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:994
bool IsAbortingRescan() const
Definition: wallet.h:541
interfaces::Chain & chain() const
Interface for accessing chain state.
Definition: wallet.h:474
bool BackupWallet(const std::string &strDest) const
Definition: wallet.cpp:3204
bool IsScanning() const
Definition: wallet.h:542
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:983
void AbortRescan()
Definition: wallet.h:540
const CAddressBookData * FindAddressBookEntry(const CTxDestination &, bool allow_change=false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:3138
Definition: config.h:19
Double ended buffer combining vector and stream-like interfaces.
Definition: streams.h:118
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:94
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:1129
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:229
const std::string CLIENT_BUILD
const std::string CLIENT_NAME
bool DecodeHexTx(CMutableTransaction &tx, const std::string &strHexTx)
Definition: core_read.cpp:198
bool SetAddressBook(const CTxDestination &address, const std::string &strName, const std::string &purpose)
Definition: wallet.cpp:2327
DBErrors ZapSelectTx(std::vector< TxId > &txIdsIn, std::vector< TxId > &txIdsOut) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:2268
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:1679
void MarkDirty()
Definition: wallet.cpp:962
bool ImportScripts(const std::set< CScript > scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1659
CWalletTx * AddToWallet(CTransactionRef tx, const CWalletTx::Confirmation &confirm, const UpdateWalletTxFn &update_wtx=nullptr, bool fFlushOnClose=true)
Definition: wallet.cpp:1020
bool ImportPrivKeys(const std::map< CKeyID, CKey > &privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1669
isminetype IsMine(const CTxDestination &dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1496
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:1693
const CChainParams & GetChainParams() const override
Definition: wallet.cpp:447
void ReacceptWalletTransactions() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:1920
bool IsWalletFlagSet(uint64_t flag) const override
Check if a certain wallet flag is set.
Definition: wallet.cpp:1589
int64_t RescanFromTime(int64_t startTime, const WalletRescanReserver &reserver, bool update)
Scan active chain for relevant transactions after importing keys.
Definition: wallet.cpp:1728
@ 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
static path absolute(const path &p)
Definition: fs.h:101
static path u8path(const std::string &utf8_str)
Definition: fs.h:90
static bool exists(const path &p)
Definition: fs.h:107
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:170
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:522
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.
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:250
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:381
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:1182
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:1188
std::set< CScript > import_scripts
Definition: backup.cpp:1185
std::map< CKeyID, std::pair< CPubKey, KeyOriginInfo > > key_origins
Definition: backup.cpp:1189
@ 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:62
std::optional< int64_t > ParseISO8601DateTime(std::string_view str)
Definition: time.cpp:103
std::string FormatISO8601DateTime(int64_t nTime)
ISO 8601 formatting is preferred.
Definition: time.cpp:78
#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.
DatabaseStatus
Definition: db.h:227
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