diff --git a/src/init.cpp b/src/init.cpp index 6032017d0e6a..c7f1e7f6e9e7 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -37,7 +37,6 @@ #include "net_processing.h" #include "policy/feerate.h" #include "policy/policy.h" -#include "reverse_iterate.h" #include "rpc/register.h" #include "rpc/server.h" #include "script/sigcache.h" @@ -87,9 +86,6 @@ #endif -#ifdef ENABLE_WALLET -int nWalletBackups = 10; -#endif volatile bool fFeeEstimatesInitialized = false; volatile bool fRestartRequested = false; // true: restart false: shutdown static const bool DEFAULT_PROXYRANDOMIZE = true; @@ -839,7 +835,6 @@ namespace { // Variables internal to initialization process only ServiceFlags nLocalServices = NODE_NETWORK; std::string strWalletFile; - bool fDisableWallet = false; } bool AppInitBasicSetup() @@ -872,12 +867,7 @@ bool AppInitBasicSetup() return UIError("Error: Initializing networking failed"); #ifndef WIN32 - if (gArgs.GetBoolArg("-sysperms", false)) { -#ifdef ENABLE_WALLET - if (!gArgs.GetBoolArg("-disablewallet", false)) - return UIError("Error: -sysperms is not allowed in combination with enabled wallet functionality"); -#endif - } else { + if (!gArgs.GetBoolArg("-sysperms", false)) { umask(077); } @@ -1137,18 +1127,14 @@ bool AppInitParameterInteraction() setvbuf(stdout, NULL, _IOLBF, 0); /// ***TODO*** do we still need this after -printtoconsole is gone? RegisterAllCoreRPCCommands(tableRPC); + // Staking needs a CWallet instance, so make sure wallet is enabled #ifdef ENABLE_WALLET - bool fDisableWallet = gArgs.GetBoolArg("-disablewallet", false); - if (fDisableWallet) { -#endif - if (gArgs.SoftSetBoolArg("-staking", false)) - LogPrintf("AppInit2 : parameter interaction: wallet functionality not enabled -> setting -staking=0\n"); -#ifdef ENABLE_WALLET - } else { - // Register wallet RPC commands - RegisterWalletRPCCommands(tableRPC); - } + // Register wallet RPC commands + RegisterWalletRPCCommands(tableRPC); +#else + if (gArgs.SoftSetBoolArg("-staking", false)) + LogPrintf("AppInit2 : parameter interaction: wallet functionality not enabled -> setting -staking=0\n"); #endif nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); @@ -1313,117 +1299,50 @@ bool AppInitMain() return UIError(_("Unable to start HTTP server. See debug log for details.")); } -// ********************************************************* Step 5: Backup wallet and verify wallet database integrity -#ifdef ENABLE_WALLET - if (!fDisableWallet) { - fs::path backupDir = GetDataDir() / "backups"; - if (!fs::exists(backupDir)) { - // Always create backup folder to not confuse the operating system's file browser - fs::create_directories(backupDir); - } - nWalletBackups = gArgs.GetArg("-createwalletbackups", DEFAULT_CREATEWALLETBACKUPS); - nWalletBackups = std::max(0, std::min(10, nWalletBackups)); - if (nWalletBackups > 0) { - if (fs::exists(backupDir)) { - // Create backup of the wallet - std::string dateTimeStr = FormatISO8601DateTimeForBackup(GetTime()); - std::string backupPathStr = backupDir.string(); - backupPathStr += "/" + strWalletFile; - std::string sourcePathStr = GetDataDir().string(); - sourcePathStr += "/" + strWalletFile; - fs::path sourceFile = sourcePathStr; - fs::path backupFile = backupPathStr + dateTimeStr; - sourceFile.make_preferred(); - backupFile.make_preferred(); - if (fs::exists(sourceFile)) { -#if BOOST_VERSION >= 105800 - try { - fs::copy_file(sourceFile, backupFile); - LogPrintf("Creating backup of %s -> %s\n", sourceFile, backupFile); - } catch (const fs::filesystem_error& error) { - LogPrintf("Failed to create backup %s\n", error.what()); - } -#else - std::ifstream src(sourceFile.string(), std::ios::binary); - std::ofstream dst(backupFile.string(), std::ios::binary); - dst << src.rdbuf(); -#endif - } - // Keep only the last 10 backups, including the new one of course - typedef std::multimap folder_set_t; - folder_set_t folder_set; - fs::directory_iterator end_iter; - fs::path backupFolder = backupDir.string(); - backupFolder.make_preferred(); - // Build map of backup files for current(!) wallet sorted by last write time - fs::path currentFile; - for (fs::directory_iterator dir_iter(backupFolder); dir_iter != end_iter; ++dir_iter) { - // Only check regular files - if (fs::is_regular_file(dir_iter->status())) { - currentFile = dir_iter->path().filename(); - // Only add the backups for the current wallet, e.g. wallet.dat.* - if (dir_iter->path().stem().string() == strWalletFile) { - folder_set.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter)); - } - } - } - // Loop backward through backup files and keep the N newest ones (1 <= N <= 10) - int counter = 0; - for (std::pair file : reverse_iterate(folder_set)) { - counter++; - if (counter > nWalletBackups) { - // More than nWalletBackups backups: delete oldest one(s) - try { - fs::remove(file.second); - LogPrintf("Old backup deleted: %s\n", file.second); - } catch (const fs::filesystem_error& error) { - LogPrintf("Failed to delete backup %s\n", error.what()); - } - } - } - } - } - - if (gArgs.GetBoolArg("-resync", false)) { - uiInterface.InitMessage(_("Preparing for resync...")); - // Delete the local blockchain folders to force a resync from scratch to get a consitent blockchain-state - fs::path blocksDir = GetBlocksDir(); - fs::path chainstateDir = GetDataDir() / "chainstate"; - fs::path sporksDir = GetDataDir() / "sporks"; - fs::path zerocoinDir = GetDataDir() / "zerocoin"; + if (gArgs.GetBoolArg("-resync", false)) { + uiInterface.InitMessage(_("Preparing for resync...")); + // Delete the local blockchain folders to force a resync from scratch to get a consitent blockchain-state + fs::path blocksDir = GetBlocksDir(); + fs::path chainstateDir = GetDataDir() / "chainstate"; + fs::path sporksDir = GetDataDir() / "sporks"; + fs::path zerocoinDir = GetDataDir() / "zerocoin"; - LogPrintf("Deleting blockchain folders blocks, chainstate, sporks and zerocoin\n"); - // We delete in 4 individual steps in case one of the folder is missing already - try { - if (fs::exists(blocksDir)){ - fs::remove_all(blocksDir); - LogPrintf("-resync: folder deleted: %s\n", blocksDir.string().c_str()); - } + LogPrintf("Deleting blockchain folders blocks, chainstate, sporks and zerocoin\n"); + // We delete in 4 individual steps in case one of the folder is missing already + try { + if (fs::exists(blocksDir)){ + fs::remove_all(blocksDir); + LogPrintf("-resync: folder deleted: %s\n", blocksDir.string().c_str()); + } - if (fs::exists(chainstateDir)){ - fs::remove_all(chainstateDir); - LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); - } + if (fs::exists(chainstateDir)){ + fs::remove_all(chainstateDir); + LogPrintf("-resync: folder deleted: %s\n", chainstateDir.string().c_str()); + } - if (fs::exists(sporksDir)){ - fs::remove_all(sporksDir); - LogPrintf("-resync: folder deleted: %s\n", sporksDir.string().c_str()); - } + if (fs::exists(sporksDir)){ + fs::remove_all(sporksDir); + LogPrintf("-resync: folder deleted: %s\n", sporksDir.string().c_str()); + } - if (fs::exists(zerocoinDir)){ - fs::remove_all(zerocoinDir); - LogPrintf("-resync: folder deleted: %s\n", zerocoinDir.string().c_str()); - } - } catch (const fs::filesystem_error& error) { - LogPrintf("Failed to delete blockchain folders %s\n", error.what()); + if (fs::exists(zerocoinDir)){ + fs::remove_all(zerocoinDir); + LogPrintf("-resync: folder deleted: %s\n", zerocoinDir.string().c_str()); } + } catch (const fs::filesystem_error& error) { + LogPrintf("Failed to delete blockchain folders %s\n", error.what()); } + } - if (!CWallet::Verify()) - return false; - - } // (!fDisableWallet) -#endif // ENABLE_WALLET +// ********************************************************* Step 5: Backup wallet and verify wallet database integrity +#ifdef ENABLE_WALLET + if (!InitAutoBackupWallet()) { + return false; + } + if (!CWallet::Verify()) { + return false; + } +#endif // ********************************************************* Step 6: network initialization // Note that we absolutely cannot open any actual connections diff --git a/src/qt/pivx/pivxgui.cpp b/src/qt/pivx/pivxgui.cpp index f7bae2b13fab..9bf9f44563a4 100644 --- a/src/qt/pivx/pivxgui.cpp +++ b/src/qt/pivx/pivxgui.cpp @@ -59,7 +59,7 @@ PIVXGUI::PIVXGUI(const NetworkStyle* networkStyle, QWidget* parent) : #ifdef ENABLE_WALLET /* if compiled with wallet support, -disablewallet can still disable the wallet */ - enableWallet = !gArgs.GetBoolArg("-disablewallet", false); + enableWallet = !gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET); #else enableWallet = false; #endif // ENABLE_WALLET diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 535d7fd60749..65f96771a61a 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -4154,6 +4154,10 @@ static const CRPCCommand commands[] = void RegisterWalletRPCCommands(CRPCTable &tableRPC) { - for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) + if (gArgs.GetBoolArg("-disablewallet", false)) { + return; + } + for (unsigned int vcidx = 0; vcidx < ARRAYLEN(commands); vcidx++) { tableRPC.appendCommand(commands[vcidx].name, &commands[vcidx]); + } } diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index d21a1366a767..73684c8bec56 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -1,7 +1,7 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2021 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers -// Copyright (c) 2015-2020 The PIVX developers +// Copyright (c) 2015-2021 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. @@ -646,6 +646,14 @@ void CWallet::SyncMetaData(std::pair::iterator, typename bool CWallet::ParameterInteraction() { + if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { + return true; + } + + if (gArgs.GetBoolArg("-sysperms", false)) { + return UIError("-sysperms is not allowed in combination with enabled wallet functionality"); + } + if (gArgs.IsArgSet("-mintxfee")) { CAmount n = 0; if (ParseMoney(gArgs.GetArg("-mintxfee", ""), n) && n > 0) @@ -2063,6 +2071,10 @@ std::set CWalletTx::GetConflicts() const bool CWallet::Verify() { + if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { + return true; + } + uiInterface.InitMessage(_("Verifying wallet...")); std::string walletFile = gArgs.GetArg("-wallet", DEFAULT_WALLET_DAT); std::string strDataDir = GetDataDir().string(); @@ -4082,7 +4094,7 @@ std::string CWallet::GetWalletHelpString(bool showDebug) strUsage += HelpMessageOpt("-backuppath=", _("Specify custom backup path to add a copy of any wallet backup. If set as dir, every backup generates a timestamped file. If set as file, will rewrite to that file every backup.")); strUsage += HelpMessageOpt("-createwalletbackups=", strprintf(_("Number of automatic wallet backups (default: %d)"), DEFAULT_CREATEWALLETBACKUPS)); strUsage += HelpMessageOpt("-custombackupthreshold=", strprintf(_("Number of custom location backups to retain (default: %d)"), DEFAULT_CUSTOMBACKUPTHRESHOLD)); - strUsage += HelpMessageOpt("-disablewallet", _("Do not load the wallet and disable wallet RPC calls")); + strUsage += HelpMessageOpt("-disablewallet", strprintf(_("Do not load the wallet and disable wallet RPC calls (default: %u)"), DEFAULT_DISABLE_WALLET)); strUsage += HelpMessageOpt("-keypool=", strprintf(_("Set key pool size to (default: %u)"), DEFAULT_KEYPOOL_SIZE)); strUsage += HelpMessageOpt("-legacywallet", _("On first run, create a legacy wallet instead of a HD wallet")); strUsage += HelpMessageOpt("-maxtxfee=", strprintf(_("Maximum total fees to use in a single wallet transaction, setting too low may abort large transactions (default: %s)"), FormatMoney(maxTxFee))); @@ -4844,3 +4856,20 @@ const CWDestination* CAddressBookIterator::GetDestKey() CStakeableOutput::CStakeableOutput(const CWalletTx* txIn, int iIn, int nDepthIn, bool fSpendableIn, bool fSolvableIn, const CBlockIndex*& _pindex) : COutput(txIn, iIn, nDepthIn, fSpendableIn, fSolvableIn), pindex(_pindex) {} + +bool InitAutoBackupWallet() +{ + if (gArgs.GetBoolArg("-disablewallet", DEFAULT_DISABLE_WALLET)) { + return true; + } + + std::string strWalletFile = gArgs.GetArg("-wallet", DEFAULT_WALLET_DAT); + + std::string strWarning, strError; + if(!AutoBackupWallet(strWalletFile, strWarning, strError)) { + if (!strWarning.empty()) UIWarning(strWarning); + if (!strError.empty()) return UIError(strError); + } + + return true; +} diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 8cfb57b62e83..27c225ad9ea0 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -1,12 +1,12 @@ // Copyright (c) 2009-2010 Satoshi Nakamoto -// Copyright (c) 2009-2014 The Bitcoin developers +// Copyright (c) 2009-2021 The Bitcoin developers // Copyright (c) 2014-2015 The Dash developers -// Copyright (c) 2015-2020 The PIVX developers +// Copyright (c) 2015-2021 The PIVX developers // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. -#ifndef BITCOIN_WALLET_H -#define BITCOIN_WALLET_H +#ifndef PIVX_WALLET_H +#define PIVX_WALLET_H #include "addressbook.h" #include "amount.h" @@ -1267,4 +1267,7 @@ class WalletRescanReserver } }; -#endif // BITCOIN_WALLET_H +// !TODO: move to wallet/init.* +bool InitAutoBackupWallet(); + +#endif // PIVX_WALLET_H diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index f8a45c5630e7..50d756e09f2e 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -11,6 +11,7 @@ #include "base58.h" #include "protocol.h" +#include "reverse_iterate.h" #include "sapling/key_io_sapling.h" #include "serialize.h" #include "sync.h" @@ -870,6 +871,97 @@ std::pair GetBackupPath(const CWallet& wallet) return {pathCustom, pathWithFile}; } +bool AutoBackupWallet(const std::string& strWalletFile, std::string& strBackupWarning, std::string& strBackupError) +{ + strBackupWarning = strBackupError = ""; + + int nWalletBackups = gArgs.GetArg("-createwalletbackups", DEFAULT_CREATEWALLETBACKUPS); + nWalletBackups = std::max(0, std::min(10, nWalletBackups)); + + if (nWalletBackups == 0) { + LogPrintf("Automatic wallet backups are disabled!\n"); + return false; + } + + fs::path backupsDir = GetDataDir() / "backups"; + if (!fs::exists(backupsDir)) { + // Always create backup folder to not confuse the operating system's file browser + LogPrintf("Creating backup folder %s\n", backupsDir.string()); + if(!fs::create_directories(backupsDir)) { + // smth is wrong, we shouldn't continue until it's resolved + strBackupError = strprintf(_("Wasn't able to create wallet backup folder %s!"), backupsDir.string()); + LogPrintf("%s\n", strBackupError); + nWalletBackups = -1; + return false; + } + } + // Create backup of the ... + std::string dateTimeStr = FormatISO8601DateTimeForBackup(GetTime()); + + // ... strWalletFile file + fs::path sourceFile = GetDataDir() / strWalletFile; + fs::path backupFile = backupsDir / (strWalletFile + dateTimeStr); + sourceFile.make_preferred(); + backupFile.make_preferred(); + if (fs::exists(backupFile)) { + strBackupWarning = _("Failed to create backup, file already exists! This could happen if you restarted wallet in less than 60 seconds. You can continue if you are ok with this."); + LogPrintf("%s\n", strBackupWarning); + return false; + } + if(fs::exists(sourceFile)) { +#if BOOST_VERSION >= 105800 + try { + fs::copy_file(sourceFile, backupFile); + LogPrintf("Creating backup of %s -> %s\n", sourceFile.string(), backupFile.string()); + } catch(fs::filesystem_error &error) { + strBackupWarning = strprintf(_("Failed to create backup, error: %s"), error.what()); + LogPrintf("%s\n", strBackupWarning); + nWalletBackups = -1; + return false; + } +#else + std::ifstream src(sourceFile.string(), std::ios::binary); + std::ofstream dst(backupFile.string(), std::ios::binary); + dst << src.rdbuf(); +#endif + } + + // Keep only the last 10 backups, including the new one of course + typedef std::multimap folder_set_t; + folder_set_t folder_set; + fs::directory_iterator end_iter; + backupsDir.make_preferred(); + // Build map of backup files for current(!) wallet sorted by last write time + fs::path currentFile; + for (fs::directory_iterator dir_iter(backupsDir); dir_iter != end_iter; ++dir_iter) { + // Only check regular files + if ( fs::is_regular_file(dir_iter->status())) { + currentFile = dir_iter->path().filename(); + // Only add the backups for the current wallet, e.g. wallet.dat.* + if(dir_iter->path().stem().string() == strWalletFile) { + folder_set.insert(folder_set_t::value_type(fs::last_write_time(dir_iter->path()), *dir_iter)); + } + } + } + // Loop backward through backup files and keep the N newest ones (1 <= N <= 10) + int counter = 0; + for (std::pair file : reverse_iterate(folder_set)) { + counter++; + if (counter > nWalletBackups) { + // More than nWalletBackups backups: delete oldest one(s) + try { + fs::remove(file.second); + LogPrintf("Old backup deleted: %s\n", file.second); + } catch(fs::filesystem_error &error) { + strBackupWarning = strprintf(_("Failed to delete backup, error: %s"), error.what()); + LogPrintf("%s\n", strBackupWarning); + return false; + } + } + } + return true; +} + void MultiBackup(const CWallet& wallet, fs::path pathCustom, fs::path pathWithFile, const fs::path& pathSrc) { int nThreshold = gArgs.GetArg("-custombackupthreshold", DEFAULT_CUSTOMBACKUPTHRESHOLD); diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index ca5783756ddf..981750975fdb 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -221,6 +221,9 @@ void NotifyBacked(const CWallet& wallet, bool fSuccess, std::string strMessage); bool BackupWallet(const CWallet& wallet, const fs::path& strDest); bool AttemptBackupWallet(const CWallet& wallet, const fs::path& pathSrc, const fs::path& pathDest); +//! Called during init: Automatic backups of wallet not running (just copying and renaming dat file) +bool AutoBackupWallet(const std::string& strWalletFile, std::string& strBackupWarning, std::string& strBackupError); + //! Compacts BDB state so that wallet.dat is self-contained (if there are changes) void MaybeCompactWalletDB();