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 self.parent_to_child.entry(block.parent_hash()).or_default().insert(hash);
70 self.earliest_blocks.entry(block.number()).or_default().insert(hash);
71 self.blocks.insert(hash, block);
72
73 if self.block_queue.len() >= self.max_blocks {
75 if let Some(evicted_hash) = self.block_queue.pop_front() {
77 self.remove_block(&evicted_hash);
78 }
79 }
80 self.block_queue.push_back(hash);
81 self.metrics.blocks.set(self.blocks.len() as f64);
82 }
83
84 pub fn remove_block_with_children(&mut self, parent_hash: &BlockHash) -> Vec<SealedBlock<B>> {
91 let removed = self
92 .remove_block(parent_hash)
93 .into_iter()
94 .chain(self.remove_children(vec![*parent_hash]))
95 .collect();
96 self.metrics.blocks.set(self.blocks.len() as f64);
97 removed
98 }
99
100 pub fn remove_old_blocks(&mut self, block_number: BlockNumber) {
102 let mut block_hashes_to_remove = Vec::new();
103
104 while let Some(entry) = self.earliest_blocks.first_entry() {
106 if *entry.key() > block_number {
107 break
108 }
109 let block_hashes = entry.remove();
110 block_hashes_to_remove.extend(block_hashes);
111 }
112
113 for block_hash in &block_hashes_to_remove {
115 self.remove_block(block_hash);
117 }
118
119 self.remove_children(block_hashes_to_remove);
120 self.metrics.blocks.set(self.blocks.len() as f64);
121 }
122
123 fn remove_from_earliest_blocks(&mut self, number: BlockNumber, hash: &BlockHash) {
125 if let Some(entry) = self.earliest_blocks.get_mut(&number) {
126 entry.remove(hash);
127 if entry.is_empty() {
128 self.earliest_blocks.remove(&number);
129 }
130 }
131 }
132
133 fn remove_from_parent(&mut self, parent_hash: BlockHash, hash: &BlockHash) {
135 if let Some(entry) = self.parent_to_child.get_mut(&parent_hash) {
137 entry.remove(hash);
138 if entry.is_empty() {
140 self.parent_to_child.remove(&parent_hash);
141 }
142 }
143 }
144
145 fn remove_block(&mut self, hash: &BlockHash) -> Option<SealedBlock<B>> {
150 let block = self.blocks.remove(hash)?;
151 self.remove_from_earliest_blocks(block.number(), hash);
152 self.remove_from_parent(block.parent_hash(), hash);
153 self.block_queue.retain(|h| h != hash);
154 Some(block)
155 }
156
157 fn remove_children(&mut self, parent_hashes: Vec<BlockHash>) -> Vec<SealedBlock<B>> {
159 let mut remove_parent_children = parent_hashes;
162 let mut removed_blocks = Vec::new();
163 while let Some(parent_hash) = remove_parent_children.pop() {
164 if let Some(parent_children) = self.parent_to_child.remove(&parent_hash) {
166 for child_hash in &parent_children {
168 if let Some(block) = self.remove_block(child_hash) {
169 removed_blocks.push(block);
170 }
171 }
172 remove_parent_children.extend(parent_children);
173 }
174 }
175 removed_blocks
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use alloy_eips::BlockNumHash;
183 use alloy_primitives::BlockHash;
184 use reth_testing_utils::generators::{self, random_block, BlockParams, Rng};
185 use std::collections::HashMap;
186
187 fn create_block<R: Rng>(
189 rng: &mut R,
190 number: u64,
191 parent: BlockHash,
192 ) -> SealedBlock<reth_ethereum_primitives::Block> {
193 random_block(rng, number, BlockParams { parent: Some(parent), ..Default::default() })
194 }
195
196 fn assert_buffer_lengths<B: Block>(buffer: &BlockBuffer<B>, expected: usize) {
198 assert_eq!(buffer.blocks.len(), expected);
199 assert_eq!(buffer.block_queue.len(), expected);
200 assert_eq!(
201 buffer.parent_to_child.iter().fold(0, |acc, (_, hashes)| acc + hashes.len()),
202 expected
203 );
204 assert_eq!(
205 buffer.earliest_blocks.iter().fold(0, |acc, (_, hashes)| acc + hashes.len()),
206 expected
207 );
208 }
209
210 fn assert_block_removal<B: Block>(
212 buffer: &BlockBuffer<B>,
213 block: &SealedBlock<reth_ethereum_primitives::Block>,
214 ) {
215 assert!(!buffer.blocks.contains_key(&block.hash()));
216 assert!(buffer
217 .parent_to_child
218 .get(&block.parent_hash)
219 .and_then(|p| p.get(&block.hash()))
220 .is_none());
221 assert!(buffer
222 .earliest_blocks
223 .get(&block.number)
224 .and_then(|hashes| hashes.get(&block.hash()))
225 .is_none());
226 }
227
228 #[test]
229 fn simple_insertion() {
230 let mut rng = generators::rng();
231 let parent = rng.random();
232 let block1 = create_block(&mut rng, 10, parent);
233 let mut buffer = BlockBuffer::new(3);
234
235 buffer.insert_block(block1.clone());
236 assert_buffer_lengths(&buffer, 1);
237 assert_eq!(buffer.block(&block1.hash()), Some(&block1));
238 }
239
240 #[test]
241 fn take_entire_chain_of_children() {
242 let mut rng = generators::rng();
243
244 let main_parent_hash = rng.random();
245 let block1 = create_block(&mut rng, 10, main_parent_hash);
246 let block2 = create_block(&mut rng, 11, block1.hash());
247 let block3 = create_block(&mut rng, 12, block2.hash());
248 let parent4 = rng.random();
249 let block4 = create_block(&mut rng, 14, parent4);
250
251 let mut buffer = BlockBuffer::new(5);
252
253 buffer.insert_block(block1.clone());
254 buffer.insert_block(block2.clone());
255 buffer.insert_block(block3.clone());
256 buffer.insert_block(block4.clone());
257
258 assert_buffer_lengths(&buffer, 4);
259 assert_eq!(buffer.block(&block4.hash()), Some(&block4));
260 assert_eq!(buffer.block(&block2.hash()), Some(&block2));
261 assert_eq!(buffer.block(&main_parent_hash), None);
262
263 assert_eq!(buffer.lowest_ancestor(&block4.hash()), Some(&block4));
264 assert_eq!(buffer.lowest_ancestor(&block3.hash()), Some(&block1));
265 assert_eq!(buffer.lowest_ancestor(&block1.hash()), Some(&block1));
266 assert_eq!(
267 buffer.remove_block_with_children(&main_parent_hash),
268 vec![block1, block2, block3]
269 );
270 assert_buffer_lengths(&buffer, 1);
271 }
272
273 #[test]
274 fn take_all_multi_level_children() {
275 let mut rng = generators::rng();
276
277 let main_parent_hash = rng.random();
278 let block1 = create_block(&mut rng, 10, main_parent_hash);
279 let block2 = create_block(&mut rng, 11, block1.hash());
280 let block3 = create_block(&mut rng, 11, block1.hash());
281 let block4 = create_block(&mut rng, 12, block2.hash());
282
283 let mut buffer = BlockBuffer::new(5);
284
285 buffer.insert_block(block1.clone());
286 buffer.insert_block(block2.clone());
287 buffer.insert_block(block3.clone());
288 buffer.insert_block(block4.clone());
289
290 assert_buffer_lengths(&buffer, 4);
291 assert_eq!(
292 buffer
293 .remove_block_with_children(&main_parent_hash)
294 .into_iter()
295 .map(|b| (b.hash(), b))
296 .collect::<HashMap<_, _>>(),
297 HashMap::from([
298 (block1.hash(), block1),
299 (block2.hash(), block2),
300 (block3.hash(), block3),
301 (block4.hash(), block4)
302 ])
303 );
304 assert_buffer_lengths(&buffer, 0);
305 }
306
307 #[test]
308 fn take_block_with_children() {
309 let mut rng = generators::rng();
310
311 let main_parent = BlockNumHash::new(9, rng.random());
312 let block1 = create_block(&mut rng, 10, main_parent.hash);
313 let block2 = create_block(&mut rng, 11, block1.hash());
314 let block3 = create_block(&mut rng, 11, block1.hash());
315 let block4 = create_block(&mut rng, 12, block2.hash());
316
317 let mut buffer = BlockBuffer::new(5);
318
319 buffer.insert_block(block1.clone());
320 buffer.insert_block(block2.clone());
321 buffer.insert_block(block3.clone());
322 buffer.insert_block(block4.clone());
323
324 assert_buffer_lengths(&buffer, 4);
325 assert_eq!(
326 buffer
327 .remove_block_with_children(&block1.hash())
328 .into_iter()
329 .map(|b| (b.hash(), b))
330 .collect::<HashMap<_, _>>(),
331 HashMap::from([
332 (block1.hash(), block1),
333 (block2.hash(), block2),
334 (block3.hash(), block3),
335 (block4.hash(), block4)
336 ])
337 );
338 assert_buffer_lengths(&buffer, 0);
339 }
340
341 #[test]
342 fn remove_chain_of_children() {
343 let mut rng = generators::rng();
344
345 let main_parent = BlockNumHash::new(9, rng.random());
346 let block1 = create_block(&mut rng, 10, main_parent.hash);
347 let block2 = create_block(&mut rng, 11, block1.hash());
348 let block3 = create_block(&mut rng, 12, block2.hash());
349 let parent4 = rng.random();
350 let block4 = create_block(&mut rng, 14, parent4);
351
352 let mut buffer = BlockBuffer::new(5);
353
354 buffer.insert_block(block1.clone());
355 buffer.insert_block(block2);
356 buffer.insert_block(block3);
357 buffer.insert_block(block4);
358
359 assert_buffer_lengths(&buffer, 4);
360 buffer.remove_old_blocks(block1.number);
361 assert_buffer_lengths(&buffer, 1);
362 }
363
364 #[test]
365 fn remove_all_multi_level_children() {
366 let mut rng = generators::rng();
367
368 let main_parent = BlockNumHash::new(9, rng.random());
369 let block1 = create_block(&mut rng, 10, main_parent.hash);
370 let block2 = create_block(&mut rng, 11, block1.hash());
371 let block3 = create_block(&mut rng, 11, block1.hash());
372 let block4 = create_block(&mut rng, 12, block2.hash());
373
374 let mut buffer = BlockBuffer::new(5);
375
376 buffer.insert_block(block1.clone());
377 buffer.insert_block(block2);
378 buffer.insert_block(block3);
379 buffer.insert_block(block4);
380
381 assert_buffer_lengths(&buffer, 4);
382 buffer.remove_old_blocks(block1.number);
383 assert_buffer_lengths(&buffer, 0);
384 }
385
386 #[test]
387 fn remove_multi_chains() {
388 let mut rng = generators::rng();
389
390 let main_parent = BlockNumHash::new(9, rng.random());
391 let block1 = create_block(&mut rng, 10, main_parent.hash);
392 let block1a = create_block(&mut rng, 10, main_parent.hash);
393 let block2 = create_block(&mut rng, 11, block1.hash());
394 let block2a = create_block(&mut rng, 11, block1.hash());
395 let random_parent1 = rng.random();
396 let random_block1 = create_block(&mut rng, 10, random_parent1);
397 let random_parent2 = rng.random();
398 let random_block2 = create_block(&mut rng, 11, random_parent2);
399 let random_parent3 = rng.random();
400 let random_block3 = create_block(&mut rng, 12, random_parent3);
401
402 let mut buffer = BlockBuffer::new(10);
403
404 buffer.insert_block(block1.clone());
405 buffer.insert_block(block1a.clone());
406 buffer.insert_block(block2.clone());
407 buffer.insert_block(block2a.clone());
408 buffer.insert_block(random_block1.clone());
409 buffer.insert_block(random_block2.clone());
410 buffer.insert_block(random_block3.clone());
411
412 assert_eq!(buffer.lowest_ancestor(&random_block1.hash()), Some(&random_block1));
414 assert_eq!(buffer.lowest_ancestor(&random_block2.hash()), Some(&random_block2));
415 assert_eq!(buffer.lowest_ancestor(&random_block3.hash()), Some(&random_block3));
416
417 assert_eq!(buffer.lowest_ancestor(&block2a.hash()), Some(&block1));
419 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block1));
420
421 assert_eq!(buffer.lowest_ancestor(&block1a.hash()), Some(&block1a));
423 assert_eq!(buffer.lowest_ancestor(&block1.hash()), Some(&block1));
424
425 assert_buffer_lengths(&buffer, 7);
426 buffer.remove_old_blocks(10);
427 assert_buffer_lengths(&buffer, 2);
428 }
429
430 #[test]
431 fn evict_with_gap() {
432 let mut rng = generators::rng();
433
434 let main_parent = BlockNumHash::new(9, rng.random());
435 let block1 = create_block(&mut rng, 10, main_parent.hash);
436 let block2 = create_block(&mut rng, 11, block1.hash());
437 let block3 = create_block(&mut rng, 12, block2.hash());
438 let parent4 = rng.random();
439 let block4 = create_block(&mut rng, 13, parent4);
440
441 let mut buffer = BlockBuffer::new(3);
442
443 buffer.insert_block(block1.clone());
444 buffer.insert_block(block2.clone());
445 buffer.insert_block(block3.clone());
446
447 assert_eq!(buffer.lowest_ancestor(&block3.hash()), Some(&block1));
449 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block1));
450 assert_eq!(buffer.lowest_ancestor(&block1.hash()), Some(&block1));
451
452 buffer.insert_block(block4.clone());
453
454 assert_eq!(buffer.lowest_ancestor(&block4.hash()), Some(&block4));
455
456 assert_block_removal(&buffer, &block1);
458
459 assert_eq!(buffer.lowest_ancestor(&block3.hash()), Some(&block2));
461 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block2));
462 assert_eq!(buffer.lowest_ancestor(&block1.hash()), None);
463
464 assert_buffer_lengths(&buffer, 3);
465 }
466
467 #[test]
468 fn simple_eviction() {
469 let mut rng = generators::rng();
470
471 let main_parent = BlockNumHash::new(9, rng.random());
472 let block1 = create_block(&mut rng, 10, main_parent.hash);
473 let block2 = create_block(&mut rng, 11, block1.hash());
474 let block3 = create_block(&mut rng, 12, block2.hash());
475 let parent4 = rng.random();
476 let block4 = create_block(&mut rng, 13, parent4);
477
478 let mut buffer = BlockBuffer::new(3);
479
480 buffer.insert_block(block1.clone());
481 buffer.insert_block(block2);
482 buffer.insert_block(block3);
483 buffer.insert_block(block4);
484
485 assert_block_removal(&buffer, &block1);
487
488 assert_buffer_lengths(&buffer, 3);
489 }
490
491 #[test]
492 fn eviction_parent_child_cleanup() {
493 let mut rng = generators::rng();
494
495 let main_parent = BlockNumHash::new(9, rng.random());
496 let block1 = create_block(&mut rng, 10, main_parent.hash);
497 let block2 = create_block(&mut rng, 11, block1.hash());
498 let unrelated_parent = rng.random();
500 let unrelated_block = create_block(&mut rng, 12, unrelated_parent);
501
502 let mut buffer = BlockBuffer::new(2);
504
505 buffer.insert_block(block1.clone());
506 buffer.insert_block(block2.clone());
507
508 assert!(buffer
510 .parent_to_child
511 .get(&main_parent.hash)
512 .and_then(|s| s.get(&block1.hash()))
513 .is_some());
514 assert!(buffer
515 .parent_to_child
516 .get(&block1.hash())
517 .and_then(|s| s.get(&block2.hash()))
518 .is_some());
519
520 buffer.insert_block(unrelated_block);
522
523 assert_block_removal(&buffer, &block1);
525
526 assert!(buffer
528 .parent_to_child
529 .get(&main_parent.hash)
530 .and_then(|s| s.get(&block1.hash()))
531 .is_none());
532
533 assert!(buffer
535 .parent_to_child
536 .get(&block1.hash())
537 .and_then(|s| s.get(&block2.hash()))
538 .is_some());
539
540 assert_eq!(buffer.lowest_ancestor(&block2.hash()), Some(&block2));
542 }
543}