diff options
Diffstat (limited to 'src')
40 files changed, 579 insertions, 457 deletions
diff --git a/src/Makefile.test.include b/src/Makefile.test.include index 0068c94070..a0c9c30f36 100644 --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -70,6 +70,7 @@ FUZZ_TARGETS = \ test/fuzz/message \ test/fuzz/messageheader_deserialize \ test/fuzz/multiplication_overflow \ + test/fuzz/net \ test/fuzz/net_permissions \ test/fuzz/netaddr_deserialize \ test/fuzz/netaddress \ @@ -722,6 +723,12 @@ test_fuzz_multiplication_overflow_LDADD = $(FUZZ_SUITE_LD_COMMON) test_fuzz_multiplication_overflow_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) test_fuzz_multiplication_overflow_SOURCES = test/fuzz/multiplication_overflow.cpp +test_fuzz_net_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) +test_fuzz_net_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) +test_fuzz_net_LDADD = $(FUZZ_SUITE_LD_COMMON) +test_fuzz_net_LDFLAGS = $(RELDFLAGS) $(AM_LDFLAGS) $(LIBTOOL_APP_LDFLAGS) +test_fuzz_net_SOURCES = test/fuzz/net.cpp + test_fuzz_net_permissions_CPPFLAGS = $(AM_CPPFLAGS) $(BITCOIN_INCLUDES) test_fuzz_net_permissions_CXXFLAGS = $(AM_CXXFLAGS) $(PIE_FLAGS) test_fuzz_net_permissions_LDADD = $(FUZZ_SUITE_LD_COMMON) diff --git a/src/base58.cpp b/src/base58.cpp index 18cd2090e0..0dc6044145 100644 --- a/src/base58.cpp +++ b/src/base58.cpp @@ -35,7 +35,7 @@ static const int8_t mapBase58[256] = { -1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1,-1,-1, }; -bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len) +NODISCARD static bool DecodeBase58(const char* psz, std::vector<unsigned char>& vch, int max_ret_len) { // Skip leading spaces. while (*psz && IsSpace(*psz)) @@ -141,7 +141,7 @@ std::string EncodeBase58Check(Span<const unsigned char> input) return EncodeBase58(vch); } -bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len) +NODISCARD static bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len) { if (!DecodeBase58(psz, vchRet, max_ret_len > std::numeric_limits<int>::max() - 4 ? std::numeric_limits<int>::max() : max_ret_len + 4) || (vchRet.size() < 4)) { diff --git a/src/base58.h b/src/base58.h index b87664b78b..468c3e2589 100644 --- a/src/base58.h +++ b/src/base58.h @@ -26,13 +26,6 @@ std::string EncodeBase58(Span<const unsigned char> input); /** - * Decode a base58-encoded string (psz) into a byte vector (vchRet). - * return true if decoding is successful. - * psz cannot be nullptr. - */ -NODISCARD bool DecodeBase58(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len); - -/** * Decode a base58-encoded string (str) into a byte vector (vchRet). * return true if decoding is successful. */ @@ -44,12 +37,6 @@ NODISCARD bool DecodeBase58(const std::string& str, std::vector<unsigned char>& std::string EncodeBase58Check(Span<const unsigned char> input); /** - * Decode a base58-encoded string (psz) that includes a checksum into a byte - * vector (vchRet), return true if decoding is successful - */ -NODISCARD bool DecodeBase58Check(const char* psz, std::vector<unsigned char>& vchRet, int max_ret_len); - -/** * Decode a base58-encoded string (str) that includes a checksum into a byte * vector (vchRet), return true if decoding is successful */ diff --git a/src/bitcoind.cpp b/src/bitcoind.cpp index b04cc12059..227626f40f 100644 --- a/src/bitcoind.cpp +++ b/src/bitcoind.cpp @@ -50,28 +50,23 @@ static bool AppInit(int argc, char* argv[]) util::ThreadSetInternalName("init"); - // - // Parameters - // // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main() SetupServerArgs(node); + ArgsManager& args = *Assert(node.args); std::string error; - if (!gArgs.ParseParameters(argc, argv, error)) { + if (!args.ParseParameters(argc, argv, error)) { return InitError(Untranslated(strprintf("Error parsing command line arguments: %s\n", error))); } // Process help and version before taking care about datadir - if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { + if (HelpRequested(args) || args.IsArgSet("-version")) { std::string strUsage = PACKAGE_NAME " version " + FormatFullVersion() + "\n"; - if (gArgs.IsArgSet("-version")) - { + if (args.IsArgSet("-version")) { strUsage += FormatParagraph(LicenseInfo()) + "\n"; - } - else - { + } else { strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"; - strUsage += "\n" + gArgs.GetHelpMessage(); + strUsage += "\n" + args.GetHelpMessage(); } tfm::format(std::cout, "%s", strUsage); @@ -82,14 +77,14 @@ static bool AppInit(int argc, char* argv[]) try { if (!CheckDataDirOption()) { - return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", gArgs.GetArg("-datadir", "")))); + return InitError(Untranslated(strprintf("Specified data directory \"%s\" does not exist.\n", args.GetArg("-datadir", "")))); } - if (!gArgs.ReadConfigFiles(error, true)) { + if (!args.ReadConfigFiles(error, true)) { return InitError(Untranslated(strprintf("Error reading configuration file: %s\n", error))); } // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) try { - SelectParams(gArgs.GetChainName()); + SelectParams(args.GetChainName()); } catch (const std::exception& e) { return InitError(Untranslated(strprintf("%s\n", e.what()))); } @@ -101,23 +96,21 @@ static bool AppInit(int argc, char* argv[]) } } - if (!gArgs.InitSettings(error)) { + if (!args.InitSettings(error)) { InitError(Untranslated(error)); return false; } // -server defaults to true for bitcoind but not for the GUI so do this here - gArgs.SoftSetBoolArg("-server", true); + args.SoftSetBoolArg("-server", true); // Set this early so that parameter interactions go to console - InitLogging(); - InitParameterInteraction(); - if (!AppInitBasicSetup()) - { + InitLogging(args); + InitParameterInteraction(args); + if (!AppInitBasicSetup(args)) { // InitError will have been called with detailed error, which ends up on console return false; } - if (!AppInitParameterInteraction()) - { + if (!AppInitParameterInteraction(args)) { // InitError will have been called with detailed error, which ends up on console return false; } @@ -126,8 +119,7 @@ static bool AppInit(int argc, char* argv[]) // InitError will have been called with detailed error, which ends up on console return false; } - if (gArgs.GetBoolArg("-daemon", false)) - { + if (args.GetBoolArg("-daemon", false)) { #if HAVE_DECL_DAEMON #if defined(MAC_OSX) #pragma GCC diagnostic push diff --git a/src/chain.h b/src/chain.h index 802e23f775..43e8a39f36 100644 --- a/src/chain.h +++ b/src/chain.h @@ -398,12 +398,6 @@ public: return vChain[nHeight]; } - /** Compare two chains efficiently. */ - friend bool operator==(const CChain &a, const CChain &b) { - return a.vChain.size() == b.vChain.size() && - a.vChain[a.vChain.size() - 1] == b.vChain[b.vChain.size() - 1]; - } - /** Efficiently check whether a block is present in this chain. */ bool Contains(const CBlockIndex *pindex) const { return (*this)[pindex->nHeight] == pindex; diff --git a/src/init.cpp b/src/init.cpp index ebea6037d6..ecd57960ad 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -107,14 +107,14 @@ static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map"; */ static const char* BITCOIN_PID_FILENAME = "bitcoind.pid"; -static fs::path GetPidFile() +static fs::path GetPidFile(const ArgsManager& args) { - return AbsPathForConfigVal(fs::path(gArgs.GetArg("-pid", BITCOIN_PID_FILENAME))); + return AbsPathForConfigVal(fs::path(args.GetArg("-pid", BITCOIN_PID_FILENAME))); } -NODISCARD static bool CreatePidFile() +NODISCARD static bool CreatePidFile(const ArgsManager& args) { - fsbridge::ofstream file{GetPidFile()}; + fsbridge::ofstream file{GetPidFile(args)}; if (file) { #ifdef WIN32 tfm::format(file, "%d\n", GetCurrentProcessId()); @@ -123,7 +123,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"), GetPidFile(args).string(), std::strerror(errno))); } } @@ -180,6 +180,7 @@ void Shutdown(NodeContext& node) TRY_LOCK(g_shutdown_mutex, lock_shutdown); if (!lock_shutdown) return; LogPrintf("%s: In progress...\n", __func__); + Assert(node.args); /// Note: Shutdown() must be able to handle cases in which initialization failed part of the way, /// for example if the data directory was found to be locked. @@ -230,7 +231,7 @@ void Shutdown(NodeContext& node) node.connman.reset(); node.banman.reset(); - if (::mempool.IsLoaded() && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { + if (::mempool.IsLoaded() && node.args->GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { DumpMempool(::mempool); } @@ -301,19 +302,19 @@ void Shutdown(NodeContext& node) GetMainSignals().UnregisterBackgroundSignalScheduler(); globalVerifyHandle.reset(); ECC_Stop(); - node.args = nullptr; node.mempool = nullptr; node.chainman = nullptr; node.scheduler.reset(); try { - if (!fs::remove(GetPidFile())) { + if (!fs::remove(GetPidFile(*node.args))) { LogPrintf("%s: Unable to remove PID file: File does not exist\n", __func__); } } catch (const fs::filesystem_error& e) { LogPrintf("%s: Unable to remove PID file: %s\n", __func__, fsbridge::get_filesystem_error_message(e)); } + node.args = nullptr; LogPrintf("%s: done\n", __func__); } @@ -372,7 +373,7 @@ void SetupServerArgs(NodeContext& node) node.args = &gArgs; ArgsManager& argsman = *node.args; - SetupHelpOptions(gArgs); + SetupHelpOptions(argsman); argsman.AddArg("-help-debug", "Print help message with debugging options and exit", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); // server-only for now const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); @@ -599,21 +600,6 @@ std::string LicenseInfo() "\n"; } -#if HAVE_SYSTEM -static void BlockNotifyCallback(SynchronizationState sync_state, const CBlockIndex* pBlockIndex) -{ - if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex) - return; - - std::string strCmd = gArgs.GetArg("-blocknotify", ""); - if (!strCmd.empty()) { - boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex()); - std::thread t(runCommand, strCmd); - t.detach(); // thread runs free - } -} -#endif - static bool fHaveGenesis = false; static Mutex g_genesis_wait_mutex; static std::condition_variable g_genesis_wait_cv; @@ -684,7 +670,7 @@ static void CleanupBlockRevFiles() } } -static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles) +static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args) { const CChainParams& chainparams = Params(); ScheduleBatchPriority(); @@ -746,13 +732,13 @@ static void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImp } } - if (gArgs.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { + if (args.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); StartShutdown(); return; } } // End scope of CImportingNow - if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { + if (args.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { LoadMempool(::mempool); } ::mempool.SetIsLoaded(!ShutdownRequested()); @@ -780,6 +766,7 @@ static bool InitSanityCheck() static bool AppInitServers(const util::Ref& context, NodeContext& node) { + const ArgsManager& args = *Assert(node.args); RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); if (!InitHTTPServer()) @@ -788,71 +775,71 @@ static bool AppInitServers(const util::Ref& context, NodeContext& node) node.rpc_interruption_point = RpcInterruptionPoint; if (!StartHTTPRPC(context)) return false; - if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(context); + if (args.GetBoolArg("-rest", DEFAULT_REST_ENABLE)) StartREST(context); StartHTTPServer(); return true; } // Parameter interaction based on rules -void InitParameterInteraction() +void InitParameterInteraction(ArgsManager& args) { // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified - if (gArgs.IsArgSet("-bind")) { - if (gArgs.SoftSetBoolArg("-listen", true)) + if (args.IsArgSet("-bind")) { + if (args.SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); } - if (gArgs.IsArgSet("-whitebind")) { - if (gArgs.SoftSetBoolArg("-listen", true)) + if (args.IsArgSet("-whitebind")) { + if (args.SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); } - if (gArgs.IsArgSet("-connect")) { + if (args.IsArgSet("-connect")) { // when only connecting to trusted nodes, do not seed via DNS, or listen by default - if (gArgs.SoftSetBoolArg("-dnsseed", false)) + if (args.SoftSetBoolArg("-dnsseed", false)) LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__); - if (gArgs.SoftSetBoolArg("-listen", false)) + if (args.SoftSetBoolArg("-listen", false)) LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); } - if (gArgs.IsArgSet("-proxy")) { + if (args.IsArgSet("-proxy")) { // to protect privacy, do not listen by default if a default proxy server is specified - if (gArgs.SoftSetBoolArg("-listen", false)) + if (args.SoftSetBoolArg("-listen", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -listen=0\n", __func__); // to protect privacy, do not use UPNP when a proxy is set. The user may still specify -listen=1 // to listen locally, so don't rely on this happening through -listen below. - if (gArgs.SoftSetBoolArg("-upnp", false)) + if (args.SoftSetBoolArg("-upnp", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); // to protect privacy, do not discover addresses by default - if (gArgs.SoftSetBoolArg("-discover", false)) + if (args.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__); } - if (!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) { + if (!args.GetBoolArg("-listen", DEFAULT_LISTEN)) { // do not map ports or try to retrieve public IP when not listening (pointless) - if (gArgs.SoftSetBoolArg("-upnp", false)) + if (args.SoftSetBoolArg("-upnp", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); - if (gArgs.SoftSetBoolArg("-discover", false)) + if (args.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); - if (gArgs.SoftSetBoolArg("-listenonion", false)) + if (args.SoftSetBoolArg("-listenonion", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } - if (gArgs.IsArgSet("-externalip")) { + if (args.IsArgSet("-externalip")) { // if an explicit public IP is specified, do not try to find others - if (gArgs.SoftSetBoolArg("-discover", false)) + if (args.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); } // disable whitelistrelay in blocksonly mode - if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { - if (gArgs.SoftSetBoolArg("-whitelistrelay", false)) + if (args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { + if (args.SoftSetBoolArg("-whitelistrelay", false)) LogPrintf("%s: parameter interaction: -blocksonly=1 -> setting -whitelistrelay=0\n", __func__); } // Forcing relay from whitelisted hosts implies we will accept relays from them in the first place. - if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { - if (gArgs.SoftSetBoolArg("-whitelistrelay", true)) + if (args.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { + if (args.SoftSetBoolArg("-whitelistrelay", true)) LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); } } @@ -863,18 +850,18 @@ void InitParameterInteraction() * Note that this is called very early in the process lifetime, so you should be * careful about what global state you rely on here. */ -void InitLogging() +void InitLogging(const ArgsManager& args) { - LogInstance().m_print_to_file = !gArgs.IsArgNegated("-debuglogfile"); - LogInstance().m_file_path = AbsPathForConfigVal(gArgs.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); - LogInstance().m_print_to_console = gArgs.GetBoolArg("-printtoconsole", !gArgs.GetBoolArg("-daemon", false)); - LogInstance().m_log_timestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); - LogInstance().m_log_time_micros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + LogInstance().m_print_to_file = !args.IsArgNegated("-debuglogfile"); + LogInstance().m_file_path = AbsPathForConfigVal(args.GetArg("-debuglogfile", DEFAULT_DEBUGLOGFILE)); + LogInstance().m_print_to_console = args.GetBoolArg("-printtoconsole", !args.GetBoolArg("-daemon", false)); + LogInstance().m_log_timestamps = args.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + LogInstance().m_log_time_micros = args.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); #ifdef HAVE_THREAD_LOCAL - LogInstance().m_log_threadnames = gArgs.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES); + LogInstance().m_log_threadnames = args.GetBoolArg("-logthreadnames", DEFAULT_LOGTHREADNAMES); #endif - fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); + fLogIPs = args.GetBoolArg("-logips", DEFAULT_LOGIPS); std::string version_string = FormatFullVersion(); #ifdef DEBUG @@ -909,7 +896,7 @@ std::set<BlockFilterType> g_enabled_filter_types; std::terminate(); }; -bool AppInitBasicSetup() +bool AppInitBasicSetup(ArgsManager& args) { // ********************************************************* Step 1: setup #ifdef _MSC_VER @@ -929,7 +916,7 @@ bool AppInitBasicSetup() } #ifndef WIN32 - if (!gArgs.GetBoolArg("-sysperms", false)) { + if (!args.GetBoolArg("-sysperms", false)) { umask(077); } @@ -951,7 +938,7 @@ bool AppInitBasicSetup() return true; } -bool AppInitParameterInteraction() +bool AppInitParameterInteraction(const ArgsManager& args) { const CChainParams& chainparams = Params(); // ********************************************************* Step 2: parameter interactions @@ -961,9 +948,9 @@ bool AppInitParameterInteraction() // Error if network-specific options (-addnode, -connect, etc) are // specified in default section of config file, but not overridden // on the command line or in this network's section of the config file. - std::string network = gArgs.GetChainName(); + std::string network = args.GetChainName(); bilingual_str errors; - for (const auto& arg : gArgs.GetUnsuitableSectionOnlyArgs()) { + for (const auto& arg : args.GetUnsuitableSectionOnlyArgs()) { errors += strprintf(_("Config setting for %s only applied on %s network when in [%s] section.") + Untranslated("\n"), arg, network, network); } @@ -973,7 +960,7 @@ bool AppInitParameterInteraction() // Warn if unrecognized section name are present in the config file. bilingual_str warnings; - for (const auto& section : gArgs.GetUnrecognizedSections()) { + for (const auto& section : args.GetUnrecognizedSections()) { warnings += strprintf(Untranslated("%s:%i ") + _("Section [%s] is not recognized.") + Untranslated("\n"), section.m_file, section.m_line, section.m_name); } @@ -982,15 +969,15 @@ bool AppInitParameterInteraction() } if (!fs::is_directory(GetBlocksDir())) { - return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), gArgs.GetArg("-blocksdir", ""))); + return InitError(strprintf(_("Specified blocks directory \"%s\" does not exist."), args.GetArg("-blocksdir", ""))); } // parse and validate enabled filter types - std::string blockfilterindex_value = gArgs.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX); + std::string blockfilterindex_value = args.GetArg("-blockfilterindex", DEFAULT_BLOCKFILTERINDEX); if (blockfilterindex_value == "" || blockfilterindex_value == "1") { g_enabled_filter_types = AllBlockFilterTypes(); } else if (blockfilterindex_value != "0") { - const std::vector<std::string> names = gArgs.GetArgs("-blockfilterindex"); + const std::vector<std::string> names = args.GetArgs("-blockfilterindex"); for (const auto& name : names) { BlockFilterType filter_type; if (!BlockFilterTypeByName(name, filter_type)) { @@ -1001,7 +988,7 @@ bool AppInitParameterInteraction() } // Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled. - if (gArgs.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) { + if (args.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) { if (g_enabled_filter_types.count(BlockFilterType::BASIC) != 1) { return InitError(_("Cannot set -peerblockfilters without -blockfilterindex.")); } @@ -1010,8 +997,8 @@ bool AppInitParameterInteraction() } // if using block pruning, then disallow txindex - if (gArgs.GetArg("-prune", 0)) { - if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) + if (args.GetArg("-prune", 0)) { + if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); if (!g_enabled_filter_types.empty()) { return InitError(_("Prune mode is incompatible with -blockfilterindex.")); @@ -1019,14 +1006,14 @@ bool AppInitParameterInteraction() } // -bind and -whitebind can't be set when not listening - size_t nUserBind = gArgs.GetArgs("-bind").size() + gArgs.GetArgs("-whitebind").size(); - if (nUserBind != 0 && !gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) { + size_t nUserBind = args.GetArgs("-bind").size() + args.GetArgs("-whitebind").size(); + if (nUserBind != 0 && !args.GetBoolArg("-listen", DEFAULT_LISTEN)) { return InitError(Untranslated("Cannot set -bind or -whitebind together with -listen=0")); } // Make sure enough file descriptors are available int nBind = std::max(nUserBind, size_t(1)); - nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); + nUserMaxConnections = args.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); nMaxConnections = std::max(nUserMaxConnections, 0); // Trim requested connection counts, to fit into system limitations @@ -1046,9 +1033,9 @@ bool AppInitParameterInteraction() InitWarning(strprintf(_("Reducing -maxconnections from %d to %d, because of system limitations."), nUserMaxConnections, nMaxConnections)); // ********************************************************* Step 3: parameter-to-internal-flags - if (gArgs.IsArgSet("-debug")) { + if (args.IsArgSet("-debug")) { // Special-case: if -debug=0/-nodebug is set, turn off debugging messages - const std::vector<std::string> categories = gArgs.GetArgs("-debug"); + const std::vector<std::string> categories = args.GetArgs("-debug"); if (std::none_of(categories.begin(), categories.end(), [](std::string cat){return cat == "0" || cat == "none";})) { @@ -1061,28 +1048,28 @@ bool AppInitParameterInteraction() } // Now remove the logging categories which were explicitly excluded - for (const std::string& cat : gArgs.GetArgs("-debugexclude")) { + for (const std::string& cat : args.GetArgs("-debugexclude")) { if (!LogInstance().DisableCategory(cat)) { InitWarning(strprintf(_("Unsupported logging category %s=%s."), "-debugexclude", cat)); } } // Checkmempool and checkblockindex default to true in regtest mode - int ratio = std::min<int>(std::max<int>(gArgs.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + int ratio = std::min<int>(std::max<int>(args.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); if (ratio != 0) { mempool.setSanityCheck(1.0 / ratio); } - fCheckBlockIndex = gArgs.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); - fCheckpointsEnabled = gArgs.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); + fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); + fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); - hashAssumeValid = uint256S(gArgs.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex())); + hashAssumeValid = uint256S(args.GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex())); if (!hashAssumeValid.IsNull()) LogPrintf("Assuming ancestors of block %s have valid signatures.\n", hashAssumeValid.GetHex()); else LogPrintf("Validating signatures for all blocks.\n"); - if (gArgs.IsArgSet("-minimumchainwork")) { - const std::string minChainWorkStr = gArgs.GetArg("-minimumchainwork", ""); + if (args.IsArgSet("-minimumchainwork")) { + const std::string minChainWorkStr = args.GetArg("-minimumchainwork", ""); if (!IsHexNumber(minChainWorkStr)) { return InitError(strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), minChainWorkStr)); } @@ -1096,22 +1083,21 @@ bool AppInitParameterInteraction() } // mempool limits - int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; - int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; + int64_t nMempoolSizeMax = args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMin = args.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))); // 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")) - { + if (args.IsArgSet("-incrementalrelayfee")) { CAmount n = 0; - if (!ParseMoney(gArgs.GetArg("-incrementalrelayfee", ""), n)) - return InitError(AmountErrMsg("incrementalrelayfee", gArgs.GetArg("-incrementalrelayfee", ""))); + if (!ParseMoney(args.GetArg("-incrementalrelayfee", ""), n)) + return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", ""))); incrementalRelayFee = CFeeRate(n); } // block pruning; get the amount of disk space (in MiB) to allot for block & undo files - int64_t nPruneArg = gArgs.GetArg("-prune", 0); + int64_t nPruneArg = args.GetArg("-prune", 0); if (nPruneArg < 0) { return InitError(_("Prune cannot be configured with a negative value.")); } @@ -1128,20 +1114,20 @@ bool AppInitParameterInteraction() fPruneMode = true; } - nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); + nConnectTimeout = args.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); if (nConnectTimeout <= 0) { nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; } - peer_connect_timeout = gArgs.GetArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT); + peer_connect_timeout = args.GetArg("-peertimeout", DEFAULT_PEER_CONNECT_TIMEOUT); if (peer_connect_timeout <= 0) { return InitError(Untranslated("peertimeout cannot be configured with a negative value.")); } - if (gArgs.IsArgSet("-minrelaytxfee")) { + if (args.IsArgSet("-minrelaytxfee")) { CAmount n = 0; - if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) { - return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", ""))); + if (!ParseMoney(args.GetArg("-minrelaytxfee", ""), n)) { + return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", ""))); } // High fee check is done afterward in CWallet::CreateWalletFromFile() ::minRelayTxFee = CFeeRate(n); @@ -1153,48 +1139,46 @@ bool AppInitParameterInteraction() // Sanity check argument for min fee for including tx in block // TODO: Harmonize which arguments need sanity checking and where that happens - if (gArgs.IsArgSet("-blockmintxfee")) - { + if (args.IsArgSet("-blockmintxfee")) { CAmount n = 0; - if (!ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) - return InitError(AmountErrMsg("blockmintxfee", gArgs.GetArg("-blockmintxfee", ""))); + if (!ParseMoney(args.GetArg("-blockmintxfee", ""), n)) + return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", ""))); } // Feerate used to define dust. Shouldn't be changed lightly as old // implementations may inadvertently create non-standard transactions - if (gArgs.IsArgSet("-dustrelayfee")) - { + if (args.IsArgSet("-dustrelayfee")) { CAmount n = 0; - if (!ParseMoney(gArgs.GetArg("-dustrelayfee", ""), n)) - return InitError(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", ""))); + if (!ParseMoney(args.GetArg("-dustrelayfee", ""), n)) + return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", ""))); dustRelayFee = CFeeRate(n); } - fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); + fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); if (!chainparams.IsTestChain() && !fRequireStandard) { return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString())); } - nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp); + nBytesPerSigOp = args.GetArg("-bytespersigop", nBytesPerSigOp); if (!g_wallet_init_interface.ParameterInteraction()) return false; - fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); - fAcceptDatacarrier = gArgs.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); - nMaxDatacarrierBytes = gArgs.GetArg("-datacarriersize", nMaxDatacarrierBytes); + fIsBareMultisigStd = args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); + fAcceptDatacarrier = args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); + nMaxDatacarrierBytes = args.GetArg("-datacarriersize", nMaxDatacarrierBytes); // Option to startup with mocktime set (used for regression testing): - SetMockTime(gArgs.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op + SetMockTime(args.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op - if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) + if (args.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); - if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) + if (args.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) return InitError(Untranslated("rpcserialversion must be non-negative.")); - if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) + if (args.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) return InitError(Untranslated("Unknown rpcserialversion requested.")); - nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + nMaxTipAge = args.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); return true; } @@ -1247,14 +1231,15 @@ bool AppInitLockDataDirectory() bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) { + const ArgsManager& args = *Assert(node.args); const CChainParams& chainparams = Params(); // ********************************************************* Step 4a: application initialization - if (!CreatePidFile()) { + if (!CreatePidFile(args)) { // Detailed error printed inside CreatePidFile(). return false; } if (LogInstance().m_print_to_file) { - if (gArgs.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) { + if (args.GetBoolArg("-shrinkdebugfile", LogInstance().DefaultShrinkDebugFile())) { // Do this first since it both loads a bunch of debug.log into memory, // and because this needs to happen before any other debug.log printing LogInstance().ShrinkDebugFile(); @@ -1271,10 +1256,10 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA LogPrintf("Using data directory %s\n", GetDataDir().string()); // Only log conf file usage message if conf file actually exists. - fs::path config_file_path = GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)); + fs::path config_file_path = GetConfigFile(args.GetArg("-conf", BITCOIN_CONF_FILENAME)); if (fs::exists(config_file_path)) { LogPrintf("Config file: %s\n", config_file_path.string()); - } else if (gArgs.IsArgSet("-conf")) { + } else if (args.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())); } else { @@ -1283,23 +1268,23 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } // Log the config arguments to debug.log - gArgs.LogArgs(); + args.LogArgs(); LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); // Warn about relative -datadir path. - if (gArgs.IsArgSet("-datadir") && !fs::path(gArgs.GetArg("-datadir", "")).is_absolute()) { + if (args.IsArgSet("-datadir") && !fs::path(args.GetArg("-datadir", "")).is_absolute()) { LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */ "current working directory '%s'. This is fragile, because if bitcoin is started in the future " "from a different location, it will be unable to locate the current data files. There could " "also be data loss if bitcoin is started while in a temporary directory.\n", - gArgs.GetArg("-datadir", ""), fs::current_path().string()); + args.GetArg("-datadir", ""), fs::current_path().string()); } InitSignatureCache(); InitScriptExecutionCache(); - int script_threads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); + int script_threads = args.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); if (script_threads <= 0) { // -par=0 means autodetect (number of cores - 1 script threads) // -par=-n means "leave n cores free" (number of cores - n - 1 script threads) @@ -1355,8 +1340,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA * that the server is there and will be ready later). Warmup mode will * be disabled when initialisation is finished. */ - if (gArgs.GetBoolArg("-server", false)) - { + if (args.GetBoolArg("-server", false)) { uiInterface.InitMessage_connect(SetRPCWarmupStatus); if (!AppInitServers(context, node)) return InitError(_("Unable to start HTTP server. See debug log for details.")); @@ -1376,9 +1360,9 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA // need to reindex later. assert(!node.banman); - node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, gArgs.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); + node.banman = MakeUnique<BanMan>(GetDataDir() / "banlist.dat", &uiInterface, args.GetArg("-bantime", DEFAULT_MISBEHAVING_BANTIME)); assert(!node.connman); - node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), gArgs.GetBoolArg("-networkactive", true)); + node.connman = MakeUnique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), args.GetBoolArg("-networkactive", true)); // Make mempool generally available in the node context. For example the connection manager, wallet, or RPC threads, // which are all started after this, may use it from the node context. assert(!node.mempool); @@ -1392,7 +1376,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA // sanitize comments per BIP-0014, format user agent and check total size std::vector<std::string> uacomments; - for (const std::string& cmt : gArgs.GetArgs("-uacomment")) { + for (const std::string& cmt : args.GetArgs("-uacomment")) { if (cmt != SanitizeString(cmt, SAFE_CHARS_UA_COMMENT)) return InitError(strprintf(_("User Agent comment (%s) contains unsafe characters."), cmt)); uacomments.push_back(cmt); @@ -1403,9 +1387,9 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA strSubVersion.size(), MAX_SUBVERSION_LENGTH)); } - if (gArgs.IsArgSet("-onlynet")) { + if (args.IsArgSet("-onlynet")) { std::set<enum Network> nets; - for (const std::string& snet : gArgs.GetArgs("-onlynet")) { + for (const std::string& snet : args.GetArgs("-onlynet")) { enum Network net = ParseNetwork(snet); if (net == NET_UNROUTABLE) return InitError(strprintf(_("Unknown network specified in -onlynet: '%s'"), snet)); @@ -1419,12 +1403,12 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } // Check for host lookup allowed before parsing any network related parameters - fNameLookup = gArgs.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); + fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); - bool proxyRandomize = gArgs.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE); + bool proxyRandomize = args.GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE); // -proxy sets a proxy for all outgoing network traffic // -noproxy (or -proxy=0) as well as the empty string can be used to not set a proxy, this is the default - std::string proxyArg = gArgs.GetArg("-proxy", ""); + std::string proxyArg = args.GetArg("-proxy", ""); SetReachable(NET_ONION, false); if (proxyArg != "" && proxyArg != "0") { CService proxyAddr; @@ -1446,7 +1430,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA // -onion can be used to set only a proxy for .onion, or override normal proxy for .onion addresses // -noonion (or -onion=0) disables connecting to .onion entirely // An empty string is used to not override the onion proxy (in which case it defaults to -proxy set above, or none) - std::string onionArg = gArgs.GetArg("-onion", ""); + std::string onionArg = args.GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 SetReachable(NET_ONION, false); @@ -1464,11 +1448,11 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } // see Step 2: parameter interactions for more information about these - fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); - fDiscover = gArgs.GetBoolArg("-discover", true); - g_relay_txes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + fListen = args.GetBoolArg("-listen", DEFAULT_LISTEN); + fDiscover = args.GetBoolArg("-discover", true); + g_relay_txes = !args.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); - for (const std::string& strAddr : gArgs.GetArgs("-externalip")) { + for (const std::string& strAddr : args.GetArgs("-externalip")) { CService addrLocal; if (Lookup(strAddr, addrLocal, GetListenPort(), fNameLookup) && addrLocal.IsValid()) AddLocal(addrLocal, LOCAL_MANUAL); @@ -1477,8 +1461,8 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } // Read asmap file if configured - if (gArgs.IsArgSet("-asmap")) { - fs::path asmap_path = fs::path(gArgs.GetArg("-asmap", "")); + if (args.IsArgSet("-asmap")) { + fs::path asmap_path = fs::path(args.GetArg("-asmap", "")); if (asmap_path.empty()) { asmap_path = DEFAULT_ASMAP_FILENAME; } @@ -1511,22 +1495,22 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; - if (gArgs.IsArgSet("-maxuploadtarget")) { - nMaxOutboundLimit = gArgs.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; + if (args.IsArgSet("-maxuploadtarget")) { + nMaxOutboundLimit = args.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET) * 1024 * 1024; } // ********************************************************* Step 7: load block chain - fReindex = gArgs.GetBoolArg("-reindex", false); - bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false); + fReindex = args.GetBoolArg("-reindex", false); + bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false); // cache size calculations - int64_t nTotalCache = (gArgs.GetArg("-dbcache", nDefaultDbCache) << 20); + int64_t nTotalCache = (args.GetArg("-dbcache", nDefaultDbCache) << 20); nTotalCache = std::max(nTotalCache, nMinDbCache << 20); // total cache cannot be less than nMinDbCache nTotalCache = std::min(nTotalCache, nMaxDbCache << 20); // total cache cannot be greater than nMaxDbcache int64_t nBlockTreeDBCache = std::min(nTotalCache / 8, nMaxBlockDBCache << 20); nTotalCache -= nBlockTreeDBCache; - int64_t nTxIndexCache = std::min(nTotalCache / 8, gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0); + int64_t nTxIndexCache = std::min(nTotalCache / 8, args.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxTxIndexCache << 20 : 0); nTotalCache -= nTxIndexCache; int64_t filter_index_cache = 0; if (!g_enabled_filter_types.empty()) { @@ -1539,10 +1523,10 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache nTotalCache -= nCoinDBCache; int64_t nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache - int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMax = args.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; LogPrintf("Cache configuration:\n"); LogPrintf("* Using %.1f MiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); - if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { + if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { LogPrintf("* Using %.1f MiB for transaction index database\n", nTxIndexCache * (1.0 / 1024 / 1024)); } for (BlockFilterType filter_type : g_enabled_filter_types) { @@ -1707,7 +1691,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA for (CChainState* chainstate : chainman.GetAll()) { if (!is_coinsview_empty(chainstate)) { uiInterface.InitMessage(_("Verifying blocks...").translated); - if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { + if (fHavePruned && args.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); } @@ -1725,10 +1709,10 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA // Only verify the DB of the active chainstate. This is fixed in later // work when we allow VerifyDB to be parameterized by chainstate. if (&::ChainstateActive() == chainstate && - !CVerifyDB().VerifyDB( + !CVerifyDB().VerifyDB( chainparams, &chainstate->CoinsDB(), - gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), - gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { + args.GetArg("-checklevel", DEFAULT_CHECKLEVEL), + args.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { strLoadError = _("Corrupted block database detected"); failed_verification = true; break; @@ -1784,7 +1768,7 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA fFeeEstimatesInitialized = true; // ********************************************************* Step 8: start indexers - if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { + if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { g_txindex = MakeUnique<TxIndex>(nTxIndexCache, false, fReindex); g_txindex->Start(); } @@ -1844,16 +1828,31 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } #if HAVE_SYSTEM - if (gArgs.IsArgSet("-blocknotify")) + if (args.IsArgSet("-blocknotify")) { + const std::string block_notify = args.GetArg("-blocknotify", ""); + const auto BlockNotifyCallback = [block_notify](SynchronizationState sync_state, const CBlockIndex* pBlockIndex) { + if (sync_state != SynchronizationState::POST_INIT || !pBlockIndex) + return; + + std::string strCmd = block_notify; + if (!strCmd.empty()) { + boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex()); + std::thread t(runCommand, strCmd); + t.detach(); // thread runs free + } + }; uiInterface.NotifyBlockTip_connect(BlockNotifyCallback); + } #endif std::vector<fs::path> vImportFiles; - for (const std::string& strFile : gArgs.GetArgs("-loadblock")) { + for (const std::string& strFile : args.GetArgs("-loadblock")) { vImportFiles.push_back(strFile); } - g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman]{ ThreadImport(chainman, vImportFiles); }); + g_load_block = std::thread(&TraceThread<std::function<void()>>, "loadblk", [=, &chainman, &args] { + ThreadImport(chainman, vImportFiles, args); + }); // Wait for genesis block to be processed { @@ -1892,13 +1891,13 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA } LogPrintf("nBestHeight = %d\n", chain_active_height); - if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) + if (args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(); Discover(); // Map ports with UPnP - if (gArgs.GetBoolArg("-upnp", DEFAULT_UPNP)) { + if (args.GetBoolArg("-upnp", DEFAULT_UPNP)) { StartMapPort(); } @@ -1913,41 +1912,41 @@ bool AppInitMain(const util::Ref& context, NodeContext& node, interfaces::BlockA connOptions.uiInterface = &uiInterface; connOptions.m_banman = node.banman.get(); connOptions.m_msgproc = node.peer_logic.get(); - connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); - connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); - connOptions.m_added_nodes = gArgs.GetArgs("-addnode"); + connOptions.nSendBufferMaxSize = 1000 * args.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); + connOptions.nReceiveFloodSize = 1000 * args.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + connOptions.m_added_nodes = args.GetArgs("-addnode"); connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; connOptions.nMaxOutboundLimit = nMaxOutboundLimit; connOptions.m_peer_connect_timeout = peer_connect_timeout; - for (const std::string& strBind : gArgs.GetArgs("-bind")) { + for (const std::string& strBind : args.GetArgs("-bind")) { CService addrBind; if (!Lookup(strBind, addrBind, GetListenPort(), false)) { return InitError(ResolveErrMsg("bind", strBind)); } connOptions.vBinds.push_back(addrBind); } - for (const std::string& strBind : gArgs.GetArgs("-whitebind")) { + for (const std::string& strBind : args.GetArgs("-whitebind")) { NetWhitebindPermissions whitebind; bilingual_str error; if (!NetWhitebindPermissions::TryParse(strBind, whitebind, error)) return InitError(error); connOptions.vWhiteBinds.push_back(whitebind); } - for (const auto& net : gArgs.GetArgs("-whitelist")) { + for (const auto& net : args.GetArgs("-whitelist")) { NetWhitelistPermissions subnet; bilingual_str error; if (!NetWhitelistPermissions::TryParse(net, subnet, error)) return InitError(error); connOptions.vWhitelistedRange.push_back(subnet); } - connOptions.vSeedNodes = gArgs.GetArgs("-seednode"); + connOptions.vSeedNodes = args.GetArgs("-seednode"); // Initiate outbound connections unless connect=0 - connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect"); + connOptions.m_use_addrman_outgoing = !args.IsArgSet("-connect"); if (!connOptions.m_use_addrman_outgoing) { - const auto connect = gArgs.GetArgs("-connect"); + const auto connect = args.GetArgs("-connect"); if (connect.size() != 1 || connect[0] != "0") { connOptions.m_specified_outgoing = connect; } diff --git a/src/init.h b/src/init.h index 20008ba5be..ce12a80dc7 100644 --- a/src/init.h +++ b/src/init.h @@ -8,8 +8,8 @@ #include <memory> #include <string> -#include <util/system.h> +class ArgsManager; struct NodeContext; namespace interfaces { struct BlockAndHeaderTipInfo; @@ -25,21 +25,21 @@ class Ref; void Interrupt(NodeContext& node); void Shutdown(NodeContext& node); //!Initialize the logging infrastructure -void InitLogging(); +void InitLogging(const ArgsManager& args); //!Parameter interaction: change current parameters depending on various rules -void InitParameterInteraction(); +void InitParameterInteraction(ArgsManager& args); /** Initialize bitcoin core: Basic context setup. * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read. */ -bool AppInitBasicSetup(); +bool AppInitBasicSetup(ArgsManager& args); /** * Initialization: parameter interaction. * @note This can be done before daemonization. Do not call Shutdown() if this function fails. * @pre Parameters should be parsed and config file should be read, AppInitBasicSetup should have been called. */ -bool AppInitParameterInteraction(); +bool AppInitParameterInteraction(const ArgsManager& args); /** * Initialization sanity checks: ecc init, sanity checks, dir lock. * @note This can be done before daemonization. Do not call Shutdown() if this function fails. diff --git a/src/interfaces/node.cpp b/src/interfaces/node.cpp index 21400d00f8..206262eb03 100644 --- a/src/interfaces/node.cpp +++ b/src/interfaces/node.cpp @@ -57,27 +57,13 @@ class NodeImpl : public Node { public: NodeImpl(NodeContext* context) { setContext(context); } - void initError(const bilingual_str& message) override { InitError(message); } - bool parseParameters(int argc, const char* const argv[], std::string& error) override - { - return gArgs.ParseParameters(argc, argv, error); - } - bool readConfigFiles(std::string& error) override { return gArgs.ReadConfigFiles(error, true); } - void forceSetArg(const std::string& arg, const std::string& value) override { gArgs.ForceSetArg(arg, value); } - bool softSetArg(const std::string& arg, const std::string& value) override { return gArgs.SoftSetArg(arg, value); } - bool softSetBoolArg(const std::string& arg, bool value) override { return gArgs.SoftSetBoolArg(arg, value); } - void selectParams(const std::string& network) override { SelectParams(network); } - bool initSettings(std::string& error) override { return gArgs.InitSettings(error); } - uint64_t getAssumedBlockchainSize() override { return Params().AssumedBlockchainSize(); } - uint64_t getAssumedChainStateSize() override { return Params().AssumedChainStateSize(); } - std::string getNetwork() override { return Params().NetworkIDString(); } - void initLogging() override { InitLogging(); } - void initParameterInteraction() override { InitParameterInteraction(); } + void initLogging() override { InitLogging(*Assert(m_context->args)); } + void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); } bilingual_str getWarnings() override { return GetWarnings(true); } uint32_t getLogCategories() override { return LogInstance().GetCategoryMask(); } bool baseInitialize() override { - return AppInitBasicSetup() && AppInitParameterInteraction() && AppInitSanityChecks() && + return AppInitBasicSetup(gArgs) && AppInitParameterInteraction(gArgs) && AppInitSanityChecks() && AppInitLockDataDirectory(); } bool appInitMain(interfaces::BlockAndHeaderTipInfo* tip_info) override @@ -109,7 +95,6 @@ public: StopMapPort(); } } - void setupServerArgs() override { return SetupServerArgs(*m_context); } bool getProxy(Network net, proxyType& proxy_info) override { return GetProxy(net, proxy_info); } size_t getNodeCount(CConnman::NumConnections flags) override { diff --git a/src/interfaces/node.h b/src/interfaces/node.h index 753f3e6b13..0cff7ae3a1 100644 --- a/src/interfaces/node.h +++ b/src/interfaces/node.h @@ -55,41 +55,6 @@ class Node public: virtual ~Node() {} - //! Send init error. - virtual void initError(const bilingual_str& message) = 0; - - //! Set command line arguments. - virtual bool parseParameters(int argc, const char* const argv[], std::string& error) = 0; - - //! Set a command line argument - virtual void forceSetArg(const std::string& arg, const std::string& value) = 0; - - //! Set a command line argument if it doesn't already have a value - virtual bool softSetArg(const std::string& arg, const std::string& value) = 0; - - //! Set a command line boolean argument if it doesn't already have a value - virtual bool softSetBoolArg(const std::string& arg, bool value) = 0; - - //! Load settings from configuration file. - virtual bool readConfigFiles(std::string& error) = 0; - - //! Choose network parameters. - virtual void selectParams(const std::string& network) = 0; - - //! Read and update <datadir>/settings.json file with saved settings. This - //! needs to be called after selectParams() because the settings file - //! location is network-specific. - virtual bool initSettings(std::string& error) = 0; - - //! Get the (assumed) blockchain size. - virtual uint64_t getAssumedBlockchainSize() = 0; - - //! Get the (assumed) chain state size. - virtual uint64_t getAssumedChainStateSize() = 0; - - //! Get network name. - virtual std::string getNetwork() = 0; - //! Init logging. virtual void initLogging() = 0; @@ -117,9 +82,6 @@ public: //! Return whether shutdown was requested. virtual bool shutdownRequested() = 0; - //! Setup arguments - virtual void setupServerArgs() = 0; - //! Map port. virtual void mapPort(bool use_upnp) = 0; diff --git a/src/interfaces/wallet.cpp b/src/interfaces/wallet.cpp index 7fd24425cf..937e602fb0 100644 --- a/src/interfaces/wallet.cpp +++ b/src/interfaces/wallet.cpp @@ -37,6 +37,7 @@ namespace { //! Construct wallet tx struct. WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx) { + LOCK(wallet.cs_wallet); WalletTx result; result.tx = wtx.tx; result.txin_is_mine.reserve(wtx.tx->vin.size()); @@ -132,7 +133,11 @@ public: { return m_wallet->SignMessage(message, pkhash, str_sig); } - bool isSpendable(const CTxDestination& dest) override { return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; } + bool isSpendable(const CTxDestination& dest) override + { + LOCK(m_wallet->cs_wallet); + return m_wallet->IsMine(dest) & ISMINE_SPENDABLE; + } bool haveWatchOnly() override { auto spk_man = m_wallet->GetLegacyScriptPubKeyMan(); diff --git a/src/netaddress.cpp b/src/netaddress.cpp index 04940f7f94..b50cf74069 100644 --- a/src/netaddress.cpp +++ b/src/netaddress.cpp @@ -4,10 +4,11 @@ // file COPYING or http://www.opensource.org/licenses/mit-license.php. #include <netaddress.h> + #include <hash.h> +#include <tinyformat.h> #include <util/strencodings.h> #include <util/asmap.h> -#include <tinyformat.h> #include <algorithm> #include <array> @@ -330,9 +331,9 @@ enum Network CNetAddr::GetNetwork() const std::string CNetAddr::ToStringIP() const { if (IsTor()) - return EncodeBase32(m_addr.data(), m_addr.size()) + ".onion"; + return EncodeBase32(m_addr) + ".onion"; if (IsInternal()) - return EncodeBase32(m_addr.data(), m_addr.size()) + ".internal"; + return EncodeBase32(m_addr) + ".internal"; CService serv(*this, 0); struct sockaddr_storage sockaddr; socklen_t socklen = sizeof(sockaddr); diff --git a/src/qt/bitcoin.cpp b/src/qt/bitcoin.cpp index f53fcc41f3..e63ffdfb36 100644 --- a/src/qt/bitcoin.cpp +++ b/src/qt/bitcoin.cpp @@ -27,9 +27,11 @@ #include <qt/walletmodel.h> #endif // ENABLE_WALLET +#include <init.h> #include <interfaces/handler.h> #include <interfaces/node.h> #include <node/context.h> +#include <node/ui_interface.h> #include <noui.h> #include <uint256.h> #include <util/system.h> @@ -37,6 +39,7 @@ #include <util/translation.h> #include <validation.h> +#include <boost/signals2/connection.hpp> #include <memory> #include <QApplication> @@ -193,10 +196,9 @@ void BitcoinCore::shutdown() static int qt_argc = 1; static const char* qt_argv = "bitcoin-qt"; -BitcoinApplication::BitcoinApplication(interfaces::Node& node): +BitcoinApplication::BitcoinApplication(): QApplication(qt_argc, const_cast<char **>(&qt_argv)), coreThread(nullptr), - m_node(node), optionsModel(nullptr), clientModel(nullptr), window(nullptr), @@ -246,12 +248,12 @@ void BitcoinApplication::createPaymentServer() void BitcoinApplication::createOptionsModel(bool resetSettings) { - optionsModel = new OptionsModel(m_node, this, resetSettings); + optionsModel = new OptionsModel(this, resetSettings); } void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) { - window = new BitcoinGUI(m_node, platformStyle, networkStyle, nullptr); + window = new BitcoinGUI(node(), platformStyle, networkStyle, nullptr); pollShutdownTimer = new QTimer(window); connect(pollShutdownTimer, &QTimer::timeout, window, &BitcoinGUI::detectShutdown); @@ -259,17 +261,26 @@ void BitcoinApplication::createWindow(const NetworkStyle *networkStyle) void BitcoinApplication::createSplashScreen(const NetworkStyle *networkStyle) { - SplashScreen *splash = new SplashScreen(m_node, nullptr, networkStyle); + assert(!m_splash); + m_splash = new SplashScreen(nullptr, networkStyle); // We don't hold a direct pointer to the splash screen after creation, but the splash // screen will take care of deleting itself when finish() happens. - splash->show(); - connect(this, &BitcoinApplication::splashFinished, splash, &SplashScreen::finish); - connect(this, &BitcoinApplication::requestedShutdown, splash, &QWidget::close); + m_splash->show(); + connect(this, &BitcoinApplication::splashFinished, m_splash, &SplashScreen::finish); + connect(this, &BitcoinApplication::requestedShutdown, m_splash, &QWidget::close); +} + +void BitcoinApplication::setNode(interfaces::Node& node) +{ + assert(!m_node); + m_node = &node; + if (optionsModel) optionsModel->setNode(*m_node); + if (m_splash) m_splash->setNode(*m_node); } bool BitcoinApplication::baseInitialize() { - return m_node.baseInitialize(); + return node().baseInitialize(); } void BitcoinApplication::startThread() @@ -277,7 +288,7 @@ void BitcoinApplication::startThread() if(coreThread) return; coreThread = new QThread(this); - BitcoinCore *executor = new BitcoinCore(m_node); + BitcoinCore *executor = new BitcoinCore(node()); executor->moveToThread(coreThread); /* communication to and from thread */ @@ -298,8 +309,8 @@ void BitcoinApplication::parameterSetup() // print to the console unnecessarily. gArgs.SoftSetBoolArg("-printtoconsole", false); - m_node.initLogging(); - m_node.initParameterInteraction(); + InitLogging(gArgs); + InitParameterInteraction(gArgs); } void BitcoinApplication::InitializePruneSetting(bool prune) @@ -331,7 +342,7 @@ void BitcoinApplication::requestShutdown() window->unsubscribeFromCoreSignals(); // Request node shutdown, which can interrupt long operations, like // rescanning a wallet. - m_node.startShutdown(); + node().startShutdown(); // Unsetting the client model can cause the current thread to wait for node // to complete an operation, like wait for a RPC execution to complete. window->setClientModel(nullptr); @@ -353,7 +364,7 @@ void BitcoinApplication::initializeResult(bool success, interfaces::BlockAndHead { // Log this only after AppInitMain finishes, as then logging setup is guaranteed complete qInfo() << "Platform customization:" << platformStyle->getName(); - clientModel = new ClientModel(m_node, optionsModel); + clientModel = new ClientModel(node(), optionsModel); window->setClientModel(clientModel, &tip_info); #ifdef ENABLE_WALLET if (WalletModel::isWalletEnabled()) { @@ -437,9 +448,9 @@ int GuiMain(int argc, char* argv[]) std::unique_ptr<interfaces::Node> node = interfaces::MakeNode(&node_context); // Subscribe to global signals from core - std::unique_ptr<interfaces::Handler> handler_message_box = node->handleMessageBox(noui_ThreadSafeMessageBox); - std::unique_ptr<interfaces::Handler> handler_question = node->handleQuestion(noui_ThreadSafeQuestion); - std::unique_ptr<interfaces::Handler> handler_init_message = node->handleInitMessage(noui_InitMessage); + boost::signals2::scoped_connection handler_message_box = ::uiInterface.ThreadSafeMessageBox_connect(noui_ThreadSafeMessageBox); + boost::signals2::scoped_connection handler_question = ::uiInterface.ThreadSafeQuestion_connect(noui_ThreadSafeQuestion); + boost::signals2::scoped_connection handler_init_message = ::uiInterface.InitMessage_connect(noui_InitMessage); // Do not refer to data directory yet, this can be overridden by Intro::pickDataDirectory @@ -453,15 +464,15 @@ int GuiMain(int argc, char* argv[]) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif - BitcoinApplication app(*node); + BitcoinApplication app; /// 2. Parse command-line options. We do this after qt in order to show an error if there are problems parsing these // Command-line options take precedence: - node->setupServerArgs(); + SetupServerArgs(node_context); SetupUIArgs(gArgs); std::string error; - if (!node->parseParameters(argc, argv, error)) { - node->initError(strprintf(Untranslated("Error parsing command line arguments: %s\n"), error)); + if (!gArgs.ParseParameters(argc, argv, error)) { + InitError(strprintf(Untranslated("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, // message can not be translated because translations have not been initialized @@ -487,7 +498,7 @@ int GuiMain(int argc, char* argv[]) // Show help message immediately after parsing command-line options (for "-lang") and setting locale, // but before showing splash screen. if (HelpRequested(gArgs) || gArgs.IsArgSet("-version")) { - HelpMessageDialog help(*node, nullptr, gArgs.IsArgSet("-version")); + HelpMessageDialog help(nullptr, gArgs.IsArgSet("-version")); help.showOrPrint(); return EXIT_SUCCESS; } @@ -497,18 +508,18 @@ int GuiMain(int argc, char* argv[]) bool did_show_intro = false; bool prune = false; // Intro dialog prune check box // Gracefully exit if the user cancels - if (!Intro::showIfNeeded(*node, did_show_intro, prune)) return EXIT_SUCCESS; + if (!Intro::showIfNeeded(did_show_intro, prune)) return EXIT_SUCCESS; /// 6. Determine availability of data directory and parse bitcoin.conf /// - Do not call GetDataDir(true) before this step finishes if (!CheckDataDirOption()) { - node->initError(strprintf(Untranslated("Specified data directory \"%s\" does not exist.\n"), gArgs.GetArg("-datadir", ""))); + InitError(strprintf(Untranslated("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(Untranslated("Error reading configuration file: %s\n"), error)); + if (!gArgs.ReadConfigFiles(error, true)) { + InitError(strprintf(Untranslated("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; @@ -522,18 +533,18 @@ int GuiMain(int argc, char* argv[]) // Check for -chain, -testnet or -regtest parameter (Params() calls are only valid after this clause) try { - node->selectParams(gArgs.GetChainName()); + SelectParams(gArgs.GetChainName()); } catch(std::exception &e) { - node->initError(Untranslated(strprintf("%s\n", e.what()))); + InitError(Untranslated(strprintf("%s\n", e.what()))); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error: %1").arg(e.what())); return EXIT_FAILURE; } #ifdef ENABLE_WALLET // Parse URIs on command line -- this can affect Params() - PaymentServer::ipcParseCommandLine(*node, argc, argv); + PaymentServer::ipcParseCommandLine(argc, argv); #endif - if (!node->initSettings(error)) { - node->initError(Untranslated(error)); + if (!gArgs.InitSettings(error)) { + InitError(Untranslated(error)); QMessageBox::critical(nullptr, PACKAGE_NAME, QObject::tr("Error initializing settings: %1").arg(QString::fromStdString(error))); return EXIT_FAILURE; } @@ -587,6 +598,8 @@ int GuiMain(int argc, char* argv[]) if (gArgs.GetBoolArg("-splash", DEFAULT_SPLASHSCREEN) && !gArgs.GetBoolArg("-min", false)) app.createSplashScreen(networkStyle.data()); + app.setNode(*node); + int rv = EXIT_SUCCESS; try { @@ -609,10 +622,10 @@ int GuiMain(int argc, char* argv[]) } } catch (const std::exception& e) { PrintExceptionContinue(&e, "Runaway exception"); - app.handleRunawayException(QString::fromStdString(node->getWarnings().translated)); + app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated)); } catch (...) { PrintExceptionContinue(nullptr, "Runaway exception"); - app.handleRunawayException(QString::fromStdString(node->getWarnings().translated)); + app.handleRunawayException(QString::fromStdString(app.node().getWarnings().translated)); } return rv; } diff --git a/src/qt/bitcoin.h b/src/qt/bitcoin.h index 20c6dfc047..69e0a5921e 100644 --- a/src/qt/bitcoin.h +++ b/src/qt/bitcoin.h @@ -10,6 +10,7 @@ #endif #include <QApplication> +#include <assert.h> #include <memory> #include <interfaces/node.h> @@ -20,6 +21,7 @@ class NetworkStyle; class OptionsModel; class PaymentServer; class PlatformStyle; +class SplashScreen; class WalletController; class WalletModel; @@ -54,7 +56,7 @@ class BitcoinApplication: public QApplication { Q_OBJECT public: - explicit BitcoinApplication(interfaces::Node& node); + explicit BitcoinApplication(); ~BitcoinApplication(); #ifdef ENABLE_WALLET @@ -88,6 +90,9 @@ public: /// Setup platform style void setupPlatformStyle(); + interfaces::Node& node() const { assert(m_node); return *m_node; } + void setNode(interfaces::Node& node); + public Q_SLOTS: void initializeResult(bool success, interfaces::BlockAndHeaderTipInfo tip_info); void shutdownResult(); @@ -102,7 +107,6 @@ Q_SIGNALS: private: QThread *coreThread; - interfaces::Node& m_node; OptionsModel *optionsModel; ClientModel *clientModel; BitcoinGUI *window; @@ -114,6 +118,8 @@ private: int returnValue; const PlatformStyle *platformStyle; std::unique_ptr<QWidget> shutdownWindow; + SplashScreen* m_splash = nullptr; + interfaces::Node* m_node = nullptr; void startThread(); }; diff --git a/src/qt/bitcoingui.cpp b/src/qt/bitcoingui.cpp index 56adbf249a..8935ff19bf 100644 --- a/src/qt/bitcoingui.cpp +++ b/src/qt/bitcoingui.cpp @@ -95,7 +95,7 @@ BitcoinGUI::BitcoinGUI(interfaces::Node& node, const PlatformStyle *_platformSty updateWindowTitle(); rpcConsole = new RPCConsole(node, _platformStyle, nullptr); - helpMessageDialog = new HelpMessageDialog(node, this, false); + helpMessageDialog = new HelpMessageDialog(this, false); #ifdef ENABLE_WALLET if(enableWallet) { @@ -821,7 +821,7 @@ void BitcoinGUI::aboutClicked() if(!clientModel) return; - HelpMessageDialog dlg(m_node, this, true); + HelpMessageDialog dlg(this, true); dlg.exec(); } diff --git a/src/qt/forms/debugwindow.ui b/src/qt/forms/debugwindow.ui index 93840b4169..d210faec03 100644 --- a/src/qt/forms/debugwindow.ui +++ b/src/qt/forms/debugwindow.ui @@ -290,7 +290,7 @@ <item row="11" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> - <string>Current number of blocks</string> + <string>Current block height</string> </property> </widget> </item> diff --git a/src/qt/intro.cpp b/src/qt/intro.cpp index ad21dfc3ef..235722d091 100644 --- a/src/qt/intro.cpp +++ b/src/qt/intro.cpp @@ -6,6 +6,7 @@ #include <config/bitcoin-config.h> #endif +#include <chainparams.h> #include <fs.h> #include <qt/intro.h> #include <qt/forms/ui_intro.h> @@ -181,7 +182,7 @@ void Intro::setDataDirectory(const QString &dataDir) } } -bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune) +bool Intro::showIfNeeded(bool& did_show_intro, bool& prune) { did_show_intro = false; @@ -199,13 +200,13 @@ bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& pru { /* Use selectParams here to guarantee Params() can be used by node interface */ try { - node.selectParams(gArgs.GetChainName()); + SelectParams(gArgs.GetChainName()); } catch (const std::exception&) { return false; } /* If current default data directory does not exist, let the user choose one */ - Intro intro(0, node.getAssumedBlockchainSize(), node.getAssumedChainStateSize()); + Intro intro(0, Params().AssumedBlockchainSize(), Params().AssumedChainStateSize()); intro.setDataDirectory(dataDir); intro.setWindowIcon(QIcon(":icons/bitcoin")); did_show_intro = true; @@ -242,7 +243,7 @@ bool Intro::showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& pru * (to be consistent with bitcoind behavior) */ if(dataDir != GUIUtil::getDefaultDataDirectory()) { - node.softSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting + gArgs.SoftSetArg("-datadir", GUIUtil::qstringToBoostPath(dataDir).string()); // use OS locale for path setting } return true; } diff --git a/src/qt/intro.h b/src/qt/intro.h index 732393246e..51f42de7ac 100644 --- a/src/qt/intro.h +++ b/src/qt/intro.h @@ -47,7 +47,7 @@ public: * @note do NOT call global GetDataDir() before calling this function, this * will cause the wrong path to be cached. */ - static bool showIfNeeded(interfaces::Node& node, bool& did_show_intro, bool& prune); + static bool showIfNeeded(bool& did_show_intro, bool& prune); Q_SIGNALS: void requestCheck(); diff --git a/src/qt/optionsmodel.cpp b/src/qt/optionsmodel.cpp index 58a7591c95..7e089b4f95 100644 --- a/src/qt/optionsmodel.cpp +++ b/src/qt/optionsmodel.cpp @@ -27,8 +27,8 @@ const char *DEFAULT_GUI_PROXY_HOST = "127.0.0.1"; static const QString GetDefaultProxyAddress(); -OptionsModel::OptionsModel(interfaces::Node& node, QObject *parent, bool resetSettings) : - QAbstractListModel(parent), m_node(node) +OptionsModel::OptionsModel(QObject *parent, bool resetSettings) : + QAbstractListModel(parent) { Init(resetSettings); } @@ -97,12 +97,12 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("nDatabaseCache")) settings.setValue("nDatabaseCache", (qint64)nDefaultDbCache); - if (!m_node.softSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString())) + if (!gArgs.SoftSetArg("-dbcache", settings.value("nDatabaseCache").toString().toStdString())) addOverriddenOption("-dbcache"); if (!settings.contains("nThreadsScriptVerif")) settings.setValue("nThreadsScriptVerif", DEFAULT_SCRIPTCHECK_THREADS); - if (!m_node.softSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString())) + if (!gArgs.SoftSetArg("-par", settings.value("nThreadsScriptVerif").toString().toStdString())) addOverriddenOption("-par"); if (!settings.contains("strDataDir")) @@ -112,19 +112,19 @@ void OptionsModel::Init(bool resetSettings) #ifdef ENABLE_WALLET if (!settings.contains("bSpendZeroConfChange")) settings.setValue("bSpendZeroConfChange", true); - if (!m_node.softSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) + if (!gArgs.SoftSetBoolArg("-spendzeroconfchange", settings.value("bSpendZeroConfChange").toBool())) addOverriddenOption("-spendzeroconfchange"); #endif // Network if (!settings.contains("fUseUPnP")) settings.setValue("fUseUPnP", DEFAULT_UPNP); - if (!m_node.softSetBoolArg("-upnp", settings.value("fUseUPnP").toBool())) + if (!gArgs.SoftSetBoolArg("-upnp", settings.value("fUseUPnP").toBool())) addOverriddenOption("-upnp"); if (!settings.contains("fListen")) settings.setValue("fListen", DEFAULT_LISTEN); - if (!m_node.softSetBoolArg("-listen", settings.value("fListen").toBool())) + if (!gArgs.SoftSetBoolArg("-listen", settings.value("fListen").toBool())) addOverriddenOption("-listen"); if (!settings.contains("fUseProxy")) @@ -132,7 +132,7 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("addrProxy")) settings.setValue("addrProxy", GetDefaultProxyAddress()); // Only try to set -proxy, if user has enabled fUseProxy - if (settings.value("fUseProxy").toBool() && !m_node.softSetArg("-proxy", settings.value("addrProxy").toString().toStdString())) + if ((settings.value("fUseProxy").toBool() && !gArgs.SoftSetArg("-proxy", settings.value("addrProxy").toString().toStdString()))) addOverriddenOption("-proxy"); else if(!settings.value("fUseProxy").toBool() && !gArgs.GetArg("-proxy", "").empty()) addOverriddenOption("-proxy"); @@ -142,7 +142,7 @@ void OptionsModel::Init(bool resetSettings) if (!settings.contains("addrSeparateProxyTor")) settings.setValue("addrSeparateProxyTor", GetDefaultProxyAddress()); // Only try to set -onion, if user has enabled fUseSeparateProxyTor - if (settings.value("fUseSeparateProxyTor").toBool() && !m_node.softSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString())) + if ((settings.value("fUseSeparateProxyTor").toBool() && !gArgs.SoftSetArg("-onion", settings.value("addrSeparateProxyTor").toString().toStdString()))) addOverriddenOption("-onion"); else if(!settings.value("fUseSeparateProxyTor").toBool() && !gArgs.GetArg("-onion", "").empty()) addOverriddenOption("-onion"); @@ -150,7 +150,7 @@ void OptionsModel::Init(bool resetSettings) // Display if (!settings.contains("language")) settings.setValue("language", ""); - if (!m_node.softSetArg("-lang", settings.value("language").toString().toStdString())) + if (!gArgs.SoftSetArg("-lang", settings.value("language").toString().toStdString())) addOverriddenOption("-lang"); language = settings.value("language").toString(); @@ -244,10 +244,10 @@ void OptionsModel::SetPruneEnabled(bool prune, bool force) const int64_t prune_target_mib = PruneGBtoMiB(settings.value("nPruneSize").toInt()); std::string prune_val = prune ? ToString(prune_target_mib) : "0"; if (force) { - m_node.forceSetArg("-prune", prune_val); + gArgs.ForceSetArg("-prune", prune_val); return; } - if (!m_node.softSetArg("-prune", prune_val)) { + if (!gArgs.SoftSetArg("-prune", prune_val)) { addOverriddenOption("-prune"); } } @@ -353,7 +353,7 @@ bool OptionsModel::setData(const QModelIndex & index, const QVariant & value, in break; case MapPortUPnP: // core option - can be changed on-the-fly settings.setValue("fUseUPnP", value.toBool()); - m_node.mapPort(value.toBool()); + node().mapPort(value.toBool()); break; case MinimizeOnClose: fMinimizeOnClose = value.toBool(); diff --git a/src/qt/optionsmodel.h b/src/qt/optionsmodel.h index 14fdf9046e..3d9e7bbb80 100644 --- a/src/qt/optionsmodel.h +++ b/src/qt/optionsmodel.h @@ -11,6 +11,8 @@ #include <QAbstractListModel> +#include <assert.h> + namespace interfaces { class Node; } @@ -39,7 +41,7 @@ class OptionsModel : public QAbstractListModel Q_OBJECT public: - explicit OptionsModel(interfaces::Node& node, QObject *parent = nullptr, bool resetSettings = false); + explicit OptionsModel(QObject *parent = nullptr, bool resetSettings = false); enum OptionID { StartAtStartup, // bool @@ -92,10 +94,11 @@ public: void setRestartRequired(bool fRequired); bool isRestartRequired() const; - interfaces::Node& node() const { return m_node; } + interfaces::Node& node() const { assert(m_node); return *m_node; } + void setNode(interfaces::Node& node) { assert(!m_node); m_node = &node; } private: - interfaces::Node& m_node; + interfaces::Node* m_node = nullptr; /* Qt-only settings */ bool fHideTrayIcon; bool fMinimizeToTray; diff --git a/src/qt/paymentserver.cpp b/src/qt/paymentserver.cpp index a1da85bda7..8679ced685 100644 --- a/src/qt/paymentserver.cpp +++ b/src/qt/paymentserver.cpp @@ -74,7 +74,7 @@ static QSet<QString> savedPaymentRequests; // Warning: ipcSendCommandLine() is called early in init, // so don't use "Q_EMIT message()", but "QMessageBox::"! // -void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char* argv[]) +void PaymentServer::ipcParseCommandLine(int argc, char* argv[]) { for (int i = 1; i < argc; i++) { @@ -97,11 +97,11 @@ void PaymentServer::ipcParseCommandLine(interfaces::Node& node, int argc, char* auto tempChainParams = CreateChainParams(CBaseChainParams::MAIN); if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { - node.selectParams(CBaseChainParams::MAIN); + SelectParams(CBaseChainParams::MAIN); } else { tempChainParams = CreateChainParams(CBaseChainParams::TESTNET); if (IsValidDestinationString(r.address.toStdString(), *tempChainParams)) { - node.selectParams(CBaseChainParams::TESTNET); + SelectParams(CBaseChainParams::TESTNET); } } } diff --git a/src/qt/paymentserver.h b/src/qt/paymentserver.h index 154f4a7ea6..eaf2bafe59 100644 --- a/src/qt/paymentserver.h +++ b/src/qt/paymentserver.h @@ -61,7 +61,7 @@ class PaymentServer : public QObject public: // Parse URIs on command line // Returns false on error - static void ipcParseCommandLine(interfaces::Node& node, int argc, char *argv[]); + static void ipcParseCommandLine(int argc, char *argv[]); // Returns true if there were URIs on the command line // which were successfully sent to an already-running diff --git a/src/qt/splashscreen.cpp b/src/qt/splashscreen.cpp index 6e6b2b8466..bd63d6e7fb 100644 --- a/src/qt/splashscreen.cpp +++ b/src/qt/splashscreen.cpp @@ -24,8 +24,8 @@ #include <QScreen> -SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle) : - QWidget(nullptr, f), curAlignment(0), m_node(node) +SplashScreen::SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle) : + QWidget(nullptr, f), curAlignment(0) { // set reference point, paddings int paddingRight = 50; @@ -124,7 +124,6 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw setFixedSize(r.size()); move(QGuiApplication::primaryScreen()->geometry().center() - r.center()); - subscribeToCoreSignals(); installEventFilter(this); GUIUtil::handleCloseWindowShortcut(this); @@ -132,14 +131,28 @@ SplashScreen::SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const Netw SplashScreen::~SplashScreen() { - unsubscribeFromCoreSignals(); + if (m_node) unsubscribeFromCoreSignals(); +} + +void SplashScreen::setNode(interfaces::Node& node) +{ + assert(!m_node); + m_node = &node; + subscribeToCoreSignals(); + if (m_shutdown) m_node->startShutdown(); +} + +void SplashScreen::shutdown() +{ + m_shutdown = true; + if (m_node) m_node->startShutdown(); } bool SplashScreen::eventFilter(QObject * obj, QEvent * ev) { if (ev->type() == QEvent::KeyPress) { QKeyEvent *keyEvent = static_cast<QKeyEvent *>(ev); if (keyEvent->key() == Qt::Key_Q) { - m_node.startShutdown(); + shutdown(); } } return QObject::eventFilter(obj, ev); @@ -183,10 +196,10 @@ void SplashScreen::ConnectWallet(std::unique_ptr<interfaces::Wallet> wallet) void SplashScreen::subscribeToCoreSignals() { // Connect signals to client - m_handler_init_message = m_node.handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1)); - m_handler_show_progress = m_node.handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); + m_handler_init_message = m_node->handleInitMessage(std::bind(InitMessage, this, std::placeholders::_1)); + m_handler_show_progress = m_node->handleShowProgress(std::bind(ShowProgress, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); #ifdef ENABLE_WALLET - m_handler_load_wallet = m_node.handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); }); + m_handler_load_wallet = m_node->handleLoadWallet([this](std::unique_ptr<interfaces::Wallet> wallet) { ConnectWallet(std::move(wallet)); }); #endif } @@ -221,6 +234,6 @@ void SplashScreen::paintEvent(QPaintEvent *event) void SplashScreen::closeEvent(QCloseEvent *event) { - m_node.startShutdown(); // allows an "emergency" shutdown during startup + shutdown(); // allows an "emergency" shutdown during startup event->ignore(); } diff --git a/src/qt/splashscreen.h b/src/qt/splashscreen.h index 3158524117..2213b02c55 100644 --- a/src/qt/splashscreen.h +++ b/src/qt/splashscreen.h @@ -28,8 +28,9 @@ class SplashScreen : public QWidget Q_OBJECT public: - explicit SplashScreen(interfaces::Node& node, Qt::WindowFlags f, const NetworkStyle *networkStyle); + explicit SplashScreen(Qt::WindowFlags f, const NetworkStyle *networkStyle); ~SplashScreen(); + void setNode(interfaces::Node& node); protected: void paintEvent(QPaintEvent *event) override; @@ -50,6 +51,8 @@ private: void subscribeToCoreSignals(); /** Disconnect core signals to splash screen */ void unsubscribeFromCoreSignals(); + /** Initiate shutdown */ + void shutdown(); /** Connect wallet signals to splash screen */ void ConnectWallet(std::unique_ptr<interfaces::Wallet> wallet); @@ -58,7 +61,8 @@ private: QColor curColor; int curAlignment; - interfaces::Node& m_node; + interfaces::Node* m_node = nullptr; + bool m_shutdown = false; std::unique_ptr<interfaces::Handler> m_handler_init_message; std::unique_ptr<interfaces::Handler> m_handler_show_progress; std::unique_ptr<interfaces::Handler> m_handler_load_wallet; diff --git a/src/qt/test/addressbooktests.cpp b/src/qt/test/addressbooktests.cpp index 035c8196bc..84f981dff3 100644 --- a/src/qt/test/addressbooktests.cpp +++ b/src/qt/test/addressbooktests.cpp @@ -108,7 +108,7 @@ void TestAddAddressesToSendBook(interfaces::Node& node) // Initialize relevant QT models. std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other")); - OptionsModel optionsModel(node); + OptionsModel optionsModel; ClientModel clientModel(node, &optionsModel); AddWallet(wallet); WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get()); diff --git a/src/qt/test/test_main.cpp b/src/qt/test/test_main.cpp index 031913bd02..86356b43c8 100644 --- a/src/qt/test/test_main.cpp +++ b/src/qt/test/test_main.cpp @@ -68,11 +68,11 @@ int main(int argc, char* argv[]) // Don't remove this, it's needed to access // QApplication:: and QCoreApplication:: in the tests - BitcoinApplication app(*node); + BitcoinApplication app; + app.setNode(*node); app.setApplicationName("Bitcoin-Qt-test"); - node->setupServerArgs(); // Make gArgs available in the NodeContext - node->context()->args->ClearArgs(); // Clear added args again + app.node().context()->args = &gArgs; // Make gArgs available in the NodeContext AppTests app_tests(app); if (QTest::qExec(&app_tests) != 0) { fInvalid = true; @@ -81,7 +81,7 @@ int main(int argc, char* argv[]) if (QTest::qExec(&test1) != 0) { fInvalid = true; } - RPCNestedTests test3(*node); + RPCNestedTests test3(app.node()); if (QTest::qExec(&test3) != 0) { fInvalid = true; } @@ -90,11 +90,11 @@ int main(int argc, char* argv[]) fInvalid = true; } #ifdef ENABLE_WALLET - WalletTests test5(*node); + WalletTests test5(app.node()); if (QTest::qExec(&test5) != 0) { fInvalid = true; } - AddressBookTests test6(*node); + AddressBookTests test6(app.node()); if (QTest::qExec(&test6) != 0) { fInvalid = true; } diff --git a/src/qt/test/wallettests.cpp b/src/qt/test/wallettests.cpp index 475fd589af..adcfe0d25c 100644 --- a/src/qt/test/wallettests.cpp +++ b/src/qt/test/wallettests.cpp @@ -163,7 +163,7 @@ void TestGUI(interfaces::Node& node) std::unique_ptr<const PlatformStyle> platformStyle(PlatformStyle::instantiate("other")); SendCoinsDialog sendCoinsDialog(platformStyle.get()); TransactionView transactionView(platformStyle.get()); - OptionsModel optionsModel(node); + OptionsModel optionsModel; ClientModel clientModel(node, &optionsModel); AddWallet(wallet); WalletModel walletModel(interfaces::MakeWallet(wallet), clientModel, platformStyle.get()); diff --git a/src/qt/utilitydialog.cpp b/src/qt/utilitydialog.cpp index 01922cf996..b7f85446f4 100644 --- a/src/qt/utilitydialog.cpp +++ b/src/qt/utilitydialog.cpp @@ -28,7 +28,7 @@ #include <QVBoxLayout> /** "Help message" or "About" dialog box */ -HelpMessageDialog::HelpMessageDialog(interfaces::Node& node, QWidget *parent, bool about) : +HelpMessageDialog::HelpMessageDialog(QWidget *parent, bool about) : QDialog(parent), ui(new Ui::HelpMessageDialog) { diff --git a/src/qt/utilitydialog.h b/src/qt/utilitydialog.h index 425b468f40..d2a5d5f67f 100644 --- a/src/qt/utilitydialog.h +++ b/src/qt/utilitydialog.h @@ -12,10 +12,6 @@ QT_BEGIN_NAMESPACE class QMainWindow; QT_END_NAMESPACE -namespace interfaces { - class Node; -} - namespace Ui { class HelpMessageDialog; } @@ -26,7 +22,7 @@ class HelpMessageDialog : public QDialog Q_OBJECT public: - explicit HelpMessageDialog(interfaces::Node& node, QWidget *parent, bool about); + explicit HelpMessageDialog(QWidget *parent, bool about); ~HelpMessageDialog(); void printToConsole(); diff --git a/src/rpc/mining.cpp b/src/rpc/mining.cpp index 76aa9dbfc1..d9cc6f8832 100644 --- a/src/rpc/mining.cpp +++ b/src/rpc/mining.cpp @@ -511,12 +511,13 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) {"mode", RPCArg::Type::STR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "This must be set to \"template\", \"proposal\" (see BIP 23), or omitted"}, {"capabilities", RPCArg::Type::ARR, /* treat as named arg */ RPCArg::Optional::OMITTED_NAMED_ARG, "A list of strings", { - {"support", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasetxn', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"}, + {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported feature, 'longpoll', 'coinbasevalue', 'proposal', 'serverlist', 'workid'"}, }, }, {"rules", RPCArg::Type::ARR, RPCArg::Optional::NO, "A list of strings", { - {"support", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "client side supported softfork deployment"}, + {"segwit", RPCArg::Type::STR, RPCArg::Optional::NO, "(literal) indicates client side segwit support"}, + {"str", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "other client side supported softfork deployment"}, }, }, }, @@ -528,7 +529,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) {RPCResult::Type::NUM, "version", "The preferred block version"}, {RPCResult::Type::ARR, "rules", "specific block rules that are to be enforced", { - {RPCResult::Type::STR, "", "rulename"}, + {RPCResult::Type::STR, "", "name of a rule the client must understand to some extent; see BIP 9 for format"}, }}, {RPCResult::Type::OBJ_DYN, "vbavailable", "set of pending, supported versionbit (BIP 9) softfork deployments", { @@ -536,7 +537,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) }}, {RPCResult::Type::NUM, "vbrequired", "bit mask of versionbits the server requires set in submissions"}, {RPCResult::Type::STR, "previousblockhash", "The hash of current highest block"}, - {RPCResult::Type::ARR, "", "contents of non-coinbase transactions that should be included in the next block", + {RPCResult::Type::ARR, "transactions", "contents of non-coinbase transactions that should be included in the next block", { {RPCResult::Type::OBJ, "", "", { @@ -552,15 +553,12 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) {RPCResult::Type::NUM, "weight", "total transaction weight, as counted for purposes of block limits"}, }}, }}, - {RPCResult::Type::OBJ, "coinbaseaux", "data that should be included in the coinbase's scriptSig content", + {RPCResult::Type::OBJ_DYN, "coinbaseaux", "data that should be included in the coinbase's scriptSig content", { - {RPCResult::Type::ELISION, "", ""}, + {RPCResult::Type::STR_HEX, "key", "values must be in the coinbase (keys may be ignored)"}, }}, {RPCResult::Type::NUM, "coinbasevalue", "maximum allowable input to coinbase transaction, including the generation award and transaction fees (in satoshis)"}, - {RPCResult::Type::OBJ, "coinbasetxn", "information for coinbase transaction", - { - {RPCResult::Type::ELISION, "", ""}, - }}, + {RPCResult::Type::STR, "longpollid", "an id to include with a request to longpoll on an update to this template"}, {RPCResult::Type::STR, "target", "The hash target"}, {RPCResult::Type::NUM_TIME, "mintime", "The minimum timestamp appropriate for the next block time, expressed in " + UNIX_EPOCH_TIME}, {RPCResult::Type::ARR, "mutable", "list of ways the block template may be changed", @@ -574,6 +572,7 @@ static UniValue getblocktemplate(const JSONRPCRequest& request) {RPCResult::Type::NUM_TIME, "curtime", "current timestamp in " + UNIX_EPOCH_TIME}, {RPCResult::Type::STR, "bits", "compressed target of next block"}, {RPCResult::Type::NUM, "height", "The height of the next block"}, + {RPCResult::Type::STR, "default_witness_commitment", /* optional */ true, "a valid witness commitment for the unmodified block template"} }}, RPCExamples{ HelpExampleCli("getblocktemplate", "'{\"rules\": [\"segwit\"]}'") diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index abc8168c55..d6988ee3ac 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -1300,7 +1300,7 @@ UniValue combinepsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << merged_psbt; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); } UniValue finalizepsbt(const JSONRPCRequest& request) @@ -1435,7 +1435,7 @@ UniValue createpsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); } UniValue converttopsbt(const JSONRPCRequest& request) @@ -1502,7 +1502,7 @@ UniValue converttopsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); } UniValue utxoupdatepsbt(const JSONRPCRequest& request) @@ -1590,7 +1590,7 @@ UniValue utxoupdatepsbt(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << psbtx; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); } UniValue joinpsbts(const JSONRPCRequest& request) @@ -1683,7 +1683,7 @@ UniValue joinpsbts(const JSONRPCRequest& request) CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION); ssTx << shuffled_psbt; - return EncodeBase64((unsigned char*)ssTx.data(), ssTx.size()); + return EncodeBase64(MakeUCharSpan(ssTx)); } UniValue analyzepsbt(const JSONRPCRequest& request) diff --git a/src/test/fuzz/net.cpp b/src/test/fuzz/net.cpp new file mode 100644 index 0000000000..1ff9d6b286 --- /dev/null +++ b/src/test/fuzz/net.cpp @@ -0,0 +1,156 @@ +// Copyright (c) 2020 The Bitcoin Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include <chainparams.h> +#include <chainparamsbase.h> +#include <net.h> +#include <net_permissions.h> +#include <netaddress.h> +#include <optional.h> +#include <protocol.h> +#include <random.h> +#include <test/fuzz/FuzzedDataProvider.h> +#include <test/fuzz/fuzz.h> +#include <test/fuzz/util.h> +#include <test/util/setup_common.h> + +#include <cstdint> +#include <string> +#include <vector> + +void initialize() +{ + static const BasicTestingSetup basic_testing_setup; +} + +void test_one_input(const std::vector<uint8_t>& buffer) +{ + FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); + + const std::optional<CAddress> address = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!address) { + return; + } + const std::optional<CAddress> address_bind = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!address_bind) { + return; + } + + CNode node{fuzzed_data_provider.ConsumeIntegral<NodeId>(), + static_cast<ServiceFlags>(fuzzed_data_provider.ConsumeIntegral<uint64_t>()), + fuzzed_data_provider.ConsumeIntegral<int>(), + INVALID_SOCKET, + *address, + fuzzed_data_provider.ConsumeIntegral<uint64_t>(), + fuzzed_data_provider.ConsumeIntegral<uint64_t>(), + *address_bind, + fuzzed_data_provider.ConsumeRandomLengthString(32), + fuzzed_data_provider.PickValueInArray({ConnectionType::INBOUND, ConnectionType::OUTBOUND, ConnectionType::MANUAL, ConnectionType::FEELER, ConnectionType::BLOCK_RELAY, ConnectionType::ADDR_FETCH})}; + while (fuzzed_data_provider.ConsumeBool()) { + switch (fuzzed_data_provider.ConsumeIntegralInRange<int>(0, 12)) { + case 0: { + node.CloseSocketDisconnect(); + break; + } + case 1: { + node.MaybeSetAddrName(fuzzed_data_provider.ConsumeRandomLengthString(32)); + break; + } + case 2: { + node.SetSendVersion(fuzzed_data_provider.ConsumeIntegral<int>()); + break; + } + case 3: { + const std::vector<bool> asmap = ConsumeRandomLengthIntegralVector<bool>(fuzzed_data_provider, 128); + if (!SanityCheckASMap(asmap)) { + break; + } + CNodeStats stats; + node.copyStats(stats, asmap); + break; + } + case 4: { + node.SetRecvVersion(fuzzed_data_provider.ConsumeIntegral<int>()); + break; + } + case 5: { + const CNode* add_ref_node = node.AddRef(); + assert(add_ref_node == &node); + break; + } + case 6: { + if (node.GetRefCount() > 0) { + node.Release(); + } + break; + } + case 7: { + if (node.m_addr_known == nullptr) { + break; + } + const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!addr_opt) { + break; + } + node.AddAddressKnown(*addr_opt); + break; + } + case 8: { + if (node.m_addr_known == nullptr) { + break; + } + const std::optional<CAddress> addr_opt = ConsumeDeserializable<CAddress>(fuzzed_data_provider); + if (!addr_opt) { + break; + } + FastRandomContext fast_random_context{ConsumeUInt256(fuzzed_data_provider)}; + node.PushAddress(*addr_opt, fast_random_context); + break; + } + case 9: { + const std::optional<CInv> inv_opt = ConsumeDeserializable<CInv>(fuzzed_data_provider); + if (!inv_opt) { + break; + } + node.AddKnownTx(inv_opt->hash); + break; + } + case 10: { + node.PushTxInventory(ConsumeUInt256(fuzzed_data_provider)); + break; + } + case 11: { + const std::optional<CService> service_opt = ConsumeDeserializable<CService>(fuzzed_data_provider); + if (!service_opt) { + break; + } + node.SetAddrLocal(*service_opt); + break; + } + case 12: { + const std::vector<uint8_t> b = ConsumeRandomLengthByteVector(fuzzed_data_provider); + bool complete; + node.ReceiveMsgBytes((const char*)b.data(), b.size(), complete); + break; + } + } + } + + (void)node.GetAddrLocal(); + (void)node.GetAddrName(); + (void)node.GetId(); + (void)node.GetLocalNonce(); + (void)node.GetLocalServices(); + (void)node.GetMyStartingHeight(); + (void)node.GetRecvVersion(); + const int ref_count = node.GetRefCount(); + assert(ref_count >= 0); + (void)node.GetSendVersion(); + (void)node.IsAddrRelayPeer(); + + const NetPermissionFlags net_permission_flags = fuzzed_data_provider.ConsumeBool() ? + fuzzed_data_provider.PickValueInArray<NetPermissionFlags>({NetPermissionFlags::PF_NONE, NetPermissionFlags::PF_BLOOMFILTER, NetPermissionFlags::PF_RELAY, NetPermissionFlags::PF_FORCERELAY, NetPermissionFlags::PF_NOBAN, NetPermissionFlags::PF_MEMPOOL, NetPermissionFlags::PF_ISIMPLICIT, NetPermissionFlags::PF_ALL}) : + static_cast<NetPermissionFlags>(fuzzed_data_provider.ConsumeIntegral<uint32_t>()); + (void)node.HasPermission(net_permission_flags); +} diff --git a/src/test/util/setup_common.cpp b/src/test/util/setup_common.cpp index 9d63aad672..d9a00c2205 100644 --- a/src/test/util/setup_common.cpp +++ b/src/test/util/setup_common.cpp @@ -97,8 +97,8 @@ BasicTestingSetup::BasicTestingSetup(const std::string& chainName, const std::ve SelectParams(chainName); SeedInsecureRand(); if (G_TEST_LOG_FUN) LogInstance().PushBackCallback(G_TEST_LOG_FUN); - InitLogging(); - AppInitParameterInteraction(); + InitLogging(*m_node.args); + AppInitParameterInteraction(*m_node.args); LogInstance().StartLogging(); SHA256AutoDetect(); ECC_Start(); @@ -196,49 +196,34 @@ TestingSetup::~TestingSetup() TestChain100Setup::TestChain100Setup() { - // CreateAndProcessBlock() does not support building SegWit blocks, so don't activate in these tests. - // TODO: fix the code to support SegWit blocks. - gArgs.ForceSetArg("-segwitheight", "432"); - // Need to recreate chainparams - SelectParams(CBaseChainParams::REGTEST); - // Generate a 100-block chain: coinbaseKey.MakeNewKey(true); - CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; - for (int i = 0; i < COINBASE_MATURITY; i++) - { + CScript scriptPubKey = CScript() << ToByteVector(coinbaseKey.GetPubKey()) << OP_CHECKSIG; + for (int i = 0; i < COINBASE_MATURITY; i++) { std::vector<CMutableTransaction> noTxns; CBlock b = CreateAndProcessBlock(noTxns, scriptPubKey); m_coinbase_txns.push_back(b.vtx[0]); } } -// Create a new block with just given transactions, coinbase paying to -// scriptPubKey, and try to add it to the current chain. CBlock TestChain100Setup::CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey) { const CChainParams& chainparams = Params(); - std::unique_ptr<CBlockTemplate> pblocktemplate = BlockAssembler(*m_node.mempool, chainparams).CreateNewBlock(scriptPubKey); - CBlock& block = pblocktemplate->block; + CTxMemPool empty_pool; + CBlock block = BlockAssembler(empty_pool, chainparams).CreateNewBlock(scriptPubKey)->block; - // Replace mempool-selected txns with just coinbase plus passed-in txns: - block.vtx.resize(1); - for (const CMutableTransaction& tx : txns) + Assert(block.vtx.size() == 1); + for (const CMutableTransaction& tx : txns) { block.vtx.push_back(MakeTransactionRef(tx)); - // IncrementExtraNonce creates a valid coinbase and merkleRoot - { - LOCK(cs_main); - unsigned int extraNonce = 0; - IncrementExtraNonce(&block, ::ChainActive().Tip(), extraNonce); } + RegenerateCommitments(block); while (!CheckProofOfWork(block.GetHash(), block.nBits, chainparams.GetConsensus())) ++block.nNonce; std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(block); Assert(m_node.chainman)->ProcessNewBlock(chainparams, shared_pblock, true, nullptr); - CBlock result = block; - return result; + return block; } TestChain100Setup::~TestChain100Setup() @@ -246,8 +231,8 @@ TestChain100Setup::~TestChain100Setup() gArgs.ForceSetArg("-segwitheight", "0"); } - -CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction &tx) { +CTxMemPoolEntry TestMemPoolEntryHelper::FromTx(const CMutableTransaction& tx) +{ return FromTx(MakeTransactionRef(tx)); } diff --git a/src/test/util/setup_common.h b/src/test/util/setup_common.h index 78b279e42a..22f5d6d936 100644 --- a/src/test/util/setup_common.h +++ b/src/test/util/setup_common.h @@ -102,15 +102,16 @@ class CBlock; struct CMutableTransaction; class CScript; -// -// Testing fixture that pre-creates a -// 100-block REGTEST-mode block chain -// +/** + * Testing fixture that pre-creates a 100-block REGTEST-mode block chain + */ struct TestChain100Setup : public RegTestingSetup { TestChain100Setup(); - // Create a new block with just given transactions, coinbase paying to - // scriptPubKey, and try to add it to the current chain. + /** + * Create a new block with just given transactions, coinbase paying to + * scriptPubKey, and try to add it to the current chain. + */ CBlock CreateAndProcessBlock(const std::vector<CMutableTransaction>& txns, const CScript& scriptPubKey); diff --git a/src/threadsafety.h b/src/threadsafety.h index 5f2c40bac6..52bf83b676 100644 --- a/src/threadsafety.h +++ b/src/threadsafety.h @@ -18,9 +18,7 @@ #define LOCKABLE __attribute__((lockable)) #define SCOPED_LOCKABLE __attribute__((scoped_lockable)) #define GUARDED_BY(x) __attribute__((guarded_by(x))) -#define GUARDED_VAR __attribute__((guarded_var)) #define PT_GUARDED_BY(x) __attribute__((pt_guarded_by(x))) -#define PT_GUARDED_VAR __attribute__((pt_guarded_var)) #define ACQUIRED_AFTER(...) __attribute__((acquired_after(__VA_ARGS__))) #define ACQUIRED_BEFORE(...) __attribute__((acquired_before(__VA_ARGS__))) #define EXCLUSIVE_LOCK_FUNCTION(...) __attribute__((exclusive_lock_function(__VA_ARGS__))) @@ -33,14 +31,12 @@ #define EXCLUSIVE_LOCKS_REQUIRED(...) __attribute__((exclusive_locks_required(__VA_ARGS__))) #define SHARED_LOCKS_REQUIRED(...) __attribute__((shared_locks_required(__VA_ARGS__))) #define NO_THREAD_SAFETY_ANALYSIS __attribute__((no_thread_safety_analysis)) -#define ASSERT_EXCLUSIVE_LOCK(...) __attribute((assert_exclusive_lock(__VA_ARGS__))) +#define ASSERT_EXCLUSIVE_LOCK(...) __attribute__((assert_exclusive_lock(__VA_ARGS__))) #else #define LOCKABLE #define SCOPED_LOCKABLE #define GUARDED_BY(x) -#define GUARDED_VAR #define PT_GUARDED_BY(x) -#define PT_GUARDED_VAR #define ACQUIRED_AFTER(...) #define ACQUIRED_BEFORE(...) #define EXCLUSIVE_LOCK_FUNCTION(...) diff --git a/src/util/message.cpp b/src/util/message.cpp index 1e7128d225..e1d5cff48c 100644 --- a/src/util/message.cpp +++ b/src/util/message.cpp @@ -64,7 +64,7 @@ bool MessageSign( return false; } - signature = EncodeBase64(signature_bytes.data(), signature_bytes.size()); + signature = EncodeBase64(signature_bytes); return true; } diff --git a/src/util/strencodings.cpp b/src/util/strencodings.cpp index 6d93029737..079a4529a3 100644 --- a/src/util/strencodings.cpp +++ b/src/util/strencodings.cpp @@ -126,20 +126,20 @@ void SplitHostPort(std::string in, int &portOut, std::string &hostOut) { hostOut = in; } -std::string EncodeBase64(const unsigned char* pch, size_t len) +std::string EncodeBase64(Span<const unsigned char> input) { static const char *pbase64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; std::string str; - str.reserve(((len + 2) / 3) * 4); - ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, pch, pch + len); + str.reserve(((input.size() + 2) / 3) * 4); + ConvertBits<8, 6, true>([&](int v) { str += pbase64[v]; }, input.begin(), input.end()); while (str.size() % 4) str += '='; return str; } std::string EncodeBase64(const std::string& str) { - return EncodeBase64((const unsigned char*)str.data(), str.size()); + return EncodeBase64(MakeUCharSpan(str)); } std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid) @@ -201,20 +201,20 @@ std::string DecodeBase64(const std::string& str, bool* pf_invalid) return std::string((const char*)vchRet.data(), vchRet.size()); } -std::string EncodeBase32(const unsigned char* pch, size_t len) +std::string EncodeBase32(Span<const unsigned char> input) { static const char *pbase32 = "abcdefghijklmnopqrstuvwxyz234567"; std::string str; - str.reserve(((len + 4) / 5) * 8); - ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, pch, pch + len); + str.reserve(((input.size() + 4) / 5) * 8); + ConvertBits<8, 5, true>([&](int v) { str += pbase32[v]; }, input.begin(), input.end()); while (str.size() % 8) str += '='; return str; } std::string EncodeBase32(const std::string& str) { - return EncodeBase32((const unsigned char*)str.data(), str.size()); + return EncodeBase32(MakeUCharSpan(str)); } std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid) diff --git a/src/util/strencodings.h b/src/util/strencodings.h index 4c7a2694a9..1519214140 100644 --- a/src/util/strencodings.h +++ b/src/util/strencodings.h @@ -48,11 +48,11 @@ bool IsHex(const std::string& str); bool IsHexNumber(const std::string& str); std::vector<unsigned char> DecodeBase64(const char* p, bool* pf_invalid = nullptr); std::string DecodeBase64(const std::string& str, bool* pf_invalid = nullptr); -std::string EncodeBase64(const unsigned char* pch, size_t len); +std::string EncodeBase64(Span<const unsigned char> input); std::string EncodeBase64(const std::string& str); std::vector<unsigned char> DecodeBase32(const char* p, bool* pf_invalid = nullptr); std::string DecodeBase32(const std::string& str, bool* pf_invalid = nullptr); -std::string EncodeBase32(const unsigned char* pch, size_t len); +std::string EncodeBase32(Span<const unsigned char> input); std::string EncodeBase32(const std::string& str); void SplitHostPort(std::string in, int& portOut, std::string& hostOut); diff --git a/src/wallet/rpcwallet.cpp b/src/wallet/rpcwallet.cpp index 7a03c4f544..17512265b5 100644 --- a/src/wallet/rpcwallet.cpp +++ b/src/wallet/rpcwallet.cpp @@ -2836,6 +2836,15 @@ static UniValue listunspent(const JSONRPCRequest& request) if (!request.params[4].isNull()) { const UniValue& options = request.params[4].get_obj(); + RPCTypeCheckObj(options, + { + {"minimumAmount", UniValueType()}, + {"maximumAmount", UniValueType()}, + {"minimumSumAmount", UniValueType()}, + {"maximumCount", UniValueType(UniValue::VNUM)}, + }, + true, true); + if (options.exists("minimumAmount")) nMinimumAmount = AmountFromValue(options["minimumAmount"]); diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp index c132a4be42..fa00d12551 100644 --- a/src/wallet/wallet.cpp +++ b/src/wallet/wallet.cpp @@ -276,7 +276,7 @@ std::string COutput::ToString() const const CWalletTx* CWallet::GetWalletTx(const uint256& hash) const { - LOCK(cs_wallet); + AssertLockHeld(cs_wallet); std::map<uint256, CWalletTx>::const_iterator it = mapWallet.find(hash); if (it == mapWallet.end()) return nullptr; @@ -1210,15 +1210,13 @@ void CWallet::BlockUntilSyncedToCurrentChain() const { isminetype CWallet::IsMine(const CTxIn &txin) const { + AssertLockHeld(cs_wallet); + std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); + if (mi != mapWallet.end()) { - LOCK(cs_wallet); - std::map<uint256, CWalletTx>::const_iterator mi = mapWallet.find(txin.prevout.hash); - if (mi != mapWallet.end()) - { - const CWalletTx& prev = (*mi).second; - if (txin.prevout.n < prev.tx->vout.size()) - return IsMine(prev.tx->vout[txin.prevout.n]); - } + const CWalletTx& prev = (*mi).second; + if (txin.prevout.n < prev.tx->vout.size()) + return IsMine(prev.tx->vout[txin.prevout.n]); } return ISMINE_NO; } @@ -1243,16 +1241,19 @@ CAmount CWallet::GetDebit(const CTxIn &txin, const isminefilter& filter) const isminetype CWallet::IsMine(const CTxOut& txout) const { + AssertLockHeld(cs_wallet); return IsMine(txout.scriptPubKey); } isminetype CWallet::IsMine(const CTxDestination& dest) const { + AssertLockHeld(cs_wallet); return IsMine(GetScriptForDestination(dest)); } isminetype CWallet::IsMine(const CScript& script) const { + AssertLockHeld(cs_wallet); isminetype result = ISMINE_NO; for (const auto& spk_man_pair : m_spk_managers) { result = std::max(result, spk_man_pair.second->IsMine(script)); @@ -1264,6 +1265,7 @@ CAmount CWallet::GetCredit(const CTxOut& txout, const isminefilter& filter) cons { if (!MoneyRange(txout.nValue)) throw std::runtime_error(std::string(__func__) + ": value out of range"); + LOCK(cs_wallet); return ((IsMine(txout) & filter) ? txout.nValue : 0); } @@ -1281,13 +1283,12 @@ bool CWallet::IsChange(const CScript& script) const // a better way of identifying which outputs are 'the send' and which are // 'the change' will need to be implemented (maybe extend CWalletTx to remember // which output, if any, was change). + AssertLockHeld(cs_wallet); if (IsMine(script)) { CTxDestination address; if (!ExtractDestination(script, address)) return true; - - LOCK(cs_wallet); if (!FindAddressBookEntry(address)) { return true; } @@ -1297,6 +1298,7 @@ bool CWallet::IsChange(const CScript& script) const CAmount CWallet::GetChange(const CTxOut& txout) const { + AssertLockHeld(cs_wallet); if (!MoneyRange(txout.nValue)) throw std::runtime_error(std::string(__func__) + ": value out of range"); return (IsChange(txout) ? txout.nValue : 0); @@ -1304,6 +1306,7 @@ CAmount CWallet::GetChange(const CTxOut& txout) const bool CWallet::IsMine(const CTransaction& tx) const { + AssertLockHeld(cs_wallet); for (const CTxOut& txout : tx.vout) if (IsMine(txout)) return true; @@ -1362,6 +1365,7 @@ CAmount CWallet::GetCredit(const CTransaction& tx, const isminefilter& filter) c CAmount CWallet::GetChange(const CTransaction& tx) const { + LOCK(cs_wallet); CAmount nChange = 0; for (const CTxOut& txout : tx.vout) { @@ -1597,6 +1601,7 @@ void CWalletTx::GetAmounts(std::list<COutputEntry>& listReceived, nFee = nDebit - nValueOut; } + LOCK(pwallet->cs_wallet); // Sent/received. for (unsigned int i = 0; i < tx->vout.size(); ++i) { @@ -1983,6 +1988,7 @@ bool CWalletTx::IsTrusted(std::set<uint256>& trusted_parents) const if (!InMempool()) return false; // Trusted if all inputs are from us and are in the mempool: + LOCK(pwallet->cs_wallet); for (const CTxIn& txin : tx->vin) { // Transactions not sent by us: not trusted @@ -3194,6 +3200,7 @@ DBErrors CWallet::ZapWalletTx(std::list<CWalletTx>& vWtx) bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& address, const std::string& strName, const std::string& strPurpose) { bool fUpdated = false; + bool is_mine; { LOCK(cs_wallet); std::map<CTxDestination, CAddressBookData>::iterator mi = m_address_book.find(address); @@ -3201,8 +3208,9 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add m_address_book[address].SetLabel(strName); if (!strPurpose.empty()) /* update purpose only if requested */ m_address_book[address].purpose = strPurpose; + is_mine = IsMine(address) != ISMINE_NO; } - NotifyAddressBookChanged(this, address, strName, IsMine(address) != ISMINE_NO, + NotifyAddressBookChanged(this, address, strName, is_mine, strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) ); if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose)) return false; @@ -3217,17 +3225,16 @@ bool CWallet::SetAddressBook(const CTxDestination& address, const std::string& s bool CWallet::DelAddressBook(const CTxDestination& address) { - // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted) - // NOTE: This isn't a problem for sending addresses because they never have any DestData yet! - // When adding new DestData, it should be considered here whether to retain or delete it (or move it?). - if (IsMine(address)) { - WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT); - return false; - } - + bool is_mine; { LOCK(cs_wallet); - + // If we want to delete receiving addresses, we need to take care that DestData "used" (and possibly newer DestData) gets preserved (and the "deleted" address transformed into a change entry instead of actually being deleted) + // NOTE: This isn't a problem for sending addresses because they never have any DestData yet! + // When adding new DestData, it should be considered here whether to retain or delete it (or move it?). + if (IsMine(address)) { + WalletLogPrintf("%s called with IsMine address, NOT SUPPORTED. Please report this bug! %s\n", __func__, PACKAGE_BUGREPORT); + return false; + } // Delete destdata tuples associated with address std::string strAddress = EncodeDestination(address); for (const std::pair<const std::string, std::string> &item : m_address_book[address].destdata) @@ -3235,9 +3242,10 @@ bool CWallet::DelAddressBook(const CTxDestination& address) WalletBatch(*database).EraseDestData(strAddress, item.first); } m_address_book.erase(address); + is_mine = IsMine(address) != ISMINE_NO; } - NotifyAddressBookChanged(this, address, "", IsMine(address) != ISMINE_NO, "", CT_DELETED); + NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED); WalletBatch(*database).ErasePurpose(EncodeDestination(address)); return WalletBatch(*database).EraseName(EncodeDestination(address)); diff --git a/src/wallet/wallet.h b/src/wallet/wallet.h index 2f9d301000..f421de0cf2 100644 --- a/src/wallet/wallet.h +++ b/src/wallet/wallet.h @@ -805,7 +805,7 @@ public: /** Interface for accessing chain state. */ interfaces::Chain& chain() const { assert(m_chain); return *m_chain; } - const CWalletTx* GetWalletTx(const uint256& hash) const; + const CWalletTx* GetWalletTx(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); //! check whether we are allowed to upgrade (or already support) to the named feature bool CanSupportFeature(enum WalletFeature wf) const override EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); return nWalletMaxVersion >= wf; } @@ -1051,20 +1051,20 @@ public: bool GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error); bool GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error); - isminetype IsMine(const CTxDestination& dest) const; - isminetype IsMine(const CScript& script) const; - isminetype IsMine(const CTxIn& txin) const; + isminetype IsMine(const CTxDestination& dest) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + isminetype IsMine(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + isminetype IsMine(const CTxIn& txin) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** * Returns amount of debit if the input matches the * filter, otherwise returns 0 */ CAmount GetDebit(const CTxIn& txin, const isminefilter& filter) const; - isminetype IsMine(const CTxOut& txout) const; + isminetype IsMine(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); CAmount GetCredit(const CTxOut& txout, const isminefilter& filter) const; - bool IsChange(const CTxOut& txout) const; - bool IsChange(const CScript& script) const; - CAmount GetChange(const CTxOut& txout) const; - bool IsMine(const CTransaction& tx) const; + bool IsChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool IsChange(const CScript& script) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + CAmount GetChange(const CTxOut& txout) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); + bool IsMine(const CTransaction& tx) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet); /** should probably be renamed to IsRelevantToMe */ bool IsFromMe(const CTransaction& tx) const; CAmount GetDebit(const CTransaction& tx, const isminefilter& filter) const; |