1use crate::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
2use alloy_primitives::{keccak256, map::B256Map, BlockNumber, B256};
3use reth_db_api::{
4 models::{AccountBeforeTx, BlockNumberAddress},
5 transaction::DbTx,
6};
7use reth_execution_errors::StateRootError;
8use reth_storage_api::{
9 BlockNumReader, ChangeSetReader, DBProvider, StorageChangeSetReader, StorageSettingsCache,
10};
11use reth_storage_errors::provider::ProviderError;
12use reth_trie::{
13 hashed_cursor::HashedPostStateCursorFactory, trie_cursor::InMemoryTrieCursorFactory,
14 updates::TrieUpdates, HashedPostStateSorted, HashedStorageSorted, StateRoot, StateRootProgress,
15 TrieInputSorted,
16};
17use std::{
18 collections::HashSet,
19 ops::{Bound, RangeBounds, RangeInclusive},
20};
21use tracing::{debug, instrument};
22
23pub trait DatabaseStateRoot<'a, TX>: Sized {
25 fn from_tx(tx: &'a TX) -> Self;
27
28 fn incremental_root_calculator(
35 provider: &'a (impl ChangeSetReader
36 + StorageChangeSetReader
37 + StorageSettingsCache
38 + DBProvider<Tx = TX>),
39 range: RangeInclusive<BlockNumber>,
40 ) -> Result<Self, StateRootError>;
41
42 fn incremental_root(
49 provider: &'a (impl ChangeSetReader
50 + StorageChangeSetReader
51 + StorageSettingsCache
52 + DBProvider<Tx = TX>),
53 range: RangeInclusive<BlockNumber>,
54 ) -> Result<B256, StateRootError>;
55
56 fn incremental_root_with_updates(
65 provider: &'a (impl ChangeSetReader
66 + StorageChangeSetReader
67 + StorageSettingsCache
68 + DBProvider<Tx = TX>),
69 range: RangeInclusive<BlockNumber>,
70 ) -> Result<(B256, TrieUpdates), StateRootError>;
71
72 fn incremental_root_with_progress(
79 provider: &'a (impl ChangeSetReader
80 + StorageChangeSetReader
81 + StorageSettingsCache
82 + DBProvider<Tx = TX>),
83 range: RangeInclusive<BlockNumber>,
84 ) -> Result<StateRootProgress, StateRootError>;
85
86 fn overlay_root(tx: &'a TX, post_state: &HashedPostStateSorted)
119 -> Result<B256, StateRootError>;
120
121 fn overlay_root_with_updates(
124 tx: &'a TX,
125 post_state: &HashedPostStateSorted,
126 ) -> Result<(B256, TrieUpdates), StateRootError>;
127
128 fn overlay_root_from_nodes(tx: &'a TX, input: TrieInputSorted) -> Result<B256, StateRootError>;
131
132 fn overlay_root_from_nodes_with_updates(
135 tx: &'a TX,
136 input: TrieInputSorted,
137 ) -> Result<(B256, TrieUpdates), StateRootError>;
138}
139
140pub trait DatabaseHashedPostState: Sized {
143 fn from_reverts(
151 provider: &(impl ChangeSetReader + StorageChangeSetReader + BlockNumReader + DBProvider),
152 range: impl RangeBounds<BlockNumber>,
153 ) -> Result<HashedPostStateSorted, ProviderError>;
154}
155
156impl<'a, TX: DbTx> DatabaseStateRoot<'a, TX>
157 for StateRoot<DatabaseTrieCursorFactory<&'a TX>, DatabaseHashedCursorFactory<&'a TX>>
158{
159 fn from_tx(tx: &'a TX) -> Self {
160 Self::new(DatabaseTrieCursorFactory::new(tx), DatabaseHashedCursorFactory::new(tx))
161 }
162
163 fn incremental_root_calculator(
164 provider: &'a (impl ChangeSetReader
165 + StorageChangeSetReader
166 + StorageSettingsCache
167 + DBProvider<Tx = TX>),
168 range: RangeInclusive<BlockNumber>,
169 ) -> Result<Self, StateRootError> {
170 let loaded_prefix_sets =
171 crate::prefix_set::load_prefix_sets_with_provider(provider, range)?;
172 Ok(Self::from_tx(provider.tx_ref()).with_prefix_sets(loaded_prefix_sets))
173 }
174
175 fn incremental_root(
176 provider: &'a (impl ChangeSetReader
177 + StorageChangeSetReader
178 + StorageSettingsCache
179 + DBProvider<Tx = TX>),
180 range: RangeInclusive<BlockNumber>,
181 ) -> Result<B256, StateRootError> {
182 debug!(target: "trie::loader", ?range, "incremental state root");
183 Self::incremental_root_calculator(provider, range)?.root()
184 }
185
186 fn incremental_root_with_updates(
187 provider: &'a (impl ChangeSetReader
188 + StorageChangeSetReader
189 + StorageSettingsCache
190 + DBProvider<Tx = TX>),
191 range: RangeInclusive<BlockNumber>,
192 ) -> Result<(B256, TrieUpdates), StateRootError> {
193 debug!(target: "trie::loader", ?range, "incremental state root");
194 Self::incremental_root_calculator(provider, range)?.root_with_updates()
195 }
196
197 fn incremental_root_with_progress(
198 provider: &'a (impl ChangeSetReader
199 + StorageChangeSetReader
200 + StorageSettingsCache
201 + DBProvider<Tx = TX>),
202 range: RangeInclusive<BlockNumber>,
203 ) -> Result<StateRootProgress, StateRootError> {
204 debug!(target: "trie::loader", ?range, "incremental state root with progress");
205 Self::incremental_root_calculator(provider, range)?.root_with_progress()
206 }
207
208 fn overlay_root(
209 tx: &'a TX,
210 post_state: &HashedPostStateSorted,
211 ) -> Result<B256, StateRootError> {
212 let prefix_sets = post_state.construct_prefix_sets().freeze();
213 StateRoot::new(
214 DatabaseTrieCursorFactory::new(tx),
215 HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), post_state),
216 )
217 .with_prefix_sets(prefix_sets)
218 .root()
219 }
220
221 fn overlay_root_with_updates(
222 tx: &'a TX,
223 post_state: &HashedPostStateSorted,
224 ) -> Result<(B256, TrieUpdates), StateRootError> {
225 let prefix_sets = post_state.construct_prefix_sets().freeze();
226 StateRoot::new(
227 DatabaseTrieCursorFactory::new(tx),
228 HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), post_state),
229 )
230 .with_prefix_sets(prefix_sets)
231 .root_with_updates()
232 }
233
234 fn overlay_root_from_nodes(tx: &'a TX, input: TrieInputSorted) -> Result<B256, StateRootError> {
235 StateRoot::new(
236 InMemoryTrieCursorFactory::new(
237 DatabaseTrieCursorFactory::new(tx),
238 input.nodes.as_ref(),
239 ),
240 HashedPostStateCursorFactory::new(
241 DatabaseHashedCursorFactory::new(tx),
242 input.state.as_ref(),
243 ),
244 )
245 .with_prefix_sets(input.prefix_sets.freeze())
246 .root()
247 }
248
249 fn overlay_root_from_nodes_with_updates(
250 tx: &'a TX,
251 input: TrieInputSorted,
252 ) -> Result<(B256, TrieUpdates), StateRootError> {
253 StateRoot::new(
254 InMemoryTrieCursorFactory::new(
255 DatabaseTrieCursorFactory::new(tx),
256 input.nodes.as_ref(),
257 ),
258 HashedPostStateCursorFactory::new(
259 DatabaseHashedCursorFactory::new(tx),
260 input.state.as_ref(),
261 ),
262 )
263 .with_prefix_sets(input.prefix_sets.freeze())
264 .root_with_updates()
265 }
266}
267
268pub fn from_reverts_auto(
273 provider: &(impl ChangeSetReader
274 + StorageChangeSetReader
275 + BlockNumReader
276 + DBProvider
277 + StorageSettingsCache),
278 range: impl RangeBounds<BlockNumber>,
279) -> Result<HashedPostStateSorted, ProviderError> {
280 HashedPostStateSorted::from_reverts(provider, range)
281}
282
283impl DatabaseHashedPostState for HashedPostStateSorted {
284 #[instrument(target = "trie::db", skip(provider), fields(range))]
295 fn from_reverts(
296 provider: &(impl ChangeSetReader + StorageChangeSetReader + BlockNumReader + DBProvider),
297 range: impl RangeBounds<BlockNumber>,
298 ) -> Result<Self, ProviderError> {
299 let start = match range.start_bound() {
301 Bound::Included(&n) => n,
302 Bound::Excluded(&n) => n + 1,
303 Bound::Unbounded => 0,
304 };
305
306 let end = match range.end_bound() {
307 Bound::Included(&n) => n + 1,
308 Bound::Excluded(&n) => n,
309 Bound::Unbounded => BlockNumber::MAX,
310 };
311
312 let mut accounts = Vec::new();
314 let mut seen_accounts = HashSet::new();
315 for entry in provider.account_changesets_range(start..end)? {
316 let (_, AccountBeforeTx { address, info }) = entry;
317 if seen_accounts.insert(address) {
318 accounts.push((keccak256(address), info));
319 }
320 }
321 accounts.sort_unstable_by_key(|(hash, _)| *hash);
322
323 let mut storages = B256Map::<Vec<_>>::default();
326 let mut seen_storage_keys = HashSet::new();
327
328 if start < end {
329 let end_inclusive = end.saturating_sub(1);
330 for (BlockNumberAddress((_, address)), storage) in
331 provider.storage_changesets_range(start..=end_inclusive)?
332 {
333 if seen_storage_keys.insert((address, storage.key.as_b256())) {
334 let hashed_address = keccak256(address);
335 storages
336 .entry(hashed_address)
337 .or_default()
338 .push((storage.key.to_hashed(), storage.value));
339 }
340 }
341 }
342
343 let hashed_storages = storages
345 .into_iter()
346 .map(|(address, mut slots)| {
347 slots.sort_unstable_by_key(|(slot, _)| *slot);
348 (address, HashedStorageSorted { storage_slots: slots, wiped: false })
349 })
350 .collect();
351
352 Ok(Self::new(accounts, hashed_storages))
353 }
354}
355
356#[cfg(test)]
357mod tests {
358 use super::*;
359 use alloy_primitives::{hex, keccak256, map::HashMap, Address, B256, U256};
360 use reth_db::test_utils::create_test_rw_db;
361 use reth_db_api::{
362 database::Database,
363 models::{AccountBeforeTx, BlockNumberAddress},
364 tables,
365 transaction::DbTxMut,
366 };
367 use reth_primitives_traits::{Account, StorageEntry};
368 use reth_provider::test_utils::create_test_provider_factory;
369 use reth_trie::{HashedPostState, HashedStorage, KeccakKeyHasher};
370 use revm::state::AccountInfo;
371 use revm_database::BundleState;
372
373 #[test]
375 fn overlay_root_with_sorted_state() {
376 let db = create_test_rw_db();
377 let tx = db.tx().expect("failed to create transaction");
378
379 let mut hashed_state = HashedPostState::default();
380 hashed_state.accounts.insert(
381 B256::from(U256::from(1)),
382 Some(Account { nonce: 1, balance: U256::from(10), bytecode_hash: None }),
383 );
384 hashed_state.accounts.insert(B256::from(U256::from(2)), None);
385 hashed_state.storages.insert(
386 B256::from(U256::from(1)),
387 HashedStorage::from_iter(false, [(B256::from(U256::from(3)), U256::from(30))]),
388 );
389
390 let sorted = hashed_state.into_sorted();
391 let overlay_root = StateRoot::overlay_root(&tx, &sorted).unwrap();
392
393 assert!(!overlay_root.is_zero());
395 }
396
397 #[test]
399 fn from_bundle_state_with_rayon() {
400 let address1 = Address::with_last_byte(1);
401 let address2 = Address::with_last_byte(2);
402 let slot1 = U256::from(1015);
403 let slot2 = U256::from(2015);
404
405 let account1 = AccountInfo { nonce: 1, ..Default::default() };
406 let account2 = AccountInfo { nonce: 2, ..Default::default() };
407
408 let bundle_state = BundleState::builder(2..=2)
409 .state_present_account_info(address1, account1)
410 .state_present_account_info(address2, account2)
411 .state_storage(address1, HashMap::from_iter([(slot1, (U256::ZERO, U256::from(10)))]))
412 .state_storage(address2, HashMap::from_iter([(slot2, (U256::ZERO, U256::from(20)))]))
413 .build();
414 assert_eq!(bundle_state.reverts.len(), 1);
415
416 let post_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(&bundle_state.state);
417 assert_eq!(post_state.accounts.len(), 2);
418 assert_eq!(post_state.storages.len(), 2);
419
420 let db = create_test_rw_db();
421 let tx = db.tx().expect("failed to create transaction");
422 assert_eq!(
423 StateRoot::overlay_root(&tx, &post_state.into_sorted()).unwrap(),
424 hex!("b464525710cafcf5d4044ac85b72c08b1e76231b8d91f288fe438cc41d8eaafd")
425 );
426 }
427
428 #[test]
430 fn from_reverts_keeps_first_occurrence_and_ordering() {
431 let factory = create_test_provider_factory();
432 let provider = factory.provider_rw().unwrap();
433
434 let address1 = Address::with_last_byte(1);
435 let address2 = Address::with_last_byte(2);
436 let slot1 = B256::from(U256::from(11));
437 let slot2 = B256::from(U256::from(22));
438
439 provider
441 .tx_ref()
442 .put::<tables::AccountChangeSets>(
443 1,
444 AccountBeforeTx {
445 address: address1,
446 info: Some(Account { nonce: 1, ..Default::default() }),
447 },
448 )
449 .unwrap();
450 provider
451 .tx_ref()
452 .put::<tables::AccountChangeSets>(
453 2,
454 AccountBeforeTx {
455 address: address1,
456 info: Some(Account { nonce: 2, ..Default::default() }),
457 },
458 )
459 .unwrap();
460 provider
461 .tx_ref()
462 .put::<tables::AccountChangeSets>(3, AccountBeforeTx { address: address2, info: None })
463 .unwrap();
464
465 provider
467 .tx_ref()
468 .put::<tables::StorageChangeSets>(
469 BlockNumberAddress((1, address1)),
470 StorageEntry { key: slot2, value: U256::from(200) },
471 )
472 .unwrap();
473 provider
474 .tx_ref()
475 .put::<tables::StorageChangeSets>(
476 BlockNumberAddress((2, address1)),
477 StorageEntry { key: slot1, value: U256::from(100) },
478 )
479 .unwrap();
480 provider
481 .tx_ref()
482 .put::<tables::StorageChangeSets>(
483 BlockNumberAddress((3, address1)),
484 StorageEntry { key: slot1, value: U256::from(999) }, )
486 .unwrap();
487
488 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=3).unwrap();
489
490 assert_eq!(sorted.accounts.len(), 2);
492 let hashed_addr1 = keccak256(address1);
493 let account1 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr1).unwrap();
494 assert_eq!(account1.1.unwrap().nonce, 1);
495
496 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
498
499 for storage in sorted.storages.values() {
501 assert!(storage.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
502 }
503 }
504
505 #[test]
507 fn from_reverts_empty_range() {
508 let factory = create_test_provider_factory();
509 let provider = factory.provider_rw().unwrap();
510
511 provider
513 .tx_ref()
514 .put::<tables::AccountChangeSets>(
515 100,
516 AccountBeforeTx {
517 address: Address::with_last_byte(1),
518 info: Some(Account { nonce: 1, ..Default::default() }),
519 },
520 )
521 .unwrap();
522
523 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=10).unwrap();
525 assert!(sorted.accounts.is_empty());
526 assert!(sorted.storages.is_empty());
527 }
528
529 #[test]
530 fn from_reverts_with_hashed_state() {
531 use reth_db_api::models::{StorageBeforeTx, StorageSettings};
532 use reth_provider::{StaticFileProviderFactory, StaticFileSegment, StaticFileWriter};
533
534 let factory = create_test_provider_factory();
535
536 factory.set_storage_settings_cache(StorageSettings::v2());
537
538 let provider = factory.provider_rw().unwrap();
539
540 let address1 = Address::with_last_byte(1);
541 let address2 = Address::with_last_byte(2);
542
543 let plain_slot1 = B256::from(U256::from(11));
544 let plain_slot2 = B256::from(U256::from(22));
545 let hashed_slot1 = keccak256(plain_slot1);
546 let hashed_slot2 = keccak256(plain_slot2);
547
548 {
549 let sf = factory.static_file_provider();
550
551 let mut aw = sf.latest_writer(StaticFileSegment::AccountChangeSets).unwrap();
553 aw.append_account_changeset(vec![], 0).unwrap();
554 aw.append_account_changeset(
555 vec![AccountBeforeTx {
556 address: address1,
557 info: Some(Account { nonce: 1, ..Default::default() }),
558 }],
559 1,
560 )
561 .unwrap();
562 aw.append_account_changeset(
563 vec![AccountBeforeTx {
564 address: address1,
565 info: Some(Account { nonce: 2, ..Default::default() }),
566 }],
567 2,
568 )
569 .unwrap();
570 aw.append_account_changeset(vec![AccountBeforeTx { address: address2, info: None }], 3)
571 .unwrap();
572 aw.commit().unwrap();
573
574 let mut writer = sf.latest_writer(StaticFileSegment::StorageChangeSets).unwrap();
575 writer.append_storage_changeset(vec![], 0).unwrap();
576 writer
577 .append_storage_changeset(
578 vec![StorageBeforeTx {
579 address: address1,
580 key: hashed_slot2,
581 value: U256::from(200),
582 }],
583 1,
584 )
585 .unwrap();
586 writer
587 .append_storage_changeset(
588 vec![StorageBeforeTx {
589 address: address1,
590 key: hashed_slot1,
591 value: U256::from(100),
592 }],
593 2,
594 )
595 .unwrap();
596 writer
597 .append_storage_changeset(
598 vec![StorageBeforeTx {
599 address: address1,
600 key: hashed_slot1,
601 value: U256::from(999),
602 }],
603 3,
604 )
605 .unwrap();
606 writer.commit().unwrap();
607 }
608
609 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=3).unwrap();
610
611 assert_eq!(sorted.accounts.len(), 2);
612
613 let hashed_addr1 = keccak256(address1);
614 let hashed_addr2 = keccak256(address2);
615
616 let account1 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr1).unwrap();
617 assert_eq!(account1.1.unwrap().nonce, 1);
618
619 let account2 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr2).unwrap();
620 assert!(account2.1.is_none());
621
622 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
623
624 let storage = sorted.storages.get(&hashed_addr1).expect("storage for address1");
625 assert_eq!(storage.storage_slots.len(), 2);
626
627 let found_slot1 = storage.storage_slots.iter().find(|(k, _)| *k == hashed_slot1).unwrap();
628 assert_eq!(found_slot1.1, U256::from(100));
629
630 let found_slot2 = storage.storage_slots.iter().find(|(k, _)| *k == hashed_slot2).unwrap();
631 assert_eq!(found_slot2.1, U256::from(200));
632
633 assert_ne!(hashed_slot1, plain_slot1);
634 assert_ne!(hashed_slot2, plain_slot2);
635
636 assert!(storage.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
637 }
638
639 #[test]
640 fn from_reverts_legacy_keccak_hashes_all_keys() {
641 let factory = create_test_provider_factory();
642 let provider = factory.provider_rw().unwrap();
643
644 let address1 = Address::with_last_byte(1);
645 let address2 = Address::with_last_byte(2);
646 let plain_slot1 = B256::from(U256::from(11));
647 let plain_slot2 = B256::from(U256::from(22));
648
649 provider
650 .tx_ref()
651 .put::<tables::AccountChangeSets>(
652 1,
653 AccountBeforeTx {
654 address: address1,
655 info: Some(Account { nonce: 10, ..Default::default() }),
656 },
657 )
658 .unwrap();
659 provider
660 .tx_ref()
661 .put::<tables::AccountChangeSets>(
662 2,
663 AccountBeforeTx {
664 address: address2,
665 info: Some(Account { nonce: 20, ..Default::default() }),
666 },
667 )
668 .unwrap();
669 provider
670 .tx_ref()
671 .put::<tables::AccountChangeSets>(
672 3,
673 AccountBeforeTx {
674 address: address1,
675 info: Some(Account { nonce: 99, ..Default::default() }),
676 },
677 )
678 .unwrap();
679
680 provider
681 .tx_ref()
682 .put::<tables::StorageChangeSets>(
683 BlockNumberAddress((1, address1)),
684 StorageEntry { key: plain_slot1, value: U256::from(100) },
685 )
686 .unwrap();
687 provider
688 .tx_ref()
689 .put::<tables::StorageChangeSets>(
690 BlockNumberAddress((2, address1)),
691 StorageEntry { key: plain_slot2, value: U256::from(200) },
692 )
693 .unwrap();
694 provider
695 .tx_ref()
696 .put::<tables::StorageChangeSets>(
697 BlockNumberAddress((3, address2)),
698 StorageEntry { key: plain_slot1, value: U256::from(300) },
699 )
700 .unwrap();
701
702 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=3).unwrap();
703
704 let expected_hashed_addr1 = keccak256(address1);
705 let expected_hashed_addr2 = keccak256(address2);
706 assert_eq!(sorted.accounts.len(), 2);
707
708 let account1 =
709 sorted.accounts.iter().find(|(addr, _)| *addr == expected_hashed_addr1).unwrap();
710 assert_eq!(account1.1.unwrap().nonce, 10);
711
712 let account2 =
713 sorted.accounts.iter().find(|(addr, _)| *addr == expected_hashed_addr2).unwrap();
714 assert_eq!(account2.1.unwrap().nonce, 20);
715
716 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
717
718 let expected_hashed_slot1 = keccak256(plain_slot1);
719 let expected_hashed_slot2 = keccak256(plain_slot2);
720
721 assert_ne!(expected_hashed_slot1, plain_slot1);
722 assert_ne!(expected_hashed_slot2, plain_slot2);
723
724 let storage1 = sorted.storages.get(&expected_hashed_addr1).expect("storage for address1");
725 assert_eq!(storage1.storage_slots.len(), 2);
726 assert!(storage1
727 .storage_slots
728 .iter()
729 .any(|(k, v)| *k == expected_hashed_slot1 && *v == U256::from(100)));
730 assert!(storage1
731 .storage_slots
732 .iter()
733 .any(|(k, v)| *k == expected_hashed_slot2 && *v == U256::from(200)));
734 assert!(storage1.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
735
736 let storage2 = sorted.storages.get(&expected_hashed_addr2).expect("storage for address2");
737 assert_eq!(storage2.storage_slots.len(), 1);
738 assert_eq!(storage2.storage_slots[0].0, expected_hashed_slot1);
739 assert_eq!(storage2.storage_slots[0].1, U256::from(300));
740 }
741}