Bitcoin Core 22.99.0
P2P Digital Currency
wallettool.cpp
Go to the documentation of this file.
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/dump.h>
9#include <wallet/salvage.h>
10#include <wallet/wallet.h>
11#include <wallet/walletutil.h>
12
13namespace WalletTool {
14
15// The standard wallet deleter function blocks on the validation interface
16// queue, which doesn't exist for the bitcoin-wallet. Define our own
17// deleter here.
19{
20 wallet->WalletLogPrintf("Releasing wallet\n");
21 wallet->Close();
22 delete wallet;
23}
24
25static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags)
26{
27 LOCK(wallet_instance->cs_wallet);
28
29 wallet_instance->SetMinVersion(FEATURE_HD_SPLIT);
30 wallet_instance->AddWalletFlags(wallet_creation_flags);
31
32 if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
33 auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
34 spk_man->SetupGeneration(false);
35 } else {
36 wallet_instance->SetupDescriptorScriptPubKeyMans();
37 }
38
39 tfm::format(std::cout, "Topping up keypool...\n");
40 wallet_instance->TopUpKeyPool();
41}
42
43static const std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options)
44{
45 DatabaseStatus status;
47 std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
48 if (!database) {
49 tfm::format(std::cerr, "%s\n", error.original);
50 return nullptr;
51 }
52
53 // dummy chain interface
54 std::shared_ptr<CWallet> wallet_instance{new CWallet(nullptr /* chain */, name, std::move(database)), WalletToolReleaseWallet};
55 DBErrors load_wallet_ret;
56 try {
57 load_wallet_ret = wallet_instance->LoadWallet();
58 } catch (const std::runtime_error&) {
59 tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
60 return nullptr;
61 }
62
63 if (load_wallet_ret != DBErrors::LOAD_OK) {
64 wallet_instance = nullptr;
65 if (load_wallet_ret == DBErrors::CORRUPT) {
66 tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name);
67 return nullptr;
68 } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
69 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 tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
75 return nullptr;
76 } else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
77 tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
78 return nullptr;
79 } else if (load_wallet_ret == DBErrors::NEED_RESCAN) {
80 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 tfm::format(std::cerr, "Error loading %s", name);
85 return nullptr;
86 }
87 }
88
89 if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
90
91 return wallet_instance;
92}
93
94static void WalletShowInfo(CWallet* wallet_instance)
95{
96 LOCK(wallet_instance->cs_wallet);
97
98 tfm::format(std::cout, "Wallet info\n===========\n");
99 tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName());
100 tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format());
101 tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no");
102 tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
103 tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
104 tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
105 tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
106 tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
107}
108
109bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
110{
111 if (args.IsArgSet("-format") && command != "createfromdump") {
112 tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n");
113 return false;
114 }
115 if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
116 tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
117 return false;
118 }
119 if (args.IsArgSet("-descriptors") && command != "create") {
120 tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
121 return false;
122 }
123 if (args.IsArgSet("-legacy") && command != "create") {
124 tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n");
125 return false;
126 }
127 if (command == "create" && !args.IsArgSet("-wallet")) {
128 tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
129 return false;
130 }
131 const std::string name = args.GetArg("-wallet", "");
133
134 if (command == "create") {
135 DatabaseOptions options;
136 options.require_create = true;
137 // If -legacy is set, use it. Otherwise default to false.
138 bool make_legacy = args.GetBoolArg("-legacy", false);
139 // If neither -legacy nor -descriptors is set, default to true. If -descriptors is set, use its value.
140 bool make_descriptors = (!args.IsArgSet("-descriptors") && !args.IsArgSet("-legacy")) || (args.IsArgSet("-descriptors") && args.GetBoolArg("-descriptors", true));
141 if (make_legacy && make_descriptors) {
142 tfm::format(std::cerr, "Only one of -legacy or -descriptors can be set to true, not both\n");
143 return false;
144 }
145 if (!make_legacy && !make_descriptors) {
146 tfm::format(std::cerr, "One of -legacy or -descriptors must be set to true (or omitted)\n");
147 return false;
148 }
149 if (make_descriptors) {
152 }
153
154 const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
155 if (wallet_instance) {
156 WalletShowInfo(wallet_instance.get());
157 wallet_instance->Close();
158 }
159 } else if (command == "info") {
160 DatabaseOptions options;
161 options.require_existing = true;
162 const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
163 if (!wallet_instance) return false;
164 WalletShowInfo(wallet_instance.get());
165 wallet_instance->Close();
166 } else if (command == "salvage") {
167#ifdef USE_BDB
169 std::vector<bilingual_str> warnings;
170 bool ret = RecoverDatabaseFile(path, error, warnings);
171 if (!ret) {
172 for (const auto& warning : warnings) {
173 tfm::format(std::cerr, "%s\n", warning.original);
174 }
175 if (!error.empty()) {
176 tfm::format(std::cerr, "%s\n", error.original);
177 }
178 }
179 return ret;
180#else
181 tfm::format(std::cerr, "Salvage command is not available as BDB support is not compiled");
182 return false;
183#endif
184 } else if (command == "dump") {
185 DatabaseOptions options;
186 options.require_existing = true;
187 const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
188 if (!wallet_instance) return false;
190 bool ret = DumpWallet(*wallet_instance, error);
191 if (!ret && !error.empty()) {
192 tfm::format(std::cerr, "%s\n", error.original);
193 return ret;
194 }
195 tfm::format(std::cout, "The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n");
196 return ret;
197 } else if (command == "createfromdump") {
199 std::vector<bilingual_str> warnings;
200 bool ret = CreateFromDump(name, path, error, warnings);
201 for (const auto& warning : warnings) {
202 tfm::format(std::cout, "%s\n", warning.original);
203 }
204 if (!ret && !error.empty()) {
205 tfm::format(std::cerr, "%s\n", error.original);
206 }
207 return ret;
208 } else {
209 tfm::format(std::cerr, "Invalid command: %s\n", command);
210 return false;
211 }
212
213 return true;
214}
215} // namespace WalletTool
#define PACKAGE_NAME
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:496
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:590
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:602
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:229
RecursiveMutex cs_wallet
Main wallet lock.
Definition: wallet.h:345
void SetupDescriptorScriptPubKeyMans() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new DescriptorScriptPubKeyMans and add them to the wallet.
Definition: wallet.cpp:3150
LegacyScriptPubKeyMan * GetOrCreateLegacyScriptPubKeyMan()
Definition: wallet.cpp:3101
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
Definition: wallet.h:355
WalletDatabase & GetDatabase() const override
Definition: wallet.h:347
bool IsCrypted() const
Definition: wallet.cpp:2967
bool SetupGeneration(bool force=false) override
Sets up the key generation stuff, i.e.
virtual std::string Format()=0
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:34
std::unique_ptr< WalletDatabase > MakeDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Definition: walletdb.cpp:1103
DatabaseStatus
Definition: db.h:212
bool CreateFromDump(const std::string &name, const fs::path &wallet_path, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: dump.cpp:108
bool DumpWallet(CWallet &wallet, bilingual_str &error)
Definition: dump.cpp:13
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:2118
bool TopUpKeyPool(unsigned int kpSize=0)
Definition: wallet.cpp:2129
bool AddWalletFlags(uint64_t flags)
overwrite all flags by the given uint64_t returns false if unknown, non-tolerable flags are present
Definition: wallet.cpp:1438
void SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr) override
signify that a particular wallet feature is now used.
Definition: wallet.cpp:475
bool IsHDEnabled() const
Definition: wallet.cpp:1370
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
Definition: wallet.cpp:1421
bool ExecuteWalletToolFunc(const ArgsManager &args, const std::string &command)
Definition: wallettool.cpp:109
static void WalletToolReleaseWallet(CWallet *wallet)
Definition: wallettool.cpp:18
static const std::shared_ptr< CWallet > MakeWallet(const std::string &name, const fs::path &path, DatabaseOptions options)
Definition: wallettool.cpp:43
static void WalletCreate(CWallet *wallet_instance, uint64_t wallet_creation_flags)
Definition: wallettool.cpp:25
static void WalletShowInfo(CWallet *wallet_instance)
Definition: wallettool.cpp:94
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:133
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:35
void format(std::ostream &out, const char *fmt, const Args &... args)
Format list of arguments to the stream according to given format string.
Definition: tinyformat.h:1062
const char * name
Definition: rest.cpp:43
bool RecoverDatabaseFile(const fs::path &file_path, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: salvage.cpp:25
bool require_create
Definition: db.h:205
std::optional< DatabaseFormat > require_format
Definition: db.h:206
uint64_t create_flags
Definition: db.h:207
bool require_existing
Definition: db.h:204
Bilingual messages:
Definition: translation.h:16
#define LOCK(cs)
Definition: sync.h:226
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
DBErrors
Error statuses for the wallet database.
Definition: walletdb.h:44
@ NONCRITICAL_ERROR
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:10
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:65
@ FEATURE_HD_SPLIT
Definition: walletutil.h:23