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 <test/fuzz/FuzzedDataProvider.h>
9 : : #include <test/fuzz/fuzz.h>
10 : : #include <test/fuzz/util.h>
11 : : #include <test/util/setup_common.h>
12 : : #include <txdb.h>
13 : : #include <validation.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 : : uint256 g_block_hash;
21 : :
22 : 10633 : bool operator==(const CBlockFileInfo& a, const CBlockFileInfo& b)
23 : : {
24 [ + - ]: 21266 : return a.nBlocks == b.nBlocks &&
25 [ + - ]: 10633 : a.nSize == b.nSize &&
26 [ + - ]: 10633 : a.nUndoSize == b.nUndoSize &&
27 [ + - ]: 10633 : a.nHeightFirst == b.nHeightFirst &&
28 [ + - ]: 10633 : a.nHeightLast == b.nHeightLast &&
29 [ - + ]: 10633 : a.nTimeFirst == b.nTimeFirst &&
30 : 10633 : a.nTimeLast == b.nTimeLast;
31 : : }
32 : :
33 : 787924 : CBlockHeader ConsumeBlockHeader(FuzzedDataProvider& provider)
34 : : {
35 : 787924 : CBlockHeader header;
36 : 787924 : header.nVersion = provider.ConsumeIntegral<decltype(header.nVersion)>();
37 : 787924 : header.hashPrevBlock = g_block_hash;
38 : 787924 : header.hashMerkleRoot = g_block_hash;
39 : 787924 : header.nTime = provider.ConsumeIntegral<decltype(header.nTime)>();
40 : 787924 : header.nBits = Params().GenesisBlock().nBits;
41 : 787924 : header.nNonce = provider.ConsumeIntegral<decltype(header.nNonce)>();
42 : 787924 : return header;
43 : : }
44 : :
45 : : } // namespace
46 : :
47 : 0 : void init_block_index()
48 : : {
49 [ # # # # : 0 : static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN);
# # ]
50 : 0 : g_setup = testing_setup.get();
51 : 0 : g_block_hash = Params().GenesisBlock().GetHash();
52 : 0 : }
53 : :
54 [ + - ]: 578 : FUZZ_TARGET(block_index, .init = init_block_index)
55 : : {
56 : 576 : FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
57 [ + - + - : 1728 : auto block_index = kernel::BlockTreeDB(DBParams{
+ - + - ]
58 : 576 : .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 : : int files_count = fuzzed_data_provider.ConsumeIntegralInRange(1, 100);
65 : : std::vector<std::unique_ptr<CBlockFileInfo>> files;
66 : : files.reserve(files_count);
67 : : std::vector<std::pair<int, const CBlockFileInfo*>> files_info;
68 : : files_info.reserve(files_count);
69 [ + + + + ]: 11662 : for (int i = 0; i < files_count; i++) {
70 [ + + + + ]: 22172 : if (auto file_info = ConsumeDeserializable<CBlockFileInfo>(fuzzed_data_provider)) {
71 [ - + + - ]: 10996 : files.push_back(std::make_unique<CBlockFileInfo>(std::move(*file_info)));
72 [ - + ]: 10996 : files_info.emplace_back(i, files.back().get());
73 : 10996 : } else {
74 : 90 : return;
75 : : }
76 : 10996 : }
77 : :
78 : : // Generate a number of block headers to be stored in the index.
79 : : int blocks_count = fuzzed_data_provider.ConsumeIntegralInRange(files_count * 10, files_count * 100);
80 : : std::vector<std::unique_ptr<CBlockIndex>> blocks;
81 : : blocks.reserve(blocks_count);
82 : : std::vector<const CBlockIndex*> blocks_info;
83 : : blocks_info.reserve(blocks_count);
84 [ + + ]: 788410 : for (int i = 0; i < blocks_count; i++) {
85 [ - + ]: 787924 : CBlockHeader header{ConsumeBlockHeader(fuzzed_data_provider)};
86 [ - + - + ]: 787924 : blocks.push_back(std::make_unique<CBlockIndex>(std::move(header)));
87 : 787924 : blocks.back()->phashBlock = &g_block_hash;
88 [ + - ]: 787924 : blocks_info.push_back(blocks.back().get());
89 : 787924 : }
90 : :
91 : : // Store these files and blocks in the block index. It should not fail.
92 : : 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 : : CBlockFileInfo info;
97 [ + + ]: 21752 : for (const auto& [n, file_info]: files_info) {
98 [ + - - + ]: 10633 : assert(block_index.ReadBlockFileInfo(n, info));
99 [ + - - + ]: 10633 : assert(info == *file_info);
100 : 10633 : }
101 : :
102 : : // We should be able to read the last block file number. Its value should be consistent.
103 : : int last_block_file;
104 : : assert(block_index.ReadLastBlockFile(last_block_file));
105 : : assert(last_block_file == files_count - 1);
106 : :
107 : : // We should be able to flip and read the reindexing flag.
108 : : bool reindexing;
109 : : block_index.WriteReindexing(true);
110 : : block_index.ReadReindexing(reindexing);
111 : : assert(reindexing);
112 : : block_index.WriteReindexing(false);
113 : : block_index.ReadReindexing(reindexing);
114 : : assert(!reindexing);
115 : :
116 : : // We should be able to set and read the value of any random flag.
117 : : const std::string flag_name = fuzzed_data_provider.ConsumeRandomLengthString(100);
118 : : bool flag_value;
119 : : block_index.WriteFlag(flag_name, true);
120 : : block_index.ReadFlag(flag_name, flag_value);
121 : : assert(flag_value);
122 : : block_index.WriteFlag(flag_name, false);
123 : : block_index.ReadFlag(flag_name, flag_value);
124 : : assert(!flag_value);
125 : :
126 : : // We should be able to load everything we've previously stored. Note to assert on the
127 : : // return value we need to make sure all blocks pass the pow check.
128 : : const auto params{Params().GetConsensus()};
129 : 972 : const auto inserter = [&](const uint256&) {
130 : 972 : return blocks.back().get();
131 : : };
132 [ + - + - ]: 486 : WITH_LOCK(::cs_main, assert(block_index.LoadBlockIndexGuts(params, inserter, g_setup->m_interrupt)));
133 : 0 : }
|