Branch data Line data Source code
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_BLOCKFILTER_H 6 : : #define BITCOIN_BLOCKFILTER_H 7 : : 8 : : #include <cstddef> 9 : : #include <cstdint> 10 : : #include <ios> 11 : : #include <set> 12 : : #include <string> 13 : : #include <unordered_set> 14 : : #include <utility> 15 : : #include <vector> 16 : : 17 : : #include <attributes.h> 18 : : #include <uint256.h> 19 : : #include <util/bytevectorhash.h> 20 : : 21 : : class CBlock; 22 : : class CBlockUndo; 23 : : 24 : : /** 25 : : * This implements a Golomb-coded set as defined in BIP 158. It is a 26 : : * compact, probabilistic data structure for testing set membership. 27 : : */ 28 : 0 : class GCSFilter 29 : : { 30 : : public: 31 : : typedef std::vector<unsigned char> Element; 32 : : typedef std::unordered_set<Element, ByteVectorHash> ElementSet; 33 : : 34 : : struct Params 35 : : { 36 : : uint64_t m_siphash_k0; 37 : : uint64_t m_siphash_k1; 38 : : uint8_t m_P; //!< Golomb-Rice coding parameter 39 : : uint32_t m_M; //!< Inverse false positive rate 40 : : 41 : 0 : Params(uint64_t siphash_k0 = 0, uint64_t siphash_k1 = 0, uint8_t P = 0, uint32_t M = 1) 42 : 0 : : m_siphash_k0(siphash_k0), m_siphash_k1(siphash_k1), m_P(P), m_M(M) 43 : 0 : {} 44 : : }; 45 : : 46 : : private: 47 : : Params m_params; 48 : : uint32_t m_N; //!< Number of elements in the filter 49 : : uint64_t m_F; //!< Range of element hashes, F = N * M 50 : : std::vector<unsigned char> m_encoded; 51 : : 52 : : /** Hash a data element to an integer in the range [0, N * M). */ 53 : : uint64_t HashToRange(const Element& element) const; 54 : : 55 : : std::vector<uint64_t> BuildHashedSet(const ElementSet& elements) const; 56 : : 57 : : /** Helper method used to implement Match and MatchAny */ 58 : : bool MatchInternal(const uint64_t* sorted_element_hashes, size_t size) const; 59 : : 60 : : public: 61 : : 62 : : /** Constructs an empty filter. */ 63 : : explicit GCSFilter(const Params& params = Params()); 64 : : 65 : : /** Reconstructs an already-created filter from an encoding. */ 66 : : GCSFilter(const Params& params, std::vector<unsigned char> encoded_filter, bool skip_decode_check); 67 : : 68 : : /** Builds a new filter from the params and set of elements. */ 69 : : GCSFilter(const Params& params, const ElementSet& elements); 70 : : 71 : 0 : uint32_t GetN() const { return m_N; } 72 : 0 : const Params& GetParams() const LIFETIMEBOUND { return m_params; } 73 : 0 : const std::vector<unsigned char>& GetEncoded() const LIFETIMEBOUND { return m_encoded; } 74 : : 75 : : /** 76 : : * Checks if the element may be in the set. False positives are possible 77 : : * with probability 1/M. 78 : : */ 79 : : bool Match(const Element& element) const; 80 : : 81 : : /** 82 : : * Checks if any of the given elements may be in the set. False positives 83 : : * are possible with probability 1/M per element checked. This is more 84 : : * efficient that checking Match on multiple elements separately. 85 : : */ 86 : : bool MatchAny(const ElementSet& elements) const; 87 : : }; 88 : : 89 : : constexpr uint8_t BASIC_FILTER_P = 19; 90 : : constexpr uint32_t BASIC_FILTER_M = 784931; 91 : : 92 : : enum class BlockFilterType : uint8_t 93 : : { 94 : : BASIC = 0, 95 : : INVALID = 255, 96 : : }; 97 : : 98 : : /** Get the human-readable name for a filter type. Returns empty string for unknown types. */ 99 : : const std::string& BlockFilterTypeName(BlockFilterType filter_type); 100 : : 101 : : /** Find a filter type by its human-readable name. */ 102 : : bool BlockFilterTypeByName(const std::string& name, BlockFilterType& filter_type); 103 : : 104 : : /** Get a list of known filter types. */ 105 : : const std::set<BlockFilterType>& AllBlockFilterTypes(); 106 : : 107 : : /** Get a comma-separated list of known filter type names. */ 108 : : const std::string& ListBlockFilterTypes(); 109 : : 110 : : /** 111 : : * Complete block filter struct as defined in BIP 157. Serialization matches 112 : : * payload of "cfilter" messages. 113 : : */ 114 : 0 : class BlockFilter 115 : : { 116 : : private: 117 : 0 : BlockFilterType m_filter_type = BlockFilterType::INVALID; 118 : : uint256 m_block_hash; 119 : : GCSFilter m_filter; 120 : : 121 : : bool BuildParams(GCSFilter::Params& params) const; 122 : : 123 : : public: 124 : : 125 : 0 : BlockFilter() = default; 126 : : 127 : : //! Reconstruct a BlockFilter from parts. 128 : : BlockFilter(BlockFilterType filter_type, const uint256& block_hash, 129 : : std::vector<unsigned char> filter, bool skip_decode_check); 130 : : 131 : : //! Construct a new BlockFilter of the specified type from a block. 132 : : BlockFilter(BlockFilterType filter_type, const CBlock& block, const CBlockUndo& block_undo); 133 : : 134 : 0 : BlockFilterType GetFilterType() const { return m_filter_type; } 135 : 0 : const uint256& GetBlockHash() const LIFETIMEBOUND { return m_block_hash; } 136 : 0 : const GCSFilter& GetFilter() const LIFETIMEBOUND { return m_filter; } 137 : : 138 : 0 : const std::vector<unsigned char>& GetEncodedFilter() const LIFETIMEBOUND 139 : : { 140 : 0 : return m_filter.GetEncoded(); 141 : : } 142 : : 143 : : //! Compute the filter hash. 144 : : uint256 GetHash() const; 145 : : 146 : : //! Compute the filter header given the previous one. 147 : : uint256 ComputeHeader(const uint256& prev_header) const; 148 : : 149 : : template <typename Stream> 150 : 0 : void Serialize(Stream& s) const { 151 : 0 : s << static_cast<uint8_t>(m_filter_type) 152 : 0 : << m_block_hash 153 : 0 : << m_filter.GetEncoded(); 154 : 0 : } 155 : : 156 : : template <typename Stream> 157 : 0 : void Unserialize(Stream& s) { 158 : 0 : std::vector<unsigned char> encoded_filter; 159 : : uint8_t filter_type; 160 : : 161 [ # # ]: 0 : s >> filter_type 162 [ # # ]: 0 : >> m_block_hash 163 [ # # ]: 0 : >> encoded_filter; 164 : : 165 : 0 : m_filter_type = static_cast<BlockFilterType>(filter_type); 166 : : 167 [ # # ]: 0 : GCSFilter::Params params; 168 [ # # ][ # # ]: 0 : if (!BuildParams(params)) { 169 [ # # ][ # # ]: 0 : throw std::ios_base::failure("unknown filter_type"); 170 : : } 171 [ # # ]: 0 : m_filter = GCSFilter(params, std::move(encoded_filter), /*skip_decode_check=*/false); 172 : 0 : } 173 : : }; 174 : : 175 : : #endif // BITCOIN_BLOCKFILTER_H