1use super::{HashedCursor, HashedCursorFactory, HashedStorageCursor};
2use crate::forward_cursor::ForwardInMemoryCursor;
3use alloy_primitives::{map::B256Set, B256};
4use reth_primitives_traits::Account;
5use reth_storage_errors::db::DatabaseError;
6use reth_trie_common::{HashedAccountsSorted, HashedPostStateSorted, HashedStorageSorted};
7use revm_state::FlaggedStorage;
8
9#[derive(Clone, Debug)]
11pub struct HashedPostStateCursorFactory<'a, CF> {
12 cursor_factory: CF,
13 post_state: &'a HashedPostStateSorted,
14}
15
16impl<'a, CF> HashedPostStateCursorFactory<'a, CF> {
17 pub const fn new(cursor_factory: CF, post_state: &'a HashedPostStateSorted) -> Self {
19 Self { cursor_factory, post_state }
20 }
21}
22
23impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorFactory<'a, CF> {
24 type AccountCursor = HashedPostStateAccountCursor<'a, CF::AccountCursor>;
25 type StorageCursor = HashedPostStateStorageCursor<'a, CF::StorageCursor>;
26
27 fn hashed_account_cursor(&self) -> Result<Self::AccountCursor, DatabaseError> {
28 let cursor = self.cursor_factory.hashed_account_cursor()?;
29 Ok(HashedPostStateAccountCursor::new(cursor, &self.post_state.accounts))
30 }
31
32 fn hashed_storage_cursor(
33 &self,
34 hashed_address: B256,
35 ) -> Result<Self::StorageCursor, DatabaseError> {
36 let cursor = self.cursor_factory.hashed_storage_cursor(hashed_address)?;
37 Ok(HashedPostStateStorageCursor::new(cursor, self.post_state.storages.get(&hashed_address)))
38 }
39}
40
41#[derive(Debug)]
44pub struct HashedPostStateAccountCursor<'a, C> {
45 cursor: C,
47 post_state_cursor: ForwardInMemoryCursor<'a, B256, Account>,
49 destroyed_accounts: &'a B256Set,
51 last_account: Option<B256>,
54}
55
56impl<'a, C> HashedPostStateAccountCursor<'a, C>
57where
58 C: HashedCursor<Value = Account>,
59{
60 pub fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self {
62 let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts);
63 let destroyed_accounts = &post_state_accounts.destroyed_accounts;
64 Self { cursor, post_state_cursor, destroyed_accounts, last_account: None }
65 }
66
67 fn is_account_cleared(&self, account: &B256) -> bool {
73 self.destroyed_accounts.contains(account)
74 }
75
76 fn seek_inner(&mut self, key: B256) -> Result<Option<(B256, Account)>, DatabaseError> {
77 let post_state_entry = self.post_state_cursor.seek(&key);
80
81 if post_state_entry.is_some_and(|entry| entry.0 == key) {
84 return Ok(post_state_entry);
85 }
86
87 let mut db_entry = self.cursor.seek(key)?;
90 while db_entry.as_ref().is_some_and(|(address, _)| self.is_account_cleared(address)) {
91 db_entry = self.cursor.next()?;
92 }
93
94 Ok(Self::compare_entries(post_state_entry, db_entry))
96 }
97
98 fn next_inner(&mut self, last_account: B256) -> Result<Option<(B256, Account)>, DatabaseError> {
99 let post_state_entry = self.post_state_cursor.first_after(&last_account);
101
102 let mut db_entry = self.cursor.seek(last_account)?;
104 while db_entry.as_ref().is_some_and(|(address, _)| {
105 address <= &last_account || self.is_account_cleared(address)
106 }) {
107 db_entry = self.cursor.next()?;
108 }
109
110 Ok(Self::compare_entries(post_state_entry, db_entry))
112 }
113
114 fn compare_entries(
119 post_state_item: Option<(B256, Account)>,
120 db_item: Option<(B256, Account)>,
121 ) -> Option<(B256, Account)> {
122 if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) {
123 Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry })
126 } else {
127 db_item.or(post_state_item)
129 }
130 }
131}
132
133impl<C> HashedCursor for HashedPostStateAccountCursor<'_, C>
134where
135 C: HashedCursor<Value = Account>,
136{
137 type Value = Account;
138
139 fn seek(&mut self, key: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
148 let entry = self.seek_inner(key)?;
150 self.last_account = entry.as_ref().map(|entry| entry.0);
151 Ok(entry)
152 }
153
154 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
162 let next = match self.last_account {
163 Some(account) => {
164 let entry = self.next_inner(account)?;
165 self.last_account = entry.as_ref().map(|entry| entry.0);
166 entry
167 }
168 None => None,
170 };
171 Ok(next)
172 }
173}
174
175#[derive(Debug)]
178pub struct HashedPostStateStorageCursor<'a, C> {
179 cursor: C,
181 post_state_cursor: Option<ForwardInMemoryCursor<'a, B256, FlaggedStorage>>,
183 cleared_slots: Option<&'a B256Set>,
185 storage_wiped: bool,
187 last_slot: Option<B256>,
190}
191
192impl<'a, C> HashedPostStateStorageCursor<'a, C>
193where
194 C: HashedStorageCursor<Value = FlaggedStorage>,
195{
196 pub fn new(cursor: C, post_state_storage: Option<&'a HashedStorageSorted>) -> Self {
198 let post_state_cursor =
199 post_state_storage.map(|s| ForwardInMemoryCursor::new(&s.non_zero_valued_slots));
200 let cleared_slots = post_state_storage.map(|s| &s.zero_valued_slots);
201 let storage_wiped = post_state_storage.is_some_and(|s| s.wiped);
202 Self { cursor, post_state_cursor, cleared_slots, storage_wiped, last_slot: None }
203 }
204
205 fn is_slot_zero_valued(&self, slot: &B256) -> bool {
208 self.cleared_slots.is_some_and(|s| s.contains(slot))
209 }
210
211 fn seek_inner(
213 &mut self,
214 subkey: B256,
215 ) -> Result<Option<(B256, FlaggedStorage)>, DatabaseError> {
216 let post_state_entry = self.post_state_cursor.as_mut().and_then(|c| c.seek(&subkey));
218
219 if self.storage_wiped || post_state_entry.is_some_and(|entry| entry.0 == subkey) {
222 return Ok(post_state_entry);
223 }
224
225 let mut db_entry = self.cursor.seek(subkey)?;
228 while db_entry.as_ref().is_some_and(|entry| self.is_slot_zero_valued(&entry.0)) {
229 db_entry = self.cursor.next()?;
230 }
231
232 Ok(Self::compare_entries(post_state_entry, db_entry))
234 }
235
236 fn next_inner(
238 &mut self,
239 last_slot: B256,
240 ) -> Result<Option<(B256, FlaggedStorage)>, DatabaseError> {
241 let post_state_entry =
243 self.post_state_cursor.as_mut().and_then(|c| c.first_after(&last_slot));
244
245 if self.storage_wiped {
247 return Ok(post_state_entry);
248 }
249
250 let mut db_entry = self.cursor.seek(last_slot)?;
253 while db_entry
254 .as_ref()
255 .is_some_and(|entry| entry.0 == last_slot || self.is_slot_zero_valued(&entry.0))
256 {
257 db_entry = self.cursor.next()?;
258 }
259
260 Ok(Self::compare_entries(post_state_entry, db_entry))
262 }
263
264 fn compare_entries(
269 post_state_item: Option<(B256, FlaggedStorage)>,
270 db_item: Option<(B256, FlaggedStorage)>,
271 ) -> Option<(B256, FlaggedStorage)> {
272 if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) {
273 Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry })
276 } else {
277 db_item.or(post_state_item)
279 }
280 }
281}
282
283impl<C> HashedCursor for HashedPostStateStorageCursor<'_, C>
284where
285 C: HashedStorageCursor<Value = FlaggedStorage>,
286{
287 type Value = FlaggedStorage;
288
289 fn seek(&mut self, subkey: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
291 let entry = self.seek_inner(subkey)?;
292 self.last_slot = entry.as_ref().map(|entry| entry.0);
293 Ok(entry)
294 }
295
296 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
298 let next = match self.last_slot {
299 Some(last_slot) => {
300 let entry = self.next_inner(last_slot)?;
301 self.last_slot = entry.as_ref().map(|entry| entry.0);
302 entry
303 }
304 None => None,
306 };
307 Ok(next)
308 }
309}
310
311impl<C> HashedStorageCursor for HashedPostStateStorageCursor<'_, C>
312where
313 C: HashedStorageCursor<Value = FlaggedStorage>,
314{
315 fn is_storage_empty(&mut self) -> Result<bool, DatabaseError> {
320 let is_empty = match &self.post_state_cursor {
321 Some(cursor) => {
322 self.storage_wiped &&
324 cursor.is_empty()
326 }
327 None => self.cursor.is_storage_empty()?,
328 };
329 Ok(is_empty)
330 }
331}