2121#include < vector>
2222
2323namespace {
24- class TestConditionChecker : public AbstractThresholdConditionChecker
24+ class TestConditionChecker : public VersionBitsConditionChecker
2525{
2626private:
2727 mutable ThresholdConditionCache m_cache;
2828
2929public:
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}
3931 {
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 );
4436 }
4537
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-
5338 ThresholdState GetStateFor (const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor (pindexPrev, m_cache); }
5439 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- }
6140};
6241
6342/* * Track blocks mined for test */
@@ -122,9 +101,6 @@ FUZZ_TARGET(versionbits, .init = initialize)
122101 const size_t max_periods = 16 ;
123102 const size_t max_blocks = 2 * period * max_periods;
124103
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-
128104 // too many blocks at 10min each might cause uint32_t time to overflow if
129105 // block_start_time is at the end of the range above
130106 assert (std::numeric_limits<uint32_t >::max () - MAX_START_TIME > interval * max_blocks);
@@ -134,53 +110,57 @@ FUZZ_TARGET(versionbits, .init = initialize)
134110 // what values for version will we use to signal / not signal?
135111 const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral <int32_t >();
136112 const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral <int32_t >();
113+ if (ver_nosignal < 0 ) return ; // negative values are uninteresting
137114
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 >();
161137 } 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 ));
168142
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);
170154
171155 // Early exit if the versions don't signal sensibly for the deployment
172156 if (!checker.Condition (ver_signal)) return ;
173157 if (checker.Condition (ver_nosignal)) return ;
174- if (ver_nosignal < 0 ) return ;
175158
176159 // TOP_BITS should ensure version will be positive and meet min
177160 // version requirement
178161 assert (ver_signal > 0 );
179162 assert (ver_signal >= VERSIONBITS_LAST_OLD_BLOCK_VERSION);
180163
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-
184164 /* Strategy:
185165 * * we will mine a final period worth of blocks, with
186166 * randomised signalling according to a mask
@@ -222,9 +202,9 @@ FUZZ_TARGET(versionbits, .init = initialize)
222202 // get statistics from end of previous period, then reset
223203 BIP9Stats last_stats;
224204 last_stats.period = period;
225- last_stats.threshold = threshold;
205+ last_stats.threshold = dep. threshold ;
226206 last_stats.count = last_stats.elapsed = 0 ;
227- last_stats.possible = (period >= threshold);
207+ last_stats.possible = (period >= dep. threshold );
228208 std::vector<bool > last_signals{};
229209
230210 int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1 );
@@ -238,7 +218,7 @@ FUZZ_TARGET(versionbits, .init = initialize)
238218 CBlockIndex* current_block = blocks.mine_block (signal);
239219
240220 // verify that signalling attempt was interpreted correctly
241- assert (checker.Condition (current_block) == signal);
221+ assert (checker.Condition (current_block-> nVersion ) == signal);
242222
243223 // state and since don't change within the period
244224 const ThresholdState state = checker.GetStateFor (current_block);
@@ -255,10 +235,10 @@ FUZZ_TARGET(versionbits, .init = initialize)
255235 && stats.possible == stats_no_signals.possible );
256236
257237 assert (stats.period == period);
258- assert (stats.threshold == threshold);
238+ assert (stats.threshold == dep. threshold );
259239 assert (stats.elapsed == b);
260240 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 ));
262242 last_stats = stats;
263243
264244 assert (signals.size () == last_signals.size () + 1 );
@@ -269,21 +249,21 @@ FUZZ_TARGET(versionbits, .init = initialize)
269249
270250 if (exp_state == ThresholdState::STARTED) {
271251 // 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 );
273253 }
274254
275255 // mine the final block
276256 bool signal = (signalling_mask >> (period % 32 )) & 1 ;
277257 if (signal) ++blocks_sig;
278258 CBlockIndex* current_block = blocks.mine_block (signal);
279- assert (checker.Condition (current_block) == signal);
259+ assert (checker.Condition (current_block-> nVersion ) == signal);
280260
281261 const BIP9Stats stats = checker.GetStateStatisticsFor (current_block);
282262 assert (stats.period == period);
283- assert (stats.threshold == threshold);
263+ assert (stats.threshold == dep. threshold );
284264 assert (stats.elapsed == period);
285265 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 ));
287267
288268 // More interesting is whether the state changed.
289269 const ThresholdState state = checker.GetStateFor (current_block);
@@ -303,33 +283,33 @@ FUZZ_TARGET(versionbits, .init = initialize)
303283 case ThresholdState::DEFINED:
304284 assert (since == 0 );
305285 assert (exp_state == ThresholdState::DEFINED);
306- assert (current_block->GetMedianTimePast () < checker. m_begin );
286+ assert (current_block->GetMedianTimePast () < dep. nStartTime );
307287 break ;
308288 case ThresholdState::STARTED:
309- assert (current_block->GetMedianTimePast () >= checker. m_begin );
289+ assert (current_block->GetMedianTimePast () >= dep. nStartTime );
310290 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 );
313293 } else {
314294 assert (exp_state == ThresholdState::DEFINED);
315295 }
316296 break ;
317297 case ThresholdState::LOCKED_IN:
318298 if (exp_state == ThresholdState::LOCKED_IN) {
319- assert (current_block->nHeight + 1 < min_activation );
299+ assert (current_block->nHeight + 1 < dep. min_activation_height );
320300 } else {
321301 assert (exp_state == ThresholdState::STARTED);
322- assert (blocks_sig >= threshold);
302+ assert (blocks_sig >= dep. threshold );
323303 }
324304 break ;
325305 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 );
327307 assert (exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN);
328308 break ;
329309 case ThresholdState::FAILED:
330- assert (never_active_test || current_block->GetMedianTimePast () >= checker. m_end );
310+ assert (never_active_test || current_block->GetMedianTimePast () >= dep. nTimeout );
331311 if (exp_state == ThresholdState::STARTED) {
332- assert (blocks_sig < threshold);
312+ assert (blocks_sig < dep. threshold );
333313 } else {
334314 assert (exp_state == ThresholdState::FAILED);
335315 }
0 commit comments