LCOV - code coverage report
Current view: top level - src - versionbits.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 62 136 45.6 %
Date: 2023-09-26 12:08:55 Functions: 12 18 66.7 %

          Line data    Source code
       1             : // Copyright (c) 2016-2022 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       10118 : ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
      10             : {
      11       10118 :     int nPeriod = Period(params);
      12       10118 :     int nThreshold = Threshold(params);
      13       10118 :     int min_activation_height = MinActivationHeight(params);
      14       10118 :     int64_t nTimeStart = BeginTime(params);
      15       10118 :     int64_t nTimeTimeout = EndTime(params);
      16             : 
      17             :     // Check if this deployment is always active.
      18       10118 :     if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
      19        5059 :         return ThresholdState::ACTIVE;
      20             :     }
      21             : 
      22             :     // Check if this deployment is never active.
      23        5059 :     if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) {
      24           0 :         return ThresholdState::FAILED;
      25             :     }
      26             : 
      27             :     // 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.
      28        5059 :     if (pindexPrev != nullptr) {
      29        5059 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
      30        5059 :     }
      31             : 
      32             :     // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
      33        5059 :     std::vector<const CBlockIndex*> vToCompute;
      34        5060 :     while (cache.count(pindexPrev) == 0) {
      35           2 :         if (pindexPrev == nullptr) {
      36             :             // The genesis block is by definition defined.
      37           1 :             cache[pindexPrev] = ThresholdState::DEFINED;
      38           1 :             break;
      39             :         }
      40           1 :         if (pindexPrev->GetMedianTimePast() < nTimeStart) {
      41             :             // Optimization: don't recompute down further, as we know every earlier block will be before the start time
      42           0 :             cache[pindexPrev] = ThresholdState::DEFINED;
      43           0 :             break;
      44             :         }
      45           1 :         vToCompute.push_back(pindexPrev);
      46           1 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
      47             :     }
      48             : 
      49             :     // At this point, cache[pindexPrev] is known
      50        5059 :     assert(cache.count(pindexPrev));
      51        5059 :     ThresholdState state = cache[pindexPrev];
      52             : 
      53             :     // Now walk forward and compute the state of descendants of pindexPrev
      54        5060 :     while (!vToCompute.empty()) {
      55           1 :         ThresholdState stateNext = state;
      56           1 :         pindexPrev = vToCompute.back();
      57           1 :         vToCompute.pop_back();
      58             : 
      59           1 :         switch (state) {
      60             :             case ThresholdState::DEFINED: {
      61           1 :                 if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
      62           1 :                     stateNext = ThresholdState::STARTED;
      63           1 :                 }
      64           1 :                 break;
      65             :             }
      66             :             case ThresholdState::STARTED: {
      67             :                 // We need to count
      68           0 :                 const CBlockIndex* pindexCount = pindexPrev;
      69           0 :                 int count = 0;
      70           0 :                 for (int i = 0; i < nPeriod; i++) {
      71           0 :                     if (Condition(pindexCount, params)) {
      72           0 :                         count++;
      73           0 :                     }
      74           2 :                     pindexCount = pindexCount->pprev;
      75           0 :                 }
      76           0 :                 if (count >= nThreshold) {
      77           0 :                     stateNext = ThresholdState::LOCKED_IN;
      78           0 :                 } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
      79           0 :                     stateNext = ThresholdState::FAILED;
      80           0 :                 }
      81           0 :                 break;
      82             :             }
      83             :             case ThresholdState::LOCKED_IN: {
      84             :                 // Progresses into ACTIVE provided activation height will have been reached.
      85           0 :                 if (pindexPrev->nHeight + 1 >= min_activation_height) {
      86           0 :                     stateNext = ThresholdState::ACTIVE;
      87           0 :                 }
      88           0 :                 break;
      89             :             }
      90             :             case ThresholdState::FAILED:
      91             :             case ThresholdState::ACTIVE: {
      92             :                 // Nothing happens, these are terminal states.
      93           0 :                 break;
      94             :             }
      95             :         }
      96           1 :         cache[pindexPrev] = state = stateNext;
      97             :     }
      98             : 
      99        5059 :     return state;
     100       10118 : }
     101             : 
     102           0 : BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks) const
     103             : {
     104           0 :     BIP9Stats stats = {};
     105             : 
     106           0 :     stats.period = Period(params);
     107           0 :     stats.threshold = Threshold(params);
     108             : 
     109           0 :     if (pindex == nullptr) return stats;
     110             : 
     111             :     // Find how many blocks are in the current period
     112           0 :     int blocks_in_period = 1 + (pindex->nHeight % stats.period);
     113             : 
     114             :     // Reset signalling_blocks
     115           0 :     if (signalling_blocks) {
     116           0 :         signalling_blocks->assign(blocks_in_period, false);
     117           0 :     }
     118             : 
     119             :     // Count from current block to beginning of period
     120           0 :     int elapsed = 0;
     121           0 :     int count = 0;
     122           0 :     const CBlockIndex* currentIndex = pindex;
     123           0 :     do {
     124           0 :         ++elapsed;
     125           0 :         --blocks_in_period;
     126           0 :         if (Condition(currentIndex, params)) {
     127           0 :             ++count;
     128           0 :             if (signalling_blocks) signalling_blocks->at(blocks_in_period) = true;
     129           0 :         }
     130           0 :         currentIndex = currentIndex->pprev;
     131           0 :     } while(blocks_in_period > 0);
     132             : 
     133           0 :     stats.elapsed = elapsed;
     134           0 :     stats.count = count;
     135           0 :     stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
     136             : 
     137           0 :     return stats;
     138           0 : }
     139             : 
     140           0 : int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
     141             : {
     142           0 :     int64_t start_time = BeginTime(params);
     143           0 :     if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
     144           0 :         return 0;
     145             :     }
     146             : 
     147           0 :     const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
     148             : 
     149             :     // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
     150           0 :     if (initialState == ThresholdState::DEFINED) {
     151           0 :         return 0;
     152             :     }
     153             : 
     154           0 :     const int nPeriod = Period(params);
     155             : 
     156             :     // 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.
     157             :     // To ease understanding of the following height calculation, it helps to remember that
     158             :     // right now pindexPrev points to the block prior to the block that we are computing for, thus:
     159             :     // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
     160             :     // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
     161             :     // The parent of the genesis block is represented by nullptr.
     162           0 :     pindexPrev = Assert(pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)));
     163             : 
     164           0 :     const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
     165             : 
     166           0 :     while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
     167           0 :         pindexPrev = previousPeriodParent;
     168           0 :         previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
     169             :     }
     170             : 
     171             :     // Adjust the result because right now we point to the parent block.
     172           0 :     return pindexPrev->nHeight + 1;
     173           0 : }
     174             : 
     175             : namespace
     176             : {
     177             : /**
     178             :  * Class to implement versionbits logic.
     179             :  */
     180             : class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
     181             : private:
     182             :     const Consensus::DeploymentPos id;
     183             : 
     184             : protected:
     185       10118 :     int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
     186       10118 :     int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
     187       10118 :     int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
     188       10118 :     int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
     189       10118 :     int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
     190             : 
     191           0 :     bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
     192             :     {
     193           0 :         return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
     194             :     }
     195             : 
     196             : public:
     197       15034 :     explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
     198        4916 :     uint32_t Mask(const Consensus::Params& params) const { return (uint32_t{1}) << params.vDeployments[id].bit; }
     199             : };
     200             : 
     201             : } // namespace
     202             : 
     203           0 : ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     204             : {
     205           0 :     LOCK(m_mutex);
     206           0 :     return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     207           0 : }
     208             : 
     209           0 : BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks)
     210             : {
     211           0 :     return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindex, params, signalling_blocks);
     212             : }
     213             : 
     214           0 : int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
     215             : {
     216           0 :     LOCK(m_mutex);
     217           0 :     return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, m_caches[pos]);
     218           0 : }
     219             : 
     220        4916 : uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
     221             : {
     222        4916 :     return VersionBitsConditionChecker(pos).Mask(params);
     223             : }
     224             : 
     225        5059 : int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
     226             : {
     227        5059 :     LOCK(m_mutex);
     228        5059 :     int32_t nVersion = VERSIONBITS_TOP_BITS;
     229             : 
     230       15177 :     for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
     231       10118 :         Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
     232       10118 :         ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     233       10118 :         if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
     234        4916 :             nVersion |= Mask(params, pos);
     235        4916 :         }
     236       10118 :     }
     237             : 
     238        5059 :     return nVersion;
     239        5059 : }
     240             : 
     241           1 : void VersionBitsCache::Clear()
     242             : {
     243           1 :     LOCK(m_mutex);
     244           3 :     for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
     245           2 :         m_caches[d].clear();
     246           2 :     }
     247           1 : }

Generated by: LCOV version 1.14