Branch data Line data Source code
1 : : // Copyright (c) 2016-2022 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 <bitcoin-build-config.h> // IWYU pragma: keep
6 : :
7 : : #include <wallet/wallettool.h>
8 : :
9 : : #include <common/args.h>
10 : : #include <util/check.h>
11 : : #include <util/fs.h>
12 : : #include <util/translation.h>
13 : : #include <wallet/dump.h>
14 : : #include <wallet/wallet.h>
15 : : #include <wallet/walletutil.h>
16 : :
17 : : namespace wallet {
18 : : namespace WalletTool {
19 : :
20 : : // The standard wallet deleter function blocks on the validation interface
21 : : // queue, which doesn't exist for the bitcoin-wallet. Define our own
22 : : // deleter here.
23 : 4 : static void WalletToolReleaseWallet(CWallet* wallet)
24 : : {
25 : 4 : wallet->WalletLogPrintf("Releasing wallet\n");
26 : 4 : wallet->Close();
27 [ + - ]: 4 : delete wallet;
28 : 4 : }
29 : :
30 : 1 : static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags)
31 : : {
32 : 1 : LOCK(wallet_instance->cs_wallet);
33 : :
34 [ + - ]: 1 : wallet_instance->SetMinVersion(FEATURE_LATEST);
35 [ + - ]: 1 : wallet_instance->InitWalletFlags(wallet_creation_flags);
36 : :
37 [ + - + - ]: 1 : Assert(wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
38 [ + - ]: 1 : wallet_instance->SetupDescriptorScriptPubKeyMans();
39 : :
40 [ + - ]: 1 : tfm::format(std::cout, "Topping up keypool...\n");
41 [ + - ]: 1 : wallet_instance->TopUpKeyPool();
42 : 1 : }
43 : :
44 : 6 : static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options)
45 : : {
46 : 6 : DatabaseStatus status;
47 [ + - ]: 6 : bilingual_str error;
48 [ + - ]: 6 : std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
49 [ + + ]: 6 : if (!database) {
50 [ + - ]: 2 : tfm::format(std::cerr, "%s\n", error.original);
51 : 2 : return nullptr;
52 : : }
53 : :
54 : : // dummy chain interface
55 [ + - + - : 8 : std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet};
+ - - - ]
56 : 4 : DBErrors load_wallet_ret;
57 : 4 : try {
58 [ + - ]: 4 : load_wallet_ret = wallet_instance->LoadWallet();
59 [ - - ]: 0 : } catch (const std::runtime_error&) {
60 [ - - ]: 0 : tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
61 : 0 : return nullptr;
62 : 0 : }
63 : :
64 [ - - - - : 4 : if (load_wallet_ret != DBErrors::LOAD_OK) {
- - + ]
65 : : if (load_wallet_ret == DBErrors::CORRUPT) {
66 [ # # ]: 0 : tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name);
67 : 0 : return nullptr;
68 : : } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
69 [ # # ]: 0 : tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
70 : : " or address book entries might be missing or incorrect.",
71 : : name);
72 : : } else if (load_wallet_ret == DBErrors::TOO_NEW) {
73 [ # # ]: 0 : tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
74 : : name, CLIENT_NAME);
75 : 0 : return nullptr;
76 : : } else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
77 [ # # ]: 0 : tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", CLIENT_NAME);
78 : 0 : return nullptr;
79 : : } else if (load_wallet_ret == DBErrors::NEED_RESCAN) {
80 [ # # ]: 0 : tfm::format(std::cerr, "Error reading %s! Some transaction data might be missing or"
81 : : " incorrect. Wallet requires a rescan.",
82 : : name);
83 : : } else {
84 [ # # ]: 0 : tfm::format(std::cerr, "Error loading %s", name);
85 : 0 : return nullptr;
86 : : }
87 : : }
88 : :
89 [ + + + - ]: 4 : if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
90 : :
91 : 4 : return wallet_instance;
92 : 12 : }
93 : :
94 : 4 : static void WalletShowInfo(CWallet* wallet_instance)
95 : : {
96 : 4 : LOCK(wallet_instance->cs_wallet);
97 : :
98 [ + - ]: 4 : tfm::format(std::cout, "Wallet info\n===========\n");
99 [ + - ]: 4 : tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName());
100 [ + - + - ]: 4 : tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format());
101 [ + - - + : 4 : tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no");
+ - ]
102 [ + - + - : 8 : tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
+ - ]
103 [ + - - + : 4 : tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
+ - ]
104 [ + - + - ]: 4 : tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
105 [ + - ]: 4 : tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
106 [ + - ]: 4 : tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
107 : 4 : }
108 : :
109 : 26 : bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
110 : : {
111 [ + - + + : 52 : if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
+ + + - -
+ ]
112 : 0 : tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
113 : 0 : return false;
114 : : }
115 [ + + + - : 28 : if (command == "create" && !args.IsArgSet("-wallet")) {
+ + + + ]
116 : 1 : tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
117 : 1 : return false;
118 : : }
119 [ + - + - ]: 50 : const std::string name = args.GetArg("-wallet", "");
120 [ + - + - : 50 : const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(name));
+ - ]
121 : :
122 [ + + ]: 25 : if (command == "create") {
123 [ + - ]: 1 : DatabaseOptions options;
124 [ + - ]: 1 : ReadDatabaseArgs(args, options);
125 : 1 : options.require_create = true;
126 : 1 : options.create_flags |= WALLET_FLAG_DESCRIPTORS;
127 [ + - ]: 1 : options.require_format = DatabaseFormat::SQLITE;
128 : :
129 [ + - + - ]: 1 : const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
130 [ + - ]: 1 : if (wallet_instance) {
131 [ + - ]: 1 : WalletShowInfo(wallet_instance.get());
132 [ + - ]: 1 : wallet_instance->Close();
133 : : }
134 [ + + ]: 25 : } else if (command == "info") {
135 [ + - ]: 5 : DatabaseOptions options;
136 [ + - ]: 5 : ReadDatabaseArgs(args, options);
137 : 5 : options.require_existing = true;
138 [ + - + - ]: 5 : const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
139 [ + + - + ]: 5 : if (!wallet_instance) return false;
140 [ + - ]: 3 : WalletShowInfo(wallet_instance.get());
141 [ + - ]: 3 : wallet_instance->Close();
142 [ + + ]: 24 : } else if (command == "dump") {
143 [ + - ]: 7 : DatabaseOptions options;
144 [ + - ]: 7 : ReadDatabaseArgs(args, options);
145 : 7 : options.require_existing = true;
146 : 7 : DatabaseStatus status;
147 : :
148 [ + - + - : 14 : if (IsBDBFile(BDBDataFile(path))) {
- + ]
149 : 0 : options.require_format = DatabaseFormat::BERKELEY_RO;
150 : : }
151 : :
152 [ + - ]: 7 : bilingual_str error;
153 [ + - ]: 7 : std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
154 [ - + ]: 7 : if (!database) {
155 [ # # ]: 0 : tfm::format(std::cerr, "%s\n", error.original);
156 : : return false;
157 : : }
158 : :
159 [ + - ]: 7 : bool ret = DumpWallet(args, *database, error);
160 [ + + - + ]: 7 : if (!ret && !error.empty()) {
161 [ + - ]: 2 : tfm::format(std::cerr, "%s\n", error.original);
162 : : return ret;
163 : : }
164 [ + - ]: 5 : tfm::format(std::cout, "The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n");
165 : : return ret;
166 [ + - ]: 26 : } else if (command == "createfromdump") {
167 [ + - ]: 12 : bilingual_str error;
168 : 12 : std::vector<bilingual_str> warnings;
169 [ + - ]: 12 : bool ret = CreateFromDump(args, name, path, error, warnings);
170 [ - + ]: 12 : for (const auto& warning : warnings) {
171 [ # # ]: 0 : tfm::format(std::cout, "%s\n", warning.original);
172 : : }
173 [ + + + - ]: 12 : if (!ret && !error.empty()) {
174 [ + - ]: 10 : tfm::format(std::cerr, "%s\n", error.original);
175 : : }
176 : 12 : return ret;
177 : 24 : } else {
178 [ # # ]: 0 : tfm::format(std::cerr, "Invalid command: %s\n", command);
179 : : return false;
180 : : }
181 : :
182 : : return true;
183 : 25 : }
184 : : } // namespace WalletTool
185 : : } // namespace wallet
|