Bitcoin ABC 0.32.12
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 <common/args.h>
9#include <interfaces/chain.h>
10#include <logging.h>
11#include <scheduler.h>
12#include <util/fs.h>
13#include <util/string.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
24using util::Join;
25
27 interfaces::Chain &chain = *context.chain;
28 if (gArgs.IsArgSet("-walletdir")) {
29 const fs::path wallet_dir{gArgs.GetPathArg("-walletdir")};
30 std::error_code error;
31 // The canonical path cleans the path, preventing >1 Berkeley
32 // environment instances for the same directory
33 fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
34 if (error || !fs::exists(canonical_wallet_dir)) {
35 chain.initError(
36 strprintf(_("Specified -walletdir \"%s\" does not exist"),
37 fs::PathToString(wallet_dir)));
38 return false;
39 } else if (!fs::is_directory(canonical_wallet_dir)) {
40 chain.initError(
41 strprintf(_("Specified -walletdir \"%s\" is not a directory"),
42 fs::PathToString(wallet_dir)));
43 return false;
44 // The canonical path transforms relative paths into absolute ones,
45 // so we check the non-canonical version
46 } else if (!wallet_dir.is_absolute()) {
47 chain.initError(
48 strprintf(_("Specified -walletdir \"%s\" is a relative path"),
49 fs::PathToString(wallet_dir)));
50 return false;
51 }
52 gArgs.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
53 }
54
55 LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
56
57 chain.initMessage(_("Verifying wallet(s)...").translated);
58
59 // For backwards compatibility if an unnamed top level wallet exists in the
60 // wallets directory, include it in the default list of wallets to load.
61 if (!gArgs.IsArgSet("wallet")) {
62 DatabaseOptions options;
63 DatabaseStatus status;
64 bilingual_str error_string;
65 options.require_existing = true;
66 options.verify = false;
67 if (MakeWalletDatabase("", options, status, error_string)) {
69 wallets.push_back(""); // Default wallet name is ""
70 // Pass write=false because no need to write file and probably
71 // better not to. If unnamed wallet needs to be added next startup
72 // and the setting is empty, this code will just run again.
73 chain.updateRwSetting("wallet", wallets, /* write= */ false);
74 }
75 }
76
77 // Keep track of each wallet absolute path to detect duplicates.
78 std::set<fs::path> wallet_paths;
79
80 for (const auto &wallet : chain.getSettingsList("wallet")) {
81 const auto &wallet_file = wallet.get_str();
83 GetWalletDir(), fs::PathFromString(wallet_file));
84
85 if (!wallet_paths.insert(path).second) {
86 chain.initWarning(
87 strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
88 continue;
89 }
90
91 DatabaseOptions options;
92 DatabaseStatus status;
93 options.require_existing = true;
94 options.verify = true;
95 bilingual_str error_string;
96 if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
99 strprintf("Skipping -wallet path that doesn't exist. %s\n",
100 error_string.original)));
101 } else {
102 chain.initError(error_string);
103 return false;
104 }
105 }
106 }
107
108 return true;
109}
110
112 interfaces::Chain &chain = *context.chain;
113 try {
114 std::set<fs::path> wallet_paths;
115 for (const auto &wallet : chain.getSettingsList("wallet")) {
116 const auto &name = wallet.get_str();
117 if (!wallet_paths.insert(fs::PathFromString(name)).second) {
118 continue;
119 }
120 DatabaseOptions options;
121 DatabaseStatus status;
122 options.require_existing = true;
123 // No need to verify, assuming verified earlier in VerifyWallets()
124 options.verify = false;
125 bilingual_str error;
126 std::vector<bilingual_str> warnings;
127 std::unique_ptr<WalletDatabase> database =
128 MakeWalletDatabase(name, options, status, error);
129 if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
130 continue;
131 }
132 chain.initMessage(_("Loading wallet...").translated);
133 std::shared_ptr<CWallet> pwallet =
134 database
135 ? CWallet::Create(context, name, std::move(database),
136 options.create_flags, error, warnings)
137 : nullptr;
138
139 if (!warnings.empty()) {
140 chain.initWarning(Join(warnings, Untranslated("\n")));
141 }
142 if (!pwallet) {
143 chain.initError(error);
144 return false;
145 }
146
147 NotifyWalletLoaded(context, pwallet);
148 AddWallet(context, pwallet);
149 }
150 return true;
151 } catch (const std::runtime_error &e) {
152 chain.initError(Untranslated(e.what()));
153 return false;
154 }
155}
156
157void StartWallets(WalletContext &context, CScheduler &scheduler) {
158 for (const std::shared_ptr<CWallet> &pwallet : GetWallets(context)) {
159 pwallet->postInitProcess();
160 }
161
162 // Schedule periodic wallet flushes and tx rebroadcasts
163 if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
164 scheduler.scheduleEvery(
165 [&context] {
166 MaybeCompactWalletDB(context);
167 return true;
168 },
169 std::chrono::milliseconds{500});
170 }
171 scheduler.scheduleEvery(
172 [&context] {
173 MaybeResendWalletTxs(context);
174 return true;
175 },
176 std::chrono::milliseconds{1000});
177}
178
180 for (const std::shared_ptr<CWallet> &pwallet : GetWallets(context)) {
181 pwallet->Flush();
182 }
183}
184
186 for (const std::shared_ptr<CWallet> &pwallet : GetWallets(context)) {
187 pwallet->Close();
188 }
189}
190
192 auto wallets = GetWallets(context);
193 while (!wallets.empty()) {
194 auto wallet = wallets.back();
195 wallets.pop_back();
196 std::vector<bilingual_str> warnings;
197 RemoveWallet(context, wallet, /*load_on_start=*/std::nullopt, warnings);
198 UnloadWallet(std::move(wallet));
199 }
200}
ArgsManager gArgs
Definition: args.cpp:39
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: args.cpp:565
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: args.cpp:371
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: args.cpp:524
fs::path GetPathArg(std::string arg, const fs::path &default_value={}) const
Return path argument or default value.
Definition: args.cpp:285
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(WalletContext &context, 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:2775
void push_back(UniValue val)
Definition: univalue.cpp:96
@ VARR
Definition: univalue.h:32
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:136
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 std::vector< util::SettingsValue > getSettingsList(const std::string &arg)=0
Get list of settings values.
virtual void initWarning(const bilingual_str &message)=0
Send init warning.
void FlushWallets(WalletContext &context)
Flush all wallets in preparation for shutdown.
Definition: load.cpp:179
void StopWallets(WalletContext &context)
Stop all wallets. Wallets will be flushed first.
Definition: load.cpp:185
void StartWallets(WalletContext &context, CScheduler &scheduler)
Complete startup of wallets.
Definition: load.cpp:157
bool LoadWallets(WalletContext &context)
Load wallet databases.
Definition: load.cpp:111
bool VerifyWallets(WalletContext &context)
Responsible for reading and validating the -wallet arguments and verifying.
Definition: load.cpp:26
void UnloadWallets(WalletContext &context)
Close all wallets.
Definition: load.cpp:191
#define LogPrintf(...)
Definition: logging.h:424
static bool exists(const path &p)
Definition: fs.h:107
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:147
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:170
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:39
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:105
const char * name
Definition: rest.cpp:47
bool verify
Definition: db.h:224
uint64_t create_flags
Definition: db.h:222
bool require_existing
Definition: db.h:220
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:35
ArgsManager * args
Definition: context.h:38
interfaces::Chain * chain
Definition: context.h:36
Bilingual messages:
Definition: translation.h:17
std::string original
Definition: translation.h:18
#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:227
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition: wallet.cpp:2743
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:124
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:216
void MaybeResendWalletTxs(WalletContext &context)
Called periodically by the schedule thread.
Definition: wallet.cpp:2069
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:110
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:156
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:183
void MaybeCompactWalletDB(WalletContext &context)
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:1048
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