LCOV - code coverage report
Current view: top level - src/wallet - load.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 15 119 12.6 %
Date: 2023-09-26 12:08:55 Functions: 8 17 47.1 %

          Line data    Source code
       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           2 : #include <wallet/wallet.h>
      18           2 : #include <wallet/walletdb.h>
      19             : 
      20             : #include <univalue.h>
      21             : 
      22             : #include <system_error>
      23             : 
      24             : namespace wallet {
      25           0 : bool VerifyWallets(WalletContext& context)
      26             : {
      27           2 :     interfaces::Chain& chain = *context.chain;
      28           0 :     ArgsManager& args = *Assert(context.args);
      29             : 
      30           0 :     if (args.IsArgSet("-walletdir")) {
      31           0 :         const fs::path wallet_dir{args.GetPathArg("-walletdir")};
      32           0 :         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           0 :         fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
      37           0 :         if (error || !fs::exists(canonical_wallet_dir)) {
      38           0 :             chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
      39           0 :             return false;
      40           0 :         } else if (!fs::is_directory(canonical_wallet_dir)) {
      41           0 :             chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
      42           0 :             return false;
      43             :         // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
      44           0 :         } else if (!wallet_dir.is_absolute()) {
      45           0 :             chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
      46           0 :             return false;
      47             :         }
      48           0 :         args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
      49           0 :     }
      50             : 
      51           0 :     LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
      52             : 
      53           0 :     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           0 :     if (!args.IsArgSet("wallet")) {
      58           0 :         DatabaseOptions options;
      59             :         DatabaseStatus status;
      60           0 :         ReadDatabaseArgs(args, options);
      61           0 :         bilingual_str error_string;
      62           0 :         options.require_existing = true;
      63           0 :         options.verify = false;
      64           0 :         if (MakeWalletDatabase("", options, status, error_string)) {
      65           0 :             common::SettingsValue wallets(common::SettingsValue::VARR);
      66           0 :             wallets.push_back(""); // Default wallet name is ""
      67             :             // Pass write=false because no need to write file and probably
      68             :             // better not to. If unnamed wallet needs to be added next startup
      69             :             // and the setting is empty, this code will just run again.
      70           0 :             chain.updateRwSetting("wallet", wallets, /* write= */ false);
      71           0 :         }
      72           0 :     }
      73             : 
      74           2 :     // Keep track of each wallet absolute path to detect duplicates.
      75           0 :     std::set<fs::path> wallet_paths;
      76             : 
      77           0 :     for (const auto& wallet : chain.getSettingsList("wallet")) {
      78           0 :         const auto& wallet_file = wallet.get_str();
      79           0 :         const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file));
      80             : 
      81           0 :         if (!wallet_paths.insert(path).second) {
      82           0 :             chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
      83           0 :             continue;
      84             :         }
      85             : 
      86           0 :         DatabaseOptions options;
      87             :         DatabaseStatus status;
      88           0 :         ReadDatabaseArgs(args, options);
      89           0 :         options.require_existing = true;
      90           0 :         options.verify = true;
      91           2 :         bilingual_str error_string;
      92           0 :         if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
      93           0 :             if (status == DatabaseStatus::FAILED_NOT_FOUND) {
      94           0 :                 chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
      95           0 :             } else {
      96           0 :                 chain.initError(error_string);
      97           0 :                 return false;
      98             :             }
      99           2 :         }
     100           0 :     }
     101             : 
     102           0 :     return true;
     103           0 : }
     104             : 
     105           0 : bool LoadWallets(WalletContext& context)
     106             : {
     107           0 :     interfaces::Chain& chain = *context.chain;
     108             :     try {
     109           0 :         std::set<fs::path> wallet_paths;
     110           0 :         for (const auto& wallet : chain.getSettingsList("wallet")) {
     111           0 :             const auto& name = wallet.get_str();
     112           0 :             if (!wallet_paths.insert(fs::PathFromString(name)).second) {
     113           0 :                 continue;
     114             :             }
     115           0 :             DatabaseOptions options;
     116             :             DatabaseStatus status;
     117           0 :             ReadDatabaseArgs(*context.args, options);
     118           0 :             options.require_existing = true;
     119           0 :             options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
     120           0 :             bilingual_str error;
     121           0 :             std::vector<bilingual_str> warnings;
     122           0 :             std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
     123           0 :             if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
     124           0 :                 continue;
     125             :             }
     126           0 :             chain.initMessage(_("Loading wallet…").translated);
     127           0 :             std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings) : nullptr;
     128           0 :             if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
     129           0 :             if (!pwallet) {
     130           0 :                 chain.initError(error);
     131           0 :                 return false;
     132             :             }
     133             : 
     134           0 :             NotifyWalletLoaded(context, pwallet);
     135           0 :             AddWallet(context, pwallet);
     136           0 :         }
     137           0 :         return true;
     138           0 :     } catch (const std::runtime_error& e) {
     139           0 :         chain.initError(Untranslated(e.what()));
     140           0 :         return false;
     141           0 :     }
     142           0 : }
     143             : 
     144           0 : void StartWallets(WalletContext& context, CScheduler& scheduler)
     145             : {
     146           0 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
     147           0 :         pwallet->postInitProcess();
     148             :     }
     149             : 
     150             :     // Schedule periodic wallet flushes and tx rebroadcasts
     151           0 :     if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
     152           0 :         scheduler.scheduleEvery([&context] { MaybeCompactWalletDB(context); }, std::chrono::milliseconds{500});
     153           0 :     }
     154           0 :     scheduler.scheduleEvery([&context] { MaybeResendWalletTxs(context); }, 1min);
     155           0 : }
     156             : 
     157           0 : void FlushWallets(WalletContext& context)
     158             : {
     159           0 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
     160           0 :         pwallet->Flush();
     161             :     }
     162           0 : }
     163           2 : 
     164           2 : void StopWallets(WalletContext& context)
     165           2 : {
     166           2 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
     167           2 :         pwallet->Close();
     168           2 :     }
     169           2 : }
     170           2 : 
     171           0 : void UnloadWallets(WalletContext& context)
     172             : {
     173           0 :     auto wallets = GetWallets(context);
     174           0 :     while (!wallets.empty()) {
     175           0 :         auto wallet = wallets.back();
     176           0 :         wallets.pop_back();
     177           0 :         std::vector<bilingual_str> warnings;
     178           0 :         RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt, warnings);
     179           0 :         UnloadWallet(std::move(wallet));
     180           0 :     }
     181           0 : }
     182             : } // namespace wallet

Generated by: LCOV version 1.14