nakamoto_test/block/cache/
model.rs1use std::ops::RangeInclusive;
5
6use nakamoto_common::bitcoin_hashes::Hash;
7use nakamoto_common::block::filter::{self, BlockFilter, FilterHash, FilterHeader, Filters};
8use nakamoto_common::block::iter::Iter;
9use nakamoto_common::block::tree::{BlockReader, BlockTree, Branch, Error, ImportResult};
10use nakamoto_common::block::Height;
11use nakamoto_common::nonempty::NonEmpty;
12
13use std::collections::{BTreeMap, HashMap, VecDeque};
14
15use nakamoto_common::bitcoin::blockdata::block::BlockHeader;
16use nakamoto_common::bitcoin::hash_types::BlockHash;
17
18#[derive(Debug, Clone)]
19pub struct Cache {
20 pub headers: HashMap<BlockHash, BlockHeader>,
21 pub chain: NonEmpty<BlockHeader>,
22 pub tip: BlockHash,
23 pub genesis: BlockHash,
24}
25
26impl Cache {
27 pub fn new(genesis: BlockHeader) -> Self {
28 let mut headers = HashMap::new();
29 let hash = genesis.block_hash();
30 let chain = NonEmpty::new(genesis);
31
32 headers.insert(hash, genesis);
33
34 Self {
35 headers,
36 chain,
37 tip: hash,
38 genesis: hash,
39 }
40 }
41
42 pub fn from(chain: NonEmpty<BlockHeader>) -> Self {
43 let genesis = chain.head.block_hash();
44 let tip = chain.last().block_hash();
45
46 let mut headers = HashMap::new();
47 for h in chain.iter() {
48 headers.insert(h.block_hash(), *h);
49 }
50
51 Self {
52 headers,
53 chain,
54 tip,
55 genesis,
56 }
57 }
58
59 pub fn rollback(&mut self, height: Height) -> Result<(), Error> {
60 for block in self.chain.tail.drain(height as usize..) {
61 self.headers.remove(&block.block_hash());
62 }
63 Ok(())
64 }
65
66 fn branch(&self, tip: &BlockHash) -> Option<NonEmpty<BlockHeader>> {
67 let mut headers = VecDeque::new();
68 let mut tip = *tip;
69
70 while let Some(header) = self.headers.get(&tip) {
71 tip = header.prev_blockhash;
72 headers.push_front(*header);
73 }
74
75 match headers.pop_front() {
76 Some(root) if root.block_hash() == self.genesis => {
77 Some(NonEmpty::from((root, headers.into())))
78 }
79 _ => None,
80 }
81 }
82
83 fn longest_chain(&self) -> NonEmpty<BlockHeader> {
84 let mut branches = Vec::new();
85
86 for tip in self.headers.keys() {
87 if let Some(branch) = self.branch(tip) {
88 branches.push(branch);
89 }
90 }
91
92 branches
93 .into_iter()
94 .max_by(|a, b| {
95 let a_work = Branch(&a.tail).work();
96 let b_work = Branch(&b.tail).work();
97
98 if a_work == b_work {
99 let a_hash = a.last().block_hash();
100 let b_hash = b.last().block_hash();
101
102 b_hash.cmp(&a_hash)
103 } else {
104 a_work.cmp(&b_work)
105 }
106 })
107 .unwrap()
108 }
109}
110
111impl BlockTree for Cache {
112 fn import_blocks<I: Iterator<Item = BlockHeader>, C>(
113 &mut self,
114 chain: I,
115 _context: &C,
116 ) -> Result<ImportResult, Error> {
117 let old = self.chain.clone();
118 let mut disconnected = Vec::new();
119 let mut connected = Vec::new();
120
121 for header in chain {
122 self.headers.insert(header.block_hash(), header);
123 }
124 let tip = self.tip;
125
126 self.chain = self.longest_chain();
127 self.tip = self.chain.last().block_hash();
128
129 if tip != self.tip {
130 for (height, header) in old.iter().enumerate() {
131 if !self.chain.contains(header) {
132 disconnected.push((height as Height, *header));
133 }
134 }
135 for (height, header) in self.chain.iter().enumerate() {
136 if !old.contains(header) {
137 connected.push((height as Height, *header));
138 }
139 }
140 let connected = NonEmpty::from_vec(connected).unwrap();
141
142 Ok(ImportResult::TipChanged(
143 self.chain.last().to_owned(),
144 self.tip,
145 self.height(),
146 disconnected,
147 connected,
148 ))
149 } else {
150 Ok(ImportResult::TipUnchanged)
151 }
152 }
153
154 fn extend_tip<C>(&mut self, header: BlockHeader, _context: &C) -> Result<ImportResult, Error> {
155 if header.prev_blockhash == self.tip {
156 let hash = header.block_hash();
157
158 self.headers.insert(hash, header);
159 self.chain.push(header);
160 self.tip = hash;
161
162 Ok(ImportResult::TipChanged(
163 header,
164 self.tip,
165 self.height(),
166 vec![],
167 NonEmpty::new((self.height(), header)),
168 ))
169 } else {
170 Ok(ImportResult::TipUnchanged)
171 }
172 }
173}
174
175impl BlockReader for Cache {
176 fn get_block(&self, hash: &BlockHash) -> Option<(Height, &BlockHeader)> {
177 for (height, header) in self.chain.iter().enumerate() {
178 if hash == &header.block_hash() {
179 return Some((height as Height, header));
180 }
181 }
182 None
183 }
184
185 fn find_branch(&self, _to: &BlockHash) -> Option<(Height, NonEmpty<BlockHeader>)> {
186 unimplemented!()
187 }
188
189 fn locate_headers(
190 &self,
191 _locators: &[BlockHash],
192 _stop_hash: BlockHash,
193 _max: usize,
194 ) -> Vec<BlockHeader> {
195 unimplemented!()
196 }
197
198 fn last_checkpoint(&self) -> Height {
199 0
200 }
201
202 fn checkpoints(&self) -> BTreeMap<Height, BlockHash> {
203 BTreeMap::new()
204 }
205
206 fn locator_hashes(&self, _from: Height) -> Vec<BlockHash> {
207 vec![self.chain.last().block_hash()]
208 }
209
210 fn get_block_by_height(&self, height: Height) -> Option<&BlockHeader> {
211 self.chain.get(height as usize)
212 }
213
214 fn tip(&self) -> (BlockHash, BlockHeader) {
215 let tip = self.chain.last();
216 (tip.block_hash(), *tip)
217 }
218
219 fn height(&self) -> Height {
220 self.chain.len() as Height - 1
221 }
222
223 fn iter<'a>(&'a self) -> Box<dyn DoubleEndedIterator<Item = (Height, BlockHeader)> + 'a> {
224 Box::new(Iter::new(&self.chain).map(|(i, h)| (i, *h)))
225 }
226
227 fn contains(&self, hash: &BlockHash) -> bool {
228 self.headers.contains_key(hash) && self.chain.iter().any(|b| b.block_hash() == *hash)
229 }
230
231 fn is_known(&self, hash: &BlockHash) -> bool {
232 self.headers.contains_key(hash)
233 }
234}
235
236#[derive(Debug, Clone)]
237pub struct FilterCache {
238 headers: NonEmpty<(FilterHash, FilterHeader)>,
239 filters: BTreeMap<Height, BlockFilter>,
240}
241
242impl FilterCache {
243 pub fn new(genesis: FilterHeader) -> Self {
244 Self {
245 headers: NonEmpty::new((FilterHash::all_zeros(), genesis)),
246 filters: BTreeMap::new(),
247 }
248 }
249
250 pub fn from(headers: NonEmpty<(FilterHash, FilterHeader)>) -> Self {
251 Self {
252 headers,
253 filters: BTreeMap::new(),
254 }
255 }
256}
257
258impl Filters for FilterCache {
259 fn get_header(&self, height: Height) -> Option<(FilterHash, FilterHeader)> {
260 self.headers.get(height as usize).copied()
261 }
262
263 fn get_headers(&self, range: RangeInclusive<Height>) -> Vec<(FilterHash, FilterHeader)> {
264 let (start, end) = (*range.start(), *range.end());
265
266 assert!(start <= end);
267
268 self.headers
269 .iter()
270 .cloned()
271 .skip(start as usize)
272 .take(end as usize - start as usize + 1)
273 .collect()
274 }
275
276 fn import_headers(
277 &mut self,
278 headers: Vec<(FilterHash, FilterHeader)>,
279 ) -> Result<Height, filter::Error> {
280 self.headers.tail.extend(headers);
281
282 Ok(self.height())
283 }
284
285 fn tip(&self) -> (&FilterHash, &FilterHeader) {
286 let (hash, header) = self.headers.last();
287 (hash, header)
288 }
289
290 fn height(&self) -> Height {
291 self.headers.tail.len() as Height
292 }
293
294 fn rollback(&mut self, height: Height) -> Result<(), filter::Error> {
295 self.headers.tail.truncate(height as usize);
296
297 let heights = self
298 .filters
299 .range(height + 1..)
300 .map(|(h, _)| *h)
301 .collect::<Vec<_>>();
302
303 for h in heights {
304 self.filters.remove(&h);
305 }
306 Ok(())
307 }
308
309 fn clear(&mut self) -> Result<(), filter::Error> {
310 self.headers.tail.clear();
311 self.filters.clear();
312
313 Ok(())
314 }
315}