blockfilterindex.h raw

   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