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