Bitcoin Core  28.1.0
P2P Digital Currency
block_index.cpp
Go to the documentation of this file.
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>
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 bool operator==(const CBlockFileInfo& a, const CBlockFileInfo& b)
23 {
24  return a.nBlocks == b.nBlocks &&
25  a.nSize == b.nSize &&
26  a.nUndoSize == b.nUndoSize &&
27  a.nHeightFirst == b.nHeightFirst &&
28  a.nHeightLast == b.nHeightLast &&
29  a.nTimeFirst == b.nTimeFirst &&
30  a.nTimeLast == b.nTimeLast;
31 }
32 
33 CBlockHeader ConsumeBlockHeader(FuzzedDataProvider& provider)
34 {
35  CBlockHeader header;
36  header.nVersion = provider.ConsumeIntegral<decltype(header.nVersion)>();
37  header.hashPrevBlock = g_block_hash;
38  header.hashMerkleRoot = g_block_hash;
39  header.nTime = provider.ConsumeIntegral<decltype(header.nTime)>();
40  header.nBits = Params().GenesisBlock().nBits;
41  header.nNonce = provider.ConsumeIntegral<decltype(header.nNonce)>();
42  return header;
43 }
44 
45 } // namespace
46 
48 {
49  static const auto testing_setup = MakeNoLogFileContext<>(ChainType::MAIN);
50  g_setup = testing_setup.get();
51  g_block_hash = Params().GenesisBlock().GetHash();
52 }
53 
55 {
56  FuzzedDataProvider fuzzed_data_provider{buffer.data(), buffer.size()};
57  auto block_index = kernel::BlockTreeDB(DBParams{
58  .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  for (int i = 0; i < files_count; i++) {
70  if (auto file_info = ConsumeDeserializable<CBlockFileInfo>(fuzzed_data_provider)) {
71  files.push_back(std::make_unique<CBlockFileInfo>(std::move(*file_info)));
72  files_info.emplace_back(i, files.back().get());
73  } else {
74  return;
75  }
76  }
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  for (int i = 0; i < blocks_count; i++) {
85  CBlockHeader header{ConsumeBlockHeader(fuzzed_data_provider)};
86  blocks.push_back(std::make_unique<CBlockIndex>(std::move(header)));
87  blocks.back()->phashBlock = &g_block_hash;
88  blocks_info.push_back(blocks.back().get());
89  }
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  for (const auto& [n, file_info]: files_info) {
98  assert(block_index.ReadBlockFileInfo(n, info));
99  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  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  const auto inserter = [&](const uint256&) {
130  return blocks.back().get();
131  };
132  WITH_LOCK(::cs_main, assert(block_index.LoadBlockIndexGuts(params, inserter, g_setup->m_interrupt)));
133 }
uint32_t nNonce
Definition: block.h:30
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:35
assert(!tx.IsCoinBase())
bool operator==(const CNetAddr &a, const CNetAddr &b)
Definition: netaddress.cpp:607
Access to the block database (blocks/index/)
Definition: blockstorage.h:50
unsigned int nSize
number of used bytes of block file
Definition: chain.h:51
const CBlock & GenesisBlock() const
Definition: chainparams.h:98
util::SignalInterrupt m_interrupt
Definition: setup_common.h:65
unsigned int nHeightLast
highest height of block in file
Definition: chain.h:54
uint32_t nTime
Definition: block.h:28
unsigned int nUndoSize
number of used bytes in the undo file
Definition: chain.h:52
Basic testing setup.
Definition: setup_common.h:64
uint64_t nTimeFirst
earliest time of block in file
Definition: chain.h:55
FUZZ_TARGET(block_index,.init=init_block_index)
Definition: block_index.cpp:54
uint256 hashMerkleRoot
Definition: block.h:27
uint256 hashPrevBlock
Definition: block.h:26
unsigned int nHeightFirst
lowest height of block in file
Definition: chain.h:53
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
Definition: sync.h:301
uint256 GetHash() const
Definition: block.cpp:11
256-bit opaque blob.
Definition: uint256.h:178
const CChainParams & Params()
Return the currently selected parameters.
void init_block_index()
Definition: block_index.cpp:47
Application-specific storage settings.
Definition: dbwrapper.h:33
unsigned int nBlocks
number of blocks stored in file
Definition: chain.h:50
uint64_t nTimeLast
latest time of block in file
Definition: chain.h:56
const Consensus::Params & GetConsensus() const
Definition: chainparams.h:93
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: cs_main.cpp:8
int32_t nVersion
Definition: block.h:25
Nodes collect new transactions into a block, hash them into a hash tree, and scan through nonce value...
Definition: block.h:21
uint32_t nBits
Definition: block.h:29