LCOV - code coverage report
Current view: top level - src - versionbits.cpp (source / functions) Coverage Total Hit
Test: fuzz_coverage.info Lines: 4.5 % 111 5
Test Date: 2024-10-23 17:21:46 Functions: 6.7 % 15 1
Branches: 2.2 % 92 2

             Branch data     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                 :           0 : ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
      10                 :             : {
      11                 :           0 :     int nPeriod = Period(params);
      12                 :           0 :     int nThreshold = Threshold(params);
      13                 :           0 :     int min_activation_height = MinActivationHeight(params);
      14                 :           0 :     int64_t nTimeStart = BeginTime(params);
      15                 :           0 :     int64_t nTimeTimeout = EndTime(params);
      16                 :             : 
      17                 :             :     // Check if this deployment is always active.
      18         [ #  # ]:           0 :     if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
      19                 :             :         return ThresholdState::ACTIVE;
      20                 :             :     }
      21                 :             : 
      22                 :             :     // Check if this deployment is never active.
      23         [ #  # ]:           0 :     if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) {
      24                 :             :         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         [ #  # ]:           0 :     if (pindexPrev != nullptr) {
      29                 :           0 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
      30                 :             :     }
      31                 :             : 
      32                 :             :     // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
      33                 :           0 :     std::vector<const CBlockIndex*> vToCompute;
      34         [ #  # ]:           0 :     while (cache.count(pindexPrev) == 0) {
      35         [ #  # ]:           0 :         if (pindexPrev == nullptr) {
      36                 :             :             // The genesis block is by definition defined.
      37         [ #  # ]:           0 :             cache[pindexPrev] = ThresholdState::DEFINED;
      38                 :           0 :             break;
      39                 :             :         }
      40         [ #  # ]:           0 :         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         [ #  # ]:           0 :         vToCompute.push_back(pindexPrev);
      46         [ #  # ]:           0 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
      47                 :             :     }
      48                 :             : 
      49                 :             :     // At this point, cache[pindexPrev] is known
      50         [ #  # ]:           0 :     assert(cache.count(pindexPrev));
      51         [ #  # ]:           0 :     ThresholdState state = cache[pindexPrev];
      52                 :             : 
      53                 :             :     // Now walk forward and compute the state of descendants of pindexPrev
      54         [ #  # ]:           0 :     while (!vToCompute.empty()) {
      55                 :           0 :         ThresholdState stateNext = state;
      56                 :           0 :         pindexPrev = vToCompute.back();
      57   [ #  #  #  # ]:           0 :         vToCompute.pop_back();
      58                 :             : 
      59   [ #  #  #  # ]:           0 :         switch (state) {
      60                 :           0 :             case ThresholdState::DEFINED: {
      61         [ #  # ]:           0 :                 if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
      62                 :           0 :                     stateNext = ThresholdState::STARTED;
      63                 :             :                 }
      64                 :             :                 break;
      65                 :             :             }
      66                 :             :             case ThresholdState::STARTED: {
      67                 :             :                 // We need to count
      68                 :             :                 const CBlockIndex* pindexCount = pindexPrev;
      69                 :             :                 int count = 0;
      70         [ #  # ]:           0 :                 for (int i = 0; i < nPeriod; i++) {
      71   [ #  #  #  # ]:           0 :                     if (Condition(pindexCount, params)) {
      72                 :           0 :                         count++;
      73                 :             :                     }
      74                 :           0 :                     pindexCount = pindexCount->pprev;
      75                 :             :                 }
      76         [ #  # ]:           0 :                 if (count >= nThreshold) {
      77                 :             :                     stateNext = ThresholdState::LOCKED_IN;
      78         [ #  # ]:           0 :                 } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
      79                 :           0 :                     stateNext = ThresholdState::FAILED;
      80                 :             :                 }
      81                 :             :                 break;
      82                 :             :             }
      83                 :           0 :             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                 :             :                 }
      88                 :             :                 break;
      89                 :             :             }
      90                 :             :             case ThresholdState::FAILED:
      91                 :             :             case ThresholdState::ACTIVE: {
      92                 :             :                 // Nothing happens, these are terminal states.
      93                 :             :                 break;
      94                 :             :             }
      95                 :             :         }
      96         [ #  # ]:           0 :         cache[pindexPrev] = state = stateNext;
      97                 :             :     }
      98                 :             : 
      99                 :           0 :     return state;
     100                 :           0 : }
     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                 :             :     }
     118                 :             : 
     119                 :             :     // Count from current block to beginning of period
     120                 :             :     int elapsed = 0;
     121                 :             :     int count = 0;
     122                 :             :     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                 :             :         }
     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                 :             : }
     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                 :             :         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                 :             :         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                 :             : }
     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                 :           0 :     int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
     186                 :           0 :     int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
     187                 :           0 :     int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
     188                 :           0 :     int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
     189                 :           0 :     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                 :           0 :     explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
     198         [ #  # ]:           0 :     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                 :           0 : uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
     221                 :             : {
     222                 :           0 :     return VersionBitsConditionChecker(pos).Mask(params);
     223                 :             : }
     224                 :             : 
     225                 :           0 : int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
     226                 :             : {
     227                 :           0 :     LOCK(m_mutex);
     228                 :           0 :     int32_t nVersion = VERSIONBITS_TOP_BITS;
     229                 :             : 
     230         [ #  # ]:           0 :     for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
     231                 :           0 :         Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
     232         [ #  # ]:           0 :         ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     233         [ #  # ]:           0 :         if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
     234         [ #  # ]:           0 :             nVersion |= Mask(params, pos);
     235                 :             :         }
     236                 :             :     }
     237                 :             : 
     238         [ #  # ]:           0 :     return nVersion;
     239                 :           0 : }
     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                 :             :     }
     247                 :           1 : }
        

Generated by: LCOV version 2.0-1