1use crate::{
2 hashed_cursor::{HashedCursor, HashedCursorFactory, HashedStorageCursor},
3 node_iter::{TrieElement, TrieNodeIter},
4 prefix_set::{PrefixSet, TriePrefixSets},
5 progress::{
6 IntermediateRootState, IntermediateStateRootState, IntermediateStorageRootState,
7 StateRootProgress, StorageRootProgress,
8 },
9 stats::TrieTracker,
10 trie_cursor::{TrieCursor, TrieCursorFactory, TrieStorageCursor},
11 updates::{StorageTrieUpdates, TrieUpdates},
12 walker::TrieWalker,
13 HashBuilder, Nibbles, TRIE_ACCOUNT_RLP_MAX_SIZE,
14};
15use alloy_consensus::EMPTY_ROOT_HASH;
16use alloy_primitives::{keccak256, Address, B256, U256};
17use alloy_rlp::{BufMut, Encodable};
18use alloy_trie::proof::AddedRemovedKeys;
19use reth_execution_errors::{StateRootError, StorageRootError};
20use reth_primitives_traits::Account;
21use tracing::{debug, instrument, trace, Span};
22
23const DEFAULT_INTERMEDIATE_THRESHOLD: u64 = 100_000;
26
27#[cfg(feature = "metrics")]
28use crate::metrics::{StateRootMetrics, TrieRootMetrics};
29
30#[derive(Debug)]
32pub struct StateRoot<T, H> {
33 pub trie_cursor_factory: T,
35 pub hashed_cursor_factory: H,
37 pub prefix_sets: TriePrefixSets,
39 previous_state: Option<IntermediateStateRootState>,
41 threshold: u64,
43 #[cfg(feature = "metrics")]
44 metrics: StateRootMetrics,
46}
47
48impl<T, H> StateRoot<T, H> {
49 pub fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
55 Self {
56 trie_cursor_factory,
57 hashed_cursor_factory,
58 prefix_sets: TriePrefixSets::default(),
59 previous_state: None,
60 threshold: DEFAULT_INTERMEDIATE_THRESHOLD,
61 #[cfg(feature = "metrics")]
62 metrics: StateRootMetrics::default(),
63 }
64 }
65
66 pub fn with_prefix_sets(mut self, prefix_sets: TriePrefixSets) -> Self {
68 self.prefix_sets = prefix_sets;
69 self
70 }
71
72 pub const fn with_threshold(mut self, threshold: u64) -> Self {
74 self.threshold = threshold;
75 self
76 }
77
78 pub const fn with_no_threshold(mut self) -> Self {
80 self.threshold = u64::MAX;
81 self
82 }
83
84 pub fn with_intermediate_state(mut self, state: Option<IntermediateStateRootState>) -> Self {
86 self.previous_state = state;
87 self
88 }
89
90 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StateRoot<T, HF> {
92 StateRoot {
93 trie_cursor_factory: self.trie_cursor_factory,
94 hashed_cursor_factory,
95 prefix_sets: self.prefix_sets,
96 threshold: self.threshold,
97 previous_state: self.previous_state,
98 #[cfg(feature = "metrics")]
99 metrics: self.metrics,
100 }
101 }
102
103 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StateRoot<TF, H> {
105 StateRoot {
106 trie_cursor_factory,
107 hashed_cursor_factory: self.hashed_cursor_factory,
108 prefix_sets: self.prefix_sets,
109 threshold: self.threshold,
110 previous_state: self.previous_state,
111 #[cfg(feature = "metrics")]
112 metrics: self.metrics,
113 }
114 }
115}
116
117impl<T, H> StateRoot<T, H>
118where
119 T: TrieCursorFactory,
120 H: HashedCursorFactory,
121{
122 pub fn root_with_updates(self) -> Result<(B256, TrieUpdates), StateRootError> {
131 match self.with_no_threshold().calculate(true)? {
132 StateRootProgress::Complete(root, _, updates) => Ok((root, updates)),
133 StateRootProgress::Progress(..) => unreachable!(), }
135 }
136
137 pub fn root(self) -> Result<B256, StateRootError> {
144 match self.calculate(false)? {
145 StateRootProgress::Complete(root, _, _) => Ok(root),
146 StateRootProgress::Progress(..) => unreachable!(), }
148 }
149
150 pub fn root_with_progress(self) -> Result<StateRootProgress, StateRootError> {
157 self.calculate(true)
158 }
159
160 fn calculate(self, retain_updates: bool) -> Result<StateRootProgress, StateRootError> {
161 trace!(target: "trie::state_root", "calculating state root");
162 let mut tracker = TrieTracker::default();
163
164 let trie_cursor = self.trie_cursor_factory.account_trie_cursor()?;
165 let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
166
167 let mut hashed_storage_cursor: Option<H::StorageCursor<'_>> = None;
170 let mut storage_trie_cursor: Option<T::StorageTrieCursor<'_>> = None;
171
172 let mut storage_ctx = StateRootContext::new();
174
175 let (mut hash_builder, mut account_node_iter) = if let Some(state) = self.previous_state {
177 let IntermediateStateRootState { account_root_state, storage_root_state } = state;
178
179 let mut hash_builder = account_root_state.hash_builder.with_updates(retain_updates);
181 let walker = TrieWalker::<_>::state_trie_from_stack(
182 trie_cursor,
183 account_root_state.walker_stack,
184 self.prefix_sets.account_prefix_set,
185 )
186 .with_deletions_retained(retain_updates);
187 let account_node_iter = TrieNodeIter::state_trie(walker, hashed_account_cursor)
188 .with_last_hashed_key(account_root_state.last_hashed_key);
189
190 if let Some(storage_state) = storage_root_state {
192 let hashed_address = account_root_state.last_hashed_key;
193 let account = storage_state.account;
194
195 debug!(
196 target: "trie::state_root",
197 account_nonce = account.nonce,
198 account_balance = ?account.balance,
199 last_hashed_key = ?account_root_state.last_hashed_key,
200 "Resuming storage root calculation"
201 );
202
203 let remaining_threshold = self.threshold.saturating_sub(
204 storage_ctx.total_updates_len(&account_node_iter, &hash_builder),
205 );
206
207 if hashed_storage_cursor.is_none() {
208 hashed_storage_cursor =
209 Some(self.hashed_cursor_factory.hashed_storage_cursor(hashed_address)?);
210 }
211 if storage_trie_cursor.is_none() {
212 storage_trie_cursor =
213 Some(self.trie_cursor_factory.storage_trie_cursor(hashed_address)?);
214 }
215
216 let storage_result = StorageRoot::<T, H>::calculate_with_cursors(
217 StorageRootCalculation {
218 hashed_address,
219 prefix_set: self
220 .prefix_sets
221 .storage_prefix_sets
222 .get(&hashed_address)
223 .cloned()
224 .unwrap_or_default(),
225 previous_state: Some(storage_state.state),
226 threshold: remaining_threshold,
227 retain_updates,
228 },
229 storage_trie_cursor.as_mut().expect("storage trie cursor is initialized"),
230 hashed_storage_cursor.as_mut().expect("hashed storage cursor is initialized"),
231 #[cfg(feature = "metrics")]
232 &self.metrics.storage_trie,
233 )?;
234 if let Some(storage_state) = storage_ctx.process_storage_root_result(
235 storage_result,
236 hashed_address,
237 account,
238 &mut hash_builder,
239 retain_updates,
240 )? {
241 return Ok(storage_ctx.create_progress_state(
243 account_node_iter,
244 hash_builder,
245 account_root_state.last_hashed_key,
246 Some(storage_state),
247 ))
248 }
249 }
250
251 (hash_builder, account_node_iter)
252 } else {
253 let hash_builder = HashBuilder::default().with_updates(retain_updates);
256 let walker = TrieWalker::state_trie(trie_cursor, self.prefix_sets.account_prefix_set)
257 .with_deletions_retained(retain_updates);
258 let node_iter = TrieNodeIter::state_trie(walker, hashed_account_cursor);
259 (hash_builder, node_iter)
260 };
261
262 while let Some(node) = account_node_iter.try_next()? {
263 match node {
264 TrieElement::Branch(node) => {
265 tracker.inc_branch();
266 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
267 }
268 TrieElement::Leaf(hashed_address, account) => {
269 tracker.inc_leaf();
270 storage_ctx.hashed_entries_walked += 1;
271
272 let remaining_threshold = self.threshold.saturating_sub(
275 storage_ctx.total_updates_len(&account_node_iter, &hash_builder),
276 );
277
278 if hashed_storage_cursor.is_none() {
279 hashed_storage_cursor =
280 Some(self.hashed_cursor_factory.hashed_storage_cursor(hashed_address)?);
281 }
282 if storage_trie_cursor.is_none() {
283 storage_trie_cursor =
284 Some(self.trie_cursor_factory.storage_trie_cursor(hashed_address)?);
285 }
286
287 let storage_result = StorageRoot::<T, H>::calculate_with_cursors(
288 StorageRootCalculation {
289 hashed_address,
290 prefix_set: self
291 .prefix_sets
292 .storage_prefix_sets
293 .get(&hashed_address)
294 .cloned()
295 .unwrap_or_default(),
296 previous_state: None,
297 threshold: remaining_threshold,
298 retain_updates,
299 },
300 storage_trie_cursor.as_mut().expect("storage trie cursor is initialized"),
301 hashed_storage_cursor
302 .as_mut()
303 .expect("hashed storage cursor is initialized"),
304 #[cfg(feature = "metrics")]
305 &self.metrics.storage_trie,
306 )?;
307 if let Some(storage_state) = storage_ctx.process_storage_root_result(
308 storage_result,
309 hashed_address,
310 account,
311 &mut hash_builder,
312 retain_updates,
313 )? {
314 return Ok(storage_ctx.create_progress_state(
316 account_node_iter,
317 hash_builder,
318 hashed_address,
319 Some(storage_state),
320 ))
321 }
322
323 let total_updates_len =
325 storage_ctx.total_updates_len(&account_node_iter, &hash_builder);
326 if retain_updates && total_updates_len >= self.threshold {
327 return Ok(storage_ctx.create_progress_state(
328 account_node_iter,
329 hash_builder,
330 hashed_address,
331 None,
332 ))
333 }
334 }
335 }
336 }
337
338 let root = hash_builder.root();
339
340 let removed_keys = account_node_iter.walker.take_removed_keys();
341 let StateRootContext { mut trie_updates, hashed_entries_walked, .. } = storage_ctx;
342 trie_updates.finalize(hash_builder, removed_keys, self.prefix_sets.destroyed_accounts);
343
344 let stats = tracker.finish();
345
346 #[cfg(feature = "metrics")]
347 self.metrics.state_trie.record(stats);
348
349 trace!(
350 target: "trie::state_root",
351 %root,
352 duration = ?stats.duration(),
353 branches_added = stats.branches_added(),
354 leaves_added = stats.leaves_added(),
355 "calculated state root"
356 );
357
358 Ok(StateRootProgress::Complete(root, hashed_entries_walked, trie_updates))
359 }
360}
361
362#[derive(Debug)]
364pub(crate) struct StateRootContext {
365 account_rlp: Vec<u8>,
367 trie_updates: TrieUpdates,
369 hashed_entries_walked: usize,
371 updated_storage_nodes: usize,
373}
374
375impl StateRootContext {
376 fn new() -> Self {
378 Self {
379 account_rlp: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
380 trie_updates: TrieUpdates::default(),
381 hashed_entries_walked: 0,
382 updated_storage_nodes: 0,
383 }
384 }
385
386 fn create_progress_state<C, H, K>(
389 mut self,
390 account_node_iter: TrieNodeIter<C, H, K>,
391 hash_builder: HashBuilder,
392 last_hashed_key: B256,
393 storage_state: Option<IntermediateStorageRootState>,
394 ) -> StateRootProgress
395 where
396 C: TrieCursor,
397 H: HashedCursor,
398 K: AsRef<AddedRemovedKeys>,
399 {
400 let (walker_stack, walker_deleted_keys) = account_node_iter.walker.split();
401 self.trie_updates.removed_nodes.extend(walker_deleted_keys);
402 let (hash_builder, hash_builder_updates) = hash_builder.split();
403 self.trie_updates.account_nodes.extend(hash_builder_updates);
404
405 let account_state = IntermediateRootState { hash_builder, walker_stack, last_hashed_key };
406
407 let state = IntermediateStateRootState {
408 account_root_state: account_state,
409 storage_root_state: storage_state,
410 };
411
412 StateRootProgress::Progress(Box::new(state), self.hashed_entries_walked, self.trie_updates)
413 }
414
415 fn total_updates_len<C, H, K>(
417 &self,
418 account_node_iter: &TrieNodeIter<C, H, K>,
419 hash_builder: &HashBuilder,
420 ) -> u64
421 where
422 C: TrieCursor,
423 H: HashedCursor,
424 K: AsRef<AddedRemovedKeys>,
425 {
426 (self.updated_storage_nodes +
427 account_node_iter.walker.removed_keys_len() +
428 hash_builder.updates_len()) as u64
429 }
430
431 fn process_storage_root_result(
441 &mut self,
442 storage_result: StorageRootProgress,
443 hashed_address: B256,
444 account: Account,
445 hash_builder: &mut HashBuilder,
446 retain_updates: bool,
447 ) -> Result<Option<IntermediateStorageRootState>, StateRootError> {
448 match storage_result {
449 StorageRootProgress::Complete(storage_root, storage_slots_walked, updates) => {
450 self.hashed_entries_walked += storage_slots_walked;
452 if retain_updates {
453 self.updated_storage_nodes += updates.len();
454 self.trie_updates.insert_storage_updates(hashed_address, updates);
455 }
456
457 self.account_rlp.clear();
459 let trie_account = account.into_trie_account(storage_root);
460 trie_account.encode(&mut self.account_rlp as &mut dyn BufMut);
461 hash_builder.add_leaf(Nibbles::unpack(hashed_address), &self.account_rlp);
462 Ok(None)
463 }
464 StorageRootProgress::Progress(state, storage_slots_walked, updates) => {
465 debug!(
467 target: "trie::state_root",
468 ?hashed_address,
469 storage_slots_walked,
470 last_storage_key = ?state.last_hashed_key,
471 ?account,
472 "Pausing storage root calculation"
473 );
474
475 self.hashed_entries_walked += storage_slots_walked;
476 if retain_updates {
477 self.trie_updates.insert_storage_updates(hashed_address, updates);
478 }
479
480 Ok(Some(IntermediateStorageRootState { state: *state, account }))
481 }
482 }
483 }
484}
485
486#[derive(Debug)]
488pub struct StorageRoot<T, H> {
489 pub trie_cursor_factory: T,
491 pub hashed_cursor_factory: H,
493 pub hashed_address: B256,
495 pub prefix_set: PrefixSet,
497 previous_state: Option<IntermediateRootState>,
499 threshold: u64,
501 #[cfg(feature = "metrics")]
503 metrics: TrieRootMetrics,
504}
505
506impl<T, H> StorageRoot<T, H> {
507 pub fn new(
509 trie_cursor_factory: T,
510 hashed_cursor_factory: H,
511 address: Address,
512 prefix_set: PrefixSet,
513 #[cfg(feature = "metrics")] metrics: TrieRootMetrics,
514 ) -> Self {
515 Self::new_hashed(
516 trie_cursor_factory,
517 hashed_cursor_factory,
518 keccak256(address),
519 prefix_set,
520 #[cfg(feature = "metrics")]
521 metrics,
522 )
523 }
524
525 pub const fn new_hashed(
527 trie_cursor_factory: T,
528 hashed_cursor_factory: H,
529 hashed_address: B256,
530 prefix_set: PrefixSet,
531 #[cfg(feature = "metrics")] metrics: TrieRootMetrics,
532 ) -> Self {
533 Self {
534 trie_cursor_factory,
535 hashed_cursor_factory,
536 hashed_address,
537 prefix_set,
538 previous_state: None,
539 threshold: DEFAULT_INTERMEDIATE_THRESHOLD,
540 #[cfg(feature = "metrics")]
541 metrics,
542 }
543 }
544
545 pub fn with_prefix_set(mut self, prefix_set: PrefixSet) -> Self {
547 self.prefix_set = prefix_set;
548 self
549 }
550
551 pub const fn with_threshold(mut self, threshold: u64) -> Self {
553 self.threshold = threshold;
554 self
555 }
556
557 pub const fn with_no_threshold(mut self) -> Self {
559 self.threshold = u64::MAX;
560 self
561 }
562
563 pub fn with_intermediate_state(mut self, state: Option<IntermediateRootState>) -> Self {
565 self.previous_state = state;
566 self
567 }
568
569 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StorageRoot<T, HF> {
571 StorageRoot {
572 trie_cursor_factory: self.trie_cursor_factory,
573 hashed_cursor_factory,
574 hashed_address: self.hashed_address,
575 prefix_set: self.prefix_set,
576 previous_state: self.previous_state,
577 threshold: self.threshold,
578 #[cfg(feature = "metrics")]
579 metrics: self.metrics,
580 }
581 }
582
583 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StorageRoot<TF, H> {
585 StorageRoot {
586 trie_cursor_factory,
587 hashed_cursor_factory: self.hashed_cursor_factory,
588 hashed_address: self.hashed_address,
589 prefix_set: self.prefix_set,
590 previous_state: self.previous_state,
591 threshold: self.threshold,
592 #[cfg(feature = "metrics")]
593 metrics: self.metrics,
594 }
595 }
596}
597
598impl<T, H> StorageRoot<T, H>
599where
600 T: TrieCursorFactory,
601 H: HashedCursorFactory,
602{
603 pub fn root_with_progress(self) -> Result<StorageRootProgress, StorageRootError> {
610 self.calculate(true)
611 }
612
613 pub fn root_with_updates(self) -> Result<(B256, usize, StorageTrieUpdates), StorageRootError> {
619 match self.with_no_threshold().calculate(true)? {
620 StorageRootProgress::Complete(root, walked, updates) => Ok((root, walked, updates)),
621 StorageRootProgress::Progress(..) => unreachable!(), }
623 }
624
625 pub fn root(self) -> Result<B256, StorageRootError> {
631 match self.calculate(false)? {
632 StorageRootProgress::Complete(root, _, _) => Ok(root),
633 StorageRootProgress::Progress(..) => unreachable!(), }
635 }
636
637 #[instrument(skip_all, level = "trace", target = "trie::storage_root", name = "storage_trie", fields(addr = %self.hashed_address, storage_root))]
644 pub fn calculate(self, retain_updates: bool) -> Result<StorageRootProgress, StorageRootError> {
645 trace!(target: "trie::storage_root", "calculating storage root");
646
647 let Self {
648 trie_cursor_factory,
649 hashed_cursor_factory,
650 hashed_address,
651 prefix_set,
652 previous_state,
653 threshold,
654 #[cfg(feature = "metrics")]
655 metrics,
656 } = self;
657
658 let mut hashed_storage_cursor =
659 hashed_cursor_factory.hashed_storage_cursor(hashed_address)?;
660 let mut storage_trie_cursor = trie_cursor_factory.storage_trie_cursor(hashed_address)?;
661
662 Self::calculate_with_cursors(
663 StorageRootCalculation {
664 hashed_address,
665 prefix_set,
666 previous_state,
667 threshold,
668 retain_updates,
669 },
670 &mut storage_trie_cursor,
671 &mut hashed_storage_cursor,
672 #[cfg(feature = "metrics")]
673 &metrics,
674 )
675 }
676
677 #[instrument(skip_all, level = "trace", target = "trie::storage_root", name = "storage_trie_with_cursor", fields(addr = %self.hashed_address, storage_root))]
683 pub fn calculate_with_cursor(
684 self,
685 hashed_storage_cursor: &mut H::StorageCursor<'_>,
686 retain_updates: bool,
687 ) -> Result<StorageRootProgress, StorageRootError> {
688 trace!(target: "trie::storage_root", "calculating storage root with cursor");
689
690 let Self {
691 trie_cursor_factory,
692 hashed_address,
693 prefix_set,
694 previous_state,
695 threshold,
696 #[cfg(feature = "metrics")]
697 metrics,
698 ..
699 } = self;
700
701 let mut storage_trie_cursor = trie_cursor_factory.storage_trie_cursor(hashed_address)?;
702
703 Self::calculate_with_cursors(
704 StorageRootCalculation {
705 hashed_address,
706 prefix_set,
707 previous_state,
708 threshold,
709 retain_updates,
710 },
711 &mut storage_trie_cursor,
712 hashed_storage_cursor,
713 #[cfg(feature = "metrics")]
714 &metrics,
715 )
716 }
717
718 fn calculate_with_cursors<TC, HC>(
721 calculation: StorageRootCalculation,
722 trie_cursor: &mut TC,
723 hashed_storage_cursor: &mut HC,
724 #[cfg(feature = "metrics")] metrics: &TrieRootMetrics,
725 ) -> Result<StorageRootProgress, StorageRootError>
726 where
727 TC: TrieStorageCursor,
728 HC: HashedStorageCursor<Value = U256>,
729 {
730 let StorageRootCalculation {
731 hashed_address,
732 prefix_set,
733 previous_state,
734 threshold,
735 retain_updates,
736 } = calculation;
737 hashed_storage_cursor.set_hashed_address(hashed_address);
738
739 if hashed_storage_cursor.is_storage_empty()? {
741 Span::current().record("storage_root", format!("{EMPTY_ROOT_HASH:?}"));
742 return Ok(StorageRootProgress::Complete(
743 EMPTY_ROOT_HASH,
744 0,
745 StorageTrieUpdates::deleted(),
746 ))
747 }
748
749 trie_cursor.set_hashed_address(hashed_address);
750
751 let mut tracker = TrieTracker::default();
752 let mut trie_updates = StorageTrieUpdates::default();
753
754 let (mut hash_builder, mut storage_node_iter) = match previous_state {
755 Some(state) => {
756 let hash_builder = state.hash_builder.with_updates(retain_updates);
757 let walker = TrieWalker::<_>::storage_trie_from_stack(
758 trie_cursor,
759 state.walker_stack,
760 prefix_set,
761 )
762 .with_deletions_retained(retain_updates);
763 let node_iter = TrieNodeIter::storage_trie(walker, hashed_storage_cursor)
764 .with_last_hashed_key(state.last_hashed_key);
765 (hash_builder, node_iter)
766 }
767 None => {
768 let hash_builder = HashBuilder::default().with_updates(retain_updates);
769 let walker = TrieWalker::storage_trie(trie_cursor, prefix_set)
770 .with_deletions_retained(retain_updates);
771 let node_iter = TrieNodeIter::storage_trie(walker, hashed_storage_cursor);
772 (hash_builder, node_iter)
773 }
774 };
775
776 let mut hashed_entries_walked = 0;
777 while let Some(node) = storage_node_iter.try_next()? {
778 match node {
779 TrieElement::Branch(node) => {
780 tracker.inc_branch();
781 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
782 }
783 TrieElement::Leaf(hashed_slot, value) => {
784 tracker.inc_leaf();
785 hashed_entries_walked += 1;
786 hash_builder.add_leaf(
787 Nibbles::unpack(hashed_slot),
788 alloy_rlp::encode_fixed_size(&value).as_ref(),
789 );
790
791 let total_updates_len =
793 storage_node_iter.walker.removed_keys_len() + hash_builder.updates_len();
794 if retain_updates && total_updates_len as u64 >= threshold {
795 let (walker_stack, walker_deleted_keys) = storage_node_iter.walker.split();
796 trie_updates.removed_nodes.extend(walker_deleted_keys);
797 let (hash_builder, hash_builder_updates) = hash_builder.split();
798 trie_updates.storage_nodes.extend(hash_builder_updates);
799
800 let state = IntermediateRootState {
801 hash_builder,
802 walker_stack,
803 last_hashed_key: hashed_slot,
804 };
805
806 return Ok(StorageRootProgress::Progress(
807 Box::new(state),
808 hashed_entries_walked,
809 trie_updates,
810 ))
811 }
812 }
813 }
814 }
815
816 let root = hash_builder.root();
817 Span::current().record("storage_root", format!("{root:?}"));
818
819 let removed_keys = storage_node_iter.walker.take_removed_keys();
820 trie_updates.finalize(hash_builder, removed_keys);
821
822 let stats = tracker.finish();
823
824 #[cfg(feature = "metrics")]
825 metrics.record(stats);
826
827 trace!(
828 target: "trie::storage_root",
829 %root,
830 %hashed_address,
831 duration = ?stats.duration(),
832 branches_added = stats.branches_added(),
833 leaves_added = stats.leaves_added(),
834 "calculated storage root"
835 );
836
837 let storage_slots_walked = stats.leaves_added() as usize;
838 Ok(StorageRootProgress::Complete(root, storage_slots_walked, trie_updates))
839 }
840}
841
842struct StorageRootCalculation {
844 hashed_address: B256,
845 prefix_set: PrefixSet,
846 previous_state: Option<IntermediateRootState>,
847 threshold: u64,
848 retain_updates: bool,
849}
850
851#[derive(Clone, Copy, Debug)]
853pub enum TrieType {
854 State,
856 Storage,
858 Custom(&'static str),
860}
861
862impl TrieType {
863 #[cfg(feature = "metrics")]
864 pub(crate) const fn as_str(&self) -> &'static str {
865 match self {
866 Self::State => "state",
867 Self::Storage => "storage",
868 Self::Custom(s) => s,
869 }
870 }
871}