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