diff options
Diffstat (limited to 'src/init.cpp')
-rw-r--r-- | src/init.cpp | 240 |
1 files changed, 142 insertions, 98 deletions
diff --git a/src/init.cpp b/src/init.cpp index a94bbe6460..24659de3df 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -11,6 +11,7 @@ #include <kernel/checks.h> #include <kernel/mempool_persist.h> +#include <kernel/validation_cache_sizes.h> #include <addrman.h> #include <banman.h> @@ -31,7 +32,6 @@ #include <interfaces/init.h> #include <interfaces/node.h> #include <mapport.h> -#include <mempool_args.h> #include <net.h> #include <net_permissions.h> #include <net_processing.h> @@ -40,10 +40,14 @@ #include <node/blockstorage.h> #include <node/caches.h> #include <node/chainstate.h> +#include <node/chainstatemanager_args.h> #include <node/context.h> #include <node/interface_ui.h> +#include <node/mempool_args.h> #include <node/mempool_persist_args.h> #include <node/miner.h> +#include <node/txreconciliation.h> +#include <node/validation_cache_args.h> #include <policy/feerate.h> #include <policy/fees.h> #include <policy/fees_args.h> @@ -105,7 +109,9 @@ #endif using kernel::DumpMempool; +using kernel::ValidationCacheSizes; +using node::ApplyArgsManOptions; using node::CacheSizes; using node::CalculateCacheSizes; using node::DEFAULT_PERSIST_MEMPOOL; @@ -259,7 +265,7 @@ void Shutdown(NodeContext& node) // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing if (node.chainman) { LOCK(cs_main); - for (CChainState* chainstate : node.chainman->GetAll()) { + for (Chainstate* chainstate : node.chainman->GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); } @@ -290,7 +296,7 @@ void Shutdown(NodeContext& node) if (node.chainman) { LOCK(cs_main); - for (CChainState* chainstate : node.chainman->GetAll()) { + for (Chainstate* chainstate : node.chainman->GetAll()) { if (chainstate->CanFlushToDisk()) { chainstate->ForceFlushStateToDisk(); chainstate->ResetCoinsViews(); @@ -472,7 +478,6 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-onlynet=<net>", "Make automatic outbound connections only to network <net> (" + Join(GetNetworkNames(), ", ") + "). Inbound and manual connections are not affected by this option. It can be specified multiple times to allow multiple networks.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerbloomfilters", strprintf("Support filtering of blocks and transaction with bloom filters (default: %u)", DEFAULT_PEERBLOOMFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-peerblockfilters", strprintf("Serve compact block filters to peers per BIP 157 (default: %u)", DEFAULT_PEERBLOCKFILTERS), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); - argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); // TODO: remove the sentence "Nodes not using ... incoming connections." once the changes from // https://github.com/bitcoin/bitcoin/pull/23542 have become widespread. argsman.AddArg("-port=<port>", strprintf("Listen for connections on <port>. Nodes not using the default ports (default: %u, testnet: %u, signet: %u, regtest: %u) are unlikely to get incoming connections. Not relevant for I2P (see doc/i2p.md).", defaultChainParams->GetDefaultPort(), testnetChainParams->GetDefaultPort(), signetChainParams->GetDefaultPort(), regtestChainParams->GetDefaultPort()), ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::CONNECTION); @@ -481,6 +486,7 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-seednode=<ip>", "Connect to a node to retrieve peer addresses, and disconnect. This option can be specified multiple times to connect to multiple nodes.", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-networkactive", "Enable all P2P network activity (default: 1). Can be changed by the setnetworkactive RPC command", ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-timeout=<n>", strprintf("Specify socket connection timeout in milliseconds. If an initial attempt to connect is unsuccessful after this amount of time, drop it (minimum: 1, default: %d)", DEFAULT_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); + argsman.AddArg("-txreconciliation", strprintf("Enable transaction reconciliations per BIP 330 (default: %d)", DEFAULT_TXRECONCILIATION_ENABLE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-peertimeout=<n>", strprintf("Specify a p2p connection timeout delay in seconds. After connecting to a peer, wait this amount of time before considering disconnection based on inactivity (minimum: 1, default: %d)", DEFAULT_PEER_CONNECT_TIMEOUT), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::CONNECTION); argsman.AddArg("-torcontrol=<ip>:<port>", strprintf("Tor control port to use if onion listening enabled (default: %s)", DEFAULT_TOR_CONTROL), ArgsManager::ALLOW_ANY, OptionsCategory::CONNECTION); argsman.AddArg("-torpassword=<pass>", "Tor control port password (default: empty)", ArgsManager::ALLOW_ANY | ArgsManager::SENSITIVE, OptionsCategory::CONNECTION); @@ -548,20 +554,25 @@ void SetupServerArgs(ArgsManager& argsman) argsman.AddArg("-addrmantest", "Allows to test address relay on localhost", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-capturemessages", "Capture all P2P messages to disk", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-mocktime=<n>", "Replace actual time with " + UNIX_EPOCH_TIME + " (default: 0)", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_SIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); - argsman.AddArg("-maxtipage=<n>", strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", DEFAULT_MAX_TIP_AGE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-maxsigcachesize=<n>", strprintf("Limit sum of signature cache and script execution cache sizes to <n> MiB (default: %u)", DEFAULT_MAX_SIG_CACHE_BYTES >> 20), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); + argsman.AddArg("-maxtipage=<n>", + strprintf("Maximum tip age in seconds to consider node in initial block download (default: %u)", + Ticks<std::chrono::seconds>(DEFAULT_MAX_TIP_AGE)), + ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-printpriority", strprintf("Log transaction fee rate in " + CURRENCY_UNIT + "/kvB when mining blocks (default: %u)", DEFAULT_PRINTPRIORITY), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::DEBUG_TEST); argsman.AddArg("-uacomment=<cmt>", "Append comment to the user agent string", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST); SetupChainParamsBaseOptions(argsman); argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); - argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and replacement policy. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define 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)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY); argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-mempoolfullrbf", strprintf("Accept transaction replace-by-fee without requiring replaceability signaling (default: %u)", DEFAULT_MEMPOOL_FULL_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); + argsman.AddArg("-permitbaremultisig", strprintf("Relay non-P2SH multisig (default: %u)", DEFAULT_PERMIT_BAREMULTISIG), ArgsManager::ALLOW_ANY, + OptionsCategory::NODE_RELAY); argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY); @@ -719,6 +730,16 @@ void InitParameterInteraction(ArgsManager& args) if (args.SoftSetBoolArg("-whitelistrelay", true)) LogPrintf("%s: parameter interaction: -whitelistforcerelay=1 -> setting -whitelistrelay=1\n", __func__); } + if (args.IsArgSet("-onlynet")) { + const auto onlynets = args.GetArgs("-onlynet"); + bool clearnet_reachable = std::any_of(onlynets.begin(), onlynets.end(), [](const auto& net) { + const auto n = ParseNetwork(net); + return n == NET_IPV4 || n == NET_IPV6; + }); + if (!clearnet_reachable && args.SoftSetBoolArg("-dnsseed", false)) { + LogPrintf("%s: parameter interaction: -onlynet excludes IPv4 and IPv6 -> setting -dnsseed=0\n", __func__); + } + } } /** @@ -738,7 +759,7 @@ namespace { // Variables internal to initialization process only int nMaxConnections; int nUserMaxConnections; int nFD; -ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK | NODE_NETWORK_LIMITED | NODE_WITNESS); +ServiceFlags nLocalServices = ServiceFlags(NODE_NETWORK_LIMITED | NODE_WITNESS); int64_t peer_connect_timeout; std::set<BlockFilterType> g_enabled_filter_types; @@ -911,39 +932,7 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb // ********************************************************* Step 3: parameter-to-internal-flags init::SetLoggingCategories(args); - - fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); - fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); - - 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 (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)); - } - 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()); - } - - // 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 (args.IsArgSet("-incrementalrelayfee")) { - if (std::optional<CAmount> inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) { - ::incrementalRelayFee = CFeeRate{inc_relay_fee.value()}; - } else { - return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", ""))); - } - } + init::SetLoggingLevel(args); // block pruning; get the amount of disk space (in MiB) to allot for block & undo files int64_t nPruneArg = args.GetIntArg("-prune", 0); @@ -952,14 +941,12 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb } nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024; if (nPruneArg == 1) { // manual pruning: -prune=1 - LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n"); nPruneTarget = std::numeric_limits<uint64_t>::max(); fPruneMode = true; } else if (nPruneTarget) { if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) { return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024)); } - LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024); fPruneMode = true; } @@ -973,19 +960,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb return InitError(Untranslated("peertimeout must be a positive integer.")); } - if (args.IsArgSet("-minrelaytxfee")) { - if (std::optional<CAmount> min_relay_fee = ParseMoney(args.GetArg("-minrelaytxfee", ""))) { - // High fee check is done afterward in CWallet::Create() - ::minRelayTxFee = CFeeRate{min_relay_fee.value()}; - } else { - return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", ""))); - } - } else if (incrementalRelayFee > ::minRelayTxFee) { - // Allow only setting incrementalRelayFee to control both - ::minRelayTxFee = incrementalRelayFee; - LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString()); - } - // Sanity check argument for min fee for including tx in block // TODO: Harmonize which arguments need sanity checking and where that happens if (args.IsArgSet("-blockmintxfee")) { @@ -994,28 +968,10 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb } } - // Feerate used to define dust. Shouldn't be changed lightly as old - // implementations may inadvertently create non-standard transactions - if (args.IsArgSet("-dustrelayfee")) { - if (std::optional<CAmount> parsed = ParseMoney(args.GetArg("-dustrelayfee", ""))) { - dustRelayFee = CFeeRate{parsed.value()}; - } else { - return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", ""))); - } - } - - 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 = args.GetIntArg("-bytespersigop", nBytesPerSigOp); if (!g_wallet_init_interface.ParameterInteraction()) return false; - fIsBareMultisigStd = args.GetBoolArg("-permitbaremultisig", DEFAULT_PERMIT_BAREMULTISIG); - fAcceptDatacarrier = args.GetBoolArg("-datacarrier", DEFAULT_ACCEPT_DATACARRIER); - nMaxDatacarrierBytes = args.GetIntArg("-datacarriersize", nMaxDatacarrierBytes); - // Option to startup with mocktime set (used for regression testing): SetMockTime(args.GetIntArg("-mocktime", 0)); // SetMockTime(0) is a no-op @@ -1028,8 +984,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb if (args.GetIntArg("-rpcserialversion", DEFAULT_RPC_SERIALIZE_VERSION) > 1) return InitError(Untranslated("Unknown rpcserialversion requested.")); - nMaxTipAge = args.GetIntArg("-maxtipage", DEFAULT_MAX_TIP_AGE); - if (args.GetBoolArg("-reindex-chainstate", false)) { // indexes that must be deactivated to prevent index corruption, see #24630 if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX)) { @@ -1077,13 +1031,23 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb } #endif // USE_SYSCALL_SANDBOX + // Also report errors from parsing before daemonization + { + ChainstateManager::Options chainman_opts_dummy{ + .chainparams = chainparams, + }; + if (const auto error{ApplyArgsManOptions(args, chainman_opts_dummy)}) { + return InitError(*error); + } + } + return true; } static bool LockDataDirectory(bool probeOnly) { // Make sure only a single Bitcoin process is using the data directory. - fs::path datadir = gArgs.GetDataDirNet(); + const fs::path& datadir = gArgs.GetDataDirNet(); if (!DirIsWritable(datadir)) { return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir))); } @@ -1156,8 +1120,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) args.GetArg("-datadir", ""), fs::PathToString(fs::current_path())); } - InitSignatureCache(); - InitScriptExecutionCache(); + ValidationCacheSizes validation_cache_sizes{}; + ApplyArgsManOptions(args, validation_cache_sizes); + if (!InitSignatureCache(validation_cache_sizes.signature_cache_bytes) + || !InitScriptExecutionCache(validation_cache_sizes.script_execution_cache_bytes)) + { + return InitError(strprintf(_("Unable to allocate memory for -maxsigcachesize: '%s' MiB"), args.GetIntArg("-maxsigcachesize", DEFAULT_MAX_SIG_CACHE_BYTES >> 20))); + } int script_threads = args.GetIntArg("-par", DEFAULT_SCRIPTCHECK_THREADS); if (script_threads <= 0) { @@ -1174,7 +1143,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) LogPrintf("Script verification uses %d additional threads\n", script_threads); if (script_threads >= 1) { - g_parallel_script_checks = true; StartScriptCheckWorkerThreads(script_threads); } @@ -1285,6 +1253,51 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // as they would never get updated. if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>(FeeestPath(args)); + // Check port numbers + for (const std::string port_option : { + "-port", + "-rpcport", + }) { + if (args.IsArgSet(port_option)) { + const std::string port = args.GetArg(port_option, ""); + uint16_t n; + if (!ParseUInt16(port, &n) || n == 0) { + return InitError(InvalidPortErrMsg(port_option, port)); + } + } + } + + for (const std::string port_option : { + "-i2psam", + "-onion", + "-proxy", + "-rpcbind", + "-torcontrol", + "-whitebind", + "-zmqpubhashblock", + "-zmqpubhashtx", + "-zmqpubrawblock", + "-zmqpubrawtx", + "-zmqpubsequence", + }) { + for (const std::string& socket_addr : args.GetArgs(port_option)) { + std::string host_out; + uint16_t port_out{0}; + if (!SplitHostPort(socket_addr, port_out, host_out)) { + return InitError(InvalidPortErrMsg(port_option, socket_addr)); + } + } + } + + for (const std::string& socket_addr : args.GetArgs("-bind")) { + std::string host_out; + uint16_t port_out{0}; + std::string bind_socket_addr = socket_addr.substr(0, socket_addr.rfind('=')); + if (!SplitHostPort(bind_socket_addr, port_out, host_out)) { + return InitError(InvalidPortErrMsg("-bind", socket_addr)); + } + } + // sanitize comments per BIP-0014, format user agent and check total size std::vector<std::string> uacomments; for (const std::string& cmt : args.GetArgs("-uacomment")) { @@ -1315,6 +1328,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } if (!args.IsArgSet("-cjdnsreachable")) { + if (args.IsArgSet("-onlynet") && IsReachable(NET_CJDNS)) { + return InitError( + _("Outbound connections restricted to CJDNS (-onlynet=cjdns) but " + "-cjdnsreachable is not provided")); + } SetReachable(NET_CJDNS, false); } // Now IsReachable(NET_CJDNS) is true if: @@ -1322,6 +1340,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // 2.1. -onlynet is not given or // 2.2. -onlynet=cjdns is given + // Requesting DNS seeds entails connecting to IPv4/IPv6, which -onlynet options may prohibit: + // If -dnsseed=1 is explicitly specified, abort. If it's left unspecified by the user, we skip + // the DNS seeds by adjusting -dnsseed in InitParameterInteraction. + if (args.GetBoolArg("-dnsseed") == true && !IsReachable(NET_IPV4) && !IsReachable(NET_IPV6)) { + return InitError(strprintf(_("Incompatible options: -dnsseed=1 was explicitly specified, but -onlynet forbids connections to IPv4/IPv6"))); + }; + // Check for host lookup allowed before parsing any network related parameters fNameLookup = args.GetBoolArg("-dns", DEFAULT_NAME_LOOKUP); @@ -1348,6 +1373,8 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) onion_proxy = addrProxy; } + const bool onlynet_used_with_onion{args.IsArgSet("-onlynet") && IsReachable(NET_ONION)}; + // -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) @@ -1355,6 +1382,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) if (onionArg != "") { if (onionArg == "0") { // Handle -noonion/-onion=0 onion_proxy = Proxy{}; + if (onlynet_used_with_onion) { + return InitError( + _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " + "reaching the Tor network is explicitly forbidden: -onion=0")); + } } else { CService addr; if (!Lookup(onionArg, addr, 9050, fNameLookup) || !addr.IsValid()) { @@ -1367,11 +1399,14 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) if (onion_proxy.IsValid()) { SetProxy(NET_ONION, onion_proxy); } else { - if (args.IsArgSet("-onlynet") && IsReachable(NET_ONION)) { + // If -listenonion is set, then we will (try to) connect to the Tor control port + // later from the torcontrol thread and may retrieve the onion proxy from there. + const bool listenonion_disabled{!args.GetBoolArg("-listenonion", DEFAULT_LISTEN_ONION)}; + if (onlynet_used_with_onion && listenonion_disabled) { return InitError( _("Outbound connections restricted to Tor (-onlynet=onion) but the proxy for " - "reaching the Tor network is not provided (no -proxy= and no -onion= given) or " - "it is explicitly forbidden (-onion=0)")); + "reaching the Tor network is not provided: none of -proxy, -onion or " + "-listenonion is given")); } SetReachable(NET_ONION, false); } @@ -1396,6 +1431,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) fReindex = args.GetBoolArg("-reindex", false); bool fReindexChainState = args.GetBoolArg("-reindex-chainstate", false); + ChainstateManager::Options chainman_opts{ + .chainparams = chainparams, + .adjusted_time_callback = GetAdjustedTime, + }; + Assert(!ApplyArgsManOptions(args, chainman_opts)); // no error can happen, already checked in AppInitParameterInteraction // cache size calculations CacheSizes cache_sizes = CalculateCacheSizes(args, g_enabled_filter_types.size()); @@ -1418,7 +1458,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) .estimator = node.fee_estimator.get(), .check_ratio = chainparams.DefaultConsistencyChecks() ? 1 : 0, }; - ApplyArgsManOptions(args, mempool_opts); + if (const auto err{ApplyArgsManOptions(args, chainparams, mempool_opts)}) { + return InitError(*err); + } mempool_opts.check_ratio = std::clamp<int>(mempool_opts.check_ratio, 0, 1'000'000); int64_t descendant_limit_bytes = mempool_opts.limits.descendant_size_vbytes * 40; @@ -1430,10 +1472,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) for (bool fLoaded = false; !fLoaded && !ShutdownRequested();) { node.mempool = std::make_unique<CTxMemPool>(mempool_opts); - const ChainstateManager::Options chainman_opts{ - .chainparams = chainparams, - .adjusted_time_callback = GetAdjustedTime, - }; node.chainman = std::make_unique<ChainstateManager>(chainman_opts); ChainstateManager& chainman = *node.chainman; @@ -1452,7 +1490,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) }; uiInterface.InitMessage(_("Loading block index…").translated); - const int64_t load_block_index_start_time = GetTimeMillis(); + const auto load_block_index_start_time{SteadyClock::now()}; auto catch_exceptions = [](auto&& f) { try { return f(); @@ -1471,7 +1509,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) std::tie(status, error) = catch_exceptions([&]{ return VerifyLoadedChainstate(chainman, options);}); if (status == node::ChainstateLoadStatus::SUCCESS) { fLoaded = true; - LogPrintf(" block index %15dms\n", GetTimeMillis() - load_block_index_start_time); + LogPrintf(" block index %15dms\n", Ticks<std::chrono::milliseconds>(SteadyClock::now() - load_block_index_start_time)); } } @@ -1549,18 +1587,19 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // ********************************************************* Step 10: data directory maintenance - // if pruning, unset the service bit and perform the initial blockstore prune + // if pruning, perform the initial blockstore prune // after any wallet rescanning has taken place. if (fPruneMode) { - LogPrintf("Unsetting NODE_NETWORK on prune mode\n"); - nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK); if (!fReindex) { LOCK(cs_main); - for (CChainState* chainstate : chainman.GetAll()) { + for (Chainstate* chainstate : chainman.GetAll()) { uiInterface.InitMessage(_("Pruning blockstore…").translated); chainstate->PruneAndFlush(); } } + } else { + LogPrintf("Setting NODE_NETWORK on non-prune mode\n"); + nLocalServices = ServiceFlags(nLocalServices | NODE_NETWORK); } // ********************************************************* Step 11: import blocks @@ -1577,7 +1616,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // 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. boost::signals2::connection block_notify_genesis_wait_connection; - if (chainman.ActiveChain().Tip() == nullptr) { + if (WITH_LOCK(chainman.GetMutex(), return chainman.ActiveChain().Tip() == nullptr)) { block_notify_genesis_wait_connection = uiInterface.NotifyBlockTip_connect(std::bind(BlockNotifyGenesisWait, std::placeholders::_2)); } else { fHaveGenesis = true; @@ -1668,7 +1707,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) const auto BadPortWarning = [](const char* prefix, uint16_t port) { return strprintf(_("%s request to listen on port %u. This port is considered \"bad\" and " - "thus it is unlikely that any Bitcoin Core peers connect to it. See " + "thus it is unlikely that any peer will connect to it. See " "doc/p2p-bad-ports.md for details and a full list."), prefix, port); @@ -1767,6 +1806,11 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) } SetProxy(NET_I2P, Proxy{addr}); } else { + if (args.IsArgSet("-onlynet") && IsReachable(NET_I2P)) { + return InitError( + _("Outbound connections restricted to i2p (-onlynet=i2p) but " + "-i2psam is not provided")); + } SetReachable(NET_I2P, false); } @@ -1781,12 +1825,12 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) // At this point, the RPC is "started", but still in warmup, which means it // cannot yet be called. Before we make it callable, we need to make sure // that the RPC's view of the best block is valid and consistent with - // ChainstateManager's ActiveTip. + // ChainstateManager's active tip. // // If we do not do this, RPC's view of the best block will be height=0 and // hash=0x0. This will lead to erroroneous responses for things like // waitforblockheight. - RPCNotifyBlockChange(chainman.ActiveTip()); + RPCNotifyBlockChange(WITH_LOCK(chainman.GetMutex(), return chainman.ActiveTip())); SetRPCWarmupFinished(); uiInterface.InitMessage(_("Done loading").translated); |