7#include <blockfilter.h>
67 switch (filter_type) {
87 size_t n_cache_size,
bool f_memory,
bool f_wipe)
89 , m_filter_type(filter_type)
92 if (filter_name.empty())
throw std::invalid_argument(
"unknown filter_type");
95 fs::create_directories(path);
97 m_db = std::make_unique<BaseIndex::DB>(path /
"db", n_cache_size, f_memory, f_wipe);
115 LogError(
"Cannot read current %s state; index may be corrupted",
127 if (!op_last_header) {
128 LogError(
"Cannot read last block filter header; index may be corrupted");
147 if (!file.Commit()) {
152 if (file.fclose() != 0) {
164 if (filein.IsNull()) {
170 std::vector<uint8_t> encoded_filter;
172 filein >> block_hash >> encoded_filter;
173 if (
Hash(encoded_filter) != hash) {
174 LogError(
"Checksum mismatch in filter decode.");
179 catch (
const std::exception& e) {
180 LogError(
"Failed to deserialize block filter from disk: %s", e.what());
198 if (last_file.IsNull()) {
202 if (!last_file.Truncate(pos.
nPos)) {
206 if (!last_file.Commit()) {
208 (void)last_file.fclose();
211 if (last_file.fclose() != 0) {
229 if (fileout.IsNull()) {
236 if (fileout.fclose() != 0) {
246 std::pair<uint256, DBVal> read_out;
251 if (read_out.first != expected_block_hash) {
252 LogError(
"previous block header belongs to unexpected block %s; expected %s",
253 read_out.first.ToString(), expected_block_hash.
ToString());
257 return read_out.second.header;
272 if (bytes_written == 0)
return false;
274 std::pair<uint256, DBVal> value;
276 value.second.hash = filter.
GetHash();
277 value.second.header = filter_header;
289 std::unique_ptr<CDBIterator> db_it(
m_db->NewIterator());
294 if (!index_util::CopyHeightIndexToHashIndex<DBVal>(*db_it, batch,
m_name, block.
height)) {
302 m_db->WriteBatch(batch);
310 const CBlockIndex* stop_index, std::vector<DBVal>& results)
312 if (start_height < 0) {
313 LogError(
"start height (%d) is negative", start_height);
316 if (start_height > stop_index->
nHeight) {
317 LogError(
"start height (%d) is greater than stop height (%d)",
318 start_height, stop_index->
nHeight);
322 size_t results_size =
static_cast<size_t>(stop_index->
nHeight - start_height + 1);
323 std::vector<std::pair<uint256, DBVal>>
values(results_size);
328 for (
int height = start_height; height <= stop_index->
nHeight; ++height) {
329 if (!db_it->Valid() || !db_it->GetKey(key) || key.
height != height) {
333 size_t i =
static_cast<size_t>(height - start_height);
334 if (!db_it->GetValue(
values[i])) {
335 LogError(
"unable to read value in %s at key (%c, %d)",
343 results.resize(results_size);
348 block_index && block_index->
nHeight >= start_height;
349 block_index = block_index->pprev) {
350 uint256 block_hash = block_index->GetBlockHash();
352 size_t i =
static_cast<size_t>(block_index->nHeight - start_height);
353 if (block_hash ==
values[i].first) {
354 results[i] = std::move(
values[i].second);
359 LogError(
"unable to read value in %s at key (%c, %s)",
386 auto header = m_headers_cache.find(block_index->
GetBlockHash());
387 if (header != m_headers_cache.end()) {
388 header_out = header->second;
401 m_headers_cache.emplace(block_index->
GetBlockHash(), entry.header);
404 header_out = entry.header;
409 std::vector<BlockFilter>& filters_out)
const
411 std::vector<DBVal> entries;
416 filters_out.resize(entries.size());
417 auto filter_pos_it = filters_out.begin();
418 for (
const auto& entry : entries) {
429 std::vector<uint256>& hashes_out)
const
432 std::vector<DBVal> entries;
438 hashes_out.reserve(entries.size());
439 for (
const auto& entry : entries) {
440 hashes_out.push_back(entry.hash);
457 size_t n_cache_size,
bool f_memory,
bool f_wipe)
460 std::forward_as_tuple(filter_type),
461 std::forward_as_tuple(make_chain(), filter_type,
462 n_cache_size, f_memory, f_wipe));
463 return result.second;
const std::string & BlockFilterTypeName(BlockFilterType filter_type)
Get the human-readable name for a filter type.
constexpr unsigned int FLTR_FILE_CHUNK_SIZE
The pre-allocation chunk size for fltr?????.dat files.
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.
constexpr uint8_t DB_FILTER_POS
constexpr unsigned int MAX_FLTR_FILE_SIZE
void ForEachBlockFilterIndex(std::function< void(BlockFilterIndex &)> fn)
Iterate over all running block filter indexes, invoking fn on each.
constexpr size_t CF_HEADERS_CACHE_MAX_SZ
Maximum size of the cfheaders cache We have a limit to prevent a bug in filling this cache potentiall...
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.
static bool LookupRange(CDBWrapper &db, const std::string &index_name, int start_height, const CBlockIndex *stop_index, std::vector< DBVal > &results)
static std::map< BlockFilterType, BlockFilterIndex > g_filter_indexes
constexpr int CFCHECKPT_INTERVAL
Interval between compact filter checkpoints.
#define Assert(val)
Identity function.
fs::path GetDataDirNet() const EXCLUSIVE_LOCKS_REQUIRED(!cs_args)
Get data directory path with appended network identifier.
Non-refcounted RAII wrapper for FILE*.
Base class for indices of blockchain data.
const std::string & GetName() const LIFETIMEBOUND
Get the name of the index for display in logs.
Complete block filter struct as defined in BIP 157.
const uint256 & GetBlockHash() const LIFETIMEBOUND
const std::vector< unsigned char > & GetEncodedFilter() const LIFETIMEBOUND
uint256 ComputeHeader(const uint256 &prev_header) const
Compute the filter header given the previous one.
BlockFilterType GetFilterType() const
uint256 GetHash() const
Compute the filter hash.
BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of bloc...
std::unique_ptr< BaseIndex::DB > m_db
bool CustomInit(const std::optional< interfaces::BlockRef > &block) override
Initialize internal state from the database and block index.
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 CustomRemove(const interfaces::BlockInfo &block) override
Rewind index by one block during a chain reorg.
bool CustomCommit(CDBBatch &batch) override
Virtual method called internally by Commit that can be overridden to atomically commit more index sta...
BlockFilterType m_filter_type
BlockFilterIndex(std::unique_ptr< interfaces::Chain > chain, BlockFilterType filter_type, size_t n_cache_size, bool f_memory=false, bool f_wipe=false)
Constructs the index, which becomes available to be queried.
interfaces::Chain::NotifyOptions CustomOptions() override
Return custom notification options for index.
std::unique_ptr< FlatFileSeq > m_filter_fileseq
bool LookupFilter(const CBlockIndex *block_index, BlockFilter &filter_out) const
Get a single filter by block.
bool ReadFilterFromDisk(const FlatFilePos &pos, const uint256 &hash, BlockFilter &filter) const
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 CustomAppend(const interfaces::BlockInfo &block) override
Write update index entries for a newly connected block.
size_t WriteFilterToDisk(FlatFilePos &pos, const BlockFilter &filter)
bool LookupFilterHeader(const CBlockIndex *block_index, uint256 &header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache)
Get a single filter header by block.
std::optional< uint256 > ReadFilterHeader(int height, const uint256 &expected_block_hash)
bool Write(const BlockFilter &filter, uint32_t block_height, const uint256 &filter_header)
FlatFilePos m_next_filter_pos
The block chain is a tree shaped structure starting with the genesis block at the root,...
uint256 GetBlockHash() const
int nHeight
height of the entry in the chain. The genesis block has height 0
Batch of changes queued to be written to a CDBWrapper.
void Write(const K &key, const V &value)
bool Read(const K &key, V &value) const
Wrapper around TryRead() that preserves the original Read() semantics: returns true on success,...
CDBIterator * NewIterator()
std::string ToString() const
static path u8path(std::string_view utf8_str)
uint256 Hash(const T &in1)
Compute the 256-bit hash of an object.
static bool LookUpOne(const CDBWrapper &db, const interfaces::BlockRef &block, DBVal &result)
constexpr uint8_t DB_BLOCK_HASH
constexpr uint8_t DB_BLOCK_HEIGHT
static const int64_t values[]
A selection of numbers that do not trigger int64_t overflow when added/subtracted.
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
uint64_t GetSerializeSize(const T &t)
Block data sent with blockConnected, blockDisconnected notifications.
const uint256 * prev_hash
const CBlockUndo * undo_data
Options specifying which chain notifications are required.
bool connect_undo_data
Include undo data with block connected notifications.
std::string SysErrorString(int err)
Return system error string from errno value.