Bitcoin Core  27.99.0
P2P Digital Currency
wallettool.cpp
Go to the documentation of this file.
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 <config/bitcoin-config.h> // IWYU pragma: keep
6 
7 #include <wallet/wallettool.h>
8 
9 #include <common/args.h>
10 #include <util/fs.h>
11 #include <util/translation.h>
12 #include <wallet/dump.h>
13 #include <wallet/salvage.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.
24 {
25  wallet->WalletLogPrintf("Releasing wallet\n");
26  wallet->Close();
27  delete wallet;
28 }
29 
30 static void WalletCreate(CWallet* wallet_instance, uint64_t wallet_creation_flags)
31 {
32  LOCK(wallet_instance->cs_wallet);
33 
34  wallet_instance->SetMinVersion(FEATURE_LATEST);
35  wallet_instance->InitWalletFlags(wallet_creation_flags);
36 
37  if (!wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
38  auto spk_man = wallet_instance->GetOrCreateLegacyScriptPubKeyMan();
39  spk_man->SetupGeneration(false);
40  } else {
41  wallet_instance->SetupDescriptorScriptPubKeyMans();
42  }
43 
44  tfm::format(std::cout, "Topping up keypool...\n");
45  wallet_instance->TopUpKeyPool();
46 }
47 
48 static std::shared_ptr<CWallet> MakeWallet(const std::string& name, const fs::path& path, DatabaseOptions options)
49 {
50  DatabaseStatus status;
51  bilingual_str error;
52  std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
53  if (!database) {
54  tfm::format(std::cerr, "%s\n", error.original);
55  return nullptr;
56  }
57 
58  // dummy chain interface
59  std::shared_ptr<CWallet> wallet_instance{new CWallet(/*chain=*/nullptr, name, std::move(database)), WalletToolReleaseWallet};
60  DBErrors load_wallet_ret;
61  try {
62  load_wallet_ret = wallet_instance->LoadWallet();
63  } catch (const std::runtime_error&) {
64  tfm::format(std::cerr, "Error loading %s. Is wallet being used by another process?\n", name);
65  return nullptr;
66  }
67 
68  if (load_wallet_ret != DBErrors::LOAD_OK) {
69  if (load_wallet_ret == DBErrors::CORRUPT) {
70  tfm::format(std::cerr, "Error loading %s: Wallet corrupted", name);
71  return nullptr;
72  } else if (load_wallet_ret == DBErrors::NONCRITICAL_ERROR) {
73  tfm::format(std::cerr, "Error reading %s! All keys read correctly, but transaction data"
74  " or address book entries might be missing or incorrect.",
75  name);
76  } else if (load_wallet_ret == DBErrors::TOO_NEW) {
77  tfm::format(std::cerr, "Error loading %s: Wallet requires newer version of %s",
79  return nullptr;
80  } else if (load_wallet_ret == DBErrors::NEED_REWRITE) {
81  tfm::format(std::cerr, "Wallet needed to be rewritten: restart %s to complete", PACKAGE_NAME);
82  return nullptr;
83  } else if (load_wallet_ret == DBErrors::NEED_RESCAN) {
84  tfm::format(std::cerr, "Error reading %s! Some transaction data might be missing or"
85  " incorrect. Wallet requires a rescan.",
86  name);
87  } else {
88  tfm::format(std::cerr, "Error loading %s", name);
89  return nullptr;
90  }
91  }
92 
93  if (options.require_create) WalletCreate(wallet_instance.get(), options.create_flags);
94 
95  return wallet_instance;
96 }
97 
98 static void WalletShowInfo(CWallet* wallet_instance)
99 {
100  LOCK(wallet_instance->cs_wallet);
101 
102  tfm::format(std::cout, "Wallet info\n===========\n");
103  tfm::format(std::cout, "Name: %s\n", wallet_instance->GetName());
104  tfm::format(std::cout, "Format: %s\n", wallet_instance->GetDatabase().Format());
105  tfm::format(std::cout, "Descriptors: %s\n", wallet_instance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) ? "yes" : "no");
106  tfm::format(std::cout, "Encrypted: %s\n", wallet_instance->IsCrypted() ? "yes" : "no");
107  tfm::format(std::cout, "HD (hd seed available): %s\n", wallet_instance->IsHDEnabled() ? "yes" : "no");
108  tfm::format(std::cout, "Keypool Size: %u\n", wallet_instance->GetKeyPoolSize());
109  tfm::format(std::cout, "Transactions: %zu\n", wallet_instance->mapWallet.size());
110  tfm::format(std::cout, "Address Book: %zu\n", wallet_instance->m_address_book.size());
111 }
112 
113 bool ExecuteWalletToolFunc(const ArgsManager& args, const std::string& command)
114 {
115  if (args.IsArgSet("-format") && command != "createfromdump") {
116  tfm::format(std::cerr, "The -format option can only be used with the \"createfromdump\" command.\n");
117  return false;
118  }
119  if (args.IsArgSet("-dumpfile") && command != "dump" && command != "createfromdump") {
120  tfm::format(std::cerr, "The -dumpfile option can only be used with the \"dump\" and \"createfromdump\" commands.\n");
121  return false;
122  }
123  if (args.IsArgSet("-descriptors") && command != "create") {
124  tfm::format(std::cerr, "The -descriptors option can only be used with the 'create' command.\n");
125  return false;
126  }
127  if (args.IsArgSet("-legacy") && command != "create") {
128  tfm::format(std::cerr, "The -legacy option can only be used with the 'create' command.\n");
129  return false;
130  }
131  if (command == "create" && !args.IsArgSet("-wallet")) {
132  tfm::format(std::cerr, "Wallet name must be provided when creating a new wallet.\n");
133  return false;
134  }
135  const std::string name = args.GetArg("-wallet", "");
137 
138  if (command == "create") {
139  DatabaseOptions options;
140  ReadDatabaseArgs(args, options);
141  options.require_create = true;
142  // If -legacy is set, use it. Otherwise default to false.
143  bool make_legacy = args.GetBoolArg("-legacy", false);
144  // If neither -legacy nor -descriptors is set, default to true. If -descriptors is set, use its value.
145  bool make_descriptors = (!args.IsArgSet("-descriptors") && !args.IsArgSet("-legacy")) || (args.IsArgSet("-descriptors") && args.GetBoolArg("-descriptors", true));
146  if (make_legacy && make_descriptors) {
147  tfm::format(std::cerr, "Only one of -legacy or -descriptors can be set to true, not both\n");
148  return false;
149  }
150  if (!make_legacy && !make_descriptors) {
151  tfm::format(std::cerr, "One of -legacy or -descriptors must be set to true (or omitted)\n");
152  return false;
153  }
154  if (make_descriptors) {
157  }
158 
159  const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
160  if (wallet_instance) {
161  WalletShowInfo(wallet_instance.get());
162  wallet_instance->Close();
163  }
164  } else if (command == "info") {
165  DatabaseOptions options;
166  ReadDatabaseArgs(args, options);
167  options.require_existing = true;
168  const std::shared_ptr<CWallet> wallet_instance = MakeWallet(name, path, options);
169  if (!wallet_instance) return false;
170  WalletShowInfo(wallet_instance.get());
171  wallet_instance->Close();
172  } else if (command == "salvage") {
173 #ifdef USE_BDB
174  bilingual_str error;
175  std::vector<bilingual_str> warnings;
176  bool ret = RecoverDatabaseFile(args, path, error, warnings);
177  if (!ret) {
178  for (const auto& warning : warnings) {
179  tfm::format(std::cerr, "%s\n", warning.original);
180  }
181  if (!error.empty()) {
182  tfm::format(std::cerr, "%s\n", error.original);
183  }
184  }
185  return ret;
186 #else
187  tfm::format(std::cerr, "Salvage command is not available as BDB support is not compiled");
188  return false;
189 #endif
190  } else if (command == "dump") {
191  DatabaseOptions options;
192  ReadDatabaseArgs(args, options);
193  options.require_existing = true;
194  DatabaseStatus status;
195 
196  if (args.GetBoolArg("-withinternalbdb", false) && IsBDBFile(BDBDataFile(path))) {
198  }
199 
200  bilingual_str error;
201  std::unique_ptr<WalletDatabase> database = MakeDatabase(path, options, status, error);
202  if (!database) {
203  tfm::format(std::cerr, "%s\n", error.original);
204  return false;
205  }
206 
207  bool ret = DumpWallet(args, *database, error);
208  if (!ret && !error.empty()) {
209  tfm::format(std::cerr, "%s\n", error.original);
210  return ret;
211  }
212  tfm::format(std::cout, "The dumpfile may contain private keys. To ensure the safety of your Bitcoin, do not share the dumpfile.\n");
213  return ret;
214  } else if (command == "createfromdump") {
215  bilingual_str error;
216  std::vector<bilingual_str> warnings;
217  bool ret = CreateFromDump(args, name, path, error, warnings);
218  for (const auto& warning : warnings) {
219  tfm::format(std::cout, "%s\n", warning.original);
220  }
221  if (!ret && !error.empty()) {
222  tfm::format(std::cerr, "%s\n", error.original);
223  }
224  return ret;
225  } else {
226  tfm::format(std::cerr, "Invalid command: %s\n", command);
227  return false;
228  }
229 
230  return true;
231 }
232 } // namespace WalletTool
233 } // namespace wallet
int ret
#define PACKAGE_NAME
const auto command
ArgsManager & args
Definition: bitcoind.cpp:267
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:369
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: args.cpp:455
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:505
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:33
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
Definition: wallet.h:301
const std::string & GetName() const
Get a name for this wallet for logging/debugging purposes.
Definition: wallet.h:453
bool IsCrypted() const
Definition: wallet.cpp:3443
WalletDatabase & GetDatabase() const override
Definition: wallet.h:445
void SetupDescriptorScriptPubKeyMans(const CExtKey &master_key) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Create new DescriptorScriptPubKeyMans and add them to the wallet.
Definition: wallet.cpp:3688
RecursiveMutex cs_wallet
Main wallet lock.
Definition: wallet.h:443
LegacyScriptPubKeyMan * GetOrCreateLegacyScriptPubKeyMan()
Definition: wallet.cpp:3605
bool SetupGeneration(bool force=false) override
Sets up the key generation stuff, i.e.
virtual std::string Format()=0
bool TopUpKeyPool(unsigned int kpSize=0)
Definition: wallet.cpp:2532
unsigned int GetKeyPoolSize() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Definition: wallet.cpp:2521
void SetMinVersion(enum WalletFeature, WalletBatch *batch_in=nullptr) override
signify that a particular wallet feature is now used.
Definition: wallet.cpp:644
bool IsWalletFlagSet(uint64_t flag) const override
check if a certain wallet flag is set
Definition: wallet.cpp:1717
bool IsHDEnabled() const
Definition: wallet.cpp:1666
void InitWalletFlags(uint64_t flags)
overwrite all flags by the given uint64_t flags must be uninitialised (or 0) only known flags may be ...
Definition: wallet.cpp:1734
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:174
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:36
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:1060
static std::shared_ptr< CWallet > MakeWallet(const std::string &name, const fs::path &path, DatabaseOptions options)
Definition: wallettool.cpp:48
static void WalletShowInfo(CWallet *wallet_instance)
Definition: wallettool.cpp:98
static void WalletToolReleaseWallet(CWallet *wallet)
Definition: wallettool.cpp:23
bool ExecuteWalletToolFunc(const ArgsManager &args, const std::string &command)
Definition: wallettool.cpp:113
static void WalletCreate(CWallet *wallet_instance, uint64_t wallet_creation_flags)
Definition: wallettool.cpp:30
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
Definition: db.cpp:145
std::unique_ptr< WalletDatabase > MakeDatabase(const fs::path &path, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error)
Definition: walletdb.cpp:1349
DBErrors
Error statuses for the wallet database.
Definition: walletdb.h:48
bool CreateFromDump(const ArgsManager &args, const std::string &name, const fs::path &wallet_path, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: dump.cpp:122
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13
bool IsBDBFile(const fs::path &path)
Definition: db.cpp:86
fs::path BDBDataFile(const fs::path &wallet_path)
Definition: db.cpp:67
bool DumpWallet(const ArgsManager &args, WalletDatabase &db, bilingual_str &error)
Definition: dump.cpp:24
@ FEATURE_LATEST
Definition: walletutil.h:30
@ WALLET_FLAG_DESCRIPTORS
Indicate that this wallet supports DescriptorScriptPubKeyMan.
Definition: walletutil.h:74
bool RecoverDatabaseFile(const ArgsManager &args, const fs::path &file_path, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: salvage.cpp:69
DatabaseStatus
Definition: db.h:204
std::shared_ptr< CWallet > wallet
const char * name
Definition: rest.cpp:48
Bilingual messages:
Definition: translation.h:18
bool empty() const
Definition: translation.h:29
std::string original
Definition: translation.h:19
bool require_existing
Definition: db.h:191
std::optional< DatabaseFormat > require_format
Definition: db.h:193
uint64_t create_flags
Definition: db.h:194
#define LOCK(cs)
Definition: sync.h:257