diff options
Diffstat (limited to 'src/init.cpp')
-rw-r--r-- | src/init.cpp | 477 |
1 files changed, 282 insertions, 195 deletions
diff --git a/src/init.cpp b/src/init.cpp index 9a8f1b0850..a997f9740c 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -30,6 +30,7 @@ #include "policy/policy.h" #include "rpc/server.h" #include "rpc/register.h" +#include "rpc/safemode.h" #include "rpc/blockchain.h" #include "script/standard.h" #include "script/sigcache.h" @@ -43,7 +44,7 @@ #include "utilmoneystr.h" #include "validationinterface.h" #ifdef ENABLE_WALLET -#include "wallet/wallet.h" +#include "wallet/init.h" #endif #include "warnings.h" #include <stdint.h> @@ -69,14 +70,13 @@ bool fFeeEstimatesInitialized = false; static const bool DEFAULT_PROXYRANDOMIZE = true; static const bool DEFAULT_REST_ENABLE = false; -static const bool DEFAULT_DISABLE_SAFEMODE = false; static const bool DEFAULT_STOPAFTERBLOCKIMPORT = false; std::unique_ptr<CConnman> g_connman; std::unique_ptr<PeerLogicValidation> peerLogic; #if ENABLE_ZMQ -static CZMQNotificationInterface* pzmqNotificationInterface = NULL; +static CZMQNotificationInterface* pzmqNotificationInterface = nullptr; #endif #ifdef WIN32 @@ -132,10 +132,10 @@ bool ShutdownRequested() * chainstate, while keeping user interface out of the common library, which is shared * between bitcoind, and bitcoin-qt and non-server tools. */ -class CCoinsViewErrorCatcher : public CCoinsViewBacked +class CCoinsViewErrorCatcher final : public CCoinsViewBacked { public: - CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} + explicit CCoinsViewErrorCatcher(CCoinsView* view) : CCoinsViewBacked(view) {} bool GetCoin(const COutPoint &outpoint, Coin &coin) const override { try { return CCoinsViewBacked::GetCoin(outpoint, coin); @@ -152,7 +152,7 @@ public: // Writes do not need similar protection, as failure to write is handled by the caller. }; -static CCoinsViewErrorCatcher *pcoinscatcher = NULL; +static CCoinsViewErrorCatcher *pcoinscatcher = nullptr; static std::unique_ptr<ECCVerifyHandle> globalVerifyHandle; void Interrupt(boost::thread_group& threadGroup) @@ -187,18 +187,19 @@ void Shutdown() StopRPC(); StopHTTPServer(); #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - pwallet->Flush(false); - } + FlushWallets(); #endif MapPort(false); + + // Because these depend on each-other, we make sure that neither can be + // using the other before destroying them. UnregisterValidationInterface(peerLogic.get()); + g_connman->Stop(); peerLogic.reset(); g_connman.reset(); StopTorControl(); - UnregisterNodeSignals(GetNodeSignals()); - if (fDumpMempoolLater && GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { + if (fDumpMempoolLater && gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { DumpMempool(); } @@ -214,31 +215,44 @@ void Shutdown() fFeeEstimatesInitialized = false; } + // FlushStateToDisk generates a SetBestChain callback, which we should avoid missing + if (pcoinsTip != nullptr) { + FlushStateToDisk(); + } + + // After there are no more peers/RPC left to give us new data which may generate + // CValidationInterface callbacks, flush them... + GetMainSignals().FlushBackgroundCallbacks(); + + // Any future callbacks will be dropped. This should absolutely be safe - if + // missing a callback results in an unrecoverable situation, unclean shutdown + // would too. The only reason to do the above flushes is to let the wallet catch + // up with our current chain to avoid any strange pruning edge cases and make + // next startup faster by avoiding rescan. + { LOCK(cs_main); - if (pcoinsTip != NULL) { + if (pcoinsTip != nullptr) { FlushStateToDisk(); } delete pcoinsTip; - pcoinsTip = NULL; + pcoinsTip = nullptr; delete pcoinscatcher; - pcoinscatcher = NULL; + pcoinscatcher = nullptr; delete pcoinsdbview; - pcoinsdbview = NULL; + pcoinsdbview = nullptr; delete pblocktree; - pblocktree = NULL; + pblocktree = nullptr; } #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - pwallet->Flush(true); - } + StopWallets(); #endif #if ENABLE_ZMQ if (pzmqNotificationInterface) { UnregisterValidationInterface(pzmqNotificationInterface); delete pzmqNotificationInterface; - pzmqNotificationInterface = NULL; + pzmqNotificationInterface = nullptr; } #endif @@ -250,11 +264,9 @@ void Shutdown() } #endif UnregisterAllValidationInterfaces(); + GetMainSignals().UnregisterBackgroundSignalScheduler(); #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - delete pwallet; - } - vpwallets.clear(); + CloseWallets(); #endif globalVerifyHandle.reset(); ECC_Stop(); @@ -283,7 +295,7 @@ static void registerSignalHandler(int signal, void(*handler)(int)) sa.sa_handler = handler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; - sigaction(signal, &sa, NULL); + sigaction(signal, &sa, nullptr); } #endif @@ -300,22 +312,13 @@ void OnRPCStopped() LogPrint(BCLog::RPC, "RPC stopped.\n"); } -void OnRPCPreCommand(const CRPCCommand& cmd) -{ - // Observe safe mode - std::string strWarning = GetWarnings("rpc"); - if (strWarning != "" && !GetBoolArg("-disablesafemode", DEFAULT_DISABLE_SAFEMODE) && - !cmd.okSafeMode) - throw JSONRPCError(RPC_FORBIDDEN_BY_SAFE_MODE, std::string("Safe mode: ") + strWarning); -} - std::string HelpMessage(HelpMessageMode mode) { const auto defaultBaseParams = CreateBaseChainParams(CBaseChainParams::MAIN); const auto testnetBaseParams = CreateBaseChainParams(CBaseChainParams::TESTNET); const auto defaultChainParams = CreateChainParams(CBaseChainParams::MAIN); const auto testnetChainParams = CreateChainParams(CBaseChainParams::TESTNET); - const bool showDebug = GetBoolArg("-help-debug", false); + const bool showDebug = gArgs.GetBoolArg("-help-debug", false); // When adding new options to the categories, please keep and ensure alphabetical ordering. // Do not translate _(...) -help-debug options, Many technical terms, and only a very small audience, so is unnecessary stress to translators. @@ -335,6 +338,9 @@ std::string HelpMessage(HelpMessageMode mode) #endif } strUsage += HelpMessageOpt("-datadir=<dir>", _("Specify data directory")); + if (showDebug) { + strUsage += HelpMessageOpt("-dbbatchsize", strprintf("Maximum database write batch size in bytes (default: %u)", nDefaultDbBatchSize)); + } strUsage += HelpMessageOpt("-dbcache=<n>", strprintf(_("Set database cache size in megabytes (%d to %d, default: %d)"), nMinDbCache, nMaxDbCache, nDefaultDbCache)); if (showDebug) strUsage += HelpMessageOpt("-feefilter", strprintf("Tell other nodes to filter invs to us by our mempool min fee (default: %u)", DEFAULT_FEEFILTER)); @@ -342,6 +348,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxorphantx=<n>", strprintf(_("Keep at most <n> unconnectable transactions in memory (default: %u)"), DEFAULT_MAX_ORPHAN_TRANSACTIONS)); strUsage += HelpMessageOpt("-maxmempool=<n>", strprintf(_("Keep the transaction memory pool below <n> megabytes (default: %u)"), DEFAULT_MAX_MEMPOOL_SIZE)); strUsage += HelpMessageOpt("-mempoolexpiry=<n>", strprintf(_("Do not keep transactions in the mempool longer than <n> hours (default: %u)"), DEFAULT_MEMPOOL_EXPIRY)); + if (showDebug) { + strUsage += HelpMessageOpt("-minimumchainwork=<hex>", strprintf("Minimum work assumed to exist on a valid chain in hex (default: %s, testnet: %s)", defaultChainParams->GetConsensus().nMinimumChainWork.GetHex(), testnetChainParams->GetConsensus().nMinimumChainWork.GetHex())); + } strUsage += HelpMessageOpt("-persistmempool", strprintf(_("Whether to save the mempool on shutdown and load on restart (default: %u)"), DEFAULT_PERSIST_MEMPOOL)); strUsage += HelpMessageOpt("-blockreconstructionextratxn=<n>", strprintf(_("Extra transactions to keep in memory for compact block reconstructions (default: %u)"), DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN)); strUsage += HelpMessageOpt("-par=<n>", strprintf(_("Set the number of script verification threads (%u to %d, 0 = auto, <0 = leave that many cores free, default: %d)"), @@ -400,7 +409,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageOpt("-maxuploadtarget=<n>", strprintf(_("Tries to keep outbound traffic under the given target (in MiB per 24h), 0 = no limit (default: %d)"), DEFAULT_MAX_UPLOAD_TARGET)); #ifdef ENABLE_WALLET - strUsage += CWallet::GetWalletHelpString(showDebug); + strUsage += GetWalletHelpString(showDebug); #endif #if ENABLE_ZMQ @@ -443,7 +452,7 @@ std::string HelpMessage(HelpMessageMode mode) { strUsage += HelpMessageOpt("-logtimemicros", strprintf("Add microsecond precision to debug timestamps (default: %u)", DEFAULT_LOGTIMEMICROS)); strUsage += HelpMessageOpt("-mocktime=<n>", "Replace actual time with <n> seconds since epoch (default: 0)"); - strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit size of signature cache to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); + strUsage += HelpMessageOpt("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE)); strUsage += HelpMessageOpt("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE)); } strUsage += HelpMessageOpt("-maxtxfee=<amt>", strprintf(_("Maximum total fees (in %s) to use in a single wallet transaction or raw transaction; setting this too low may abort large transactions (default: %s)"), @@ -459,9 +468,9 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Node relay options:")); if (showDebug) { - strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", defaultChainParams->RequireStandard())); + strUsage += HelpMessageOpt("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard())); strUsage += HelpMessageOpt("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE))); - strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost about 1/3 of its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE))); + strUsage += HelpMessageOpt("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kB) used to defined dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE))); } strUsage += HelpMessageOpt("-bytespersigop", strprintf(_("Equivalent bytes per sigop in transactions for relay and mining (default: %u)"), DEFAULT_BYTES_PER_SIGOP)); strUsage += HelpMessageOpt("-datacarrier", strprintf(_("Relay and mine data carrier transactions (default: %u)"), DEFAULT_ACCEPT_DATACARRIER)); @@ -474,7 +483,7 @@ std::string HelpMessage(HelpMessageMode mode) strUsage += HelpMessageGroup(_("Block creation options:")); strUsage += HelpMessageOpt("-blockmaxweight=<n>", strprintf(_("Set maximum BIP141 block weight (default: %d)"), DEFAULT_BLOCK_MAX_WEIGHT)); - strUsage += HelpMessageOpt("-blockmaxsize=<n>", strprintf(_("Set maximum block size in bytes (default: %d)"), DEFAULT_BLOCK_MAX_SIZE)); + strUsage += HelpMessageOpt("-blockmaxsize=<n>", _("Set maximum BIP141 block weight to this * 4. Deprecated, use blockmaxweight")); strUsage += HelpMessageOpt("-blockmintxfee=<amt>", strprintf(_("Set lowest fee rate (in %s/kB) for transactions to be included in block creation. (default: %s)"), CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE))); if (showDebug) strUsage += HelpMessageOpt("-blockversion=<n>", "Override block version to test forking scenarios"); @@ -526,7 +535,7 @@ static void BlockNotifyCallback(bool initialSync, const CBlockIndex *pBlockIndex if (initialSync || !pBlockIndex) return; - std::string strCmd = GetArg("-blocknotify", ""); + std::string strCmd = gArgs.GetArg("-blocknotify", ""); boost::replace_all(strCmd, "%s", pBlockIndex->GetBlockHash().GetHex()); boost::thread t(runCommand, strCmd); // thread runs free @@ -538,7 +547,7 @@ static CConditionVariable condvar_GenesisWait; static void BlockNotifyGenesisWait(bool, const CBlockIndex *pBlockIndex) { - if (pBlockIndex != NULL) { + if (pBlockIndex != nullptr) { { boost::unique_lock<boost::mutex> lock_GenesisWait(cs_GenesisWait); fHaveGenesis = true; @@ -628,7 +637,7 @@ void ThreadImport(std::vector<fs::path> vImportFiles) fReindex = false; LogPrintf("Reindexing finished\n"); // To avoid ending up in a situation without genesis block, re-try initializing (no-op if reindexing worked): - InitBlockIndex(chainparams); + LoadGenesisBlock(chainparams); } // hardcoded $DATADIR/bootstrap.dat @@ -663,12 +672,12 @@ void ThreadImport(std::vector<fs::path> vImportFiles) StartShutdown(); } - if (GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { + if (gArgs.GetBoolArg("-stopafterblockimport", DEFAULT_STOPAFTERBLOCKIMPORT)) { LogPrintf("Stopping after block import\n"); StartShutdown(); } } // End scope of CImportingNow - if (GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { + if (gArgs.GetArg("-persistmempool", DEFAULT_PERSIST_MEMPOOL)) { LoadMempool(); fDumpMempoolLater = !fRequestShutdown; } @@ -700,14 +709,13 @@ bool AppInitServers(boost::thread_group& threadGroup) { RPCServer::OnStarted(&OnRPCStarted); RPCServer::OnStopped(&OnRPCStopped); - RPCServer::OnPreCommand(&OnRPCPreCommand); if (!InitHTTPServer()) return false; if (!StartRPC()) return false; if (!StartHTTPRPC()) return false; - if (GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST()) + if (gArgs.GetBoolArg("-rest", DEFAULT_REST_ENABLE) && !StartREST()) return false; if (!StartHTTPServer()) return false; @@ -719,63 +727,72 @@ void InitParameterInteraction() { // when specifying an explicit binding address, you want to listen on it // even when -connect or -proxy is specified - if (IsArgSet("-bind")) { - if (SoftSetBoolArg("-listen", true)) + if (gArgs.IsArgSet("-bind")) { + if (gArgs.SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -bind set -> setting -listen=1\n", __func__); } - if (IsArgSet("-whitebind")) { - if (SoftSetBoolArg("-listen", true)) + if (gArgs.IsArgSet("-whitebind")) { + if (gArgs.SoftSetBoolArg("-listen", true)) LogPrintf("%s: parameter interaction: -whitebind set -> setting -listen=1\n", __func__); } if (gArgs.IsArgSet("-connect")) { // when only connecting to trusted nodes, do not seed via DNS, or listen by default - if (SoftSetBoolArg("-dnsseed", false)) + if (gArgs.SoftSetBoolArg("-dnsseed", false)) LogPrintf("%s: parameter interaction: -connect set -> setting -dnsseed=0\n", __func__); - if (SoftSetBoolArg("-listen", false)) + if (gArgs.SoftSetBoolArg("-listen", false)) LogPrintf("%s: parameter interaction: -connect set -> setting -listen=0\n", __func__); } - if (IsArgSet("-proxy")) { + if (gArgs.IsArgSet("-proxy")) { // to protect privacy, do not listen by default if a default proxy server is specified - if (SoftSetBoolArg("-listen", false)) + if (gArgs.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 (SoftSetBoolArg("-upnp", false)) + if (gArgs.SoftSetBoolArg("-upnp", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -upnp=0\n", __func__); // to protect privacy, do not discover addresses by default - if (SoftSetBoolArg("-discover", false)) + if (gArgs.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -proxy set -> setting -discover=0\n", __func__); } - if (!GetBoolArg("-listen", DEFAULT_LISTEN)) { + if (!gArgs.GetBoolArg("-listen", DEFAULT_LISTEN)) { // do not map ports or try to retrieve public IP when not listening (pointless) - if (SoftSetBoolArg("-upnp", false)) + if (gArgs.SoftSetBoolArg("-upnp", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -upnp=0\n", __func__); - if (SoftSetBoolArg("-discover", false)) + if (gArgs.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -discover=0\n", __func__); - if (SoftSetBoolArg("-listenonion", false)) + if (gArgs.SoftSetBoolArg("-listenonion", false)) LogPrintf("%s: parameter interaction: -listen=0 -> setting -listenonion=0\n", __func__); } - if (IsArgSet("-externalip")) { + if (gArgs.IsArgSet("-externalip")) { // if an explicit public IP is specified, do not try to find others - if (SoftSetBoolArg("-discover", false)) + if (gArgs.SoftSetBoolArg("-discover", false)) LogPrintf("%s: parameter interaction: -externalip set -> setting -discover=0\n", __func__); } // disable whitelistrelay in blocksonly mode - if (GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { - if (SoftSetBoolArg("-whitelistrelay", false)) + if (gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY)) { + if (gArgs.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 (GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { - if (SoftSetBoolArg("-whitelistrelay", true)) + if (gArgs.GetBoolArg("-whitelistforcerelay", DEFAULT_WHITELISTFORCERELAY)) { + if (gArgs.SoftSetBoolArg("-whitelistrelay", true)) LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); } + + if (gArgs.IsArgSet("-blockmaxsize")) { + unsigned int max_size = gArgs.GetArg("-blockmaxsize", 0); + if (gArgs.SoftSetArg("blockmaxweight", strprintf("%d", max_size * WITNESS_SCALE_FACTOR))) { + LogPrintf("%s: parameter interaction: -blockmaxsize=%d -> setting -blockmaxweight=%d (-blockmaxsize is deprecated!)\n", __func__, max_size, max_size * WITNESS_SCALE_FACTOR); + } else { + LogPrintf("%s: Ignoring blockmaxsize setting which is overridden by blockmaxweight", __func__); + } + } } static std::string ResolveErrMsg(const char * const optname, const std::string& strBind) @@ -785,10 +802,10 @@ static std::string ResolveErrMsg(const char * const optname, const std::string& void InitLogging() { - fPrintToConsole = GetBoolArg("-printtoconsole", false); - fLogTimestamps = GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); - fLogTimeMicros = GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); - fLogIPs = GetBoolArg("-logips", DEFAULT_LOGIPS); + fPrintToConsole = gArgs.GetBoolArg("-printtoconsole", false); + fLogTimestamps = gArgs.GetBoolArg("-logtimestamps", DEFAULT_LOGTIMESTAMPS); + fLogTimeMicros = gArgs.GetBoolArg("-logtimemicros", DEFAULT_LOGTIMEMICROS); + fLogIPs = gArgs.GetBoolArg("-logips", DEFAULT_LOGIPS); LogPrintf("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"); LogPrintf("Bitcoin version %s\n", FormatFullVersion()); @@ -823,7 +840,7 @@ bool AppInitBasicSetup() #ifdef _MSC_VER // Turn off Microsoft heap dump noise _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, 0)); + _CrtSetReportFile(_CRT_WARN, CreateFileA("NUL", GENERIC_WRITE, 0, nullptr, OPEN_EXISTING, 0, 0)); // Disable confusing "helpful" text message on abort, Ctrl-C _set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT); #endif @@ -838,14 +855,14 @@ bool AppInitBasicSetup() #endif typedef BOOL (WINAPI *PSETPROCDEPPOL)(DWORD); PSETPROCDEPPOL setProcDEPPol = (PSETPROCDEPPOL)GetProcAddress(GetModuleHandleA("Kernel32.dll"), "SetProcessDEPPolicy"); - if (setProcDEPPol != NULL) setProcDEPPol(PROCESS_DEP_ENABLE); + if (setProcDEPPol != nullptr) setProcDEPPol(PROCESS_DEP_ENABLE); #endif if (!SetupNetworking()) return InitError("Initializing networking failed"); #ifndef WIN32 - if (!GetBoolArg("-sysperms", false)) { + if (!gArgs.GetBoolArg("-sysperms", false)) { umask(077); } @@ -873,8 +890,8 @@ bool AppInitParameterInteraction() // also see: InitParameterInteraction() // if using block pruning, then disallow txindex - if (GetArg("-prune", 0)) { - if (GetBoolArg("-txindex", DEFAULT_TXINDEX)) + if (gArgs.GetArg("-prune", 0)) { + if (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) return InitError(_("Prune mode is incompatible with -txindex.")); } @@ -886,7 +903,7 @@ bool AppInitParameterInteraction() // Make sure enough file descriptors are available int nBind = std::max(nUserBind, size_t(1)); - nUserMaxConnections = GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); + nUserMaxConnections = gArgs.GetArg("-maxconnections", DEFAULT_MAX_PEER_CONNECTIONS); nMaxConnections = std::max(nUserMaxConnections, 0); // Trim requested connection counts, to fit into system limitations @@ -927,55 +944,69 @@ bool AppInitParameterInteraction() } // Check for -debugnet - if (GetBoolArg("-debugnet", false)) + if (gArgs.GetBoolArg("-debugnet", false)) InitWarning(_("Unsupported argument -debugnet ignored, use -debug=net.")); // Check for -socks - as this is a privacy risk to continue, exit here - if (IsArgSet("-socks")) + if (gArgs.IsArgSet("-socks")) return InitError(_("Unsupported argument -socks found. Setting SOCKS version isn't possible anymore, only SOCKS5 proxies are supported.")); // Check for -tor - as this is a privacy risk to continue, exit here - if (GetBoolArg("-tor", false)) + if (gArgs.GetBoolArg("-tor", false)) return InitError(_("Unsupported argument -tor found, use -onion.")); - if (GetBoolArg("-benchmark", false)) + if (gArgs.GetBoolArg("-benchmark", false)) InitWarning(_("Unsupported argument -benchmark ignored, use -debug=bench.")); - if (GetBoolArg("-whitelistalwaysrelay", false)) + if (gArgs.GetBoolArg("-whitelistalwaysrelay", false)) InitWarning(_("Unsupported argument -whitelistalwaysrelay ignored, use -whitelistrelay and/or -whitelistforcerelay.")); - if (IsArgSet("-blockminsize")) + if (gArgs.IsArgSet("-blockminsize")) InitWarning("Unsupported argument -blockminsize ignored."); // Checkmempool and checkblockindex default to true in regtest mode - int ratio = std::min<int>(std::max<int>(GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); + int ratio = std::min<int>(std::max<int>(gArgs.GetArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000); if (ratio != 0) { mempool.setSanityCheck(1.0 / ratio); } - fCheckBlockIndex = GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); - fCheckpointsEnabled = GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); + fCheckBlockIndex = gArgs.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); + fCheckpointsEnabled = gArgs.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); - hashAssumeValid = uint256S(GetArg("-assumevalid", chainparams.GetConsensus().defaultAssumeValid.GetHex())); + hashAssumeValid = uint256S(gArgs.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 (!IsHexNumber(minChainWorkStr)) { + return InitError(strprintf("Invalid non-hex (%s) minimum chain work value specified", minChainWorkStr)); + } + nMinimumChainWork = UintToArith256(uint256S(minChainWorkStr)); + } else { + nMinimumChainWork = UintToArith256(chainparams.GetConsensus().nMinimumChainWork); + } + LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex()); + if (nMinimumChainWork < UintToArith256(chainparams.GetConsensus().nMinimumChainWork)) { + LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainparams.GetConsensus().nMinimumChainWork.GetHex()); + } + // mempool limits - int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; - int64_t nMempoolSizeMin = GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; + int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMin = gArgs.GetArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40; if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin) return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0))); // 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 (IsArgSet("-incrementalrelayfee")) + if (gArgs.IsArgSet("-incrementalrelayfee")) { CAmount n = 0; - if (!ParseMoney(GetArg("-incrementalrelayfee", ""), n)) - return InitError(AmountErrMsg("incrementalrelayfee", GetArg("-incrementalrelayfee", ""))); + if (!ParseMoney(gArgs.GetArg("-incrementalrelayfee", ""), n)) + return InitError(AmountErrMsg("incrementalrelayfee", gArgs.GetArg("-incrementalrelayfee", ""))); incrementalRelayFee = CFeeRate(n); } // -par=0 means autodetect, but nScriptCheckThreads==0 means no concurrency - nScriptCheckThreads = GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); + nScriptCheckThreads = gArgs.GetArg("-par", DEFAULT_SCRIPTCHECK_THREADS); if (nScriptCheckThreads <= 0) nScriptCheckThreads += GetNumCores(); if (nScriptCheckThreads <= 1) @@ -984,7 +1015,7 @@ bool AppInitParameterInteraction() nScriptCheckThreads = MAX_SCRIPTCHECK_THREADS; // block pruning; get the amount of disk space (in MiB) to allot for block & undo files - int64_t nPruneArg = GetArg("-prune", 0); + int64_t nPruneArg = gArgs.GetArg("-prune", 0); if (nPruneArg < 0) { return InitError(_("Prune cannot be configured with a negative value.")); } @@ -1003,19 +1034,19 @@ bool AppInitParameterInteraction() RegisterAllCoreRPCCommands(tableRPC); #ifdef ENABLE_WALLET - RegisterWalletRPCCommands(tableRPC); + RegisterWalletRPC(tableRPC); #endif - nConnectTimeout = GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); + nConnectTimeout = gArgs.GetArg("-timeout", DEFAULT_CONNECT_TIMEOUT); if (nConnectTimeout <= 0) nConnectTimeout = DEFAULT_CONNECT_TIMEOUT; - if (IsArgSet("-minrelaytxfee")) { + if (gArgs.IsArgSet("-minrelaytxfee")) { CAmount n = 0; - if (!ParseMoney(GetArg("-minrelaytxfee", ""), n)) { - return InitError(AmountErrMsg("minrelaytxfee", GetArg("-minrelaytxfee", ""))); + if (!ParseMoney(gArgs.GetArg("-minrelaytxfee", ""), n)) { + return InitError(AmountErrMsg("minrelaytxfee", gArgs.GetArg("-minrelaytxfee", ""))); } - // High fee check is done afterward in CWallet::ParameterInteraction() + // High fee check is done afterward in WalletParameterInteraction() ::minRelayTxFee = CFeeRate(n); } else if (incrementalRelayFee > ::minRelayTxFee) { // Allow only setting incrementalRelayFee to control both @@ -1025,55 +1056,55 @@ 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 (IsArgSet("-blockmintxfee")) + if (gArgs.IsArgSet("-blockmintxfee")) { CAmount n = 0; - if (!ParseMoney(GetArg("-blockmintxfee", ""), n)) - return InitError(AmountErrMsg("blockmintxfee", GetArg("-blockmintxfee", ""))); + if (!ParseMoney(gArgs.GetArg("-blockmintxfee", ""), n)) + return InitError(AmountErrMsg("blockmintxfee", gArgs.GetArg("-blockmintxfee", ""))); } // Feerate used to define dust. Shouldn't be changed lightly as old // implementations may inadvertently create non-standard transactions - if (IsArgSet("-dustrelayfee")) + if (gArgs.IsArgSet("-dustrelayfee")) { CAmount n = 0; - if (!ParseMoney(GetArg("-dustrelayfee", ""), n) || 0 == n) - return InitError(AmountErrMsg("dustrelayfee", GetArg("-dustrelayfee", ""))); + if (!ParseMoney(gArgs.GetArg("-dustrelayfee", ""), n) || 0 == n) + return InitError(AmountErrMsg("dustrelayfee", gArgs.GetArg("-dustrelayfee", ""))); dustRelayFee = CFeeRate(n); } - fRequireStandard = !GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); + fRequireStandard = !gArgs.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard()); if (chainparams.RequireStandard() && !fRequireStandard) return InitError(strprintf("acceptnonstdtxn is not currently supported for %s chain", chainparams.NetworkIDString())); - nBytesPerSigOp = GetArg("-bytespersigop", nBytesPerSigOp); + nBytesPerSigOp = gArgs.GetArg("-bytespersigop", nBytesPerSigOp); #ifdef ENABLE_WALLET - if (!CWallet::ParameterInteraction()) + if (!WalletParameterInteraction()) return false; #endif - fIsBareMultisigStd = GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); - fAcceptDatacarrier = GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); - nMaxDatacarrierBytes = GetArg("-datacarriersize", nMaxDatacarrierBytes); + fIsBareMultisigStd = gArgs.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); + fAcceptDatacarrier = gArgs.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); + nMaxDatacarrierBytes = gArgs.GetArg("-datacarriersize", nMaxDatacarrierBytes); // Option to startup with mocktime set (used for regression testing): - SetMockTime(GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op + SetMockTime(gArgs.GetArg("-mocktime", 0)); // SetMockTime(0) is a no-op - if (GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) + if (gArgs.GetBoolArg("-peerbloomfilters", DEFAULT_PEERBLOOMFILTERS)) nLocalServices = ServiceFlags(nLocalServices | NODE_BLOOM); - if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) + if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) < 0) return InitError("rpcserialversion must be non-negative."); - if (GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) + if (gArgs.GetArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) return InitError("unknown rpcserialversion requested."); - nMaxTipAge = GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); + nMaxTipAge = gArgs.GetArg("-maxtipage", DEFAULT_MAX_TIP_AGE); - fEnableReplacement = GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); - if ((!fEnableReplacement) && IsArgSet("-mempoolreplacement")) { + fEnableReplacement = gArgs.GetBoolArg("-mempoolreplacement", DEFAULT_ENABLE_REPLACEMENT); + if ((!fEnableReplacement) && gArgs.IsArgSet("-mempoolreplacement")) { // Minimal effort at forwards compatibility - std::string strReplacementModeList = GetArg("-mempoolreplacement", ""); // default is impossible + std::string strReplacementModeList = gArgs.GetArg("-mempoolreplacement", ""); // default is impossible std::vector<std::string> vstrReplacementModes; boost::split(vstrReplacementModes, strReplacementModeList, boost::is_any_of(",")); fEnableReplacement = (std::find(vstrReplacementModes.begin(), vstrReplacementModes.end(), "fee") != vstrReplacementModes.end()); @@ -1143,6 +1174,8 @@ bool AppInitSanityChecks() // ********************************************************* Step 4: sanity checks // Initialize elliptic curve code + std::string sha256_algo = SHA256AutoDetect(); + LogPrintf("Using the '%s' SHA256 implementation\n", sha256_algo); RandomInit(); ECC_Start(); globalVerifyHandle.reset(new ECCVerifyHandle()); @@ -1152,13 +1185,13 @@ bool AppInitSanityChecks() return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), _(PACKAGE_NAME))); // Probe the data directory lock to give an early error message, if possible + // We cannot hold the data directory lock here, as the forking for daemon() hasn't yet happened, + // and a fork will cause weird behavior to it. return LockDataDirectory(true); } -bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) +bool AppInitLockDataDirectory() { - const CChainParams& chainparams = Params(); - // ********************************************************* Step 4a: application initialization // After daemonization get the data directory lock again and hold on to it until exit // This creates a slight window for a race condition to happen, however this condition is harmless: it // will at most make us exit without printing a message to console. @@ -1166,11 +1199,17 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Detailed error printed inside LockDataDirectory return false; } + return true; +} +bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) +{ + const CChainParams& chainparams = Params(); + // ********************************************************* Step 4a: application initialization #ifndef WIN32 CreatePidFile(GetPidFile(), getpid()); #endif - if (GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) { + if (gArgs.GetBoolArg("-shrinkdebugfile", logCategories == BCLog::NONE)) { // 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 ShrinkDebugFile(); @@ -1183,10 +1222,11 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Startup time: %s\n", DateTimeStrFormat("%Y-%m-%d %H:%M:%S", GetTime())); LogPrintf("Default data directory %s\n", GetDefaultDataDir().string()); LogPrintf("Using data directory %s\n", GetDataDir().string()); - LogPrintf("Using config file %s\n", GetConfigFile(GetArg("-conf", BITCOIN_CONF_FILENAME)).string()); + LogPrintf("Using config file %s\n", GetConfigFile(gArgs.GetArg("-conf", BITCOIN_CONF_FILENAME)).string()); LogPrintf("Using at most %i automatic connections (%i file descriptors available)\n", nMaxConnections, nFD); InitSignatureCache(); + InitScriptExecutionCache(); LogPrintf("Using %u threads for script verification\n", nScriptCheckThreads); if (nScriptCheckThreads) { @@ -1198,12 +1238,14 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) CScheduler::Function serviceLoop = boost::bind(&CScheduler::serviceQueue, &scheduler); threadGroup.create_thread(boost::bind(&TraceThread<CScheduler::Function>, "scheduler", serviceLoop)); + GetMainSignals().RegisterBackgroundSignalScheduler(scheduler); + /* Start the RPC server already. It will be started in "warmup" mode * and not really process calls already (but it will signify connections * that the server is there and will be ready later). Warmup mode will * be disabled when initialisation is finished. */ - if (GetBoolArg("-server", false)) + if (gArgs.GetBoolArg("-server", false)) { uiInterface.InitMessage.connect(SetRPCWarmupStatus); if (!AppInitServers(threadGroup)) @@ -1214,7 +1256,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 5: verify wallet database integrity #ifdef ENABLE_WALLET - if (!CWallet::Verify()) + if (!VerifyWallets()) return false; #endif // ********************************************************* Step 6: network initialization @@ -1229,7 +1271,6 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) peerLogic.reset(new PeerLogicValidation(&connman)); RegisterValidationInterface(peerLogic.get()); - RegisterNodeSignals(GetNodeSignals()); // sanitize comments per BIP-0014, format user agent and check total size std::vector<std::string> uacomments; @@ -1260,12 +1301,12 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) } // Check for host lookup allowed before parsing any network related parameters - fNameLookup = GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); + fNameLookup = gArgs.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); - bool proxyRandomize = GetBoolArg("-proxyrandomize", DEFAULT_PROXYRANDOMIZE); + bool proxyRandomize = gArgs.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 = GetArg("-proxy", ""); + std::string proxyArg = gArgs.GetArg("-proxy", ""); SetLimited(NET_TOR); if (proxyArg != "" && proxyArg != "0") { CService proxyAddr; @@ -1287,7 +1328,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // -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 = GetArg("-onion", ""); + std::string onionArg = gArgs.GetArg("-onion", ""); if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 SetLimited(NET_TOR); // set onions as unreachable @@ -1305,9 +1346,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) } // see Step 2: parameter interactions for more information about these - fListen = GetBoolArg("-listen", DEFAULT_LISTEN); - fDiscover = GetBoolArg("-discover", true); - fRelayTxes = !GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); + fListen = gArgs.GetBoolArg("-listen", DEFAULT_LISTEN); + fDiscover = gArgs.GetBoolArg("-discover", true); + fRelayTxes = !gArgs.GetBoolArg("-blocksonly", DEFAULT_BLOCKSONLY); for (const std::string& strAddr : gArgs.GetArgs("-externalip")) { CService addrLocal; @@ -1327,34 +1368,34 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) uint64_t nMaxOutboundLimit = 0; //unlimited unless -maxuploadtarget is set uint64_t nMaxOutboundTimeframe = MAX_UPLOAD_TIMEFRAME; - if (IsArgSet("-maxuploadtarget")) { - nMaxOutboundLimit = GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; + if (gArgs.IsArgSet("-maxuploadtarget")) { + nMaxOutboundLimit = gArgs.GetArg("-maxuploadtarget", DEFAULT_MAX_UPLOAD_TARGET)*1024*1024; } // ********************************************************* Step 7: load block chain - fReindex = GetBoolArg("-reindex", false); - bool fReindexChainState = GetBoolArg("-reindex-chainstate", false); + fReindex = gArgs.GetBoolArg("-reindex", false); + bool fReindexChainState = gArgs.GetBoolArg("-reindex-chainstate", false); // cache size calculations - int64_t nTotalCache = (GetArg("-dbcache", nDefaultDbCache) << 20); + int64_t nTotalCache = (gArgs.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 = nTotalCache / 8; - nBlockTreeDBCache = std::min(nBlockTreeDBCache, (GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20); + nBlockTreeDBCache = std::min(nBlockTreeDBCache, (gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX) ? nMaxBlockDBAndTxIndexCache : nMaxBlockDBCache) << 20); nTotalCache -= nBlockTreeDBCache; int64_t nCoinDBCache = std::min(nTotalCache / 2, (nTotalCache / 4) + (1 << 23)); // use 25%-50% of the remainder for disk cache nCoinDBCache = std::min(nCoinDBCache, nMaxCoinsDBCache << 20); // cap total coins db cache nTotalCache -= nCoinDBCache; nCoinCacheUsage = nTotalCache; // the rest goes to in-memory cache - int64_t nMempoolSizeMax = GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; + int64_t nMempoolSizeMax = gArgs.GetArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000; LogPrintf("Cache configuration:\n"); LogPrintf("* Using %.1fMiB for block index database\n", nBlockTreeDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for chain state database\n", nCoinDBCache * (1.0 / 1024 / 1024)); LogPrintf("* Using %.1fMiB for in-memory UTXO set (plus up to %.1fMiB of unused mempool space)\n", nCoinCacheUsage * (1.0 / 1024 / 1024), nMempoolSizeMax * (1.0 / 1024 / 1024)); bool fLoaded = false; - while (!fLoaded) { + while (!fLoaded && !fRequestShutdown) { bool fReset = fReindex; std::string strLoadError; @@ -1369,24 +1410,22 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) delete pcoinscatcher; delete pblocktree; - pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReindex); - pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReindex || fReindexChainState); - pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); - pcoinsTip = new CCoinsViewCache(pcoinscatcher); + pblocktree = new CBlockTreeDB(nBlockTreeDBCache, false, fReset); - if (fReindex) { + if (fReset) { pblocktree->WriteReindexing(true); //If we're reindexing in prune mode, wipe away unusable block files and all undo data files if (fPruneMode) CleanupBlockRevFiles(); - } else { - // If necessary, upgrade from older database format. - if (!pcoinsdbview->Upgrade()) { - strLoadError = _("Error upgrading chainstate database"); - break; - } } + if (fRequestShutdown) break; + + // LoadBlockIndex will load fTxIndex from the db, or set it if + // we're reindexing. It will also load fHavePruned if we've + // ever removed a block file from disk. + // Note that it also sets fReindex based on the disk flag! + // From here on out fReindex and fReset mean something different! if (!LoadBlockIndex(chainparams)) { strLoadError = _("Error loading block database"); break; @@ -1397,15 +1436,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) if (!mapBlockIndex.empty() && mapBlockIndex.count(chainparams.GetConsensus().hashGenesisBlock) == 0) return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?")); - // Initialize the block index (no-op if non-empty database was already loaded) - if (!InitBlockIndex(chainparams)) { - strLoadError = _("Error initializing block database"); - break; - } - // Check for changed -txindex state - if (fTxIndex != GetBoolArg("-txindex", DEFAULT_TXINDEX)) { - strLoadError = _("You need to rebuild the database using -reindex-chainstate to change -txindex"); + if (fTxIndex != gArgs.GetBoolArg("-txindex", DEFAULT_TXINDEX)) { + strLoadError = _("You need to rebuild the database using -reindex to change -txindex"); break; } @@ -1416,7 +1449,51 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) break; } - if (!fReindex && chainActive.Tip() != NULL) { + // At this point blocktree args are consistent with what's on disk. + // If we're not mid-reindex (based on disk + args), add a genesis block on disk + // (otherwise we use the one already on disk). + // This is called again in ThreadImport after the reindex completes. + if (!fReindex && !LoadGenesisBlock(chainparams)) { + strLoadError = _("Error initializing block database"); + break; + } + + // At this point we're either in reindex or we've loaded a useful + // block tree into mapBlockIndex! + + pcoinsdbview = new CCoinsViewDB(nCoinDBCache, false, fReset || fReindexChainState); + pcoinscatcher = new CCoinsViewErrorCatcher(pcoinsdbview); + + // If necessary, upgrade from older database format. + // This is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate + if (!pcoinsdbview->Upgrade()) { + strLoadError = _("Error upgrading chainstate database"); + break; + } + + // ReplayBlocks is a no-op if we cleared the coinsviewdb with -reindex or -reindex-chainstate + if (!ReplayBlocks(chainparams, pcoinsdbview)) { + strLoadError = _("Unable to replay blocks. You will need to rebuild the database using -reindex-chainstate."); + break; + } + + // The on-disk coinsdb is now in a good state, create the cache + pcoinsTip = new CCoinsViewCache(pcoinscatcher); + + bool is_coinsview_empty = fReset || fReindexChainState || pcoinsTip->GetBestBlock().IsNull(); + if (!is_coinsview_empty) { + // LoadChainTip sets chainActive based on pcoinsTip's best block + if (!LoadChainTip(chainparams)) { + strLoadError = _("Error initializing block database"); + break; + } + assert(chainActive.Tip() != nullptr); + } + + if (!fReset) { + // Note that RewindBlockIndex MUST run even if we're about to -reindex-chainstate. + // It both disconnects blocks based on chainActive, and drops block data in + // mapBlockIndex based on lack of available witness data. uiInterface.InitMessage(_("Rewinding blocks...")); if (!RewindBlockIndex(chainparams)) { strLoadError = _("Unable to rewind the database to a pre-fork state. You will need to redownload the blockchain"); @@ -1424,28 +1501,30 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) } } - uiInterface.InitMessage(_("Verifying blocks...")); - if (fHavePruned && GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { - LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks", - MIN_BLOCKS_TO_KEEP); - } + if (!is_coinsview_empty) { + uiInterface.InitMessage(_("Verifying blocks...")); + if (fHavePruned && gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS) > MIN_BLOCKS_TO_KEEP) { + LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks", + MIN_BLOCKS_TO_KEEP); + } - { - LOCK(cs_main); - CBlockIndex* tip = chainActive.Tip(); - RPCNotifyBlockChange(true, tip); - if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { - strLoadError = _("The block database contains a block which appears to be from the future. " - "This may be due to your computer's date and time being set incorrectly. " - "Only rebuild the block database if you are sure that your computer's date and time are correct"); - break; + { + LOCK(cs_main); + CBlockIndex* tip = chainActive.Tip(); + RPCNotifyBlockChange(true, tip); + if (tip && tip->nTime > GetAdjustedTime() + 2 * 60 * 60) { + strLoadError = _("The block database contains a block which appears to be from the future. " + "This may be due to your computer's date and time being set incorrectly. " + "Only rebuild the block database if you are sure that your computer's date and time are correct"); + break; + } } - } - if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, GetArg("-checklevel", DEFAULT_CHECKLEVEL), - GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { - strLoadError = _("Corrupted block database detected"); - break; + if (!CVerifyDB().VerifyDB(chainparams, pcoinsdbview, gArgs.GetArg("-checklevel", DEFAULT_CHECKLEVEL), + gArgs.GetArg("-checkblocks", DEFAULT_CHECKBLOCKS))) { + strLoadError = _("Corrupted block database detected"); + break; + } } } catch (const std::exception& e) { LogPrintf("%s\n", e.what()); @@ -1456,7 +1535,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) fLoaded = true; } while(false); - if (!fLoaded) { + if (!fLoaded && !fRequestShutdown) { // first suggest a reindex if (!fReset) { bool fRet = uiInterface.ThreadSafeQuestion( @@ -1484,7 +1563,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) LogPrintf("Shutdown requested. Exiting.\n"); return false; } - LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); + if (fLoaded) { + LogPrintf(" block index %15dms\n", GetTimeMillis() - nStart); + } fs::path est_path = GetDataDir() / FEE_ESTIMATES_FILENAME; CAutoFile est_filein(fsbridge::fopen(est_path, "rb"), SER_DISK, CLIENT_VERSION); @@ -1495,7 +1576,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // ********************************************************* Step 8: load wallet #ifdef ENABLE_WALLET - if (!CWallet::InitLoadWallet()) + if (!OpenWallets()) return false; #else LogPrintf("No wallet support compiled in!\n"); @@ -1533,13 +1614,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) // Either install a handler to notify us when genesis activates, or set fHaveGenesis directly. // No locking, as this happens before any background thread is started. - if (chainActive.Tip() == NULL) { + if (chainActive.Tip() == nullptr) { uiInterface.NotifyBlockTip.connect(BlockNotifyGenesisWait); } else { fHaveGenesis = true; } - if (IsArgSet("-blocknotify")) + if (gArgs.IsArgSet("-blocknotify")) uiInterface.NotifyBlockTip.connect(BlockNotifyCallback); std::vector<fs::path> vImportFiles; @@ -1563,13 +1644,13 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) //// debug print LogPrintf("mapBlockIndex.size() = %u\n", mapBlockIndex.size()); LogPrintf("nBestHeight = %d\n", chainActive.Height()); - if (GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) + if (gArgs.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)) StartTorControl(threadGroup, scheduler); Discover(threadGroup); // Map ports with UPnP - MapPort(GetBoolArg("-upnp", DEFAULT_UPNP)); + MapPort(gArgs.GetBoolArg("-upnp", DEFAULT_UPNP)); CConnman::Options connOptions; connOptions.nLocalServices = nLocalServices; @@ -1580,8 +1661,9 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) connOptions.nMaxFeeler = 1; connOptions.nBestHeight = chainActive.Height(); connOptions.uiInterface = &uiInterface; - connOptions.nSendBufferMaxSize = 1000*GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); - connOptions.nReceiveFloodSize = 1000*GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); + connOptions.m_msgproc = peerLogic.get(); + connOptions.nSendBufferMaxSize = 1000*gArgs.GetArg("-maxsendbuffer", DEFAULT_MAXSENDBUFFER); + connOptions.nReceiveFloodSize = 1000*gArgs.GetArg("-maxreceivebuffer", DEFAULT_MAXRECEIVEBUFFER); connOptions.nMaxOutboundTimeframe = nMaxOutboundTimeframe; connOptions.nMaxOutboundLimit = nMaxOutboundLimit; @@ -1615,7 +1697,14 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) if (gArgs.IsArgSet("-seednode")) { connOptions.vSeedNodes = gArgs.GetArgs("-seednode"); } - + // Initiate outbound connections unless connect=0 + connOptions.m_use_addrman_outgoing = !gArgs.IsArgSet("-connect"); + if (!connOptions.m_use_addrman_outgoing) { + const auto connect = gArgs.GetArgs("-connect"); + if (connect.size() != 1 || connect[0] != "0") { + connOptions.m_specified_outgoing = connect; + } + } if (!connman.Start(scheduler, connOptions)) { return false; } @@ -1626,9 +1715,7 @@ bool AppInitMain(boost::thread_group& threadGroup, CScheduler& scheduler) uiInterface.InitMessage(_("Done loading")); #ifdef ENABLE_WALLET - for (CWalletRef pwallet : vpwallets) { - pwallet->postInitProcess(scheduler); - } + StartWallets(scheduler); #endif return !fRequestShutdown; |