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