use super::bip158::CompactBlockFilter;
use crate::Hash;
use sha2::{Digest, Sha256};
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct FilterHeader {
pub filter_hash: Hash,
pub prev_header_hash: Hash,
}
impl FilterHeader {
pub fn new(filter: &CompactBlockFilter, prev_header: Option<&FilterHeader>) -> Self {
let mut hasher = Sha256::new();
hasher.update(&filter.filter_data);
let first_hash = hasher.finalize();
let mut hasher2 = Sha256::new();
hasher2.update(first_hash);
let filter_hash_bytes = hasher2.finalize();
let mut filter_hash = [0u8; 32];
filter_hash.copy_from_slice(&filter_hash_bytes);
let prev_header_hash = if let Some(prev) = prev_header {
let mut combined = Vec::new();
combined.extend_from_slice(&prev.filter_hash);
combined.extend_from_slice(&prev.prev_header_hash);
let mut hasher = Sha256::new();
hasher.update(&combined);
let first_hash = hasher.finalize();
let mut hasher2 = Sha256::new();
hasher2.update(first_hash);
let header_hash_bytes = hasher2.finalize();
let mut header_hash = [0u8; 32];
header_hash.copy_from_slice(&header_hash_bytes);
header_hash
} else {
[0u8; 32]
};
FilterHeader {
filter_hash,
prev_header_hash,
}
}
pub fn header_hash(&self) -> Hash {
let mut combined = Vec::new();
combined.extend_from_slice(&self.filter_hash);
combined.extend_from_slice(&self.prev_header_hash);
let mut hasher = Sha256::new();
hasher.update(&combined);
let first_hash = hasher.finalize();
let mut hasher2 = Sha256::new();
hasher2.update(first_hash);
let hash_bytes = hasher2.finalize();
let mut header_hash = [0u8; 32];
header_hash.copy_from_slice(&hash_bytes);
header_hash
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum FilterType {
Basic = 0,
}
impl FilterType {
pub fn from_u8(value: u8) -> Option<Self> {
match value {
0 => Some(FilterType::Basic),
_ => None,
}
}
pub fn to_u8(self) -> u8 {
self as u8
}
}
#[derive(Debug, Clone)]
pub struct GetCfilters {
pub filter_type: FilterType,
pub start_height: u32,
pub stop_hash: Hash,
}
#[derive(Debug, Clone)]
pub struct CFilter {
pub filter_type: FilterType,
pub block_hash: Hash,
pub filter: CompactBlockFilter,
}
#[derive(Debug, Clone)]
pub struct GetCfheaders {
pub filter_type: FilterType,
pub start_height: u32,
pub stop_hash: Hash,
}
#[derive(Debug, Clone)]
pub struct Cfheaders {
pub filter_type: FilterType,
pub stop_hash: Hash,
pub prev_header: FilterHeader,
pub filter_headers: Vec<Hash>,
}
#[derive(Debug, Clone)]
pub struct GetCfcheckpt {
pub filter_type: FilterType,
pub stop_hash: Hash,
}
#[derive(Debug, Clone)]
pub struct Cfcheckpt {
pub filter_type: FilterType,
pub stop_hash: Hash,
pub filter_header_hashes: Vec<Hash>,
}
pub const NODE_COMPACT_FILTERS: u64 = 1 << 6;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_filter_header() {
let empty_filter = CompactBlockFilter {
filter_data: vec![1, 2, 3],
num_elements: 0,
};
let header1 = FilterHeader::new(&empty_filter, None);
let header2 = FilterHeader::new(&empty_filter, Some(&header1));
assert_eq!(header1.filter_hash, header2.filter_hash);
assert_ne!(header1.header_hash(), header2.header_hash());
assert_eq!(header2.prev_header_hash, header1.header_hash());
}
}