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