Move `FilterHash`, `FilterHeader` to `p2p`
What changed, and why it matters
This commit is a routine code reorganization: it moves two related data types, FilterHash and FilterHeader, from the main bitcoin crate into the p2p crate because they are used in peer-to-peer network messages. It also removes one test assertion that checked a now-removed helper method. There is no security fix or vulnerability here.
No security action required. Developers using these types should update imports from bitcoin::bip158 to p2p::message_filter (or the crate's public re-export).
Security signals we found
No strong security signals were identified.
Evidence from the diff
The patch relocates FilterHash and FilterHeader definitions from bitcoin/src/bip158.rs to p2p/src/message_filter.rs, updates imports accordingly, removes the deprecated re-exports in bitcoin/src/hash_types.rs, and deletes the BlockFilter::filter_header() helper and its test assertion. The consensus encoding logic is duplicated locally in p2p via a private macro. This is an API refactor with no cryptographic or memory-safety changes.
Changed components
bitcoin/src/bip158.rsbitcoin/src/consensus/encode.rsbitcoin/src/hash_types.rsbitcoin/src/internal_macros.rsp2p/src/message.rsp2p/src/message_filter.rsInspect captured patch +58 / −89
diff --git a/bitcoin/src/bip158.rs b/bitcoin/src/bip158.rs
index 1ac7d3bb..637b50e0 100644
--- a/bitcoin/src/bip158.rs
+++ b/bitcoin/src/bip158.rs
@@ -41,16 +41,13 @@ use core::cmp::{self, Ordering};
use core::convert::Infallible;
use core::fmt;
-#[cfg(feature = "arbitrary")]
-use arbitrary::{Arbitrary, Unstructured};
-use hashes::{sha256d, siphash24, HashEngine as _};
+use hashes::{sha256d, siphash24};
use internals::array::ArrayExt as _;
use internals::{write_err, ToU64 as _};
use io::{BufRead, Write};
use crate::block::{Block, BlockHash, Checked};
use crate::consensus::{ReadExt, WriteExt};
-use crate::internal_macros;
use crate::prelude::{BTreeSet, Borrow, Vec};
use crate::script::{ScriptPubKey, ScriptPubKeyExt as _};
use crate::transaction::OutPoint;
@@ -59,20 +56,6 @@ use crate::transaction::OutPoint;
const P: u8 = 19;
const M: u64 = 784931;
-hashes::hash_newtype! {
- /// Filter hash, as defined in BIP-0157.
- pub struct FilterHash(sha256d::Hash);
- /// Filter header, as defined in BIP-0157.
- pub struct FilterHeader(sha256d::Hash);
-}
-
-hashes::impl_hex_for_newtype!(FilterHash, FilterHeader);
-#[cfg(feature = "serde")]
-hashes::impl_serde_for_newtype!(FilterHash, FilterHeader);
-
-internal_macros::impl_hashencode!(FilterHash);
-internal_macros::impl_hashencode!(FilterHeader);
-
/// Errors for blockfilter.
#[derive(Debug)]
#[non_exhaustive]
@@ -117,15 +100,6 @@ pub struct BlockFilter {
pub content: Vec<u8>,
}
-impl FilterHash {
- /// Computes the filter header from a filter hash and previous filter header.
- pub fn filter_header(&self, previous_filter_header: FilterHeader) -> FilterHeader {
- let mut engine = sha256d::Hash::engine();
- engine.input(self.as_ref());
- engine.input(previous_filter_header.as_ref());
- FilterHeader(sha256d::Hash::from_engine(engine))
- }
-}
impl BlockFilter {
/// Constructs a new filter from pre-computed data.
@@ -150,17 +124,9 @@ impl BlockFilter {
Ok(Self { content: out })
}
- /// Computes this filter's ID in a chain of filters (see [BIP 157]).
- ///
- /// [BIP-0157]: <https://github.com/bitcoin/bips/blob/master/bip-0157.mediawiki#Filter_Headers>
- pub fn filter_header(&self, previous_filter_header: FilterHeader) -> FilterHeader {
- FilterHash(sha256d::Hash::hash(&self.content)).filter_header(previous_filter_header)
- }
-
/// Computes the canonical hash for the given filter.
- pub fn filter_hash(&self) -> FilterHash {
- let hash = sha256d::Hash::hash(&self.content);
- FilterHash(hash)
+ pub fn filter_hash(&self) -> sha256d::Hash {
+ sha256d::Hash::hash(&self.content)
}
/// Returns true if any query matches against this [`BlockFilter`].
@@ -572,19 +538,6 @@ impl<'a, W: Write> BitStreamWriter<'a, W> {
}
}
-#[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for FilterHash {
- fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
- Ok(Self::from_byte_array(u.arbitrary()?))
- }
-}
-
-#[cfg(feature = "arbitrary")]
-impl<'a> Arbitrary<'a> for FilterHeader {
- fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
- Ok(Self::from_byte_array(u.arbitrary()?))
- }
-}
#[cfg(test)]
mod test {
@@ -611,11 +564,7 @@ mod test {
let block = block.assume_checked(None);
assert_eq!(block.block_hash(), block_hash);
let scripts = t.get(3).unwrap().as_array().unwrap();
- let previous_filter_header =
- t.get(4).unwrap().as_str().unwrap().parse::<FilterHeader>().unwrap();
let filter_content = hex(t.get(5).unwrap().as_str().unwrap());
- let filter_header =
- t.get(6).unwrap().as_str().unwrap().parse::<FilterHeader>().unwrap();
let mut txmap = HashMap::new();
let mut si = scripts.iter();
@@ -661,8 +610,6 @@ mod test {
.unwrap());
}
}
-
- assert_eq!(filter_header, filter.filter_header(previous_filter_header));
}
}
diff --git a/bitcoin/src/consensus/encode.rs b/bitcoin/src/consensus/encode.rs
index 69181dd7..c9edbc6b 100644
--- a/bitcoin/src/consensus/encode.rs
+++ b/bitcoin/src/consensus/encode.rs
@@ -684,7 +684,6 @@ mod tests {
use core::mem::discriminant;
use super::*;
- use crate::bip158::FilterHash;
use crate::block::BlockHash;
use crate::merkle_tree::TxMerkleNode;
use crate::prelude::{Cow, Vec};
@@ -1008,7 +1007,6 @@ mod tests {
test_len_is_max_vec::<u8>();
test_len_is_max_vec::<BlockHash>();
- test_len_is_max_vec::<FilterHash>();
test_len_is_max_vec::<TxMerkleNode>();
test_len_is_max_vec::<Transaction>();
test_len_is_max_vec::<TxOut>();
diff --git a/bitcoin/src/hash_types.rs b/bitcoin/src/hash_types.rs
index 296e1f13..9f63e8b0 100644
--- a/bitcoin/src/hash_types.rs
+++ b/bitcoin/src/hash_types.rs
@@ -4,8 +4,6 @@
//!
//! This module is deprecated. You can find hash types in their respective, hopefully obvious, modules.
-#[deprecated(since = "TBD", note = "use `crate::T` instead")]
-pub use crate::bip158::{FilterHash, FilterHeader};
#[deprecated(since = "TBD", note = "use `crate::T` instead")]
pub use crate::{BlockHash, TxMerkleNode, Txid, WitnessCommitment, WitnessMerkleNode, Wtxid};
@@ -93,13 +91,5 @@ mod tests {
"b472a266d0bd89c13706a4132ccfb16f7c3b9fcb",
);
- assert_eq!(
- FilterHash::from_byte_array(DUMMY32).to_string(),
- "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d",
- );
- assert_eq!(
- FilterHeader::from_byte_array(DUMMY32).to_string(),
- "56944c5d3f98413ef45cf54545538103cc9f298e0575820ad3591376e2e0f65d",
- );
}
}
diff --git a/bitcoin/src/internal_macros.rs b/bitcoin/src/internal_macros.rs
index da38582b..34d3e38e 100644
--- a/bitcoin/src/internal_macros.rs
+++ b/bitcoin/src/internal_macros.rs
@@ -174,24 +174,6 @@ macro_rules! impl_array_newtype_stringify {
}
pub(crate) use impl_array_newtype_stringify;
-#[rustfmt::skip]
-macro_rules! impl_hashencode {
- ($hashtype:ident) => {
- impl $crate::consensus::Encodable for $hashtype {
- fn consensus_encode<W: $crate::io::Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, $crate::io::Error> {
- self.as_byte_array().consensus_encode(w)
- }
- }
-
- impl $crate::consensus::Decodable for $hashtype {
- fn consensus_decode<R: $crate::io::BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, $crate::consensus::encode::Error> {
- Ok(Self::from_byte_array(<<$hashtype as $crate::hashes::Hash>::Bytes>::consensus_decode(r)?))
- }
- }
- };
-}
-pub(crate) use impl_hashencode;
-
#[rustfmt::skip]
macro_rules! impl_asref_push_bytes {
($($hashtype:ident),*) => {
diff --git a/p2p/src/message.rs b/p2p/src/message.rs
index b501491c..6581afde 100644
--- a/p2p/src/message.rs
+++ b/p2p/src/message.rs
@@ -1667,7 +1667,6 @@ mod test {
use alloc::vec;
use std::net::Ipv4Addr;
- use bitcoin::bip158::{FilterHash, FilterHeader};
use bitcoin::block::{Block, BlockHash};
use bitcoin::consensus::encode::{deserialize, deserialize_partial, serialize};
use bitcoin::transaction::{Transaction, Txid};
@@ -1681,7 +1680,7 @@ mod test {
use crate::message_bloom::{BloomFlags, FilterAdd, FilterLoad};
use crate::message_compact_blocks::{GetBlockTxn, SendCmpct};
use crate::message_filter::{
- CFCheckpt, CFHeaders, CFilter, GetCFCheckpt, GetCFHeaders, GetCFilters,
+ CFCheckpt, CFHeaders, CFilter, FilterHash, FilterHeader, GetCFCheckpt, GetCFHeaders, GetCFilters,
};
use crate::message_network::{Alert, Reject, RejectReason, VersionMessage};
use crate::{ProtocolVersion, ServiceFlags};
diff --git a/p2p/src/message_filter.rs b/p2p/src/message_filter.rs
index a8a5a6b7..01ca9221 100644
--- a/p2p/src/message_filter.rs
+++ b/p2p/src/message_filter.rs
@@ -8,12 +8,65 @@ use alloc::vec::Vec;
#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};
-use bitcoin::bip158::{FilterHash, FilterHeader};
use bitcoin::block::BlockHash;
+use hashes::{sha256d, HashEngine};
use units::BlockHeight;
use crate::consensus::impl_consensus_encoding;
+hashes::hash_newtype! {
+ /// Filter hash, as defined in BIP-0157.
+ pub struct FilterHash(pub sha256d::Hash);
+ /// Filter header, as defined in BIP-0157.
+ pub struct FilterHeader(pub sha256d::Hash);
+}
+
+hashes::impl_hex_for_newtype!(FilterHash, FilterHeader);
+
+impl FilterHash {
+ /// Computes the filter header from a filter hash and previous filter header.
+ pub fn filter_header(&self, previous_filter_header: FilterHeader) -> FilterHeader {
+ let mut engine = sha256d::Hash::engine();
+ engine.input(self.as_ref());
+ engine.input(previous_filter_header.as_ref());
+ FilterHeader(sha256d::Hash::from_engine(engine))
+ }
+}
+
+#[rustfmt::skip]
+macro_rules! impl_hashencode {
+ ($hashtype:ident) => {
+ impl bitcoin::consensus::Encodable for $hashtype {
+ fn consensus_encode<W: bitcoin::io::Write + ?Sized>(&self, w: &mut W) -> core::result::Result<usize, bitcoin::io::Error> {
+ self.as_byte_array().consensus_encode(w)
+ }
+ }
+
+ impl bitcoin::consensus::Decodable for $hashtype {
+ fn consensus_decode<R: bitcoin::io::BufRead + ?Sized>(r: &mut R) -> core::result::Result<Self, bitcoin::consensus::encode::Error> {
+ Ok(Self::from_byte_array(<<$hashtype as hashes::Hash>::Bytes>::consensus_decode(r)?))
+ }
+ }
+ };
+}
+
+impl_hashencode!(FilterHash);
+impl_hashencode!(FilterHeader);
+
+#[cfg(feature = "arbitrary")]
+impl<'a> Arbitrary<'a> for FilterHash {
+ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
+ Ok(Self::from_byte_array(u.arbitrary()?))
+ }
+}
+
+#[cfg(feature = "arbitrary")]
+impl<'a> Arbitrary<'a> for FilterHeader {
+ fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
+ Ok(Self::from_byte_array(u.arbitrary()?))
+ }
+}
+
/// getcfilters message
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct GetCFilters {
Why this scored 18/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.