Skip to content

Commit 03eae87

Browse files
committed
Abstract filter with base class
1 parent 3f09a47 commit 03eae87

7 files changed

Lines changed: 141 additions & 16 deletions

File tree

src/blockfilter.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -254,3 +254,63 @@ uint256 BlockFilter::ComputeHeader(const uint256& prev_header) const
254254
{
255255
return Hash(GetHash(), prev_header);
256256
}
257+
258+
// --- BlockFilterBase implementation ---
259+
260+
/**
261+
* GCS-based implementation of BlockFilterBase.
262+
* Wraps the existing BlockFilter class, exposing a clean interface
263+
* that operates on scripts rather than GCS internal elements.
264+
*/
265+
class GCSBlockFilter : public BlockFilterBase {
266+
public:
267+
explicit GCSBlockFilter(BlockFilter filter) : m_filter(std::move(filter)) {}
268+
269+
BlockFilterType GetFilterType() const override { return m_filter.GetFilterType(); }
270+
const uint256& GetBlockHash() const override { return m_filter.GetBlockHash(); }
271+
272+
bool Match(const CScript& script) const override {
273+
GCSFilter::Element element(script.begin(), script.end());
274+
return m_filter.GetFilter().Match(element);
275+
}
276+
277+
bool MatchAny(const std::vector<CScript>& scripts) const override {
278+
GCSFilter::ElementSet elements;
279+
for (const CScript& script : scripts) {
280+
elements.emplace(script.begin(), script.end());
281+
}
282+
return m_filter.GetFilter().MatchAny(elements);
283+
}
284+
285+
const std::vector<unsigned char>& GetEncodedFilter() const override {
286+
return m_filter.GetEncodedFilter();
287+
}
288+
289+
uint256 GetHash() const override { return m_filter.GetHash(); }
290+
291+
uint256 ComputeHeader(const uint256& prev_header) const override {
292+
return m_filter.ComputeHeader(prev_header);
293+
}
294+
295+
private:
296+
BlockFilter m_filter;
297+
};
298+
299+
// --- Factory functions ---
300+
301+
std::unique_ptr<BlockFilterBase> CreateBlockFilter(BlockFilterType type, const CBlock& block, const CBlockUndo& block_undo)
302+
{
303+
return std::make_unique<GCSBlockFilter>(BlockFilter(type, block, block_undo));
304+
}
305+
306+
std::unique_ptr<BlockFilterBase> CreateBlockFilter(BlockFilterType type, const uint256& block_hash, std::vector<unsigned char> encoded)
307+
{
308+
return std::make_unique<GCSBlockFilter>(BlockFilter(type, block_hash, std::move(encoded), /*skip_decode_check=*/false));
309+
}
310+
311+
std::unique_ptr<BlockFilterBase> CreateBlockFilter(BlockFilterType type, SpanReader& stream)
312+
{
313+
BlockFilter filter;
314+
filter.Unserialize(stream);
315+
return std::make_unique<GCSBlockFilter>(std::move(filter));
316+
}

src/blockfilter.h

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
#include <cstddef>
99
#include <cstdint>
1010
#include <ios>
11+
#include <memory>
1112
#include <set>
1213
#include <string>
1314
#include <string_view>
@@ -21,6 +22,8 @@
2122

2223
class CBlock;
2324
class CBlockUndo;
25+
class CScript;
26+
template<typename T> class Span;
2427

2528
/**
2629
* This implements a Golomb-coded set as defined in BIP 158. It is a
@@ -173,4 +176,45 @@ class BlockFilter
173176
}
174177
};
175178

179+
/**
180+
* Abstract interface for block filters.
181+
* Callers can query filters by script without knowing the internal encoding.
182+
*/
183+
class BlockFilterBase {
184+
public:
185+
virtual ~BlockFilterBase() = default;
186+
187+
//! Filter type
188+
virtual BlockFilterType GetFilterType() const = 0;
189+
190+
//! Block this filter is for
191+
virtual const uint256& GetBlockHash() const = 0;
192+
193+
//! Query: does the filter possibly contain this script?
194+
virtual bool Match(const CScript& script) const = 0;
195+
196+
//! Query: does the filter possibly contain any of these scripts?
197+
virtual bool MatchAny(const std::vector<CScript>& scripts) const = 0;
198+
199+
//! Serialized filter data (for P2P/storage)
200+
virtual const std::vector<unsigned char>& GetEncodedFilter() const = 0;
201+
202+
//! Filter hash (BIP 157)
203+
virtual uint256 GetHash() const = 0;
204+
205+
//! Filter header (BIP 157)
206+
virtual uint256 ComputeHeader(const uint256& prev_header) const = 0;
207+
};
208+
209+
/**
210+
* Create a block filter from a block and its undo data.
211+
* The filter type determines the encoding algorithm used internally.
212+
*/
213+
std::unique_ptr<BlockFilterBase> CreateBlockFilter(BlockFilterType type, const CBlock& block, const CBlockUndo& block_undo);
214+
215+
/**
216+
* Create a block filter from serialized data.
217+
*/
218+
std::unique_ptr<BlockFilterBase> CreateBlockFilter(BlockFilterType type, const uint256& block_hash, std::vector<unsigned char> encoded);
219+
176220
#endif // BITCOIN_BLOCKFILTER_H

src/index/blockfilterindex.cpp

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,7 @@ bool BlockFilterIndex::ReadFilterFromDisk(const FlatFilePos& pos, const uint256&
174174
return true;
175175
}
176176

177-
size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& filter)
177+
size_t BlockFilterIndex::WriteFilterToDisk(FlatFilePos& pos, const BlockFilterBase& filter)
178178
{
179179
assert(filter.GetFilterType() == GetFilterType());
180180

@@ -249,14 +249,14 @@ std::optional<uint256> BlockFilterIndex::ReadFilterHeader(int height, const uint
249249

250250
bool BlockFilterIndex::CustomAppend(const interfaces::BlockInfo& block)
251251
{
252-
BlockFilter filter(m_filter_type, *Assert(block.data), *Assert(block.undo_data));
253-
const uint256& header = filter.ComputeHeader(m_last_header);
254-
bool res = Write(filter, block.height, header);
252+
std::unique_ptr<BlockFilterBase> filter = CreateBlockFilter(m_filter_type, *Assert(block.data), *Assert(block.undo_data));
253+
const uint256& header = filter->ComputeHeader(m_last_header);
254+
bool res = Write(*filter, block.height, header);
255255
if (res) m_last_header = header; // update last header
256256
return res;
257257
}
258258

259-
bool BlockFilterIndex::Write(const BlockFilter& filter, uint32_t block_height, const uint256& filter_header)
259+
bool BlockFilterIndex::Write(const BlockFilterBase& filter, uint32_t block_height, const uint256& filter_header)
260260
{
261261
size_t bytes_written = WriteFilterToDisk(m_next_filter_pos, filter);
262262
if (bytes_written == 0) return false;
@@ -365,6 +365,21 @@ bool BlockFilterIndex::LookupFilter(const CBlockIndex* block_index, BlockFilter&
365365
return ReadFilterFromDisk(entry.pos, entry.hash, filter_out);
366366
}
367367

368+
std::unique_ptr<BlockFilterBase> BlockFilterIndex::LookupFilter(const CBlockIndex* block_index) const
369+
{
370+
DBVal entry;
371+
if (!index_util::LookUpOne(*m_db, {block_index->GetBlockHash(), block_index->nHeight}, entry)) {
372+
return nullptr;
373+
}
374+
375+
BlockFilter filter;
376+
if (!ReadFilterFromDisk(entry.pos, entry.hash, filter)) {
377+
return nullptr;
378+
}
379+
380+
return CreateBlockFilter(filter.GetFilterType(), filter.GetBlockHash(), filter.GetEncodedFilter());
381+
}
382+
368383
bool BlockFilterIndex::LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out)
369384
{
370385
LOCK(m_cs_headers_cache);

src/index/blockfilterindex.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ class BlockFilterIndex final : public BaseIndex
4747
std::unique_ptr<FlatFileSeq> m_filter_fileseq;
4848

4949
bool ReadFilterFromDisk(const FlatFilePos& pos, const uint256& hash, BlockFilter& filter) const;
50-
size_t WriteFilterToDisk(FlatFilePos& pos, const BlockFilter& filter);
50+
size_t WriteFilterToDisk(FlatFilePos& pos, const BlockFilterBase& filter);
5151

5252
Mutex m_cs_headers_cache;
5353
/** cache of block hash to filter header, to avoid disk access when responding to getcfcheckpt. */
@@ -58,7 +58,7 @@ class BlockFilterIndex final : public BaseIndex
5858

5959
bool AllowPrune() const override { return true; }
6060

61-
bool Write(const BlockFilter& filter, uint32_t block_height, const uint256& filter_header);
61+
bool Write(const BlockFilterBase& filter, uint32_t block_height, const uint256& filter_header);
6262

6363
std::optional<uint256> ReadFilterHeader(int height, const uint256& expected_block_hash);
6464

@@ -85,6 +85,9 @@ class BlockFilterIndex final : public BaseIndex
8585
/** Get a single filter by block. */
8686
bool LookupFilter(const CBlockIndex* block_index, BlockFilter& filter_out) const;
8787

88+
/** Get a single filter by block (returns interface pointer). */
89+
std::unique_ptr<BlockFilterBase> LookupFilter(const CBlockIndex* block_index) const;
90+
8891
/** Get a single filter header by block. */
8992
bool LookupFilterHeader(const CBlockIndex* block_index, uint256& header_out) EXCLUSIVE_LOCKS_REQUIRED(!m_cs_headers_cache);
9093

src/interfaces/chain.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,9 +139,9 @@ class Chain
139139
//! Returns whether a block filter index is available.
140140
virtual bool hasBlockFilterIndex(BlockFilterType filter_type) = 0;
141141

142-
//! Returns whether any of the elements match the block via a BIP 157 block filter
142+
//! Returns whether any of the scripts match the block via a BIP 157 block filter
143143
//! or std::nullopt if the block filter for this block couldn't be found.
144-
virtual std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) = 0;
144+
virtual std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const std::vector<CScript>& scripts) = 0;
145145

146146
//! Return whether node has the block and optionally return block metadata
147147
//! or contents.

src/node/interfaces.cpp

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
#include <net_processing.h>
3333
#include <netaddress.h>
3434
#include <netbase.h>
35+
#include <script/script.h>
3536
#include <node/blockstorage.h>
3637
#include <node/coin.h>
3738
#include <node/context.h>
@@ -576,15 +577,17 @@ class ChainImpl : public Chain
576577
{
577578
return GetBlockFilterIndex(filter_type) != nullptr;
578579
}
579-
std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const GCSFilter::ElementSet& filter_set) override
580+
std::optional<bool> blockFilterMatchesAny(BlockFilterType filter_type, const uint256& block_hash, const std::vector<CScript>& scripts) override
580581
{
581582
const BlockFilterIndex* block_filter_index{GetBlockFilterIndex(filter_type)};
582583
if (!block_filter_index) return std::nullopt;
583584

584-
BlockFilter filter;
585585
const CBlockIndex* index{WITH_LOCK(::cs_main, return chainman().m_blockman.LookupBlockIndex(block_hash))};
586-
if (index == nullptr || !block_filter_index->LookupFilter(index, filter)) return std::nullopt;
587-
return filter.GetFilter().MatchAny(filter_set);
586+
if (!index) return std::nullopt;
587+
588+
std::unique_ptr<BlockFilterBase> filter = block_filter_index->LookupFilter(index);
589+
if (!filter) return std::nullopt;
590+
return filter->MatchAny(scripts);
588591
}
589592
bool findBlock(const uint256& hash, const FoundBlock& block) override
590593
{

src/wallet/wallet.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ class FastWalletRescanFilter
338338

339339
std::optional<bool> MatchesBlock(const uint256& block_hash) const
340340
{
341-
return m_wallet.chain().blockFilterMatchesAny(BlockFilterType::BASIC, block_hash, m_filter_set);
341+
return m_wallet.chain().blockFilterMatchesAny(BlockFilterType::BASIC, block_hash, m_scripts);
342342
}
343343

344344
private:
@@ -350,12 +350,12 @@ class FastWalletRescanFilter
350350
* take possible keypool top-ups into account.
351351
*/
352352
std::map<uint256, int32_t> m_last_range_ends;
353-
GCSFilter::ElementSet m_filter_set;
353+
std::vector<CScript> m_scripts;
354354

355355
void AddScriptPubKeys(const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
356356
{
357357
for (const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
358-
m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
358+
m_scripts.push_back(script_pub_key);
359359
}
360360
}
361361
};

0 commit comments

Comments
 (0)