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