Bitcoin Core  27.99.0
P2P Digital Currency
versionbits.cpp
Go to the documentation of this file.
1 // Copyright (c) 2020-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 <chain.h>
6 #include <chainparams.h>
7 #include <common/args.h>
8 #include <consensus/params.h>
9 #include <primitives/block.h>
10 #include <util/chaintype.h>
11 #include <versionbits.h>
12 
14 #include <test/fuzz/fuzz.h>
15 #include <test/fuzz/util.h>
16 
17 #include <cstdint>
18 #include <limits>
19 #include <memory>
20 #include <vector>
21 
22 namespace {
24 {
25 private:
26  mutable ThresholdConditionCache m_cache;
27  const Consensus::Params dummy_params{};
28 
29 public:
30  const int64_t m_begin;
31  const int64_t m_end;
32  const int m_period;
33  const int m_threshold;
34  const int m_min_activation_height;
35  const int m_bit;
36 
37  TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int min_activation_height, int bit)
38  : m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_min_activation_height{min_activation_height}, m_bit{bit}
39  {
40  assert(m_period > 0);
41  assert(0 <= m_threshold && m_threshold <= m_period);
42  assert(0 <= m_bit && m_bit < 32 && m_bit < VERSIONBITS_NUM_BITS);
43  assert(0 <= m_min_activation_height);
44  }
45 
46  bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); }
47  int64_t BeginTime(const Consensus::Params& params) const override { return m_begin; }
48  int64_t EndTime(const Consensus::Params& params) const override { return m_end; }
49  int Period(const Consensus::Params& params) const override { return m_period; }
50  int Threshold(const Consensus::Params& params) const override { return m_threshold; }
51  int MinActivationHeight(const Consensus::Params& params) const override { return m_min_activation_height; }
52 
53  ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); }
54  int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); }
55  BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, std::vector<bool>* signals=nullptr) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindex, dummy_params, signals); }
56 
57  bool Condition(int32_t version) const
58  {
59  uint32_t mask = (uint32_t{1}) << m_bit;
60  return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0);
61  }
62 
63  bool Condition(const CBlockIndex* pindex) const { return Condition(pindex->nVersion); }
64 };
65 
67 class Blocks
68 {
69 private:
70  std::vector<std::unique_ptr<CBlockIndex>> m_blocks;
71  const uint32_t m_start_time;
72  const uint32_t m_interval;
73  const int32_t m_signal;
74  const int32_t m_no_signal;
75 
76 public:
77  Blocks(uint32_t start_time, uint32_t interval, int32_t signal, int32_t no_signal)
78  : m_start_time{start_time}, m_interval{interval}, m_signal{signal}, m_no_signal{no_signal} {}
79 
80  size_t size() const { return m_blocks.size(); }
81 
82  CBlockIndex* tip() const
83  {
84  return m_blocks.empty() ? nullptr : m_blocks.back().get();
85  }
86 
87  CBlockIndex* mine_block(bool signal)
88  {
89  CBlockHeader header;
90  header.nVersion = signal ? m_signal : m_no_signal;
91  header.nTime = m_start_time + m_blocks.size() * m_interval;
92  header.nBits = 0x1d00ffff;
93 
94  auto current_block = std::make_unique<CBlockIndex>(header);
95  current_block->pprev = tip();
96  current_block->nHeight = m_blocks.size();
97  current_block->BuildSkip();
98 
99  return m_blocks.emplace_back(std::move(current_block)).get();
100  }
101 };
102 
103 std::unique_ptr<const CChainParams> g_params;
104 
105 void initialize()
106 {
107  // this is actually comparatively slow, so only do it once
109  assert(g_params != nullptr);
110 }
111 
112 constexpr uint32_t MAX_START_TIME = 4102444800; // 2100-01-01
113 
114 FUZZ_TARGET(versionbits, .init = initialize)
115 {
116  const CChainParams& params = *g_params;
117  const int64_t interval = params.GetConsensus().nPowTargetSpacing;
118  assert(interval > 1); // need to be able to halve it
119  assert(interval < std::numeric_limits<int32_t>::max());
120 
121  FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size());
122 
123  // making period/max_periods larger slows these tests down significantly
124  const int period = 32;
125  const size_t max_periods = 16;
126  const size_t max_blocks = 2 * period * max_periods;
127 
128  const int threshold = fuzzed_data_provider.ConsumeIntegralInRange(1, period);
129  assert(0 < threshold && threshold <= period); // must be able to both pass and fail threshold!
130 
131  // too many blocks at 10min each might cause uint32_t time to overflow if
132  // block_start_time is at the end of the range above
133  assert(std::numeric_limits<uint32_t>::max() - MAX_START_TIME > interval * max_blocks);
134 
135  const int64_t block_start_time = fuzzed_data_provider.ConsumeIntegralInRange<uint32_t>(params.GenesisBlock().nTime, MAX_START_TIME);
136 
137  // what values for version will we use to signal / not signal?
138  const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
139  const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral<int32_t>();
140 
141  // select deployment parameters: bit, start time, timeout
142  const int bit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, VERSIONBITS_NUM_BITS - 1);
143 
144  bool always_active_test = false;
145  bool never_active_test = false;
146  int64_t start_time;
147  int64_t timeout;
148  if (fuzzed_data_provider.ConsumeBool()) {
149  // pick the timestamp to switch based on a block
150  // note states will change *after* these blocks because mediantime lags
151  int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
152  int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3));
153 
154  start_time = block_start_time + start_block * interval;
155  timeout = block_start_time + end_block * interval;
156 
157  // allow for times to not exactly match a block
158  if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2;
159  if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2;
160  } else {
161  if (fuzzed_data_provider.ConsumeBool()) {
163  always_active_test = true;
164  } else {
166  never_active_test = true;
167  }
168  timeout = fuzzed_data_provider.ConsumeBool() ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral<int64_t>();
169  }
170  int min_activation = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * max_periods);
171 
172  TestConditionChecker checker(start_time, timeout, period, threshold, min_activation, bit);
173 
174  // Early exit if the versions don't signal sensibly for the deployment
175  if (!checker.Condition(ver_signal)) return;
176  if (checker.Condition(ver_nosignal)) return;
177  if (ver_nosignal < 0) return;
178 
179  // TOP_BITS should ensure version will be positive and meet min
180  // version requirement
181  assert(ver_signal > 0);
183 
184  // Now that we have chosen time and versions, setup to mine blocks
185  Blocks blocks(block_start_time, interval, ver_signal, ver_nosignal);
186 
187  /* Strategy:
188  * * we will mine a final period worth of blocks, with
189  * randomised signalling according to a mask
190  * * but before we mine those blocks, we will mine some
191  * randomised number of prior periods; with either all
192  * or no blocks in the period signalling
193  *
194  * We establish the mask first, then consume "bools" until
195  * we run out of fuzz data to work out how many prior periods
196  * there are and which ones will signal.
197  */
198 
199  // establish the mask
200  const uint32_t signalling_mask = fuzzed_data_provider.ConsumeIntegral<uint32_t>();
201 
202  // mine prior periods
203  while (fuzzed_data_provider.remaining_bytes() > 0) { // early exit; no need for LIMITED_WHILE
204  // all blocks in these periods either do or don't signal
205  bool signal = fuzzed_data_provider.ConsumeBool();
206  for (int b = 0; b < period; ++b) {
207  blocks.mine_block(signal);
208  }
209 
210  // don't risk exceeding max_blocks or times may wrap around
211  if (blocks.size() + 2 * period > max_blocks) break;
212  }
213  // NOTE: fuzzed_data_provider may be fully consumed at this point and should not be used further
214 
215  // now we mine the final period and check that everything looks sane
216 
217  // count the number of signalling blocks
218  int blocks_sig = 0;
219 
220  // get the info for the first block of the period
221  CBlockIndex* prev = blocks.tip();
222  const int exp_since = checker.GetStateSinceHeightFor(prev);
223  const ThresholdState exp_state = checker.GetStateFor(prev);
224 
225  // get statistics from end of previous period, then reset
226  BIP9Stats last_stats;
227  last_stats.period = period;
228  last_stats.threshold = threshold;
229  last_stats.count = last_stats.elapsed = 0;
230  last_stats.possible = (period >= threshold);
231  std::vector<bool> last_signals{};
232 
233  int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1);
234  assert(exp_since <= prev_next_height);
235 
236  // mine (period-1) blocks and check state
237  for (int b = 1; b < period; ++b) {
238  const bool signal = (signalling_mask >> (b % 32)) & 1;
239  if (signal) ++blocks_sig;
240 
241  CBlockIndex* current_block = blocks.mine_block(signal);
242 
243  // verify that signalling attempt was interpreted correctly
244  assert(checker.Condition(current_block) == signal);
245 
246  // state and since don't change within the period
247  const ThresholdState state = checker.GetStateFor(current_block);
248  const int since = checker.GetStateSinceHeightFor(current_block);
249  assert(state == exp_state);
250  assert(since == exp_since);
251 
252  // check that after mining this block stats change as expected
253  std::vector<bool> signals;
254  const BIP9Stats stats = checker.GetStateStatisticsFor(current_block, &signals);
255  const BIP9Stats stats_no_signals = checker.GetStateStatisticsFor(current_block);
256  assert(stats.period == stats_no_signals.period && stats.threshold == stats_no_signals.threshold
257  && stats.elapsed == stats_no_signals.elapsed && stats.count == stats_no_signals.count
258  && stats.possible == stats_no_signals.possible);
259 
260  assert(stats.period == period);
261  assert(stats.threshold == threshold);
262  assert(stats.elapsed == b);
263  assert(stats.count == last_stats.count + (signal ? 1 : 0));
264  assert(stats.possible == (stats.count + period >= stats.elapsed + threshold));
265  last_stats = stats;
266 
267  assert(signals.size() == last_signals.size() + 1);
268  assert(signals.back() == signal);
269  last_signals.push_back(signal);
270  assert(signals == last_signals);
271  }
272 
273  if (exp_state == ThresholdState::STARTED) {
274  // double check that stats.possible is sane
275  if (blocks_sig >= threshold - 1) assert(last_stats.possible);
276  }
277 
278  // mine the final block
279  bool signal = (signalling_mask >> (period % 32)) & 1;
280  if (signal) ++blocks_sig;
281  CBlockIndex* current_block = blocks.mine_block(signal);
282  assert(checker.Condition(current_block) == signal);
283 
284  const BIP9Stats stats = checker.GetStateStatisticsFor(current_block);
285  assert(stats.period == period);
286  assert(stats.threshold == threshold);
287  assert(stats.elapsed == period);
288  assert(stats.count == blocks_sig);
289  assert(stats.possible == (stats.count + period >= stats.elapsed + threshold));
290 
291  // More interesting is whether the state changed.
292  const ThresholdState state = checker.GetStateFor(current_block);
293  const int since = checker.GetStateSinceHeightFor(current_block);
294 
295  // since is straightforward:
296  assert(since % period == 0);
297  assert(0 <= since && since <= current_block->nHeight + 1);
298  if (state == exp_state) {
299  assert(since == exp_since);
300  } else {
301  assert(since == current_block->nHeight + 1);
302  }
303 
304  // state is where everything interesting is
305  switch (state) {
307  assert(since == 0);
308  assert(exp_state == ThresholdState::DEFINED);
309  assert(current_block->GetMedianTimePast() < checker.m_begin);
310  break;
312  assert(current_block->GetMedianTimePast() >= checker.m_begin);
313  if (exp_state == ThresholdState::STARTED) {
314  assert(blocks_sig < threshold);
315  assert(current_block->GetMedianTimePast() < checker.m_end);
316  } else {
317  assert(exp_state == ThresholdState::DEFINED);
318  }
319  break;
321  if (exp_state == ThresholdState::LOCKED_IN) {
322  assert(current_block->nHeight + 1 < min_activation);
323  } else {
324  assert(exp_state == ThresholdState::STARTED);
325  assert(blocks_sig >= threshold);
326  }
327  break;
329  assert(always_active_test || min_activation <= current_block->nHeight + 1);
330  assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
331  break;
333  assert(never_active_test || current_block->GetMedianTimePast() >= checker.m_end);
334  if (exp_state == ThresholdState::STARTED) {
335  assert(blocks_sig < threshold);
336  } else {
337  assert(exp_state == ThresholdState::FAILED);
338  }
339  break;
340  default:
341  assert(false);
342  }
343 
344  if (blocks.size() >= period * max_periods) {
345  // we chose the timeout (and block times) so that by the time we have this many blocks it's all over
347  }
348 
349  if (always_active_test) {
350  // "always active" has additional restrictions
351  assert(state == ThresholdState::ACTIVE);
352  assert(exp_state == ThresholdState::ACTIVE);
353  assert(since == 0);
354  } else if (never_active_test) {
355  // "never active" does too
356  assert(state == ThresholdState::FAILED);
357  assert(exp_state == ThresholdState::FAILED);
358  assert(since == 0);
359  } else {
360  // for signalled deployments, the initial state is always DEFINED
361  assert(since > 0 || state == ThresholdState::DEFINED);
362  assert(exp_since > 0 || exp_state == ThresholdState::DEFINED);
363  }
364 }
365 } // namespace
std::unique_ptr< const CChainParams > CreateChainParams(const ArgsManager &args, const ChainType chain)
Creates and returns a std::unique_ptr<CChainParams> of the chosen chain.
Abstract class that implements BIP9-style threshold logic, and caches results.
Definition: versionbits.h:57
ThresholdState GetStateFor(const CBlockIndex *pindexPrev, const Consensus::Params &params, ThresholdConditionCache &cache) const
Returns the state for pindex A based on parent pindexPrev B.
Definition: versionbits.cpp:9
virtual int MinActivationHeight(const Consensus::Params &params) const
Definition: versionbits.h:62
int GetStateSinceHeightFor(const CBlockIndex *pindexPrev, const Consensus::Params &params, ThresholdConditionCache &cache) const
Returns the height since when the ThresholdState has started for pindex A based on parent pindexPrev ...
BIP9Stats GetStateStatisticsFor(const CBlockIndex *pindex, const Consensus::Params &params, std::vector< bool > *signalling_blocks=nullptr) const
Returns the numerical statistics of an in-progress BIP9 softfork in the period including pindex If pr...
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:22
uint32_t nBits
Definition: block.h:29
uint32_t nTime
Definition: block.h:28
int32_t nVersion
Definition: block.h:25
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: chain.h:141
int64_t GetMedianTimePast() const
Definition: chain.h:279
int32_t nVersion
block header
Definition: chain.h:188
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:153
CChainParams defines various tweakable parameters of a given instance of the Bitcoin system.
Definition: chainparams.h:81
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:93
const CBlock & GenesisBlock() const
Definition: chainparams.h:97
int Threshold(const Consensus::Params &params) const override
int Period(const Consensus::Params &params) const override
int64_t BeginTime(const Consensus::Params &params) const override
bool Condition(const CBlockIndex *pindex, const Consensus::Params &params) const override
ThresholdState GetStateFor(const CBlockIndex *pindexPrev) const
int64_t EndTime(const Consensus::Params &params) const override
int GetStateSinceHeightFor(const CBlockIndex *pindexPrev) const
void initialize()
Definition: fuzz.cpp:83
#define FUZZ_TARGET(...)
Definition: fuzz.h:36
unsigned int nHeight
Display status of an in-progress BIP9 softfork.
Definition: versionbits.h:41
int count
Number of blocks with the version bit set since the beginning of the current period.
Definition: versionbits.h:49
int elapsed
Number of blocks elapsed since the beginning of the current period.
Definition: versionbits.h:47
int threshold
Number of blocks with the version bit set required to activate the softfork.
Definition: versionbits.h:45
bool possible
False if there are not enough blocks left in this period to pass activation threshold.
Definition: versionbits.h:51
int period
Length of blocks of the BIP9 signalling period.
Definition: versionbits.h:43
static constexpr int64_t ALWAYS_ACTIVE
Special value for nStartTime indicating that the deployment is always active.
Definition: params.h:63
static constexpr int64_t NEVER_ACTIVE
Special value for nStartTime indicating that the deployment is never active.
Definition: params.h:68
static constexpr int64_t NO_TIMEOUT
Constant for nTimeout very far in the future.
Definition: params.h:57
Parameters that influence chain consensus.
Definition: params.h:74
int64_t nPowTargetSpacing
Definition: params.h:112
assert(!tx.IsCoinBase())
std::map< const CBlockIndex *, ThresholdState > ThresholdConditionCache
Definition: versionbits.h:38
static const int32_t VERSIONBITS_NUM_BITS
Total bits available for versionbits.
Definition: versionbits.h:20
static const int32_t VERSIONBITS_TOP_BITS
What bits to set in version for versionbits blocks.
Definition: versionbits.h:16
static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION
What block version to use for new blocks (pre versionbits)
Definition: versionbits.h:14
static const int32_t VERSIONBITS_TOP_MASK
What bitmask determines whether versionbits is in use.
Definition: versionbits.h:18
ThresholdState
BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
Definition: versionbits.h:27