Bitcoin Core 28.0.0
P2P Digital Currency
Loading...
Searching...
No Matches
load.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2022 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 <scheduler.h>
11#include <util/check.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
26namespace wallet {
28{
29 interfaces::Chain& chain = *context.chain;
30 ArgsManager& args = *Assert(context.args);
31
32 if (args.IsArgSet("-walletdir")) {
33 const fs::path wallet_dir{args.GetPathArg("-walletdir")};
34 std::error_code error;
35 // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory
36 // It also lets the fs::exists and fs::is_directory checks below pass on windows, since they return false
37 // if a path has trailing slashes, and it strips trailing slashes.
38 fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
39 if (error || !fs::exists(canonical_wallet_dir)) {
40 chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
41 return false;
42 } else if (!fs::is_directory(canonical_wallet_dir)) {
43 chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
44 return false;
45 // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
46 } else if (!wallet_dir.is_absolute()) {
47 chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
48 return false;
49 }
50 args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
51 }
52
53 LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
54
55 chain.initMessage(_("Verifying wallet(s)…").translated);
56
57 // For backwards compatibility if an unnamed top level wallet exists in the
58 // wallets directory, include it in the default list of wallets to load.
59 if (!args.IsArgSet("wallet")) {
60 DatabaseOptions options;
61 DatabaseStatus status;
62 ReadDatabaseArgs(args, options);
63 bilingual_str error_string;
64 options.require_existing = true;
65 options.verify = false;
66 if (MakeWalletDatabase("", options, status, error_string)) {
68 wallets.push_back(""); // Default wallet name is ""
69 // Pass write=false because no need to write file and probably
70 // better not to. If unnamed wallet needs to be added next startup
71 // and the setting is empty, this code will just run again.
72 chain.overwriteRwSetting("wallet", wallets, /*write=*/false);
73 }
74 }
75
76 // Keep track of each wallet absolute path to detect duplicates.
77 std::set<fs::path> wallet_paths;
78
79 for (const auto& wallet : chain.getSettingsList("wallet")) {
80 const auto& wallet_file = wallet.get_str();
82
83 if (!wallet_paths.insert(path).second) {
84 chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
85 continue;
86 }
87
88 DatabaseOptions options;
89 DatabaseStatus status;
90 ReadDatabaseArgs(args, options);
91 options.require_existing = true;
92 options.verify = true;
93 bilingual_str error_string;
94 if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
96 chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
97 } else {
98 chain.initError(error_string);
99 return false;
100 }
101 }
102 }
103
104 return true;
105}
106
108{
109 interfaces::Chain& chain = *context.chain;
110 try {
111 std::set<fs::path> wallet_paths;
112 for (const auto& wallet : chain.getSettingsList("wallet")) {
113 const auto& name = wallet.get_str();
114 if (!wallet_paths.insert(fs::PathFromString(name)).second) {
115 continue;
116 }
117 DatabaseOptions options;
118 DatabaseStatus status;
119 ReadDatabaseArgs(*context.args, options);
120 options.require_existing = true;
121 options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
122 bilingual_str error;
123 std::vector<bilingual_str> warnings;
124 std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
125 if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
126 continue;
127 }
128 chain.initMessage(_("Loading wallet…").translated);
129 std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings) : nullptr;
130 if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
131 if (!pwallet) {
132 chain.initError(error);
133 return false;
134 }
135
136 NotifyWalletLoaded(context, pwallet);
137 AddWallet(context, pwallet);
138 }
139 return true;
140 } catch (const std::runtime_error& e) {
141 chain.initError(Untranslated(e.what()));
142 return false;
143 }
144}
145
147{
148 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
149 pwallet->postInitProcess();
150 }
151
152 // Schedule periodic wallet flushes and tx rebroadcasts
153 if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
154 context.scheduler->scheduleEvery([&context] { MaybeCompactWalletDB(context); }, 500ms);
155 }
156 context.scheduler->scheduleEvery([&context] { MaybeResendWalletTxs(context); }, 1min);
157}
158
160{
161 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
162 pwallet->Flush();
163 }
164}
165
167{
168 for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
169 pwallet->Close();
170 }
171}
172
174{
175 auto wallets = GetWallets(context);
176 while (!wallets.empty()) {
177 auto wallet = wallets.back();
178 wallets.pop_back();
179 std::vector<bilingual_str> warnings;
180 RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt, warnings);
181 WaitForDeleteWallet(std::move(wallet));
182 }
183}
184} // namespace wallet
ArgsManager & args
Definition bitcoind.cpp:270
#define Assert(val)
Identity function.
Definition check.h:77
void ForceSetArg(const std::string &strArg, const std::string &strValue)
Definition args.cpp:545
bool IsArgSet(const std::string &strArg) const
Return true if the given argument has been manually set.
Definition args.cpp:370
bool GetBoolArg(const std::string &strArg, bool fDefault) const
Return boolean argument or default value.
Definition args.cpp:506
fs::path GetPathArg(std::string arg, const fs::path &default_value={}) const
Return path argument or default value.
Definition args.cpp:271
void scheduleEvery(Function f, std::chrono::milliseconds delta) EXCLUSIVE_LOCKS_REQUIRED(!newTaskMutex)
Repeat f until the scheduler is stopped.
void push_back(UniValue val)
Definition univalue.cpp:104
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition fs.h:33
Interface giving clients (wallet processes, maybe other analysis tools in the future) ability to acce...
Definition chain.h:135
virtual void initMessage(const std::string &message)=0
Send init message.
virtual std::vector< common::SettingsValue > getSettingsList(const std::string &arg)=0
Get list of settings values.
virtual void initError(const bilingual_str &message)=0
Send init error.
virtual void initWarning(const bilingual_str &message)=0
Send init warning.
virtual bool overwriteRwSetting(const std::string &name, common::SettingsValue &value, bool write=true)=0
Replace a setting in <datadir>/settings.json with a new value.
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:2972
#define LogPrintf(...)
Definition logging.h:274
static bool exists(const path &p)
Definition fs.h:89
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition fs.h:151
static path PathFromString(const std::string &string)
Convert byte string to path object.
Definition fs.h:174
fs::path AbsPathJoin(const fs::path &base, const fs::path &path)
Helper function for joining two paths.
Definition fs.cpp:36
auto Join(const C &container, const S &separator, UnaryOp unary_op)
Join all container items.
Definition string.h:115
void StartWallets(WalletContext &context)
Complete startup of wallets.
Definition load.cpp:146
void ReadDatabaseArgs(const ArgsManager &args, DatabaseOptions &options)
Definition db.cpp:153
void MaybeResendWalletTxs(WalletContext &context)
Called periodically by the schedule thread.
Definition wallet.cpp:2139
std::vector< std::shared_ptr< CWallet > > GetWallets(WalletContext &context)
Definition wallet.cpp:191
void MaybeCompactWalletDB(WalletContext &context)
Compacts BDB state so that wallet.dat is self-contained (if there are changes)
bool VerifyWallets(WalletContext &context)
Responsible for reading and validating the -wallet arguments and verifying the wallet database.
Definition load.cpp:27
fs::path GetWalletDir()
Get the path of the wallet directory.
std::unique_ptr< WalletDatabase > MakeWalletDatabase(const std::string &name, const DatabaseOptions &options, DatabaseStatus &status, bilingual_str &error_string)
Definition wallet.cpp:2961
void NotifyWalletLoaded(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition wallet.cpp:220
bool AddWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet)
Definition wallet.cpp:149
void UnloadWallets(WalletContext &context)
Close all wallets.
Definition load.cpp:173
bool LoadWallets(WalletContext &context)
Load wallet databases.
Definition load.cpp:107
static const bool DEFAULT_FLUSHWALLET
Overview of wallet database classes:
Definition walletdb.h:42
void FlushWallets(WalletContext &context)
Flush all wallets in preparation for shutdown.
Definition load.cpp:159
void StopWallets(WalletContext &context)
Stop all wallets. Wallets will be flushed first.
Definition load.cpp:166
void WaitForDeleteWallet(std::shared_ptr< CWallet > &&wallet)
Explicitly delete the wallet.
Definition wallet.cpp:252
DatabaseStatus
Definition db.h:204
bool RemoveWallet(WalletContext &context, const std::shared_ptr< CWallet > &wallet, std::optional< bool > load_on_start, std::vector< bilingual_str > &warnings)
Definition wallet.cpp:161
const char * name
Definition rest.cpp:49
Bilingual messages:
Definition translation.h:18
std::string original
Definition translation.h:19
bool verify
Check data integrity on load.
Definition db.h:198
uint64_t create_flags
Definition db.h:194
WalletContext struct containing references to state shared between CWallet instances,...
Definition context.h:36
interfaces::Chain * chain
Definition context.h:37
CScheduler * scheduler
Definition context.h:38
ArgsManager * args
Definition context.h:39
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
bilingual_str _(ConstevalStringLiteral str)
Translation function.
Definition translation.h:80
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition translation.h:48