diff --git a/src/init.cpp b/src/init.cpp --- a/src/init.cpp +++ b/src/init.cpp @@ -1865,10 +1865,6 @@ LogPrintf("Skipping checkpoint verification.\n"); } - hashAssumeValid = BlockHash::fromHex( - args.GetArg("-assumevalid", - chainparams.GetConsensus().defaultAssumeValid.GetHex())); - if (args.IsArgSet("-minimumchainwork")) { const std::string minChainWorkStr = args.GetArg("-minimumchainwork", ""); diff --git a/src/kernel/chainstatemanager_opts.h b/src/kernel/chainstatemanager_opts.h --- a/src/kernel/chainstatemanager_opts.h +++ b/src/kernel/chainstatemanager_opts.h @@ -5,10 +5,12 @@ #ifndef BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H #define BITCOIN_KERNEL_CHAINSTATEMANAGER_OPTS_H +#include #include #include #include +#include class Config; @@ -25,6 +27,9 @@ const Config &config; const std::function adjusted_time_callback{ nullptr}; + //! If set, it will override the block hash whose ancestors we will assume + //! to have valid scripts without checking them. + std::optional assumed_valid_block{}; //! If the tip is older than this, the node is considered to be in initial //! block download. std::chrono::seconds max_tip_age{DEFAULT_MAX_TIP_AGE}; diff --git a/src/node/chainstate.cpp b/src/node/chainstate.cpp --- a/src/node/chainstate.cpp +++ b/src/node/chainstate.cpp @@ -163,9 +163,9 @@ ChainstateLoadResult LoadChainstate(ChainstateManager &chainman, const CacheSizes &cache_sizes, const ChainstateLoadOptions &options) { - if (!hashAssumeValid.IsNull()) { + if (!chainman.AssumedValidBlock().IsNull()) { LogPrintf("Assuming ancestors of block %s have valid signatures.\n", - hashAssumeValid.GetHex()); + chainman.AssumedValidBlock().GetHex()); } else { LogPrintf("Validating signatures for all blocks.\n"); } diff --git a/src/node/chainstatemanager_args.cpp b/src/node/chainstatemanager_args.cpp --- a/src/node/chainstatemanager_args.cpp +++ b/src/node/chainstatemanager_args.cpp @@ -12,6 +12,10 @@ namespace node { void ApplyArgsManOptions(const ArgsManager &args, ChainstateManager::Options &opts) { + if (auto value{args.GetArg("-assumevalid")}) { + opts.assumed_valid_block = BlockHash::fromHex(*value); + } + if (auto value{args.GetIntArg("-maxtipage")}) { opts.max_tip_age = std::chrono::seconds{*value}; } diff --git a/src/validation.h b/src/validation.h --- a/src/validation.h +++ b/src/validation.h @@ -120,12 +120,6 @@ extern bool fCheckBlockIndex; extern bool fCheckpointsEnabled; -/** - * Block hash whose ancestors we will assume to have valid scripts without - * checking them. - */ -extern BlockHash hashAssumeValid; - /** * Minimum work we will assume exists on some valid chain. */ @@ -1235,10 +1229,7 @@ public: using Options = kernel::ChainstateManagerOpts; - explicit ChainstateManager(Options options) - : m_options{std::move(options)} { - Assert(m_options.adjusted_time_callback); - } + explicit ChainstateManager(Options options); const Config &GetConfig() const { return m_options.config; } @@ -1248,6 +1239,9 @@ const Consensus::Params &GetConsensus() const { return m_options.config.GetChainParams().GetConsensus(); } + const BlockHash &AssumedValidBlock() const { + return *Assert(m_options.assumed_valid_block); + } /** * Alias for ::cs_main. diff --git a/src/validation.cpp b/src/validation.cpp --- a/src/validation.cpp +++ b/src/validation.cpp @@ -112,7 +112,6 @@ bool fCheckBlockIndex = false; bool fCheckpointsEnabled = DEFAULT_CHECKPOINTS_ENABLED; -BlockHash hashAssumeValid; arith_uint256 nMinimumChainWork; BlockValidationOptions::BlockValidationOptions(const Config &config) @@ -1754,7 +1753,7 @@ } bool fScriptChecks = true; - if (!hashAssumeValid.IsNull()) { + if (!m_chainman.AssumedValidBlock().IsNull()) { // We've been configured with the hash of a block which has been // externally verified to have a valid history. A suitable default value // is included with the software and updated from time to time. Because @@ -1762,8 +1761,8 @@ // defaults can be easily reviewed. This setting doesn't force the // selection of any particular chain but makes validating some faster by // effectively caching the result of part of the verification. - BlockMap::const_iterator it = - m_blockman.m_block_index.find(hashAssumeValid); + BlockMap::const_iterator it{ + m_blockman.m_block_index.find(m_chainman.AssumedValidBlock())}; if (it != m_blockman.m_block_index.end()) { if (it->second.GetAncestor(pindex->nHeight) == pindex && m_chainman.m_best_header->GetAncestor(pindex->nHeight) == @@ -6363,6 +6362,23 @@ m_active_chainstate = nullptr; } +/** + * Apply default chain params to nullopt members. + * This helps to avoid coding errors around the accidental use of the compare + * operators that accept nullopt, thus ignoring the intended default value. + */ +static ChainstateManager::Options &&Flatten(ChainstateManager::Options &&opts) { + if (!opts.assumed_valid_block.has_value()) { + opts.assumed_valid_block = + opts.config.GetChainParams().GetConsensus().defaultAssumeValid; + } + Assert(opts.adjusted_time_callback); + return std::move(opts); +} + +ChainstateManager::ChainstateManager(Options options) + : m_options{Flatten(std::move(options))} {} + bool ChainstateManager::DetectSnapshotChainstate(CTxMemPool *mempool) { assert(!m_snapshot_chainstate); std::optional path = node::FindSnapshotChainstateDir();