// Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2020 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include #include #include #include #include #include #include bool VerifyWallets(interfaces::Chain& chain, const std::vector& wallet_files) { if (gArgs.IsArgSet("-walletdir")) { fs::path wallet_dir = gArgs.GetArg("-walletdir", ""); boost::system::error_code error; // The canonical path cleans the path, preventing >1 Berkeley environment instances for the same directory fs::path canonical_wallet_dir = fs::canonical(wallet_dir, error); if (error || !fs::exists(wallet_dir)) { chain.initError(strprintf(_("Specified -walletdir \"%s\" does not exist").translated, wallet_dir.string())); return false; } else if (!fs::is_directory(wallet_dir)) { chain.initError(strprintf(_("Specified -walletdir \"%s\" is not a directory").translated, wallet_dir.string())); return false; // The canonical path transforms relative paths into absolute ones, so we check the non-canonical version } else if (!wallet_dir.is_absolute()) { chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path").translated, wallet_dir.string())); return false; } gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string()); } LogPrintf("Using wallet directory %s\n", GetWalletDir().string()); chain.initMessage(_("Verifying wallet(s)...").translated); // Parameter interaction code should have thrown an error if -salvagewallet // was enabled with more than wallet file, so the wallet_files size check // here should have no effect. bool salvage_wallet = gArgs.GetBoolArg("-salvagewallet", false) && wallet_files.size() <= 1; // Keep track of each wallet absolute path to detect duplicates. std::set wallet_paths; for (const auto& wallet_file : wallet_files) { WalletLocation location(wallet_file); if (!wallet_paths.insert(location.GetPath()).second) { chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified.").translated, wallet_file)); return false; } bilingual_str error_string; std::vector warnings; bool verify_success = CWallet::Verify(chain, location, salvage_wallet, error_string, warnings); if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated)); if (!verify_success) { chain.initError(error_string.translated); return false; } } return true; } bool LoadWallets(interfaces::Chain& chain, const std::vector& wallet_files) { try { for (const std::string& walletFile : wallet_files) { bilingual_str error; std::vector warnings; std::shared_ptr pwallet = CWallet::CreateWalletFromFile(chain, WalletLocation(walletFile), error, warnings); if (!warnings.empty()) chain.initWarning(Join(warnings, "\n", OpTranslated)); if (!pwallet) { chain.initError(error.translated); return false; } AddWallet(pwallet); } return true; } catch (const std::runtime_error& e) { chain.initError(e.what()); return false; } } void StartWallets(CScheduler& scheduler) { for (const std::shared_ptr& pwallet : GetWallets()) { pwallet->postInitProcess(); } // Schedule periodic wallet flushes and tx rebroadcasts scheduler.scheduleEvery(MaybeCompactWalletDB, std::chrono::milliseconds{500}); scheduler.scheduleEvery(MaybeResendWalletTxs, std::chrono::milliseconds{1000}); } void FlushWallets() { for (const std::shared_ptr& pwallet : GetWallets()) { pwallet->Flush(false); } } void StopWallets() { for (const std::shared_ptr& pwallet : GetWallets()) { pwallet->Flush(true); } } void UnloadWallets() { auto wallets = GetWallets(); while (!wallets.empty()) { auto wallet = wallets.back(); wallets.pop_back(); RemoveWallet(wallet); UnloadWallet(std::move(wallet)); } }