LCOV - code coverage report
Current view: top level - src - versionbits.cpp (source / functions) Hit Total Coverage
Test: test_dash_coverage.info Lines: 161 173 93.1 %
Date: 2026-06-25 07:23:51 Functions: 19 20 95.0 %

          Line data    Source code
       1             : // Copyright (c) 2016-2021 The Bitcoin Core developers
       2             : // Distributed under the MIT software license, see the accompanying
       3             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       4             : 
       5             : #include <consensus/params.h>
       6             : #include <util/check.h>
       7             : #include <versionbits.h>
       8             : 
       9             : #include <limits>
      10             : 
      11       12752 : static int calculateStartHeight(const CBlockIndex* pindexPrev, ThresholdState state, const int nPeriod, const ThresholdConditionCache& cache) {
      12       12752 :     int nStartHeight{std::numeric_limits<int>::max()};
      13             : 
      14             :     // we are interested only in state STARTED
      15             :     // For state DEFINED: it is not started yet, nothing to do
      16             :     // For states LOCKED_IN, FAILED, ACTIVE: it is too late, nothing to do
      17       27749 :     while (state == ThresholdState::STARTED) {
      18       14997 :         nStartHeight = std::min(pindexPrev->nHeight + 1, nStartHeight);
      19             : 
      20             :         // we can walk back here because the only way for STARTED state to exist
      21             :         // in cache already is to be calculated in previous runs via "walk forward"
      22             :         // loop below starting from DEFINED state.
      23       14997 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
      24       14997 :         auto cache_it = cache.find(pindexPrev);
      25       14997 :         assert(cache_it != cache.end());
      26             : 
      27       14997 :         state = cache_it->second;
      28             :     }
      29             : 
      30       12752 :     return nStartHeight;
      31             : }
      32             : 
      33      905196 : ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
      34             : {
      35      905196 :     int nPeriod = Period(params);
      36      905196 :     int min_activation_height = MinActivationHeight(params);
      37      905196 :     int64_t nTimeStart = BeginTime(params);
      38      905196 :     int masternodeStartHeight = SignalHeight(pindexPrev, params);
      39      905196 :     int64_t nTimeTimeout = EndTime(params);
      40             : 
      41             :     // Check if this deployment is always active.
      42      905196 :     if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
      43        6736 :         return ThresholdState::ACTIVE;
      44             :     }
      45             : 
      46             :     // Check if this deployment is never active.
      47      898460 :     if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) {
      48        6777 :         return ThresholdState::FAILED;
      49             :     }
      50             : 
      51             :     // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
      52      891683 :     if (pindexPrev != nullptr) {
      53      889404 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
      54      889404 :     }
      55             : 
      56             :     // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
      57      891683 :     std::vector<const CBlockIndex*> vToCompute;
      58      929988 :     while (cache.count(pindexPrev) == 0) {
      59       45701 :         if (pindexPrev == nullptr) {
      60             :             // The genesis block is by definition defined.
      61        4507 :             cache[pindexPrev] = ThresholdState::DEFINED;
      62        4507 :             break;
      63             :         }
      64       41194 :         if (pindexPrev->nHeight < params.MinBIP9WarningHeight) {
      65             :             // Optimization: don't compute below MinBIP9WarningHeight, consider it defined.
      66           0 :             cache[pindexPrev] = ThresholdState::DEFINED;
      67           0 :             break;
      68             :         }
      69       41194 :         if (pindexPrev->GetMedianTimePast() < nTimeStart || pindexPrev->nHeight < masternodeStartHeight) {
      70             :             // Optimization: don't recompute down further, as we know every earlier block will be before the start time
      71        2889 :             cache[pindexPrev] = ThresholdState::DEFINED;
      72        2889 :             break;
      73             :         }
      74       38305 :         vToCompute.push_back(pindexPrev);
      75       38305 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
      76             :     }
      77             : 
      78             :     // At this point, cache[pindexPrev] is known
      79      891683 :     assert(cache.count(pindexPrev));
      80      891683 :     ThresholdState state = cache[pindexPrev];
      81             : 
      82             :     // we should avoid heavy calculation of nStartHeight below if there's nothing to compute
      83      891683 :     if (vToCompute.empty()) return state;
      84             : 
      85       12752 :     int nStartHeight = calculateStartHeight(pindexPrev, state, nPeriod, cache);
      86             : 
      87             :     // Now walk forward and compute the state of descendants of pindexPrev
      88       51057 :     while (!vToCompute.empty()) {
      89       38305 :         ThresholdState stateNext = state;
      90       38305 :         pindexPrev = vToCompute.back();
      91       38305 :         vToCompute.pop_back();
      92             : 
      93       38305 :         switch (state) {
      94             :             case ThresholdState::DEFINED: {
      95        3796 :                 if (pindexPrev->GetMedianTimePast() >= nTimeStart && pindexPrev->nHeight >= masternodeStartHeight) {
      96        3796 :                     stateNext = ThresholdState::STARTED;
      97        3796 :                     nStartHeight = pindexPrev->nHeight + 1;
      98        3796 :                 }
      99        3796 :                 break;
     100             :             }
     101             :             case ThresholdState::STARTED: {
     102             :                 // We need to count
     103        6722 :                 const CBlockIndex* pindexCount = pindexPrev;
     104        6722 :                 int count = 0;
     105        6722 :                 int nAttempt = (pindexCount->nHeight - nStartHeight) / nPeriod;
     106        6722 :                 int threshold = Threshold(params, nAttempt);
     107     1928308 :                 for (int i = 0; count + (nPeriod - i) >= threshold && i < nPeriod; ++i) {
     108     1921586 :                     if (Condition(pindexCount, params)) {
     109     1491946 :                         count++;
     110     1491946 :                     }
     111     1921586 :                     pindexCount = pindexCount->pprev;
     112     1921586 :                 }
     113        6722 :                 assert(nStartHeight > 0 && nStartHeight < std::numeric_limits<int>::max());
     114        6722 :                 if (count >= threshold) {
     115        1178 :                     stateNext = ThresholdState::LOCKED_IN;
     116        6722 :                 } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
     117        1506 :                     stateNext = ThresholdState::FAILED;
     118        1506 :                 }
     119        6722 :                 break;
     120             :             }
     121             :             case ThresholdState::LOCKED_IN: {
     122             :                 // Progresses into ACTIVE provided activation height will have been reached.
     123        8910 :                 if (pindexPrev->nHeight + 1 >= min_activation_height) {
     124         935 :                     stateNext = ThresholdState::ACTIVE;
     125         935 :                 }
     126        8910 :                 break;
     127             :             }
     128             :             case ThresholdState::FAILED:
     129             :             case ThresholdState::ACTIVE: {
     130             :                 // Nothing happens, these are terminal states.
     131       18877 :                 break;
     132             :             }
     133             :         }
     134       38305 :         cache[pindexPrev] = state = stateNext;
     135             :     }
     136             : 
     137       12752 :     return state;
     138      905196 : }
     139             : 
     140         102 : BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, ThresholdConditionCache& cache) const
     141             : {
     142         102 :     BIP9Stats stats = {};
     143             : 
     144         102 :     stats.period = Period(params);
     145         102 :     stats.threshold = Threshold(params, 0);
     146             : 
     147         102 :     if (pindex == nullptr)
     148           0 :         return stats;
     149             : 
     150             :     // Find beginning of period
     151         102 :     const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));
     152         102 :     stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;
     153             : 
     154             :     // Re-calculate current threshold
     155         102 :     int nAttempt{0};
     156         102 :     const ThresholdState state = GetStateFor(pindexEndOfPrevPeriod, params, cache);
     157         102 :     if (state == ThresholdState::STARTED) {
     158         102 :         int nStartHeight = GetStateSinceHeightFor(pindexEndOfPrevPeriod, params, cache);
     159         102 :         nAttempt = (pindexEndOfPrevPeriod->nHeight + 1 - nStartHeight)/stats.period;
     160         102 :     }
     161         102 :     stats.threshold = Threshold(params, nAttempt);
     162             : 
     163             :     // Count from current block to beginning of period
     164         102 :     int count = 0;
     165         102 :     const CBlockIndex* currentIndex = pindex;
     166         102 :     while (pindexEndOfPrevPeriod->nHeight != currentIndex->nHeight){
     167           0 :         if (Condition(currentIndex, params))
     168           0 :             count++;
     169           0 :         currentIndex = currentIndex->pprev;
     170             :     }
     171             : 
     172         102 :     stats.count = count;
     173         102 :     stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
     174             : 
     175         102 :     return stats;
     176         102 : }
     177             : 
     178       27022 : int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
     179             : {
     180       27022 :     int64_t start_time = BeginTime(params);
     181       27022 :     if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
     182       13460 :         return 0;
     183             :     }
     184             : 
     185       13562 :     const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
     186             : 
     187             :     // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
     188       13562 :     if (initialState == ThresholdState::DEFINED) {
     189        4436 :         return 0;
     190             :     }
     191             : 
     192        9126 :     const int nPeriod = Period(params);
     193             : 
     194             :     // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
     195             :     // To ease understanding of the following height calculation, it helps to remember that
     196             :     // right now pindexPrev points to the block prior to the block that we are computing for, thus:
     197             :     // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
     198             :     // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
     199             :     // The parent of the genesis block is represented by nullptr.
     200        9126 :     pindexPrev = Assert(pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)));
     201             : 
     202        9126 :     const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
     203             : 
     204       31076 :     while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
     205       21950 :         pindexPrev = previousPeriodParent;
     206       21950 :         previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
     207             :     }
     208             : 
     209             :     // Adjust the result because right now we point to the parent block.
     210        9126 :     return pindexPrev->nHeight + 1;
     211       27022 : }
     212             : 
     213             : namespace
     214             : {
     215             : /**
     216             :  * Class to implement versionbits logic.
     217             :  */
     218             : class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
     219             : private:
     220             :     const Consensus::DeploymentPos id;
     221             : 
     222             : protected:
     223      150185 :     int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
     224      150083 :     int SignalHeight(const CBlockIndex* const pindexPrev, const Consensus::Params& params) const override {
     225      150083 :         const auto& deployment = params.vDeployments[id];
     226      150083 :         if (!deployment.useEHF) {
     227       76373 :             return 0;
     228             :         }
     229             :         // ehfManager should be initialized before first usage of VersionBitsConditionChecker
     230       73710 :         const auto ehfManagerPtr = AbstractEHFManager::getInstance();
     231       73710 :         const auto signals = ehfManagerPtr->GetSignalsStage(pindexPrev);
     232       73710 :         const auto it = signals.find(deployment.bit);
     233       73710 :         if (it == signals.end()) {
     234       73710 :             return std::numeric_limits<int>::max();
     235             :         }
     236             : 
     237           0 :         return it->second;
     238      150083 :     }
     239      150083 :     int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
     240      150083 :     int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
     241      150581 :     int Period(const Consensus::Params& params) const override { return params.vDeployments[id].nWindowSize ? params.vDeployments[id].nWindowSize : params.nMinerConfirmationWindow; }
     242         320 :     int Threshold(const Consensus::Params& params, int nAttempt) const override
     243             :     {
     244         320 :         if (params.vDeployments[id].nThresholdStart == 0) {
     245          26 :             return params.nRuleChangeActivationThreshold;
     246             :         }
     247         294 :         if (params.vDeployments[id].nThresholdMin == 0 || params.vDeployments[id].nFalloffCoeff == 0) {
     248           0 :             return params.vDeployments[id].nThresholdStart;
     249             :         }
     250         294 :         int64_t nThresholdCalc = params.vDeployments[id].nThresholdStart - nAttempt * nAttempt * Period(params) / 100 / params.vDeployments[id].nFalloffCoeff;
     251         294 :         return std::max(params.vDeployments[id].nThresholdMin, nThresholdCalc);
     252         320 :     }
     253             : 
     254       11674 :     bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
     255             :     {
     256       11674 :         return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
     257             :     }
     258             : 
     259             : public:
     260      336900 :     explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
     261       30215 :     uint32_t Mask(const Consensus::Params& params) const { return (uint32_t{1}) << params.vDeployments[id].bit; }
     262             : };
     263             : 
     264             : } // namespace
     265             : 
     266       90417 : ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     267             : {
     268       90417 :     LOCK(m_mutex);
     269       90417 :     return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     270       90417 : }
     271             : 
     272         102 : BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     273             : {
     274         102 :     LOCK(m_mutex);
     275         102 :     return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindexPrev, params, m_caches[pos]);
     276         102 : }
     277             : 
     278           0 : int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     279             : {
     280           0 :     LOCK(m_mutex);
     281           0 :     return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, m_caches[pos]);
     282           0 : }
     283             : 
     284       18911 : uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
     285             : {
     286       18911 :     return VersionBitsConditionChecker(pos).Mask(params);
     287             : }
     288             : 
     289       29510 : int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
     290             : {
     291       29510 :     LOCK(m_mutex);
     292       29510 :     int32_t nVersion = VERSIONBITS_TOP_BITS;
     293             : 
     294       88530 :     for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
     295       59020 :         Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
     296       59020 :         ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     297       59020 :         if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
     298       18900 :             nVersion |= Mask(params, pos);
     299       18900 :         }
     300       59020 :     }
     301             : 
     302       29510 :     return nVersion;
     303       29510 : }
     304             : 
     305         194 : void VersionBitsCache::Clear()
     306             : {
     307         194 :     LOCK(m_mutex);
     308         582 :     for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
     309         388 :         m_caches[d].clear();
     310         388 :     }
     311         194 : }
     312             : AbstractEHFManager* AbstractEHFManager::globalInstance{nullptr};

Generated by: LCOV version 1.16