Branch data Line data Source code
1 : : // Copyright (c) 2023 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 <node/blockstorage.h> 8 : : #include <txdb.h> 9 : : #include <validation.h> 10 : : #include <test/fuzz/FuzzedDataProvider.h> 11 : : #include <test/fuzz/fuzz.h> 12 : : #include <test/fuzz/util.h> 13 : : #include <test/util/setup_common.h> 14 : : 15 : : namespace { 16 : : 17 : : const BasicTestingSetup* g_setup; 18 : : 19 : : // Hardcoded block hash and nBits to make sure the blocks we store pass the pow check. 20 : 2 : const uint256 g_block_hash{uint256S("000000002c05cc2e78923c34df87fd108b22221ac6076c18f3ade378a4d915e9")}; 21 : : uint32_t g_bits{0x1d00ffff}; 22 : : 23 : 4392 : bool operator==(const CBlockFileInfo& a, const CBlockFileInfo& b) 24 : : { 25 [ + - ]: 8784 : return a.nBlocks == b.nBlocks && 26 [ + - ]: 4392 : a.nSize == b.nSize && 27 [ + - ]: 4392 : a.nUndoSize == b.nUndoSize && 28 [ + - ]: 4392 : a.nHeightFirst == b.nHeightFirst && 29 [ + - ]: 4392 : a.nHeightLast == b.nHeightLast && 30 [ - + ]: 4392 : a.nTimeFirst == b.nTimeFirst && 31 : 4392 : a.nTimeLast == b.nTimeLast; 32 : : } 33 : : 34 : 326521 : CBlockHeader ConsumeBlockHeader(FuzzedDataProvider& provider) 35 : : { 36 : 326521 : CBlockHeader header; 37 : 326521 : header.nVersion = provider.ConsumeIntegral<decltype(header.nVersion)>(); 38 : 326521 : header.hashPrevBlock = g_block_hash; 39 : 326521 : header.hashMerkleRoot = g_block_hash; 40 : 326521 : header.nTime = provider.ConsumeIntegral<decltype(header.nTime)>(); 41 : 326521 : header.nBits = g_bits; 42 : 326521 : header.nNonce = provider.ConsumeIntegral<decltype(header.nNonce)>(); 43 : 326521 : return header; 44 : : } 45 : : 46 : 154 : } // namespace 47 : : 48 : 1 : void init_block_index() 49 : : { 50 [ + - ][ - + ]: 1 : static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN); [ + - ] 51 : 1 : g_setup = testing_setup.get(); 52 : 1 : } 53 : : 54 [ + - ]: 158 : FUZZ_TARGET(block_index, .init = init_block_index) 55 : : { 56 : 154 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()}; 57 [ + - ][ + - ]: 462 : auto block_index = kernel::BlockTreeDB(DBParams{ [ + - ] 58 : 154 : .path = "", // Memory only. 59 : : .cache_bytes = 1 << 20, // 1MB. 60 : : .memory_only = true, 61 : : }); 62 : : 63 : : // Generate a number of block files to be stored in the index. 64 [ + - ]: 154 : int files_count = fuzzed_data_provider.ConsumeIntegralInRange(1, 100); 65 : 154 : std::vector<std::unique_ptr<CBlockFileInfo>> files; 66 [ + - ]: 154 : files.reserve(files_count); 67 : 154 : std::vector<std::pair<int, const CBlockFileInfo*>> files_info; 68 [ + - ]: 154 : files_info.reserve(files_count); 69 [ + + ]: 4558 : for (int i = 0; i < files_count; i++) { 70 [ + + ]: 4421 : if (auto file_info = ConsumeDeserializable<CBlockFileInfo>(fuzzed_data_provider)) { 71 [ + - ][ + - ]: 4404 : files.push_back(std::make_unique<CBlockFileInfo>(std::move(*file_info))); 72 [ + - ]: 4404 : files_info.emplace_back(i, files.back().get()); 73 : 4404 : } else { 74 : 17 : return; 75 : : } 76 : 4404 : } 77 : : 78 : : // Generate a number of block headers to be stored in the index. 79 [ + - ]: 137 : int blocks_count = fuzzed_data_provider.ConsumeIntegralInRange(files_count * 10, files_count * 100); 80 : 137 : std::vector<std::unique_ptr<CBlockIndex>> blocks; 81 [ + - ]: 137 : blocks.reserve(blocks_count); 82 : 137 : std::vector<const CBlockIndex*> blocks_info; 83 [ + - ]: 137 : blocks_info.reserve(blocks_count); 84 [ + + ]: 326658 : for (int i = 0; i < blocks_count; i++) { 85 [ + - ]: 326521 : CBlockHeader header{ConsumeBlockHeader(fuzzed_data_provider)}; 86 [ + - ][ + - ]: 326521 : blocks.push_back(std::make_unique<CBlockIndex>(std::move(header))); 87 : 326521 : blocks.back()->phashBlock = &g_block_hash; 88 [ + - ]: 326521 : blocks_info.push_back(blocks.back().get()); 89 : 326521 : } 90 : : 91 : : // Store these files and blocks in the block index. It should not fail. 92 [ + - ][ + - ]: 137 : assert(block_index.WriteBatchSync(files_info, files_count - 1, blocks_info)); 93 : : 94 : : // We should be able to read every block file info we stored. Its value should correspond to 95 : : // what we stored above. 96 [ + - ]: 137 : CBlockFileInfo info; 97 [ + + ]: 8921 : for (const auto& [n, file_info]: files_info) { 98 [ + - ][ - + ]: 4392 : assert(block_index.ReadBlockFileInfo(n, info)); 99 [ + - ][ + - ]: 4392 : assert(info == *file_info); 100 : : } 101 : : 102 : : // We should be able to read the last block file number. Its value should be consistent. 103 : : int last_block_file; 104 [ + - ][ + - ]: 137 : assert(block_index.ReadLastBlockFile(last_block_file)); 105 [ + - ]: 137 : assert(last_block_file == files_count - 1); 106 : : 107 : : // We should be able to flip and read the reindexing flag. 108 : : bool reindexing; 109 [ + - ]: 137 : block_index.WriteReindexing(true); 110 [ + - ]: 137 : block_index.ReadReindexing(reindexing); 111 [ + - ]: 137 : assert(reindexing); 112 [ + - ]: 137 : block_index.WriteReindexing(false); 113 [ + - ]: 137 : block_index.ReadReindexing(reindexing); 114 [ + - ]: 137 : assert(!reindexing); 115 : : 116 : : // We should be able to set and read the value of any random flag. 117 [ + - ]: 137 : int flag_size = fuzzed_data_provider.ConsumeIntegralInRange(0, 100); 118 [ + - ]: 137 : const std::string flag_name = fuzzed_data_provider.ConsumeBytesAsString(flag_size); 119 : : bool flag_value; 120 [ + - ]: 137 : block_index.WriteFlag(flag_name, true); 121 [ + - ]: 137 : block_index.ReadFlag(flag_name, flag_value); 122 [ + - ]: 137 : assert(flag_value); 123 [ + - ]: 137 : block_index.WriteFlag(flag_name, false); 124 [ + - ]: 137 : block_index.ReadFlag(flag_name, flag_value); 125 [ + - ]: 137 : assert(!flag_value); 126 : : 127 : : // We should be able to load everything we've previously stored. Note to assert on the 128 : : // return value we need to make sure all blocks pass the pow check. 129 [ + - ][ + - ]: 137 : const auto params{Params().GetConsensus()}; [ + - ] 130 : 411 : const auto inserter = [&](const uint256&) { 131 : 274 : return blocks.back().get(); 132 : : }; 133 [ + - ][ + - ]: 274 : WITH_LOCK(::cs_main, assert(block_index.LoadBlockIndexGuts(params, inserter, g_setup->m_interrupt))); [ + - ][ + - ] 134 [ - + ]: 154 : }