Line data Source code
1 : // Copyright (c) 2016-2020 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 <fs.h>
6 : #include <util/system.h>
7 : #include <util/translation.h>
8 : #include <wallet/salvage.h>
9 : #include <wallet/wallet.h>
10 : #include <wallet/walletutil.h>
11 :
12 : namespace WalletTool {
13 :
14 : // The standard wallet deleter function blocks on the validation interface
15 : // queue, which doesn't exist for the bitcoin-wallet. Define our own
16 : // deleter here.
17 3 : static void WalletToolReleaseWallet(CWallet* wallet)
18 : {
19 3 : wallet->WalletLogPrintf("Releasing wallet\n");
20 3 : wallet->Close();
21 3 : delete wallet;
22 3 : }
23 :
24 1 : static void WalletCreate(CWallet* wallet_instance)
25 : {
26 1 : LOCK(wallet_instance->cs_wallet);
27 :
28 1 : wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
29 :
30 : // generate a new HD seed
31 1 : auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
32 1 : CPubKey seed = spk_man->GenerateNewSeed();
33 1 : spk_man->SetHDSeed(seed);
34 :
35 1 : tfm::format(std::cout, "Topping up keypool...\n");
36 1 : wallet_instance->TopUpKeyPool();
37 1 : }
38 :
39 5 : static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, bool create)
40 : {
41 5 : DatabaseOptions options;
42 5 : DatabaseStatus status;
43 5 : if (create) {
44 1 : options.require_create = true;
45 1 : } else {
46 4 : options.require_existing = true;
47 : }
48 5 : bilingual_str error;
49 5 : std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
50 5 : if (!database) {
51 2 : tfm::format(std::cerr, "%s\n", error.original);
52 2 : return nullptr;
53 : }
54 :
55 : // dummy chain interface
56 3 : std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet};
57 : DBErrors load_wallet_ret;
58 : try {
59 3 : bool first_run;
60 3 : load_wallet_ret = wallet_instance->LoadWallet(first_run);
61 3 : } catch (const std::runtime_error&) {
62 0 : tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
63 0 : return nullptr;
64 0 : }
65 :
66 3 : if (load_wallet_ret != DBErrors::LOAD_OK) {
67 0 : wallet_instance = nullptr;
68 0 : if (load_wallet_ret == DBErrors::CORRUPT) {
69 0 : tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name);
70 0 : return nullptr;
71 0 : } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
72 0 : tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
73 : " or address book entries might be missing or incorrect.",
74 : name);
75 0 : } else if (load_wallet_ret == DBErrors::TOO_NEW) {
76 0 : tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
77 : name, PACKAGE_NAME);
78 0 : return nullptr;
79 0 : } else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
80 0 : tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
81 0 : return nullptr;
82 : } else {
83 0 : tfm::format(std::cerr, "Error loading %s", name);
84 0 : return nullptr;
85 : }
86 : }
87 :
88 3 : if (create) WalletCreate(wallet_instance.get());
89 :
90 3 : return wallet_instance;
91 5 : }
92 :
93 3 : static void WalletShowInfo(CWallet* wallet_instance)
94 : {
95 3 : LOCK(wallet_instance->cs_wallet);
96 :
97 3 : tfm::format(std::cout, "Wallet info\n===========\n");
98 3 : tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
99 3 : tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
100 3 : tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
101 3 : tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
102 3 : tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
103 3 : }
104 :
105 8 : bool ExecuteWalletToolFunc(const std::string& command, const std::string& name)
106 : {
107 8 : fs::path path = fs::absolute(name, GetWalletDir());
108 :
109 8 : if (command == "create") {
110 1 : std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ true);
111 1 : if (wallet_instance) {
112 1 : WalletShowInfo(wallet_instance.get());
113 1 : wallet_instance->Close();
114 : }
115 8 : } else if (command == "info" || command == "salvage") {
116 5 : if (command == "info") {
117 4 : std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, /* create= */ false);
118 4 : if (!wallet_instance) return false;
119 2 : WalletShowInfo(wallet_instance.get());
120 2 : wallet_instance->Close();
121 5 : } else if (command == "salvage") {
122 1 : bilingual_str error;
123 1 : std::vector<bilingual_str> warnings;
124 1 : bool ret = RecoverDatabaseFile(path, error, warnings);
125 1 : if (!ret) {
126 0 : for (const auto& warning : warnings) {
127 0 : tfm::format(std::cerr, "%s\n", warning.original);
128 : }
129 0 : if (!error.empty()) {
130 0 : tfm::format(std::cerr, "%s\n", error.original);
131 : }
132 : }
133 : return ret;
134 1 : }
135 : } else {
136 2 : tfm::format(std::cerr, "Invalid command: %s\n", command);
137 2 : return false;
138 : }
139 :
140 3 : return true;
141 8 : }
142 : } // namespace WalletTool
|