Branch data Line data Source code
1 : : #include <blockencodings.h> 2 : : #include <consensus/merkle.h> 3 : : #include <consensus/validation.h> 4 : : #include <primitives/block.h> 5 : : #include <primitives/transaction.h> 6 : : #include <test/fuzz/FuzzedDataProvider.h> 7 : : #include <test/fuzz/fuzz.h> 8 : : #include <test/fuzz/util.h> 9 : : #include <test/fuzz/util/mempool.h> 10 : : #include <test/util/setup_common.h> 11 : : #include <test/util/txmempool.h> 12 : : #include <txmempool.h> 13 : : 14 : : #include <cstddef> 15 : : #include <cstdint> 16 : : #include <limits> 17 [ + - ]: 173 : #include <memory> 18 [ + - ]: 173 : #include <optional> 19 : : #include <set> 20 : : #include <vector> 21 : : 22 : : namespace { 23 : : const TestingSetup* g_setup; 24 : : } // namespace 25 : : 26 : 1 : void initialize_pdb() 27 : : { 28 [ + - - + : 1 : static const auto testing_setup = MakeNoLogFileContext<const TestingSetup>(); + - ] 29 : 1 : g_setup = testing_setup.get(); 30 : 1 : } 31 : : 32 : 434 : PartiallyDownloadedBlock::CheckBlockFn FuzzedCheckBlock(std::optional<BlockValidationResult> result) 33 : : { 34 : 649 : return [result](const CBlock&, BlockValidationState& state, const Consensus::Params&, bool, bool) { 35 [ + + ]: 215 : if (result) { 36 [ + - + - : 8 : return state.Invalid(*result); - + ] 37 : : } 38 : : 39 : 207 : return true; 40 : 215 : }; 41 : : } 42 : : 43 [ + - - + ]: 852 : FUZZ_TARGET(partially_downloaded_block, .init = initialize_pdb) 44 : : { 45 : 506 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; 46 : : 47 : 506 : auto block{ConsumeDeserializable<CBlock>(fuzzed_data_provider)}; 48 [ + + + - : 940 : if (!block || block->vtx.size() == 0 || + + + - ] 49 [ + - ]: 434 : block->vtx.size() >= std::numeric_limits<uint16_t>::max()) { 50 : 72 : return; 51 : : } 52 : : 53 [ + - + - ]: 434 : CBlockHeaderAndShortTxIDs cmpctblock{*block}; 54 : : 55 [ + - + - ]: 434 : CTxMemPool pool{MemPoolOptionsForTest(g_setup->m_node)}; 56 [ + - ]: 434 : PartiallyDownloadedBlock pdb{&pool}; 57 : : 58 : : // Set of available transactions (mempool or extra_txn) 59 : 434 : std::set<uint16_t> available; 60 : : // The coinbase is always available 61 [ + - ]: 434 : available.insert(0); 62 : : 63 : 434 : std::vector<std::pair<uint256, CTransactionRef>> extra_txn; 64 [ + - + + ]: 304997 : for (size_t i = 1; i < block->vtx.size(); ++i) { 65 [ + - ]: 304563 : auto tx{block->vtx[i]}; 66 : : 67 [ + - ]: 304563 : bool add_to_extra_txn{fuzzed_data_provider.ConsumeBool()}; 68 [ + - ]: 304563 : bool add_to_mempool{fuzzed_data_provider.ConsumeBool()}; 69 : : 70 [ + + ]: 304563 : if (add_to_extra_txn) { 71 [ + - + - ]: 48829 : extra_txn.emplace_back(tx->GetWitnessHash(), tx); 72 [ + - ]: 48829 : available.insert(i); 73 : 48829 : } 74 : 173 : 75 [ + + ]: 304563 : if (add_to_mempool) { 76 [ + - + - : 48560 : LOCK2(cs_main, pool.cs); + - + - ] 77 [ + - ]: 48560 : pool.addUnchecked(ConsumeTxMemPoolEntry(fuzzed_data_provider, *tx)); 78 [ + - ]: 48560 : available.insert(i); 79 : 48560 : } 80 : 304563 : } 81 : : 82 [ + - ]: 434 : auto init_status{pdb.InitData(cmpctblock, extra_txn)}; 83 : : 84 : 434 : std::vector<CTransactionRef> missing; 85 : : // Whether we skipped a transaction that should be included in `missing`. 86 : : // FillBlock should never return READ_STATUS_OK if that is the case. 87 : 434 : bool skipped_missing{false}; 88 [ + - + + ]: 305431 : for (size_t i = 0; i < cmpctblock.BlockTxCount(); i++) { 89 : : // If init_status == READ_STATUS_OK then a available transaction in the 90 : : // compact block (i.e. IsTxAvailable(i) == true) implies that we marked 91 : : // that transaction as available above (i.e. available.count(i) > 0). 92 : : // The reverse is not true, due to possible compact block short id 93 : : // collisions (i.e. available.count(i) > 0 does not imply 94 : : // IsTxAvailable(i) == true). 95 [ + + ]: 304997 : if (init_status == READ_STATUS_OK) { 96 [ + - + + : 1541 : assert(!pdb.IsTxAvailable(i) || available.count(i) > 0); + - + - ] 97 : 1541 : } 98 : : 99 [ + - ]: 304997 : bool skip{fuzzed_data_provider.ConsumeBool()}; 100 [ + - + + : 304997 : if (!pdb.IsTxAvailable(i) && !skip) { + + ] 101 [ + - + - ]: 285128 : missing.push_back(block->vtx[i]); 102 : 285128 : } 103 : : 104 [ + - + + ]: 304997 : skipped_missing |= (!pdb.IsTxAvailable(i) && skip); 105 : 304997 : } 106 : : 107 : : // Mock CheckBlock 108 [ + - ]: 434 : bool fail_check_block{fuzzed_data_provider.ConsumeBool()}; 109 : 434 : auto validation_result = 110 [ + - ]: 434 : fuzzed_data_provider.PickValueInArray( 111 : 434 : {BlockValidationResult::BLOCK_RESULT_UNSET, 112 : : BlockValidationResult::BLOCK_CONSENSUS, 113 : : BlockValidationResult::BLOCK_RECENT_CONSENSUS_CHANGE, 114 : : BlockValidationResult::BLOCK_CACHED_INVALID, 115 : : BlockValidationResult::BLOCK_INVALID_HEADER, 116 : : BlockValidationResult::BLOCK_MUTATED, 117 : : BlockValidationResult::BLOCK_MISSING_PREV, 118 : : BlockValidationResult::BLOCK_INVALID_PREV, 119 : : BlockValidationResult::BLOCK_TIME_FUTURE, 120 : : BlockValidationResult::BLOCK_CHECKPOINT, 121 : : BlockValidationResult::BLOCK_HEADER_LOW_WORK}); 122 [ + - ]: 434 : pdb.m_check_block_mock = FuzzedCheckBlock( 123 [ + + ]: 593 : fail_check_block ? 124 [ + - ]: 159 : std::optional<BlockValidationResult>{validation_result} : 125 : 275 : std::nullopt); 126 : : 127 [ + - ]: 434 : CBlock reconstructed_block; 128 [ + - ]: 434 : auto fill_status{pdb.FillBlock(reconstructed_block, missing)}; 129 [ - + + + : 434 : switch (fill_status) { + ] 130 : : case READ_STATUS_OK: 131 [ + - ]: 207 : assert(!skipped_missing); 132 [ + - ]: 207 : assert(!fail_check_block); 133 [ + - + - : 207 : assert(block->GetHash() == reconstructed_block.GetHash()); + - + - + - ] 134 : 214 : break; 135 : : case READ_STATUS_CHECKBLOCK_FAILED: [[fallthrough]]; 136 : : case READ_STATUS_FAILED: 137 [ + - ]: 8 : assert(fail_check_block); 138 : 8 : break; 139 : : case READ_STATUS_INVALID: 140 : 219 : break; 141 : : } 142 [ - + ]: 506 : }