ethrex_storage/
block_data_buffer.rs1use std::collections::VecDeque;
2use std::sync::Arc;
3
4use ethrex_common::H256;
5use ethrex_common::types::{Block, BlockBody, BlockHash, BlockHeader, BlockNumber, Code, Receipt};
6use ethrex_crypto::NativeCrypto;
7use rustc_hash::{FxHashMap, FxHashSet};
8
9#[derive(Debug, Clone)]
12pub struct BufferedBlock {
13 pub header: BlockHeader,
14 pub body: BlockBody,
15 pub number: BlockNumber,
16 pub receipts: Vec<Receipt>,
17}
18
19#[derive(Debug, Clone)]
27pub struct BlockDataBuffer {
28 by_hash: FxHashMap<BlockHash, Arc<BufferedBlock>>,
29 by_number: FxHashMap<BlockNumber, Vec<BlockHash>>,
30 tx_index: FxHashMap<H256, Vec<(BlockNumber, BlockHash, u64)>>,
31 codes: FxHashMap<H256, (Code, BlockNumber)>,
34 unflushed: VecDeque<BlockHash>,
36 flushed_upto: BlockNumber,
38}
39
40impl Default for BlockDataBuffer {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46impl BlockDataBuffer {
47 pub fn new() -> Self {
48 Self {
49 by_hash: FxHashMap::default(),
50 by_number: FxHashMap::default(),
51 tx_index: FxHashMap::default(),
52 codes: FxHashMap::default(),
53 unflushed: VecDeque::new(),
54 flushed_upto: 0,
55 }
56 }
57
58 pub fn insert(&mut self, block: Block, receipts: Vec<Receipt>, codes: Vec<(H256, Code)>) {
62 let hash = block.hash();
63 let number = block.header.number;
64 if self.by_hash.contains_key(&hash) {
65 return; }
67 for (index, tx) in block.body.transactions.iter().enumerate() {
68 self.tx_index
69 .entry(tx.hash(&NativeCrypto))
70 .or_default()
71 .push((number, hash, index as u64));
72 }
73 for (code_hash, code) in codes {
74 self.codes.entry(code_hash).or_insert((code, number));
75 }
76 self.by_number.entry(number).or_default().push(hash);
77 let Block { header, body } = block;
78 self.by_hash.insert(
79 hash,
80 Arc::new(BufferedBlock {
81 header,
82 body,
83 number,
84 receipts,
85 }),
86 );
87 self.unflushed.push_back(hash);
88 }
89
90 pub fn get_header(&self, hash: &BlockHash) -> Option<BlockHeader> {
91 self.by_hash.get(hash).map(|b| b.header.clone())
92 }
93
94 pub fn get_body(&self, hash: &BlockHash) -> Option<BlockBody> {
95 self.by_hash.get(hash).map(|b| b.body.clone())
96 }
97
98 pub fn get_number(&self, hash: &BlockHash) -> Option<BlockNumber> {
99 self.by_hash.get(hash).map(|b| b.number)
100 }
101
102 pub fn get_receipt(&self, hash: &BlockHash, index: u64) -> Option<Receipt> {
103 self.by_hash
104 .get(hash)
105 .and_then(|b| b.receipts.get(index as usize).cloned())
106 }
107
108 pub fn get_receipts(&self, hash: &BlockHash) -> Option<Vec<Receipt>> {
109 self.by_hash.get(hash).map(|b| b.receipts.clone())
110 }
111
112 pub fn get_code(&self, code_hash: &H256) -> Option<Code> {
113 self.codes.get(code_hash).map(|(c, _)| c.clone())
114 }
115
116 pub fn get_tx_locations(&self, tx_hash: &H256) -> Vec<(BlockNumber, BlockHash, u64)> {
117 self.tx_index.get(tx_hash).cloned().unwrap_or_default()
118 }
119
120 pub fn flushed_upto(&self) -> BlockNumber {
121 self.flushed_upto
122 }
123
124 pub fn set_flushed_upto(&mut self, n: BlockNumber) {
125 self.flushed_upto = self.flushed_upto.max(n);
126 }
127
128 pub fn flushable(&self) -> Vec<Arc<BufferedBlock>> {
130 let mut out: Vec<Arc<BufferedBlock>> = self
131 .unflushed
132 .iter()
133 .filter_map(|h| self.by_hash.get(h).cloned())
134 .collect();
135 out.sort_by_key(|b| b.number);
136 out
137 }
138
139 pub fn codes_for(&self, hashes: &[BlockHash]) -> Vec<(H256, Code)> {
141 let numbers: FxHashSet<BlockNumber> =
142 hashes.iter().filter_map(|h| self.get_number(h)).collect();
143 self.codes
144 .iter()
145 .filter(|(_, (_, n))| numbers.contains(n))
146 .map(|(h, (c, _))| (*h, c.clone()))
147 .collect()
148 }
149
150 pub fn evict_flushed(&mut self, new_flushed_upto: BlockNumber) {
153 self.set_flushed_upto(new_flushed_upto);
154 let drop_hashes: Vec<BlockHash> = self
155 .by_hash
156 .iter()
157 .filter(|(_, b)| b.number <= new_flushed_upto)
158 .map(|(h, _)| *h)
159 .collect();
160 for h in &drop_hashes {
161 if let Some(b) = self.by_hash.remove(h) {
162 if let Some(v) = self.by_number.get_mut(&b.number) {
163 v.retain(|x| x != h);
164 if v.is_empty() {
165 self.by_number.remove(&b.number);
166 }
167 }
168 for tx in b.body.transactions.iter() {
169 if let Some(v) = self.tx_index.get_mut(&tx.hash(&NativeCrypto)) {
170 v.retain(|(_, bh, _)| bh != h);
171 if v.is_empty() {
172 self.tx_index.remove(&tx.hash(&NativeCrypto));
173 }
174 }
175 }
176 }
177 }
178 self.unflushed.retain(|h| self.by_hash.contains_key(h));
179 self.codes.retain(|_, (_, n)| *n > new_flushed_upto);
180 }
181}