Coverage Report

Created: 2026-10-07 20:27

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/root/bitcoin/src/test/fuzz/block_index.cpp
Line
Count
Source
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
bool operator==(const CBlockFileInfo& a, const CBlockFileInfo& b)
26
0
{
27
0
    return a.nBlocks == b.nBlocks &&
  Branch (27:12): [True: 0, False: 0]
28
0
        a.nSize == b.nSize &&
  Branch (28:9): [True: 0, False: 0]
29
0
        a.nUndoSize == b.nUndoSize &&
  Branch (29:9): [True: 0, False: 0]
30
0
        a.nHeightFirst == b.nHeightFirst &&
  Branch (30:9): [True: 0, False: 0]
31
0
        a.nHeightLast == b.nHeightLast &&
  Branch (31:9): [True: 0, False: 0]
32
0
        a.nTimeFirst == b.nTimeFirst &&
  Branch (32:9): [True: 0, False: 0]
33
0
        a.nTimeLast == b.nTimeLast;
  Branch (33:9): [True: 0, False: 0]
34
0
}
35
36
CBlockHeader ConsumeBlockHeader(FuzzedDataProvider& provider)
37
0
{
38
0
    CBlockHeader header;
39
0
    header.nVersion = provider.ConsumeIntegral<decltype(header.nVersion)>();
40
0
    header.hashPrevBlock = g_block_hash;
41
0
    header.hashMerkleRoot = g_block_hash;
42
0
    header.nTime = provider.ConsumeIntegral<decltype(header.nTime)>();
43
0
    header.nBits = Params().GenesisBlock().nBits;
44
0
    header.nNonce = provider.ConsumeIntegral<decltype(header.nNonce)>();
45
0
    return header;
46
0
}
47
48
} // namespace
49
50
void init_block_index()
51
0
{
52
0
    static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN);
53
0
    g_setup = testing_setup.get();
54
0
    g_block_hash = Params().GenesisBlock().GetHash();
55
0
}
56
57
FUZZ_TARGET(block_index, .init = init_block_index)
58
0
{
59
0
    FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
60
0
    auto block_index = kernel::BlockTreeDB(DBParams{
61
0
        .path = "", // Memory only.
62
0
        .cache_bytes = 1_MiB,
63
0
        .memory_only = true,
64
0
    });
65
66
    // Generate a number of block files to be stored in the index.
67
0
    int files_count = fuzzed_data_provider.ConsumeIntegralInRange(1, 100);
68
0
    std::vector<std::unique_ptr<CBlockFileInfo>> files;
69
0
    files.reserve(files_count);
70
0
    std::vector<std::pair<int, const CBlockFileInfo*>> files_info;
71
0
    files_info.reserve(files_count);
72
0
    for (int i = 0; i < files_count; i++) {
  Branch (72:21): [True: 0, False: 0]
73
0
        if (auto file_info = ConsumeDeserializable<CBlockFileInfo>(fuzzed_data_provider)) {
  Branch (73:18): [True: 0, False: 0]
74
0
            files.push_back(std::make_unique<CBlockFileInfo>(std::move(*file_info)));
75
0
            files_info.emplace_back(i, files.back().get());
76
0
        } else {
77
0
            return;
78
0
        }
79
0
    }
80
81
    // Generate a number of block headers to be stored in the index.
82
0
    int blocks_count = fuzzed_data_provider.ConsumeIntegralInRange(files_count * 10, files_count * 100);
83
0
    std::vector<std::unique_ptr<CBlockIndex>> blocks;
84
0
    blocks.reserve(blocks_count);
85
0
    std::vector<const CBlockIndex*> blocks_info;
86
0
    blocks_info.reserve(blocks_count);
87
0
    for (int i = 0; i < blocks_count; i++) {
  Branch (87:21): [True: 0, False: 0]
88
0
        CBlockHeader header{ConsumeBlockHeader(fuzzed_data_provider)};
89
0
        blocks.push_back(std::make_unique<CBlockIndex>(std::move(header)));
90
0
        blocks.back()->phashBlock = &g_block_hash;
91
0
        blocks_info.push_back(blocks.back().get());
92
0
    }
93
94
    // Store these files and blocks in the block index. It should not fail.
95
0
    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
0
    CBlockFileInfo info;
100
0
    for (const auto& [n, file_info]: files_info) {
  Branch (100:36): [True: 0, False: 0]
101
0
        assert(block_index.ReadBlockFileInfo(n, info));
  Branch (101:9): [True: 0, False: 0]
102
0
        assert(info == *file_info);
  Branch (102:9): [True: 0, False: 0]
103
0
    }
104
105
    // We should be able to read the last block file number. Its value should be consistent.
106
0
    int last_block_file;
107
0
    assert(block_index.ReadLastBlockFile(last_block_file));
  Branch (107:5): [True: 0, False: 0]
108
0
    assert(last_block_file == files_count - 1);
  Branch (108:5): [True: 0, False: 0]
109
110
    // We should be able to flip and read the reindexing flag.
111
0
    bool reindexing;
112
0
    block_index.WriteReindexing(true);
113
0
    block_index.ReadReindexing(reindexing);
114
0
    assert(reindexing);
  Branch (114:5): [True: 0, False: 0]
115
0
    block_index.WriteReindexing(false);
116
0
    block_index.ReadReindexing(reindexing);
117
0
    assert(!reindexing);
  Branch (117:5): [True: 0, False: 0]
118
119
    // We should be able to set and read the value of any random flag.
120
0
    const std::string flag_name = fuzzed_data_provider.ConsumeRandomLengthString(100);
121
0
    bool flag_value;
122
0
    block_index.WriteFlag(flag_name, true);
123
0
    block_index.ReadFlag(flag_name, flag_value);
124
0
    assert(flag_value);
  Branch (124:5): [True: 0, False: 0]
125
0
    block_index.WriteFlag(flag_name, false);
126
0
    block_index.ReadFlag(flag_name, flag_value);
127
0
    assert(!flag_value);
  Branch (127:5): [True: 0, False: 0]
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
0
    const auto params{Params().GetConsensus()};
132
0
    const auto inserter = [&](const uint256&) {
133
0
        return blocks.back().get();
134
0
    };
135
0
    WITH_LOCK(::cs_main, assert(block_index.LoadBlockIndexGuts(params, inserter, g_setup->m_interrupt)));
136
0
}