diff options
Diffstat (limited to 'src')
42 files changed, 424 insertions, 343 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 0ed412295f..0f05439227 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..ba021a5163 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/net.cpp b/src/net.cpp index 7d11111b25..8e263b7953 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> @@ -2039,9 +2040,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 +2052,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 +2193,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 +2204,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 +2219,7 @@ bool CConnman::Start(CScheduler& scheduler, const Options& connOptions) } } - uiInterface.InitMessage(_("Starting network threads...")); + uiInterface.InitMessage(_("Starting network threads...").translated); fAddressesInitialized = true; @@ -2258,7 +2259,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/net_processing.h b/src/net_processing.h index 39c22d7118..dffc3f273f 100644 --- a/src/net_processing.h +++ b/src/net_processing.h @@ -19,6 +19,7 @@ static const unsigned int DEFAULT_MAX_ORPHAN_TRANSACTIONS = 100; static const unsigned int DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN = 100; /** Default for BIP61 (sending reject messages) */ static constexpr bool DEFAULT_ENABLE_BIP61{false}; +static const bool DEFAULT_PEERBLOOMFILTERS = false; class PeerLogicValidation final : public CValidationInterface, public NetEventsInterface { private: diff --git a/src/netbase.cpp b/src/netbase.cpp index 53e5985a0f..6d4738c835 100644 --- a/src/netbase.cpp +++ b/src/netbase.cpp @@ -347,7 +347,7 @@ static IntrRecvError InterruptibleRecv(uint8_t* data, size_t len, int timeout, c #ifdef USE_POLL struct pollfd pollfd = {}; pollfd.fd = hSocket; - pollfd.events = POLLIN | POLLOUT; + pollfd.events = POLLIN; int nRet = poll(&pollfd, 1, timeout_ms); #else struct timeval tval = MillisToTimeval(timeout_ms); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index 4a9742f7b7..ed5d47cad7 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> @@ -30,15 +30,12 @@ #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> @@ -462,8 +459,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 +499,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 +521,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; } 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/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/test/addrman_tests.cpp b/src/test/addrman_tests.cpp index eeb54b4cf0..da0abd495a 100644 --- a/src/test/addrman_tests.cpp +++ b/src/test/addrman_tests.cpp @@ -533,9 +533,6 @@ BOOST_AUTO_TEST_CASE(addrman_selecttriedcollision) { CAddrManTest addrman; - // Set addrman addr placement to be deterministic. - addrman.MakeDeterministic(); - BOOST_CHECK(addrman.size() == 0); // Empty addrman should return blank addrman info. @@ -568,9 +565,6 @@ BOOST_AUTO_TEST_CASE(addrman_noevict) { CAddrManTest addrman; - // Set addrman addr placement to be deterministic. - addrman.MakeDeterministic(); - // Add twenty two addresses. CNetAddr source = ResolveIP("252.2.2.2"); for (unsigned int i = 1; i < 23; i++) { @@ -627,9 +621,6 @@ BOOST_AUTO_TEST_CASE(addrman_evictionworks) { CAddrManTest addrman; - // Set addrman addr placement to be deterministic. - addrman.MakeDeterministic(); - BOOST_CHECK(addrman.size() == 0); // Empty addrman should return blank addrman info. 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 0bc6167bad..19f4f098d7 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> @@ -616,7 +617,21 @@ static bool AcceptToMemoryPoolWorker(const CChainParams& chainparams, CTxMemPool size_t nLimitDescendantSize = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT)*1000; std::string errString; if (!pool.CalculateMemPoolAncestors(entry, setAncestors, nLimitAncestors, nLimitAncestorSize, nLimitDescendants, nLimitDescendantSize, errString)) { - return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); + setAncestors.clear(); + // 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 + // descendant limit descendants. + // + // This allows protocols which rely on distrusting counterparties + // being able to broadcast descendants of an unconfirmed transaction + // to be secure by simply only having two immediately-spendable + // 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)) { + return state.Invalid(ValidationInvalidReason::TX_MEMPOOL_POLICY, false, REJECT_NONSTANDARD, "too-long-mempool-chain", errString); + } } // A transaction that spends outputs that would be replaced by it is invalid. Now @@ -1394,7 +1409,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; @@ -2013,7 +2028,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(); @@ -2048,7 +2063,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()) @@ -2122,7 +2137,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 { @@ -2139,7 +2154,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, @@ -2170,7 +2185,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(); { @@ -2427,6 +2442,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; @@ -2916,7 +2936,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; @@ -2940,7 +2960,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; @@ -3861,7 +3881,7 @@ bool LoadChainTip(const CChainParams& chainparams) CVerifyDB::CVerifyDB() { - uiInterface.ShowProgress(_("Verifying blocks..."), 0, false); + uiInterface.ShowProgress(_("Verifying blocks...").translated, 0, false); } CVerifyDB::~CVerifyDB() @@ -3895,7 +3915,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)) { @@ -3953,7 +3973,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())) @@ -4000,7 +4020,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. @@ -4046,7 +4066,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/validation.h b/src/validation.h index a1b8029e01..d747fdbf27 100644 --- a/src/validation.h +++ b/src/validation.h @@ -64,6 +64,12 @@ static const unsigned int DEFAULT_ANCESTOR_SIZE_LIMIT = 101; static const unsigned int DEFAULT_DESCENDANT_LIMIT = 25; /** Default for -limitdescendantsize, maximum kilobytes of in-mempool descendants */ static const unsigned int DEFAULT_DESCENDANT_SIZE_LIMIT = 101; +/** + * An extra transaction can be added to a package, as long as it only has one + * ancestor and is no larger than this. Not really any reason to make this + * configurable as it doesn't materially change DoS parameters. + */ +static const unsigned int EXTRA_DESCENDANT_TX_SIZE_LIMIT = 10000; /** Default for -mempoolexpiry, expiration time for mempool transactions in hours */ static const unsigned int DEFAULT_MEMPOOL_EXPIRY = 336; /** Maximum kilobytes for transactions to store for processing during reorg */ @@ -126,8 +132,6 @@ static const unsigned int MAX_BLOCKS_TO_ANNOUNCE = 8; /** Maximum number of unconnecting headers announcements before DoS score */ static const int MAX_UNCONNECTING_HEADERS = 10; -static const bool DEFAULT_PEERBLOOMFILTERS = true; - /** Default for -stopatheight */ static const int DEFAULT_STOPATHEIGHT = 0; diff --git a/src/wallet/db.cpp b/src/wallet/db.cpp index b5f90deabd..852b194386 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; } } 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..7af009f430 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -3263,12 +3263,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 +3276,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 +3331,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..b9eb0d3eed 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> @@ -1776,14 +1777,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 +1809,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 +1837,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 +1856,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 +1867,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 +2037,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 +2056,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 +2112,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 +2931,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 +2941,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 +2979,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 +3045,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 +3078,7 @@ bool CWallet::CreateTransaction(interfaces::Chain::Lock& locked_chain, const std continue; } else { - strFailReason = _("Insufficient funds"); + strFailReason = _("Insufficient funds").translated; return false; } } @@ -3085,7 +3109,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 +3128,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 +3175,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 +3232,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 +3248,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 +3261,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 +4249,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 +4270,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 +4308,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 +4321,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 +4349,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 +4369,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 +4377,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 +4404,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 +4426,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 +4443,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 +4461,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 +4473,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 +4521,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 +4540,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; } } diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 6a7097bf44..8ed27c3cc8 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> @@ -1150,10 +1149,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/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") |