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