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