diff --git a/src/Makefile.test.include b/src/Makefile.test.include --- a/src/Makefile.test.include +++ b/src/Makefile.test.include @@ -15,6 +15,7 @@ test/data/base58_keys_valid.json \ test/data/base58_encode_decode.json \ test/data/base58_keys_invalid.json \ + test/data/blockfilters.json \ test/data/tx_invalid.json \ test/data/tx_valid.json \ test/data/sighash.json diff --git a/src/blockfilter.h b/src/blockfilter.h --- a/src/blockfilter.h +++ b/src/blockfilter.h @@ -5,8 +5,10 @@ #ifndef BITCOIN_BLOCKFILTER_H #define BITCOIN_BLOCKFILTER_H +#include #include #include +#include #include #include @@ -71,4 +73,66 @@ bool MatchAny(const ElementSet &elements) const; }; +constexpr uint8_t BASIC_FILTER_P = 19; +constexpr uint32_t BASIC_FILTER_M = 784931; + +enum BlockFilterType : uint8_t { + BASIC = 0, +}; + +/** + * Complete block filter struct as defined in BIP 157. Serialization matches + * payload of "cfilter" messages. + */ +class BlockFilter { +private: + BlockFilterType m_filter_type; + uint256 m_block_hash; + GCSFilter m_filter; + +public: + // Construct a new BlockFilter of the specified type from a block. + BlockFilter(BlockFilterType filter_type, const CBlock &block, + const CBlockUndo &block_undo); + + BlockFilterType GetFilterType() const { return m_filter_type; } + + const GCSFilter &GetFilter() const { return m_filter; } + + const std::vector &GetEncodedFilter() const { + return m_filter.GetEncoded(); + } + + // Compute the filter hash. + uint256 GetHash() const; + + // Compute the filter header given the previous one. + uint256 ComputeHeader(const uint256 &prev_header) const; + + template void Serialize(Stream &s) const { + s << m_block_hash << static_cast(m_filter_type) + << m_filter.GetEncoded(); + } + + template void Unserialize(Stream &s) { + std::vector encoded_filter; + uint8_t filter_type; + + s >> m_block_hash >> filter_type >> encoded_filter; + + m_filter_type = static_cast(filter_type); + + switch (m_filter_type) { + case BlockFilterType::BASIC: + m_filter = GCSFilter(m_block_hash.GetUint64(0), + m_block_hash.GetUint64(1), BASIC_FILTER_P, + BASIC_FILTER_M, std::move(encoded_filter)); + break; + + default: + throw std::ios_base::failure("unknown filter_type"); + } + } +}; + #endif // BITCOIN_BLOCKFILTER_H diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -4,6 +4,9 @@ #include #include +#include +#include +#include