LCOV - code coverage report
Current view: top level - src - versionbits.cpp (source / functions) Hit Total Coverage
Test: fuzz_coverage.info Lines: 61 136 44.9 %
Date: 2023-11-06 23:13:05 Functions: 11 17 64.7 %
Branches: 33 101 32.7 %

           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                 :        400 : ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
      10                 :            : {
      11                 :        400 :     int nPeriod = Period(params);
      12                 :        400 :     int nThreshold = Threshold(params);
      13                 :        400 :     int min_activation_height = MinActivationHeight(params);
      14                 :        400 :     int64_t nTimeStart = BeginTime(params);
      15                 :        400 :     int64_t nTimeTimeout = EndTime(params);
      16                 :            : 
      17                 :            :     // Check if this deployment is always active.
      18         [ +  + ]:        400 :     if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
      19                 :        200 :         return ThresholdState::ACTIVE;
      20                 :            :     }
      21                 :            : 
      22                 :            :     // Check if this deployment is never active.
      23         [ -  + ]:        200 :     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         [ -  + ]:        200 :     if (pindexPrev != nullptr) {
      29                 :        200 :         pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
      30                 :        200 :     }
      31                 :            : 
      32                 :            :     // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
      33                 :        200 :     std::vector<const CBlockIndex*> vToCompute;
      34 [ +  - ][ +  + ]:        201 :     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 [ +  - ][ -  + ]:        200 :     assert(cache.count(pindexPrev));
      51         [ +  - ]:        200 :     ThresholdState state = cache[pindexPrev];
      52                 :            : 
      53                 :            :     // Now walk forward and compute the state of descendants of pindexPrev
      54         [ +  + ]:        201 :     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                 :          0 :                     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                 :        200 :     return state;
     100                 :        400 : }
     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                 :        400 :     int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
     186                 :        400 :     int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
     187                 :        400 :     int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
     188                 :        400 :     int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
     189                 :        400 :     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                 :        457 :     explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
     198                 :         57 :     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                 :         57 : uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
     221                 :            : {
     222                 :         57 :     return VersionBitsConditionChecker(pos).Mask(params);
     223                 :            : }
     224                 :            : 
     225                 :        200 : int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
     226                 :            : {
     227                 :        200 :     LOCK(m_mutex);
     228                 :        200 :     int32_t nVersion = VERSIONBITS_TOP_BITS;
     229                 :            : 
     230         [ +  + ]:        600 :     for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
     231                 :        400 :         Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
     232 [ +  - ][ +  - ]:        400 :         ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
     233 [ +  - ][ +  + ]:        400 :         if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
     234         [ +  - ]:         57 :             nVersion |= Mask(params, pos);
     235                 :         57 :         }
     236                 :        400 :     }
     237                 :            : 
     238                 :        200 :     return nVersion;
     239                 :        200 : }
     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