1use alloc::vec::Vec;
4use alloy_primitives::B256;
5use alloy_rlp::{Decodable, Encodable};
6use itertools::Itertools;
7use reth_trie_common::{
8 HashedPostState, Nibbles, TrieAccount, EMPTY_ROOT_HASH, TRIE_ACCOUNT_RLP_MAX_SIZE,
9};
10use reth_trie_sparse::{errors::SparseStateTrieResult, SparseStateTrie, SparseTrie};
11
12pub(crate) fn calculate_state_root(
20 trie: &mut SparseStateTrie,
21 state: HashedPostState,
22) -> SparseStateTrieResult<B256> {
23 let mut storage_results = Vec::with_capacity(state.storages.len());
32
33 for (address, storage) in state.storages.into_iter().sorted_unstable_by_key(|(addr, _)| *addr) {
34 let mut storage_trie =
36 trie.take_storage_trie(&address).unwrap_or_else(SparseTrie::revealed_empty);
37
38 if storage.wiped {
39 storage_trie.wipe()?;
40 }
41
42 for (hashed_slot, value) in
44 storage.storage.into_iter().sorted_unstable_by_key(|(slot, _)| *slot)
45 {
46 let nibbles = Nibbles::unpack(hashed_slot);
47 if value.is_zero() {
48 storage_trie.remove_leaf(&nibbles)?;
49 } else {
50 storage_trie.update_leaf(
51 nibbles,
52 alloy_rlp::encode_fixed_size(&value).to_vec(),
53 value.is_private,
54 )?;
55 }
56 }
57
58 storage_trie.root();
60 storage_results.push((address, storage_trie));
61 }
62
63 for (address, storage_trie) in storage_results {
65 trie.insert_storage_trie(address, storage_trie);
66 }
67
68 let mut account_rlp_buf = Vec::with_capacity(TRIE_ACCOUNT_RLP_MAX_SIZE);
72
73 for (hashed_address, account) in
74 state.accounts.into_iter().sorted_unstable_by_key(|(addr, _)| *addr)
75 {
76 let nibbles = Nibbles::unpack(hashed_address);
77 let account = account.unwrap_or_default();
78
79 let storage_root = if let Some(storage_trie) = trie.storage_trie_mut(&hashed_address) {
81 storage_trie.root()
82 } else if let Some(value) = trie.get_account_value(&hashed_address) {
83 TrieAccount::decode(&mut &value[..])?.storage_root
84 } else {
85 EMPTY_ROOT_HASH
86 };
87
88 if account.is_empty() && storage_root == EMPTY_ROOT_HASH {
90 trie.remove_account_leaf(&nibbles)?;
91 } else {
92 account_rlp_buf.clear();
93 account.into_trie_account(storage_root).encode(&mut account_rlp_buf);
94 trie.update_account_leaf(nibbles, account_rlp_buf.clone())?;
95 }
96 }
97
98 trie.root()
100}