1use super::bip158::CompactBlockFilter;
9use crate::Hash;
10use sha2::{Digest, Sha256};
11
12#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct FilterHeader {
15 pub filter_hash: Hash,
17 pub prev_header_hash: Hash,
19}
20
21pub fn hash256(data: &[u8]) -> Hash {
23 let mut hasher = Sha256::new();
24 hasher.update(data);
25 let first = hasher.finalize();
26
27 let mut hasher = Sha256::new();
28 hasher.update(first);
29 let hash_bytes = hasher.finalize();
30
31 let mut hash = [0u8; 32];
32 hash.copy_from_slice(&hash_bytes);
33 hash
34}
35
36pub fn hash256_concat(left: &[u8], right: &[u8]) -> Hash {
38 let mut hasher = Sha256::new();
39 hasher.update(left);
40 hasher.update(right);
41 let first_hash = hasher.finalize();
42
43 let mut hasher = Sha256::new();
44 hasher.update(first_hash);
45 let hash_bytes = hasher.finalize();
46
47 let mut hash = [0u8; 32];
48 hash.copy_from_slice(&hash_bytes);
49 hash
50}
51
52impl FilterHeader {
53 pub fn new(filter: &CompactBlockFilter, prev_header: Option<&FilterHeader>) -> Self {
55 let filter_hash = hash256(filter.filter_data.as_slice());
56
57 let prev_header_hash = if let Some(prev) = prev_header {
59 hash256_concat(&prev.filter_hash, &prev.prev_header_hash)
60 } else {
61 [0u8; 32]
63 };
64
65 FilterHeader {
66 filter_hash,
67 prev_header_hash,
68 }
69 }
70
71 pub fn header_hash(&self) -> Hash {
73 hash256_concat(&self.filter_hash, &self.prev_header_hash)
74 }
75}
76
77#[derive(Debug, Clone, Copy, PartialEq, Eq)]
79pub enum FilterType {
80 Basic = 0,
82}
83
84impl FilterType {
85 pub fn from_u8(value: u8) -> Option<Self> {
86 match value {
87 0 => Some(FilterType::Basic),
88 _ => None,
89 }
90 }
91
92 pub fn to_u8(self) -> u8 {
93 self as u8
94 }
95}
96
97#[derive(Debug, Clone)]
99pub struct GetCfilters {
100 pub filter_type: FilterType,
102 pub start_height: u32,
104 pub stop_hash: Hash,
106}
107
108#[derive(Debug, Clone)]
110pub struct CFilter {
111 pub filter_type: FilterType,
113 pub block_hash: Hash,
115 pub filter: CompactBlockFilter,
117}
118
119#[derive(Debug, Clone)]
121pub struct GetCfheaders {
122 pub filter_type: FilterType,
124 pub start_height: u32,
126 pub stop_hash: Hash,
128}
129
130#[derive(Debug, Clone)]
132pub struct Cfheaders {
133 pub filter_type: FilterType,
135 pub stop_hash: Hash,
137 pub prev_header: FilterHeader,
139 pub filter_headers: Vec<Hash>,
141}
142
143#[derive(Debug, Clone)]
145pub struct GetCfcheckpt {
146 pub filter_type: FilterType,
148 pub stop_hash: Hash,
150}
151
152#[derive(Debug, Clone)]
154pub struct Cfcheckpt {
155 pub filter_type: FilterType,
157 pub stop_hash: Hash,
159 pub filter_header_hashes: Vec<Hash>,
161}
162
163pub const NODE_COMPACT_FILTERS: u64 = 1 << 6;
165
166#[cfg(test)]
167mod tests {
168 use super::*;
169
170 #[test]
171 fn test_filter_header() {
172 let empty_filter = CompactBlockFilter {
173 filter_data: std::sync::Arc::new(vec![1, 2, 3]),
174 num_elements: 0,
175 };
176
177 let header1 = FilterHeader::new(&empty_filter, None);
178 let header2 = FilterHeader::new(&empty_filter, Some(&header1));
179
180 assert_eq!(header1.filter_hash, header2.filter_hash);
182 assert_ne!(header1.header_hash(), header2.header_hash());
184 assert_eq!(header2.prev_header_hash, header1.header_hash());
185 assert_eq!(
186 header1.header_hash(),
187 concat_hash256(&header1.filter_hash, &header1.prev_header_hash)
188 );
189 assert_eq!(
190 header2.header_hash(),
191 concat_hash256(&header2.filter_hash, &header2.prev_header_hash)
192 );
193 }
194
195 fn concat_hash256(left: &[u8], right: &[u8]) -> [u8; 32] {
196 use sha2::{Digest, Sha256};
197 let mut combined = Vec::new();
198 combined.extend_from_slice(left);
199 combined.extend_from_slice(right);
200 let mut hasher = Sha256::new();
201 hasher.update(&combined);
202 let first = hasher.finalize();
203 let mut hasher = Sha256::new();
204 hasher.update(first);
205 let bytes = hasher.finalize();
206 let mut hash = [0u8; 32];
207 hash.copy_from_slice(&bytes);
208 hash
209 }
210}