Bitcoin Core 32.1.0
P2P Digital Currency
Loading...
Searching...
No Matches
block_index.cpp
Go to the documentation of this file.
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>
9#include <test/fuzz/fuzz.h>
10#include <test/fuzz/util.h>
12#include <txdb.h>
13#include <util/byte_units.h>
14#include <validation.h>
15
17
18namespace {
19
21
22// Hardcoded block hash and nBits to make sure the blocks we store pass the pow check.
23uint256 g_block_hash;
24
25bool operator==(const CBlockFileInfo& a, const CBlockFileInfo& b)
26{
27 return a.nBlocks == b.nBlocks &&
28 a.nSize == b.nSize &&
29 a.nUndoSize == b.nUndoSize &&
31 a.nHeightLast == b.nHeightLast &&
32 a.nTimeFirst == b.nTimeFirst &&
33 a.nTimeLast == b.nTimeLast;
34}
35
37{
38 CBlockHeader header;
39 header.nVersion = provider.ConsumeIntegral<decltype(header.nVersion)>();
40 header.hashPrevBlock = g_block_hash;
41 header.hashMerkleRoot = g_block_hash;
42 header.nTime = provider.ConsumeIntegral<decltype(header.nTime)>();
43 header.nBits = Params().GenesisBlock().nBits;
44 header.nNonce = provider.ConsumeIntegral<decltype(header.nNonce)>();
45 return header;
46}
47
48} // namespace
49
51{
52 static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN);
53 g_setup = testing_setup.get();
54 g_block_hash = Params().GenesisBlock().GetHash();
55}
56
58{
59 FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
60 auto block_index = kernel::BlockTreeDB(DBParams{
61 .path = "", // Memory only.
62 .cache_bytes = 1_MiB,
63 .memory_only = true,
64 });
65
66 // Generate a number of block files to be stored in the index.
67 int files_count = fuzzed_data_provider.ConsumeIntegralInRange(1, 100);
68 std::vector<std::unique_ptr<CBlockFileInfo>> files;
69 files.reserve(files_count);
70 std::vector<std::pair<int, const CBlockFileInfo*>> files_info;
71 files_info.reserve(files_count);
72 for (int i = 0; i < files_count; i++) {
73 if (auto file_info = ConsumeDeserializable<CBlockFileInfo>(fuzzed_data_provider)) {
74 files.push_back(std::make_unique<CBlockFileInfo>(std::move(*file_info)));
75 files_info.emplace_back(i, files.back().get());
76 } else {
77 return;
78 }
79 }
80
81 // Generate a number of block headers to be stored in the index.
82 int blocks_count = fuzzed_data_provider.ConsumeIntegralInRange(files_count * 10, files_count * 100);
83 std::vector<std::unique_ptr<CBlockIndex>> blocks;
84 blocks.reserve(blocks_count);
85 std::vector<const CBlockIndex*> blocks_info;
86 blocks_info.reserve(blocks_count);
87 for (int i = 0; i < blocks_count; i++) {
88 CBlockHeader header{ConsumeBlockHeader(fuzzed_data_provider)};
89 blocks.push_back(std::make_unique<CBlockIndex>(std::move(header)));
90 blocks.back()->phashBlock = &g_block_hash;
91 blocks_info.push_back(blocks.back().get());
92 }
93
94 // Store these files and blocks in the block index. It should not fail.
95 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 CBlockFileInfo info;
100 for (const auto& [n, file_info]: files_info) {
101 assert(block_index.ReadBlockFileInfo(n, info));
102 assert(info == *file_info);
103 }
104
105 // We should be able to read the last block file number. Its value should be consistent.
106 int last_block_file;
107 assert(block_index.ReadLastBlockFile(last_block_file));
108 assert(last_block_file == files_count - 1);
109
110 // We should be able to flip and read the reindexing flag.
111 bool reindexing;
112 block_index.WriteReindexing(true);
113 block_index.ReadReindexing(reindexing);
114 assert(reindexing);
115 block_index.WriteReindexing(false);
116 block_index.ReadReindexing(reindexing);
117 assert(!reindexing);
118
119 // We should be able to set and read the value of any random flag.
120 const std::string flag_name = fuzzed_data_provider.ConsumeRandomLengthString(100);
121 bool flag_value;
122 block_index.WriteFlag(flag_name, true);
123 block_index.ReadFlag(flag_name, flag_value);
124 assert(flag_value);
125 block_index.WriteFlag(flag_name, false);
126 block_index.ReadFlag(flag_name, flag_value);
127 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 const auto params{Params().GetConsensus()};
132 const auto inserter = [&](const uint256&) {
133 return blocks.back().get();
134 };
135 WITH_LOCK(::cs_main, assert(block_index.LoadBlockIndexGuts(params, inserter, g_setup->m_interrupt)));
136}
void init_block_index()
CBlockHeader ConsumeBlockHeader(FuzzedDataProvider &provider, uint256 prev_hash, int &nonce_counter)
const TestingSetup * g_setup
const CChainParams & Params()
Return the currently selected parameters.
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition block.h:27
uint32_t nNonce
Definition block.h:35
uint32_t nBits
Definition block.h:34
uint32_t nTime
Definition block.h:33
int32_t nVersion
Definition block.h:30
uint256 hashPrevBlock
Definition block.h:31
uint256 hashMerkleRoot
Definition block.h:32
uint256 GetHash() const
Definition block.cpp:14
const CBlock & GenesisBlock() const
Definition chainparams.h:94
const Consensus::Params & GetConsensus() const
Definition chainparams.h:89
std::string ConsumeRandomLengthString(size_t max_length)
T ConsumeIntegralInRange(T min, T max)
Access to the block database (blocks/index/).
uint64_t nTimeFirst
earliest time of block in file
uint64_t nUndoSize
number of used bytes in the undo file
uint64_t nTimeLast
latest time of block in file
uint32_t nHeightFirst
lowest height of block in file
uint32_t nBlocks
number of blocks stored in file
uint32_t nHeightLast
highest height of block in file
uint64_t nSize
number of used bytes of block file
256-bit opaque blob.
Definition uint256.h:196
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition cs_main.cpp:8
#define FUZZ_TARGET(...)
Definition fuzz.h:35
Definition basic.cpp:11
bool operator==(const CNetAddr &a, const CNetAddr &b)
std::unique_ptr< T > MakeNoLogFileContext(const ChainType chain_type=ChainType::REGTEST, TestOpts opts={})
Make a test setup that has disk access to the debug.log file disabled.
Basic testing setup.
util::SignalInterrupt m_interrupt
Application-specific storage settings.
Definition dbwrapper.h:42
#define WITH_LOCK(cs, code)
Definition sync.h:299
FuzzedDataProvider provider
std::optional< T > ConsumeDeserializable(FuzzedDataProvider &fuzzed_data_provider, const P &params, const std::optional< size_t > &max_length=std::nullopt) noexcept
Definition util.h:106
assert(!tx.IsCoinBase())