Line data Source code
1 : // Copyright (c) 2020-2022 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 <pow.h> 8 : #include <primitives/block.h> 9 : #include <test/fuzz/FuzzedDataProvider.h> 10 : #include <test/fuzz/fuzz.h> 11 : #include <test/fuzz/util.h> 12 : #include <util/chaintype.h> 13 : #include <util/check.h> 14 : #include <util/overflow.h> 15 : 16 : #include <cstdint> 17 : #include <optional> 18 : #include <string> 19 : #include <vector> 20 : 21 0 : void initialize_pow() 22 : { 23 0 : SelectParams(ChainType::MAIN); 24 0 : } 25 : 26 4 : FUZZ_TARGET(pow, .init = initialize_pow) 27 : { 28 0 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); 29 0 : const Consensus::Params& consensus_params = Params().GetConsensus(); 30 0 : std::vector<std::unique_ptr<CBlockIndex>> blocks; 31 0 : const uint32_t fixed_time = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); 32 0 : const uint32_t fixed_bits = fuzzed_data_provider.ConsumeIntegral<uint32_t>(); 33 0 : LIMITED_WHILE(fuzzed_data_provider.remaining_bytes() > 0, 10000) { 34 0 : const std::optional<CBlockHeader> block_header = ConsumeDeserializable<CBlockHeader>(fuzzed_data_provider); 35 0 : if (!block_header) { 36 0 : continue; 37 : } 38 0 : CBlockIndex& current_block{ 39 0 : *blocks.emplace_back(std::make_unique<CBlockIndex>(*block_header))}; 40 : { 41 0 : CBlockIndex* previous_block = blocks.empty() ? nullptr : PickValue(fuzzed_data_provider, blocks).get(); 42 0 : const int current_height = (previous_block != nullptr && previous_block->nHeight != std::numeric_limits<int>::max()) ? previous_block->nHeight + 1 : 0; 43 0 : if (fuzzed_data_provider.ConsumeBool()) { 44 0 : current_block.pprev = previous_block; 45 0 : } 46 0 : if (fuzzed_data_provider.ConsumeBool()) { 47 0 : current_block.nHeight = current_height; 48 0 : } 49 0 : if (fuzzed_data_provider.ConsumeBool()) { 50 0 : const uint32_t seconds = current_height * consensus_params.nPowTargetSpacing; 51 0 : if (!AdditionOverflow(fixed_time, seconds)) { 52 0 : current_block.nTime = fixed_time + seconds; 53 0 : } 54 0 : } 55 0 : if (fuzzed_data_provider.ConsumeBool()) { 56 0 : current_block.nBits = fixed_bits; 57 0 : } 58 0 : if (fuzzed_data_provider.ConsumeBool()) { 59 0 : current_block.nChainWork = previous_block != nullptr ? previous_block->nChainWork + GetBlockProof(*previous_block) : arith_uint256{0}; 60 0 : } else { 61 0 : current_block.nChainWork = ConsumeArithUInt256(fuzzed_data_provider); 62 : } 63 : } 64 : { 65 0 : (void)GetBlockProof(current_block); 66 0 : (void)CalculateNextWorkRequired(¤t_block, fuzzed_data_provider.ConsumeIntegralInRange<int64_t>(0, std::numeric_limits<int64_t>::max()), consensus_params); 67 0 : if (current_block.nHeight != std::numeric_limits<int>::max() && current_block.nHeight - (consensus_params.DifficultyAdjustmentInterval() - 1) >= 0) { 68 0 : (void)GetNextWorkRequired(¤t_block, &(*block_header), consensus_params); 69 0 : } 70 : } 71 : { 72 0 : const auto& to = PickValue(fuzzed_data_provider, blocks); 73 0 : const auto& from = PickValue(fuzzed_data_provider, blocks); 74 2 : const auto& tip = PickValue(fuzzed_data_provider, blocks); 75 : try { 76 0 : (void)GetBlockProofEquivalentTime(*to, *from, *tip, consensus_params); 77 0 : } catch (const uint_error&) { 78 0 : } 79 : } 80 : { 81 0 : const std::optional<uint256> hash = ConsumeDeserializable<uint256>(fuzzed_data_provider); 82 0 : if (hash) { 83 0 : (void)CheckProofOfWork(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params); 84 0 : } 85 : } 86 0 : } 87 0 : } 88 : 89 : 90 4 : FUZZ_TARGET(pow_transition, .init = initialize_pow) 91 : { 92 0 : FuzzedDataProvider fuzzed_data_provider(buffer.data(), buffer.size()); 93 0 : const Consensus::Params& consensus_params{Params().GetConsensus()}; 94 0 : std::vector<std::unique_ptr<CBlockIndex>> blocks; 95 : 96 0 : const uint32_t old_time{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; 97 0 : const uint32_t new_time{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; 98 0 : const int32_t version{fuzzed_data_provider.ConsumeIntegral<int32_t>()}; 99 0 : uint32_t nbits{fuzzed_data_provider.ConsumeIntegral<uint32_t>()}; 100 : 101 0 : const arith_uint256 pow_limit = UintToArith256(consensus_params.powLimit); 102 0 : arith_uint256 old_target; 103 0 : old_target.SetCompact(nbits); 104 0 : if (old_target > pow_limit) { 105 0 : nbits = pow_limit.GetCompact(); 106 0 : } 107 : // Create one difficulty adjustment period worth of headers 108 0 : for (int height = 0; height < consensus_params.DifficultyAdjustmentInterval(); ++height) { 109 0 : CBlockHeader header; 110 0 : header.nVersion = version; 111 0 : header.nTime = old_time; 112 0 : header.nBits = nbits; 113 0 : if (height == consensus_params.DifficultyAdjustmentInterval() - 1) { 114 0 : header.nTime = new_time; 115 0 : } 116 0 : auto current_block{std::make_unique<CBlockIndex>(header)}; 117 0 : current_block->pprev = blocks.empty() ? nullptr : blocks.back().get(); 118 0 : current_block->nHeight = height; 119 0 : blocks.emplace_back(std::move(current_block)); 120 0 : } 121 0 : auto last_block{blocks.back().get()}; 122 0 : unsigned int new_nbits{GetNextWorkRequired(last_block, nullptr, consensus_params)}; 123 0 : Assert(PermittedDifficultyTransition(consensus_params, last_block->nHeight + 1, last_block->nBits, new_nbits)); 124 0 : }