Skip to main content

reth_trie/
trie.rs

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
23/// The default updates after which root algorithms should return intermediate progress rather than
24/// finishing the computation.
25const DEFAULT_INTERMEDIATE_THRESHOLD: u64 = 100_000;
26
27#[cfg(feature = "metrics")]
28use crate::metrics::{StateRootMetrics, TrieRootMetrics};
29
30/// `StateRoot` is used to compute the root node of a state trie.
31#[derive(Debug)]
32pub struct StateRoot<T, H> {
33    /// The factory for trie cursors.
34    pub trie_cursor_factory: T,
35    /// The factory for hashed cursors.
36    pub hashed_cursor_factory: H,
37    /// A set of prefix sets that have changed.
38    pub prefix_sets: TriePrefixSets,
39    /// Previous intermediate state.
40    previous_state: Option<IntermediateStateRootState>,
41    /// The number of updates after which the intermediate progress should be returned.
42    threshold: u64,
43    #[cfg(feature = "metrics")]
44    /// State root metrics.
45    metrics: StateRootMetrics,
46}
47
48impl<T, H> StateRoot<T, H> {
49    /// Creates [`StateRoot`] with `trie_cursor_factory` and `hashed_cursor_factory`. All other
50    /// parameters are set to reasonable defaults.
51    ///
52    /// The cursors created by given factories are then used to walk through the accounts and
53    /// calculate the state root value with.
54    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    /// Set the prefix sets.
67    pub fn with_prefix_sets(mut self, prefix_sets: TriePrefixSets) -> Self {
68        self.prefix_sets = prefix_sets;
69        self
70    }
71
72    /// Set the threshold.
73    pub const fn with_threshold(mut self, threshold: u64) -> Self {
74        self.threshold = threshold;
75        self
76    }
77
78    /// Set the threshold to maximum value so that intermediate progress is not returned.
79    pub const fn with_no_threshold(mut self) -> Self {
80        self.threshold = u64::MAX;
81        self
82    }
83
84    /// Set the previously recorded intermediate state.
85    pub fn with_intermediate_state(mut self, state: Option<IntermediateStateRootState>) -> Self {
86        self.previous_state = state;
87        self
88    }
89
90    /// Set the hashed cursor factory.
91    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    /// Set the trie cursor factory.
104    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    /// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
123    /// nodes into the hash builder. Collects the updates in the process.
124    ///
125    /// Ignores the threshold.
126    ///
127    /// # Returns
128    ///
129    /// The state root and the trie updates.
130    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!(), // unreachable threshold
134        }
135    }
136
137    /// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
138    /// nodes into the hash builder.
139    ///
140    /// # Returns
141    ///
142    /// The state root hash.
143    pub fn root(self) -> Result<B256, StateRootError> {
144        match self.calculate(false)? {
145            StateRootProgress::Complete(root, _, _) => Ok(root),
146            StateRootProgress::Progress(..) => unreachable!(), // update retention is disabled
147        }
148    }
149
150    /// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
151    /// nodes into the hash builder. Collects the updates in the process.
152    ///
153    /// # Returns
154    ///
155    /// The intermediate progress of state root computation.
156    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        // Shared storage cursors for reuse across all storage root calculations.
168        // Created lazily on first use to avoid issues with mock cursors.
169        let mut hashed_storage_cursor: Option<H::StorageCursor<'_>> = None;
170        let mut storage_trie_cursor: Option<T::StorageTrieCursor<'_>> = None;
171
172        // create state root context once for reuse
173        let mut storage_ctx = StateRootContext::new();
174
175        // first handle any in-progress storage root calculation
176        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            // resume account trie iteration
180            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 we have an in-progress storage root, complete it first
191            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                    // still in progress, need to pause again
242                    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            // no intermediate state, create new hash builder and node iter for state root
254            // calculation
255            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                    // calculate storage root, calculating the remaining threshold so we have
273                    // bounded memory usage even while in the middle of storage root calculation
274                    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                        // storage root hit threshold, need to pause
315                        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                    // decide if we need to return intermediate progress
324                    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/// Contains state mutated during state root calculation and storage root result handling.
363#[derive(Debug)]
364pub(crate) struct StateRootContext {
365    /// Reusable buffer for encoding account data.
366    account_rlp: Vec<u8>,
367    /// Accumulates updates from account and storage root calculation.
368    trie_updates: TrieUpdates,
369    /// Tracks total hashed entries walked.
370    hashed_entries_walked: usize,
371    /// Counts storage trie nodes updated.
372    updated_storage_nodes: usize,
373}
374
375impl StateRootContext {
376    /// Creates a new state root context.
377    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    /// Creates a [`StateRootProgress`] when the threshold is hit, from the state of the current
387    /// [`TrieNodeIter`], [`HashBuilder`], last hashed key and any storage root intermediate state.
388    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    /// Calculates the total number of updated nodes.
416    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    /// Processes the result of a storage root calculation.
432    ///
433    /// Handles both completed and in-progress storage root calculations:
434    /// - For completed roots: encodes the account with the storage root, updates the hash builder
435    ///   with the new account, and updates metrics.
436    /// - For in-progress roots: returns the intermediate state for later resumption
437    ///
438    /// Returns an [`IntermediateStorageRootState`] if the calculation needs to be resumed later, or
439    /// `None` if the storage root was successfully computed and added to the trie.
440    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                // Storage root completed
451                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                // Encode the account with the computed storage root
458                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                // Storage root hit threshold or resumed calculation hit threshold
466                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/// `StorageRoot` is used to compute the root node of an account storage trie.
487#[derive(Debug)]
488pub struct StorageRoot<T, H> {
489    /// A reference to the database transaction.
490    pub trie_cursor_factory: T,
491    /// The factory for hashed cursors.
492    pub hashed_cursor_factory: H,
493    /// The hashed address of an account.
494    pub hashed_address: B256,
495    /// The set of storage slot prefixes that have changed.
496    pub prefix_set: PrefixSet,
497    /// Previous intermediate state.
498    previous_state: Option<IntermediateRootState>,
499    /// The number of updates after which the intermediate progress should be returned.
500    threshold: u64,
501    /// Storage root metrics.
502    #[cfg(feature = "metrics")]
503    metrics: TrieRootMetrics,
504}
505
506impl<T, H> StorageRoot<T, H> {
507    /// Creates a new storage root calculator given a raw address.
508    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    /// Creates a new storage root calculator given a hashed address.
526    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    /// Set the changed prefixes.
546    pub fn with_prefix_set(mut self, prefix_set: PrefixSet) -> Self {
547        self.prefix_set = prefix_set;
548        self
549    }
550
551    /// Set the threshold.
552    pub const fn with_threshold(mut self, threshold: u64) -> Self {
553        self.threshold = threshold;
554        self
555    }
556
557    /// Set the threshold to maximum value so that intermediate progress is not returned.
558    pub const fn with_no_threshold(mut self) -> Self {
559        self.threshold = u64::MAX;
560        self
561    }
562
563    /// Set the previously recorded intermediate state.
564    pub fn with_intermediate_state(mut self, state: Option<IntermediateRootState>) -> Self {
565        self.previous_state = state;
566        self
567    }
568
569    /// Set the hashed cursor factory.
570    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    /// Set the trie cursor factory.
584    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    /// Walks the intermediate nodes of existing storage trie (if any) and hashed entries. Feeds the
604    /// nodes into the hash builder. Collects the updates in the process.
605    ///
606    /// # Returns
607    ///
608    /// The intermediate progress of state root computation.
609    pub fn root_with_progress(self) -> Result<StorageRootProgress, StorageRootError> {
610        self.calculate(true)
611    }
612
613    /// Walks the hashed storage table entries for a given address and calculates the storage root.
614    ///
615    /// # Returns
616    ///
617    /// The storage root and storage trie updates for a given address.
618    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!(), // unreachable threshold
622        }
623    }
624
625    /// Walks the hashed storage table entries for a given address and calculates the storage root.
626    ///
627    /// # Returns
628    ///
629    /// The storage root.
630    pub fn root(self) -> Result<B256, StorageRootError> {
631        match self.calculate(false)? {
632            StorageRootProgress::Complete(root, _, _) => Ok(root),
633            StorageRootProgress::Progress(..) => unreachable!(), // update retention is disabled
634        }
635    }
636
637    /// Walks the hashed storage table entries for a given address and calculates the storage root.
638    ///
639    /// # Returns
640    ///
641    /// The storage root, number of walked entries and trie updates
642    /// for a given address if requested.
643    #[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    /// Walks the hashed storage table entries for a given address and calculates the storage root
678    /// using a pre-created cursor. The cursor will be repositioned to the given hashed address.
679    ///
680    /// This method allows reusing a single cursor across multiple storage root calculations,
681    /// reducing overhead when computing storage roots for many accounts.
682    #[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    /// Walks the hashed storage table entries for a given address and calculates the storage root
719    /// using pre-created cursors. The cursors will be repositioned to the given hashed address.
720    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        // short circuit on empty storage
740        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                    // Check if we need to return intermediate progress
792                    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
842/// Parameters for a storage root calculation using pre-created cursors.
843struct StorageRootCalculation {
844    hashed_address: B256,
845    prefix_set: PrefixSet,
846    previous_state: Option<IntermediateRootState>,
847    threshold: u64,
848    retain_updates: bool,
849}
850
851/// Trie type for differentiating between various trie calculations.
852#[derive(Clone, Copy, Debug)]
853pub enum TrieType {
854    /// State trie type.
855    State,
856    /// Storage trie type.
857    Storage,
858    /// Custom trie type. Can be used in ExEx.
859    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}