1use crate::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory, PrefixSetLoader};
2use alloy_primitives::{map::B256Map, BlockNumber, B256};
3use reth_db_api::{
4 cursor::DbCursorRO,
5 models::{AccountBeforeTx, BlockNumberAddress, BlockNumberAddressRange},
6 tables,
7 transaction::DbTx,
8 DatabaseError,
9};
10use reth_execution_errors::StateRootError;
11use reth_trie::{
12 hashed_cursor::HashedPostStateCursorFactory, trie_cursor::InMemoryTrieCursorFactory,
13 updates::TrieUpdates, HashedPostStateSorted, HashedStorageSorted, KeccakKeyHasher, KeyHasher,
14 StateRoot, StateRootProgress, TrieInputSorted,
15};
16use std::{
17 collections::HashSet,
18 ops::{RangeBounds, RangeInclusive},
19};
20use tracing::{debug, instrument};
21
22pub trait DatabaseStateRoot<'a, TX>: Sized {
24 fn from_tx(tx: &'a TX) -> Self;
26
27 fn incremental_root_calculator(
34 tx: &'a TX,
35 range: RangeInclusive<BlockNumber>,
36 ) -> Result<Self, StateRootError>;
37
38 fn incremental_root(
45 tx: &'a TX,
46 range: RangeInclusive<BlockNumber>,
47 ) -> Result<B256, StateRootError>;
48
49 fn incremental_root_with_updates(
58 tx: &'a TX,
59 range: RangeInclusive<BlockNumber>,
60 ) -> Result<(B256, TrieUpdates), StateRootError>;
61
62 fn incremental_root_with_progress(
69 tx: &'a TX,
70 range: RangeInclusive<BlockNumber>,
71 ) -> Result<StateRootProgress, StateRootError>;
72
73 fn overlay_root(tx: &'a TX, post_state: &HashedPostStateSorted)
106 -> Result<B256, StateRootError>;
107
108 fn overlay_root_with_updates(
111 tx: &'a TX,
112 post_state: &HashedPostStateSorted,
113 ) -> Result<(B256, TrieUpdates), StateRootError>;
114
115 fn overlay_root_from_nodes(tx: &'a TX, input: TrieInputSorted) -> Result<B256, StateRootError>;
118
119 fn overlay_root_from_nodes_with_updates(
122 tx: &'a TX,
123 input: TrieInputSorted,
124 ) -> Result<(B256, TrieUpdates), StateRootError>;
125}
126
127pub trait DatabaseHashedPostState<TX>: Sized {
130 fn from_reverts<KH: KeyHasher>(
133 tx: &TX,
134 range: impl RangeBounds<BlockNumber>,
135 ) -> Result<HashedPostStateSorted, DatabaseError>;
136}
137
138impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX>
139 for StateRoot<DatabaseTrieCursorFactory<&'a TX>, DatabaseHashedCursorFactory<&'a TX>>
140{
141 fn from_tx(tx: &'a TX) -> Self {
142 Self::new(DatabaseTrieCursorFactory::new(tx), DatabaseHashedCursorFactory::new(tx))
143 }
144
145 fn incremental_root_calculator(
146 tx: &'a TX,
147 range: RangeInclusive<BlockNumber>,
148 ) -> Result<Self, StateRootError> {
149 let loaded_prefix_sets = PrefixSetLoader::<_, KeccakKeyHasher>::new(tx).load(range)?;
150 Ok(Self::from_tx(tx).with_prefix_sets(loaded_prefix_sets))
151 }
152
153 fn incremental_root(
154 tx: &'a TX,
155 range: RangeInclusive<BlockNumber>,
156 ) -> Result<B256, StateRootError> {
157 debug!(target: "trie::loader", ?range, "incremental state root");
158 Self::incremental_root_calculator(tx, range)?.root()
159 }
160
161 fn incremental_root_with_updates(
162 tx: &'a TX,
163 range: RangeInclusive<BlockNumber>,
164 ) -> Result<(B256, TrieUpdates), StateRootError> {
165 debug!(target: "trie::loader", ?range, "incremental state root");
166 Self::incremental_root_calculator(tx, range)?.root_with_updates()
167 }
168
169 fn incremental_root_with_progress(
170 tx: &'a TX,
171 range: RangeInclusive<BlockNumber>,
172 ) -> Result<StateRootProgress, StateRootError> {
173 debug!(target: "trie::loader", ?range, "incremental state root with progress");
174 Self::incremental_root_calculator(tx, range)?.root_with_progress()
175 }
176
177 fn overlay_root(
178 tx: &'a TX,
179 post_state: &HashedPostStateSorted,
180 ) -> Result<B256, StateRootError> {
181 let prefix_sets = post_state.construct_prefix_sets().freeze();
182 StateRoot::new(
183 DatabaseTrieCursorFactory::new(tx),
184 HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), post_state),
185 )
186 .with_prefix_sets(prefix_sets)
187 .root()
188 }
189
190 fn overlay_root_with_updates(
191 tx: &'a TX,
192 post_state: &HashedPostStateSorted,
193 ) -> Result<(B256, TrieUpdates), StateRootError> {
194 let prefix_sets = post_state.construct_prefix_sets().freeze();
195 StateRoot::new(
196 DatabaseTrieCursorFactory::new(tx),
197 HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), post_state),
198 )
199 .with_prefix_sets(prefix_sets)
200 .root_with_updates()
201 }
202
203 fn overlay_root_from_nodes(tx: &'a TX, input: TrieInputSorted) -> Result<B256, StateRootError> {
204 StateRoot::new(
205 InMemoryTrieCursorFactory::new(
206 DatabaseTrieCursorFactory::new(tx),
207 input.nodes.as_ref(),
208 ),
209 HashedPostStateCursorFactory::new(
210 DatabaseHashedCursorFactory::new(tx),
211 input.state.as_ref(),
212 ),
213 )
214 .with_prefix_sets(input.prefix_sets.freeze())
215 .root()
216 }
217
218 fn overlay_root_from_nodes_with_updates(
219 tx: &'a TX,
220 input: TrieInputSorted,
221 ) -> Result<(B256, TrieUpdates), StateRootError> {
222 StateRoot::new(
223 InMemoryTrieCursorFactory::new(
224 DatabaseTrieCursorFactory::new(tx),
225 input.nodes.as_ref(),
226 ),
227 HashedPostStateCursorFactory::new(
228 DatabaseHashedCursorFactory::new(tx),
229 input.state.as_ref(),
230 ),
231 )
232 .with_prefix_sets(input.prefix_sets.freeze())
233 .root_with_updates()
234 }
235}
236
237impl<TX: DbTx> DatabaseHashedPostState<TX> for HashedPostStateSorted {
238 #[instrument(target = "trie::db", skip(tx), fields(range))]
246 fn from_reverts<KH: KeyHasher>(
247 tx: &TX,
248 range: impl RangeBounds<BlockNumber>,
249 ) -> Result<Self, DatabaseError> {
250 let mut accounts = Vec::new();
253 let mut seen_accounts = HashSet::new();
254 let account_range = (range.start_bound(), range.end_bound());
255 let mut account_changesets_cursor = tx.cursor_read::<tables::AccountChangeSets>()?;
256
257 for entry in account_changesets_cursor.walk_range(account_range)? {
258 let (_, AccountBeforeTx { address, info }) = entry?;
259 if seen_accounts.insert(address) {
260 accounts.push((KH::hash_key(address), info));
261 }
262 }
263 accounts.sort_unstable_by_key(|(hash, _)| *hash);
264
265 let storage_range: BlockNumberAddressRange = range.into();
268 let mut storages = B256Map::<Vec<_>>::default();
269 let mut seen_storage_keys = HashSet::new();
270 let mut storage_changesets_cursor = tx.cursor_read::<tables::StorageChangeSets>()?;
271
272 for entry in storage_changesets_cursor.walk_range(storage_range)? {
273 let (BlockNumberAddress((_, address)), storage) = entry?;
274 if seen_storage_keys.insert((address, storage.key)) {
275 let hashed_address = KH::hash_key(address);
276 storages
277 .entry(hashed_address)
278 .or_default()
279 .push((KH::hash_key(storage.key), storage.value));
280 }
281 }
282
283 let hashed_storages = storages
285 .into_iter()
286 .map(|(address, mut slots)| {
287 slots.sort_unstable_by_key(|(slot, _)| *slot);
288 (address, HashedStorageSorted { storage_slots: slots, wiped: false })
289 })
290 .collect();
291
292 Ok(Self::new(accounts, hashed_storages))
293 }
294}
295
296#[cfg(test)]
297mod tests {
298 use super::*;
299 use alloy_primitives::{hex, map::HashMap, Address, B256, U256};
300 use reth_db::test_utils::create_test_rw_db;
301 use reth_db_api::{
302 database::Database,
303 models::{AccountBeforeTx, BlockNumberAddress},
304 tables,
305 transaction::DbTxMut,
306 };
307 use reth_primitives_traits::{Account, StorageEntry};
308 use reth_trie::{HashedPostState, HashedStorage, KeccakKeyHasher};
309 use revm::state::AccountInfo;
310 use revm_database::BundleState;
311
312 #[test]
314 fn overlay_root_with_sorted_state() {
315 let db = create_test_rw_db();
316 let tx = db.tx().expect("failed to create transaction");
317
318 let mut hashed_state = HashedPostState::default();
319 hashed_state.accounts.insert(
320 B256::from(U256::from(1)),
321 Some(Account { nonce: 1, balance: U256::from(10), bytecode_hash: None }),
322 );
323 hashed_state.accounts.insert(B256::from(U256::from(2)), None);
324 hashed_state.storages.insert(
325 B256::from(U256::from(1)),
326 HashedStorage::from_iter(false, [(B256::from(U256::from(3)), U256::from(30))]),
327 );
328
329 let sorted = hashed_state.into_sorted();
330 let overlay_root = StateRoot::overlay_root(&tx, &sorted).unwrap();
331
332 assert!(!overlay_root.is_zero());
334 }
335
336 #[test]
338 fn from_bundle_state_with_rayon() {
339 let address1 = Address::with_last_byte(1);
340 let address2 = Address::with_last_byte(2);
341 let slot1 = U256::from(1015);
342 let slot2 = U256::from(2015);
343
344 let account1 = AccountInfo { nonce: 1, ..Default::default() };
345 let account2 = AccountInfo { nonce: 2, ..Default::default() };
346
347 let bundle_state = BundleState::builder(2..=2)
348 .state_present_account_info(address1, account1)
349 .state_present_account_info(address2, account2)
350 .state_storage(address1, HashMap::from_iter([(slot1, (U256::ZERO, U256::from(10)))]))
351 .state_storage(address2, HashMap::from_iter([(slot2, (U256::ZERO, U256::from(20)))]))
352 .build();
353 assert_eq!(bundle_state.reverts.len(), 1);
354
355 let post_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(&bundle_state.state);
356 assert_eq!(post_state.accounts.len(), 2);
357 assert_eq!(post_state.storages.len(), 2);
358
359 let db = create_test_rw_db();
360 let tx = db.tx().expect("failed to create transaction");
361 assert_eq!(
362 StateRoot::overlay_root(&tx, &post_state.into_sorted()).unwrap(),
363 hex!("b464525710cafcf5d4044ac85b72c08b1e76231b8d91f288fe438cc41d8eaafd")
364 );
365 }
366
367 #[test]
369 fn from_reverts_keeps_first_occurrence_and_ordering() {
370 let db = create_test_rw_db();
371 let tx = db.tx_mut().expect("failed to create rw tx");
372
373 let address1 = Address::with_last_byte(1);
374 let address2 = Address::with_last_byte(2);
375 let slot1 = B256::from(U256::from(11));
376 let slot2 = B256::from(U256::from(22));
377
378 tx.put::<tables::AccountChangeSets>(
380 1,
381 AccountBeforeTx {
382 address: address1,
383 info: Some(Account { nonce: 1, ..Default::default() }),
384 },
385 )
386 .unwrap();
387 tx.put::<tables::AccountChangeSets>(
388 2,
389 AccountBeforeTx {
390 address: address1,
391 info: Some(Account { nonce: 2, ..Default::default() }),
392 },
393 )
394 .unwrap();
395 tx.put::<tables::AccountChangeSets>(3, AccountBeforeTx { address: address2, info: None })
396 .unwrap();
397
398 tx.put::<tables::StorageChangeSets>(
400 BlockNumberAddress((1, address1)),
401 StorageEntry { key: slot2, value: U256::from(200) },
402 )
403 .unwrap();
404 tx.put::<tables::StorageChangeSets>(
405 BlockNumberAddress((2, address1)),
406 StorageEntry { key: slot1, value: U256::from(100) },
407 )
408 .unwrap();
409 tx.put::<tables::StorageChangeSets>(
410 BlockNumberAddress((3, address1)),
411 StorageEntry { key: slot1, value: U256::from(999) }, )
413 .unwrap();
414
415 tx.commit().unwrap();
416 let tx = db.tx().expect("failed to create ro tx");
417
418 let sorted = HashedPostStateSorted::from_reverts::<KeccakKeyHasher>(&tx, 1..=3).unwrap();
419
420 assert_eq!(sorted.accounts.len(), 2);
422 let hashed_addr1 = KeccakKeyHasher::hash_key(address1);
423 let account1 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr1).unwrap();
424 assert_eq!(account1.1.unwrap().nonce, 1);
425
426 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
428
429 for storage in sorted.storages.values() {
431 assert!(storage.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
432 }
433 }
434
435 #[test]
437 fn from_reverts_empty_range() {
438 let db = create_test_rw_db();
439
440 db.update(|tx| {
442 tx.put::<tables::AccountChangeSets>(
443 100,
444 AccountBeforeTx {
445 address: Address::with_last_byte(1),
446 info: Some(Account { nonce: 1, ..Default::default() }),
447 },
448 )
449 .unwrap();
450 })
451 .unwrap();
452
453 let tx = db.tx().unwrap();
454
455 let sorted = HashedPostStateSorted::from_reverts::<KeccakKeyHasher>(&tx, 1..=10).unwrap();
457 assert!(sorted.accounts.is_empty());
458 assert!(sorted.storages.is_empty());
459 }
460}