Bitcoin Core  22.99.0
P2P Digital Currency
load.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <wallet/load.h>
7 
8 #include <fs.h>
9 #include <interfaces/chain.h>
10 #include <scheduler.h>
11 #include <util/check.h>
12 #include <util/string.h>
13 #include <util/system.h>
14 #include <util/translation.h>
15 #include <wallet/context.h>
16 #include <wallet/spend.h>
17 #include <wallet/wallet.h>
18 #include <wallet/walletdb.h>
19 
20 #include <univalue.h>
21 
22 #include <system_error>
23 
24 namespace wallet {
26 {
29 
30  if (args.IsArgSet("-walletdir")) {
31  const fs::path wallet_dir{args.GetPathArg("-walletdir")};
32  std::error_code error;
33  // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
34  // It also lets the fs::exists and fs::is_directory checks below pass on windows, since they return false
35  // if a path has trailing slashes, and it strips trailing slashes.
36  fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
37  if (error || !fs::exists(canonical_wallet_dir)) {
38  chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
39  return false;
40  } else if (!fs::is_directory(canonical_wallet_dir)) {
41  chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
42  return false;
43  // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
44  } else if (!wallet_dir.is_absolute()) {
45  chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
46  return false;
47  }
48  args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
49  }
50 
51  LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
52 
53  chain.initMessage(_("Verifying wallet(s)…").translated);
54 
55  // For backwards compatibility if an unnamed top level wallet exists in the
56  // wallets directory, include it in the default list of wallets to load.
57  if (!args.IsArgSet("wallet")) {
58  DatabaseOptions options;
59  DatabaseStatus status;
60  bilingual_str error_string;
61  options.require_existing = true;
62  options.verify = false;
63  if (MakeWalletDatabase("", options, status, error_string)) {
65  wallets.push_back(""); // Default wallet name is ""
66  // Pass write=false because no need to write file and probably
67  // better not to. If unnamed wallet needs to be added next startup
68  // and the setting is empty, this code will just run again.
69  chain.updateRwSetting("wallet", wallets, /* write= */ false);
70  }
71  }
72 
73  // Keep track of each wallet absolute path to detect duplicates.
74  std::set<fs::path> wallet_paths;
75 
76  for (const auto& wallet : chain.getSettingsList("wallet")) {
77  const auto& wallet_file = wallet.get_str();
78  const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file));
79 
80  if (!wallet_paths.insert(path).second) {
81  chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
82  continue;
83  }
84 
85  DatabaseOptions options;
86  DatabaseStatus status;
87  options.require_existing = true;
88  options.verify = true;
89  bilingual_str error_string;
90  if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
91  if (status == DatabaseStatus::FAILED_NOT_FOUND) {
92  chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
93  } else {
94  chain.initError(error_string);
95  return false;
96  }
97  }
98  }
99 
100  return true;
101 }
102 
104 {
105  interfaces::Chain& chain = *context.chain;
106  try {
107  std::set<fs::path> wallet_paths;
108  for (const auto& wallet : chain.getSettingsList("wallet")) {
109  const auto& name = wallet.get_str();
110  if (!wallet_paths.insert(fs::PathFromString(name)).second) {
111  continue;
112  }
113  DatabaseOptions options;
114  DatabaseStatus status;
115  options.require_existing = true;
116  options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
118  std::vector<bilingual_str> warnings;
119  std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
120  if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
121  continue;
122  }
123  chain.initMessage(_("Loading wallet…").translated);
124  std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings) : nullptr;
125  if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
126  if (!pwallet) {
127  chain.initError(error);
128  return false;
129  }
130  AddWallet(context, pwallet);
131  }
132  return true;
133  } catch (const std::runtime_error& e) {
134  chain.initError(Untranslated(e.what()));
135  return false;
136  }
137 }
138 
140 {
141  for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
142  pwallet->postInitProcess();
143  }
144 
145  // Schedule periodic wallet flushes and tx rebroadcasts
146  if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
147  scheduler.scheduleEvery([&context] { MaybeCompactWalletDB(context); }, std::chrono::milliseconds{500});
148  }
149  scheduler.scheduleEvery([&context] { MaybeResendWalletTxs(context); }, std::chrono::milliseconds{1000});
150 }
151 
153 {
154  for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
155  pwallet->Flush();
156  }
157 }
158 
160 {
161  for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
162  pwallet->Close();
163  }
164 }
165 
167 {
168  auto wallets = GetWallets(context);
169  while (!wallets.empty()) {
170  auto wallet = wallets.back();
171  wallets.pop_back();
172  std::vector<bilingual_str> warnings;
173  RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt, warnings);
174  UnloadWallet(std::move(wallet));
175  }
176 }
177 } // namespace wallet
wallet::StartWallets
void StartWallets(WalletContext &context, CScheduler &scheduler)
Complete startup of wallets.
Definition: load.cpp:139
CScheduler
Simple class for background tasks that should be run periodically or once "after a while".
Definition: scheduler.h:33
ArgsManager::GetBoolArg
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:600
fs::exists
static bool exists(const path &p)
Definition: fs.h:69
_
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:63
check.h
wallet.h
wallet::AddWallet
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:110
wallet::UnloadWallets
void UnloadWallets(WalletContext &context)
Close all wallets.
Definition: load.cpp:166
fs.h
wallet::DatabaseStatus
DatabaseStatus
Definition: db.h:213
ArgsManager::GetPathArg
fs::path GetPathArg(std::string pathlike_arg) const
Get a normalized path from a specified pathlike argument.
Definition: system.cpp:390
string.h
bilingual_str
Bilingual messages:
Definition: translation.h:16
ArgsManager::IsArgSet
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:494
wallet::MaybeResendWalletTxs
void MaybeResendWalletTxs(WalletContext &context)
Called periodically by the schedule thread.
Definition: wallet.cpp:1903
interfaces::Chain::getSettingsList
virtual std::vector< util::SettingsValue > getSettingsList(const std::string &arg)=0
Get list of settings values.
fsbridge::AbsPathJoin
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:37
wallet
Definition: node.h:38
fs::PathToString
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:112
wallet::DatabaseOptions::require_existing
bool require_existing
Definition: db.h:205
chain.h
Assert
#define Assert(val)
Identity function.
Definition: check.h:57
scheduler.h
UniValue
Definition: univalue.h:17
wallet::FlushWallets
void FlushWallets(WalletContext &context)
Flush all wallets in preparation for shutdown.
Definition: load.cpp:152
wallet::GetWallets
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:148
load.h
interfaces::Chain
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:94
wallet::WalletContext::args
ArgsManager * args
Definition: context.h:37
Untranslated
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:46
wallet::MakeWalletDatabase
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition: wallet.cpp:2644
fs::path
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:29
wallet::DatabaseOptions::verify
bool verify
Definition: db.h:210
univalue.h
wallet::LoadWallets
bool LoadWallets(WalletContext &context)
Load wallet databases.
Definition: load.cpp:103
ArgsManager::ForceSetArg
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:622
LogPrintf
#define LogPrintf(...)
Definition: logging.h:188
context
WalletContext context
Definition: notifications.cpp:37
CScheduler::scheduleEvery
void scheduleEvery(Function f, std::chrono::milliseconds delta)
Repeat f until the scheduler is stopped.
Definition: scheduler.cpp:112
fs::PathFromString
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:135
interfaces::Chain::updateRwSetting
virtual bool updateRwSetting(const std::string &name, const util::SettingsValue &value, bool write=true)=0
Write a setting to <datadir>/settings.json.
wallet::DatabaseStatus::FAILED_NOT_FOUND
@ FAILED_NOT_FOUND
bilingual_str::original
std::string original
Definition: translation.h:17
name
const char * name
Definition: rest.cpp:52
interfaces::Chain::initWarning
virtual void initWarning(const bilingual_str &message)=0
Send init warning.
wallet::VerifyWallets
bool VerifyWallets(WalletContext &context)
Responsible for reading and validating the -wallet arguments and verifying the wallet database.
Definition: load.cpp:25
system.h
strprintf
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
Join
auto Join(const std::vector< T > &list, const BaseType &separator, UnaryOp unary_op) -> decltype(unary_op(list.at(0)))
Join a list of items.
Definition: string.h:44
wallet::DEFAULT_FLUSHWALLET
static const bool DEFAULT_FLUSHWALLET
Overview of wallet database classes:
Definition: walletdb.h:42
ArgsManager
Definition: system.h:164
translation.h
wallet::GetWalletDir
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:11
interfaces::Chain::initMessage
virtual void initMessage(const std::string &message)=0
Send init message.
wallet::CWallet::Create
static std::shared_ptr< CWallet > Create(WalletContext &context, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bilingual_str &error, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:2668
UniValue::push_back
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
context.h
walletdb.h
interfaces::Chain::initError
virtual void initError(const bilingual_str &message)=0
Send init error.
wallet::WalletContext
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:35
wallet::UnloadWallet
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:194
error
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
UniValue::VARR
@ VARR
Definition: univalue.h:19
wallet::MaybeCompactWalletDB
void MaybeCompactWalletDB(WalletContext &context)
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:1041
wallet::WalletContext::chain
interfaces::Chain * chain
Definition: context.h:36
wallet::DatabaseOptions
Definition: db.h:204
wallet::RemoveWallet
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:122
wallet::StopWallets
void StopWallets(WalletContext &context)
Stop all wallets. Wallets will be flushed first.
Definition: load.cpp:159
wallet::DatabaseOptions::create_flags
uint64_t create_flags
Definition: db.h:208
spend.h
args
ArgsManager args
Definition: notifications.cpp:36