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