diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index a1a75f915..befd0abde 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -1,245 +1,226 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2017 The Bitcoin Core developers // Copyright (c) 2018-2020 The Bitcoin 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 #include #include #include #include #include #include #include class WalletInit : public WalletInitInterface { public: //! Was the wallet component compiled in. bool HasWalletSupport() const override { return true; } //! Return the wallets help message. void AddWalletOptions() const override; //! Wallets parameter interaction bool ParameterInteraction() const override; //! Add wallets that should be opened to list of chain clients. void Construct(NodeContext &node) const override; }; const WalletInitInterface &g_wallet_init_interface = WalletInit(); void WalletInit::AddWalletOptions() const { gArgs.AddArg( "-avoidpartialspends", strprintf("Group outputs by address, selecting all or none, instead of " "selecting on a per-output basis. Privacy is improved as an " "address is only used once (unless someone sends to it after " "spending from it), but may result in slightly higher fees " "as suboptimal coin selection may result due to the added " "limitation (default: %u (always enabled for wallets with " "\"avoid_reuse\" enabled))", DEFAULT_AVOIDPARTIALSPENDS), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg("-fallbackfee=", strprintf("A fee rate (in %s/kB) that will be used when fee " "estimation has insufficient data. 0 to entirely " "disable the fallbackfee feature. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg( "-keypool=", strprintf("Set key pool size to (default: %u). Warning: Smaller " "sizes may increase the risk of losing funds when restoring " "from an old backup, if none of the addresses in the " "original keypool have been used.", DEFAULT_KEYPOOL_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg( "-maxapsfee=", strprintf( "Spend up to this amount in additional (absolute) fees (in %s) if " "it allows the use of partial spend avoidance (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MAX_AVOIDPARTIALSPEND_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg( "-maxtxfee=", strprintf("Maximum total fees (in %s) to use in a single wallet " "transaction or raw transaction; setting this too low may " "abort large transactions (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); gArgs.AddArg("-mintxfee=", strprintf("Fees (in %s/kB) smaller than this are considered " "zero fee for transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE_PER_KB)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg( "-paytxfee=", strprintf( "Fee (in %s/kB) to add to transactions you send (default: %s)", CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg( "-rescan", "Rescan the block chain for missing wallet transactions on startup", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); - gArgs.AddArg( - "-salvagewallet", - "Attempt to recover private keys from a corrupt wallet on startup", - ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); - gArgs.AddArg( "-spendzeroconfchange", strprintf( "Spend unconfirmed change when sending transactions (default: %d)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg("-wallet=", "Specify wallet database path. Can be specified multiple " "times to load multiple wallets. Path is interpreted relative " "to if it is not absolute, and will be created if " "it does not exist (as a directory containing a wallet.dat " "file and log files). For backwards compatibility this will " "also accept names of existing data files in .)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); gArgs.AddArg( "-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %d)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg("-walletdir=", "Specify directory to hold wallets (default: " "/wallets if it exists, otherwise )", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET); #if defined(HAVE_SYSTEM) gArgs.AddArg("-walletnotify=", "Execute command when a wallet transaction changes. %s in cmd " "is replaced by TxID and %w is replaced by wallet name. %w is " "not currently implemented on windows. On systems where %w is " "supported, it should NOT be quoted because this would break " "shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); #endif gArgs.AddArg( "-zapwallettxes=", "Delete all wallet transactions and only recover those parts of the " "blockchain through -rescan on startup (1 = keep tx meta data e.g. " "payment request information, 2 = drop tx meta data)", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET); gArgs.AddArg("-dblogsize=", strprintf("Flush wallet database activity from memory to disk " "log every megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg( "-flushwallet", strprintf("Run a thread to flush wallet periodically (default: %d)", DEFAULT_FLUSHWALLET), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg("-privdb", strprintf("Sets the DB_PRIVATE flag in the wallet db " "environment (default: %d)", DEFAULT_WALLET_PRIVDB), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); gArgs.AddArg("-walletrejectlongchains", strprintf("Wallet will not create transactions that violate " "mempool chain limits (default: %d)", DEFAULT_WALLET_REJECT_LONG_CHAINS), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST); } bool WalletInit::ParameterInteraction() const { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { for (const std::string &wallet : gArgs.GetArgs("-wallet")) { LogPrintf("%s: parameter interaction: -disablewallet -> ignoring " "-wallet=%s\n", __func__, wallet); } return true; } const bool is_multiwallet = gArgs.GetArgs("-wallet").size() > 1; if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY) && gArgs.SoftSetBoolArg("-walletbroadcast", false)) { LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting " "-walletbroadcast=0\n", __func__); } - if (gArgs.GetBoolArg("-salvagewallet", false)) { - if (is_multiwallet) { - return InitError(strprintf( - Untranslated("%s is only allowed with a single wallet file"), - "-salvagewallet")); - } - // Rewrite just private keys: rescan to find transactions - if (gArgs.SoftSetBoolArg("-rescan", true)) { - LogPrintf("%s: parameter interaction: -salvagewallet=1 -> setting " - "-rescan=1\n", - __func__); - } - } - bool zapwallettxes = gArgs.GetBoolArg("-zapwallettxes", false); // -zapwallettxes implies dropping the mempool on startup if (zapwallettxes && gArgs.SoftSetBoolArg("-persistmempool", false)) { LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> " "setting -persistmempool=0\n", __func__); } // -zapwallettxes implies a rescan if (zapwallettxes) { if (is_multiwallet) { return InitError(strprintf( Untranslated("%s is only allowed with a single wallet file"), "-zapwallettxes")); } if (gArgs.SoftSetBoolArg("-rescan", true)) { LogPrintf("%s: parameter interaction: -zapwallettxes enabled -> " "setting -rescan=1\n", __func__); } } if (gArgs.GetBoolArg("-sysperms", false)) { return InitError( Untranslated("-sysperms is not allowed in combination with enabled " "wallet functionality")); } return true; } void WalletInit::Construct(NodeContext &node) const { if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { LogPrintf("Wallet disabled!\n"); return; } gArgs.SoftSetArg("-wallet", ""); node.chain_clients.emplace_back( interfaces::MakeWalletClient(*node.chain, gArgs.GetArgs("-wallet"))); } diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 33e31db77..cc83424a8 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -1,144 +1,137 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 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(const CChainParams &chainParams, 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"), wallet_dir.string())); return false; } else if (!fs::is_directory(wallet_dir)) { chain.initError( strprintf(_("Specified -walletdir \"%s\" is not a directory"), 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"), 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."), wallet_file)); return false; } bilingual_str error_string; std::vector warnings; - bool verify_success = - CWallet::Verify(chainParams, chain, location, salvage_wallet, - error_string, warnings); + bool verify_success = CWallet::Verify(chainParams, chain, location, + error_string, warnings); if (!warnings.empty()) { chain.initWarning(Join(warnings, "\n", OpTranslated)); } if (!verify_success) { chain.initError(error_string); return false; } } return true; } bool LoadWallets(const CChainParams &chainParams, interfaces::Chain &chain, const std::vector &wallet_files) { for (const std::string &walletFile : wallet_files) { bilingual_str error; std::vector warnings; std::shared_ptr pwallet = CWallet::CreateWalletFromFile( chainParams, chain, WalletLocation(walletFile), error, warnings); if (!warnings.empty()) { chain.initWarning(Join(warnings, "\n", OpTranslated)); } if (!pwallet) { chain.initError(error); return false; } AddWallet(pwallet); } return true; } void StartWallets(CScheduler &scheduler) { for (const std::shared_ptr &pwallet : GetWallets()) { pwallet->postInitProcess(); } // Schedule periodic wallet flushes and tx rebroadcasts scheduler.scheduleEvery( [] { MaybeCompactWalletDB(); return true; }, std::chrono::milliseconds{500}); scheduler.scheduleEvery( [] { MaybeResendWalletTxs(); return true; }, 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)); } } diff --git a/src/wallet/load.h b/src/wallet/load.h index 237effd31..5630f9340 100644 --- a/src/wallet/load.h +++ b/src/wallet/load.h @@ -1,43 +1,40 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2018 The Bitcoin Core developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. #ifndef BITCOIN_WALLET_LOAD_H #define BITCOIN_WALLET_LOAD_H #include #include class CChainParams; class CScheduler; namespace interfaces { class Chain; } // namespace interfaces //! Responsible for reading and validating the -wallet arguments and verifying //! the wallet database. -// This function will perform salvage on the wallet if requested, as long as -// only one wallet is being loaded (WalletInit::ParameterInteraction() forbids -// -salvagewallet, -zapwallettxes or -upgradewallet with multiwallet). bool VerifyWallets(const CChainParams &chainParams, interfaces::Chain &chain, const std::vector &wallet_files); //! Load wallet databases. bool LoadWallets(const CChainParams &chainParams, interfaces::Chain &chain, const std::vector &wallet_files); //! Complete startup of wallets. void StartWallets(CScheduler &scheduler); //! Flush all wallets in preparation for shutdown. void FlushWallets(); //! Stop all wallets. Wallets will be flushed first. void StopWallets(); //! Close all wallets. void UnloadWallets(); #endif // BITCOIN_WALLET_LOAD_H diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 570a6ec46..f279868af 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,5059 +1,5046 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto // Copyright (c) 2009-2019 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 #include #include #include #include #include #include #include #include