/root/bitcoin/src/test/fuzz/pow.cpp
| Line | Count | Source | 
| 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 |  | void initialize_pow() | 
| 22 | 0 | { | 
| 23 | 0 |     SelectParams(ChainType::MAIN); | 
| 24 | 0 | } | 
| 25 |  |  | 
| 26 |  | FUZZ_TARGET(pow, .init = initialize_pow) | 
| 27 | 0 | { | 
| 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 | 0 |         } | 
| 38 | 0 |         CBlockIndex& current_block{ | 
| 39 | 0 |             *blocks.emplace_back(std::make_unique<CBlockIndex>(*block_header))}; | 
| 40 | 0 |         { | 
| 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 | 0 |             } | 
| 63 | 0 |         } | 
| 64 | 0 |         { | 
| 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 | 0 |         } | 
| 71 | 0 |         { | 
| 72 | 0 |             const auto& to = PickValue(fuzzed_data_provider, blocks); | 
| 73 | 0 |             const auto& from = PickValue(fuzzed_data_provider, blocks); | 
| 74 | 0 |             const auto& tip = PickValue(fuzzed_data_provider, blocks); | 
| 75 | 0 |             try { | 
| 76 | 0 |                 (void)GetBlockProofEquivalentTime(*to, *from, *tip, consensus_params); | 
| 77 | 0 |             } catch (const uint_error&) { | 
| 78 | 0 |             } | 
| 79 | 0 |         } | 
| 80 | 0 |         { | 
| 81 | 0 |             const std::optional<uint256> hash = ConsumeDeserializable<uint256>(fuzzed_data_provider); | 
| 82 | 0 |             if (hash) { | 
| 83 | 0 |                 (void)CheckProofOfWorkImpl(*hash, fuzzed_data_provider.ConsumeIntegral<unsigned int>(), consensus_params); | 
| 84 | 0 |             } | 
| 85 | 0 |         } | 
| 86 | 0 |     } | 
| 87 | 0 | } | 
| 88 |  |  | 
| 89 |  |  | 
| 90 |  | FUZZ_TARGET(pow_transition, .init = initialize_pow) | 
| 91 | 0 | { | 
| 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 | } |