From 2290d2f30f5d658aa6619a6ca0265723c28c6f32 Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Thu, 15 Jan 2026 14:00:32 +0000 Subject: [PATCH 1/2] index: Implement taproot-only GCS filter --- src/blockfilter.cpp | 38 +++++++++++++++++++++++++++++++++++++- src/blockfilter.h | 1 + 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/src/blockfilter.cpp b/src/blockfilter.cpp index 44d08440d136..bdeb0ef2ed59 100644 --- a/src/blockfilter.cpp +++ b/src/blockfilter.cpp @@ -21,6 +21,7 @@ using util::Join; static const std::map g_filter_types = { {BlockFilterType::BASIC, "basic"}, + {BlockFilterType::TAPROOT, "taproot"}, }; uint64_t GCSFilter::HashToRange(const Element& element) const @@ -208,6 +209,30 @@ static GCSFilter::ElementSet BasicFilterElements(const CBlock& block, return elements; } +static GCSFilter::ElementSet TaprootFilterElements(const CBlock& block, + const CBlockUndo& block_undo) +{ + GCSFilter::ElementSet elements; + + for (const CTransactionRef& tx : block.vtx) { + for (const CTxOut& txout : tx->vout) { + const CScript& script = txout.scriptPubKey; + if (!script.IsPayToTaproot() || script.empty()) continue; + elements.emplace(script.begin(), script.end()); + } + } + + for (const CTxUndo& tx_undo : block_undo.vtxundo) { + for (const Coin& prevout : tx_undo.vprevout) { + const CScript& script = prevout.out.scriptPubKey; + if (!script.IsPayToTaproot() || script.empty()) continue; + elements.emplace(script.begin(), script.end()); + } + } + + return elements; +} + BlockFilter::BlockFilter(BlockFilterType filter_type, const uint256& block_hash, std::vector filter, bool skip_decode_check) : m_filter_type(filter_type), m_block_hash(block_hash) @@ -226,7 +251,12 @@ BlockFilter::BlockFilter(BlockFilterType filter_type, const CBlock& block, const if (!BuildParams(params)) { throw std::invalid_argument("unknown filter_type"); } - m_filter = GCSFilter(params, BasicFilterElements(block, block_undo)); + if (filter_type == BlockFilterType::BASIC) { + m_filter = GCSFilter(params, BasicFilterElements(block, block_undo)); + } + if (filter_type == BlockFilterType::TAPROOT) { + m_filter = GCSFilter(params, TaprootFilterElements(block, block_undo)); + } } bool BlockFilter::BuildParams(GCSFilter::Params& params) const @@ -238,6 +268,12 @@ bool BlockFilter::BuildParams(GCSFilter::Params& params) const params.m_P = BASIC_FILTER_P; params.m_M = BASIC_FILTER_M; return true; + case BlockFilterType::TAPROOT: + params.m_siphash_k0 = m_block_hash.GetUint64(0); + params.m_siphash_k1 = m_block_hash.GetUint64(1); + params.m_P = BASIC_FILTER_P; + params.m_M = BASIC_FILTER_M; + return true; case BlockFilterType::INVALID: return false; } diff --git a/src/blockfilter.h b/src/blockfilter.h index 225d3b16bede..b40ca6c97e74 100644 --- a/src/blockfilter.h +++ b/src/blockfilter.h @@ -93,6 +93,7 @@ constexpr uint32_t BASIC_FILTER_M = 784931; enum class BlockFilterType : uint8_t { BASIC = 0, + TAPROOT = 1, INVALID = 255, }; From 7528e6e972b047d6d7e55154be4d1f7f635c24db Mon Sep 17 00:00:00 2001 From: rustaceanrob Date: Thu, 15 Jan 2026 15:40:00 +0000 Subject: [PATCH 2/2] net, init: Support taproot filters --- src/init.cpp | 2 +- src/net_processing.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/init.cpp b/src/init.cpp index 571d8b9c02d1..1cceeaffd33e 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -977,7 +977,7 @@ bool AppInitParameterInteraction(const ArgsManager& args) // Signal NODE_COMPACT_FILTERS if peerblockfilters and basic filters index are both enabled. if (args.GetBoolArg("-peerblockfilters", DEFAULT_PEERBLOCKFILTERS)) { - if (!g_enabled_filter_types.contains(BlockFilterType::BASIC)) { + if (!g_enabled_filter_types.contains(BlockFilterType::BASIC) && !g_enabled_filter_types.contains(BlockFilterType::TAPROOT)) { return InitError(_("Cannot set -peerblockfilters without -blockfilterindex.")); } diff --git a/src/net_processing.cpp b/src/net_processing.cpp index 1202eaf15253..3481cb7f9d0b 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -3237,7 +3237,7 @@ bool PeerManagerImpl::PrepareBlockFilterRequest(CNode& node, Peer& peer, BlockFilterIndex*& filter_index) { const bool supported_filter_type = - (filter_type == BlockFilterType::BASIC && + ((filter_type == BlockFilterType::BASIC || filter_type == BlockFilterType::TAPROOT) && (peer.m_our_services & NODE_COMPACT_FILTERS)); if (!supported_filter_type) { LogDebug(BCLog::NET, "peer requested unsupported block filter type: %d, %s\n",