Bitcoin Core 32.99.0
P2P Digital Currency
Loading...
Searching...
No Matches
blockfilter_index_tests.cpp
Go to the documentation of this file.
1// Copyright (c) 2017-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 <addresstype.h>
6#include <blockfilter.h>
7#include <chain.h>
9#include <interfaces/chain.h>
10#include <key.h>
11#include <node/blockstorage.h>
12#include <primitives/block.h>
13#include <script/script.h>
14#include <sync.h>
16#include <test/util/common.h>
17#include <test/util/mining.h>
20#include <uint256.h>
21#include <util/check.h>
22#include <validation.h>
23
24#include <boost/test/unit_test.hpp>
25
26#include <compare>
27#include <cstddef>
28#include <cstdint>
29#include <functional>
30#include <memory>
31#include <span>
32#include <string>
33#include <utility>
34#include <vector>
35
37
39
42{
44 if (!ComputeFilter(filter_index.GetFilterType(), *block_index, expected_filter, blockman)) {
45 BOOST_ERROR("ComputeFilter failed on block " << block_index->nHeight);
46 return false;
47 }
48
49 BlockFilter filter;
51 std::vector<BlockFilter> filters;
52 std::vector<uint256> filter_hashes;
53
54 BOOST_CHECK(filter_index.LookupFilter(block_index, filter));
55 BOOST_CHECK(filter_index.LookupFilterHeader(block_index, filter_header));
56 BOOST_CHECK(filter_index.LookupFilterRange(block_index->nHeight, block_index, filters));
57 BOOST_CHECK(filter_index.LookupFilterHashRange(block_index->nHeight, block_index,
59
60 BOOST_CHECK_EQUAL(filters.size(), 1U);
62
63 BOOST_CHECK_EQUAL(filter.GetHash(), expected_filter.GetHash());
65 BOOST_CHECK_EQUAL(filters[0].GetHash(), expected_filter.GetHash());
67
68 filters.clear();
69 filter_hashes.clear();
71 return true;
72}
73
75{
77 BOOST_REQUIRE(filter_index.Init());
78
80
81 // Filter should not be found in the index before it is started.
82 {
84
85 BlockFilter filter;
87 std::vector<BlockFilter> filters;
88 std::vector<uint256> filter_hashes;
89
90 for (const CBlockIndex* block_index = m_node.chainman->ActiveChain().Genesis();
91 block_index != nullptr;
92 block_index = m_node.chainman->ActiveChain().Next(*block_index)) {
93 BOOST_CHECK(!filter_index.LookupFilter(block_index, filter));
98 }
99 }
100
101 // BlockUntilSyncedToCurrentChain should return false before index is started.
102 BOOST_CHECK(!filter_index.BlockUntilSyncedToCurrentChain());
103
104 filter_index.Sync();
105
106 // Check that filter index has all blocks that were in the chain before it started.
107 {
108 LOCK(cs_main);
110 for (block_index = m_node.chainman->ActiveChain().Genesis();
111 block_index != nullptr;
112 block_index = m_node.chainman->ActiveChain().Next(*block_index)) {
113 CheckFilterLookups(filter_index, block_index, last_header, m_node.chainman->m_blockman);
114 }
115 }
116
117 // Create two forks.
118 const CBlockIndex* tip;
119 {
120 LOCK(cs_main);
121 tip = m_node.chainman->ActiveChain().Tip();
122 }
127 std::vector<std::shared_ptr<CBlock>> chainA, chainB;
130
131 // Check that new blocks on chain A get indexed.
133 for (size_t i = 0; i < 2; i++) {
134 const auto& block = chainA[i];
135 BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));
136 }
137 for (size_t i = 0; i < 2; i++) {
138 const auto& block = chainA[i];
140 {
141 LOCK(cs_main);
142 block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());
143 }
144
145 BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
147 }
148
149 // Reorg to chain B.
151 for (size_t i = 0; i < 3; i++) {
152 const auto& block = chainB[i];
153 BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));
154 }
155 for (size_t i = 0; i < 3; i++) {
156 const auto& block = chainB[i];
158 {
159 LOCK(cs_main);
160 block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());
161 }
162
163 BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
165 }
166
167 // Check that filters for stale blocks on A can be retrieved.
169 for (size_t i = 0; i < 2; i++) {
170 const auto& block = chainA[i];
172 {
173 LOCK(cs_main);
174 block_index = m_node.chainman->m_blockman.LookupBlockIndex(block->GetHash());
175 }
176
177 BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
179 }
180
181 // Reorg back to chain A.
182 for (size_t i = 2; i < 4; i++) {
183 const auto& block = chainA[i];
184 BOOST_REQUIRE(Assert(m_node.chainman)->ProcessNewBlock(block, true, true, nullptr));
185 }
186
187 // Check that chain A and B blocks can be retrieved.
190 for (size_t i = 0; i < 3; i++) {
192
193 {
194 LOCK(cs_main);
195 block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainA[i]->GetHash());
196 }
197 BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
199
200 {
201 LOCK(cs_main);
202 block_index = m_node.chainman->m_blockman.LookupBlockIndex(chainB[i]->GetHash());
203 }
204 BOOST_CHECK(filter_index.BlockUntilSyncedToCurrentChain());
206 }
207
208 // Test lookups for a range of filters/hashes.
209 std::vector<BlockFilter> filters;
210 std::vector<uint256> filter_hashes;
211
212 {
213 LOCK(cs_main);
214 tip = m_node.chainman->ActiveChain().Tip();
215 }
216 BOOST_CHECK(filter_index.LookupFilterRange(0, tip, filters));
218
219 assert(tip->nHeight >= 0);
220 BOOST_CHECK_EQUAL(filters.size(), tip->nHeight + 1U);
221 BOOST_CHECK_EQUAL(filter_hashes.size(), tip->nHeight + 1U);
222
223 filters.clear();
224 filter_hashes.clear();
225
226 filter_index.Interrupt();
227 StopIndex(filter_index, m_node);
228}
229
231{
232 BlockFilterIndex* filter_index;
233
235 BOOST_CHECK(filter_index == nullptr);
236
238
240 BOOST_CHECK(filter_index != nullptr);
242
243 // Initialize returns false if index already exists.
245
246 int iter_count = 0;
249
251
252 // Destroy returns false because index was already destroyed.
254
256 BOOST_CHECK(filter_index == nullptr);
257
258 // Reinitialize index.
260
262
264 BOOST_CHECK(filter_index == nullptr);
265}
266
CScript GetScriptForDestination(const CTxDestination &dest)
Generate a Bitcoin scriptPubKey for the given CTxDestination.
node::NodeContext m_node
static bool CheckFilterLookups(BlockFilterIndex &filter_index, const CBlockIndex *block_index, uint256 &last_header, const BlockManager &blockman)
BOOST_FIXTURE_TEST_CASE(blockfilter_index_initial_sync, TestChain100Setup)
bool DestroyBlockFilterIndex(BlockFilterType filter_type)
Destroy the block filter index with the given type.
void DestroyAllBlockFilterIndexes()
Destroy all open block filter indexes.
BlockFilterIndex * GetBlockFilterIndex(BlockFilterType filter_type)
Get a block filter index by type.
void ForEachBlockFilterIndex(std::function< void(BlockFilterIndex &)> fn)
Iterate over all running block filter indexes, invoking fn on each.
bool InitBlockFilterIndex(std::function< std::unique_ptr< interfaces::Chain >()> make_chain, BlockFilterType filter_type, size_t n_cache_size, bool f_memory, bool f_wipe)
Initialize a block filter index for the given type if one does not already exist.
#define Assert(val)
Identity function.
Definition check.h:119
bool Init()
Initializes the sync state and registers the instance to the validation interface so that it stays in...
Definition base.cpp:105
bool BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(void Interrupt()
Blocks the current thread until the index is caught up to the current state of the block chain.
Definition base.cpp:464
void Sync()
Sync the index with the block index starting from the current best block.
Definition base.cpp:208
Complete block filter struct as defined in BIP 157.
uint256 GetHash() const
Compute the filter hash.
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
bool LookupFilterRange(int start_height, const CBlockIndex *stop_index, std::vector< BlockFilter > &filters_out) const
Get a range of filters between two heights on a chain.
BlockFilterType GetFilterType() const
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
bool LookupFilterHashRange(int start_height, const CBlockIndex *stop_index, std::vector< uint256 > &hashes_out) const
Get a range of filter hashes between two heights on a chain.
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition chain.h:94
An encapsulated private key.
Definition key.h:46
Serialized script, used inside transaction inputs and outputs.
Definition script.h:406
Maintains a tree of blocks (stored in m_block_index) which is consulted to determine where the most-w...
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
BOOST_AUTO_TEST_SUITE_END()
CKey GenerateRandomKey(bool compressed) noexcept
Definition key.cpp:354
std::unique_ptr< Chain > MakeChain(node::NodeContext &node)
Return implementation of Chain interface.
#define BOOST_CHECK_EQUAL(v1, v2)
Definition object.cpp:17
#define BOOST_CHECK(expr)
Definition object.cpp:16
Basic testing setup.
Testing fixture that pre-creates a 100-block REGTEST-mode block chain.
std::unique_ptr< ChainstateManager > chainman
Definition context.h:74
#define LOCK(cs)
Definition sync.h:268
bool ComputeFilter(BlockFilterType filter_type, const CBlockIndex &block_index, BlockFilter &filter, const BlockManager &blockman)
bool BuildChain(const NodeContext &node, const CBlockIndex *pindex, const CScript &coinbase_script_pub_key, size_t length, std::vector< std::shared_ptr< CBlock > > &chain)
Build a chain of length coinbase-only blocks on top of pindex (which need not be the active tip,...
Definition mining.cpp:80
void StopIndex(BaseIndex &index, node::NodeContext &node)
Drain validation callbacks before stopping an index, matching Shutdown() in init.cpp.
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.
Definition time.h:82
assert(!tx.IsCoinBase())