diff options
Diffstat (limited to 'src')
48 files changed, 633 insertions, 612 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index ffa2980d59..ef5b1900d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -212,6 +212,7 @@ BITCOIN_CORE_H = \ util/rbf.h \ util/threadnames.h \ util/time.h \ + util/translation.h \ util/url.h \ util/validation.h \ validation.h \ diff --git a/src/banman.cpp b/src/banman.cpp index 47d64a8f31..37fca7dd82 100644 --- a/src/banman.cpp +++ b/src/banman.cpp @@ -9,12 +9,13 @@ #include <ui_interface.h> #include <util/system.h> #include <util/time.h> +#include <util/translation.h> BanMan::BanMan(fs::path ban_file, CClientUIInterface* client_interface, int64_t default_ban_time) : m_client_interface(client_interface), m_ban_db(std::move(ban_file)), m_default_ban_time(default_ban_time) { - if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist...")); + if (m_client_interface) m_client_interface->InitMessage(_("Loading banlist...").translated); int64_t n_start = GetTimeMillis(); m_is_dirty = false; diff --git a/src/bitcoin-cli.cpp b/src/bitcoin-cli.cpp index d3419520a7..8ca985458d 100644 --- a/src/bitcoin-cli.cpp +++ b/src/bitcoin-cli.cpp @@ -13,9 +13,11 @@ #include <rpc/client.h> #include <rpc/protocol.h> #include <rpc/request.h> -#include <util/system.h> #include <util/strencodings.h> +#include <util/system.h> +#include <util/translation.h> +#include <functional> #include <memory> #include <stdio.h> #include <tuple> diff --git a/src/bitcoin-tx.cpp b/src/bitcoin-tx.cpp index 4d513deed8..89e2ab305b 100644 --- a/src/bitcoin-tx.cpp +++ b/src/bitcoin-tx.cpp @@ -18,11 +18,13 @@ #include <script/sign.h> #include <script/signingprovider.h> #include <univalue.h> -#include <util/rbf.h> -#include <util/system.h> #include <util/moneystr.h> +#include <util/rbf.h> #include <util/strencodings.h> +#include <util/system.h> +#include <util/translation.h> +#include <functional> #include <memory> #include <stdio.h> diff --git a/src/bitcoin-wallet.cpp b/src/bitcoin-wallet.cpp index cbb4ea750c..a690e2facb 100644 --- a/src/bitcoin-wallet.cpp +++ b/src/bitcoin-wallet.cpp @@ -9,10 +9,12 @@ #include <chainparams.h> #include <chainparamsbase.h> #include <logging.h> -#include <util/system.h> #include <util/strencodings.h> +#include <util/system.h> +#include <util/translation.h> #include <wallet/wallettool.h> +#include <functional> #include <stdio.h> const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index ba6de702e0..8e31f6e32b 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -11,15 +11,17 @@ #include <clientversion.h> #include <compat.h> #include <fs.h> -#include <interfaces/chain.h> #include <init.h> +#include <interfaces/chain.h> #include <noui.h> #include <shutdown.h> +#include <ui_interface.h> +#include <util/strencodings.h> #include <util/system.h> #include <util/threadnames.h> -#include <util/strencodings.h> +#include <util/translation.h> -#include <stdio.h> +#include <functional> const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; @@ -70,8 +72,7 @@ static bool AppInit(int argc, char* argv[]) SetupServerArgs(); std::string error; if (!gArgs.ParseParameters(argc, argv, error)) { - tfm::format(std::cerr, "Error parsing command line arguments: %s\n", error.c_str()); - return false; + return InitError(strprintf("Error parsing command line arguments: %s\n", error)); } // Process help and version before taking care about datadir @@ -96,26 +97,22 @@ static bool AppInit(int argc, char* argv[]) { if (!fs::is_directory(GetDataDir(false))) { - tfm::format(std::cerr, "Error: Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "").c_str()); - return false; + return InitError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))); } if (!gArgs.ReadConfigFiles(error, true)) { - tfm::format(std::cerr, "Error reading configuration file: %s\n", error.c_str()); - return false; + return InitError(strprintf("Error reading configuration file: %s\n", error)); } // Check for -testnet or -regtest parameter (Params() calls are only valid after this clause) try { SelectParams(gArgs.GetChainName()); } catch (const std::exception& e) { - tfm::format(std::cerr, "Error: %s\n", e.what()); - return false; + return InitError(strprintf("%s\n", e.what())); } // Error out when loose non-argument tokens are encountered on command line for (int i = 1; i < argc; i++) { if (!IsSwitchChar(argv[i][0])) { - tfm::format(std::cerr, "Error: Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i]); - return false; + return InitError(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i])); } } @@ -146,19 +143,17 @@ static bool AppInit(int argc, char* argv[]) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wdeprecated-declarations" #endif - tfm::format(std::cout, "Bitcoin server starting\n"); + tfm::format(std::cout, PACKAGE_NAME " daemon starting\n"); // Daemonize if (daemon(1, 0)) { // don't chdir (1), do close FDs (0) - tfm::format(std::cerr, "Error: daemon() failed: %s\n", strerror(errno)); - return false; + return InitError(strprintf("daemon() failed: %s\n", strerror(errno))); } #if defined(MAC_OSX) #pragma GCC diagnostic pop #endif #else - tfm::format(std::cerr, "Error: -daemon is not supported on this operating system\n"); - return false; + return InitError("-daemon is not supported on this operating system\n"); #endif // HAVE_DECL_DAEMON } // Lock data directory after daemonization diff --git a/src/chainparams.cpp b/src/chainparams.cpp index f937e2754b..c24234aeb7 100644 --- a/src/chainparams.cpp +++ b/src/chainparams.cpp @@ -167,9 +167,6 @@ public: /* nTxCount */ 383732546, /* dTxRate */ 3.685496590998308 }; - - /* disable fallback fee on mainnet */ - m_fallback_fee_enabled = false; } }; @@ -262,9 +259,6 @@ public: /* nTxCount */ 19438708, /* dTxRate */ 0.626 }; - - /* enable fallback fee on testnet */ - m_fallback_fee_enabled = true; } }; @@ -346,9 +340,6 @@ public: base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94}; bech32_hrp = "bcrt"; - - /* enable fallback fee on regtest */ - m_fallback_fee_enabled = true; } /** diff --git a/src/chainparams.h b/src/chainparams.h index b3fcd77cea..8f1d27e03c 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -66,7 +66,7 @@ public: bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; } /** Policy: Filter transactions that do not match well-defined patterns */ bool RequireStandard() const { return fRequireStandard; } - /** If this is a test chain */ + /** If this chain is exclusively used for testing */ bool IsTestChain() const { return m_is_test_chain; } uint64_t PruneAfterHeight() const { return nPruneAfterHeight; } /** Minimum free space (in GB) needed for data directory */ @@ -77,8 +77,6 @@ public: bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; } /** Return the BIP70 network string (main, test or regtest) */ std::string NetworkIDString() const { return strNetworkID; } - /** Return true if the fallback fee is by default enabled for this network */ - bool IsFallbackFeeEnabled() const { return m_fallback_fee_enabled; } /** Return the list of hostnames to look up for DNS seeds */ const std::vector<std::string>& DNSSeeds() const { return vSeeds; } const std::vector<unsigned char>& Base58Prefix(Base58Type type) const { return base58Prefixes[type]; } @@ -106,7 +104,6 @@ protected: bool m_is_test_chain; CCheckpointData checkpointData; ChainTxData chainTxData; - bool m_fallback_fee_enabled; }; /** diff --git a/src/chainparamsbase.h b/src/chainparamsbase.h index 355df043d3..f34646f7ac 100644 --- a/src/chainparamsbase.h +++ b/src/chainparamsbase.h @@ -7,7 +7,6 @@ #include <memory> #include <string> -#include <vector> /** * CBaseChainParams defines the base parameters (shared between bitcoin-cli and bitcoind) diff --git a/src/coins.cpp b/src/coins.cpp index 3ef9e0463c..6b85edd01a 100644 --- a/src/coins.cpp +++ b/src/coins.cpp @@ -5,6 +5,7 @@ #include <coins.h> #include <consensus/consensus.h> +#include <logging.h> #include <random.h> #include <version.h> @@ -258,3 +259,19 @@ const Coin& AccessByTxid(const CCoinsViewCache& view, const uint256& txid) } return coinEmpty; } + +bool CCoinsViewErrorCatcher::GetCoin(const COutPoint &outpoint, Coin &coin) const { + try { + return CCoinsViewBacked::GetCoin(outpoint, coin); + } catch(const std::runtime_error& e) { + for (auto f : m_err_callbacks) { + f(); + } + LogPrintf("Error reading from database: %s\n", e.what()); + // Starting the shutdown sequence and returning false to the caller would be + // interpreted as 'entry not found' (as opposed to unable to read data), and + // could lead to invalid interpretation. Just exit immediately, as we can't + // continue anyway, and all writes should be atomic. + std::abort(); + } +} diff --git a/src/coins.h b/src/coins.h index 482e233e8c..dca1beabb6 100644 --- a/src/coins.h +++ b/src/coins.h @@ -17,6 +17,7 @@ #include <assert.h> #include <stdint.h> +#include <functional> #include <unordered_map> /** @@ -315,4 +316,28 @@ void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool //! lookups to database, so it should be used with care. const Coin& AccessByTxid(const CCoinsViewCache& cache, const uint256& txid); +/** + * This is a minimally invasive approach to shutdown on LevelDB read errors from the + * chainstate, while keeping user interface out of the common library, which is shared + * between bitcoind, and bitcoin-qt and non-server tools. + * + * Writes do not need similar protection, as failure to write is handled by the caller. +*/ +class CCoinsViewErrorCatcher final : public CCoinsViewBacked +{ +public: + explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} + + void AddReadErrCallback(std::function<void()> f) { + m_err_callbacks.emplace_back(std::move(f)); + } + + bool GetCoin(const COutPoint &outpoint, Coin &coin) const override; + +private: + /** A list of callbacks to execute upon leveldb read error. */ + std::vector<std::function<void()>> m_err_callbacks; + +}; + #endif // BITCOIN_COINS_H diff --git a/src/httprpc.cpp b/src/httprpc.cpp index c7a119440b..306d718574 100644 --- a/src/httprpc.cpp +++ b/src/httprpc.cpp @@ -5,19 +5,20 @@ #include <httprpc.h> #include <chainparams.h> +#include <crypto/hmac_sha256.h> #include <httpserver.h> #include <key_io.h> #include <rpc/protocol.h> #include <rpc/server.h> #include <sync.h> -#include <util/system.h> -#include <util/strencodings.h> #include <ui_interface.h> +#include <util/strencodings.h> +#include <util/system.h> +#include <util/translation.h> #include <walletinitinterface.h> -#include <crypto/hmac_sha256.h> -#include <stdio.h> #include <memory> +#include <stdio.h> #include <boost/algorithm/string.hpp> // boost::trim @@ -218,7 +219,7 @@ static bool InitRPCAuthentication() LogPrintf("No rpcpassword set - using random cookie authentication.\n"); if (!GenerateAuthCookie(&strRPCUserColonPass)) { uiInterface.ThreadSafeMessageBox( - _("Error: A fatal internal error occurred, see debug.log for details"), // Same message as AbortNode + _("Error: A fatal internal error occurred, see debug.log for details").translated, // Same message as AbortNode "", CClientUIInterface::MSG_ERROR); return false; } diff --git a/src/index/txindex.cpp b/src/index/txindex.cpp index 929b85bfb5..62db38f894 100644 --- a/src/index/txindex.cpp +++ b/src/index/txindex.cpp @@ -6,6 +6,7 @@ #include <shutdown.h> #include <ui_interface.h> #include <util/system.h> +#include <util/translation.h> #include <validation.h> #include <boost/thread.hpp> @@ -137,7 +138,7 @@ bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& int64_t count = 0; LogPrintf("Upgrading txindex database... [0%%]\n"); - uiInterface.ShowProgress(_("Upgrading txindex database"), 0, true); + uiInterface.ShowProgress(_("Upgrading txindex database").translated, 0, true); int report_done = 0; const size_t batch_size = 1 << 24; // 16 MiB @@ -174,7 +175,7 @@ bool TxIndex::DB::MigrateData(CBlockTreeDB& block_tree_db, const CBlockLocator& (static_cast<uint32_t>(*(txid.begin() + 1)) << 0); int percentage_done = (int)(high_nibble * 100.0 / 65536.0 + 0.5); - uiInterface.ShowProgress(_("Upgrading txindex database"), percentage_done, true); + uiInterface.ShowProgress(_("Upgrading txindex database").translated, percentage_done, true); if (report_done < percentage_done/10) { LogPrintf("Upgrading txindex database... [%d%%]\n", percentage_done); report_done = percentage_done/10; diff --git a/src/init.cpp b/src/init.cpp index 26b2f9d6c2..b84c7dc93d 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -15,43 +15,46 @@ #include <blockfilter.h> #include <chain.h> #include <chainparams.h> +#include <coins.h> #include <compat/sanity.h> #include <consensus/validation.h> #include <fs.h> -#include <httpserver.h> #include <httprpc.h> +#include <httpserver.h> #include <index/blockfilterindex.h> -#include <interfaces/chain.h> #include <index/txindex.h> +#include <interfaces/chain.h> #include <key.h> -#include <validation.h> #include <miner.h> -#include <netbase.h> #include <net.h> #include <net_processing.h> +#include <netbase.h> #include <policy/feerate.h> #include <policy/fees.h> #include <policy/policy.h> #include <policy/settings.h> -#include <rpc/server.h> -#include <rpc/register.h> #include <rpc/blockchain.h> +#include <rpc/register.h> +#include <rpc/server.h> #include <rpc/util.h> -#include <script/standard.h> -#include <script/sigcache.h> #include <scheduler.h> +#include <script/sigcache.h> +#include <script/standard.h> #include <shutdown.h> -#include <util/threadnames.h> #include <timedata.h> +#include <torcontrol.h> #include <txdb.h> #include <txmempool.h> -#include <torcontrol.h> #include <ui_interface.h> -#include <util/system.h> #include <util/moneystr.h> +#include <util/system.h> +#include <util/threadnames.h> +#include <util/translation.h> #include <util/validation.h> +#include <validation.h> #include <validationinterface.h> #include <walletinitinterface.h> + #include <stdint.h> #include <stdio.h> @@ -117,7 +120,7 @@ NODISCARD static bool CreatePidFile() #endif return true; } else { - return InitError(strprintf(_("Unable to create the PID file '%s': %s"), GetPidFile().string(), std::strerror(errno))); + return InitError(strprintf(_("Unable to create the PID file '%s': %s").translated, GetPidFile().string(), std::strerror(errno))); } } @@ -146,31 +149,6 @@ NODISCARD static bool CreatePidFile() // shutdown thing. // -/** - * This is a minimally invasive approach to shutdown on LevelDB read errors from the - * chainstate, while keeping user interface out of the common library, which is shared - * between bitcoind, and bitcoin-qt and non-server tools. -*/ -class CCoinsViewErrorCatcher final : public CCoinsViewBacked -{ -public: - explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} - bool GetCoin(const COutPoint &outpoint, Coin &coin) const override { - try { - return CCoinsViewBacked::GetCoin(outpoint, coin); - } catch(const std::runtime_error& e) { - uiInterface.ThreadSafeMessageBox(_("Error reading from database, shutting down."), "", CClientUIInterface::MSG_ERROR); - LogPrintf("Error reading from database: %s\n", e.what()); - // Starting the shutdown sequence and returning false to the caller would be - // interpreted as 'entry not found' (as opposed to unable to read data), and - // could lead to invalid interpretation. Just exit immediately, as we can't - // continue anyway, and all writes should be atomic. - abort(); - } - } - // Writes do not need similar protection, as failure to write is handled by the caller. -}; - static std::unique_ptr<CCoinsViewErrorCatcher> pcoinscatcher; static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; @@ -566,20 +544,20 @@ std::string LicenseInfo() const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>"; const std::string URL_WEBSITE = "<https://bitcoincore.org>"; - return CopyrightHolders(strprintf(_("Copyright (C) %i-%i"), 2009, COPYRIGHT_YEAR) + " ") + "\n" + + return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009, COPYRIGHT_YEAR) + " ") + "\n" + "\n" + strprintf(_("Please contribute if you find %s useful. " - "Visit %s for further information about the software."), + "Visit %s for further information about the software.").translated, PACKAGE_NAME, URL_WEBSITE) + "\n" + - strprintf(_("The source code is available from %s."), + strprintf(_("The source code is available from %s.").translated, URL_SOURCE_CODE) + "\n" + "\n" + - _("This is experimental software.") + "\n" + - strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s"), "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" + + _("This is experimental software.").translated + "\n" + + strprintf(_("Distributed under the MIT software license, see the accompanying file %s or %s").translated, "COPYING", "<https://opensource.org/licenses/MIT>") + "\n" + "\n" + - strprintf(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard."), "<https://www.openssl.org>") + + strprintf(_("This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit %s and cryptographic software written by Eric Young and UPnP software written by Thomas Bernard.").translated, "<https://www.openssl.org>") + "\n"; } @@ -845,7 +823,7 @@ void InitParameterInteraction() static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) { - return strprintf(_("Cannot resolve -%s address: '%s'"), optname, strBind); + return strprintf(_("Cannot resolve -%s address: '%s'").translated, optname, strBind); } /** @@ -951,16 +929,16 @@ bool AppInitParameterInteraction() // on the command line or in this network's section of the config file. std::string network = gArgs.GetChainName(); for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) { - return InitError(strprintf(_("Config setting for %s only applied on %s network when in [%s] section."), arg, network, network)); + return InitError(strprintf(_("Config setting for %s only applied on %s network when in [%s] section.").translated, arg, network, network)); } // Warn if unrecognized section name are present in the config file. for (const auto& section : gArgs.GetUnrecognizedSections()) { - InitWarning(strprintf("%s:%i " + _("Section [%s] is not recognized."), section.m_file, section.m_line, section.m_name)); + InitWarning(strprintf("%s:%i " + _("Section [%s] is not recognized.").translated, section.m_file, section.m_line, section.m_name)); } if (!fs::is_directory(GetBlocksDir())) { - return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", "").c_str())); + return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist.").translated, gArgs.GetArg("-blocksdir", "").c_str())); } // parse and validate enabled filter types @@ -973,7 +951,7 @@ bool AppInitParameterInteraction() for (const auto& name : names) { BlockFilterType filter_type; if (!BlockFilterTypeByName(name, filter_type)) { - return InitError(strprintf(_("Unknown -blockfilterindex value %s."), name)); + return InitError(strprintf(_("Unknown -blockfilterindex value %s.").translated, name)); } g_enabled_filter_types.push_back(filter_type); } @@ -982,9 +960,9 @@ bool AppInitParameterInteraction() // if using block pruning, then disallow txindex if (gArgs.GetArg("-prune", 0)) { if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) - return InitError(_("Prune mode is incompatible with -txindex.")); + return InitError(_("Prune mode is incompatible with -txindex.").translated); if (!g_enabled_filter_types.empty()) { - return InitError(_("Prune mode is incompatible with -blockfilterindex.")); + return InitError(_("Prune mode is incompatible with -blockfilterindex.").translated); } } @@ -1009,11 +987,11 @@ bool AppInitParameterInteraction() #endif nMaxConnections = std::max(std::min<int>(nMaxConnections, fd_max - nBind - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS), 0); if (nFD < MIN_CORE_FILEDESCRIPTORS) - return InitError(_("Not enough file descriptors available.")); + return InitError(_("Not enough file descriptors available.").translated); nMaxConnections = std::min(nFD - MIN_CORE_FILEDESCRIPTORS - MAX_ADDNODE_CONNECTIONS, nMaxConnections); if (nMaxConnections < nUserMaxConnections) - InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); + InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations.").translated, nUserMaxConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags if (gArgs.IsArgSet("-debug")) { @@ -1024,7 +1002,7 @@ bool AppInitParameterInteraction() [](std::string cat){return cat == "0" || cat == "none";})) { for (const auto& cat : categories) { if (!LogInstance().EnableCategory(cat)) { - InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debug", cat)); + InitWarning(strprintf(_("Unsupported logging category %s=%s.").translated, "-debug", cat)); } } } @@ -1033,7 +1011,7 @@ bool AppInitParameterInteraction() // Now remove the logging categories which were explicitly excluded for (const std::string& cat : gArgs.GetArgs("-debugexclude")) { if (!LogInstance().DisableCategory(cat)) { - InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); + InitWarning(strprintf(_("Unsupported logging category %s=%s.").translated, "-debugexclude", cat)); } } @@ -1069,7 +1047,7 @@ bool AppInitParameterInteraction() int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) - return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); + return InitError(strprintf(_("-maxmempool must be at least %d MB").translated, std::ceil(nMempoolSizeMin / 1000000.0))); // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting. if (gArgs.IsArgSet("-incrementalrelayfee")) @@ -1092,7 +1070,7 @@ bool AppInitParameterInteraction() // block pruning; get the amount of disk space (in MiB) to allot for block & undo files int64_t nPruneArg = gArgs.GetArg("-prune", 0); if (nPruneArg < 0) { - return InitError(_("Prune cannot be configured with a negative value.")); + return InitError(_("Prune cannot be configured with a negative value.").translated); } nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024; if (nPruneArg == 1) { // manual pruning: -prune=1 @@ -1101,7 +1079,7 @@ bool AppInitParameterInteraction() fPruneMode = true; } else if (nPruneTarget) { if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { - return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); + return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number.").translated, MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); } LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024); fPruneMode = true; @@ -1183,10 +1161,10 @@ static bool LockDataDirectory(bool probeOnly) // Make sure only a single Bitcoin process is using the data directory. fs::path datadir = GetDataDir(); if (!DirIsWritable(datadir)) { - return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), datadir.string())); + return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions.").translated, datadir.string())); } if (!LockDirectory(datadir, ".lock", probeOnly)) { - return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running."), datadir.string(), PACKAGE_NAME)); + return InitError(strprintf(_("Cannot obtain a lock on data directory %s. %s is probably already running.").translated, datadir.string(), PACKAGE_NAME)); } return true; } @@ -1204,7 +1182,7 @@ bool AppInitSanityChecks() // Sanity check if (!InitSanityCheck()) - return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME)); + return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down.").translated, PACKAGE_NAME)); // Probe the data directory lock to give an early error message, if possible // We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened, @@ -1255,7 +1233,7 @@ bool AppInitMain(InitInterfaces& interfaces) LogPrintf("Config file: %s\n", config_file_path.string()); } else if (gArgs.IsArgSet("-conf")) { // Warn if no conf file exists at path provided by user - InitWarning(strprintf(_("The specified config file %s does not exist\n"), config_file_path.string())); + InitWarning(strprintf(_("The specified config file %s does not exist\n").translated, config_file_path.string())); } else { // Not categorizing as "Warning" because it's the default behavior LogPrintf("Config file: %s (not found, skipping)\n", config_file_path.string()); @@ -1315,7 +1293,7 @@ bool AppInitMain(InitInterfaces& interfaces) { uiInterface.InitMessage_connect(SetRPCWarmupStatus); if (!AppInitServers()) - return InitError(_("Unable to start HTTP server. See debug log for details.")); + return InitError(_("Unable to start HTTP server. See debug log for details.").translated); } // ********************************************************* Step 5: verify wallet database integrity @@ -1343,12 +1321,12 @@ bool AppInitMain(InitInterfaces& interfaces) std::vector<std::string> uacomments; for (const std::string& cmt : gArgs.GetArgs("-uacomment")) { if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) - return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); + return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters.").translated, cmt)); uacomments.push_back(cmt); } strSubVersion = FormatSubVersion(CLIENT_NAME, CLIENT_VERSION, uacomments); if (strSubVersion.size() > MAX_SUBVERSION_LENGTH) { - return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments."), + return InitError(strprintf(_("Total length of network version string (%i) exceeds maximum length (%i). Reduce the number or size of uacomments.").translated, strSubVersion.size(), MAX_SUBVERSION_LENGTH)); } @@ -1357,7 +1335,7 @@ bool AppInitMain(InitInterfaces& interfaces) for (const std::string& snet : gArgs.GetArgs("-onlynet")) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) - return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); + return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'").translated, snet)); nets.insert(net); } for (int n = 0; n < NET_MAX; n++) { @@ -1378,12 +1356,12 @@ bool AppInitMain(InitInterfaces& interfaces) if (proxyArg != "" && proxyArg != "0") { CService proxyAddr; if (!Lookup(proxyArg.c_str(), proxyAddr, 9050, fNameLookup)) { - return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); + return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'").translated, proxyArg)); } proxyType addrProxy = proxyType(proxyAddr, proxyRandomize); if (!addrProxy.IsValid()) - return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'"), proxyArg)); + return InitError(strprintf(_("Invalid -proxy address or hostname: '%s'").translated, proxyArg)); SetProxy(NET_IPV4, addrProxy); SetProxy(NET_IPV6, addrProxy); @@ -1402,11 +1380,11 @@ bool AppInitMain(InitInterfaces& interfaces) } else { CService onionProxy; if (!Lookup(onionArg.c_str(), onionProxy, 9050, fNameLookup)) { - return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); + return InitError(strprintf(_("Invalid -onion address or hostname: '%s'").translated, onionArg)); } proxyType addrOnion = proxyType(onionProxy, proxyRandomize); if (!addrOnion.IsValid()) - return InitError(strprintf(_("Invalid -onion address or hostname: '%s'"), onionArg)); + return InitError(strprintf(_("Invalid -onion address or hostname: '%s'").translated, onionArg)); SetProxy(NET_ONION, addrOnion); SetReachable(NET_ONION, true); } @@ -1481,7 +1459,7 @@ bool AppInitMain(InitInterfaces& interfaces) bool fReset = fReindex; std::string strLoadError; - uiInterface.InitMessage(_("Loading block index...")); + uiInterface.InitMessage(_("Loading block index...").translated); do { const int64_t load_block_index_start_time = GetTimeMillis(); @@ -1512,7 +1490,7 @@ bool AppInitMain(InitInterfaces& interfaces) // From here on out fReindex and fReset mean something different! if (!LoadBlockIndex(chainparams)) { if (ShutdownRequested()) break; - strLoadError = _("Error loading block database"); + strLoadError = _("Error loading block database").translated; break; } @@ -1520,13 +1498,13 @@ bool AppInitMain(InitInterfaces& interfaces) // (we're likely using a testnet datadir, or the other way around). if (!::BlockIndex().empty() && !LookupBlockIndex(chainparams.GetConsensus().hashGenesisBlock)) { - return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); + return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?").translated); } // Check for changed -prune state. What we are concerned about is a user who has pruned blocks // in the past, but is now trying to run unpruned. if (fHavePruned && !fPruneMode) { - strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain"); + strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain").translated; break; } @@ -1535,7 +1513,7 @@ bool AppInitMain(InitInterfaces& interfaces) // (otherwise we use the one already on disk). // This is called again in ThreadImport after the reindex completes. if (!fReindex && !LoadGenesisBlock(chainparams)) { - strLoadError = _("Error initializing block database"); + strLoadError = _("Error initializing block database").translated; break; } @@ -1544,17 +1522,22 @@ bool AppInitMain(InitInterfaces& interfaces) pcoinsdbview.reset(new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState)); pcoinscatcher.reset(new CCoinsViewErrorCatcher(pcoinsdbview.get())); + pcoinscatcher->AddReadErrCallback([]() { + uiInterface.ThreadSafeMessageBox( + _("Error reading from database, shutting down.").translated, + "", CClientUIInterface::MSG_ERROR); + }); // If necessary, upgrade from older database format. // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate if (!pcoinsdbview->Upgrade()) { - strLoadError = _("Error upgrading chainstate database"); + strLoadError = _("Error upgrading chainstate database").translated; break; } // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate if (!ReplayBlocks(chainparams, pcoinsdbview.get())) { - strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate."); + strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate.").translated; break; } @@ -1565,14 +1548,14 @@ bool AppInitMain(InitInterfaces& interfaces) if (!is_coinsview_empty) { // LoadChainTip sets ::ChainActive() based on pcoinsTip's best block if (!LoadChainTip(chainparams)) { - strLoadError = _("Error initializing block database"); + strLoadError = _("Error initializing block database").translated; break; } assert(::ChainActive().Tip() != nullptr); } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); - strLoadError = _("Error opening block database"); + strLoadError = _("Error opening block database").translated; break; } @@ -1580,9 +1563,9 @@ bool AppInitMain(InitInterfaces& interfaces) // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate. // It both disconnects blocks based on ::ChainActive(), and drops block data in // BlockIndex() based on lack of available witness data. - uiInterface.InitMessage(_("Rewinding blocks...")); + uiInterface.InitMessage(_("Rewinding blocks...").translated); if (!RewindBlockIndex(chainparams)) { - strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain"); + strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain").translated; break; } } @@ -1590,7 +1573,7 @@ bool AppInitMain(InitInterfaces& interfaces) try { LOCK(cs_main); if (!is_coinsview_empty) { - uiInterface.InitMessage(_("Verifying blocks...")); + uiInterface.InitMessage(_("Verifying blocks...").translated); if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n", MIN_BLOCKS_TO_KEEP); @@ -1601,19 +1584,19 @@ bool AppInitMain(InitInterfaces& interfaces) if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { strLoadError = _("The block database contains a block which appears to be from the future. " "This may be due to your computer's date and time being set incorrectly. " - "Only rebuild the block database if you are sure that your computer's date and time are correct"); + "Only rebuild the block database if you are sure that your computer's date and time are correct").translated; break; } if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview.get(), gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { - strLoadError = _("Corrupted block database detected"); + strLoadError = _("Corrupted block database detected").translated; break; } } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); - strLoadError = _("Error opening block database"); + strLoadError = _("Error opening block database").translated; break; } @@ -1625,7 +1608,7 @@ bool AppInitMain(InitInterfaces& interfaces) // first suggest a reindex if (!fReset) { bool fRet = uiInterface.ThreadSafeQuestion( - strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?"), + strLoadError + ".\n\n" + _("Do you want to rebuild the block database now?").translated, strLoadError + ".\nPlease restart with -reindex or -reindex-chainstate to recover.", "", CClientUIInterface::MSG_ERROR | CClientUIInterface::BTN_ABORT); if (fRet) { @@ -1682,7 +1665,7 @@ bool AppInitMain(InitInterfaces& interfaces) LogPrintf("Unsetting NODE_NETWORK on prune mode\n"); nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK); if (!fReindex) { - uiInterface.InitMessage(_("Pruning blockstore...")); + uiInterface.InitMessage(_("Pruning blockstore...").translated); ::ChainstateActive().PruneAndFlush(); } } @@ -1699,11 +1682,11 @@ bool AppInitMain(InitInterfaces& interfaces) // ********************************************************* Step 11: import blocks if (!CheckDiskSpace(GetDataDir())) { - InitError(strprintf(_("Error: Disk space is low for %s"), GetDataDir())); + InitError(strprintf(_("Error: Disk space is low for %s").translated, GetDataDir())); return false; } if (!CheckDiskSpace(GetBlocksDir())) { - InitError(strprintf(_("Error: Disk space is low for %s"), GetBlocksDir())); + InitError(strprintf(_("Error: Disk space is low for %s").translated, GetBlocksDir())); return false; } @@ -1797,7 +1780,7 @@ bool AppInitMain(InitInterfaces& interfaces) return InitError(ResolveErrMsg("whitebind", strBind)); } if (addrBind.GetPort() == 0) { - return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'"), strBind)); + return InitError(strprintf(_("Need to specify a port with -whitebind: '%s'").translated, strBind)); } connOptions.vWhiteBinds.push_back(addrBind); } @@ -1806,7 +1789,7 @@ bool AppInitMain(InitInterfaces& interfaces) CSubNet subnet; LookupSubNet(net.c_str(), subnet); if (!subnet.IsValid()) - return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'"), net)); + return InitError(strprintf(_("Invalid netmask specified in -whitelist: '%s'").translated, net)); connOptions.vWhitelistedRange.push_back(subnet); } @@ -1827,7 +1810,7 @@ bool AppInitMain(InitInterfaces& interfaces) // ********************************************************* Step 13: finished SetRPCWarmupFinished(); - uiInterface.InitMessage(_("Done loading")); + uiInterface.InitMessage(_("Done loading").translated); for (const auto& client : interfaces.chain_clients) { client->start(scheduler); diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 584d218dba..fd2fb6531b 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -54,6 +54,7 @@ class NodeImpl : public Node { public: NodeImpl() { m_interfaces.chain = MakeChain(); } + void initError(const std::string& message) override { InitError(message); } bool parseParameters(int argc, const char* const argv[], std::string& error) override { return gArgs.ParseParameters(argc, argv, error); diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 1ccd2a31b7..bb4b3e1fae 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -38,6 +38,9 @@ class Node public: virtual ~Node() {} + //! Send init error. + virtual void initError(const std::string& message) = 0; + //! Set command line arguments. virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index deb1618ceb..077dc1ab4d 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -33,31 +33,6 @@ namespace interfaces { namespace { -class PendingWalletTxImpl : public PendingWalletTx -{ -public: - explicit PendingWalletTxImpl(CWallet& wallet) : m_wallet(wallet) {} - - const CTransaction& get() override { return *m_tx; } - - bool commit(WalletValueMap value_map, - WalletOrderForm order_form, - std::string& reject_reason) override - { - auto locked_chain = m_wallet.chain().lock(); - LOCK(m_wallet.cs_wallet); - CValidationState state; - if (!m_wallet.CommitTransaction(m_tx, std::move(value_map), std::move(order_form), state)) { - reject_reason = state.GetRejectReason(); - return false; - } - return true; - } - - CTransactionRef m_tx; - CWallet& m_wallet; -}; - //! Construct wallet tx struct. WalletTx MakeWalletTx(interfaces::Chain::Lock& locked_chain, CWallet& wallet, const CWalletTx& wtx) { @@ -227,7 +202,7 @@ public: LOCK(m_wallet->cs_wallet); return m_wallet->ListLockedCoins(outputs); } - std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients, + CTransactionRef createTransaction(const std::vector<CRecipient>& recipients, const CCoinControl& coin_control, bool sign, int& change_pos, @@ -236,12 +211,26 @@ public: { auto locked_chain = m_wallet->chain().lock(); LOCK(m_wallet->cs_wallet); - auto pending = MakeUnique<PendingWalletTxImpl>(*m_wallet); - if (!m_wallet->CreateTransaction(*locked_chain, recipients, pending->m_tx, fee, change_pos, + CTransactionRef tx; + if (!m_wallet->CreateTransaction(*locked_chain, recipients, tx, fee, change_pos, fail_reason, coin_control, sign)) { return {}; } - return std::move(pending); + return tx; + } + bool commitTransaction(CTransactionRef tx, + WalletValueMap value_map, + WalletOrderForm order_form, + std::string& reject_reason) override + { + auto locked_chain = m_wallet->chain().lock(); + LOCK(m_wallet->cs_wallet); + CValidationState state; + if (!m_wallet->CommitTransaction(std::move(tx), std::move(value_map), std::move(order_form), state)) { + reject_reason = state.GetRejectReason(); + return false; + } + return true; } bool transactionCanBeAbandoned(const uint256& txid) override { return m_wallet->TransactionCanBeAbandoned(txid); } bool abandonTransaction(const uint256& txid) override diff --git a/src/interfaces/wallet.h b/src/interfaces/wallet.h index db47dbafaf..89e056b18b 100644 --- a/src/interfaces/wallet.h +++ b/src/interfaces/wallet.h @@ -34,7 +34,6 @@ struct CRecipient; namespace interfaces { class Handler; -class PendingWalletTx; struct WalletAddress; struct WalletBalances; struct WalletTx; @@ -134,13 +133,19 @@ public: virtual void listLockedCoins(std::vector<COutPoint>& outputs) = 0; //! Create transaction. - virtual std::unique_ptr<PendingWalletTx> createTransaction(const std::vector<CRecipient>& recipients, + virtual CTransactionRef createTransaction(const std::vector<CRecipient>& recipients, const CCoinControl& coin_control, bool sign, int& change_pos, CAmount& fee, std::string& fail_reason) = 0; + //! Commit transaction. + virtual bool commitTransaction(CTransactionRef tx, + WalletValueMap value_map, + WalletOrderForm order_form, + std::string& reject_reason) = 0; + //! Return whether transaction can be abandoned. virtual bool transactionCanBeAbandoned(const uint256& txid) = 0; @@ -288,21 +293,6 @@ public: virtual std::unique_ptr<Handler> handleCanGetAddressesChanged(CanGetAddressesChangedFn fn) = 0; }; -//! Tracking object returned by CreateTransaction and passed to CommitTransaction. -class PendingWalletTx -{ -public: - virtual ~PendingWalletTx() {} - - //! Get transaction data. - virtual const CTransaction& get() = 0; - - //! Send pending transaction and commit to wallet. - virtual bool commit(WalletValueMap value_map, - WalletOrderForm order_form, - std::string& reject_reason) = 0; -}; - //! Information about one wallet address. struct WalletAddress { diff --git a/src/net.cpp b/src/net.cpp index 7d11111b25..7d6eb31a7c 100644 --- a/src/net.cpp +++ b/src/net.cpp @@ -15,11 +15,12 @@ #include <consensus/consensus.h> #include <crypto/common.h> #include <crypto/sha256.h> -#include <primitives/transaction.h> #include <netbase.h> +#include <primitives/transaction.h> #include <scheduler.h> #include <ui_interface.h> #include <util/strencodings.h> +#include <util/translation.h> #ifdef WIN32 #include <string.h> @@ -36,6 +37,9 @@ #include <miniupnpc/miniwget.h> #include <miniupnpc/upnpcommands.h> #include <miniupnpc/upnperrors.h> +// The minimum supported miniUPnPc API version is set to 10. This keeps compatibility +// with Ubuntu 16.04 LTS and Debian 8 libminiupnpc-dev packages. +static_assert(MINIUPNPC_API_VERSION >= 10, "miniUPnPc API version >= 10 assumed"); #endif #include <unordered_map> @@ -1403,16 +1407,10 @@ static void ThreadMapPort() struct UPNPDev * devlist = nullptr; char lanaddr[64]; -#ifndef UPNPDISCOVER_SUCCESS - /* miniupnpc 1.5 */ - devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0); -#elif MINIUPNPC_API_VERSION < 14 - /* miniupnpc 1.6 */ int error = 0; +#if MINIUPNPC_API_VERSION < 14 devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, &error); #else - /* miniupnpc 1.9.20150730 */ - int error = 0; devlist = upnpDiscover(2000, multicastif, minissdpdpath, 0, 0, 2, &error); #endif @@ -1426,43 +1424,32 @@ static void ThreadMapPort() if (fDiscover) { char externalIPAddress[40]; r = UPNP_GetExternalIPAddress(urls.controlURL, data.first.servicetype, externalIPAddress); - if(r != UPNPCOMMAND_SUCCESS) + if (r != UPNPCOMMAND_SUCCESS) { LogPrintf("UPnP: GetExternalIPAddress() returned %d\n", r); - else - { - if(externalIPAddress[0]) - { + } else { + if (externalIPAddress[0]) { CNetAddr resolved; - if(LookupHost(externalIPAddress, resolved, false)) { + if (LookupHost(externalIPAddress, resolved, false)) { LogPrintf("UPnP: ExternalIPAddress = %s\n", resolved.ToString().c_str()); AddLocal(resolved, LOCAL_UPNP); } - } - else + } else { LogPrintf("UPnP: GetExternalIPAddress failed.\n"); + } } } - std::string strDesc = "Bitcoin " + FormatFullVersion(); + std::string strDesc = PACKAGE_NAME " " + FormatFullVersion(); do { -#ifndef UPNPDISCOVER_SUCCESS - /* miniupnpc 1.5 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0); -#else - /* miniupnpc 1.6 */ - r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, - port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); -#endif + r = UPNP_AddPortMapping(urls.controlURL, data.first.servicetype, port.c_str(), port.c_str(), lanaddr, strDesc.c_str(), "TCP", 0, "0"); - if(r!=UPNPCOMMAND_SUCCESS) - LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", - port, port, lanaddr, r, strupnperror(r)); - else + if (r != UPNPCOMMAND_SUCCESS) { + LogPrintf("AddPortMapping(%s, %s, %s) failed with code %d (%s)\n", port, port, lanaddr, r, strupnperror(r)); + } else { LogPrintf("UPnP Port Mapping successful.\n"); - } - while(g_upnp_interrupt.sleep_for(std::chrono::minutes(20))); + } + } while (g_upnp_interrupt.sleep_for(std::chrono::minutes(20))); r = UPNP_DeletePortMapping(urls.controlURL, data.first.servicetype, port.c_str(), "TCP", 0); LogPrintf("UPNP_DeletePortMapping() returned: %d\n", r); @@ -2039,9 +2026,9 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b { int nErr = WSAGetLastError(); if (nErr == WSAEADDRINUSE) - strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running."), addrBind.ToString(), PACKAGE_NAME); + strError = strprintf(_("Unable to bind to %s on this computer. %s is probably already running.").translated, addrBind.ToString(), PACKAGE_NAME); else - strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)"), addrBind.ToString(), NetworkErrorString(nErr)); + strError = strprintf(_("Unable to bind to %s on this computer (bind returned error %s)").translated, addrBind.ToString(), NetworkErrorString(nErr)); LogPrintf("%s\n", strError); CloseSocket(hListenSocket); return false; @@ -2051,7 +2038,7 @@ bool CConnman::BindListenPort(const CService &addrBind, std::string& strError, b // Listen for incoming connections if (listen(hListenSocket, SOMAXCONN) == SOCKET_ERROR) { - strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)"), NetworkErrorString(WSAGetLastError())); + strError = strprintf(_("Error: Listening for incoming connections failed (listen returned error %s)").translated, NetworkErrorString(WSAGetLastError())); LogPrintf("%s\n", strError); CloseSocket(hListenSocket); return false; @@ -2192,7 +2179,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) if (fListen && !InitBinds(connOptions.vBinds, connOptions.vWhiteBinds)) { if (clientInterface) { clientInterface->ThreadSafeMessageBox( - _("Failed to listen on any port. Use -listen=0 if you want this."), + _("Failed to listen on any port. Use -listen=0 if you want this.").translated, "", CClientUIInterface::MSG_ERROR); } return false; @@ -2203,7 +2190,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) } if (clientInterface) { - clientInterface->InitMessage(_("Loading P2P addresses...")); + clientInterface->InitMessage(_("Loading P2P addresses...").translated); } // Load addresses from peers.dat int64_t nStart = GetTimeMillis(); @@ -2218,7 +2205,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) } } - uiInterface.InitMessage(_("Starting network threads...")); + uiInterface.InitMessage(_("Starting network threads...").translated); fAddressesInitialized = true; @@ -2258,7 +2245,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) if (connOptions.m_use_addrman_outgoing && !connOptions.m_specified_outgoing.empty()) { if (clientInterface) { clientInterface->ThreadSafeMessageBox( - _("Cannot provide specific connections and have addrman find outgoing connections at the same."), + _("Cannot provide specific connections and have addrman find outgoing connections at the same.").translated, "", CClientUIInterface::MSG_ERROR); } return false; diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 4a9742f7b7..a3b6a92855 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -10,8 +10,8 @@ #include <qt/bitcoingui.h> #include <chainparams.h> -#include <qt/clientmodel.h> #include <fs.h> +#include <qt/clientmodel.h> #include <qt/guiconstants.h> #include <qt/guiutil.h> #include <qt/intro.h> @@ -25,20 +25,18 @@ #ifdef ENABLE_WALLET #include <qt/paymentserver.h> #include <qt/walletcontroller.h> -#endif +#include <qt/walletmodel.h> +#endif // ENABLE_WALLET #include <interfaces/handler.h> #include <interfaces/node.h> #include <noui.h> -#include <util/threadnames.h> #include <ui_interface.h> #include <uint256.h> #include <util/system.h> +#include <util/threadnames.h> #include <memory> -#include <stdint.h> - -#include <boost/thread.hpp> #include <QApplication> #include <QDebug> @@ -210,12 +208,6 @@ BitcoinApplication::~BitcoinApplication() delete window; window = nullptr; -#ifdef ENABLE_WALLET - delete paymentServer; - paymentServer = nullptr; - delete m_wallet_controller; - m_wallet_controller = nullptr; -#endif delete optionsModel; optionsModel = nullptr; delete platformStyle; @@ -331,24 +323,21 @@ void BitcoinApplication::initializeResult(bool success) { // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete qInfo() << "Platform customization:" << platformStyle->getName(); -#ifdef ENABLE_WALLET - m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this); -#ifdef ENABLE_BIP70 - PaymentServer::LoadRootCAs(); -#endif - if (paymentServer) { - paymentServer->setOptionsModel(optionsModel); -#ifdef ENABLE_BIP70 - connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK); -#endif - } -#endif - clientModel = new ClientModel(m_node, optionsModel); window->setClientModel(clientModel); #ifdef ENABLE_WALLET - window->setWalletController(m_wallet_controller); + if (WalletModel::isWalletEnabled()) { + m_wallet_controller = new WalletController(m_node, platformStyle, optionsModel, this); + window->setWalletController(m_wallet_controller); + if (paymentServer) { + paymentServer->setOptionsModel(optionsModel); +#ifdef ENABLE_BIP70 + PaymentServer::LoadRootCAs(); + connect(m_wallet_controller, &WalletController::coinsSent, paymentServer, &PaymentServer::fetchPaymentACK); #endif + } + } +#endif // ENABLE_WALLET // If -min option passed, start window minimized (iconified) or minimized to tray if (!gArgs.GetBoolArg("-min", false)) { @@ -462,8 +451,11 @@ int GuiMain(int argc, char* argv[]) SetupUIArgs(); std::string error; if (!node->parseParameters(argc, argv, error)) { + node->initError(strprintf("Error parsing command line arguments: %s\n", error)); + // Create a message box, because the gui has neither been created nor has subscribed to core signals QMessageBox::critical(nullptr, PACKAGE_NAME, - QObject::tr("Error parsing command line arguments: %1.").arg(QString::fromStdString(error))); + // message can not be translated because translations have not been initialized + QString::fromStdString("Error parsing command line arguments: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -499,11 +491,13 @@ int GuiMain(int argc, char* argv[]) /// - Do not call GetDataDir(true) before this step finishes if (!fs::is_directory(GetDataDir(false))) { + node->initError(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", ""))); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: Specified data directory \"%1\" does not exist.").arg(QString::fromStdString(gArgs.GetArg("-datadir", "")))); return EXIT_FAILURE; } if (!node->readConfigFiles(error)) { + node->initError(strprintf("Error reading configuration file: %s\n", error)); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: Cannot parse configuration file: %1.").arg(QString::fromStdString(error))); return EXIT_FAILURE; @@ -519,6 +513,7 @@ int GuiMain(int argc, char* argv[]) try { node->selectParams(gArgs.GetChainName()); } catch(std::exception &e) { + node->initError(strprintf("%s\n", e.what())); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what())); return EXIT_FAILURE; } @@ -546,8 +541,10 @@ int GuiMain(int argc, char* argv[]) // Start up the payment server early, too, so impatient users that click on // bitcoin: links repeatedly have their payment requests routed to this process: - app.createPaymentServer(); -#endif + if (WalletModel::isWalletEnabled()) { + app.createPaymentServer(); + } +#endif // ENABLE_WALLET /// 9. Main GUI initialization // Install global event filter that makes sure that long tooltips can be word-wrapped diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 370712d953..40537c1813 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -11,7 +11,6 @@ #include <QApplication> #include <memory> -#include <vector> class BitcoinGUI; class ClientModel; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index c9a09573f9..3533227483 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -36,9 +36,6 @@ #include <ui_interface.h> #include <util/system.h> -#include <iostream> -#include <memory> - #include <QAction> #include <QApplication> #include <QComboBox> diff --git a/src/qt/main.cpp b/src/qt/main.cpp index 6a3c2249d1..999c434d23 100644 --- a/src/qt/main.cpp +++ b/src/qt/main.cpp @@ -4,6 +4,8 @@ #include <qt/bitcoin.h> +#include <util/translation.h> + #include <QCoreApplication> #include <functional> diff --git a/src/qt/sendcoinsdialog.cpp b/src/qt/sendcoinsdialog.cpp index cb9efe9319..193fba78b1 100644 --- a/src/qt/sendcoinsdialog.cpp +++ b/src/qt/sendcoinsdialog.cpp @@ -392,7 +392,7 @@ void SendCoinsDialog::on_sendButton_clicked() accept(); CoinControlDialog::coinControl()->UnSelectAll(); coinControlUpdateLabels(); - Q_EMIT coinsSent(currentTransaction.getWtx()->get().GetHash()); + Q_EMIT coinsSent(currentTransaction.getWtx()->GetHash()); } fNewRecipientAllowed = true; } diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 98eeee1a47..5bceb1f945 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -16,6 +16,7 @@ #include <interfaces/wallet.h> #include <ui_interface.h> #include <util/system.h> +#include <util/translation.h> #include <version.h> #include <QApplication> @@ -167,8 +168,8 @@ static void InitMessage(SplashScreen *splash, const std::string &message) static void ShowProgress(SplashScreen *splash, const std::string &title, int nProgress, bool resume_possible) { InitMessage(splash, title + std::string("\n") + - (resume_possible ? _("(press q to shutdown and continue later)") - : _("press q to shutdown")) + + (resume_possible ? _("(press q to shutdown and continue later)").translated + : _("press q to shutdown").translated) + strprintf("\n%d", nProgress) + "%"); } #ifdef ENABLE_WALLET diff --git a/src/qt/walletmodel.cpp b/src/qt/walletmodel.cpp index 57406179f7..49a13330ec 100644 --- a/src/qt/walletmodel.cpp +++ b/src/qt/walletmodel.cpp @@ -261,11 +261,11 @@ WalletModel::SendCoinsReturn WalletModel::sendCoins(WalletModelTransaction &tran auto& newTx = transaction.getWtx(); std::string rejectReason; - if (!newTx->commit({} /* mapValue */, std::move(vOrderForm), rejectReason)) + if (!wallet().commitTransaction(newTx, {} /* mapValue */, std::move(vOrderForm), rejectReason)) return SendCoinsReturn(TransactionCommitFailed, QString::fromStdString(rejectReason)); CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); - ssTx << newTx->get(); + ssTx << *newTx; transaction_array.append(&(ssTx[0]), ssTx.size()); } diff --git a/src/qt/walletmodeltransaction.cpp b/src/qt/walletmodeltransaction.cpp index 8c0dc276b0..d00ccf70d9 100644 --- a/src/qt/walletmodeltransaction.cpp +++ b/src/qt/walletmodeltransaction.cpp @@ -21,14 +21,14 @@ QList<SendCoinsRecipient> WalletModelTransaction::getRecipients() const return recipients; } -std::unique_ptr<interfaces::PendingWalletTx>& WalletModelTransaction::getWtx() +CTransactionRef& WalletModelTransaction::getWtx() { return wtx; } unsigned int WalletModelTransaction::getTransactionSize() { - return wtx ? GetVirtualTransactionSize(wtx->get()) : 0; + return wtx ? GetVirtualTransactionSize(*wtx) : 0; } CAmount WalletModelTransaction::getTransactionFee() const @@ -43,7 +43,7 @@ void WalletModelTransaction::setTransactionFee(const CAmount& newFee) void WalletModelTransaction::reassignAmounts(int nChangePosRet) { - const CTransaction* walletTransaction = &wtx->get(); + const CTransaction* walletTransaction = wtx.get(); int i = 0; for (QList<SendCoinsRecipient>::iterator it = recipients.begin(); it != recipients.end(); ++it) { diff --git a/src/qt/walletmodeltransaction.h b/src/qt/walletmodeltransaction.h index 289aee847b..a41d8f2457 100644 --- a/src/qt/walletmodeltransaction.h +++ b/src/qt/walletmodeltransaction.h @@ -16,7 +16,6 @@ class SendCoinsRecipient; namespace interfaces { class Node; -class PendingWalletTx; } /** Data model for a walletmodel transaction. */ @@ -27,7 +26,7 @@ public: QList<SendCoinsRecipient> getRecipients() const; - std::unique_ptr<interfaces::PendingWalletTx>& getWtx(); + CTransactionRef& getWtx(); unsigned int getTransactionSize(); void setTransactionFee(const CAmount& newFee); @@ -39,7 +38,7 @@ public: private: QList<SendCoinsRecipient> recipients; - std::unique_ptr<interfaces::PendingWalletTx> wtx; + CTransactionRef wtx; CAmount fee; }; diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 532765b3d8..0ab504de06 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -760,7 +760,10 @@ static UniValue signrawtransactionwithkey(const JSONRPCRequest& request) static UniValue sendrawtransaction(const JSONRPCRequest& request) { RPCHelpMan{"sendrawtransaction", - "\nSubmits raw transaction (serialized, hex-encoded) to local node and network.\n" + "\nSubmit a raw transaction (serialized, hex-encoded) to local node and network.\n" + "\nNote that the transaction will be sent unconditionally to all peers, so using this\n" + "for manual rebroadcast may degrade privacy by leaking the transaction's origin, as\n" + "nodes will normally not rebroadcast non-wallet transactions already in their mempool.\n" "\nAlso see createrawtransaction and signrawtransactionwithkey calls.\n", { {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"}, diff --git a/src/test/setup_common.cpp b/src/test/setup_common.cpp index 24c7d51898..de877fd167 100644 --- a/src/test/setup_common.cpp +++ b/src/test/setup_common.cpp @@ -23,10 +23,13 @@ #include <util/memory.h> #include <util/strencodings.h> #include <util/time.h> +#include <util/translation.h> #include <util/validation.h> #include <validation.h> #include <validationinterface.h> +#include <functional> + const std::function<std::string(const char*)> G_TRANSLATION_FUN = nullptr; FastRandomContext g_insecure_rand_ctx; diff --git a/src/timedata.cpp b/src/timedata.cpp index f4613eeec8..9458b9ae0c 100644 --- a/src/timedata.cpp +++ b/src/timedata.cpp @@ -12,6 +12,7 @@ #include <sync.h> #include <ui_interface.h> #include <util/system.h> +#include <util/translation.h> #include <warnings.h> @@ -100,7 +101,7 @@ void AddTimeData(const CNetAddr& ip, int64_t nOffsetSample) if (!fMatch) { fDone = true; - std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly."), PACKAGE_NAME); + std::string strMessage = strprintf(_("Please check that your computer's date and time are correct! If your clock is wrong, %s will not work properly.").translated, PACKAGE_NAME); SetMiscWarning(strMessage); uiInterface.ThreadSafeMessageBox(strMessage, "", CClientUIInterface::MSG_WARNING); } diff --git a/src/txdb.cpp b/src/txdb.cpp index 90b92969b9..df9851396e 100644 --- a/src/txdb.cpp +++ b/src/txdb.cpp @@ -5,12 +5,13 @@ #include <txdb.h> -#include <random.h> #include <pow.h> +#include <random.h> #include <shutdown.h> +#include <ui_interface.h> #include <uint256.h> #include <util/system.h> -#include <ui_interface.h> +#include <util/translation.h> #include <stdint.h> @@ -357,7 +358,7 @@ bool CCoinsViewDB::Upgrade() { int64_t count = 0; LogPrintf("Upgrading utxo-set database...\n"); LogPrintf("[0%%]..."); /* Continued */ - uiInterface.ShowProgress(_("Upgrading UTXO database"), 0, true); + uiInterface.ShowProgress(_("Upgrading UTXO database").translated, 0, true); size_t batch_size = 1 << 24; CDBBatch batch(db); int reportDone = 0; @@ -372,7 +373,7 @@ bool CCoinsViewDB::Upgrade() { if (count++ % 256 == 0) { uint32_t high = 0x100 * *key.second.begin() + *(key.second.begin() + 1); int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5); - uiInterface.ShowProgress(_("Upgrading UTXO database"), percentageDone, true); + uiInterface.ShowProgress(_("Upgrading UTXO database").translated, percentageDone, true); if (reportDone < percentageDone/10) { // report max. every 10% step LogPrintf("[%d%%]...", percentageDone); /* Continued */ diff --git a/src/util/error.cpp b/src/util/error.cpp index 9331a92ad7..9edb7dc533 100644 --- a/src/util/error.cpp +++ b/src/util/error.cpp @@ -4,7 +4,9 @@ #include <util/error.h> +#include <tinyformat.h> #include <util/system.h> +#include <util/translation.h> std::string TransactionErrorString(const TransactionError err) { @@ -36,10 +38,10 @@ std::string TransactionErrorString(const TransactionError err) std::string AmountHighWarn(const std::string& optname) { - return strprintf(_("%s is set very high!"), optname); + return strprintf(_("%s is set very high!").translated, optname); } std::string AmountErrMsg(const char* const optname, const std::string& strValue) { - return strprintf(_("Invalid amount for -%s=<amount>: '%s'"), optname, strValue); + return strprintf(_("Invalid amount for -%s=<amount>: '%s'").translated, optname, strValue); } diff --git a/src/util/system.cpp b/src/util/system.cpp index 72b37b9187..c27b0cc105 100644 --- a/src/util/system.cpp +++ b/src/util/system.cpp @@ -7,6 +7,7 @@ #include <chainparamsbase.h> #include <util/strencodings.h> +#include <util/translation.h> #include <stdarg.h> @@ -1184,7 +1185,7 @@ int GetNumCores() std::string CopyrightHolders(const std::string& strPrefix) { - const auto copyright_devs = strprintf(_(COPYRIGHT_HOLDERS), COPYRIGHT_HOLDERS_SUBSTITUTION); + const auto copyright_devs = strprintf(_(COPYRIGHT_HOLDERS).translated, COPYRIGHT_HOLDERS_SUBSTITUTION); std::string strCopyrightHolders = strPrefix + copyright_devs; // Make sure Bitcoin Core copyright is not removed by accident diff --git a/src/util/system.h b/src/util/system.h index dda9156488..66a9eb4612 100644 --- a/src/util/system.h +++ b/src/util/system.h @@ -40,18 +40,6 @@ int64_t GetStartupTime(); extern const char * const BITCOIN_CONF_FILENAME; -/** Translate a message to the native language of the user. */ -const extern std::function<std::string(const char*)> G_TRANSLATION_FUN; - -/** - * Translation function. - * If no translation function is set, simply return the input. - */ -inline std::string _(const char* psz) -{ - return G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz; -} - void SetupEnvironment(); bool SetupNetworking(); diff --git a/src/util/translation.h b/src/util/translation.h new file mode 100644 index 0000000000..f100dab20d --- /dev/null +++ b/src/util/translation.h @@ -0,0 +1,42 @@ +// Copyright (c) 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. + +#ifndef BITCOIN_UTIL_TRANSLATION_H +#define BITCOIN_UTIL_TRANSLATION_H + +#include <tinyformat.h> + +#include <utility> + +/** + * Bilingual messages: + * - in GUI: user's native language + untranslated (i.e. English) + * - in log and stderr: untranslated only + */ +struct bilingual_str { + std::string original; + std::string translated; +}; + +namespace tinyformat { +template <typename... Args> +bilingual_str format(const bilingual_str& fmt, const Args&... args) +{ + return bilingual_str{format(fmt.original, args...), format(fmt.translated, args...)}; +} +} // namespace tinyformat + +/** Translate a message to the native language of the user. */ +const extern std::function<std::string(const char*)> G_TRANSLATION_FUN; + +/** + * Translation function. + * If no translation function is set, simply return the input. + */ +inline bilingual_str _(const char* psz) +{ + return bilingual_str{psz, G_TRANSLATION_FUN ? (G_TRANSLATION_FUN)(psz) : psz}; +} + +#endif // BITCOIN_UTIL_TRANSLATION_H diff --git a/src/validation.cpp b/src/validation.cpp index f585bc7d2d..b4677df62f 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -41,6 +41,7 @@ #include <util/rbf.h> #include <util/strencodings.h> #include <util/system.h> +#include <util/translation.h> #include <util/validation.h> #include <validationinterface.h> #include <warnings.h> @@ -617,6 +618,8 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool std::string errString; if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { setAncestors.clear(); + // If CalculateMemPoolAncestors fails second time, we want the original error string. + std::string dummy_err_string; // If the new transaction is relatively small (up to 40k weight) // and has at most one ancestor (ie ancestor limit of 2, including // the new transaction), allow it if its parent has exactly the @@ -628,7 +631,7 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool // outputs - one for each counterparty. For more info on the uses for // this, see https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-November/016518.html if (nSize > EXTRA_DESCENDANT_TX_SIZE_LIMIT || - !pool.CalculateMemPoolAncestors(entry, setAncestors, 2, nLimitAncestorSize, nLimitDescendants + 1, nLimitDescendantSize + EXTRA_DESCENDANT_TX_SIZE_LIMIT, errString)) { + !pool.CalculateMemPoolAncestors(entry, setAncestors, 2, nLimitAncestorSize, nLimitDescendants + 1, nLimitDescendantSize + EXTRA_DESCENDANT_TX_SIZE_LIMIT, dummy_err_string)) { return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); } } @@ -1408,7 +1411,7 @@ static bool AbortNode(const std::string& strMessage, const std::string& userMess if (!userMessage.empty()) { uiInterface.ThreadSafeMessageBox(userMessage, "", CClientUIInterface::MSG_ERROR | prefix); } else { - uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details"), "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX); + uiInterface.ThreadSafeMessageBox(_("Error: A fatal internal error occurred, see debug.log for details").translated, "", CClientUIInterface::MSG_ERROR | CClientUIInterface::MSG_NOPREFIX); } StartShutdown(); return false; @@ -2027,7 +2030,7 @@ bool CChainState::FlushStateToDisk( if (fDoFullFlush || fPeriodicWrite) { // Depend on nMinDiskSpace to ensure we can write block index if (!CheckDiskSpace(GetBlocksDir())) { - return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX); + return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX); } // First make sure all block and undo data is flushed to disk. FlushBlockFile(); @@ -2062,7 +2065,7 @@ bool CChainState::FlushStateToDisk( // an overestimation, as most will delete an existing entry or // overwrite one. Still, use a conservative safety factor of 2. if (!CheckDiskSpace(GetDataDir(), 48 * 2 * 2 * pcoinsTip->GetCacheSize())) { - return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX); + return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX); } // Flush the chainstate (which may refer to block index entries). if (!pcoinsTip->Flush()) @@ -2136,7 +2139,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar WarningBitsConditionChecker checker(bit); ThresholdState state = checker.GetStateFor(pindex, chainParams.GetConsensus(), warningcache[bit]); if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) { - const std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)"), bit); + const std::string strWarning = strprintf(_("Warning: unknown new rules activated (versionbit %i)").translated, bit); if (state == ThresholdState::ACTIVE) { DoWarning(strWarning); } else { @@ -2153,7 +2156,7 @@ void static UpdateTip(const CBlockIndex *pindexNew, const CChainParams& chainPar pindex = pindex->pprev; } if (nUpgraded > 0) - AppendWarning(warningMessages, strprintf(_("%d of last 100 blocks have unexpected version"), nUpgraded)); + AppendWarning(warningMessages, strprintf(_("%d of last 100 blocks have unexpected version").translated, nUpgraded)); } LogPrintf("%s: new best=%s height=%d version=0x%08x log2_work=%.8g tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)", __func__, /* Continued */ pindexNew->GetBlockHash().ToString(), pindexNew->nHeight, pindexNew->nVersion, @@ -2184,7 +2187,7 @@ bool CChainState::DisconnectTip(CValidationState& state, const CChainParams& cha std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>(); CBlock& block = *pblock; if (!ReadBlockFromDisk(block, pindexDelete, chainparams.GetConsensus())) - return AbortNode(state, "Failed to read block"); + return error("DisconnectTip(): Failed to read block"); // Apply the block atomically to the chain state. int64_t nStart = GetTimeMicros(); { @@ -2441,6 +2444,11 @@ bool CChainState::ActivateBestChainStep(CValidationState& state, const CChainPar // This is likely a fatal error, but keep the mempool consistent, // just in case. Only remove from the mempool in this case. UpdateMempoolForReorg(disconnectpool, false); + + // If we're unable to disconnect a block during normal operation, + // then that is a failure of our local system -- we should abort + // rather than stay on a less work chain. + AbortNode(state, "Failed to disconnect block; see debug.log for details"); return false; } fBlocksDisconnected = true; @@ -2930,7 +2938,7 @@ static bool FindBlockPos(FlatFilePos &pos, unsigned int nAddSize, unsigned int n bool out_of_space; size_t bytes_allocated = BlockFileSeq().Allocate(pos, nAddSize, out_of_space); if (out_of_space) { - return AbortNode("Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX); + return AbortNode("Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX); } if (bytes_allocated != 0 && fPruneMode) { fCheckForPruning = true; @@ -2954,7 +2962,7 @@ static bool FindUndoPos(CValidationState &state, int nFile, FlatFilePos &pos, un bool out_of_space; size_t bytes_allocated = UndoFileSeq().Allocate(pos, nAddSize, out_of_space); if (out_of_space) { - return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!"), CClientUIInterface::MSG_NOPREFIX); + return AbortNode(state, "Disk space is too low!", _("Error: Disk space is too low!").translated, CClientUIInterface::MSG_NOPREFIX); } if (bytes_allocated != 0 && fPruneMode) { fCheckForPruning = true; @@ -3875,7 +3883,7 @@ bool LoadChainTip(const CChainParams& chainparams) CVerifyDB::CVerifyDB() { - uiInterface.ShowProgress(_("Verifying blocks..."), 0, false); + uiInterface.ShowProgress(_("Verifying blocks...").translated, 0, false); } CVerifyDB::~CVerifyDB() @@ -3909,7 +3917,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, LogPrintf("[%d%%]...", percentageDone); /* Continued */ reportDone = percentageDone/10; } - uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); + uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false); if (pindex->nHeight <= ::ChainActive().Height()-nCheckDepth) break; if (fPruneMode && !(pindex->nStatus & BLOCK_HAVE_DATA)) { @@ -3967,7 +3975,7 @@ bool CVerifyDB::VerifyDB(const CChainParams& chainparams, CCoinsView *coinsview, LogPrintf("[%d%%]...", percentageDone); /* Continued */ reportDone = percentageDone/10; } - uiInterface.ShowProgress(_("Verifying blocks..."), percentageDone, false); + uiInterface.ShowProgress(_("Verifying blocks...").translated, percentageDone, false); pindex = ::ChainActive().Next(pindex); CBlock block; if (!ReadBlockFromDisk(block, pindex, chainparams.GetConsensus())) @@ -4014,7 +4022,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) if (hashHeads.empty()) return true; // We're already in a consistent state. if (hashHeads.size() != 2) return error("ReplayBlocks(): unknown inconsistent state"); - uiInterface.ShowProgress(_("Replaying blocks..."), 0, false); + uiInterface.ShowProgress(_("Replaying blocks...").translated, 0, false); LogPrintf("Replaying blocks\n"); const CBlockIndex* pindexOld = nullptr; // Old tip during the interrupted flush. @@ -4060,7 +4068,7 @@ bool CChainState::ReplayBlocks(const CChainParams& params, CCoinsView* view) for (int nHeight = nForkHeight + 1; nHeight <= pindexNew->nHeight; ++nHeight) { const CBlockIndex* pindex = pindexNew->GetAncestor(nHeight); LogPrintf("Rolling forward %s (%i)\n", pindex->GetBlockHash().ToString(), nHeight); - uiInterface.ShowProgress(_("Replaying blocks..."), (int) ((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)) , false); + uiInterface.ShowProgress(_("Replaying blocks...").translated, (int) ((nHeight - nForkHeight) * 100.0 / (pindexNew->nHeight - nForkHeight)) , false); if (!RollforwardBlock(pindex, cache, params)) return false; } diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index b5f90deabd..26aeb754ad 100644 --- a/src/wallet/db.cpp +++ b/src/wallet/db.cpp @@ -6,6 +6,7 @@ #include <wallet/db.h> #include <util/strencodings.h> +#include <util/translation.h> #include <stdint.h> @@ -404,7 +405,7 @@ bool BerkeleyBatch::VerifyEnvironment(const fs::path& file_path, std::string& er LogPrintf("Using wallet %s\n", file_path.string()); if (!env->Open(true /* retry */)) { - errorStr = strprintf(_("Error initializing wallet database environment %s!"), walletDir); + errorStr = strprintf(_("Error initializing wallet database environment %s!").translated, walletDir); return false; } @@ -426,12 +427,12 @@ bool BerkeleyBatch::VerifyDatabaseFile(const fs::path& file_path, std::string& w warningStr = strprintf(_("Warning: Wallet file corrupt, data salvaged!" " Original %s saved as %s in %s; if" " your balance or transactions are incorrect you should" - " restore from a backup."), + " restore from a backup.").translated, walletFile, backup_filename, walletDir); } if (r == BerkeleyEnvironment::VerifyResult::RECOVER_FAIL) { - errorStr = strprintf(_("%s corrupt, salvage failed"), walletFile); + errorStr = strprintf(_("%s corrupt, salvage failed").translated, walletFile); return false; } } @@ -584,7 +585,7 @@ BerkeleyBatch::BerkeleyBatch(BerkeleyDatabase& database, const char* pszMode, bo if (fCreate && !Exists(std::string("version"))) { bool fTmp = fReadOnly; fReadOnly = false; - WriteVersion(CLIENT_VERSION); + Write(std::string("version"), CLIENT_VERSION); fReadOnly = fTmp; } } diff --git a/src/wallet/db.h b/src/wallet/db.h index b3856fbaf9..94f41eaf16 100644 --- a/src/wallet/db.h +++ b/src/wallet/db.h @@ -399,17 +399,6 @@ public: return (ret == 0); } - bool ReadVersion(int& nVersion) - { - nVersion = 0; - return Read(std::string("version"), nVersion); - } - - bool WriteVersion(int nVersion) - { - return Write(std::string("version"), nVersion); - } - bool static Rewrite(BerkeleyDatabase& database, const char* pszSkip = nullptr); }; diff --git a/src/wallet/init.cpp b/src/wallet/init.cpp index 4c327c77ae..cb94799d9e 100644 --- a/src/wallet/init.cpp +++ b/src/wallet/init.cpp @@ -7,11 +7,12 @@ #include <interfaces/chain.h> #include <net.h> #include <outputtype.h> -#include <util/system.h> #include <util/moneystr.h> -#include <walletinitinterface.h> +#include <util/system.h> +#include <util/translation.h> #include <wallet/wallet.h> #include <wallet/walletutil.h> +#include <walletinitinterface.h> class WalletInit : public WalletInitInterface { public: @@ -121,7 +122,7 @@ bool WalletInit::ParameterInteraction() const if (gArgs.GetBoolArg("-sysperms", false)) return InitError("-sysperms is not allowed in combination with enabled wallet functionality"); if (gArgs.GetArg("-prune", 0) && gArgs.GetBoolArg("-rescan", false)) - return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.")); + return InitError(_("Rescans are not possible in pruned mode. You will need to use -reindex which will download the whole blockchain again.").translated); return true; } diff --git a/src/wallet/load.cpp b/src/wallet/load.cpp index 54aa12dba8..b5d3b8c305 100644 --- a/src/wallet/load.cpp +++ b/src/wallet/load.cpp @@ -8,6 +8,7 @@ #include <interfaces/chain.h> #include <scheduler.h> #include <util/system.h> +#include <util/translation.h> #include <wallet/wallet.h> bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wallet_files) @@ -18,14 +19,14 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal // 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())); + 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"), wallet_dir.string())); + 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"), wallet_dir.string())); + chain.initError(strprintf(_("Specified -walletdir \"%s\" is a relative path").translated, wallet_dir.string())); return false; } gArgs.ForceSetArg("-walletdir", canonical_wallet_dir.string()); @@ -33,7 +34,7 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal LogPrintf("Using wallet directory %s\n", GetWalletDir().string()); - chain.initMessage(_("Verifying wallet(s)...")); + 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 @@ -47,7 +48,7 @@ bool VerifyWallets(interfaces::Chain& chain, const std::vector<std::string>& wal WalletLocation location(wallet_file); if (!wallet_paths.insert(location.GetPath()).second) { - chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified."), wallet_file)); + chain.initError(strprintf(_("Error loading wallet %s. Duplicate -wallet filename specified.").translated, wallet_file)); return false; } diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp index 7e973194d9..a905cc0c55 100644 --- a/src/wallet/rpcdump.cpp +++ b/src/wallet/rpcdump.cpp @@ -16,9 +16,9 @@ #include <util/bip32.h> #include <util/system.h> #include <util/time.h> -#include <wallet/wallet.h> - +#include <util/translation.h> #include <wallet/rpcwallet.h> +#include <wallet/wallet.h> #include <stdint.h> #include <tuple> @@ -185,19 +185,15 @@ UniValue importprivkey(const JSONRPCRequest& request) } } - // Don't throw error in case a key is already there - if (pwallet->HaveKey(vchAddress)) { - return NullUniValue; + // Use timestamp of 1 to scan the whole chain + if (!pwallet->ImportPrivKeys({{vchAddress, key}}, 1)) { + throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); } - // whenever a key is imported, we need to scan the whole chain - pwallet->UpdateTimeFirstKey(1); - pwallet->mapKeyMetadata[vchAddress].nCreateTime = 1; - - if (!pwallet->AddKeyPubKey(key, pubkey)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding key to wallet"); + // Add the wpkh script for this key if possible + if (pubkey.IsCompressed()) { + pwallet->ImportScripts({GetScriptForDestination(WitnessV0KeyHash(vchAddress))}, 0 /* timestamp */); } - pwallet->LearnAllRelatedScripts(pubkey); } } if (fRescan) { @@ -235,42 +231,6 @@ UniValue abortrescan(const JSONRPCRequest& request) return true; } -static void ImportAddress(CWallet*, const CTxDestination& dest, const std::string& strLabel); -static void ImportScript(CWallet* const pwallet, const CScript& script, const std::string& strLabel, bool isRedeemScript) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) -{ - if (!isRedeemScript && ::IsMine(*pwallet, script) == ISMINE_SPENDABLE) { - throw JSONRPCError(RPC_WALLET_ERROR, "The wallet already contains the private key for this address or script"); - } - - pwallet->MarkDirty(); - - if (!pwallet->HaveWatchOnly(script) && !pwallet->AddWatchOnly(script, 0 /* nCreateTime */)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); - } - - if (isRedeemScript) { - const CScriptID id(script); - if (!pwallet->HaveCScript(id) && !pwallet->AddCScript(script)) { - throw JSONRPCError(RPC_WALLET_ERROR, "Error adding p2sh redeemScript to wallet"); - } - ImportAddress(pwallet, ScriptHash(id), strLabel); - } else { - CTxDestination destination; - if (ExtractDestination(script, destination)) { - pwallet->SetAddressBook(destination, strLabel, "receive"); - } - } -} - -static void ImportAddress(CWallet* const pwallet, const CTxDestination& dest, const std::string& strLabel) EXCLUSIVE_LOCKS_REQUIRED(pwallet->cs_wallet) -{ - CScript script = GetScriptForDestination(dest); - ImportScript(pwallet, script, strLabel, false); - // add to address book or update label - if (IsValidDestination(dest)) - pwallet->SetAddressBook(dest, strLabel, "receive"); -} - UniValue importaddress(const JSONRPCRequest& request) { std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request); @@ -341,10 +301,22 @@ UniValue importaddress(const JSONRPCRequest& request) if (fP2SH) { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Cannot use the p2sh flag with an address - use a script instead"); } - ImportAddress(pwallet, dest, strLabel); + + pwallet->MarkDirty(); + + pwallet->ImportScriptPubKeys(strLabel, {GetScriptForDestination(dest)}, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); } else if (IsHex(request.params[0].get_str())) { std::vector<unsigned char> data(ParseHex(request.params[0].get_str())); - ImportScript(pwallet, CScript(data.begin(), data.end()), strLabel, fP2SH); + CScript redeem_script(data.begin(), data.end()); + + std::set<CScript> scripts = {redeem_script}; + pwallet->ImportScripts(scripts, 0 /* timestamp */); + + if (fP2SH) { + scripts.insert(GetScriptForDestination(ScriptHash(CScriptID(redeem_script)))); + } + + pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); } else { throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script"); } @@ -529,11 +501,16 @@ UniValue importpubkey(const JSONRPCRequest& request) auto locked_chain = pwallet->chain().lock(); LOCK(pwallet->cs_wallet); + std::set<CScript> script_pub_keys; for (const auto& dest : GetAllDestinationsForKey(pubKey)) { - ImportAddress(pwallet, dest, strLabel); + script_pub_keys.insert(GetScriptForDestination(dest)); } - ImportScript(pwallet, GetScriptForRawPubKey(pubKey), strLabel, false); - pwallet->LearnAllRelatedScripts(pubKey); + + pwallet->MarkDirty(); + + pwallet->ImportScriptPubKeys(strLabel, script_pub_keys, true /* have_solving_data */, true /* apply_label */, 1 /* timestamp */); + + pwallet->ImportPubKeys({pubKey.GetID()}, {{pubKey.GetID(), pubKey}} , {} /* key_origins */, false /* add_keypool */, false /* internal */, 1 /* timestamp */); } if (fRescan) { @@ -607,7 +584,7 @@ UniValue importwallet(const JSONRPCRequest& request) // Use uiInterface.ShowProgress instead of pwallet.ShowProgress because pwallet.ShowProgress has a cancel button tied to AbortRescan which // we don't want for this progress bar showing the import progress. uiInterface.ShowProgress does not have a cancel button. - pwallet->chain().showProgress(strprintf("%s " + _("Importing..."), pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI + pwallet->chain().showProgress(strprintf("%s " + _("Importing...").translated, pwallet->GetDisplayName()), 0, false); // show progress dialog in GUI std::vector<std::tuple<CKey, int64_t, bool, std::string>> keys; std::vector<std::pair<CScript, int64_t>> scripts; while (file.good()) { @@ -664,18 +641,18 @@ UniValue importwallet(const JSONRPCRequest& request) CPubKey pubkey = key.GetPubKey(); assert(key.VerifyPubKey(pubkey)); CKeyID keyid = pubkey.GetID(); - if (pwallet->HaveKey(keyid)) { - pwallet->WalletLogPrintf("Skipping import of %s (key already present)\n", EncodeDestination(PKHash(keyid))); - continue; - } + pwallet->WalletLogPrintf("Importing %s...\n", EncodeDestination(PKHash(keyid))); - if (!pwallet->AddKeyPubKey(key, pubkey)) { + + if (!pwallet->ImportPrivKeys({{keyid, key}}, time)) { + pwallet->WalletLogPrintf("Error importing key for %s\n", EncodeDestination(PKHash(keyid))); fGood = false; continue; } - pwallet->mapKeyMetadata[keyid].nCreateTime = time; + if (has_label) pwallet->SetAddressBook(PKHash(keyid), label, "receive"); + nTimeBegin = std::min(nTimeBegin, time); progress++; } @@ -683,24 +660,19 @@ UniValue importwallet(const JSONRPCRequest& request) pwallet->chain().showProgress("", std::max(50, std::min(75, (int)((progress / total) * 100) + 50)), false); const CScript& script = script_pair.first; int64_t time = script_pair.second; - CScriptID id(script); - if (pwallet->HaveCScript(id)) { - pwallet->WalletLogPrintf("Skipping import of %s (script already present)\n", HexStr(script)); - continue; - } - if(!pwallet->AddCScript(script)) { + + if (!pwallet->ImportScripts({script}, time)) { pwallet->WalletLogPrintf("Error importing script %s\n", HexStr(script)); fGood = false; continue; } if (time > 0) { - pwallet->m_script_metadata[id].nCreateTime = time; nTimeBegin = std::min(nTimeBegin, time); } + progress++; } pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI - pwallet->UpdateTimeFirstKey(nTimeBegin); } pwallet->chain().showProgress("", 100, false); // hide progress dialog in GUI RescanWallet(*pwallet, reserver, nTimeBegin, false /* update */); @@ -1255,7 +1227,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con // All good, time to import pwallet->MarkDirty(); - if (!pwallet->ImportScripts(import_data.import_scripts)) { + if (!pwallet->ImportScripts(import_data.import_scripts, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding script to wallet"); } if (!pwallet->ImportPrivKeys(privkey_map, timestamp)) { @@ -1264,7 +1236,7 @@ static UniValue ProcessImport(CWallet * const pwallet, const UniValue& data, con if (!pwallet->ImportPubKeys(ordered_pubkeys, pubkey_map, import_data.key_origins, add_keypool, internal, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } - if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, internal, timestamp)) { + if (!pwallet->ImportScriptPubKeys(label, script_pub_keys, have_solving_data, !internal, timestamp)) { throw JSONRPCError(RPC_WALLET_ERROR, "Error adding address to wallet"); } diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index ab732dc0d8..f95d025815 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2690,14 +2690,16 @@ static UniValue createwallet(const JSONRPCRequest& request) std::string error; std::string warning; - WalletCreationStatus status; - std::shared_ptr<CWallet> wallet = CreateWallet(*g_rpc_interfaces->chain, request.params[0].get_str(), error, warning, status, passphrase, flags); - if (status == WalletCreationStatus::CREATION_FAILED) { - throw JSONRPCError(RPC_WALLET_ERROR, error); - } else if (status == WalletCreationStatus::ENCRYPTION_FAILED) { - throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error); - } else if (status != WalletCreationStatus::SUCCESS) { - throw JSONRPCError(RPC_WALLET_ERROR, "Wallet creation failed"); + std::shared_ptr<CWallet> wallet; + WalletCreationStatus status = CreateWallet(*g_rpc_interfaces->chain, passphrase, flags, request.params[0].get_str(), error, warning, wallet); + switch (status) { + case WalletCreationStatus::CREATION_FAILED: + throw JSONRPCError(RPC_WALLET_ERROR, error); + case WalletCreationStatus::ENCRYPTION_FAILED: + throw JSONRPCError(RPC_WALLET_ENCRYPTION_FAILED, error); + case WalletCreationStatus::SUCCESS: + break; + // no default case, so the compiler can warn about missing cases } UniValue obj(UniValue::VOBJ); @@ -3263,12 +3265,12 @@ static UniValue bumpfee(const JSONRPCRequest& request) "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n" "An opt-in RBF transaction with the given txid must be in the wallet.\n" "The command will pay the additional fee by reducing change outputs or adding inputs when necessary. It may add a new change output if one does not already exist.\n" - "If `totalFee` is given, adding inputs is not supported, so there must be a single change output that is big enough or it will fail.\n" + "If `totalFee` (DEPRECATED) is given, adding inputs is not supported, so there must be a single change output that is big enough or it will fail.\n" "All inputs in the original transaction will be included in the replacement transaction.\n" "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n" "By default, the new fee will be calculated automatically using estimatesmartfee.\n" "The user can specify a confirmation target for estimatesmartfee.\n" - "Alternatively, the user can specify totalFee, or use RPC settxfee to set a higher fee rate.\n" + "Alternatively, the user can specify totalFee (DEPRECATED), or use RPC settxfee to set a higher fee rate.\n" "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n" "returned by getnetworkinfo) to enter the node's mempool.\n", { @@ -3276,7 +3278,7 @@ static UniValue bumpfee(const JSONRPCRequest& request) {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "", { {"confTarget", RPCArg::Type::NUM, /* default */ "fallback to wallet's default", "Confirmation target (in blocks)"}, - {"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis.\n" + {"totalFee", RPCArg::Type::NUM, /* default */ "fallback to 'confTarget'", "Total fee (NOT feerate) to pay, in satoshis. (DEPRECATED)\n" " In rare cases, the actual fee paid might be slightly higher than the specified\n" " totalFee if the tx change output has to be removed because it is too close to\n" " the dust threshold."}, @@ -3331,6 +3333,9 @@ static UniValue bumpfee(const JSONRPCRequest& request) } else if (options.exists("confTarget")) { // TODO: alias this to conf_target coin_control.m_confirm_target = ParseConfirmTarget(options["confTarget"], pwallet->chain().estimateMaxBlocks()); } else if (options.exists("totalFee")) { + if (!pwallet->chain().rpcEnableDeprecated("totalFee")) { + throw JSONRPCError(RPC_INVALID_PARAMETER, "totalFee argument has been deprecated and will be removed in 0.20. Please use -deprecatedrpc=totalFee to continue using this argument until removal."); + } totalFee = options["totalFee"].get_int64(); if (totalFee <= 0) { throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Invalid totalFee %s (must be greater than 0)", FormatMoney(totalFee))); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index 452d4f7a6a..638ed569c3 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -25,6 +25,7 @@ #include <util/fees.h> #include <util/moneystr.h> #include <util/rbf.h> +#include <util/translation.h> #include <util/validation.h> #include <validation.h> #include <wallet/coincontrol.h> @@ -160,7 +161,7 @@ std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const std::string& return LoadWallet(chain, WalletLocation(name), error, warning); } -std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning, WalletCreationStatus& status, const SecureString& passphrase, uint64_t wallet_creation_flags) +WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::shared_ptr<CWallet>& result) { // Indicate that the wallet is actually supposed to be blank and not just blank to make it encrypted bool create_blank = (wallet_creation_flags & WALLET_FLAG_BLANK_WALLET); @@ -174,39 +175,40 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin WalletLocation location(name); if (location.Exists()) { error = "Wallet " + location.GetName() + " already exists."; - status = WalletCreationStatus::CREATION_FAILED; - return nullptr; + return WalletCreationStatus::CREATION_FAILED; } // Wallet::Verify will check if we're trying to create a wallet with a duplicate name. std::string wallet_error; if (!CWallet::Verify(chain, location, false, wallet_error, warning)) { error = "Wallet file verification failed: " + wallet_error; - status = WalletCreationStatus::CREATION_FAILED; - return nullptr; + return WalletCreationStatus::CREATION_FAILED; + } + + // Do not allow a passphrase when private keys are disabled + if (!passphrase.empty() && (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { + error = "Passphrase provided but private keys are disabled. A passphrase is only used to encrypt private keys, so cannot be used for wallets with private keys disabled."; + return WalletCreationStatus::CREATION_FAILED; } // Make the wallet std::shared_ptr<CWallet> wallet = CWallet::CreateWalletFromFile(chain, location, wallet_creation_flags); if (!wallet) { error = "Wallet creation failed"; - status = WalletCreationStatus::CREATION_FAILED; - return nullptr; + return WalletCreationStatus::CREATION_FAILED; } // Encrypt the wallet if (!passphrase.empty() && !(wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { if (!wallet->EncryptWallet(passphrase)) { error = "Error: Wallet created but failed to encrypt."; - status = WalletCreationStatus::ENCRYPTION_FAILED; - return nullptr; + return WalletCreationStatus::ENCRYPTION_FAILED; } if (!create_blank) { // Unlock the wallet if (!wallet->Unlock(passphrase)) { error = "Error: Wallet was encrypted but could not be unlocked"; - status = WalletCreationStatus::ENCRYPTION_FAILED; - return nullptr; + return WalletCreationStatus::ENCRYPTION_FAILED; } // Set a seed for the wallet @@ -220,8 +222,8 @@ std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::strin } AddWallet(wallet); wallet->postInitProcess(); - status = WalletCreationStatus::SUCCESS; - return wallet; + result = wallet; + return WalletCreationStatus::SUCCESS; } const uint32_t BIP32_HARDENED_KEY_LIMIT = 0x80000000; @@ -1776,14 +1778,27 @@ bool CWallet::DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> return true; } -bool CWallet::ImportScripts(const std::set<CScript> scripts) +bool CWallet::ImportScripts(const std::set<CScript> scripts, int64_t timestamp) { WalletBatch batch(*database); for (const auto& entry : scripts) { - if (!HaveCScript(CScriptID(entry)) && !AddCScriptWithDB(batch, entry)) { + CScriptID id(entry); + if (HaveCScript(id)) { + WalletLogPrintf("Already have script %s, skipping\n", HexStr(entry)); + continue; + } + if (!AddCScriptWithDB(batch, entry)) { return false; } + + if (timestamp > 0) { + m_script_metadata[CScriptID(entry)].nCreateTime = timestamp; + } + } + if (timestamp > 0) { + UpdateTimeFirstKey(timestamp); } + return true; } @@ -1795,9 +1810,14 @@ bool CWallet::ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const in CPubKey pubkey = key.GetPubKey(); const CKeyID& id = entry.first; assert(key.VerifyPubKey(pubkey)); + // Skip if we already have the key + if (HaveKey(id)) { + WalletLogPrintf("Already have key with pubkey %s, skipping\n", HexStr(pubkey)); + continue; + } mapKeyMetadata[id].nCreateTime = timestamp; // If the private key is not present in the wallet, insert it. - if (!HaveKey(id) && !AddKeyPubKeyWithDB(batch, key, pubkey)) { + if (!AddKeyPubKeyWithDB(batch, key, pubkey)) { return false; } UpdateTimeFirstKey(timestamp); @@ -1818,7 +1838,12 @@ bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const st } const CPubKey& pubkey = entry->second; CPubKey temp; - if (!GetPubKey(id, temp) && !AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) { + if (GetPubKey(id, temp)) { + // Already have pubkey, skipping + WalletLogPrintf("Already have pubkey %s, skipping\n", HexStr(temp)); + continue; + } + if (!AddWatchOnlyWithDB(batch, GetScriptForRawPubKey(pubkey), timestamp)) { return false; } mapKeyMetadata[id].nCreateTime = timestamp; @@ -1832,7 +1857,7 @@ bool CWallet::ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const st return true; } -bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool internal, const int64_t timestamp) +bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) { WalletBatch batch(*database); for (const CScript& script : script_pub_keys) { @@ -1843,7 +1868,7 @@ bool CWallet::ImportScriptPubKeys(const std::string& label, const std::set<CScri } CTxDestination dest; ExtractDestination(script, dest); - if (!internal && IsValidDestination(dest)) { + if (apply_label && IsValidDestination(dest)) { SetAddressBookWithDB(batch, dest, label, "receive"); } } @@ -2013,7 +2038,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc WalletLogPrintf("Rescan started from block %s...\n", start_block.ToString()); fAbortRescan = false; - ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup + ShowProgress(strprintf("%s " + _("Rescanning...").translated, GetDisplayName()), 0); // show rescan progress in GUI as dialog or on splashscreen, if -rescan on startup uint256 tip_hash; // The way the 'block_height' is initialized is just a workaround for the gcc bug #47679 since version 4.6.0. Optional<int> block_height = MakeOptional(false, int()); @@ -2032,7 +2057,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc while (block_height && !fAbortRescan && !chain().shutdownRequested()) { m_scanning_progress = (progress_current - progress_begin) / (progress_end - progress_begin); if (*block_height % 100 == 0 && progress_end - progress_begin > 0.0) { - ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100)))); + ShowProgress(strprintf("%s " + _("Rescanning...").translated, GetDisplayName()), std::max(1, std::min(99, (int)(m_scanning_progress * 100)))); } if (GetTime() >= nNow + 60) { nNow = GetTime(); @@ -2088,7 +2113,7 @@ CWallet::ScanResult CWallet::ScanForWalletTransactions(const uint256& start_bloc } } } - ShowProgress(strprintf("%s " + _("Rescanning..."), GetDisplayName()), 100); // hide progress dialog in GUI + ShowProgress(strprintf("%s " + _("Rescanning...").translated, GetDisplayName()), 100); // hide progress dialog in GUI if (block_height && fAbortRescan) { WalletLogPrintf("Rescan aborted at block %d. Progress=%f\n", *block_height, progress_current); result.status = ScanResult::USER_ABORT; @@ -2907,7 +2932,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std { if (nValue < 0 || recipient.nAmount < 0) { - strFailReason = _("Transaction amounts must not be negative"); + strFailReason = _("Transaction amounts must not be negative").translated; return false; } nValue += recipient.nAmount; @@ -2917,7 +2942,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std } if (vecSend.empty()) { - strFailReason = _("Transaction must have at least one recipient"); + strFailReason = _("Transaction must have at least one recipient").translated; return false; } @@ -2955,7 +2980,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std // Reserve a new key pair from key pool if (!CanGetAddresses(true)) { - strFailReason = _("Can't generate a change-address key. No keys in the internal keypool and can't generate any keys."); + strFailReason = _("Can't generate a change-address key. No keys in the internal keypool and can't generate any keys.").translated; return false; } CTxDestination dest; @@ -3021,12 +3046,12 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std if (recipient.fSubtractFeeFromAmount && nFeeRet > 0) { if (txout.nValue < 0) - strFailReason = _("The transaction amount is too small to pay the fee"); + strFailReason = _("The transaction amount is too small to pay the fee").translated; else - strFailReason = _("The transaction amount is too small to send after the fee has been deducted"); + strFailReason = _("The transaction amount is too small to send after the fee has been deducted").translated; } else - strFailReason = _("Transaction amount too small"); + strFailReason = _("Transaction amount too small").translated; return false; } txNew.vout.push_back(txout); @@ -3054,7 +3079,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std continue; } else { - strFailReason = _("Insufficient funds"); + strFailReason = _("Insufficient funds").translated; return false; } } @@ -3085,7 +3110,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std } else if ((unsigned int)nChangePosInOut > txNew.vout.size()) { - strFailReason = _("Change index out of range"); + strFailReason = _("Change index out of range").translated; return false; } @@ -3104,14 +3129,14 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std nBytes = CalculateMaximumSignedTxSize(CTransaction(txNew), this, coin_control.fAllowWatchOnly); if (nBytes < 0) { - strFailReason = _("Signing transaction failed"); + strFailReason = _("Signing transaction failed").translated; return false; } nFeeNeeded = GetMinimumFee(*this, nBytes, coin_control, &feeCalc); if (feeCalc.reason == FeeReason::FALLBACK && !m_allow_fallback_fee) { // eventually allow a fallback fee - strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee."); + strFailReason = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.").translated; return false; } @@ -3151,7 +3176,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std // fee to pay for the new output and still meet nFeeNeeded // Or we should have just subtracted fee from recipients and // nFeeNeeded should not have changed - strFailReason = _("Transaction fee and change calculation failed"); + strFailReason = _("Transaction fee and change calculation failed").translated; return false; } @@ -3208,7 +3233,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std if (!ProduceSignature(*this, MutableTransactionSignatureCreator(&txNew, nIn, coin.txout.nValue, SIGHASH_ALL), scriptPubKey, sigdata)) { - strFailReason = _("Signing transaction failed"); + strFailReason = _("Signing transaction failed").translated; return false; } else { UpdateInput(txNew.vin.at(nIn), sigdata); @@ -3224,7 +3249,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std // Limit size if (GetTransactionWeight(*tx) > MAX_STANDARD_TX_WEIGHT) { - strFailReason = _("Transaction too large"); + strFailReason = _("Transaction too large").translated; return false; } } @@ -3237,7 +3262,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) { // Lastly, ensure this tx will pass the mempool's chain limits if (!chain().checkChainLimits(tx)) { - strFailReason = _("Transaction has too long of a mempool chain"); + strFailReason = _("Transaction has too long of a mempool chain").translated; return false; } } @@ -4225,17 +4250,17 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, std::vector<CWalletTx> vWtx; if (gArgs.GetBoolArg("-zapwallettxes", false)) { - chain.initMessage(_("Zapping all transactions from wallet...")); + chain.initMessage(_("Zapping all transactions from wallet...").translated); std::unique_ptr<CWallet> tempWallet = MakeUnique<CWallet>(&chain, location, WalletDatabase::Create(location.GetPath())); DBErrors nZapWalletRet = tempWallet->ZapWalletTx(vWtx); if (nZapWalletRet != DBErrors::LOAD_OK) { - chain.initError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + chain.initError(strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile)); return nullptr; } } - chain.initMessage(_("Loading wallet...")); + chain.initMessage(_("Loading wallet...").translated); int64_t nStart = GetTimeMillis(); bool fFirstRun = true; @@ -4246,26 +4271,26 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if (nLoadWalletRet != DBErrors::LOAD_OK) { if (nLoadWalletRet == DBErrors::CORRUPT) { - chain.initError(strprintf(_("Error loading %s: Wallet corrupted"), walletFile)); + chain.initError(strprintf(_("Error loading %s: Wallet corrupted").translated, walletFile)); return nullptr; } else if (nLoadWalletRet == DBErrors::NONCRITICAL_ERROR) { chain.initWarning(strprintf(_("Error reading %s! All keys read correctly, but transaction data" - " or address book entries might be missing or incorrect."), + " or address book entries might be missing or incorrect.").translated, walletFile)); } else if (nLoadWalletRet == DBErrors::TOO_NEW) { - chain.initError(strprintf(_("Error loading %s: Wallet requires newer version of %s"), walletFile, PACKAGE_NAME)); + chain.initError(strprintf(_("Error loading %s: Wallet requires newer version of %s").translated, walletFile, PACKAGE_NAME)); return nullptr; } else if (nLoadWalletRet == DBErrors::NEED_REWRITE) { - chain.initError(strprintf(_("Wallet needed to be rewritten: restart %s to complete"), PACKAGE_NAME)); + chain.initError(strprintf(_("Wallet needed to be rewritten: restart %s to complete").translated, PACKAGE_NAME)); return nullptr; } else { - chain.initError(strprintf(_("Error loading %s"), walletFile)); + chain.initError(strprintf(_("Error loading %s").translated, walletFile)); return nullptr; } } @@ -4284,7 +4309,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, walletInstance->WalletLogPrintf("Allowing wallet upgrade up to %i\n", nMaxVersion); if (nMaxVersion < walletInstance->GetVersion()) { - chain.initError(_("Cannot downgrade wallet")); + chain.initError(_("Cannot downgrade wallet").translated); return nullptr; } walletInstance->SetMaxVersion(nMaxVersion); @@ -4297,7 +4322,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, // Do not upgrade versions to any version between HD_SPLIT and FEATURE_PRE_SPLIT_KEYPOOL unless already supporting HD_SPLIT int max_version = walletInstance->GetVersion(); if (!walletInstance->CanSupportFeature(FEATURE_HD_SPLIT) && max_version >= FEATURE_HD_SPLIT && max_version < FEATURE_PRE_SPLIT_KEYPOOL) { - chain.initError(_("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.")); + chain.initError(_("Cannot upgrade a non HD split wallet without upgrading to support pre split keypool. Please use -upgradewallet=169900 or -upgradewallet with no version specified.").translated); return nullptr; } @@ -4325,7 +4350,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, // Regenerate the keypool if upgraded to HD if (hd_upgrade) { if (!walletInstance->TopUpKeyPool()) { - chain.initError(_("Unable to generate keys")); + chain.initError(_("Unable to generate keys").translated); return nullptr; } } @@ -4345,7 +4370,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, // Top up the keypool if (walletInstance->CanGenerateKeys() && !walletInstance->TopUpKeyPool()) { - chain.initError(_("Unable to generate initial keys")); + chain.initError(_("Unable to generate initial keys").translated); return nullptr; } @@ -4353,12 +4378,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, walletInstance->ChainStateFlushed(locked_chain->getTipLocator()); } else if (wallet_creation_flags & WALLET_FLAG_DISABLE_PRIVATE_KEYS) { // Make it impossible to disable private keys after creation - chain.initError(strprintf(_("Error loading %s: Private keys can only be disabled during creation"), walletFile)); + chain.initError(strprintf(_("Error loading %s: Private keys can only be disabled during creation").translated, walletFile)); return NULL; } else if (walletInstance->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS)) { LOCK(walletInstance->cs_KeyStore); if (!walletInstance->mapKeys.empty() || !walletInstance->mapCryptedKeys.empty()) { - chain.initWarning(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys"), walletFile)); + chain.initWarning(strprintf(_("Warning: Private keys detected in wallet {%s} with disabled private keys").translated, walletFile)); } } @@ -4380,21 +4405,21 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, } if (n > HIGH_TX_FEE_PER_KB) { chain.initWarning(AmountHighWarn("-mintxfee") + " " + - _("This is the minimum transaction fee you pay on every transaction.")); + _("This is the minimum transaction fee you pay on every transaction.").translated); } walletInstance->m_min_fee = CFeeRate(n); } - walletInstance->m_allow_fallback_fee = Params().IsFallbackFeeEnabled(); + walletInstance->m_allow_fallback_fee = Params().IsTestChain(); if (gArgs.IsArgSet("-fallbackfee")) { CAmount nFeePerK = 0; if (!ParseMoney(gArgs.GetArg("-fallbackfee", ""), nFeePerK)) { - chain.initError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), gArgs.GetArg("-fallbackfee", ""))); + chain.initError(strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'").translated, gArgs.GetArg("-fallbackfee", ""))); return nullptr; } if (nFeePerK > HIGH_TX_FEE_PER_KB) { chain.initWarning(AmountHighWarn("-fallbackfee") + " " + - _("This is the transaction fee you may pay when fee estimates are not available.")); + _("This is the transaction fee you may pay when fee estimates are not available.").translated); } walletInstance->m_fallback_fee = CFeeRate(nFeePerK); walletInstance->m_allow_fallback_fee = nFeePerK != 0; //disable fallback fee in case value was set to 0, enable if non-null value @@ -4402,12 +4427,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if (gArgs.IsArgSet("-discardfee")) { CAmount nFeePerK = 0; if (!ParseMoney(gArgs.GetArg("-discardfee", ""), nFeePerK)) { - chain.initError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), gArgs.GetArg("-discardfee", ""))); + chain.initError(strprintf(_("Invalid amount for -discardfee=<amount>: '%s'").translated, gArgs.GetArg("-discardfee", ""))); return nullptr; } if (nFeePerK > HIGH_TX_FEE_PER_KB) { chain.initWarning(AmountHighWarn("-discardfee") + " " + - _("This is the transaction fee you may discard if change is smaller than dust at this level")); + _("This is the transaction fee you may discard if change is smaller than dust at this level").translated); } walletInstance->m_discard_rate = CFeeRate(nFeePerK); } @@ -4419,11 +4444,11 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, } if (nFeePerK > HIGH_TX_FEE_PER_KB) { chain.initWarning(AmountHighWarn("-paytxfee") + " " + - _("This is the transaction fee you will pay if you send a transaction.")); + _("This is the transaction fee you will pay if you send a transaction.").translated); } walletInstance->m_pay_tx_fee = CFeeRate(nFeePerK, 1000); if (walletInstance->m_pay_tx_fee < chain.relayMinFee()) { - chain.initError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"), + chain.initError(strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)").translated, gArgs.GetArg("-paytxfee", ""), chain.relayMinFee().ToString())); return nullptr; } @@ -4437,10 +4462,10 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, return nullptr; } if (nMaxFee > HIGH_MAX_TX_FEE) { - chain.initWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.")); + chain.initWarning(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction.").translated); } if (CFeeRate(nMaxFee, 1000) < chain.relayMinFee()) { - chain.initError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"), + chain.initError(strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)").translated, gArgs.GetArg("-maxtxfee", ""), chain.relayMinFee().ToString())); return nullptr; } @@ -4449,7 +4474,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, if (chain.relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) chain.initWarning(AmountHighWarn("-minrelaytxfee") + " " + - _("The wallet will avoid paying less than the minimum relay fee.")); + _("The wallet will avoid paying less than the minimum relay fee.").translated); walletInstance->m_confirm_target = gArgs.GetArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET); walletInstance->m_spend_zero_conf_change = gArgs.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE); @@ -4497,12 +4522,12 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, } if (rescan_height != block_height) { - chain.initError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)")); + chain.initError(_("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)").translated); return nullptr; } } - chain.initMessage(_("Rescanning...")); + chain.initMessage(_("Rescanning...").translated); walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height); // No need to read and scan block if block was created before @@ -4516,7 +4541,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain, { WalletRescanReserver reserver(walletInstance.get()); if (!reserver.reserve() || (ScanResult::SUCCESS != walletInstance->ScanForWalletTransactions(locked_chain->getBlockHash(rescan_height), {} /* stop block */, reserver, true /* update */).status)) { - chain.initError(_("Failed to rescan the wallet during initialization")); + chain.initError(_("Failed to rescan the wallet during initialization").translated); return nullptr; } } @@ -4602,12 +4627,6 @@ CKeyPool::CKeyPool(const CPubKey& vchPubKeyIn, bool internalIn) m_pre_split = false; } -CWalletKey::CWalletKey(int64_t nExpires) -{ - nTimeCreated = (nExpires ? GetTime() : 0); - nTimeExpires = nExpires; -} - void CMerkleTx::SetMerkleBranch(const uint256& block_hash, int posInBlock) { // Update the tx's hashBlock diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6a7097bf44..06e22895b5 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -12,7 +12,6 @@ #include <outputtype.h> #include <policy/feerate.h> #include <script/sign.h> -#include <streams.h> #include <tinyformat.h> #include <ui_interface.h> #include <util/strencodings.h> @@ -51,13 +50,13 @@ std::vector<std::shared_ptr<CWallet>> GetWallets(); std::shared_ptr<CWallet> GetWallet(const std::string& name); std::shared_ptr<CWallet> LoadWallet(interfaces::Chain& chain, const WalletLocation& location, std::string& error, std::string& warning); -enum WalletCreationStatus { +enum class WalletCreationStatus { SUCCESS, CREATION_FAILED, ENCRYPTION_FAILED }; -std::shared_ptr<CWallet> CreateWallet(interfaces::Chain& chain, const std::string& name, std::string& error, std::string& warning, WalletCreationStatus& status, const SecureString& passphrase, uint64_t wallet_creation_flags); +WalletCreationStatus CreateWallet(interfaces::Chain& chain, const SecureString& passphrase, uint64_t wallet_creation_flags, const std::string& name, std::string& error, std::string& warning, std::shared_ptr<CWallet>& result); //! Default for -keypool static const unsigned int DEFAULT_KEYPOOL_SIZE = 1000; @@ -677,23 +676,18 @@ public: } }; -/** Private key that includes an expiration date in case it never gets used. */ -class CWalletKey -{ -public: +/** Private key that was serialized by an old wallet (only used for deserialization) */ +struct OldKey { CPrivKey vchPrivKey; - int64_t nTimeCreated; - int64_t nTimeExpires; - std::string strComment; - // todo: add something to note what created it (user, getnewaddress, change) - // maybe should have a map<string, string> property map - - explicit CWalletKey(int64_t nExpires=0); - ADD_SERIALIZE_METHODS; template <typename Stream, typename Operation> inline void SerializationOp(Stream& s, Operation ser_action) { + // no longer used by the wallet, thus dropped after deserialization: + int64_t nTimeCreated; + int64_t nTimeExpires; + std::string strComment; + int nVersion = s.GetVersion(); if (!(s.GetType() & SER_GETHASH)) READWRITE(nVersion); @@ -1150,10 +1144,10 @@ public: bool DummySignTx(CMutableTransaction &txNew, const std::vector<CTxOut> &txouts, bool use_max_sig = false) const; bool DummySignInput(CTxIn &tx_in, const CTxOut &txout, bool use_max_sig = false) const; - bool ImportScripts(const std::set<CScript> scripts) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool ImportScripts(const std::set<CScript> scripts, int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool ImportPrivKeys(const std::map<CKeyID, CKey>& privkey_map, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); - bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE}; unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET}; diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp index ece97e2a75..9f467c0f5a 100644 --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -21,45 +21,71 @@ #include <boost/thread.hpp> +namespace DBKeys { +const std::string ACENTRY{"acentry"}; +const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"}; +const std::string BESTBLOCK{"bestblock"}; +const std::string CRYPTED_KEY{"ckey"}; +const std::string CSCRIPT{"cscript"}; +const std::string DEFAULTKEY{"defaultkey"}; +const std::string DESTDATA{"destdata"}; +const std::string FLAGS{"flags"}; +const std::string HDCHAIN{"hdchain"}; +const std::string KEYMETA{"keymeta"}; +const std::string KEY{"key"}; +const std::string MASTER_KEY{"mkey"}; +const std::string MINVERSION{"minversion"}; +const std::string NAME{"name"}; +const std::string OLD_KEY{"wkey"}; +const std::string ORDERPOSNEXT{"orderposnext"}; +const std::string POOL{"pool"}; +const std::string PURPOSE{"purpose"}; +const std::string SETTINGS{"settings"}; +const std::string TX{"tx"}; +const std::string VERSION{"version"}; +const std::string WATCHMETA{"watchmeta"}; +const std::string WATCHS{"watchs"}; +} // namespace DBKeys + // // WalletBatch // bool WalletBatch::WriteName(const std::string& strAddress, const std::string& strName) { - return WriteIC(std::make_pair(std::string("name"), strAddress), strName); + return WriteIC(std::make_pair(DBKeys::NAME, strAddress), strName); } bool WalletBatch::EraseName(const std::string& strAddress) { // This should only be used for sending addresses, never for receiving addresses, // receiving addresses must always have an address book entry if they're not change return. - return EraseIC(std::make_pair(std::string("name"), strAddress)); + return EraseIC(std::make_pair(DBKeys::NAME, strAddress)); } bool WalletBatch::WritePurpose(const std::string& strAddress, const std::string& strPurpose) { - return WriteIC(std::make_pair(std::string("purpose"), strAddress), strPurpose); + return WriteIC(std::make_pair(DBKeys::PURPOSE, strAddress), strPurpose); } bool WalletBatch::ErasePurpose(const std::string& strAddress) { - return EraseIC(std::make_pair(std::string("purpose"), strAddress)); + return EraseIC(std::make_pair(DBKeys::PURPOSE, strAddress)); } bool WalletBatch::WriteTx(const CWalletTx& wtx) { - return WriteIC(std::make_pair(std::string("tx"), wtx.GetHash()), wtx); + return WriteIC(std::make_pair(DBKeys::TX, wtx.GetHash()), wtx); } bool WalletBatch::EraseTx(uint256 hash) { - return EraseIC(std::make_pair(std::string("tx"), hash)); + return EraseIC(std::make_pair(DBKeys::TX, hash)); } bool WalletBatch::WriteKeyMetadata(const CKeyMetadata& meta, const CPubKey& pubkey, const bool overwrite) { - return WriteIC(std::make_pair(std::string("keymeta"), pubkey), meta, overwrite); + return WriteIC(std::make_pair(DBKeys::KEYMETA, pubkey), meta, overwrite); } bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, const CKeyMetadata& keyMeta) @@ -74,7 +100,7 @@ bool WalletBatch::WriteKey(const CPubKey& vchPubKey, const CPrivKey& vchPrivKey, vchKey.insert(vchKey.end(), vchPubKey.begin(), vchPubKey.end()); vchKey.insert(vchKey.end(), vchPrivKey.begin(), vchPrivKey.end()); - return WriteIC(std::make_pair(std::string("key"), vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); + return WriteIC(std::make_pair(DBKeys::KEY, vchPubKey), std::make_pair(vchPrivKey, Hash(vchKey.begin(), vchKey.end())), false); } bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey, @@ -85,75 +111,75 @@ bool WalletBatch::WriteCryptedKey(const CPubKey& vchPubKey, return false; } - if (!WriteIC(std::make_pair(std::string("ckey"), vchPubKey), vchCryptedSecret, false)) { + if (!WriteIC(std::make_pair(DBKeys::CRYPTED_KEY, vchPubKey), vchCryptedSecret, false)) { return false; } - EraseIC(std::make_pair(std::string("key"), vchPubKey)); - EraseIC(std::make_pair(std::string("wkey"), vchPubKey)); + EraseIC(std::make_pair(DBKeys::KEY, vchPubKey)); + EraseIC(std::make_pair(DBKeys::OLD_KEY, vchPubKey)); return true; } bool WalletBatch::WriteMasterKey(unsigned int nID, const CMasterKey& kMasterKey) { - return WriteIC(std::make_pair(std::string("mkey"), nID), kMasterKey, true); + return WriteIC(std::make_pair(DBKeys::MASTER_KEY, nID), kMasterKey, true); } bool WalletBatch::WriteCScript(const uint160& hash, const CScript& redeemScript) { - return WriteIC(std::make_pair(std::string("cscript"), hash), redeemScript, false); + return WriteIC(std::make_pair(DBKeys::CSCRIPT, hash), redeemScript, false); } bool WalletBatch::WriteWatchOnly(const CScript &dest, const CKeyMetadata& keyMeta) { - if (!WriteIC(std::make_pair(std::string("watchmeta"), dest), keyMeta)) { + if (!WriteIC(std::make_pair(DBKeys::WATCHMETA, dest), keyMeta)) { return false; } - return WriteIC(std::make_pair(std::string("watchs"), dest), '1'); + return WriteIC(std::make_pair(DBKeys::WATCHS, dest), '1'); } bool WalletBatch::EraseWatchOnly(const CScript &dest) { - if (!EraseIC(std::make_pair(std::string("watchmeta"), dest))) { + if (!EraseIC(std::make_pair(DBKeys::WATCHMETA, dest))) { return false; } - return EraseIC(std::make_pair(std::string("watchs"), dest)); + return EraseIC(std::make_pair(DBKeys::WATCHS, dest)); } bool WalletBatch::WriteBestBlock(const CBlockLocator& locator) { - WriteIC(std::string("bestblock"), CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan - return WriteIC(std::string("bestblock_nomerkle"), locator); + WriteIC(DBKeys::BESTBLOCK, CBlockLocator()); // Write empty block locator so versions that require a merkle branch automatically rescan + return WriteIC(DBKeys::BESTBLOCK_NOMERKLE, locator); } bool WalletBatch::ReadBestBlock(CBlockLocator& locator) { - if (m_batch.Read(std::string("bestblock"), locator) && !locator.vHave.empty()) return true; - return m_batch.Read(std::string("bestblock_nomerkle"), locator); + if (m_batch.Read(DBKeys::BESTBLOCK, locator) && !locator.vHave.empty()) return true; + return m_batch.Read(DBKeys::BESTBLOCK_NOMERKLE, locator); } bool WalletBatch::WriteOrderPosNext(int64_t nOrderPosNext) { - return WriteIC(std::string("orderposnext"), nOrderPosNext); + return WriteIC(DBKeys::ORDERPOSNEXT, nOrderPosNext); } bool WalletBatch::ReadPool(int64_t nPool, CKeyPool& keypool) { - return m_batch.Read(std::make_pair(std::string("pool"), nPool), keypool); + return m_batch.Read(std::make_pair(DBKeys::POOL, nPool), keypool); } bool WalletBatch::WritePool(int64_t nPool, const CKeyPool& keypool) { - return WriteIC(std::make_pair(std::string("pool"), nPool), keypool); + return WriteIC(std::make_pair(DBKeys::POOL, nPool), keypool); } bool WalletBatch::ErasePool(int64_t nPool) { - return EraseIC(std::make_pair(std::string("pool"), nPool)); + return EraseIC(std::make_pair(DBKeys::POOL, nPool)); } bool WalletBatch::WriteMinVersion(int nVersion) { - return WriteIC(std::string("minversion"), nVersion); + return WriteIC(DBKeys::MINVERSION, nVersion); } class CWalletScanState { @@ -165,7 +191,6 @@ public: unsigned int m_unknown_records{0}; bool fIsEncrypted{false}; bool fAnyUnordered{false}; - int nFileVersion{0}; std::vector<uint256> vWalletUpgrade; CWalletScanState() { @@ -181,20 +206,15 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, // Taking advantage of the fact that pair serialization // is just the two items serialized one after the other ssKey >> strType; - if (strType == "name") - { + if (strType == DBKeys::NAME) { std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].name; - } - else if (strType == "purpose") - { + } else if (strType == DBKeys::PURPOSE) { std::string strAddress; ssKey >> strAddress; ssValue >> pwallet->mapAddressBook[DecodeDestination(strAddress)].purpose; - } - else if (strType == "tx") - { + } else if (strType == DBKeys::TX) { uint256 hash; ssKey >> hash; CWalletTx wtx(nullptr /* pwallet */, MakeTransactionRef()); @@ -228,9 +248,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, wss.fAnyUnordered = true; pwallet->LoadToWallet(wtx); - } - else if (strType == "watchs") - { + } else if (strType == DBKeys::WATCHS) { wss.nWatchKeys++; CScript script; ssKey >> script; @@ -238,9 +256,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, ssValue >> fYes; if (fYes == '1') pwallet->LoadWatchOnly(script); - } - else if (strType == "key" || strType == "wkey") - { + } else if (strType == DBKeys::KEY || strType == DBKeys::OLD_KEY) { CPubKey vchPubKey; ssKey >> vchPubKey; if (!vchPubKey.IsValid()) @@ -252,20 +268,19 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, CPrivKey pkey; uint256 hash; - if (strType == "key") - { + if (strType == DBKeys::KEY) { wss.nKeys++; ssValue >> pkey; } else { - CWalletKey wkey; + OldKey wkey; ssValue >> wkey; pkey = wkey.vchPrivKey; } - // Old wallets store keys as "key" [pubkey] => [privkey] + // Old wallets store keys as DBKeys::KEY [pubkey] => [privkey] // ... which was slow for wallets with lots of keys, because the public key is re-derived from the private key // using EC operations as a checksum. - // Newer wallets store keys as "key"[pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while + // Newer wallets store keys as DBKeys::KEY [pubkey] => [privkey][hash(pubkey,privkey)], which is much faster while // remaining backwards-compatible. try { @@ -302,9 +317,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: LoadKey failed"; return false; } - } - else if (strType == "mkey") - { + } else if (strType == DBKeys::MASTER_KEY) { unsigned int nID; ssKey >> nID; CMasterKey kMasterKey; @@ -317,9 +330,7 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, pwallet->mapMasterKeys[nID] = kMasterKey; if (pwallet->nMasterKeyMaxID < nID) pwallet->nMasterKeyMaxID = nID; - } - else if (strType == "ckey") - { + } else if (strType == DBKeys::CRYPTED_KEY) { CPubKey vchPubKey; ssKey >> vchPubKey; if (!vchPubKey.IsValid()) @@ -337,27 +348,21 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, return false; } wss.fIsEncrypted = true; - } - else if (strType == "keymeta") - { + } else if (strType == DBKeys::KEYMETA) { CPubKey vchPubKey; ssKey >> vchPubKey; CKeyMetadata keyMeta; ssValue >> keyMeta; wss.nKeyMeta++; pwallet->LoadKeyMetadata(vchPubKey.GetID(), keyMeta); - } - else if (strType == "watchmeta") - { + } else if (strType == DBKeys::WATCHMETA) { CScript script; ssKey >> script; CKeyMetadata keyMeta; ssValue >> keyMeta; wss.nKeyMeta++; pwallet->LoadScriptMetadata(CScriptID(script), keyMeta); - } - else if (strType == "defaultkey") - { + } else if (strType == DBKeys::DEFAULTKEY) { // We don't want or need the default key, but if there is one set, // we want to make sure that it is valid so that we can detect corruption CPubKey vchPubKey; @@ -366,24 +371,14 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: Default Key corrupt"; return false; } - } - else if (strType == "pool") - { + } else if (strType == DBKeys::POOL) { int64_t nIndex; ssKey >> nIndex; CKeyPool keypool; ssValue >> keypool; pwallet->LoadKeyPool(nIndex, keypool); - } - else if (strType == "version") - { - ssValue >> wss.nFileVersion; - if (wss.nFileVersion == 10300) - wss.nFileVersion = 300; - } - else if (strType == "cscript") - { + } else if (strType == DBKeys::CSCRIPT) { uint160 hash; ssKey >> hash; CScript script; @@ -393,33 +388,28 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, strErr = "Error reading wallet database: LoadCScript failed"; return false; } - } - else if (strType == "orderposnext") - { + } else if (strType == DBKeys::ORDERPOSNEXT) { ssValue >> pwallet->nOrderPosNext; - } - else if (strType == "destdata") - { + } else if (strType == DBKeys::DESTDATA) { std::string strAddress, strKey, strValue; ssKey >> strAddress; ssKey >> strKey; ssValue >> strValue; pwallet->LoadDestData(DecodeDestination(strAddress), strKey, strValue); - } - else if (strType == "hdchain") - { + } else if (strType == DBKeys::HDCHAIN) { CHDChain chain; ssValue >> chain; pwallet->SetHDChain(chain, true); - } else if (strType == "flags") { + } else if (strType == DBKeys::FLAGS) { uint64_t flags; ssValue >> flags; if (!pwallet->SetWalletFlags(flags, true)) { strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found"; return false; } - } else if (strType != "bestblock" && strType != "bestblock_nomerkle" && - strType != "minversion" && strType != "acentry") { + } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE && + strType != DBKeys::MINVERSION && strType != DBKeys::ACENTRY && + strType != DBKeys::VERSION && strType != DBKeys::SETTINGS) { wss.m_unknown_records++; } } catch (const std::exception& e) { @@ -438,8 +428,8 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue, bool WalletBatch::IsKeyType(const std::string& strType) { - return (strType== "key" || strType == "wkey" || - strType == "mkey" || strType == "ckey"); + return (strType == DBKeys::KEY || strType == DBKeys::OLD_KEY || + strType == DBKeys::MASTER_KEY || strType == DBKeys::CRYPTED_KEY); } DBErrors WalletBatch::LoadWallet(CWallet* pwallet) @@ -451,8 +441,7 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) LOCK(pwallet->cs_wallet); try { int nMinVersion = 0; - if (m_batch.Read((std::string)"minversion", nMinVersion)) - { + if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) { if (nMinVersion > FEATURE_LATEST) return DBErrors::TOO_NEW; pwallet->LoadMinVersion(nMinVersion); @@ -486,15 +475,15 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) { // losing keys is considered a catastrophic error, anything else // we assume the user can live with: - if (IsKeyType(strType) || strType == "defaultkey") { + if (IsKeyType(strType) || strType == DBKeys::DEFAULTKEY) { result = DBErrors::CORRUPT; - } else if(strType == "flags") { + } else if (strType == DBKeys::FLAGS) { // reading the wallet flags can only fail if unknown flags are present result = DBErrors::TOO_NEW; } else { // Leave other errors alone, if we try to fix them we might make things worse. fNoncriticalErrors = true; // ... but do warn the user there is something wrong. - if (strType == "tx") + if (strType == DBKeys::TX) // Rescan if there is a bad transaction record: gArgs.SoftSetBoolArg("-rescan", true); } @@ -519,7 +508,12 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) if (result != DBErrors::LOAD_OK) return result; - pwallet->WalletLogPrintf("nFileVersion = %d\n", wss.nFileVersion); + // Last client version to open this wallet, was previously the file version number + int last_client = CLIENT_VERSION; + m_batch.Read(DBKeys::VERSION, last_client); + + int wallet_version = pwallet->GetVersion(); + pwallet->WalletLogPrintf("Wallet File Version = %d\n", wallet_version > 0 ? wallet_version : last_client); pwallet->WalletLogPrintf("Keys: %u plaintext, %u encrypted, %u w/ metadata, %u total. Unknown wallet records: %u\n", wss.nKeys, wss.nCKeys, wss.nKeyMeta, wss.nKeys + wss.nCKeys, wss.m_unknown_records); @@ -532,11 +526,11 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet) WriteTx(pwallet->mapWallet.at(hash)); // Rewrite encrypted wallets of versions 0.4.0 and 0.5.0rc: - if (wss.fIsEncrypted && (wss.nFileVersion == 40000 || wss.nFileVersion == 50000)) + if (wss.fIsEncrypted && (last_client == 40000 || last_client == 50000)) return DBErrors::NEED_REWRITE; - if (wss.nFileVersion < CLIENT_VERSION) // Update - WriteVersion(CLIENT_VERSION); + if (last_client < CLIENT_VERSION) // Update + m_batch.Write(DBKeys::VERSION, CLIENT_VERSION); if (wss.fAnyUnordered) result = pwallet->ReorderTransactions(); @@ -558,8 +552,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CW try { int nMinVersion = 0; - if (m_batch.Read((std::string)"minversion", nMinVersion)) - { + if (m_batch.Read(DBKeys::MINVERSION, nMinVersion)) { if (nMinVersion > FEATURE_LATEST) return DBErrors::TOO_NEW; } @@ -588,7 +581,7 @@ DBErrors WalletBatch::FindWalletTx(std::vector<uint256>& vTxHash, std::vector<CW std::string strType; ssKey >> strType; - if (strType == "tx") { + if (strType == DBKeys::TX) { uint256 hash; ssKey >> hash; @@ -723,8 +716,9 @@ bool WalletBatch::RecoverKeysOnlyFilter(void *callbackData, CDataStream ssKey, C fReadOK = ReadKeyValue(dummyWallet, ssKey, ssValue, dummyWss, strType, strErr); } - if (!IsKeyType(strType) && strType != "hdchain") + if (!IsKeyType(strType) && strType != DBKeys::HDCHAIN) { return false; + } if (!fReadOK) { LogPrintf("WARNING: WalletBatch::Recover skipping %s: %s\n", strType, strErr); @@ -746,23 +740,23 @@ bool WalletBatch::VerifyDatabaseFile(const fs::path& wallet_path, std::string& w bool WalletBatch::WriteDestData(const std::string &address, const std::string &key, const std::string &value) { - return WriteIC(std::make_pair(std::string("destdata"), std::make_pair(address, key)), value); + return WriteIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key)), value); } bool WalletBatch::EraseDestData(const std::string &address, const std::string &key) { - return EraseIC(std::make_pair(std::string("destdata"), std::make_pair(address, key))); + return EraseIC(std::make_pair(DBKeys::DESTDATA, std::make_pair(address, key))); } bool WalletBatch::WriteHDChain(const CHDChain& chain) { - return WriteIC(std::string("hdchain"), chain); + return WriteIC(DBKeys::HDCHAIN, chain); } bool WalletBatch::WriteWalletFlags(const uint64_t flags) { - return WriteIC(std::string("flags"), flags); + return WriteIC(DBKeys::FLAGS, flags); } bool WalletBatch::TxnBegin() @@ -779,13 +773,3 @@ bool WalletBatch::TxnAbort() { return m_batch.TxnAbort(); } - -bool WalletBatch::ReadVersion(int& nVersion) -{ - return m_batch.ReadVersion(nVersion); -} - -bool WalletBatch::WriteVersion(int nVersion) -{ - return m_batch.WriteVersion(nVersion); -} diff --git a/src/wallet/walletdb.h b/src/wallet/walletdb.h index d4a3bba97a..0fee35934d 100644 --- a/src/wallet/walletdb.h +++ b/src/wallet/walletdb.h @@ -55,6 +55,32 @@ enum class DBErrors NEED_REWRITE }; +namespace DBKeys { +extern const std::string ACENTRY; +extern const std::string BESTBLOCK; +extern const std::string BESTBLOCK_NOMERKLE; +extern const std::string CRYPTED_KEY; +extern const std::string CSCRIPT; +extern const std::string DEFAULTKEY; +extern const std::string DESTDATA; +extern const std::string FLAGS; +extern const std::string HDCHAIN; +extern const std::string KEY; +extern const std::string KEYMETA; +extern const std::string MASTER_KEY; +extern const std::string MINVERSION; +extern const std::string NAME; +extern const std::string OLD_KEY; +extern const std::string ORDERPOSNEXT; +extern const std::string POOL; +extern const std::string PURPOSE; +extern const std::string SETTINGS; +extern const std::string TX; +extern const std::string VERSION; +extern const std::string WATCHMETA; +extern const std::string WATCHS; +} // namespace DBKeys + /* simple HD chain data model */ class CHDChain { @@ -249,10 +275,6 @@ public: bool TxnCommit(); //! Abort current transaction bool TxnAbort(); - //! Read wallet version - bool ReadVersion(int& nVersion); - //! Write wallet version - bool WriteVersion(int nVersion); private: BerkeleyBatch m_batch; WalletDatabase& m_database; diff --git a/src/warnings.cpp b/src/warnings.cpp index 5542412a7f..35d2033ba8 100644 --- a/src/warnings.cpp +++ b/src/warnings.cpp @@ -3,9 +3,11 @@ // Distributed under the MIT software license, see the accompanying // file COPYING or http://www.opensource.org/licenses/mit-license.php. +#include <warnings.h> + #include <sync.h> #include <util/system.h> -#include <warnings.h> +#include <util/translation.h> static RecursiveMutex cs_warnings; static std::string strMiscWarning GUARDED_BY(cs_warnings); @@ -46,7 +48,7 @@ std::string GetWarnings(const std::string& strFor) if (!CLIENT_VERSION_IS_RELEASE) { strStatusBar = "This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"; - strGUI = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications"); + strGUI = _("This is a pre-release test build - use at your own risk - do not use for mining or merchant applications").translated; } // Misc warnings like out of disk space and clock is wrong @@ -59,12 +61,12 @@ std::string GetWarnings(const std::string& strFor) if (fLargeWorkForkFound) { strStatusBar = "Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."; - strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues."); + strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: The network does not appear to fully agree! Some miners appear to be experiencing issues.").translated; } else if (fLargeWorkInvalidChainFound) { strStatusBar = "Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."; - strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade."); + strGUI += (strGUI.empty() ? "" : uiAlertSeperator) + _("Warning: We do not appear to fully agree with our peers! You may need to upgrade, or other nodes may need to upgrade.").translated; } if (strFor == "gui") |