LCOV - code coverage report
Current view: top level - src - versionbits.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 169 173 97.7 %
Date: 2026-06-25 07:23:43 Functions: 20 20 100.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       74133 : static int calculateStartHeight(const CBlockIndex* pindexPrev, ThresholdState state, const int nPeriod, const ThresholdConditionCache& cache) {
      12       74133 :     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      122533 :     while (state == ThresholdState::STARTED) {
      18       48400 :         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       48400 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
      24       48400 :         auto cache_it = cache.find(pindexPrev);
      25       48400 :         assert(cache_it != cache.end());
      26             : 
      27       48400 :         state = cache_it->second;
      28             :     }
      29             : 
      30       74133 :     return nStartHeight;
      31             : }
      32             : 
      33     8601821 : ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
      34             : {
      35     8601821 :     int nPeriod = Period(params);
      36     8601821 :     int min_activation_height = MinActivationHeight(params);
      37     8601821 :     int64_t nTimeStart = BeginTime(params);
      38     8601821 :     int masternodeStartHeight = SignalHeight(pindexPrev, params);
      39     8601821 :     int64_t nTimeTimeout = EndTime(params);
      40             : 
      41             :     // Check if this deployment is always active.
      42     8601821 :     if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
      43        6736 :         return ThresholdState::ACTIVE;
      44             :     }
      45             : 
      46             :     // Check if this deployment is never active.
      47     8595085 :     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     8588308 :     if (pindexPrev != nullptr) {
      53     8586029 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
      54     8586029 :     }
      55             : 
      56             :     // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
      57     8588308 :     std::vector<const CBlockIndex*> vToCompute;
      58     8695387 :     while (cache.count(pindexPrev) == 0) {
      59      175574 :         if (pindexPrev == nullptr) {
      60             :             // The genesis block is by definition defined.
      61       64858 :             cache[pindexPrev] = ThresholdState::DEFINED;
      62       64858 :             break;
      63             :         }
      64      110716 :         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      110716 :         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        3637 :             cache[pindexPrev] = ThresholdState::DEFINED;
      72        3637 :             break;
      73             :         }
      74      107079 :         vToCompute.push_back(pindexPrev);
      75      107079 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
      76             :     }
      77             : 
      78             :     // At this point, cache[pindexPrev] is known
      79     8588308 :     assert(cache.count(pindexPrev));
      80     8588308 :     ThresholdState state = cache[pindexPrev];
      81             : 
      82             :     // we should avoid heavy calculation of nStartHeight below if there's nothing to compute
      83     8588308 :     if (vToCompute.empty()) return state;
      84             : 
      85       74133 :     int nStartHeight = calculateStartHeight(pindexPrev, state, nPeriod, cache);
      86             : 
      87             :     // Now walk forward and compute the state of descendants of pindexPrev
      88      181212 :     while (!vToCompute.empty()) {
      89      107079 :         ThresholdState stateNext = state;
      90      107079 :         pindexPrev = vToCompute.back();
      91      107079 :         vToCompute.pop_back();
      92             : 
      93      107079 :         switch (state) {
      94             :             case ThresholdState::DEFINED: {
      95       47192 :                 if (pindexPrev->GetMedianTimePast() >= nTimeStart && pindexPrev->nHeight >= masternodeStartHeight) {
      96       47192 :                     stateNext = ThresholdState::STARTED;
      97       47192 :                     nStartHeight = pindexPrev->nHeight + 1;
      98       47192 :                 }
      99       47192 :                 break;
     100             :             }
     101             :             case ThresholdState::STARTED: {
     102             :                 // We need to count
     103       27307 :                 const CBlockIndex* pindexCount = pindexPrev;
     104       27307 :                 int count = 0;
     105       27307 :                 int nAttempt = (pindexCount->nHeight - nStartHeight) / nPeriod;
     106       27307 :                 int threshold = Threshold(params, nAttempt);
     107     2733372 :                 for (int i = 0; count + (nPeriod - i) >= threshold && i < nPeriod; ++i) {
     108     2706065 :                     if (Condition(pindexCount, params)) {
     109     1544860 :                         count++;
     110     1544860 :                     }
     111     2706065 :                     pindexCount = pindexCount->pprev;
     112     2706065 :                 }
     113       27307 :                 assert(nStartHeight > 0 && nStartHeight < std::numeric_limits<int>::max());
     114       27307 :                 if (count >= threshold) {
     115        1758 :                     stateNext = ThresholdState::LOCKED_IN;
     116       27307 :                 } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
     117        1506 :                     stateNext = ThresholdState::FAILED;
     118        1506 :                 }
     119       27307 :                 break;
     120             :             }
     121             :             case ThresholdState::LOCKED_IN: {
     122             :                 // Progresses into ACTIVE provided activation height will have been reached.
     123        9232 :                 if (pindexPrev->nHeight + 1 >= min_activation_height) {
     124        1257 :                     stateNext = ThresholdState::ACTIVE;
     125        1257 :                 }
     126        9232 :                 break;
     127             :             }
     128             :             case ThresholdState::FAILED:
     129             :             case ThresholdState::ACTIVE: {
     130             :                 // Nothing happens, these are terminal states.
     131       23348 :                 break;
     132             :             }
     133             :         }
     134      107079 :         cache[pindexPrev] = state = stateNext;
     135             :     }
     136             : 
     137       74133 :     return state;
     138     8601821 : }
     139             : 
     140       13758 : BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, ThresholdConditionCache& cache) const
     141             : {
     142       13758 :     BIP9Stats stats = {};
     143             : 
     144       13758 :     stats.period = Period(params);
     145       13758 :     stats.threshold = Threshold(params, 0);
     146             : 
     147       13758 :     if (pindex == nullptr)
     148           0 :         return stats;
     149             : 
     150             :     // Find beginning of period
     151       13758 :     const CBlockIndex* pindexEndOfPrevPeriod = pindex->GetAncestor(pindex->nHeight - ((pindex->nHeight + 1) % stats.period));
     152       13758 :     stats.elapsed = pindex->nHeight - pindexEndOfPrevPeriod->nHeight;
     153             : 
     154             :     // Re-calculate current threshold
     155       13758 :     int nAttempt{0};
     156       13758 :     const ThresholdState state = GetStateFor(pindexEndOfPrevPeriod, params, cache);
     157       13758 :     if (state == ThresholdState::STARTED) {
     158        3123 :         int nStartHeight = GetStateSinceHeightFor(pindexEndOfPrevPeriod, params, cache);
     159        3123 :         nAttempt = (pindexEndOfPrevPeriod->nHeight + 1 - nStartHeight)/stats.period;
     160        3123 :     }
     161       13758 :     stats.threshold = Threshold(params, nAttempt);
     162             : 
     163             :     // Count from current block to beginning of period
     164       13758 :     int count = 0;
     165       13758 :     const CBlockIndex* currentIndex = pindex;
     166      549474 :     while (pindexEndOfPrevPeriod->nHeight != currentIndex->nHeight){
     167      535716 :         if (Condition(currentIndex, params))
     168      441212 :             count++;
     169      535716 :         currentIndex = currentIndex->pprev;
     170             :     }
     171             : 
     172       13758 :     stats.count = count;
     173       13758 :     stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
     174             : 
     175       13758 :     return stats;
     176       13758 : }
     177             : 
     178       60315 : int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
     179             : {
     180       60315 :     int64_t start_time = BeginTime(params);
     181       60315 :     if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
     182       13460 :         return 0;
     183             :     }
     184             : 
     185       46855 :     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       46855 :     if (initialState == ThresholdState::DEFINED) {
     189       20630 :         return 0;
     190             :     }
     191             : 
     192       26225 :     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       26225 :     pindexPrev = Assert(pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)));
     201             : 
     202       26225 :     const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
     203             : 
     204       50253 :     while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
     205       24028 :         pindexPrev = previousPeriodParent;
     206       24028 :         previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
     207             :     }
     208             : 
     209             :     // Adjust the result because right now we point to the parent block.
     210       26225 :     return pindexPrev->nHeight + 1;
     211       60315 : }
     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     1341444 :     int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
     224     1308049 :     int SignalHeight(const CBlockIndex* const pindexPrev, const Consensus::Params& params) const override {
     225     1308049 :         const auto& deployment = params.vDeployments[id];
     226     1308049 :         if (!deployment.useEHF) {
     227      774929 :             return 0;
     228             :         }
     229             :         // ehfManager should be initialized before first usage of VersionBitsConditionChecker
     230      533120 :         const auto ehfManagerPtr = AbstractEHFManager::getInstance();
     231      533120 :         const auto signals = ehfManagerPtr->GetSignalsStage(pindexPrev);
     232      533120 :         const auto it = signals.find(deployment.bit);
     233      533120 :         if (it == signals.end()) {
     234      408929 :             return std::numeric_limits<int>::max();
     235             :         }
     236             : 
     237      124191 :         return it->second;
     238     1308049 :     }
     239     1308049 :     int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
     240     1308049 :     int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
     241     1340026 :     int Period(const Consensus::Params& params) const override { return params.vDeployments[id].nWindowSize ? params.vDeployments[id].nWindowSize : params.nMinerConfirmationWindow; }
     242       28530 :     int Threshold(const Consensus::Params& params, int nAttempt) const override
     243             :     {
     244       28530 :         if (params.vDeployments[id].nThresholdStart == 0) {
     245       27512 :             return params.nRuleChangeActivationThreshold;
     246             :         }
     247        1018 :         if (params.vDeployments[id].nThresholdMin == 0 || params.vDeployments[id].nFalloffCoeff == 0) {
     248           0 :             return params.vDeployments[id].nThresholdStart;
     249             :         }
     250        1018 :         int64_t nThresholdCalc = params.vDeployments[id].nThresholdStart - nAttempt * nAttempt * Period(params) / 100 / params.vDeployments[id].nFalloffCoeff;
     251        1018 :         return std::max(params.vDeployments[id].nThresholdMin, nThresholdCalc);
     252       28530 :     }
     253             : 
     254      602594 :     bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
     255             :     {
     256      602594 :         return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
     257             :     }
     258             : 
     259             : public:
     260     2740288 :     explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
     261      584771 :     uint32_t Mask(const Consensus::Params& params) const { return (uint32_t{1}) << params.vDeployments[id].bit; }
     262             : };
     263             : 
     264             : } // namespace
     265             : 
     266     1014437 : ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     267             : {
     268     1014437 :     LOCK(m_mutex);
     269     1014437 :     return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     270     1014437 : }
     271             : 
     272       13758 : BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     273             : {
     274       13758 :     LOCK(m_mutex);
     275       13758 :     return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindexPrev, params, m_caches[pos]);
     276       13758 : }
     277             : 
     278       30272 : int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     279             : {
     280       30272 :     LOCK(m_mutex);
     281       30272 :     return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, m_caches[pos]);
     282       30272 : }
     283             : 
     284       78827 : uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
     285             : {
     286       78827 :     return VersionBitsConditionChecker(pos).Mask(params);
     287             : }
     288             : 
     289      116425 : int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
     290             : {
     291      116425 :     LOCK(m_mutex);
     292      116425 :     int32_t nVersion = VERSIONBITS_TOP_BITS;
     293             : 
     294      349275 :     for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
     295      232850 :         Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
     296      232850 :         ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     297      232850 :         if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
     298       78718 :             nVersion |= Mask(params, pos);
     299       78718 :         }
     300      232850 :     }
     301             : 
     302      116425 :     return nVersion;
     303      116425 : }
     304             : 
     305        3079 : void VersionBitsCache::Clear()
     306             : {
     307        3079 :     LOCK(m_mutex);
     308        9237 :     for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
     309        6158 :         m_caches[d].clear();
     310        6158 :     }
     311        3079 : }
     312             : AbstractEHFManager* AbstractEHFManager::globalInstance{nullptr};

Generated by: LCOV version 1.16