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