21
21
#include < vector>
22
22
23
23
namespace {
24
- class TestConditionChecker : public AbstractThresholdConditionChecker
24
+ class TestConditionChecker : public VersionBitsConditionChecker
25
25
{
26
26
private:
27
27
mutable ThresholdConditionCache m_cache;
28
28
29
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}
30
+ TestConditionChecker (const Consensus::BIP9Deployment& dep) : VersionBitsConditionChecker{dep}
39
31
{
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 );
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 );
44
36
}
45
37
46
- bool Condition (const CBlockIndex* pindex) const override { return Condition (pindex->nVersion ); }
47
- int64_t BeginTime () const override { return m_begin; }
48
- int64_t EndTime () const override { return m_end; }
49
- int Period () const override { return m_period; }
50
- int Threshold () const override { return m_threshold; }
51
- int MinActivationHeight () const override { return m_min_activation_height; }
52
-
53
38
ThresholdState GetStateFor (const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor (pindexPrev, m_cache); }
54
39
int GetStateSinceHeightFor (const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor (pindexPrev, m_cache); }
55
-
56
- bool Condition (int32_t version) const
57
- {
58
- uint32_t mask = (uint32_t {1 }) << m_bit;
59
- return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0 );
60
- }
61
40
};
62
41
63
42
/* * Track blocks mined for test */
@@ -122,9 +101,6 @@ FUZZ_TARGET(versionbits, .init = initialize)
122
101
const size_t max_periods = 16 ;
123
102
const size_t max_blocks = 2 * period * max_periods;
124
103
125
- const uint32_t threshold = fuzzed_data_provider.ConsumeIntegralInRange <uint32_t >(1 , period);
126
- assert (0 < threshold && threshold <= period); // must be able to both pass and fail threshold!
127
-
128
104
// too many blocks at 10min each might cause uint32_t time to overflow if
129
105
// block_start_time is at the end of the range above
130
106
assert (std::numeric_limits<uint32_t >::max () - MAX_START_TIME > interval * max_blocks);
@@ -134,53 +110,57 @@ FUZZ_TARGET(versionbits, .init = initialize)
134
110
// what values for version will we use to signal / not signal?
135
111
const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral <int32_t >();
136
112
const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral <int32_t >();
113
+ if (ver_nosignal < 0 ) return ; // negative values are uninteresting
137
114
138
- // select deployment parameters: bit, start time, timeout
139
- const int bit = fuzzed_data_provider.ConsumeIntegralInRange <int >(0 , VERSIONBITS_NUM_BITS - 1 );
140
-
141
- bool always_active_test = false ;
142
- bool never_active_test = false ;
143
- int64_t start_time;
144
- int64_t timeout;
145
- if (fuzzed_data_provider.ConsumeBool ()) {
146
- // pick the timestamp to switch based on a block
147
- // note states will change *after* these blocks because mediantime lags
148
- int start_block = fuzzed_data_provider.ConsumeIntegralInRange <int >(0 , period * (max_periods - 3 ));
149
- int end_block = fuzzed_data_provider.ConsumeIntegralInRange <int >(0 , period * (max_periods - 3 ));
150
-
151
- start_time = block_start_time + start_block * interval;
152
- timeout = block_start_time + end_block * interval;
153
-
154
- // allow for times to not exactly match a block
155
- if (fuzzed_data_provider.ConsumeBool ()) start_time += interval / 2 ;
156
- if (fuzzed_data_provider.ConsumeBool ()) timeout += interval / 2 ;
157
- } else {
158
- if (fuzzed_data_provider.ConsumeBool ()) {
159
- start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
160
- always_active_test = true ;
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{[&]() {
122
+ 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
129
+ dep.bit = fuzzed_data_provider.ConsumeIntegralInRange <int >(0 , VERSIONBITS_NUM_BITS - 1 );
130
+
131
+ if (always_active_test) {
132
+ dep.nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
133
+ dep.nTimeout = fuzzed_data_provider.ConsumeBool () ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral <int64_t >();
134
+ } else if (never_active_test) {
135
+ dep.nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
136
+ dep.nTimeout = fuzzed_data_provider.ConsumeBool () ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral <int64_t >();
161
137
} else {
162
- start_time = Consensus::BIP9Deployment::NEVER_ACTIVE;
163
- never_active_test = true ;
164
- }
165
- timeout = fuzzed_data_provider.ConsumeBool () ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral <int64_t >();
166
- }
167
- int min_activation = fuzzed_data_provider.ConsumeIntegralInRange <int >(0 , period * max_periods);
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 ));
168
142
169
- TestConditionChecker checker (start_time, timeout, period, threshold, min_activation, bit);
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);
170
154
171
155
// Early exit if the versions don't signal sensibly for the deployment
172
156
if (!checker.Condition (ver_signal)) return ;
173
157
if (checker.Condition (ver_nosignal)) return ;
174
- if (ver_nosignal < 0 ) return ;
175
158
176
159
// TOP_BITS should ensure version will be positive and meet min
177
160
// version requirement
178
161
assert (ver_signal > 0 );
179
162
assert (ver_signal >= VERSIONBITS_LAST_OLD_BLOCK_VERSION);
180
163
181
- // Now that we have chosen time and versions, setup to mine blocks
182
- Blocks blocks (block_start_time, interval, ver_signal, ver_nosignal);
183
-
184
164
/* Strategy:
185
165
* * we will mine a final period worth of blocks, with
186
166
* randomised signalling according to a mask
@@ -222,9 +202,9 @@ FUZZ_TARGET(versionbits, .init = initialize)
222
202
// get statistics from end of previous period, then reset
223
203
BIP9Stats last_stats;
224
204
last_stats.period = period;
225
- last_stats.threshold = threshold;
205
+ last_stats.threshold = dep. threshold ;
226
206
last_stats.count = last_stats.elapsed = 0 ;
227
- last_stats.possible = (period >= threshold);
207
+ last_stats.possible = (period >= dep. threshold );
228
208
std::vector<bool > last_signals{};
229
209
230
210
int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1 );
@@ -238,7 +218,7 @@ FUZZ_TARGET(versionbits, .init = initialize)
238
218
CBlockIndex* current_block = blocks.mine_block (signal);
239
219
240
220
// verify that signalling attempt was interpreted correctly
241
- assert (checker.Condition (current_block) == signal);
221
+ assert (checker.Condition (current_block-> nVersion ) == signal);
242
222
243
223
// state and since don't change within the period
244
224
const ThresholdState state = checker.GetStateFor (current_block);
@@ -255,10 +235,10 @@ FUZZ_TARGET(versionbits, .init = initialize)
255
235
&& stats.possible == stats_no_signals.possible );
256
236
257
237
assert (stats.period == period);
258
- assert (stats.threshold == threshold);
238
+ assert (stats.threshold == dep. threshold );
259
239
assert (stats.elapsed == b);
260
240
assert (stats.count == last_stats.count + (signal ? 1 : 0 ));
261
- assert (stats.possible == (stats.count + period >= stats.elapsed + threshold));
241
+ assert (stats.possible == (stats.count + period >= stats.elapsed + dep. threshold ));
262
242
last_stats = stats;
263
243
264
244
assert (signals.size () == last_signals.size () + 1 );
@@ -269,21 +249,21 @@ FUZZ_TARGET(versionbits, .init = initialize)
269
249
270
250
if (exp_state == ThresholdState::STARTED) {
271
251
// double check that stats.possible is sane
272
- if (blocks_sig >= threshold - 1 ) assert (last_stats.possible );
252
+ if (blocks_sig >= dep. threshold - 1 ) assert (last_stats.possible );
273
253
}
274
254
275
255
// mine the final block
276
256
bool signal = (signalling_mask >> (period % 32 )) & 1 ;
277
257
if (signal) ++blocks_sig;
278
258
CBlockIndex* current_block = blocks.mine_block (signal);
279
- assert (checker.Condition (current_block) == signal);
259
+ assert (checker.Condition (current_block-> nVersion ) == signal);
280
260
281
261
const BIP9Stats stats = checker.GetStateStatisticsFor (current_block);
282
262
assert (stats.period == period);
283
- assert (stats.threshold == threshold);
263
+ assert (stats.threshold == dep. threshold );
284
264
assert (stats.elapsed == period);
285
265
assert (stats.count == blocks_sig);
286
- assert (stats.possible == (stats.count + period >= stats.elapsed + threshold));
266
+ assert (stats.possible == (stats.count + period >= stats.elapsed + dep. threshold ));
287
267
288
268
// More interesting is whether the state changed.
289
269
const ThresholdState state = checker.GetStateFor (current_block);
@@ -303,33 +283,33 @@ FUZZ_TARGET(versionbits, .init = initialize)
303
283
case ThresholdState::DEFINED:
304
284
assert (since == 0 );
305
285
assert (exp_state == ThresholdState::DEFINED);
306
- assert (current_block->GetMedianTimePast () < checker. m_begin );
286
+ assert (current_block->GetMedianTimePast () < dep. nStartTime );
307
287
break ;
308
288
case ThresholdState::STARTED:
309
- assert (current_block->GetMedianTimePast () >= checker. m_begin );
289
+ assert (current_block->GetMedianTimePast () >= dep. nStartTime );
310
290
if (exp_state == ThresholdState::STARTED) {
311
- assert (blocks_sig < threshold);
312
- assert (current_block->GetMedianTimePast () < checker. m_end );
291
+ assert (blocks_sig < dep. threshold );
292
+ assert (current_block->GetMedianTimePast () < dep. nTimeout );
313
293
} else {
314
294
assert (exp_state == ThresholdState::DEFINED);
315
295
}
316
296
break ;
317
297
case ThresholdState::LOCKED_IN:
318
298
if (exp_state == ThresholdState::LOCKED_IN) {
319
- assert (current_block->nHeight + 1 < min_activation );
299
+ assert (current_block->nHeight + 1 < dep. min_activation_height );
320
300
} else {
321
301
assert (exp_state == ThresholdState::STARTED);
322
- assert (blocks_sig >= threshold);
302
+ assert (blocks_sig >= dep. threshold );
323
303
}
324
304
break ;
325
305
case ThresholdState::ACTIVE:
326
- assert (always_active_test || min_activation <= current_block->nHeight + 1 );
306
+ assert (always_active_test || dep. min_activation_height <= current_block->nHeight + 1 );
327
307
assert (exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
328
308
break ;
329
309
case ThresholdState::FAILED:
330
- assert (never_active_test || current_block->GetMedianTimePast () >= checker. m_end );
310
+ assert (never_active_test || current_block->GetMedianTimePast () >= dep. nTimeout );
331
311
if (exp_state == ThresholdState::STARTED) {
332
- assert (blocks_sig < threshold);
312
+ assert (blocks_sig < dep. threshold );
333
313
} else {
334
314
assert (exp_state == ThresholdState::FAILED);
335
315
}
0 commit comments