Bitcoin ABC  0.26.3
P2P Digital Currency
load.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2018 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 <interfaces/chain.h>
9 #include <scheduler.h>
10 #include <util/fs.h>
11 #include <util/string.h>
12 #include <util/system.h>
13 #include <util/translation.h>
14 #include <wallet/spend.h>
15 #include <wallet/wallet.h>
16 #include <wallet/walletdb.h>
17 
18 #include <univalue.h>
19 
20 #include <system_error>
21 
23  if (gArgs.IsArgSet("-walletdir")) {
24  const fs::path wallet_dir{gArgs.GetPathArg("-walletdir")};
25  std::error_code error;
26  // The canonical path cleans the path, preventing >1 Berkeley
27  // environment instances for the same directory
28  fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
29  if (error || !fs::exists(canonical_wallet_dir)) {
30  chain.initError(
31  strprintf(_("Specified -walletdir \"%s\" does not exist"),
32  fs::PathToString(wallet_dir)));
33  return false;
34  } else if (!fs::is_directory(canonical_wallet_dir)) {
35  chain.initError(
36  strprintf(_("Specified -walletdir \"%s\" is not a directory"),
37  fs::PathToString(wallet_dir)));
38  return false;
39  // The canonical path transforms relative paths into absolute ones,
40  // so we check the non-canonical version
41  } else if (!wallet_dir.is_absolute()) {
42  chain.initError(
43  strprintf(_("Specified -walletdir \"%s\" is a relative path"),
44  fs::PathToString(wallet_dir)));
45  return false;
46  }
47  gArgs.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
48  }
49 
50  LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
51 
52  chain.initMessage(_("Verifying wallet(s)...").translated);
53 
54  // For backwards compatibility if an unnamed top level wallet exists in the
55  // wallets directory, include it in the default list of wallets to load.
56  if (!gArgs.IsArgSet("wallet")) {
57  DatabaseOptions options;
58  DatabaseStatus status;
59  bilingual_str error_string;
60  options.require_existing = true;
61  options.verify = false;
62  if (MakeWalletDatabase("", options, status, error_string)) {
64  wallets.push_back(""); // Default wallet name is ""
65  // Pass write=false because no need to write file and probably
66  // better not to. If unnamed wallet needs to be added next startup
67  // and the setting is empty, this code will just run again.
68  chain.updateRwSetting("wallet", wallets, /* write= */ false);
69  }
70  }
71 
72  // Keep track of each wallet absolute path to detect duplicates.
73  std::set<fs::path> wallet_paths;
74 
75  for (const auto &wallet : chain.getSettingsList("wallet")) {
76  const auto &wallet_file = wallet.get_str();
77  const fs::path path = fsbridge::AbsPathJoin(
78  GetWalletDir(), fs::PathFromString(wallet_file));
79 
80  if (!wallet_paths.insert(path).second) {
81  chain.initWarning(
82  strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
83  continue;
84  }
85 
86  DatabaseOptions options;
87  DatabaseStatus status;
88  options.require_existing = true;
89  options.verify = true;
90  bilingual_str error_string;
91  if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
92  if (status == DatabaseStatus::FAILED_NOT_FOUND) {
94  strprintf("Skipping -wallet path that doesn't exist. %s\n",
95  error_string.original)));
96  } else {
97  chain.initError(error_string);
98  return false;
99  }
100  }
101  }
102 
103  return true;
104 }
105 
107  try {
108  std::set<fs::path> wallet_paths;
109  for (const auto &wallet : chain.getSettingsList("wallet")) {
110  const auto &name = wallet.get_str();
111  if (!wallet_paths.insert(fs::PathFromString(name)).second) {
112  continue;
113  }
114  DatabaseOptions options;
115  DatabaseStatus status;
116  options.require_existing = true;
117  // No need to verify, assuming verified earlier in VerifyWallets()
118  options.verify = false;
120  std::vector<bilingual_str> warnings;
121  std::unique_ptr<WalletDatabase> database =
122  MakeWalletDatabase(name, options, status, error);
123  if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
124  continue;
125  }
126  std::shared_ptr<CWallet> pwallet =
127  database
128  ? CWallet::Create(chain, name, std::move(database),
129  options.create_flags, error, warnings)
130  : nullptr;
131 
132  if (!warnings.empty()) {
133  chain.initWarning(Join(warnings, Untranslated("\n")));
134  }
135  if (!pwallet) {
136  chain.initError(error);
137  return false;
138  }
139  AddWallet(pwallet);
140  }
141  return true;
142  } catch (const std::runtime_error &e) {
143  chain.initError(Untranslated(e.what()));
144  return false;
145  }
146 }
147 
148 void StartWallets(CScheduler &scheduler, const ArgsManager &args) {
149  for (const std::shared_ptr<CWallet> &pwallet : GetWallets()) {
150  pwallet->postInitProcess();
151  }
152 
153  // Schedule periodic wallet flushes and tx rebroadcasts
154  if (args.GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
155  scheduler.scheduleEvery(
156  [] {
158  return true;
159  },
160  std::chrono::milliseconds{500});
161  }
162  scheduler.scheduleEvery(
163  [] {
165  return true;
166  },
167  std::chrono::milliseconds{1000});
168 }
169 
170 void FlushWallets() {
171  for (const std::shared_ptr<CWallet> &pwallet : GetWallets()) {
172  pwallet->Flush();
173  }
174 }
175 
176 void StopWallets() {
177  for (const std::shared_ptr<CWallet> &pwallet : GetWallets()) {
178  pwallet->Close();
179  }
180 }
181 
183  auto wallets = GetWallets();
184  while (!wallets.empty()) {
185  auto wallet = wallets.back();
186  wallets.pop_back();
187  std::vector<bilingual_str> warnings;
188  RemoveWallet(wallet, std::nullopt, warnings);
189  UnloadWallet(std::move(wallet));
190  }
191 }
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:617
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:401
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:576
fs::path GetPathArg(std::string arg, const fs::path &default_value={}) const
Return path argument or default value.
Definition: system.cpp:307
Simple class for background tasks that should be run periodically or once "after a while".
Definition: scheduler.h:41
void scheduleEvery(Predicate p, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat p until it return false.
Definition: scheduler.cpp:114
static std::shared_ptr< CWallet > Create(interfaces::Chain &chain, const std::string &name, std::unique_ptr< WalletDatabase > database, uint64_t wallet_creation_flags, bilingual_str &error, std::vector< bilingual_str > &warnings)
Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error.
Definition: wallet.cpp:2706
@ VARR
Definition: univalue.h:27
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:123
virtual bool updateRwSetting(const std::string &name, const util::SettingsValue &value, bool write=true)=0
Write a setting to <datadir>/settings.json.
virtual void initMessage(const std::string &message)=0
Send init message.
virtual void initError(const bilingual_str &message)=0
Send init error.
virtual void initWarning(const bilingual_str &message)=0
Send init warning.
virtual std::vector< util::SettingsValue > getSettingsList(const std::string &arg)=0
Get list of settings values.
void StartWallets(CScheduler &scheduler, const ArgsManager &args)
Complete startup of wallets.
Definition: load.cpp:148
bool VerifyWallets(interfaces::Chain &chain)
Responsible for reading and validating the -wallet arguments and verifying the wallet database.
Definition: load.cpp:22
void UnloadWallets()
Close all wallets.
Definition: load.cpp:182
void FlushWallets()
Flush all wallets in preparation for shutdown.
Definition: load.cpp:170
void StopWallets()
Stop all wallets. Wallets will be flushed first.
Definition: load.cpp:176
bool LoadWallets(interfaces::Chain &chain)
Load wallet databases.
Definition: load.cpp:106
bool error(const char *fmt, const Args &...args)
Definition: logging.h:225
#define LogPrintf(...)
Definition: logging.h:206
static bool exists(const path &p)
Definition: fs.h:102
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:142
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:165
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:37
const char * name
Definition: rest.cpp:47
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:54
bool verify
Definition: db.h:226
uint64_t create_flags
Definition: db.h:224
bool require_existing
Definition: db.h:222
Bilingual messages:
Definition: translation.h:17
std::string original
Definition: translation.h:18
ArgsManager gArgs
Definition: system.cpp:68
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:36
DatabaseStatus
Definition: db.h:229
bool RemoveWallet(const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:120
void MaybeResendWalletTxs()
Called periodically by the schedule thread.
Definition: wallet.cpp:1990
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:201
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition: wallet.cpp:2674
std::vector< std::shared_ptr< CWallet > > GetWallets()
Definition: wallet.cpp:150
bool AddWallet(const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:106
void MaybeCompactWalletDB()
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:1050
static const bool DEFAULT_FLUSHWALLET
Overview of wallet database classes:
Definition: walletdb.h:33
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:13