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, TrieCursorIter, 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, map::B256Map, 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 walk_all_changed_branch_children: bool,
41 previous_state: Option<IntermediateStateRootState>,
43 threshold: u64,
45 #[cfg(feature = "metrics")]
46 metrics: StateRootMetrics,
48}
49
50impl<T, H> StateRoot<T, H> {
51 pub fn new(trie_cursor_factory: T, hashed_cursor_factory: H) -> Self {
57 Self {
58 trie_cursor_factory,
59 hashed_cursor_factory,
60 prefix_sets: TriePrefixSets::default(),
61 walk_all_changed_branch_children: false,
62 previous_state: None,
63 threshold: DEFAULT_INTERMEDIATE_THRESHOLD,
64 #[cfg(feature = "metrics")]
65 metrics: StateRootMetrics::default(),
66 }
67 }
68
69 pub fn with_prefix_sets(mut self, prefix_sets: TriePrefixSets) -> Self {
71 self.prefix_sets = prefix_sets;
72 self
73 }
74
75 pub const fn with_walk_all_changed_branch_children(mut self, enabled: bool) -> Self {
80 self.walk_all_changed_branch_children = enabled;
81 self
82 }
83
84 pub const fn with_threshold(mut self, threshold: u64) -> Self {
86 self.threshold = threshold;
87 self
88 }
89
90 pub const fn with_no_threshold(mut self) -> Self {
92 self.threshold = u64::MAX;
93 self
94 }
95
96 pub fn with_intermediate_state(mut self, state: Option<IntermediateStateRootState>) -> Self {
98 self.previous_state = state;
99 self
100 }
101
102 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StateRoot<T, HF> {
104 StateRoot {
105 trie_cursor_factory: self.trie_cursor_factory,
106 hashed_cursor_factory,
107 prefix_sets: self.prefix_sets,
108 walk_all_changed_branch_children: self.walk_all_changed_branch_children,
109 threshold: self.threshold,
110 previous_state: self.previous_state,
111 #[cfg(feature = "metrics")]
112 metrics: self.metrics,
113 }
114 }
115
116 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StateRoot<TF, H> {
118 StateRoot {
119 trie_cursor_factory,
120 hashed_cursor_factory: self.hashed_cursor_factory,
121 prefix_sets: self.prefix_sets,
122 walk_all_changed_branch_children: self.walk_all_changed_branch_children,
123 threshold: self.threshold,
124 previous_state: self.previous_state,
125 #[cfg(feature = "metrics")]
126 metrics: self.metrics,
127 }
128 }
129}
130
131impl<T, H> StateRoot<T, H>
132where
133 T: TrieCursorFactory,
134 H: HashedCursorFactory,
135{
136 pub fn root_with_updates(self) -> Result<(B256, TrieUpdates), StateRootError> {
145 match self.with_no_threshold().calculate(true)? {
146 StateRootProgress::Complete(root, _, updates) => Ok((root, updates)),
147 StateRootProgress::Progress(..) => unreachable!(), }
149 }
150
151 pub fn root(self) -> Result<B256, StateRootError> {
158 match self.calculate(false)? {
159 StateRootProgress::Complete(root, _, _) => Ok(root),
160 StateRootProgress::Progress(..) => unreachable!(), }
162 }
163
164 pub fn root_with_progress(self) -> Result<StateRootProgress, StateRootError> {
171 self.calculate(true)
172 }
173
174 fn calculate(self, retain_updates: bool) -> Result<StateRootProgress, StateRootError> {
175 trace!(target: "trie::state_root", "calculating state root");
176 let mut tracker = TrieTracker::default();
177
178 let trie_cursor = self.trie_cursor_factory.account_trie_cursor()?;
179 let hashed_account_cursor = self.hashed_cursor_factory.hashed_account_cursor()?;
180
181 let mut hashed_storage_cursor: Option<H::StorageCursor<'_>> = None;
184 let mut storage_trie_cursor: Option<T::StorageTrieCursor<'_>> = None;
185
186 let mut storage_ctx = StateRootContext::new();
188
189 let (mut hash_builder, mut account_node_iter) = if let Some(state) = self.previous_state {
191 let IntermediateStateRootState { account_root_state, storage_root_state } = state;
192
193 let mut hash_builder = account_root_state.hash_builder.with_updates(retain_updates);
195 let walker = TrieWalker::<_>::state_trie_from_stack(
196 trie_cursor,
197 account_root_state.walker_stack,
198 self.prefix_sets.account_prefix_set,
199 )
200 .with_walk_all_changed_branch_children(self.walk_all_changed_branch_children)
201 .with_deletions_retained(retain_updates);
202 let account_node_iter = TrieNodeIter::state_trie(walker, hashed_account_cursor)
203 .with_last_hashed_key(account_root_state.last_hashed_key);
204
205 if let Some(storage_state) = storage_root_state {
207 let hashed_address = account_root_state.last_hashed_key;
208 let account = storage_state.account;
209
210 debug!(
211 target: "trie::state_root",
212 account_nonce = account.nonce,
213 account_balance = ?account.balance,
214 last_hashed_key = ?account_root_state.last_hashed_key,
215 "Resuming storage root calculation"
216 );
217
218 let remaining_threshold = self.threshold.saturating_sub(
219 storage_ctx.total_updates_len(&account_node_iter, &hash_builder),
220 );
221
222 if hashed_storage_cursor.is_none() {
223 hashed_storage_cursor =
224 Some(self.hashed_cursor_factory.hashed_storage_cursor(hashed_address)?);
225 }
226 if storage_trie_cursor.is_none() {
227 storage_trie_cursor =
228 Some(self.trie_cursor_factory.storage_trie_cursor(hashed_address)?);
229 }
230
231 let storage_result = StorageRoot::<T, H>::calculate_with_cursors(
232 StorageRootCalculation {
233 hashed_address,
234 prefix_set: self
235 .prefix_sets
236 .storage_prefix_sets
237 .get(&hashed_address)
238 .cloned()
239 .unwrap_or_default(),
240 previous_state: Some(storage_state.state),
241 walk_all_changed_branch_children: self.walk_all_changed_branch_children,
242 threshold: remaining_threshold,
243 retain_updates,
244 },
245 storage_trie_cursor.as_mut().expect("storage trie cursor is initialized"),
246 hashed_storage_cursor.as_mut().expect("hashed storage cursor is initialized"),
247 #[cfg(feature = "metrics")]
248 &self.metrics.storage_trie,
249 )?;
250 if let Some(storage_state) = storage_ctx.process_storage_root_result(
251 storage_result,
252 hashed_address,
253 account,
254 &mut hash_builder,
255 retain_updates,
256 )? {
257 return Ok(storage_ctx.create_progress_state(
259 account_node_iter,
260 hash_builder,
261 account_root_state.last_hashed_key,
262 Some(storage_state),
263 ))
264 }
265 }
266
267 (hash_builder, account_node_iter)
268 } else {
269 let hash_builder = HashBuilder::default().with_updates(retain_updates);
272 let walker = TrieWalker::state_trie(trie_cursor, self.prefix_sets.account_prefix_set)?
273 .with_walk_all_changed_branch_children(self.walk_all_changed_branch_children)
274 .with_deletions_retained(retain_updates);
275 let node_iter = TrieNodeIter::state_trie(walker, hashed_account_cursor);
276 (hash_builder, node_iter)
277 };
278
279 while let Some(node) = account_node_iter.try_next()? {
280 match node {
281 TrieElement::Branch(node) => {
282 tracker.inc_branch();
283 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
284 }
285 TrieElement::Leaf(hashed_address, account) => {
286 tracker.inc_leaf();
287 storage_ctx.hashed_entries_walked += 1;
288
289 let remaining_threshold = self.threshold.saturating_sub(
292 storage_ctx.total_updates_len(&account_node_iter, &hash_builder),
293 );
294
295 if hashed_storage_cursor.is_none() {
296 hashed_storage_cursor =
297 Some(self.hashed_cursor_factory.hashed_storage_cursor(hashed_address)?);
298 }
299 if storage_trie_cursor.is_none() {
300 storage_trie_cursor =
301 Some(self.trie_cursor_factory.storage_trie_cursor(hashed_address)?);
302 }
303
304 let storage_result = StorageRoot::<T, H>::calculate_with_cursors(
305 StorageRootCalculation {
306 hashed_address,
307 prefix_set: self
308 .prefix_sets
309 .storage_prefix_sets
310 .get(&hashed_address)
311 .cloned()
312 .unwrap_or_default(),
313 previous_state: None,
314 walk_all_changed_branch_children: self.walk_all_changed_branch_children,
315 threshold: remaining_threshold,
316 retain_updates,
317 },
318 storage_trie_cursor.as_mut().expect("storage trie cursor is initialized"),
319 hashed_storage_cursor
320 .as_mut()
321 .expect("hashed storage cursor is initialized"),
322 #[cfg(feature = "metrics")]
323 &self.metrics.storage_trie,
324 )?;
325 if let Some(storage_state) = storage_ctx.process_storage_root_result(
326 storage_result,
327 hashed_address,
328 account,
329 &mut hash_builder,
330 retain_updates,
331 )? {
332 return Ok(storage_ctx.create_progress_state(
334 account_node_iter,
335 hash_builder,
336 hashed_address,
337 Some(storage_state),
338 ))
339 }
340
341 let total_updates_len =
343 storage_ctx.total_updates_len(&account_node_iter, &hash_builder);
344 if retain_updates && total_updates_len >= self.threshold {
345 return Ok(storage_ctx.create_progress_state(
346 account_node_iter,
347 hash_builder,
348 hashed_address,
349 None,
350 ))
351 }
352 }
353 }
354 }
355
356 let root = hash_builder.root();
357
358 let mut destroyed_storage_trie_nodes = B256Map::default();
359 if retain_updates && !self.prefix_sets.destroyed_accounts.is_empty() {
360 let mut storage_trie_cursor = match storage_trie_cursor {
361 Some(cursor) => cursor,
362 None => self.trie_cursor_factory.storage_trie_cursor(B256::ZERO)?,
363 };
364
365 for hashed_address in &self.prefix_sets.destroyed_accounts {
366 storage_trie_cursor.set_hashed_address(*hashed_address);
367 let nodes = TrieCursorIter::new(&mut storage_trie_cursor)
368 .map(|node| node.map(|(path, _)| path))
369 .collect::<Result<Vec<_>, _>>()?;
370
371 if !nodes.is_empty() {
372 destroyed_storage_trie_nodes.insert(*hashed_address, nodes);
373 }
374 }
375 }
376
377 let removed_keys = account_node_iter.walker.take_removed_keys();
378 let StateRootContext { mut trie_updates, hashed_entries_walked, .. } = storage_ctx;
379 trie_updates.finalize(hash_builder, removed_keys, destroyed_storage_trie_nodes);
380
381 let stats = tracker.finish();
382
383 #[cfg(feature = "metrics")]
384 self.metrics.state_trie.record(stats);
385
386 trace!(
387 target: "trie::state_root",
388 %root,
389 duration = ?stats.duration(),
390 branches_added = stats.branches_added(),
391 leaves_added = stats.leaves_added(),
392 "calculated state root"
393 );
394
395 Ok(StateRootProgress::Complete(root, hashed_entries_walked, trie_updates))
396 }
397}
398
399#[derive(Debug)]
401pub(crate) struct StateRootContext {
402 account_rlp: Vec<u8>,
404 trie_updates: TrieUpdates,
406 hashed_entries_walked: usize,
408 updated_storage_nodes: usize,
410}
411
412impl StateRootContext {
413 fn new() -> Self {
415 Self {
416 account_rlp: Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE),
417 trie_updates: TrieUpdates::default(),
418 hashed_entries_walked: 0,
419 updated_storage_nodes: 0,
420 }
421 }
422
423 fn create_progress_state<C, H, K>(
426 mut self,
427 account_node_iter: TrieNodeIter<C, H, K>,
428 hash_builder: HashBuilder,
429 last_hashed_key: B256,
430 storage_state: Option<IntermediateStorageRootState>,
431 ) -> StateRootProgress
432 where
433 C: TrieCursor,
434 H: HashedCursor,
435 K: AsRef<AddedRemovedKeys>,
436 {
437 let (walker_stack, walker_deleted_keys) = account_node_iter.walker.split();
438 self.trie_updates.removed_nodes.extend(walker_deleted_keys);
439 let (hash_builder, hash_builder_updates) = hash_builder.split();
440 self.trie_updates.account_nodes.extend(hash_builder_updates);
441
442 let account_state = IntermediateRootState { hash_builder, walker_stack, last_hashed_key };
443
444 let state = IntermediateStateRootState {
445 account_root_state: account_state,
446 storage_root_state: storage_state,
447 };
448
449 StateRootProgress::Progress(Box::new(state), self.hashed_entries_walked, self.trie_updates)
450 }
451
452 fn total_updates_len<C, H, K>(
454 &self,
455 account_node_iter: &TrieNodeIter<C, H, K>,
456 hash_builder: &HashBuilder,
457 ) -> u64
458 where
459 C: TrieCursor,
460 H: HashedCursor,
461 K: AsRef<AddedRemovedKeys>,
462 {
463 (self.updated_storage_nodes +
464 account_node_iter.walker.removed_keys_len() +
465 hash_builder.updates_len()) as u64
466 }
467
468 fn process_storage_root_result(
478 &mut self,
479 storage_result: StorageRootProgress,
480 hashed_address: B256,
481 account: Account,
482 hash_builder: &mut HashBuilder,
483 retain_updates: bool,
484 ) -> Result<Option<IntermediateStorageRootState>, StateRootError> {
485 match storage_result {
486 StorageRootProgress::Complete(storage_root, storage_slots_walked, updates) => {
487 self.hashed_entries_walked += storage_slots_walked;
489 if retain_updates {
490 self.updated_storage_nodes += updates.len();
491 self.trie_updates.insert_storage_updates(hashed_address, updates);
492 }
493
494 self.account_rlp.clear();
496 let trie_account = account.into_trie_account(storage_root);
497 trie_account.encode(&mut self.account_rlp as &mut dyn BufMut);
498 hash_builder.add_leaf(Nibbles::unpack(hashed_address), &self.account_rlp);
499 Ok(None)
500 }
501 StorageRootProgress::Progress(state, storage_slots_walked, updates) => {
502 debug!(
504 target: "trie::state_root",
505 ?hashed_address,
506 storage_slots_walked,
507 last_storage_key = ?state.last_hashed_key,
508 ?account,
509 "Pausing storage root calculation"
510 );
511
512 self.hashed_entries_walked += storage_slots_walked;
513 if retain_updates {
514 self.trie_updates.insert_storage_updates(hashed_address, updates);
515 }
516
517 Ok(Some(IntermediateStorageRootState { state: *state, account }))
518 }
519 }
520 }
521}
522
523#[derive(Debug)]
525pub struct StorageRoot<T, H> {
526 pub trie_cursor_factory: T,
528 pub hashed_cursor_factory: H,
530 pub hashed_address: B256,
532 pub prefix_set: PrefixSet,
534 walk_all_changed_branch_children: bool,
536 previous_state: Option<IntermediateRootState>,
538 threshold: u64,
540 #[cfg(feature = "metrics")]
542 metrics: TrieRootMetrics,
543}
544
545impl<T, H> StorageRoot<T, H> {
546 pub fn new(
548 trie_cursor_factory: T,
549 hashed_cursor_factory: H,
550 address: Address,
551 prefix_set: PrefixSet,
552 #[cfg(feature = "metrics")] metrics: TrieRootMetrics,
553 ) -> Self {
554 Self::new_hashed(
555 trie_cursor_factory,
556 hashed_cursor_factory,
557 keccak256(address),
558 prefix_set,
559 #[cfg(feature = "metrics")]
560 metrics,
561 )
562 }
563
564 pub const fn new_hashed(
566 trie_cursor_factory: T,
567 hashed_cursor_factory: H,
568 hashed_address: B256,
569 prefix_set: PrefixSet,
570 #[cfg(feature = "metrics")] metrics: TrieRootMetrics,
571 ) -> Self {
572 Self {
573 trie_cursor_factory,
574 hashed_cursor_factory,
575 hashed_address,
576 prefix_set,
577 walk_all_changed_branch_children: false,
578 previous_state: None,
579 threshold: DEFAULT_INTERMEDIATE_THRESHOLD,
580 #[cfg(feature = "metrics")]
581 metrics,
582 }
583 }
584
585 pub fn with_prefix_set(mut self, prefix_set: PrefixSet) -> Self {
587 self.prefix_set = prefix_set;
588 self
589 }
590
591 pub const fn with_walk_all_changed_branch_children(mut self, enabled: bool) -> Self {
596 self.walk_all_changed_branch_children = enabled;
597 self
598 }
599
600 pub const fn with_threshold(mut self, threshold: u64) -> Self {
602 self.threshold = threshold;
603 self
604 }
605
606 pub const fn with_no_threshold(mut self) -> Self {
608 self.threshold = u64::MAX;
609 self
610 }
611
612 pub fn with_intermediate_state(mut self, state: Option<IntermediateRootState>) -> Self {
614 self.previous_state = state;
615 self
616 }
617
618 pub fn with_hashed_cursor_factory<HF>(self, hashed_cursor_factory: HF) -> StorageRoot<T, HF> {
620 StorageRoot {
621 trie_cursor_factory: self.trie_cursor_factory,
622 hashed_cursor_factory,
623 hashed_address: self.hashed_address,
624 prefix_set: self.prefix_set,
625 walk_all_changed_branch_children: self.walk_all_changed_branch_children,
626 previous_state: self.previous_state,
627 threshold: self.threshold,
628 #[cfg(feature = "metrics")]
629 metrics: self.metrics,
630 }
631 }
632
633 pub fn with_trie_cursor_factory<TF>(self, trie_cursor_factory: TF) -> StorageRoot<TF, H> {
635 StorageRoot {
636 trie_cursor_factory,
637 hashed_cursor_factory: self.hashed_cursor_factory,
638 hashed_address: self.hashed_address,
639 prefix_set: self.prefix_set,
640 walk_all_changed_branch_children: self.walk_all_changed_branch_children,
641 previous_state: self.previous_state,
642 threshold: self.threshold,
643 #[cfg(feature = "metrics")]
644 metrics: self.metrics,
645 }
646 }
647}
648
649impl<T, H> StorageRoot<T, H>
650where
651 T: TrieCursorFactory,
652 H: HashedCursorFactory,
653{
654 pub fn root_with_progress(self) -> Result<StorageRootProgress, StorageRootError> {
661 self.calculate(true)
662 }
663
664 pub fn root_with_updates(self) -> Result<(B256, usize, StorageTrieUpdates), StorageRootError> {
670 match self.with_no_threshold().calculate(true)? {
671 StorageRootProgress::Complete(root, walked, updates) => Ok((root, walked, updates)),
672 StorageRootProgress::Progress(..) => unreachable!(), }
674 }
675
676 pub fn root(self) -> Result<B256, StorageRootError> {
682 match self.calculate(false)? {
683 StorageRootProgress::Complete(root, _, _) => Ok(root),
684 StorageRootProgress::Progress(..) => unreachable!(), }
686 }
687
688 #[instrument(skip_all, level = "trace", target = "trie::storage_root", name = "storage_trie", fields(addr = %self.hashed_address, storage_root))]
695 pub fn calculate(self, retain_updates: bool) -> Result<StorageRootProgress, StorageRootError> {
696 trace!(target: "trie::storage_root", "calculating storage root");
697
698 let Self {
699 trie_cursor_factory,
700 hashed_cursor_factory,
701 hashed_address,
702 prefix_set,
703 walk_all_changed_branch_children,
704 previous_state,
705 threshold,
706 #[cfg(feature = "metrics")]
707 metrics,
708 } = self;
709
710 let mut hashed_storage_cursor =
711 hashed_cursor_factory.hashed_storage_cursor(hashed_address)?;
712 let mut storage_trie_cursor = trie_cursor_factory.storage_trie_cursor(hashed_address)?;
713
714 Self::calculate_with_cursors(
715 StorageRootCalculation {
716 hashed_address,
717 prefix_set,
718 previous_state,
719 walk_all_changed_branch_children,
720 threshold,
721 retain_updates,
722 },
723 &mut storage_trie_cursor,
724 &mut hashed_storage_cursor,
725 #[cfg(feature = "metrics")]
726 &metrics,
727 )
728 }
729
730 #[instrument(skip_all, level = "trace", target = "trie::storage_root", name = "storage_trie_with_cursor", fields(addr = %self.hashed_address, storage_root))]
736 pub fn calculate_with_cursor(
737 self,
738 hashed_storage_cursor: &mut H::StorageCursor<'_>,
739 retain_updates: bool,
740 ) -> Result<StorageRootProgress, StorageRootError> {
741 trace!(target: "trie::storage_root", "calculating storage root with cursor");
742
743 let Self {
744 trie_cursor_factory,
745 hashed_address,
746 prefix_set,
747 walk_all_changed_branch_children,
748 previous_state,
749 threshold,
750 #[cfg(feature = "metrics")]
751 metrics,
752 ..
753 } = self;
754
755 let mut storage_trie_cursor = trie_cursor_factory.storage_trie_cursor(hashed_address)?;
756
757 Self::calculate_with_cursors(
758 StorageRootCalculation {
759 hashed_address,
760 prefix_set,
761 previous_state,
762 walk_all_changed_branch_children,
763 threshold,
764 retain_updates,
765 },
766 &mut storage_trie_cursor,
767 hashed_storage_cursor,
768 #[cfg(feature = "metrics")]
769 &metrics,
770 )
771 }
772
773 fn calculate_with_cursors<TC, HC>(
776 calculation: StorageRootCalculation,
777 trie_cursor: &mut TC,
778 hashed_storage_cursor: &mut HC,
779 #[cfg(feature = "metrics")] metrics: &TrieRootMetrics,
780 ) -> Result<StorageRootProgress, StorageRootError>
781 where
782 TC: TrieStorageCursor,
783 HC: HashedStorageCursor<Value = U256>,
784 {
785 let StorageRootCalculation {
786 hashed_address,
787 prefix_set,
788 previous_state,
789 walk_all_changed_branch_children,
790 threshold,
791 retain_updates,
792 } = calculation;
793 hashed_storage_cursor.set_hashed_address(hashed_address);
794
795 if previous_state.is_none() &&
797 (!retain_updates || prefix_set.is_empty()) &&
798 hashed_storage_cursor.is_storage_empty()?
799 {
800 Span::current().record("storage_root", tracing::field::debug(EMPTY_ROOT_HASH));
801 return Ok(StorageRootProgress::Complete(
802 EMPTY_ROOT_HASH,
803 0,
804 StorageTrieUpdates::default(),
805 ))
806 }
807
808 trie_cursor.set_hashed_address(hashed_address);
809
810 let mut tracker = TrieTracker::default();
811 let mut trie_updates = StorageTrieUpdates::default();
812
813 let (mut hash_builder, mut storage_node_iter) = match previous_state {
814 Some(state) => {
815 let hash_builder = state.hash_builder.with_updates(retain_updates);
816 let walker = TrieWalker::<_>::storage_trie_from_stack(
817 trie_cursor,
818 state.walker_stack,
819 prefix_set,
820 )
821 .with_walk_all_changed_branch_children(walk_all_changed_branch_children)
822 .with_deletions_retained(retain_updates);
823 let node_iter = TrieNodeIter::storage_trie(walker, hashed_storage_cursor)
824 .with_last_hashed_key(state.last_hashed_key);
825 (hash_builder, node_iter)
826 }
827 None => {
828 let hash_builder = HashBuilder::default().with_updates(retain_updates);
829 let walker = TrieWalker::storage_trie(trie_cursor, prefix_set)?
830 .with_walk_all_changed_branch_children(walk_all_changed_branch_children)
831 .with_deletions_retained(retain_updates);
832 let node_iter = TrieNodeIter::storage_trie(walker, hashed_storage_cursor);
833 (hash_builder, node_iter)
834 }
835 };
836
837 let mut hashed_entries_walked = 0;
838 while let Some(node) = storage_node_iter.try_next()? {
839 match node {
840 TrieElement::Branch(node) => {
841 tracker.inc_branch();
842 hash_builder.add_branch(node.key, node.value, node.children_are_in_trie);
843 }
844 TrieElement::Leaf(hashed_slot, value) => {
845 tracker.inc_leaf();
846 hashed_entries_walked += 1;
847 hash_builder.add_leaf(
848 Nibbles::unpack(hashed_slot),
849 alloy_rlp::encode_fixed_size(&value).as_ref(),
850 );
851
852 let total_updates_len =
854 storage_node_iter.walker.removed_keys_len() + hash_builder.updates_len();
855 if retain_updates && total_updates_len as u64 >= threshold {
856 let (walker_stack, walker_deleted_keys) = storage_node_iter.walker.split();
857 trie_updates.removed_nodes.extend(walker_deleted_keys);
858 let (hash_builder, hash_builder_updates) = hash_builder.split();
859 trie_updates.storage_nodes.extend(hash_builder_updates);
860
861 let state = IntermediateRootState {
862 hash_builder,
863 walker_stack,
864 last_hashed_key: hashed_slot,
865 };
866
867 return Ok(StorageRootProgress::Progress(
868 Box::new(state),
869 hashed_entries_walked,
870 trie_updates,
871 ))
872 }
873 }
874 }
875 }
876
877 let root = hash_builder.root();
878 Span::current().record("storage_root", tracing::field::debug(root));
879
880 let removed_keys = storage_node_iter.walker.take_removed_keys();
881 trie_updates.finalize(hash_builder, removed_keys);
882
883 let stats = tracker.finish();
884
885 #[cfg(feature = "metrics")]
886 metrics.record(stats);
887
888 trace!(
889 target: "trie::storage_root",
890 %root,
891 %hashed_address,
892 duration = ?stats.duration(),
893 branches_added = stats.branches_added(),
894 leaves_added = stats.leaves_added(),
895 "calculated storage root"
896 );
897
898 let storage_slots_walked = stats.leaves_added() as usize;
899 Ok(StorageRootProgress::Complete(root, storage_slots_walked, trie_updates))
900 }
901}
902
903struct StorageRootCalculation {
905 hashed_address: B256,
906 prefix_set: PrefixSet,
907 previous_state: Option<IntermediateRootState>,
908 walk_all_changed_branch_children: bool,
909 threshold: u64,
910 retain_updates: bool,
911}
912
913#[derive(Clone, Copy, Debug)]
915pub enum TrieType {
916 State,
918 Storage,
920 Custom(&'static str),
922}
923
924impl TrieType {
925 #[cfg(feature = "metrics")]
926 pub(crate) const fn as_str(&self) -> &'static str {
927 match self {
928 Self::State => "state",
929 Self::Storage => "storage",
930 Self::Custom(s) => s,
931 }
932 }
933}