1use super::{TrieCursor, TrieCursorFactory};
2use crate::{
3 forward_cursor::ForwardInMemoryCursor,
4 updates::{StorageTrieUpdatesSorted, TrieUpdatesSorted},
5};
6use alloy_primitives::{map::HashSet, B256};
7use reth_storage_errors::db::DatabaseError;
8use reth_trie_common::{BranchNodeCompact, Nibbles};
9
10#[derive(Debug, Clone)]
12pub struct InMemoryTrieCursorFactory<'a, CF> {
13 cursor_factory: CF,
15 trie_updates: &'a TrieUpdatesSorted,
17}
18
19impl<'a, CF> InMemoryTrieCursorFactory<'a, CF> {
20 pub const fn new(cursor_factory: CF, trie_updates: &'a TrieUpdatesSorted) -> Self {
22 Self { cursor_factory, trie_updates }
23 }
24}
25
26impl<'a, CF: TrieCursorFactory> TrieCursorFactory for InMemoryTrieCursorFactory<'a, CF> {
27 type AccountTrieCursor = InMemoryAccountTrieCursor<'a, CF::AccountTrieCursor>;
28 type StorageTrieCursor = InMemoryStorageTrieCursor<'a, CF::StorageTrieCursor>;
29
30 fn account_trie_cursor(&self) -> Result<Self::AccountTrieCursor, DatabaseError> {
31 let cursor = self.cursor_factory.account_trie_cursor()?;
32 Ok(InMemoryAccountTrieCursor::new(cursor, self.trie_updates))
33 }
34
35 fn storage_trie_cursor(
36 &self,
37 hashed_address: B256,
38 ) -> Result<Self::StorageTrieCursor, DatabaseError> {
39 let cursor = self.cursor_factory.storage_trie_cursor(hashed_address)?;
40 Ok(InMemoryStorageTrieCursor::new(
41 hashed_address,
42 cursor,
43 self.trie_updates.storage_tries.get(&hashed_address),
44 ))
45 }
46}
47
48#[derive(Debug)]
51pub struct InMemoryAccountTrieCursor<'a, C> {
52 cursor: C,
54 in_memory_cursor: ForwardInMemoryCursor<'a, Nibbles, BranchNodeCompact>,
56 removed_nodes: &'a HashSet<Nibbles>,
58 last_key: Option<Nibbles>,
60}
61
62impl<'a, C: TrieCursor> InMemoryAccountTrieCursor<'a, C> {
63 pub const fn new(cursor: C, trie_updates: &'a TrieUpdatesSorted) -> Self {
66 let in_memory_cursor = ForwardInMemoryCursor::new(&trie_updates.account_nodes);
67 Self {
68 cursor,
69 in_memory_cursor,
70 removed_nodes: &trie_updates.removed_nodes,
71 last_key: None,
72 }
73 }
74
75 fn seek_inner(
76 &mut self,
77 key: Nibbles,
78 exact: bool,
79 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
80 let in_memory = self.in_memory_cursor.seek(&key);
81 if exact && in_memory.as_ref().is_some_and(|entry| entry.0 == key) {
82 return Ok(in_memory)
83 }
84
85 let mut db_entry = self.cursor.seek(key.clone())?;
87 while db_entry.as_ref().is_some_and(|entry| self.removed_nodes.contains(&entry.0)) {
88 db_entry = self.cursor.next()?;
89 }
90
91 Ok(compare_trie_node_entries(in_memory, db_entry)
94 .filter(|(nibbles, _)| !exact || nibbles == &key))
95 }
96
97 fn next_inner(
98 &mut self,
99 last: Nibbles,
100 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
101 let in_memory = self.in_memory_cursor.first_after(&last);
102
103 let mut db_entry = self.cursor.seek(last.clone())?;
105 while db_entry
106 .as_ref()
107 .is_some_and(|entry| entry.0 < last || self.removed_nodes.contains(&entry.0))
108 {
109 db_entry = self.cursor.next()?;
110 }
111
112 Ok(compare_trie_node_entries(in_memory, db_entry))
114 }
115}
116
117impl<C: TrieCursor> TrieCursor for InMemoryAccountTrieCursor<'_, C> {
118 fn seek_exact(
119 &mut self,
120 key: Nibbles,
121 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
122 let entry = self.seek_inner(key, true)?;
123 self.last_key = entry.as_ref().map(|(nibbles, _)| nibbles.clone());
124 Ok(entry)
125 }
126
127 fn seek(
128 &mut self,
129 key: Nibbles,
130 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
131 let entry = self.seek_inner(key, false)?;
132 self.last_key = entry.as_ref().map(|(nibbles, _)| nibbles.clone());
133 Ok(entry)
134 }
135
136 fn next(&mut self) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
137 let next = match &self.last_key {
138 Some(last) => {
139 let entry = self.next_inner(last.clone())?;
140 self.last_key = entry.as_ref().map(|entry| entry.0.clone());
141 entry
142 }
143 None => None,
145 };
146 Ok(next)
147 }
148
149 fn current(&mut self) -> Result<Option<Nibbles>, DatabaseError> {
150 match &self.last_key {
151 Some(key) => Ok(Some(key.clone())),
152 None => self.cursor.current(),
153 }
154 }
155}
156
157#[derive(Debug)]
160#[allow(dead_code)]
161pub struct InMemoryStorageTrieCursor<'a, C> {
162 hashed_address: B256,
164 cursor: C,
166 in_memory_cursor: Option<ForwardInMemoryCursor<'a, Nibbles, BranchNodeCompact>>,
168 removed_nodes: Option<&'a HashSet<Nibbles>>,
170 storage_trie_cleared: bool,
172 last_key: Option<Nibbles>,
174}
175
176impl<'a, C> InMemoryStorageTrieCursor<'a, C> {
177 pub fn new(
180 hashed_address: B256,
181 cursor: C,
182 updates: Option<&'a StorageTrieUpdatesSorted>,
183 ) -> Self {
184 let in_memory_cursor = updates.map(|u| ForwardInMemoryCursor::new(&u.storage_nodes));
185 let removed_nodes = updates.map(|u| &u.removed_nodes);
186 let storage_trie_cleared = updates.is_some_and(|u| u.is_deleted);
187 Self {
188 hashed_address,
189 cursor,
190 in_memory_cursor,
191 removed_nodes,
192 storage_trie_cleared,
193 last_key: None,
194 }
195 }
196}
197
198impl<C: TrieCursor> InMemoryStorageTrieCursor<'_, C> {
199 fn seek_inner(
200 &mut self,
201 key: Nibbles,
202 exact: bool,
203 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
204 let in_memory = self.in_memory_cursor.as_mut().and_then(|c| c.seek(&key));
205 if self.storage_trie_cleared ||
206 (exact && in_memory.as_ref().is_some_and(|entry| entry.0 == key))
207 {
208 return Ok(in_memory.filter(|(nibbles, _)| !exact || nibbles == &key))
209 }
210
211 let mut db_entry = self.cursor.seek(key.clone())?;
213 while db_entry
214 .as_ref()
215 .is_some_and(|entry| self.removed_nodes.as_ref().is_some_and(|r| r.contains(&entry.0)))
216 {
217 db_entry = self.cursor.next()?;
218 }
219
220 Ok(compare_trie_node_entries(in_memory, db_entry)
223 .filter(|(nibbles, _)| !exact || nibbles == &key))
224 }
225
226 fn next_inner(
227 &mut self,
228 last: Nibbles,
229 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
230 let in_memory = self.in_memory_cursor.as_mut().and_then(|c| c.first_after(&last));
231 if self.storage_trie_cleared {
232 return Ok(in_memory)
233 }
234
235 let mut db_entry = self.cursor.seek(last.clone())?;
237 while db_entry.as_ref().is_some_and(|entry| {
238 entry.0 < last || self.removed_nodes.as_ref().is_some_and(|r| r.contains(&entry.0))
239 }) {
240 db_entry = self.cursor.next()?;
241 }
242
243 Ok(compare_trie_node_entries(in_memory, db_entry))
245 }
246}
247
248impl<C: TrieCursor> TrieCursor for InMemoryStorageTrieCursor<'_, C> {
249 fn seek_exact(
250 &mut self,
251 key: Nibbles,
252 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
253 let entry = self.seek_inner(key, true)?;
254 self.last_key = entry.as_ref().map(|(nibbles, _)| nibbles.clone());
255 Ok(entry)
256 }
257
258 fn seek(
259 &mut self,
260 key: Nibbles,
261 ) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
262 let entry = self.seek_inner(key, false)?;
263 self.last_key = entry.as_ref().map(|(nibbles, _)| nibbles.clone());
264 Ok(entry)
265 }
266
267 fn next(&mut self) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
268 let next = match &self.last_key {
269 Some(last) => {
270 let entry = self.next_inner(last.clone())?;
271 self.last_key = entry.as_ref().map(|entry| entry.0.clone());
272 entry
273 }
274 None => None,
276 };
277 Ok(next)
278 }
279
280 fn current(&mut self) -> Result<Option<Nibbles>, DatabaseError> {
281 match &self.last_key {
282 Some(key) => Ok(Some(key.clone())),
283 None => self.cursor.current(),
284 }
285 }
286}
287
288fn compare_trie_node_entries(
293 mut in_memory_item: Option<(Nibbles, BranchNodeCompact)>,
294 mut db_item: Option<(Nibbles, BranchNodeCompact)>,
295) -> Option<(Nibbles, BranchNodeCompact)> {
296 if let Some((in_memory_entry, db_entry)) = in_memory_item.as_ref().zip(db_item.as_ref()) {
297 if in_memory_entry.0 <= db_entry.0 {
300 in_memory_item.take()
301 } else {
302 db_item.take()
303 }
304 } else {
305 db_item.or(in_memory_item)
307 }
308}