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, 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
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    /// Whether every child under a branch whose path matches the prefix set should be walked.
40    walk_all_changed_branch_children: bool,
41    /// Previous intermediate state.
42    previous_state: Option<IntermediateStateRootState>,
43    /// The number of updates after which the intermediate progress should be returned.
44    threshold: u64,
45    #[cfg(feature = "metrics")]
46    /// State root metrics.
47    metrics: StateRootMetrics,
48}
49
50impl<T, H> StateRoot<T, H> {
51    /// Creates [`StateRoot`] with `trie_cursor_factory` and `hashed_cursor_factory`. All other
52    /// parameters are set to reasonable defaults.
53    ///
54    /// The cursors created by given factories are then used to walk through the accounts and
55    /// calculate the state root value with.
56    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    /// Set the prefix sets.
70    pub fn with_prefix_sets(mut self, prefix_sets: TriePrefixSets) -> Self {
71        self.prefix_sets = prefix_sets;
72        self
73    }
74
75    /// Configures the state root walker to visit all children of changed branch paths.
76    ///
77    /// When updates are retained, also removes stored descendants hidden by a changed branch's
78    /// tree mask. Regenerated branch updates take precedence over these deletions.
79    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    /// Set the threshold.
85    pub const fn with_threshold(mut self, threshold: u64) -> Self {
86        self.threshold = threshold;
87        self
88    }
89
90    /// Set the threshold to maximum value so that intermediate progress is not returned.
91    pub const fn with_no_threshold(mut self) -> Self {
92        self.threshold = u64::MAX;
93        self
94    }
95
96    /// Set the previously recorded intermediate state.
97    pub fn with_intermediate_state(mut self, state: Option<IntermediateStateRootState>) -> Self {
98        self.previous_state = state;
99        self
100    }
101
102    /// Set the hashed cursor factory.
103    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    /// Set the trie cursor factory.
117    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    /// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
137    /// nodes into the hash builder. Collects the updates in the process.
138    ///
139    /// Ignores the threshold.
140    ///
141    /// # Returns
142    ///
143    /// The state root and the trie updates.
144    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!(), // unreachable threshold
148        }
149    }
150
151    /// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
152    /// nodes into the hash builder.
153    ///
154    /// # Returns
155    ///
156    /// The state root hash.
157    pub fn root(self) -> Result<B256, StateRootError> {
158        match self.calculate(false)? {
159            StateRootProgress::Complete(root, _, _) => Ok(root),
160            StateRootProgress::Progress(..) => unreachable!(), // update retention is disabled
161        }
162    }
163
164    /// Walks the intermediate nodes of existing state trie (if any) and hashed entries. Feeds the
165    /// nodes into the hash builder. Collects the updates in the process.
166    ///
167    /// # Returns
168    ///
169    /// The intermediate progress of state root computation.
170    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        // Shared storage cursors for reuse across all storage root calculations.
182        // Created lazily on first use to avoid issues with mock cursors.
183        let mut hashed_storage_cursor: Option<H::StorageCursor<'_>> = None;
184        let mut storage_trie_cursor: Option<T::StorageTrieCursor<'_>> = None;
185
186        // create state root context once for reuse
187        let mut storage_ctx = StateRootContext::new();
188
189        // first handle any in-progress storage root calculation
190        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            // resume account trie iteration
194            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 we have an in-progress storage root, complete it first
206            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                    // still in progress, need to pause again
258                    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            // no intermediate state, create new hash builder and node iter for state root
270            // calculation
271            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                    // calculate storage root, calculating the remaining threshold so we have
290                    // bounded memory usage even while in the middle of storage root calculation
291                    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                        // storage root hit threshold, need to pause
333                        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                    // decide if we need to return intermediate progress
342                    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/// Contains state mutated during state root calculation and storage root result handling.
400#[derive(Debug)]
401pub(crate) struct StateRootContext {
402    /// Reusable buffer for encoding account data.
403    account_rlp: Vec<u8>,
404    /// Accumulates updates from account and storage root calculation.
405    trie_updates: TrieUpdates,
406    /// Tracks total hashed entries walked.
407    hashed_entries_walked: usize,
408    /// Counts storage trie nodes updated.
409    updated_storage_nodes: usize,
410}
411
412impl StateRootContext {
413    /// Creates a new state root context.
414    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    /// Creates a [`StateRootProgress`] when the threshold is hit, from the state of the current
424    /// [`TrieNodeIter`], [`HashBuilder`], last hashed key and any storage root intermediate state.
425    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    /// Calculates the total number of updated nodes.
453    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    /// Processes the result of a storage root calculation.
469    ///
470    /// Handles both completed and in-progress storage root calculations:
471    /// - For completed roots: encodes the account with the storage root, updates the hash builder
472    ///   with the new account, and updates metrics.
473    /// - For in-progress roots: returns the intermediate state for later resumption
474    ///
475    /// Returns an [`IntermediateStorageRootState`] if the calculation needs to be resumed later, or
476    /// `None` if the storage root was successfully computed and added to the trie.
477    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                // Storage root completed
488                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                // Encode the account with the computed storage root
495                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                // Storage root hit threshold or resumed calculation hit threshold
503                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/// `StorageRoot` is used to compute the root node of an account storage trie.
524#[derive(Debug)]
525pub struct StorageRoot<T, H> {
526    /// A reference to the database transaction.
527    pub trie_cursor_factory: T,
528    /// The factory for hashed cursors.
529    pub hashed_cursor_factory: H,
530    /// The hashed address of an account.
531    pub hashed_address: B256,
532    /// The set of storage slot prefixes that have changed.
533    pub prefix_set: PrefixSet,
534    /// Whether every child under a branch whose path matches the prefix set should be walked.
535    walk_all_changed_branch_children: bool,
536    /// Previous intermediate state.
537    previous_state: Option<IntermediateRootState>,
538    /// The number of updates after which the intermediate progress should be returned.
539    threshold: u64,
540    /// Storage root metrics.
541    #[cfg(feature = "metrics")]
542    metrics: TrieRootMetrics,
543}
544
545impl<T, H> StorageRoot<T, H> {
546    /// Creates a new storage root calculator given a raw address.
547    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    /// Creates a new storage root calculator given a hashed address.
565    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    /// Set the changed prefixes.
586    pub fn with_prefix_set(mut self, prefix_set: PrefixSet) -> Self {
587        self.prefix_set = prefix_set;
588        self
589    }
590
591    /// Configures the storage root walker to visit all children of changed branch paths.
592    ///
593    /// When updates are retained, also removes stored descendants hidden by a changed branch's
594    /// tree mask. Regenerated branch updates take precedence over these deletions.
595    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    /// Set the threshold.
601    pub const fn with_threshold(mut self, threshold: u64) -> Self {
602        self.threshold = threshold;
603        self
604    }
605
606    /// Set the threshold to maximum value so that intermediate progress is not returned.
607    pub const fn with_no_threshold(mut self) -> Self {
608        self.threshold = u64::MAX;
609        self
610    }
611
612    /// Set the previously recorded intermediate state.
613    pub fn with_intermediate_state(mut self, state: Option<IntermediateRootState>) -> Self {
614        self.previous_state = state;
615        self
616    }
617
618    /// Set the hashed cursor factory.
619    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    /// Set the trie cursor factory.
634    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    /// Walks the intermediate nodes of existing storage trie (if any) and hashed entries. Feeds the
655    /// nodes into the hash builder. Collects the updates in the process.
656    ///
657    /// # Returns
658    ///
659    /// The intermediate progress of state root computation.
660    pub fn root_with_progress(self) -> Result<StorageRootProgress, StorageRootError> {
661        self.calculate(true)
662    }
663
664    /// Walks the hashed storage table entries for a given address and calculates the storage root.
665    ///
666    /// # Returns
667    ///
668    /// The storage root and storage trie updates for a given address.
669    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!(), // unreachable threshold
673        }
674    }
675
676    /// Walks the hashed storage table entries for a given address and calculates the storage root.
677    ///
678    /// # Returns
679    ///
680    /// The storage root.
681    pub fn root(self) -> Result<B256, StorageRootError> {
682        match self.calculate(false)? {
683            StorageRootProgress::Complete(root, _, _) => Ok(root),
684            StorageRootProgress::Progress(..) => unreachable!(), // update retention is disabled
685        }
686    }
687
688    /// Walks the hashed storage table entries for a given address and calculates the storage root.
689    ///
690    /// # Returns
691    ///
692    /// The storage root, number of walked entries and trie updates
693    /// for a given address if requested.
694    #[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    /// Walks the hashed storage table entries for a given address and calculates the storage root
731    /// using a pre-created cursor. The cursor will be repositioned to the given hashed address.
732    ///
733    /// This method allows reusing a single cursor across multiple storage root calculations,
734    /// reducing overhead when computing storage roots for many accounts.
735    #[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    /// Walks the hashed storage table entries for a given address and calculates the storage root
774    /// using pre-created cursors. The cursors will be repositioned to the given hashed address.
775    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        // Empty storage only needs to be walked when changed prefixes must produce trie updates.
796        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                    // Check if we need to return intermediate progress
853                    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
903/// Parameters for a storage root calculation using pre-created cursors.
904struct 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/// Trie type for differentiating between various trie calculations.
914#[derive(Clone, Copy, Debug)]
915pub enum TrieType {
916    /// State trie type.
917    State,
918    /// Storage trie type.
919    Storage,
920    /// Custom trie type. Can be used in ExEx.
921    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}