diff options
-rw-r--r-- | src/init.cpp | 22 | ||||
-rw-r--r-- | src/kernel/chainstatemanager_opts.h | 3 | ||||
-rw-r--r-- | src/net_processing.cpp | 18 | ||||
-rw-r--r-- | src/node/chainstate.cpp | 4 | ||||
-rw-r--r-- | src/node/chainstatemanager_args.cpp | 18 | ||||
-rw-r--r-- | src/node/chainstatemanager_args.h | 5 | ||||
-rw-r--r-- | src/validation.cpp | 12 | ||||
-rw-r--r-- | src/validation.h | 4 |
8 files changed, 53 insertions, 33 deletions
diff --git a/src/init.cpp b/src/init.cpp index b99f16d85e..0c368d8bac 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -937,16 +937,6 @@ bool AppInitParameterInteraction(const ArgsManager& args, bool use_syscall_sandb fCheckBlockIndex = args.GetBoolArg("-checkblockindex", chainparams.DefaultConsistencyChecks()); fCheckpointsEnabled = args.GetBoolArg("-checkpoints", DEFAULT_CHECKPOINTS_ENABLED); - 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); - } - // block pruning; get the amount of disk space (in MiB) to allot for block & undo files int64_t nPruneArg = args.GetIntArg("-prune", 0); if (nPruneArg < 0) { @@ -1044,6 +1034,16 @@ 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; } @@ -1439,7 +1439,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info) .chainparams = chainparams, .adjusted_time_callback = GetAdjustedTime, }; - ApplyArgsManOptions(args, chainman_opts); + 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()); diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h index f698372d05..90acfab63a 100644 --- a/src/kernel/chainstatemanager_opts.h +++ b/src/kernel/chainstatemanager_opts.h @@ -5,6 +5,7 @@ #ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H #define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H +#include <arith_uint256.h> #include <uint256.h> #include <util/time.h> @@ -26,6 +27,8 @@ namespace kernel { struct ChainstateManagerOpts { const CChainParams& chainparams; const std::function<NodeClock::time_point()> adjusted_time_callback{nullptr}; + //! If set, it will override the minimum work we will assume exists on some valid chain. + std::optional<arith_uint256> minimum_chain_work; //! If set, it will override the block hash whose ancestors we will assume to have valid scripts without checking them. std::optional<uint256> assumed_valid_block; //! If the tip is older than this, the node is considered to be in initial block download. diff --git a/src/net_processing.cpp b/src/net_processing.cpp index c87b0e7cd2..19438149e6 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -1291,7 +1291,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(const Peer& peer, unsigned int co // Make sure pindexBestKnownBlock is up to date, we'll need it. ProcessBlockAvailability(peer.m_id); - if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { + if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < m_chainman.MinimumChainWork()) { // This peer has nothing interesting. return; } @@ -2392,7 +2392,7 @@ arith_uint256 PeerManagerImpl::GetAntiDoSWorkThreshold() // near our tip. near_chaintip_work = tip->nChainWork - std::min<arith_uint256>(144*GetBlockProof(*tip), tip->nChainWork); } - return std::max(near_chaintip_work, arith_uint256(nMinimumChainWork)); + return std::max(near_chaintip_work, m_chainman.MinimumChainWork()); } /** @@ -2702,14 +2702,14 @@ void PeerManagerImpl::UpdatePeerStateForReceivedHeaders(CNode& pfrom, if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && !may_have_more_headers) { // If the peer has no more headers to give us, then we know we have // their tip. - if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) { + if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < m_chainman.MinimumChainWork()) { // This peer has too little work on their headers chain to help // us sync -- disconnect if it is an outbound disconnection // candidate. - // Note: We compare their tip to nMinimumChainWork (rather than + // Note: We compare their tip to the minumum chain work (rather than // m_chainman.ActiveChain().Tip()) because we won't start block download // until we have a headers chain that has at least - // nMinimumChainWork, even if a peer has a chain past our tip, + // the minimum chain work, even if a peer has a chain past our tip, // as an anti-DoS measure. if (pfrom.IsOutboundOrBlockRelayConn()) { LogPrintf("Disconnecting outbound peer %d -- headers chain has insufficient work\n", pfrom.GetId()); @@ -3893,12 +3893,12 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // Note that if we were to be on a chain that forks from the checkpointed // chain, then serving those headers to a peer that has seen the // checkpointed chain would cause that peer to disconnect us. Requiring - // that our chainwork exceed nMinimumChainWork is a protection against + // that our chainwork exceed the mimimum chain work is a protection against // being fed a bogus chain when we started up for the first time and // getting partitioned off the honest network for serving that chain to // others. if (m_chainman.ActiveTip() == nullptr || - (m_chainman.ActiveTip()->nChainWork < nMinimumChainWork && !pfrom.HasPermission(NetPermissionFlags::Download))) { + (m_chainman.ActiveTip()->nChainWork < m_chainman.MinimumChainWork() && !pfrom.HasPermission(NetPermissionFlags::Download))) { LogPrint(BCLog::NET, "Ignoring getheaders from peer=%d because active chain has too little work; sending empty response\n", pfrom.GetId()); // Just respond with an empty headers message, to tell the peer to // go away but not treat us as unresponsive. @@ -4362,7 +4362,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type, // (eg disk space). Because we only try to reconstruct blocks when // we're close to caught up (via the CanDirectFetch() requirement // above, combined with the behavior of not requesting blocks until - // we have a chain with at least nMinimumChainWork), and we ignore + // we have a chain with at least the minimum chain work), and we ignore // compact blocks with less work than our tip, it is safe to treat // reconstructed compact blocks as having been requested. ProcessBlock(pfrom, pblock, /*force_processing=*/true, /*min_pow_checked=*/true); @@ -5228,7 +5228,7 @@ void PeerManagerImpl::MaybeSendSendHeaders(CNode& node, Peer& peer) LOCK(cs_main); CNodeState &state = *State(node.GetId()); if (state.pindexBestKnownBlock != nullptr && - state.pindexBestKnownBlock->nChainWork > nMinimumChainWork) { + state.pindexBestKnownBlock->nChainWork > m_chainman.MinimumChainWork()) { // Tell our peer we prefer to receive headers rather than inv's // We send this to non-NODE NETWORK peers as well, because even // non-NODE NETWORK peers can announce blocks (such as pruning diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp index d9df4b48b5..57d0083d89 100644 --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -37,8 +37,8 @@ ChainstateLoadResult LoadChainstate(ChainstateManager& chainman, const CacheSize } else { LogPrintf("Validating signatures for all blocks.\n"); } - LogPrintf("Setting nMinimumChainWork=%s\n", nMinimumChainWork.GetHex()); - if (nMinimumChainWork < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) { + LogPrintf("Setting nMinimumChainWork=%s\n", chainman.MinimumChainWork().GetHex()); + if (chainman.MinimumChainWork() < UintToArith256(chainman.GetConsensus().nMinimumChainWork)) { LogPrintf("Warning: nMinimumChainWork set below default value of %s\n", chainman.GetConsensus().nMinimumChainWork.GetHex()); } if (nPruneTarget == std::numeric_limits<uint64_t>::max()) { diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp index 811d812e9f..4716be46b5 100644 --- a/src/node/chainstatemanager_args.cpp +++ b/src/node/chainstatemanager_args.cpp @@ -4,16 +4,32 @@ #include <node/chainstatemanager_args.h> +#include <arith_uint256.h> +#include <tinyformat.h> +#include <uint256.h> +#include <util/strencodings.h> #include <util/system.h> +#include <util/translation.h> +#include <validation.h> #include <chrono> #include <optional> +#include <string> namespace node { -void ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts) +std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts) { + if (auto value{args.GetArg("-minimumchainwork")}) { + if (!IsHexNumber(*value)) { + return strprintf(Untranslated("Invalid non-hex (%s) minimum chain work value specified"), *value); + } + opts.minimum_chain_work = UintToArith256(uint256S(*value)); + } + if (auto value{args.GetArg("-assumevalid")}) opts.assumed_valid_block = uint256S(*value); if (auto value{args.GetIntArg("-maxtipage")}) opts.max_tip_age = std::chrono::seconds{*value}; + + return std::nullopt; } } // namespace node diff --git a/src/node/chainstatemanager_args.h b/src/node/chainstatemanager_args.h index 847ddefb8c..6c46b998f2 100644 --- a/src/node/chainstatemanager_args.h +++ b/src/node/chainstatemanager_args.h @@ -7,10 +7,13 @@ #include <validation.h> +#include <optional> + class ArgsManager; +struct bilingual_str; namespace node { -void ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts); +std::optional<bilingual_str> ApplyArgsManOptions(const ArgsManager& args, ChainstateManager::Options& opts); } // namespace node #endif // BITCOIN_NODE_CHAINSTATEMANAGER_ARGS_H diff --git a/src/validation.cpp b/src/validation.cpp index a6f71aba9f..3df4bfb0d0 100644 --- a/src/validation.cpp +++ b/src/validation.cpp @@ -124,8 +124,6 @@ bool g_parallel_script_checks{false}; bool fCheckBlockIndex = false; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; -arith_uint256 nMinimumChainWork; - const CBlockIndex* Chainstate::FindForkInGlobalIndex(const CBlockLocator& locator) const { AssertLockHeld(cs_main); @@ -1544,8 +1542,9 @@ bool Chainstate::IsInitialBlockDownload() const return true; if (m_chain.Tip() == nullptr) return true; - if (m_chain.Tip()->nChainWork < nMinimumChainWork) + if (m_chain.Tip()->nChainWork < m_chainman.MinimumChainWork()) { return true; + } if (m_chain.Tip()->Time() < NodeClock::now() - m_chainman.m_options.max_tip_age) { return true; } @@ -2045,7 +2044,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, if (it != m_blockman.m_block_index.end()) { if (it->second.GetAncestor(pindex->nHeight) == pindex && m_chainman.m_best_header->GetAncestor(pindex->nHeight) == pindex && - m_chainman.m_best_header->nChainWork >= nMinimumChainWork) { + m_chainman.m_best_header->nChainWork >= m_chainman.MinimumChainWork()) { // This block is a member of the assumed verified chain and an ancestor of the best header. // Script verification is skipped when connecting blocks under the // assumevalid block. Assuming the assumevalid block is valid this @@ -2058,7 +2057,7 @@ bool Chainstate::ConnectBlock(const CBlock& block, BlockValidationState& state, // it hard to hide the implication of the demand. This also avoids having release candidates // that are hardly doing any signature verification at all in testing without having to // artificially set the default assumed verified block further back. - // The test against nMinimumChainWork prevents the skipping when denied access to any chain at + // The test against the minimum chain work prevents the skipping when denied access to any chain at // least as good as the expected chain. fScriptChecks = (GetBlockProofEquivalentTime(*m_chainman.m_best_header, *pindex, *m_chainman.m_best_header, m_params.GetConsensus()) <= 60 * 60 * 24 * 7 * 2); } @@ -3843,7 +3842,7 @@ bool Chainstate::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockV // If our tip is behind, a peer could try to send us // low-work blocks on a fake chain that we would never // request; don't process these. - if (pindex->nChainWork < nMinimumChainWork) return true; + if (pindex->nChainWork < m_chainman.MinimumChainWork()) return true; } if (!CheckBlock(block, state, m_params.GetConsensus()) || @@ -5250,6 +5249,7 @@ void ChainstateManager::ResetChainstates() */ static ChainstateManager::Options&& Flatten(ChainstateManager::Options&& opts) { + if (!opts.minimum_chain_work.has_value()) opts.minimum_chain_work = UintToArith256(opts.chainparams.GetConsensus().nMinimumChainWork); if (!opts.assumed_valid_block.has_value()) opts.assumed_valid_block = opts.chainparams.GetConsensus().defaultAssumeValid; Assert(opts.adjusted_time_callback); return std::move(opts); diff --git a/src/validation.h b/src/validation.h index 0483edaff3..495618549a 100644 --- a/src/validation.h +++ b/src/validation.h @@ -99,9 +99,6 @@ extern bool g_parallel_script_checks; extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; -/** Minimum work we will assume exists on some valid chain. */ -extern arith_uint256 nMinimumChainWork; - /** Documentation for argument 'checklevel'. */ extern const std::vector<std::string> CHECKLEVEL_DOC; @@ -865,6 +862,7 @@ public: const CChainParams& GetParams() const { return m_options.chainparams; } const Consensus::Params& GetConsensus() const { return m_options.chainparams.GetConsensus(); } + const arith_uint256& MinimumChainWork() const { return *Assert(m_options.minimum_chain_work); } const uint256& AssumedValidBlock() const { return *Assert(m_options.assumed_valid_block); } /** |