/ src / versionbits.cpp
versionbits.cpp
  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  ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
 10  {
 11      int nPeriod = Period(params);
 12      int nThreshold = Threshold(params);
 13      int min_activation_height = MinActivationHeight(params);
 14      int64_t nTimeStart = BeginTime(params);
 15      int64_t nTimeTimeout = EndTime(params);
 16  
 17      // Check if this deployment is always active.
 18      if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
 19          return ThresholdState::ACTIVE;
 20      }
 21  
 22      // Check if this deployment is never active.
 23      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      if (pindexPrev != nullptr) {
 29          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      std::vector<const CBlockIndex*> vToCompute;
 34      while (cache.count(pindexPrev) == 0) {
 35          if (pindexPrev == nullptr) {
 36              // The genesis block is by definition defined.
 37              cache[pindexPrev] = ThresholdState::DEFINED;
 38              break;
 39          }
 40          if (pindexPrev->GetMedianTimePast() < nTimeStart) {
 41              // Optimization: don't recompute down further, as we know every earlier block will be before the start time
 42              cache[pindexPrev] = ThresholdState::DEFINED;
 43              break;
 44          }
 45          vToCompute.push_back(pindexPrev);
 46          pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
 47      }
 48  
 49      // At this point, cache[pindexPrev] is known
 50      assert(cache.count(pindexPrev));
 51      ThresholdState state = cache[pindexPrev];
 52  
 53      // Now walk forward and compute the state of descendants of pindexPrev
 54      while (!vToCompute.empty()) {
 55          ThresholdState stateNext = state;
 56          pindexPrev = vToCompute.back();
 57          vToCompute.pop_back();
 58  
 59          switch (state) {
 60              case ThresholdState::DEFINED: {
 61                  if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
 62                      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                  for (int i = 0; i < nPeriod; i++) {
 71                      if (Condition(pindexCount, params)) {
 72                          count++;
 73                      }
 74                      pindexCount = pindexCount->pprev;
 75                  }
 76                  if (count >= nThreshold) {
 77                      stateNext = ThresholdState::LOCKED_IN;
 78                  } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
 79                      stateNext = ThresholdState::FAILED;
 80                  }
 81                  break;
 82              }
 83              case ThresholdState::LOCKED_IN: {
 84                  // Progresses into ACTIVE provided activation height will have been reached.
 85                  if (pindexPrev->nHeight + 1 >= min_activation_height) {
 86                      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          cache[pindexPrev] = state = stateNext;
 97      }
 98  
 99      return state;
100  }
101  
102  BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks) const
103  {
104      BIP9Stats stats = {};
105  
106      stats.period = Period(params);
107      stats.threshold = Threshold(params);
108  
109      if (pindex == nullptr) return stats;
110  
111      // Find how many blocks are in the current period
112      int blocks_in_period = 1 + (pindex->nHeight % stats.period);
113  
114      // Reset signalling_blocks
115      if (signalling_blocks) {
116          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      do {
124          ++elapsed;
125          --blocks_in_period;
126          if (Condition(currentIndex, params)) {
127              ++count;
128              if (signalling_blocks) signalling_blocks->at(blocks_in_period) = true;
129          }
130          currentIndex = currentIndex->pprev;
131      } while(blocks_in_period > 0);
132  
133      stats.elapsed = elapsed;
134      stats.count = count;
135      stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
136  
137      return stats;
138  }
139  
140  int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
141  {
142      int64_t start_time = BeginTime(params);
143      if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
144          return 0;
145      }
146  
147      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      if (initialState == ThresholdState::DEFINED) {
151          return 0;
152      }
153  
154      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      pindexPrev = Assert(pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod)));
163  
164      const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
165  
166      while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
167          pindexPrev = previousPeriodParent;
168          previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
169      }
170  
171      // Adjust the result because right now we point to the parent block.
172      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      int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
186      int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
187      int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
188      int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
189      int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
190  
191      bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
192      {
193          return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
194      }
195  
196  public:
197      explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
198      uint32_t Mask(const Consensus::Params& params) const { return (uint32_t{1}) << params.vDeployments[id].bit; }
199  };
200  
201  } // namespace
202  
203  ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
204  {
205      LOCK(m_mutex);
206      return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
207  }
208  
209  BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks)
210  {
211      return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindex, params, signalling_blocks);
212  }
213  
214  int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
215  {
216      LOCK(m_mutex);
217      return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, m_caches[pos]);
218  }
219  
220  uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
221  {
222      return VersionBitsConditionChecker(pos).Mask(params);
223  }
224  
225  int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
226  {
227      LOCK(m_mutex);
228      int32_t nVersion = VERSIONBITS_TOP_BITS;
229  
230      for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
231          Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
232          ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
233          if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
234              nVersion |= Mask(params, pos);
235          }
236      }
237  
238      return nVersion;
239  }
240  
241  void VersionBitsCache::Clear()
242  {
243      LOCK(m_mutex);
244      for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
245          m_caches[d].clear();
246      }
247  }