Branch data 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 : }