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