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,
}
pub fn hash256(data: &[u8]) -> Hash {
let mut hasher = Sha256::new();
hasher.update(data);
let first = hasher.finalize();
let mut hasher = Sha256::new();
hasher.update(first);
let hash_bytes = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&hash_bytes);
hash
}
pub fn hash256_concat(left: &[u8], right: &[u8]) -> Hash {
let mut hasher = Sha256::new();
hasher.update(left);
hasher.update(right);
let first_hash = hasher.finalize();
let mut hasher = Sha256::new();
hasher.update(first_hash);
let hash_bytes = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&hash_bytes);
hash
}
impl FilterHeader {
pub fn new(filter: &CompactBlockFilter, prev_header: Option<&FilterHeader>) -> Self {
let filter_hash = hash256(filter.filter_data.as_slice());
let prev_header_hash = if let Some(prev) = prev_header {
hash256_concat(&prev.filter_hash, &prev.prev_header_hash)
} else {
[0u8; 32]
};
FilterHeader {
filter_hash,
prev_header_hash,
}
}
pub fn header_hash(&self) -> Hash {
hash256_concat(&self.filter_hash, &self.prev_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: std::sync::Arc::new(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());
assert_eq!(
header1.header_hash(),
concat_hash256(&header1.filter_hash, &header1.prev_header_hash)
);
assert_eq!(
header2.header_hash(),
concat_hash256(&header2.filter_hash, &header2.prev_header_hash)
);
}
fn concat_hash256(left: &[u8], right: &[u8]) -> [u8; 32] {
use sha2::{Digest, Sha256};
let mut combined = Vec::new();
combined.extend_from_slice(left);
combined.extend_from_slice(right);
let mut hasher = Sha256::new();
hasher.update(&combined);
let first = hasher.finalize();
let mut hasher = Sha256::new();
hasher.update(first);
let bytes = hasher.finalize();
let mut hash = [0u8; 32];
hash.copy_from_slice(&bytes);
hash
}
}