1use super::{HashedCursor, HashedCursorFactory, HashedStorageCursor};
2use crate::{
3 forward_cursor::ForwardInMemoryCursor, HashedAccountsSorted, HashedPostStateSorted,
4 HashedStorageSorted,
5};
6use alloy_primitives::{map::B256HashSet, B256};
7use reth_primitives::Account;
8use reth_storage_errors::db::DatabaseError;
9use revm::primitives::FlaggedStorage;
10
11#[derive(Clone, Debug)]
13pub struct HashedPostStateCursorFactory<'a, CF> {
14 cursor_factory: CF,
15 post_state: &'a HashedPostStateSorted,
16}
17
18impl<'a, CF> HashedPostStateCursorFactory<'a, CF> {
19 pub const fn new(cursor_factory: CF, post_state: &'a HashedPostStateSorted) -> Self {
21 Self { cursor_factory, post_state }
22 }
23}
24
25impl<'a, CF: HashedCursorFactory> HashedCursorFactory for HashedPostStateCursorFactory<'a, CF> {
26 type AccountCursor = HashedPostStateAccountCursor<'a, CF::AccountCursor>;
27 type StorageCursor = HashedPostStateStorageCursor<'a, CF::StorageCursor>;
28
29 fn hashed_account_cursor(&self) -> Result<Self::AccountCursor, DatabaseError> {
30 let cursor = self.cursor_factory.hashed_account_cursor()?;
31 Ok(HashedPostStateAccountCursor::new(cursor, &self.post_state.accounts))
32 }
33
34 fn hashed_storage_cursor(
35 &self,
36 hashed_address: B256,
37 ) -> Result<Self::StorageCursor, DatabaseError> {
38 let cursor = self.cursor_factory.hashed_storage_cursor(hashed_address)?;
39 Ok(HashedPostStateStorageCursor::new(cursor, self.post_state.storages.get(&hashed_address)))
40 }
41}
42
43#[derive(Debug)]
46pub struct HashedPostStateAccountCursor<'a, C> {
47 cursor: C,
49 post_state_cursor: ForwardInMemoryCursor<'a, B256, Account>,
51 destroyed_accounts: &'a B256HashSet,
53 last_account: Option<B256>,
56}
57
58impl<'a, C> HashedPostStateAccountCursor<'a, C>
59where
60 C: HashedCursor<Value = Account>,
61{
62 pub const fn new(cursor: C, post_state_accounts: &'a HashedAccountsSorted) -> Self {
64 let post_state_cursor = ForwardInMemoryCursor::new(&post_state_accounts.accounts);
65 let destroyed_accounts = &post_state_accounts.destroyed_accounts;
66 Self { cursor, post_state_cursor, destroyed_accounts, last_account: None }
67 }
68
69 fn is_account_cleared(&self, account: &B256) -> bool {
75 self.destroyed_accounts.contains(account)
76 }
77
78 fn seek_inner(&mut self, key: B256) -> Result<Option<(B256, Account)>, DatabaseError> {
79 let post_state_entry = self.post_state_cursor.seek(&key);
82
83 if post_state_entry.is_some_and(|entry| entry.0 == key) {
86 return Ok(post_state_entry)
87 }
88
89 let mut db_entry = self.cursor.seek(key)?;
92 while db_entry.as_ref().is_some_and(|(address, _)| self.is_account_cleared(address)) {
93 db_entry = self.cursor.next()?;
94 }
95
96 Ok(Self::compare_entries(post_state_entry, db_entry))
98 }
99
100 fn next_inner(&mut self, last_account: B256) -> Result<Option<(B256, Account)>, DatabaseError> {
101 let post_state_entry = self.post_state_cursor.first_after(&last_account);
103
104 let mut db_entry = self.cursor.seek(last_account)?;
106 while db_entry.as_ref().is_some_and(|(address, _)| {
107 address <= &last_account || self.is_account_cleared(address)
108 }) {
109 db_entry = self.cursor.next()?;
110 }
111
112 Ok(Self::compare_entries(post_state_entry, db_entry))
114 }
115
116 fn compare_entries(
121 post_state_item: Option<(B256, Account)>,
122 db_item: Option<(B256, Account)>,
123 ) -> Option<(B256, Account)> {
124 if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) {
125 Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry })
128 } else {
129 db_item.or(post_state_item)
131 }
132 }
133}
134
135impl<C> HashedCursor for HashedPostStateAccountCursor<'_, C>
136where
137 C: HashedCursor<Value = Account>,
138{
139 type Value = Account;
140
141 fn seek(&mut self, key: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
150 let entry = self.seek_inner(key)?;
152 self.last_account = entry.as_ref().map(|entry| entry.0);
153 Ok(entry)
154 }
155
156 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
164 let next = match self.last_account {
165 Some(account) => {
166 let entry = self.next_inner(account)?;
167 self.last_account = entry.as_ref().map(|entry| entry.0);
168 entry
169 }
170 None => None,
172 };
173 Ok(next)
174 }
175}
176
177#[derive(Debug)]
180pub struct HashedPostStateStorageCursor<'a, C> {
181 cursor: C,
183 post_state_cursor: Option<ForwardInMemoryCursor<'a, B256, FlaggedStorage>>,
185 cleared_slots: Option<&'a B256HashSet>,
187 storage_wiped: bool,
189 last_slot: Option<B256>,
192}
193
194impl<'a, C> HashedPostStateStorageCursor<'a, C>
195where
196 C: HashedStorageCursor<Value = FlaggedStorage>,
197{
198 pub fn new(cursor: C, post_state_storage: Option<&'a HashedStorageSorted>) -> Self {
200 let post_state_cursor =
201 post_state_storage.map(|s| ForwardInMemoryCursor::new(&s.non_zero_valued_slots));
202 let cleared_slots = post_state_storage.map(|s| &s.zero_valued_slots);
203 let storage_wiped = post_state_storage.is_some_and(|s| s.wiped);
204 Self { cursor, post_state_cursor, cleared_slots, storage_wiped, last_slot: None }
205 }
206
207 fn is_slot_zero_valued(&self, slot: &B256) -> bool {
210 self.cleared_slots.is_some_and(|s| s.contains(slot))
211 }
212
213 fn seek_inner(
215 &mut self,
216 subkey: B256,
217 ) -> Result<Option<(B256, FlaggedStorage)>, DatabaseError> {
218 let post_state_entry = self.post_state_cursor.as_mut().and_then(|c| c.seek(&subkey));
220
221 if self.storage_wiped || post_state_entry.is_some_and(|entry| entry.0 == subkey) {
224 return Ok(post_state_entry)
225 }
226
227 let mut db_entry = self.cursor.seek(subkey)?;
230 while db_entry.as_ref().is_some_and(|entry| self.is_slot_zero_valued(&entry.0)) {
231 db_entry = self.cursor.next()?;
232 }
233
234 Ok(Self::compare_entries(post_state_entry, db_entry))
236 }
237
238 fn next_inner(
240 &mut self,
241 last_slot: B256,
242 ) -> Result<Option<(B256, FlaggedStorage)>, DatabaseError> {
243 let post_state_entry =
245 self.post_state_cursor.as_mut().and_then(|c| c.first_after(&last_slot));
246
247 if self.storage_wiped {
249 return Ok(post_state_entry)
250 }
251
252 let mut db_entry = self.cursor.seek(last_slot)?;
255 while db_entry
256 .as_ref()
257 .is_some_and(|entry| entry.0 == last_slot || self.is_slot_zero_valued(&entry.0))
258 {
259 db_entry = self.cursor.next()?;
260 }
261
262 Ok(Self::compare_entries(post_state_entry, db_entry))
264 }
265
266 fn compare_entries(
271 post_state_item: Option<(B256, FlaggedStorage)>,
272 db_item: Option<(B256, FlaggedStorage)>,
273 ) -> Option<(B256, FlaggedStorage)> {
274 if let Some((post_state_entry, db_entry)) = post_state_item.zip(db_item) {
275 Some(if post_state_entry.0 <= db_entry.0 { post_state_entry } else { db_entry })
278 } else {
279 db_item.or(post_state_item)
281 }
282 }
283}
284
285impl<C> HashedCursor for HashedPostStateStorageCursor<'_, C>
286where
287 C: HashedStorageCursor<Value = FlaggedStorage>,
288{
289 type Value = FlaggedStorage;
290
291 fn seek(&mut self, subkey: B256) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
293 let entry = self.seek_inner(subkey)?;
294 self.last_slot = entry.as_ref().map(|entry| entry.0);
295 Ok(entry)
296 }
297
298 fn next(&mut self) -> Result<Option<(B256, Self::Value)>, DatabaseError> {
300 let next = match self.last_slot {
301 Some(last_slot) => {
302 let entry = self.next_inner(last_slot)?;
303 self.last_slot = entry.as_ref().map(|entry| entry.0);
304 entry
305 }
306 None => None,
308 };
309 Ok(next)
310 }
311}
312
313impl<C> HashedStorageCursor for HashedPostStateStorageCursor<'_, C>
314where
315 C: HashedStorageCursor<Value = FlaggedStorage>,
316{
317 fn is_storage_empty(&mut self) -> Result<bool, DatabaseError> {
322 let is_empty = match &self.post_state_cursor {
323 Some(cursor) => {
324 self.storage_wiped &&
326 cursor.is_empty()
328 }
329 None => self.cursor.is_storage_empty()?,
330 };
331 Ok(is_empty)
332 }
333}