1use crate::tree::metrics::BlockBufferMetrics;
2use alloy_consensus::BlockHeader;
3use alloy_primitives::{BlockHash, BlockNumber};
4use reth_primitives_traits::{Block, SealedBlock};
5use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
6
7#[derive(Debug)]
19pub struct BlockBuffer<B: Block> {
20 pub(crate) blocks: HashMap<BlockHash, SealedBlock<B>>,
22 pub(crate) parent_to_child: HashMap<BlockHash, HashSet<BlockHash>>,
26 pub(crate) earliest_blocks: BTreeMap<BlockNumber, HashSet<BlockHash>>,
29 pub(crate) block_queue: VecDeque<BlockHash>,
32 pub(crate) max_blocks: usize,
34 pub(crate) metrics: BlockBufferMetrics,
36}
37
38impl<B: Block> BlockBuffer<B> {
39 pub fn new(limit: u32) -> Self {
41 Self {
42 blocks: Default::default(),
43 parent_to_child: Default::default(),
44 earliest_blocks: Default::default(),
45 block_queue: VecDeque::default(),
46 max_blocks: limit as usize,
47 metrics: Default::default(),
48 }
49 }
50
51 pub fn block(&self, hash: &BlockHash) -> Option<&SealedBlock<B>> {
53 self.blocks.get(hash)
54 }
55
56 pub fn lowest_ancestor(&self, hash: &BlockHash) -> Option<&SealedBlock<B>> {
58 let mut current_block = self.blocks.get(hash)?;
59 while let Some(parent) = self.blocks.get(¤t_block.parent_hash()) {
60 current_block = parent;
61 }
62 Some(current_block)
63 }
64
65 pub fn insert_block(&mut self, block: SealedBlock<B>) {
67 let hash = block.hash();
68
69 match self.blocks.entry(hash) {
70 std::collections::hash_map::Entry::Occupied(_) => return,
71 std::collections::hash_map::Entry::Vacant(entry) => {
72 self.parent_to_child.entry(block.parent_hash()).or_default().insert(hash);
73 self.earliest_blocks.entry(block.number()).or_default().insert(hash);
74 entry.insert(block);
75 }
76 };
77
78 if self.block_queue.len() >= self.max_blocks {
80 if let Some(evicted_hash) = self.block_queue.pop_front() {
82 self.remove_block(&evicted_hash);
83 }
84 }
85 self.block_queue.push_back(hash);
86 self.metrics.blocks.set(self.blocks.len() as f64);
87 }
88
89 pub fn remove_block_with_children(&mut self, parent_hash: &BlockHash) -> Vec<SealedBlock<B>> {
96 let removed = self
97 .remove_block(parent_hash)
98 .into_iter()
99 .chain(self.remove_children(vec![*parent_hash]))
100 .collect();
101 self.metrics.blocks.set(self.blocks.len() as f64);
102 removed
103 }
104
105 pub fn remove_old_blocks(&mut self, block_number: BlockNumber) {
107 let mut block_hashes_to_remove = Vec::new();
108
109 while let Some(entry) = self.earliest_blocks.first_entry() {
111 if *entry.key() > block_number {
112 break
113 }
114 let block_hashes = entry.remove();
115 block_hashes_to_remove.extend(block_hashes);
116 }
117
118 for block_hash in &block_hashes_to_remove {
120 self.remove_block(block_hash);
122 }
123
124 self.remove_children(block_hashes_to_remove);
125 self.metrics.blocks.set(self.blocks.len() as f64);
126 }
127
128 fn remove_from_earliest_blocks(&mut self, number: BlockNumber, hash: &BlockHash) {
130 if let Some(entry) = self.earliest_blocks.get_mut(&number) {
131 entry.remove(hash);
132 if entry.is_empty() {
133 self.earliest_blocks.remove(&number);
134 }
135 }
136 }
137
138 fn remove_from_parent(&mut self, parent_hash: BlockHash, hash: &BlockHash) {
140 if let Some(entry) = self.parent_to_child.get_mut(&parent_hash) {
142 entry.remove(hash);
143 if entry.is_empty() {
145 self.parent_to_child.remove(&parent_hash);
146 }
147 }
148 }
149
150 fn remove_block(&mut self, hash: &BlockHash) -> Option<SealedBlock<B>> {
155 let block = self.blocks.remove(hash)?;
156 self.remove_from_earliest_blocks(block.number(), hash);
157 self.remove_from_parent(block.parent_hash(), hash);
158 self.block_queue.retain(|h| h != hash);
159 Some(block)
160 }
161
162 fn remove_children(&mut self, parent_hashes: Vec<BlockHash>) -> Vec<SealedBlock<B>> {
164 let mut remove_parent_children = parent_hashes;
167 let mut removed_blocks = Vec::new();
168 while let Some(parent_hash) = remove_parent_children.pop() {
169 if let Some(parent_children) = self.parent_to_child.remove(&parent_hash) {
171 for child_hash in &parent_children {
173 if let Some(block) = self.remove_block(child_hash) {
174 removed_blocks.push(block);
175 }
176 }
177 remove_parent_children.extend(parent_children);
178 }
179 }
180 removed_blocks
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use alloy_eips::BlockNumHash;
188 use alloy_primitives::BlockHash;
189 use reth_testing_utils::generators::{self, random_block, BlockParams, Rng};
190 use std::collections::HashMap;
191
192 fn create_block<R: Rng>(
194 rng: &mut R,
195 number: u64,
196 parent: BlockHash,
197 ) -> SealedBlock<reth_ethereum_primitives::Block> {
198 random_block(rng, number, BlockParams { parent: Some(parent), ..Default::default() })
199 }
200
201 fn assert_buffer_lengths<B: Block>(buffer: &BlockBuffer<B>, expected: usize) {
203 assert_eq!(buffer.blocks.len(), expected);
204 assert_eq!(buffer.block_queue.len(), expected);
205 assert_eq!(
206 buffer.parent_to_child.iter().fold(0, |acc, (_, hashes)| acc + hashes.len()),
207 expected
208 );
209 assert_eq!(
210 buffer.earliest_blocks.iter().fold(0, |acc, (_, hashes)| acc + hashes.len()),
211 expected
212 );
213 }
214
215 fn assert_block_removal<B: Block>(
217 buffer: &BlockBuffer<B>,
218 block: &SealedBlock<reth_ethereum_primitives::Block>,
219 ) {
220 assert!(!buffer.blocks.contains_key(&block.hash()));
221 assert!(buffer
222 .parent_to_child
223 .get(&block.parent_hash)
224 .and_then(|p| p.get(&block.hash()))
225 .is_none());
226 assert!(buffer
227 .earliest_blocks
228 .get(&block.number)
229 .and_then(|hashes| hashes.get(&block.hash()))
230 .is_none());
231 }
232
233 #[test]
234 fn simple_insertion() {
235 let mut rng = generators::rng();
236 let parent = rng.random();
237 let block1 = create_block(&mut rng, 10, parent);
238 let mut buffer = BlockBuffer::new(3);
239
240 buffer.insert_block(block1.clone());
241 assert_buffer_lengths(&buffer, 1);
242 assert_eq!(buffer.block(&block1.hash()), Some(&block1));
243 }
244
245 #[test]
246 fn take_entire_chain_of_children() {
247 let mut rng = generators::rng();
248
249 let main_parent_hash = rng.random();
250 let block1 = create_block(&mut rng, 10, main_parent_hash);
251 let block2 = create_block(&mut rng, 11, block1.hash());
252 let block3 = create_block(&mut rng, 12, block2.hash());
253 let parent4 = rng.random();
254 let block4 = create_block(&mut rng, 14, parent4);
255
256 let mut buffer = BlockBuffer::new(5);
257
258 buffer.insert_block(block1.clone());
259 buffer.insert_block(block2.clone());
260 buffer.insert_block(block3.clone());
261 buffer.insert_block(block4.clone());
262
263 assert_buffer_lengths(&buffer, 4);
264 assert_eq!(buffer.block(&block4.hash()), Some(&block4));
265 assert_eq!(buffer.block(&block2.hash()), Some(&block2));
266 assert_eq!(buffer.block(&main_parent_hash), None);
267
268 assert_eq!(buffer.lowest_ancestor(&block4.hash()), Some(&block4));
269 assert_eq!(buffer.lowest_ancestor(&block3.hash()), Some(&block1));
270 assert_eq!(buffer.lowest_ancestor(&block1.hash()), Some(&block1));
271 assert_eq!(
272 buffer.remove_block_with_children(&main_parent_hash),
273 vec![block1, block2, block3]
274 );
275 assert_buffer_lengths(&buffer, 1);
276 }
277
278 #[test]
279 fn take_all_multi_level_children() {
280 let mut rng = generators::rng();
281
282 let main_parent_hash = rng.random();
283 let block1 = create_block(&mut rng, 10, main_parent_hash);
284 let block2 = create_block(&mut rng, 11, block1.hash());
285 let block3 = create_block(&mut rng, 11, block1.hash());
286 let block4 = create_block(&mut rng, 12, block2.hash());
287
288 let mut buffer = BlockBuffer::new(5);
289
290 buffer.insert_block(block1.clone());
291 buffer.insert_block(block2.clone());
292 buffer.insert_block(block3.clone());
293 buffer.insert_block(block4.clone());
294
295 assert_buffer_lengths(&buffer, 4);
296 assert_eq!(
297 buffer
298 .remove_block_with_children(&main_parent_hash)
299 .into_iter()
300 .map(|b| (b.hash(), b))
301 .collect::<HashMap<_, _>>(),
302 HashMap::from([
303 (block1.hash(), block1),
304 (block2.hash(), block2),
305 (block3.hash(), block3),
306 (block4.hash(), block4)
307 ])
308 );
309 assert_buffer_lengths(&buffer, 0);
310 }
311
312 #[test]
313 fn take_block_with_children() {
314 let mut rng = generators::rng();
315
316 let main_parent = BlockNumHash::new(9, rng.random());
317 let block1 = create_block(&mut rng, 10, main_parent.hash);
318 let block2 = create_block(&mut rng, 11, block1.hash());
319 let block3 = create_block(&mut rng, 11, block1.hash());
320 let block4 = create_block(&mut rng, 12, block2.hash());
321
322 let mut buffer = BlockBuffer::new(5);
323
324 buffer.insert_block(block1.clone());
325 buffer.insert_block(block2.clone());
326 buffer.insert_block(block3.clone());
327 buffer.insert_block(block4.clone());
328
329 assert_buffer_lengths(&buffer, 4);
330 assert_eq!(
331 buffer
332 .remove_block_with_children(&block1.hash())
333 .into_iter()
334 .map(|b| (b.hash(), b))
335 .collect::<HashMap<_, _>>(),
336 HashMap::from([
337 (block1.hash(), block1),
338 (block2.hash(), block2),
339 (block3.hash(), block3),
340 (block4.hash(), block4)
341 ])
342 );
343 assert_buffer_lengths(&buffer, 0);
344 }
345
346 #[test]
347 fn remove_chain_of_children() {
348 let mut rng = generators::rng();
349
350 let main_parent = BlockNumHash::new(9, rng.random());
351 let block1 = create_block(&mut rng, 10, main_parent.hash);
352 let block2 = create_block(&mut rng, 11, block1.hash());
353 let block3 = create_block(&mut rng, 12, block2.hash());
354 let parent4 = rng.random();
355 let block4 = create_block(&mut rng, 14, parent4);
356
357 let mut buffer = BlockBuffer::new(5);
358
359 buffer.insert_block(block1.clone());
360 buffer.insert_block(block2);
361 buffer.insert_block(block3);
362 buffer.insert_block(block4);
363
364 assert_buffer_lengths(&buffer, 4);
365 buffer.remove_old_blocks(block1.number);
366 assert_buffer_lengths(&buffer, 1);
367 }
368
369 #[test]
370 fn remove_all_multi_level_children() {
371 let mut rng = generators::rng();
372
373 let main_parent = BlockNumHash::new(9, rng.random());
374 let block1 = create_block(&mut rng, 10, main_parent.hash);
375 let block2 = create_block(&mut rng, 11, block1.hash());
376 let block3 = create_block(&mut rng, 11, block1.hash());
377 let block4 = create_block(&mut rng, 12, block2.hash());
378
379 let mut buffer = BlockBuffer::new(5);
380
381 buffer.insert_block(block1.clone());
382 buffer.insert_block(block2);
383 buffer.insert_block(block3);
384 buffer.insert_block(block4);
385
386 assert_buffer_lengths(&buffer, 4);
387 buffer.remove_old_blocks(block1.number);
388 assert_buffer_lengths(&buffer, 0);
389 }
390
391 #[test]
392 fn remove_multi_chains() {
393 let mut rng = generators::rng();
394
395 let main_parent = BlockNumHash::new(9, rng.random());
396 let block1 = create_block(&mut rng, 10, main_parent.hash);
397 let block1a = create_block(&mut rng, 10, main_parent.hash);
398 let block2 = create_block(&mut rng, 11, block1.hash());
399 let block2a = create_block(&mut rng, 11, block1.hash());
400 let random_parent1 = rng.random();
401 let random_block1 = create_block(&mut rng, 10, random_parent1);
402 let random_parent2 = rng.random();
403 let random_block2 = create_block(&mut rng, 11, random_parent2);
404 let random_parent3 = rng.random();
405 let random_block3 = create_block(&mut rng, 12, random_parent3);
406
407 let mut buffer = BlockBuffer::new(10);
408
409 buffer.insert_block(block1.clone());
410 buffer.insert_block(block1a.clone());
411 buffer.insert_block(block2.clone());
412 buffer.insert_block(block2a.clone());
413 buffer.insert_block(random_block1.clone());
414 buffer.insert_block(random_block2.clone());
415 buffer.insert_block(random_block3.clone());
416
417 assert_eq!(buffer.lowest_ancestor(&random_block1.hash()), Some(&random_block1));
419 assert_eq!(buffer.lowest_ancestor(&random_block2.hash()), Some(&random_block2));
420 assert_eq!(buffer.lowest_ancestor(&random_block3.hash()), Some(&random_block3));
421
422 assert_eq!(buffer.lowest_ancestor(&block2a.hash()), Some(&block1));
424 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block1));
425
426 assert_eq!(buffer.lowest_ancestor(&block1a.hash()), Some(&block1a));
428 assert_eq!(buffer.lowest_ancestor(&block1.hash()), Some(&block1));
429
430 assert_buffer_lengths(&buffer, 7);
431 buffer.remove_old_blocks(10);
432 assert_buffer_lengths(&buffer, 2);
433 }
434
435 #[test]
436 fn evict_with_gap() {
437 let mut rng = generators::rng();
438
439 let main_parent = BlockNumHash::new(9, rng.random());
440 let block1 = create_block(&mut rng, 10, main_parent.hash);
441 let block2 = create_block(&mut rng, 11, block1.hash());
442 let block3 = create_block(&mut rng, 12, block2.hash());
443 let parent4 = rng.random();
444 let block4 = create_block(&mut rng, 13, parent4);
445
446 let mut buffer = BlockBuffer::new(3);
447
448 buffer.insert_block(block1.clone());
449 buffer.insert_block(block2.clone());
450 buffer.insert_block(block3.clone());
451
452 assert_eq!(buffer.lowest_ancestor(&block3.hash()), Some(&block1));
454 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block1));
455 assert_eq!(buffer.lowest_ancestor(&block1.hash()), Some(&block1));
456
457 buffer.insert_block(block4.clone());
458
459 assert_eq!(buffer.lowest_ancestor(&block4.hash()), Some(&block4));
460
461 assert_block_removal(&buffer, &block1);
463
464 assert_eq!(buffer.lowest_ancestor(&block3.hash()), Some(&block2));
466 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block2));
467 assert_eq!(buffer.lowest_ancestor(&block1.hash()), None);
468
469 assert_buffer_lengths(&buffer, 3);
470 }
471
472 #[test]
473 fn simple_eviction() {
474 let mut rng = generators::rng();
475
476 let main_parent = BlockNumHash::new(9, rng.random());
477 let block1 = create_block(&mut rng, 10, main_parent.hash);
478 let block2 = create_block(&mut rng, 11, block1.hash());
479 let block3 = create_block(&mut rng, 12, block2.hash());
480 let parent4 = rng.random();
481 let block4 = create_block(&mut rng, 13, parent4);
482
483 let mut buffer = BlockBuffer::new(3);
484
485 buffer.insert_block(block1.clone());
486 buffer.insert_block(block2);
487 buffer.insert_block(block3);
488 buffer.insert_block(block4);
489
490 assert_block_removal(&buffer, &block1);
492
493 assert_buffer_lengths(&buffer, 3);
494 }
495
496 #[test]
497 fn eviction_parent_child_cleanup() {
498 let mut rng = generators::rng();
499
500 let main_parent = BlockNumHash::new(9, rng.random());
501 let block1 = create_block(&mut rng, 10, main_parent.hash);
502 let block2 = create_block(&mut rng, 11, block1.hash());
503 let unrelated_parent = rng.random();
505 let unrelated_block = create_block(&mut rng, 12, unrelated_parent);
506
507 let mut buffer = BlockBuffer::new(2);
509
510 buffer.insert_block(block1.clone());
511 buffer.insert_block(block2.clone());
512
513 assert!(buffer
515 .parent_to_child
516 .get(&main_parent.hash)
517 .and_then(|s| s.get(&block1.hash()))
518 .is_some());
519 assert!(buffer
520 .parent_to_child
521 .get(&block1.hash())
522 .and_then(|s| s.get(&block2.hash()))
523 .is_some());
524
525 buffer.insert_block(unrelated_block);
527
528 assert_block_removal(&buffer, &block1);
530
531 assert!(buffer
533 .parent_to_child
534 .get(&main_parent.hash)
535 .and_then(|s| s.get(&block1.hash()))
536 .is_none());
537
538 assert!(buffer
540 .parent_to_child
541 .get(&block1.hash())
542 .and_then(|s| s.get(&block2.hash()))
543 .is_some());
544
545 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block2));
547 }
548}