LCOV - code coverage report
Current view: top level - src/wallet - load.cpp (source / functions) Coverage Total Hit
Test: total_coverage.info Lines: 92.5 % 120 111
Test Date: 2024-11-04 05:10:19 Functions: 100.0 % 6 6
Branches: 50.0 % 234 117

             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                 :             : using util::Join;
      25                 :             : 
      26                 :             : namespace wallet {
      27                 :         383 : bool VerifyWallets(WalletContext& context)
      28                 :             : {
      29                 :         383 :     interfaces::Chain& chain = *context.chain;
      30                 :         383 :     ArgsManager& args = *Assert(context.args);
      31                 :             : 
      32   [ +  -  +  + ]:         383 :     if (args.IsArgSet("-walletdir")) {
      33   [ +  -  +  - ]:          48 :         const fs::path wallet_dir{args.GetPathArg("-walletdir")};
      34         [ +  - ]:          24 :         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         [ +  - ]:          48 :         fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error);
      39   [ +  +  -  + ]:          43 :         if (error || !fs::exists(canonical_wallet_dir)) {
      40   [ +  -  +  -  :          20 :             chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist"), fs::PathToString(wallet_dir)));
             +  -  +  - ]
      41                 :           5 :             return false;
      42   [ +  -  +  + ]:          19 :         } else if (!fs::is_directory(canonical_wallet_dir)) {
      43   [ +  -  +  -  :          20 :             chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory"), fs::PathToString(wallet_dir)));
             +  -  +  - ]
      44                 :           5 :             return false;
      45                 :             :         // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version
      46         [ +  + ]:          14 :         } else if (!wallet_dir.is_absolute()) {
      47   [ +  -  +  -  :          12 :             chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path"), fs::PathToString(wallet_dir)));
             +  -  +  - ]
      48                 :           3 :             return false;
      49                 :             :         }
      50   [ +  -  +  -  :          33 :         args.ForceSetArg("-walletdir", fs::PathToString(canonical_wallet_dir));
                   +  - ]
      51                 :          48 :     }
      52                 :             : 
      53   [ +  -  +  - ]:        1110 :     LogPrintf("Using wallet directory %s\n", fs::PathToString(GetWalletDir()));
      54                 :             : 
      55         [ +  - ]:         370 :     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   [ +  -  +  + ]:         370 :     if (!args.IsArgSet("wallet")) {
      60         [ +  - ]:         261 :         DatabaseOptions options;
      61                 :         261 :         DatabaseStatus status;
      62         [ +  - ]:         261 :         ReadDatabaseArgs(args, options);
      63         [ +  - ]:         261 :         bilingual_str error_string;
      64                 :         261 :         options.require_existing = true;
      65                 :         261 :         options.verify = false;
      66   [ +  -  +  -  :         261 :         if (MakeWalletDatabase("", options, status, error_string)) {
                   +  + ]
      67                 :           1 :             common::SettingsValue wallets(common::SettingsValue::VARR);
      68   [ +  -  +  - ]:           1 :             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   [ +  -  +  - ]:           2 :             chain.overwriteRwSetting("wallet", std::move(wallets), interfaces::SettingsAction::SKIP_WRITE);
      73                 :           1 :         }
      74                 :         261 :     }
      75                 :             : 
      76                 :             :     // Keep track of each wallet absolute path to detect duplicates.
      77         [ +  - ]:         370 :     std::set<fs::path> wallet_paths;
      78                 :             : 
      79   [ +  -  +  -  :         458 :     for (const auto& wallet : chain.getSettingsList("wallet")) {
                   +  + ]
      80         [ +  + ]:         101 :         if (!wallet.isStr()) {
      81   [ +  -  +  - ]:           8 :             chain.initError(_("Invalid value detected for '-wallet' or '-nowallet'. "
      82                 :             :                               "'-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets"));
      83                 :           8 :             return false;
      84                 :             :         }
      85         [ +  - ]:          93 :         const auto& wallet_file = wallet.get_str();
      86   [ +  -  +  -  :         186 :         const fs::path path = fsbridge::AbsPathJoin(GetWalletDir(), fs::PathFromString(wallet_file));
                   +  - ]
      87                 :             : 
      88   [ +  -  +  + ]:          93 :         if (!wallet_paths.insert(path).second) {
      89   [ +  -  +  -  :           4 :             chain.initWarning(strprintf(_("Ignoring duplicate -wallet %s."), wallet_file));
                   +  - ]
      90                 :           2 :             continue;
      91                 :             :         }
      92                 :             : 
      93         [ +  - ]:          91 :         DatabaseOptions options;
      94                 :          91 :         DatabaseStatus status;
      95         [ +  - ]:          91 :         ReadDatabaseArgs(args, options);
      96                 :          91 :         options.require_existing = true;
      97                 :          91 :         options.verify = true;
      98         [ +  - ]:          91 :         bilingual_str error_string;
      99   [ +  -  +  + ]:          91 :         if (!MakeWalletDatabase(wallet_file, options, status, error_string)) {
     100         [ -  + ]:           5 :             if (status == DatabaseStatus::FAILED_NOT_FOUND) {
     101   [ #  #  #  #  :           0 :                 chain.initWarning(Untranslated(strprintf("Skipping -wallet path that doesn't exist. %s", error_string.original)));
                   #  # ]
     102                 :             :             } else {
     103         [ +  - ]:           5 :                 chain.initError(error_string);
     104                 :           5 :                 return false;
     105                 :             :             }
     106                 :             :         }
     107                 :         192 :     }
     108                 :             : 
     109                 :         357 :     return true;
     110                 :         370 : }
     111                 :             : 
     112                 :         332 : bool LoadWallets(WalletContext& context)
     113                 :             : {
     114                 :         332 :     interfaces::Chain& chain = *context.chain;
     115                 :         332 :     try {
     116         [ +  - ]:         332 :         std::set<fs::path> wallet_paths;
     117   [ +  -  +  -  :         418 :         for (const auto& wallet : chain.getSettingsList("wallet")) {
                   +  + ]
     118         [ -  + ]:          86 :             if (!wallet.isStr()) {
     119   [ #  #  #  # ]:           0 :                 chain.initError(_("Invalid value detected for '-wallet' or '-nowallet'. "
     120                 :             :                                   "'-wallet' requires a string value, while '-nowallet' accepts only '1' to disable all wallets"));
     121                 :           0 :                 return false;
     122                 :             :             }
     123         [ +  - ]:          86 :             const auto& name = wallet.get_str();
     124   [ +  -  +  -  :         172 :             if (!wallet_paths.insert(fs::PathFromString(name)).second) {
                   +  + ]
     125                 :           2 :                 continue;
     126                 :             :             }
     127         [ +  - ]:          84 :             DatabaseOptions options;
     128                 :          84 :             DatabaseStatus status;
     129         [ +  - ]:          84 :             ReadDatabaseArgs(*context.args, options);
     130                 :          84 :             options.require_existing = true;
     131                 :          84 :             options.verify = false; // No need to verify, assuming verified earlier in VerifyWallets()
     132         [ +  - ]:          84 :             bilingual_str error;
     133                 :          84 :             std::vector<bilingual_str> warnings;
     134         [ +  - ]:          84 :             std::unique_ptr<WalletDatabase> database = MakeWalletDatabase(name, options, status, error);
     135   [ -  +  -  - ]:          84 :             if (!database && status == DatabaseStatus::FAILED_NOT_FOUND) {
     136                 :           0 :                 continue;
     137                 :             :             }
     138   [ +  -  +  - ]:          84 :             chain.initMessage(_("Loading wallet…").translated);
     139   [ +  -  +  - ]:          84 :             std::shared_ptr<CWallet> pwallet = database ? CWallet::Create(context, name, std::move(database), options.create_flags, error, warnings) : nullptr;
     140   [ -  +  -  -  :          84 :             if (!warnings.empty()) chain.initWarning(Join(warnings, Untranslated("\n")));
          -  -  -  -  -  
                      - ]
     141         [ -  + ]:          84 :             if (!pwallet) {
     142         [ #  # ]:           0 :                 chain.initError(error);
     143         [ #  # ]:           0 :                 return false;
     144                 :             :             }
     145                 :             : 
     146         [ +  - ]:          84 :             NotifyWalletLoaded(context, pwallet);
     147         [ +  - ]:          84 :             AddWallet(context, pwallet);
     148                 :         168 :         }
     149                 :         332 :         return true;
     150         [ -  - ]:         332 :     } catch (const std::runtime_error& e) {
     151   [ -  -  -  -  :           0 :         chain.initError(Untranslated(e.what()));
                   -  - ]
     152                 :           0 :         return false;
     153                 :           0 :     }
     154                 :             : }
     155                 :             : 
     156                 :         332 : void StartWallets(WalletContext& context)
     157                 :             : {
     158         [ +  + ]:         416 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
     159         [ +  - ]:          84 :         pwallet->postInitProcess();
     160                 :         332 :     }
     161                 :             : 
     162                 :             :     // Schedule periodic wallet flushes and tx rebroadcasts
     163   [ +  -  +  - ]:         332 :     if (context.args->GetBoolArg("-flushwallet", DEFAULT_FLUSHWALLET)) {
     164         [ +  - ]:       14334 :         context.scheduler->scheduleEvery([&context] { MaybeCompactWalletDB(context); }, 500ms);
     165                 :             :     }
     166         [ +  - ]:         424 :     context.scheduler->scheduleEvery([&context] { MaybeResendWalletTxs(context); }, 1min);
     167                 :         332 : }
     168                 :             : 
     169                 :         376 : void FlushWallets(WalletContext& context)
     170                 :             : {
     171         [ +  + ]:         822 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
     172         [ +  - ]:         446 :         pwallet->Flush();
     173                 :         376 :     }
     174                 :         376 : }
     175                 :             : 
     176                 :         376 : void StopWallets(WalletContext& context)
     177                 :             : {
     178         [ +  + ]:         822 :     for (const std::shared_ptr<CWallet>& pwallet : GetWallets(context)) {
     179         [ +  - ]:         446 :         pwallet->Close();
     180                 :         376 :     }
     181                 :         376 : }
     182                 :             : 
     183                 :         401 : void UnloadWallets(WalletContext& context)
     184                 :             : {
     185                 :         401 :     auto wallets = GetWallets(context);
     186         [ +  + ]:        1248 :     while (!wallets.empty()) {
     187         [ +  - ]:         446 :         auto wallet = wallets.back();
     188                 :         446 :         wallets.pop_back();
     189                 :         446 :         std::vector<bilingual_str> warnings;
     190         [ +  - ]:         446 :         RemoveWallet(context, wallet, /* load_on_start= */ std::nullopt, warnings);
     191         [ +  - ]:         446 :         WaitForDeleteWallet(std::move(wallet));
     192         [ -  + ]:         446 :     }
     193                 :         401 : }
     194                 :             : } // namespace wallet
        

Generated by: LCOV version 2.0-1