1use super::{HashedCursor, HashedCursorFactory, HashedStorageCursor};
2use crate::forward_cursor::ForwardInMemoryCursor;
3use alloy_primitives::{map::B256Set, B256, U256};
4use reth_primitives_traits::Account;
5use reth_storage_errors::db::DatabaseError;
6use reth_trie_common::{HashedAccountsSorted, HashedPostStateSorted, HashedStorageSorted};
7
8#[derive(Clone, Debug)]
10pub struct HashedPostStateCursorFactory<'a, CF> {
11 cursor_factory: CF,
12 post_state: &'a HashedPostStateSorted,
13}
14
15impl<'a, CF> HashedPostStateCursorFactory<'a, CF> {
16 pub const fn new(cursor_factory: CF, post_state: &'a HashedPostStateSorted) -> Self {
18 Self { cursor_factory, post_state }
19 }
20}
21
22impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorFactory<'a, CF> {
23 type AccountCursor = HashedPostStateAccountCursor<'a, CF::AccountCursor>;
24 type StorageCursor = HashedPostStateStorageCursor<'a, CF::StorageCursor>;
25
26 fn hashed_account_cursor(&self) -> Result<Self::AccountCursor, DatabaseError> {
27 let cursor = self.cursor_factory.hashed_account_cursor()?;
28 Ok(HashedPostStateAccountCursor::new(cursor, &self.post_state.accounts))
29 }
30
31 fn hashed_storage_cursor(
32 &self,
33 hashed_address: B256,
34 ) -> Result<Self::StorageCursor, DatabaseError> {
35 let cursor = self.cursor_factory.hashed_storage_cursor(hashed_address)?;
36 Ok(HashedPostStateStorageCursor::new(cursor, self.post_state.storages.get(&hashed_address)))
37 }
38}
39
40#[derive(Debug)]
43pub struct HashedPostStateAccountCursor<'a, C> {
44 cursor: C,
46 post_state_cursor: ForwardInMemoryCursor<'a, B256, Account>,
48 destroyed_accounts: &'a B256Set,
50 last_account: Option<B256>,
53}
54
55impl<'a, C> HashedPostStateAccountCursor<'a, C>
56where
57 C: HashedCursor<Value = Account>,
58{
59 pub fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self {
61 let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts);
62 let destroyed_accounts = &post_state_accounts.destroyed_accounts;
63 Self { cursor, post_state_cursor, destroyed_accounts, last_account: None }
64 }
65
66 fn is_account_cleared(&self, account: &B256) -> bool {
72 self.destroyed_accounts.contains(account)
73 }
74
75 fn seek_inner(&mut self, key: B256) -> Result<Option<(B256, Account)>, DatabaseError> {
76 let post_state_entry = self.post_state_cursor.seek(&key);
79
80 if post_state_entry.is_some_and(|entry| entry.0 == key) {
83 return Ok(post_state_entry)
84 }
85
86 let mut db_entry = self.cursor.seek(key)?;
89 while db_entry.as_ref().is_some_and(|(address, _)| self.is_account_cleared(address)) {
90 db_entry = self.cursor.next()?;
91 }
92
93 Ok(Self::compare_entries(post_state_entry, db_entry))
95 }
96
97 fn next_inner(&mut self, last_account: B256) -> Result<Option<(B256, Account)>, DatabaseError> {
98 let post_state_entry = self.post_state_cursor.first_after(&last_account);
100
101 let mut db_entry = self.cursor.seek(last_account)?;
103 while db_entry.as_ref().is_some_and(|(address, _)| {
104 address <= &last_account || self.is_account_cleared(address)
105 }) {
106 db_entry = self.cursor.next()?;
107 }
108
109 Ok(Self::compare_entries(post_state_entry, db_entry))
111 }
112
113 fn compare_entries(
118 post_state_item: Option<(B256, Account)>,
119 db_item: Option<(B256, Account)>,
120 ) -> Option<(B256, Account)> {
121 if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) {
122 Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry })
125 } else {
126 db_item.or(post_state_item)
128 }
129 }
130}
131
132impl<C> HashedCursor for HashedPostStateAccountCursor<'_, C>
133where
134 C: HashedCursor<Value = Account>,
135{
136 type Value = Account;
137
138 fn seek(&mut self, key: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
147 let entry = self.seek_inner(key)?;
149 self.last_account = entry.as_ref().map(|entry| entry.0);
150 Ok(entry)
151 }
152
153 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
161 let next = match self.last_account {
162 Some(account) => {
163 let entry = self.next_inner(account)?;
164 self.last_account = entry.as_ref().map(|entry| entry.0);
165 entry
166 }
167 None => None,
169 };
170 Ok(next)
171 }
172}
173
174#[derive(Debug)]
177pub struct HashedPostStateStorageCursor<'a, C> {
178 cursor: C,
180 post_state_cursor: Option<ForwardInMemoryCursor<'a, B256, U256>>,
182 cleared_slots: Option<&'a B256Set>,
184 storage_wiped: bool,
186 last_slot: Option<B256>,
189}
190
191impl<'a, C> HashedPostStateStorageCursor<'a, C>
192where
193 C: HashedStorageCursor<Value = U256>,
194{
195 pub fn new(cursor: C, post_state_storage: Option<&'a HashedStorageSorted>) -> Self {
197 let post_state_cursor =
198 post_state_storage.map(|s| ForwardInMemoryCursor::new(&s.non_zero_valued_slots));
199 let cleared_slots = post_state_storage.map(|s| &s.zero_valued_slots);
200 let storage_wiped = post_state_storage.is_some_and(|s| s.wiped);
201 Self { cursor, post_state_cursor, cleared_slots, storage_wiped, last_slot: None }
202 }
203
204 fn is_slot_zero_valued(&self, slot: &B256) -> bool {
207 self.cleared_slots.is_some_and(|s| s.contains(slot))
208 }
209
210 fn seek_inner(&mut self, subkey: B256) -> Result<Option<(B256, U256)>, DatabaseError> {
212 let post_state_entry = self.post_state_cursor.as_mut().and_then(|c| c.seek(&subkey));
214
215 if self.storage_wiped || post_state_entry.is_some_and(|entry| entry.0 == subkey) {
218 return Ok(post_state_entry)
219 }
220
221 let mut db_entry = self.cursor.seek(subkey)?;
224 while db_entry.as_ref().is_some_and(|entry| self.is_slot_zero_valued(&entry.0)) {
225 db_entry = self.cursor.next()?;
226 }
227
228 Ok(Self::compare_entries(post_state_entry, db_entry))
230 }
231
232 fn next_inner(&mut self, last_slot: B256) -> Result<Option<(B256, U256)>, DatabaseError> {
234 let post_state_entry =
236 self.post_state_cursor.as_mut().and_then(|c| c.first_after(&last_slot));
237
238 if self.storage_wiped {
240 return Ok(post_state_entry)
241 }
242
243 let mut db_entry = self.cursor.seek(last_slot)?;
246 while db_entry
247 .as_ref()
248 .is_some_and(|entry| entry.0 == last_slot || self.is_slot_zero_valued(&entry.0))
249 {
250 db_entry = self.cursor.next()?;
251 }
252
253 Ok(Self::compare_entries(post_state_entry, db_entry))
255 }
256
257 fn compare_entries(
262 post_state_item: Option<(B256, U256)>,
263 db_item: Option<(B256, U256)>,
264 ) -> Option<(B256, U256)> {
265 if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) {
266 Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry })
269 } else {
270 db_item.or(post_state_item)
272 }
273 }
274}
275
276impl<C> HashedCursor for HashedPostStateStorageCursor<'_, C>
277where
278 C: HashedStorageCursor<Value = U256>,
279{
280 type Value = U256;
281
282 fn seek(&mut self, subkey: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
284 let entry = self.seek_inner(subkey)?;
285 self.last_slot = entry.as_ref().map(|entry| entry.0);
286 Ok(entry)
287 }
288
289 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
291 let next = match self.last_slot {
292 Some(last_slot) => {
293 let entry = self.next_inner(last_slot)?;
294 self.last_slot = entry.as_ref().map(|entry| entry.0);
295 entry
296 }
297 None => None,
299 };
300 Ok(next)
301 }
302}
303
304impl<C> HashedStorageCursor for HashedPostStateStorageCursor<'_, C>
305where
306 C: HashedStorageCursor<Value = U256>,
307{
308 fn is_storage_empty(&mut self) -> Result<bool, DatabaseError> {
313 let is_empty = match &self.post_state_cursor {
314 Some(cursor) => {
315 self.storage_wiped &&
317 cursor.is_empty()
319 }
320 None => self.cursor.is_storage_empty()?,
321 };
322 Ok(is_empty)
323 }
324}