1use crate::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
2use alloy_primitives::{keccak256, map::B256Map, Address, 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 let mut last_address: Option<(Address, B256)> = None;
313 for (BlockNumberAddress((_, address)), storage) in
314 provider.storage_changesets_range(start..=end_inclusive)?
315 {
316 if seen_storage_keys.insert((address, storage.key)) {
317 let hashed_address = match last_address {
318 Some((last, hashed)) if last == address => hashed,
319 _ => {
320 let hashed = keccak256(address);
321 last_address = Some((address, hashed));
322 hashed
323 }
324 };
325 storages
326 .entry(hashed_address)
327 .or_default()
328 .push((keccak256(storage.key), storage.value));
329 }
330 }
331 }
332
333 let hashed_storages = storages
335 .into_iter()
336 .map(|(address, mut slots)| {
337 slots.sort_unstable_by_key(|(slot, _)| *slot);
338 (address, HashedStorageSorted { storage_slots: slots })
339 })
340 .collect();
341
342 Ok(Self::new(accounts, hashed_storages))
343 }
344}
345
346#[cfg(test)]
347mod tests {
348 use super::*;
349 use alloy_primitives::{hex, keccak256, map::HashMap, Address, B256, U256};
350 use evm2::evm::AccountInfo;
351 use reth_db_api::{
352 models::{AccountBeforeTx, BlockNumberAddress, StorageBeforeTx, StorageSettings},
353 tables,
354 transaction::DbTxMut,
355 };
356 use reth_execution_errors::StateRootError;
357 use reth_primitives_traits::{Account, StorageEntry};
358 use reth_provider::{
359 test_utils::create_test_provider_factory, StaticFileProviderFactory, StaticFileSegment,
360 StaticFileWriter,
361 };
362 use reth_storage_api::StorageSettingsCache;
363 use reth_trie::{
364 HashedPostState, HashedPostStateSorted, HashedStorage, KeccakKeyHasher, StateRoot,
365 };
366 use reth_trie_common::bundle_state::BundleState;
367
368 fn overlay_root_for_provider<TX: reth_db_api::transaction::DbTx>(
369 provider: &impl StorageSettingsCache,
370 tx: &TX,
371 sorted: &HashedPostStateSorted,
372 ) -> Result<B256, StateRootError> {
373 crate::with_adapter!(provider, |A| {
374 type S<'a, TX> = StateRoot<
375 crate::DatabaseTrieCursorFactory<&'a TX, A>,
376 crate::DatabaseHashedCursorFactory<&'a TX>,
377 >;
378 S::overlay_root(tx, sorted)
379 })
380 }
381
382 #[test]
384 fn overlay_root_with_sorted_state() {
385 let factory = create_test_provider_factory();
386 let provider = factory.provider_rw().unwrap();
387
388 let mut hashed_state = HashedPostState::default();
389 hashed_state.accounts.insert(
390 B256::with_last_byte(1),
391 Some(Account { nonce: 1, balance: U256::from(10), ..Default::default() }),
392 );
393 hashed_state.accounts.insert(B256::with_last_byte(2), None);
394 hashed_state.storages.insert(
395 B256::with_last_byte(1),
396 HashedStorage::from_iter([(B256::with_last_byte(3), U256::from(30))]),
397 );
398
399 let sorted = hashed_state.into_sorted();
400 let overlay_root =
401 overlay_root_for_provider(&*provider, provider.tx_ref(), &sorted).unwrap();
402
403 assert!(!overlay_root.is_zero());
405 }
406
407 #[test]
409 fn from_bundle_state_with_rayon() {
410 let address1 = Address::with_last_byte(1);
411 let address2 = Address::with_last_byte(2);
412 let slot1 = U256::from(1015);
413 let slot2 = U256::from(2015);
414
415 let account1 = AccountInfo { nonce: 1, ..Default::default() };
416 let account2 = AccountInfo { nonce: 2, ..Default::default() };
417
418 let bundle_state = BundleState::builder(2..=2)
419 .state_present_account_info(address1, account1)
420 .state_present_account_info(address2, account2)
421 .state_storage(address1, HashMap::from_iter([(slot1, (U256::ZERO, U256::from(10)))]))
422 .state_storage(address2, HashMap::from_iter([(slot2, (U256::ZERO, U256::from(20)))]))
423 .build();
424 assert_eq!(bundle_state.reverts.len(), 1);
425
426 let post_state = HashedPostState::from_bundle_state::<KeccakKeyHasher>(&bundle_state.state);
427 assert_eq!(post_state.accounts.len(), 2);
428 assert_eq!(post_state.storages.len(), 2);
429
430 let factory = create_test_provider_factory();
431 let provider = factory.provider_rw().unwrap();
432 let sorted = post_state.into_sorted();
433 assert_eq!(
434 overlay_root_for_provider(&*provider, provider.tx_ref(), &sorted).unwrap(),
435 hex!("b464525710cafcf5d4044ac85b72c08b1e76231b8d91f288fe438cc41d8eaafd")
436 );
437 }
438
439 #[test]
441 fn from_reverts_keeps_first_occurrence_and_ordering() {
442 let factory = create_test_provider_factory();
443 let provider = factory.provider_rw().unwrap();
444
445 let address1 = Address::with_last_byte(1);
446 let address2 = Address::with_last_byte(2);
447 let slot1 = B256::with_last_byte(11);
448 let slot2 = B256::with_last_byte(22);
449
450 provider
452 .tx_ref()
453 .put::<tables::AccountChangeSets>(
454 1,
455 AccountBeforeTx {
456 address: address1,
457 info: Some(Account { nonce: 1, ..Default::default() }),
458 },
459 )
460 .unwrap();
461 provider
462 .tx_ref()
463 .put::<tables::AccountChangeSets>(
464 2,
465 AccountBeforeTx {
466 address: address1,
467 info: Some(Account { nonce: 2, ..Default::default() }),
468 },
469 )
470 .unwrap();
471 provider
472 .tx_ref()
473 .put::<tables::AccountChangeSets>(3, AccountBeforeTx { address: address2, info: None })
474 .unwrap();
475
476 provider
478 .tx_ref()
479 .put::<tables::StorageChangeSets>(
480 BlockNumberAddress((1, address1)),
481 StorageEntry { key: slot2, value: U256::from(200) },
482 )
483 .unwrap();
484 provider
485 .tx_ref()
486 .put::<tables::StorageChangeSets>(
487 BlockNumberAddress((2, address1)),
488 StorageEntry { key: slot1, value: U256::from(100) },
489 )
490 .unwrap();
491 provider
492 .tx_ref()
493 .put::<tables::StorageChangeSets>(
494 BlockNumberAddress((3, address1)),
495 StorageEntry { key: slot1, value: U256::from(999) }, )
497 .unwrap();
498
499 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=3).unwrap();
500
501 assert_eq!(sorted.accounts.len(), 2);
503 let hashed_addr1 = keccak256(address1);
504 let account1 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr1).unwrap();
505 assert_eq!(account1.1.as_ref().unwrap().nonce, 1);
506
507 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
509
510 for storage in sorted.storages.values() {
512 assert!(storage.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
513 }
514 }
515
516 #[test]
518 fn from_reverts_empty_range() {
519 let factory = create_test_provider_factory();
520 let provider = factory.provider_rw().unwrap();
521
522 provider
524 .tx_ref()
525 .put::<tables::AccountChangeSets>(
526 100,
527 AccountBeforeTx {
528 address: Address::with_last_byte(1),
529 info: Some(Account { nonce: 1, ..Default::default() }),
530 },
531 )
532 .unwrap();
533
534 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=10).unwrap();
536 assert!(sorted.accounts.is_empty());
537 assert!(sorted.storages.is_empty());
538 }
539
540 #[test]
541 fn from_reverts_with_hashed_state() {
542 let factory = create_test_provider_factory();
543
544 factory.set_storage_settings_cache(StorageSettings::v2());
545
546 let provider = factory.provider_rw().unwrap();
547
548 let address1 = Address::with_last_byte(1);
549 let address2 = Address::with_last_byte(2);
550
551 let plain_slot1 = B256::with_last_byte(11);
552 let plain_slot2 = B256::with_last_byte(22);
553 let hashed_slot1 = keccak256(plain_slot1);
554 let hashed_slot2 = keccak256(plain_slot2);
555
556 {
557 let sf = factory.static_file_provider();
558
559 let mut aw = sf.latest_writer(StaticFileSegment::AccountChangeSets).unwrap();
561 aw.append_account_changeset(vec![], 0).unwrap();
562 aw.append_account_changeset(
563 vec![AccountBeforeTx {
564 address: address1,
565 info: Some(Account { nonce: 1, ..Default::default() }),
566 }],
567 1,
568 )
569 .unwrap();
570 aw.append_account_changeset(
571 vec![AccountBeforeTx {
572 address: address1,
573 info: Some(Account { nonce: 2, ..Default::default() }),
574 }],
575 2,
576 )
577 .unwrap();
578 aw.append_account_changeset(vec![AccountBeforeTx { address: address2, info: None }], 3)
579 .unwrap();
580 aw.commit().unwrap();
581
582 let mut writer = sf.latest_writer(StaticFileSegment::StorageChangeSets).unwrap();
583 writer.append_storage_changeset(vec![], 0).unwrap();
584 writer
585 .append_storage_changeset(
586 vec![StorageBeforeTx {
587 address: address1,
588 key: plain_slot2,
589 value: U256::from(200),
590 }],
591 1,
592 )
593 .unwrap();
594 writer
595 .append_storage_changeset(
596 vec![StorageBeforeTx {
597 address: address1,
598 key: plain_slot1,
599 value: U256::from(100),
600 }],
601 2,
602 )
603 .unwrap();
604 writer
605 .append_storage_changeset(
606 vec![StorageBeforeTx {
607 address: address1,
608 key: plain_slot1,
609 value: U256::from(999),
610 }],
611 3,
612 )
613 .unwrap();
614 writer.commit().unwrap();
615 }
616
617 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=3).unwrap();
618
619 assert_eq!(sorted.accounts.len(), 2);
620
621 let hashed_addr1 = keccak256(address1);
622 let hashed_addr2 = keccak256(address2);
623
624 let account1 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr1).unwrap();
625 assert_eq!(account1.1.as_ref().unwrap().nonce, 1);
626
627 let account2 = sorted.accounts.iter().find(|(addr, _)| *addr == hashed_addr2).unwrap();
628 assert!(account2.1.is_none());
629
630 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
631
632 let storage = sorted.storages.get(&hashed_addr1).expect("storage for address1");
633 assert_eq!(storage.storage_slots.len(), 2);
634
635 let found_slot1 = storage.storage_slots.iter().find(|(k, _)| *k == hashed_slot1).unwrap();
636 assert_eq!(found_slot1.1, U256::from(100));
637
638 let found_slot2 = storage.storage_slots.iter().find(|(k, _)| *k == hashed_slot2).unwrap();
639 assert_eq!(found_slot2.1, U256::from(200));
640
641 assert_ne!(hashed_slot1, plain_slot1);
642 assert_ne!(hashed_slot2, plain_slot2);
643
644 assert!(storage.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
645 }
646
647 #[test]
648 fn from_reverts_legacy_keccak_hashes_all_keys() {
649 let factory = create_test_provider_factory();
650 let provider = factory.provider_rw().unwrap();
651
652 let address1 = Address::with_last_byte(1);
653 let address2 = Address::with_last_byte(2);
654 let plain_slot1 = B256::with_last_byte(11);
655 let plain_slot2 = B256::with_last_byte(22);
656
657 provider
658 .tx_ref()
659 .put::<tables::AccountChangeSets>(
660 1,
661 AccountBeforeTx {
662 address: address1,
663 info: Some(Account { nonce: 10, ..Default::default() }),
664 },
665 )
666 .unwrap();
667 provider
668 .tx_ref()
669 .put::<tables::AccountChangeSets>(
670 2,
671 AccountBeforeTx {
672 address: address2,
673 info: Some(Account { nonce: 20, ..Default::default() }),
674 },
675 )
676 .unwrap();
677 provider
678 .tx_ref()
679 .put::<tables::AccountChangeSets>(
680 3,
681 AccountBeforeTx {
682 address: address1,
683 info: Some(Account { nonce: 99, ..Default::default() }),
684 },
685 )
686 .unwrap();
687
688 provider
689 .tx_ref()
690 .put::<tables::StorageChangeSets>(
691 BlockNumberAddress((1, address1)),
692 StorageEntry { key: plain_slot1, value: U256::from(100) },
693 )
694 .unwrap();
695 provider
696 .tx_ref()
697 .put::<tables::StorageChangeSets>(
698 BlockNumberAddress((2, address1)),
699 StorageEntry { key: plain_slot2, value: U256::from(200) },
700 )
701 .unwrap();
702 provider
703 .tx_ref()
704 .put::<tables::StorageChangeSets>(
705 BlockNumberAddress((3, address2)),
706 StorageEntry { key: plain_slot1, value: U256::from(300) },
707 )
708 .unwrap();
709
710 let sorted = HashedPostStateSorted::from_reverts(&*provider, 1..=3).unwrap();
711
712 let expected_hashed_addr1 = keccak256(address1);
713 let expected_hashed_addr2 = keccak256(address2);
714 assert_eq!(sorted.accounts.len(), 2);
715
716 let account1 =
717 sorted.accounts.iter().find(|(addr, _)| *addr == expected_hashed_addr1).unwrap();
718 assert_eq!(account1.1.as_ref().unwrap().nonce, 10);
719
720 let account2 =
721 sorted.accounts.iter().find(|(addr, _)| *addr == expected_hashed_addr2).unwrap();
722 assert_eq!(account2.1.as_ref().unwrap().nonce, 20);
723
724 assert!(sorted.accounts.windows(2).all(|w| w[0].0 <= w[1].0));
725
726 let expected_hashed_slot1 = keccak256(plain_slot1);
727 let expected_hashed_slot2 = keccak256(plain_slot2);
728
729 assert_ne!(expected_hashed_slot1, plain_slot1);
730 assert_ne!(expected_hashed_slot2, plain_slot2);
731
732 let storage1 = sorted.storages.get(&expected_hashed_addr1).expect("storage for address1");
733 assert_eq!(storage1.storage_slots.len(), 2);
734 assert!(storage1
735 .storage_slots
736 .iter()
737 .any(|(k, v)| *k == expected_hashed_slot1 && *v == U256::from(100)));
738 assert!(storage1
739 .storage_slots
740 .iter()
741 .any(|(k, v)| *k == expected_hashed_slot2 && *v == U256::from(200)));
742 assert!(storage1.storage_slots.windows(2).all(|w| w[0].0 <= w[1].0));
743
744 let storage2 = sorted.storages.get(&expected_hashed_addr2).expect("storage for address2");
745 assert_eq!(storage2.storage_slots.len(), 1);
746 assert_eq!(storage2.storage_slots[0].0, expected_hashed_slot1);
747 assert_eq!(storage2.storage_slots[0].1, U256::from(300));
748 }
749}