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-2020 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
23{
24 interfaces::Chain& chain = *context.chain;
25 ArgsManager& args = *Assert(context.args);
26
27 if (args.IsArgSet("-walletdir")) {
28 fs::path wallet_dir = fs::PathFromString(args.GetArg("-walletdir", ""));
29 boost::system::error_code error;
30 // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
31 fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
32 if (error || !fs::exists(wallet_dir)) {
33 chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
34 return false;
35 } else if (!fs::is_directory(wallet_dir)) {
36 chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
37 return false;
38 // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
39 } else if (!wallet_dir.is_absolute()) {
40 chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
41 return false;
42 }
43 args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
44 }
45
46 LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
47
48 chain.initMessage(_("Verifying wallet(s)…").translated);
49
50 // For backwards compatibility if an unnamed top level wallet exists in the
51 // wallets directory, include it in the default list of wallets to load.
52 if (!args.IsArgSet("wallet")) {
53 DatabaseOptions options;
54 DatabaseStatus status;
55 bilingual_str error_string;
56 options.require_existing = true;
57 options.verify = false;
58 if (MakeWalletDatabase("", options, status, error_string)) {
60 wallets.push_back(""); // Default wallet name is ""
61 // Pass write=false because no need to write file and probably
62 // better not to. If unnamed wallet needs to be added next startup
63 // and the setting is empty, this code will just run again.
64 chain.updateRwSetting("wallet", wallets, /* write= */ false);
65 }
66 }
67
68 // Keep track of each wallet absolute path to detect duplicates.
69 std::set<fs::path> wallet_paths;
70
71 for (const auto& wallet : chain.getSettingsList("wallet")) {
72 const auto& wallet_file = wallet.get_str();
74
75 if (!wallet_paths.insert(path).second) {
76 chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
77 continue;
78 }
79
80 DatabaseOptions options;
81 DatabaseStatus status;
82 options.require_existing = true;
83 options.verify = true;
84 bilingual_str error_string;
85 if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
87 chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
88 } else {
89 chain.initError(error_string);
90 return false;
91 }
92 }
93 }
94
95 return true;
96}
97
99{
100 interfaces::Chain& chain = *context.chain;
101 try {
102 std::set<fs::path> wallet_paths;
103 for (const auto& wallet : chain.getSettingsList("wallet")) {
104 const auto& name = wallet.get_str();
105 if (!wallet_paths.insert(fs::PathFromString(name)).second) {
106 continue;
107 }
108 DatabaseOptions options;
109 DatabaseStatus status;
110 options.require_existing = true;
111 options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
113 std::vector<bilingual_str> warnings;
114 std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
115 if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
116 continue;
117 }
118 chain.initMessage(_("Loading wallet…").translated);
119 std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings) : nullptr;
120 if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
121 if (!pwallet) {
122 chain.initError(error);
123 return false;
124 }
125 AddWallet(context, pwallet);
126 }
127 return true;
128 } catch (const std::runtime_error& e) {
129 chain.initError(Untranslated(e.what()));
130 return false;
131 }
132}
133
134void StartWallets(WalletContext& context, CScheduler& scheduler)
135{
136 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
137 pwallet->postInitProcess();
138 }
139
140 // Schedule periodic wallet flushes and tx rebroadcasts
141 if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
142 scheduler.scheduleEvery([&context] { MaybeCompactWalletDB(context); }, std::chrono::milliseconds{500});
143 }
144 scheduler.scheduleEvery([&context] { MaybeResendWalletTxs(context); }, std::chrono::milliseconds{1000});
145}
146
148{
149 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
150 pwallet->Flush();
151 }
152}
153
155{
156 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
157 pwallet->Close();
158 }
159}
160
162{
163 auto wallets = GetWallets(context);
164 while (!wallets.empty()) {
165 auto wallet = wallets.back();
166 wallets.pop_back();
167 std::vector<bilingual_str> warnings;
168 RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt, warnings);
169 UnloadWallet(std::move(wallet));
170 }
171}
#define Assert(val)
Identity function.
Definition: check.h:57
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition: system.cpp:624
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition: system.cpp:496
std::string GetArg(const std::string &strArg, const std::string &strDefault) const
Return string argument or default value.
Definition: system.cpp:590
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition: system.cpp:602
Simple class for background tasks that should be run periodically or once "after a while".
Definition: scheduler.h:34
void scheduleEvery(Function f, std::chrono::milliseconds delta)
Repeat f until the scheduler is stopped.
Definition: scheduler.cpp:112
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:2534
@ VARR
Definition: univalue.h:19
bool push_back(const UniValue &val)
Definition: univalue.cpp:108
Path class wrapper to prepare application code for transition from boost::filesystem library to std::...
Definition: fs.h:34
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition: chain.h:93
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.
DatabaseStatus
Definition: db.h:212
void FlushWallets(WalletContext &context)
Flush all wallets in preparation for shutdown.
Definition: load.cpp:147
void StopWallets(WalletContext &context)
Stop all wallets. Wallets will be flushed first.
Definition: load.cpp:154
void StartWallets(WalletContext &context, CScheduler &scheduler)
Complete startup of wallets.
Definition: load.cpp:134
bool LoadWallets(WalletContext &context)
Load wallet databases.
Definition: load.cpp:98
bool VerifyWallets(WalletContext &context)
Responsible for reading and validating the -wallet arguments and verifying the wallet database.
Definition: load.cpp:22
void UnloadWallets(WalletContext &context)
Close all wallets.
Definition: load.cpp:161
#define LogPrintf(...)
Definition: logging.h:187
static bool exists(const path &p)
Definition: fs.h:77
static std::string PathToString(const path &path)
Convert path object to byte string.
Definition: fs.h:120
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition: fs.h:133
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition: fs.cpp:35
const char * name
Definition: rest.cpp:43
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
bool verify
Definition: db.h:209
uint64_t create_flags
Definition: db.h:207
bool require_existing
Definition: db.h:204
WalletContext struct containing references to state shared between CWallet instances,...
Definition: context.h:34
ArgsManager * args
Definition: context.h:36
interfaces::Chain * chain
Definition: context.h:35
Bilingual messages:
Definition: translation.h:16
std::string original
Definition: translation.h:17
bool error(const char *fmt, const Args &... args)
Definition: system.h:49
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1164
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:63
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:46
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition: wallet.cpp:2510
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition: wallet.cpp:117
void UnloadWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly unload and delete the wallet.
Definition: wallet.cpp:189
void MaybeResendWalletTxs(WalletContext &context)
Called periodically by the schedule thread.
Definition: wallet.cpp:1809
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition: wallet.cpp:105
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition: wallet.cpp:143
void MaybeCompactWalletDB(WalletContext &context)
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
Definition: walletdb.cpp:1040
static const bool DEFAULT_FLUSHWALLET
Overview of wallet database classes:
Definition: walletdb.h:30
fs::path GetWalletDir()
Get the path of the wallet directory.
Definition: walletutil.cpp:10