blockfilterindex.h
1 // Copyright (c) 2018-2022 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 #ifndef BITCOIN_INDEX_BLOCKFILTERINDEX_H 6 #define BITCOIN_INDEX_BLOCKFILTERINDEX_H 7 8 #include <attributes.h> 9 #include <blockfilter.h> 10 #include <chain.h> 11 #include <flatfile.h> 12 #include <index/base.h> 13 #include <util/hasher.h> 14 15 #include <unordered_map> 16 17 static const char* const DEFAULT_BLOCKFILTERINDEX = "0"; 18 19 /** Interval between compact filter checkpoints. See BIP 157. */ 20 static constexpr int CFCHECKPT_INTERVAL = 1000; 21 22 /** 23 * BlockFilterIndex is used to store and retrieve block filters, hashes, and headers for a range of 24 * blocks by height. An index is constructed for each supported filter type with its own database 25 * (ie. filter data for different types are stored in separate databases). 26 * 27 * This index is used to serve BIP 157 net requests. 28 */ 29 class BlockFilterIndex final : public BaseIndex 30 { 31 private: 32 BlockFilterType m_filter_type; 33 std::unique_ptr<BaseIndex::DB> m_db; 34 35 FlatFilePos m_next_filter_pos; 36 std::unique_ptr<FlatFileSeq> m_filter_fileseq; 37 38 bool ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const; 39 size_t WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& filter); 40 41 Mutex m_cs_headers_cache; 42 /** cache of block hash to filter header, to avoid disk access when responding to getcfcheckpt. */ 43 std::unordered_map<uint256, uint256, FilterHeaderHasher> m_headers_cache GUARDED_BY(m_cs_headers_cache); 44 45 // Last computed header to avoid disk reads on every new block. 46 uint256 m_last_header{}; 47 48 bool AllowPrune() const override { return true; } 49 50 bool Write(const BlockFilter& filter, uint32_t block_height, const uint256& filter_header); 51 52 std::optional<uint256> ReadFilterHeader(int height, const uint256& expected_block_hash); 53 54 protected: 55 bool CustomInit(const std::optional<interfaces::BlockKey>& block) override; 56 57 bool CustomCommit(CDBBatch& batch) override; 58 59 bool CustomAppend(const interfaces::BlockInfo& block) override; 60 61 bool CustomRewind(const interfaces::BlockKey& current_tip, const interfaces::BlockKey& new_tip) override; 62 63 BaseIndex::DB& GetDB() const LIFETIMEBOUND override { return *m_db; } 64 65 public: 66 /** Constructs the index, which becomes available to be queried. */ 67 explicit BlockFilterIndex(std::unique_ptr<interfaces::Chain> chain, BlockFilterType filter_type, 68 size_t n_cache_size, bool f_memory = false, bool f_wipe = false); 69 70 BlockFilterType GetFilterType() const { return m_filter_type; } 71 72 /** Get a single filter by block. */ 73 bool LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const; 74 75 /** Get a single filter header by block. */ 76 bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache); 77 78 /** Get a range of filters between two heights on a chain. */ 79 bool LookupFilterRange(int start_height, const CBlockIndex* stop_index, 80 std::vector<BlockFilter>& filters_out) const; 81 82 /** Get a range of filter hashes between two heights on a chain. */ 83 bool LookupFilterHashRange(int start_height, const CBlockIndex* stop_index, 84 std::vector<uint256>& hashes_out) const; 85 }; 86 87 /** 88 * Get a block filter index by type. Returns nullptr if index has not been initialized or was 89 * already destroyed. 90 */ 91 BlockFilterIndex* GetBlockFilterIndex(BlockFilterType filter_type); 92 93 /** Iterate over all running block filter indexes, invoking fn on each. */ 94 void ForEachBlockFilterIndex(std::function<void (BlockFilterIndex&)> fn); 95 96 /** 97 * Initialize a block filter index for the given type if one does not already exist. Returns true if 98 * a new index is created and false if one has already been initialized. 99 */ 100 bool InitBlockFilterIndex(std::function<std::unique_ptr<interfaces::Chain>()> make_chain, BlockFilterType filter_type, 101 size_t n_cache_size, bool f_memory = false, bool f_wipe = false); 102 103 /** 104 * Destroy the block filter index with the given type. Returns false if no such index exists. This 105 * just releases the allocated memory and closes the database connection, it does not delete the 106 * index data. 107 */ 108 bool DestroyBlockFilterIndex(BlockFilterType filter_type); 109 110 /** Destroy all open block filter indexes. */ 111 void DestroyAllBlockFilterIndexes(); 112 113 #endif // BITCOIN_INDEX_BLOCKFILTERINDEX_H