Line data Source code
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 : 13 : #include <test/fuzz/FuzzedDataProvider.h> 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 { 23 : class TestConditionChecker : public AbstractThresholdConditionChecker 24 : { 25 : private: 26 : mutable ThresholdConditionCache m_cache; 27 0 : 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 0 : TestConditionChecker(int64_t begin, int64_t end, int period, int threshold, int min_activation_height, int bit) 38 0 : : m_begin{begin}, m_end{end}, m_period{period}, m_threshold{threshold}, m_min_activation_height{min_activation_height}, m_bit{bit} 39 0 : { 40 0 : assert(m_period > 0); 41 0 : assert(0 <= m_threshold && m_threshold <= m_period); 42 0 : assert(0 <= m_bit && m_bit < 32 && m_bit < VERSIONBITS_NUM_BITS); 43 0 : assert(0 <= m_min_activation_height); 44 0 : } 45 : 46 0 : bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override { return Condition(pindex->nVersion); } 47 0 : int64_t BeginTime(const Consensus::Params& params) const override { return m_begin; } 48 0 : int64_t EndTime(const Consensus::Params& params) const override { return m_end; } 49 0 : int Period(const Consensus::Params& params) const override { return m_period; } 50 0 : int Threshold(const Consensus::Params& params) const override { return m_threshold; } 51 0 : int MinActivationHeight(const Consensus::Params& params) const override { return m_min_activation_height; } 52 : 53 0 : ThresholdState GetStateFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateFor(pindexPrev, dummy_params, m_cache); } 54 0 : int GetStateSinceHeightFor(const CBlockIndex* pindexPrev) const { return AbstractThresholdConditionChecker::GetStateSinceHeightFor(pindexPrev, dummy_params, m_cache); } 55 0 : BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, std::vector<bool>* signals=nullptr) const { return AbstractThresholdConditionChecker::GetStateStatisticsFor(pindex, dummy_params, signals); } 56 : 57 0 : bool Condition(int32_t version) const 58 : { 59 0 : uint32_t mask = (uint32_t{1}) << m_bit; 60 0 : return (((version & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (version & mask) != 0); 61 : } 62 : 63 0 : bool Condition(const CBlockIndex* pindex) const { return Condition(pindex->nVersion); } 64 : }; 65 : 66 : /** Track blocks mined for test */ 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 2 : const int32_t m_no_signal; 75 : 76 : public: 77 0 : Blocks(uint32_t start_time, uint32_t interval, int32_t signal, int32_t no_signal) 78 0 : : m_start_time{start_time}, m_interval{interval}, m_signal{signal}, m_no_signal{no_signal} {} 79 : 80 0 : size_t size() const { return m_blocks.size(); } 81 : 82 0 : CBlockIndex* tip() const 83 : { 84 0 : return m_blocks.empty() ? nullptr : m_blocks.back().get(); 85 : } 86 : 87 0 : CBlockIndex* mine_block(bool signal) 88 : { 89 0 : CBlockHeader header; 90 0 : header.nVersion = signal ? m_signal : m_no_signal; 91 0 : header.nTime = m_start_time + m_blocks.size() * m_interval; 92 0 : header.nBits = 0x1d00ffff; 93 : 94 0 : auto current_block = std::make_unique<CBlockIndex>(header); 95 0 : current_block->pprev = tip(); 96 0 : current_block->nHeight = m_blocks.size(); 97 0 : current_block->BuildSkip(); 98 : 99 0 : return m_blocks.emplace_back(std::move(current_block)).get(); 100 0 : } 101 : }; 102 : 103 : std::unique_ptr<const CChainParams> g_params; 104 : 105 0 : void initialize() 106 : { 107 : // this is actually comparatively slow, so only do it once 108 0 : g_params = CreateChainParams(ArgsManager{}, ChainType::MAIN); 109 0 : assert(g_params != nullptr); 110 0 : } 111 : 112 : constexpr uint32_t MAX_START_TIME = 4102444800; // 2100-01-01 113 : 114 4 : FUZZ_TARGET(versionbits, .init = initialize) 115 : { 116 0 : const CChainParams& params = *g_params; 117 0 : const int64_t interval = params.GetConsensus().nPowTargetSpacing; 118 0 : assert(interval > 1); // need to be able to halve it 119 0 : assert(interval < std::numeric_limits<int32_t>::max()); 120 : 121 0 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); 122 : 123 : // making period/max_periods larger slows these tests down significantly 124 0 : const int period = 32; 125 0 : const size_t max_periods = 16; 126 0 : const size_t max_blocks = 2 * period * max_periods; 127 : 128 0 : const int threshold = fuzzed_data_provider.ConsumeIntegralInRange(1, period); 129 0 : 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 0 : assert(std::numeric_limits<uint32_t>::max() - MAX_START_TIME > interval * max_blocks); 134 : 135 0 : 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 0 : const int32_t ver_signal = fuzzed_data_provider.ConsumeIntegral<int32_t>(); 139 0 : const int32_t ver_nosignal = fuzzed_data_provider.ConsumeIntegral<int32_t>(); 140 : 141 : // select deployment parameters: bit, start time, timeout 142 0 : const int bit = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, VERSIONBITS_NUM_BITS - 1); 143 : 144 0 : bool always_active_test = false; 145 0 : bool never_active_test = false; 146 : int64_t start_time; 147 : int64_t timeout; 148 0 : 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 0 : int start_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3)); 152 0 : int end_block = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * (max_periods - 3)); 153 : 154 0 : start_time = block_start_time + start_block * interval; 155 0 : timeout = block_start_time + end_block * interval; 156 : 157 : // allow for times to not exactly match a block 158 0 : if (fuzzed_data_provider.ConsumeBool()) start_time += interval / 2; 159 0 : if (fuzzed_data_provider.ConsumeBool()) timeout += interval / 2; 160 0 : } else { 161 0 : if (fuzzed_data_provider.ConsumeBool()) { 162 0 : start_time = Consensus::BIP9Deployment::ALWAYS_ACTIVE; 163 0 : always_active_test = true; 164 0 : } else { 165 0 : start_time = Consensus::BIP9Deployment::NEVER_ACTIVE; 166 0 : never_active_test = true; 167 : } 168 0 : timeout = fuzzed_data_provider.ConsumeBool() ? Consensus::BIP9Deployment::NO_TIMEOUT : fuzzed_data_provider.ConsumeIntegral<int64_t>(); 169 : } 170 0 : int min_activation = fuzzed_data_provider.ConsumeIntegralInRange<int>(0, period * max_periods); 171 : 172 0 : 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 0 : if (!checker.Condition(ver_signal)) return; 176 0 : if (checker.Condition(ver_nosignal)) return; 177 0 : if (ver_nosignal < 0) return; 178 : 179 : // TOP_BITS should ensure version will be positive and meet min 180 : // version requirement 181 0 : assert(ver_signal > 0); 182 0 : assert(ver_signal >= VERSIONBITS_LAST_OLD_BLOCK_VERSION); 183 : 184 : // Now that we have chosen time and versions, setup to mine blocks 185 0 : 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 0 : const uint32_t signalling_mask = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); 201 : 202 : // mine prior periods 203 0 : 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 0 : bool signal = fuzzed_data_provider.ConsumeBool(); 206 0 : for (int b = 0; b < period; ++b) { 207 0 : blocks.mine_block(signal); 208 0 : } 209 : 210 : // don't risk exceeding max_blocks or times may wrap around 211 0 : 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 0 : int blocks_sig = 0; 219 : 220 : // get the info for the first block of the period 221 0 : CBlockIndex* prev = blocks.tip(); 222 0 : const int exp_since = checker.GetStateSinceHeightFor(prev); 223 0 : const ThresholdState exp_state = checker.GetStateFor(prev); 224 : 225 : // get statistics from end of previous period, then reset 226 : BIP9Stats last_stats; 227 0 : last_stats.period = period; 228 0 : last_stats.threshold = threshold; 229 0 : last_stats.count = last_stats.elapsed = 0; 230 0 : last_stats.possible = (period >= threshold); 231 0 : std::vector<bool> last_signals{}; 232 : 233 0 : int prev_next_height = (prev == nullptr ? 0 : prev->nHeight + 1); 234 0 : assert(exp_since <= prev_next_height); 235 : 236 : // mine (period-1) blocks and check state 237 0 : for (int b = 1; b < period; ++b) { 238 0 : const bool signal = (signalling_mask >> (b % 32)) & 1; 239 0 : if (signal) ++blocks_sig; 240 : 241 0 : CBlockIndex* current_block = blocks.mine_block(signal); 242 : 243 : // verify that signalling attempt was interpreted correctly 244 0 : assert(checker.Condition(current_block) == signal); 245 : 246 : // state and since don't change within the period 247 0 : const ThresholdState state = checker.GetStateFor(current_block); 248 0 : const int since = checker.GetStateSinceHeightFor(current_block); 249 0 : assert(state == exp_state); 250 0 : assert(since == exp_since); 251 : 252 : // check that after mining this block stats change as expected 253 0 : std::vector<bool> signals; 254 0 : const BIP9Stats stats = checker.GetStateStatisticsFor(current_block, &signals); 255 0 : const BIP9Stats stats_no_signals = checker.GetStateStatisticsFor(current_block); 256 0 : 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 0 : assert(stats.period == period); 261 0 : assert(stats.threshold == threshold); 262 0 : assert(stats.elapsed == b); 263 0 : assert(stats.count == last_stats.count + (signal ? 1 : 0)); 264 0 : assert(stats.possible == (stats.count + period >= stats.elapsed + threshold)); 265 0 : last_stats = stats; 266 : 267 0 : assert(signals.size() == last_signals.size() + 1); 268 0 : assert(signals.back() == signal); 269 0 : last_signals.push_back(signal); 270 0 : assert(signals == last_signals); 271 0 : } 272 : 273 0 : if (exp_state == ThresholdState::STARTED) { 274 : // double check that stats.possible is sane 275 0 : if (blocks_sig >= threshold - 1) assert(last_stats.possible); 276 0 : } 277 : 278 : // mine the final block 279 0 : bool signal = (signalling_mask >> (period % 32)) & 1; 280 0 : if (signal) ++blocks_sig; 281 0 : CBlockIndex* current_block = blocks.mine_block(signal); 282 0 : assert(checker.Condition(current_block) == signal); 283 : 284 0 : const BIP9Stats stats = checker.GetStateStatisticsFor(current_block); 285 0 : assert(stats.period == period); 286 0 : assert(stats.threshold == threshold); 287 0 : assert(stats.elapsed == period); 288 0 : assert(stats.count == blocks_sig); 289 0 : assert(stats.possible == (stats.count + period >= stats.elapsed + threshold)); 290 : 291 : // More interesting is whether the state changed. 292 0 : const ThresholdState state = checker.GetStateFor(current_block); 293 0 : const int since = checker.GetStateSinceHeightFor(current_block); 294 : 295 : // since is straightforward: 296 0 : assert(since % period == 0); 297 0 : assert(0 <= since && since <= current_block->nHeight + 1); 298 0 : if (state == exp_state) { 299 0 : assert(since == exp_since); 300 0 : } else { 301 0 : assert(since == current_block->nHeight + 1); 302 : } 303 : 304 : // state is where everything interesting is 305 0 : switch (state) { 306 : case ThresholdState::DEFINED: 307 0 : assert(since == 0); 308 0 : assert(exp_state == ThresholdState::DEFINED); 309 0 : assert(current_block->GetMedianTimePast() < checker.m_begin); 310 0 : break; 311 : case ThresholdState::STARTED: 312 0 : assert(current_block->GetMedianTimePast() >= checker.m_begin); 313 0 : if (exp_state == ThresholdState::STARTED) { 314 0 : assert(blocks_sig < threshold); 315 0 : assert(current_block->GetMedianTimePast() < checker.m_end); 316 0 : } else { 317 0 : assert(exp_state == ThresholdState::DEFINED); 318 : } 319 0 : break; 320 : case ThresholdState::LOCKED_IN: 321 0 : if (exp_state == ThresholdState::LOCKED_IN) { 322 0 : assert(current_block->nHeight + 1 < min_activation); 323 0 : } else { 324 0 : assert(exp_state == ThresholdState::STARTED); 325 0 : assert(blocks_sig >= threshold); 326 : } 327 0 : break; 328 : case ThresholdState::ACTIVE: 329 0 : assert(always_active_test || min_activation <= current_block->nHeight + 1); 330 0 : assert(exp_state == ThresholdState::ACTIVE || exp_state == ThresholdState::LOCKED_IN); 331 0 : break; 332 : case ThresholdState::FAILED: 333 0 : assert(never_active_test || current_block->GetMedianTimePast() >= checker.m_end); 334 0 : if (exp_state == ThresholdState::STARTED) { 335 0 : assert(blocks_sig < threshold); 336 0 : } else { 337 0 : assert(exp_state == ThresholdState::FAILED); 338 : } 339 0 : break; 340 : default: 341 0 : assert(false); 342 : } 343 : 344 0 : 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 346 0 : assert(state == ThresholdState::ACTIVE || state == ThresholdState::FAILED); 347 0 : } 348 : 349 0 : if (always_active_test) { 350 : // "always active" has additional restrictions 351 0 : assert(state == ThresholdState::ACTIVE); 352 0 : assert(exp_state == ThresholdState::ACTIVE); 353 0 : assert(since == 0); 354 0 : } else if (never_active_test) { 355 : // "never active" does too 356 0 : assert(state == ThresholdState::FAILED); 357 0 : assert(exp_state == ThresholdState::FAILED); 358 0 : assert(since == 0); 359 0 : } else { 360 : // for signalled deployments, the initial state is always DEFINED 361 0 : assert(since > 0 || state == ThresholdState::DEFINED); 362 0 : assert(exp_since > 0 || exp_state == ThresholdState::DEFINED); 363 : } 364 0 : } 365 : } // namespace