LCOV - code coverage report
Current view: top level - src/wallet - load.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 11 119 9.2 %
Date: 2024-01-03 14:57:27 Functions: 0 13 0.0 %
Branches: 8 257 3.1 %

           Branch data     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                 :            : #include <wallet/wallet.h>
      18                 :            : #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                 :            :     // 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                 :          0 :         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                 :          2 :             }
      99                 :          0 :         }
     100      [ #  #  # ]:          0 :     }
     101                 :            : 
     102                 :          0 :     return true;
     103                 :          0 : }
     104                 :            : 
     105                 :          0 : bool LoadWallets(WalletContext& context)
     106                 :          2 : {
     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)
     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 :         context.scheduler->scheduleEvery([&context] { MaybeCompactWalletDB(context); }, 500ms);
     153                 :          0 :     }
     154 [ #  # ][ #  # ]:          0 :     context.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