reth_trie_common/
account.rs1use crate::root::storage_root_unhashed;
2use alloy_consensus::constants::KECCAK_EMPTY;
3use alloy_genesis::GenesisAccount;
4use alloy_primitives::{keccak256, B256, U256};
5use alloy_rlp::{RlpDecodable, RlpEncodable};
6use alloy_trie::EMPTY_ROOT_HASH;
7use reth_primitives_traits::Account;
8use revm_primitives::{AccountInfo, FlaggedStorage};
9
10#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
12pub struct TrieAccount {
13 pub nonce: u64,
15 pub balance: U256,
17 pub storage_root: B256,
19 pub code_hash: B256,
21}
22
23impl TrieAccount {
24 pub const fn storage_root(&self) -> B256 {
26 self.storage_root
27 }
28}
29
30impl From<GenesisAccount> for TrieAccount {
31 fn from(account: GenesisAccount) -> Self {
32 let storage_root = account
33 .storage
34 .map(|storage| {
35 storage_root_unhashed(
36 storage.into_iter().filter(|(_, value)| !value.is_zero()).map(
37 |(slot, value)| {
38 (slot, FlaggedStorage::new_from_value(U256::from_be_bytes(*value)))
39 },
40 ),
41 )
42 })
43 .unwrap_or(EMPTY_ROOT_HASH);
44
45 Self {
46 nonce: account.nonce.unwrap_or_default(),
47 balance: account.balance,
48 storage_root,
49 code_hash: account.code.map_or(KECCAK_EMPTY, keccak256),
50 }
51 }
52}
53
54impl From<(Account, B256)> for TrieAccount {
55 fn from((account, storage_root): (Account, B256)) -> Self {
56 Self {
57 nonce: account.nonce,
58 balance: account.balance,
59 storage_root,
60 code_hash: account.bytecode_hash.unwrap_or(KECCAK_EMPTY),
61 }
62 }
63}
64
65impl From<(AccountInfo, B256)> for TrieAccount {
66 fn from((account, storage_root): (AccountInfo, B256)) -> Self {
67 Self {
68 nonce: account.nonce,
69 balance: account.balance,
70 storage_root,
71 code_hash: account.code_hash,
72 }
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use alloy_primitives::Bytes;
80 use std::collections::BTreeMap;
81
82 #[test]
83 fn test_from_genesis_account_with_default_values() {
84 let genesis_account = GenesisAccount::default();
85
86 let trie_account: TrieAccount = genesis_account.into();
88
89 assert_eq!(trie_account.nonce, 0);
91 assert_eq!(trie_account.balance, U256::default());
92 assert_eq!(trie_account.storage_root(), EMPTY_ROOT_HASH);
93 assert_eq!(trie_account.code_hash, KECCAK_EMPTY);
94
95 assert_eq!(TrieAccount::from((Account::default(), EMPTY_ROOT_HASH)), trie_account);
97
98 assert_eq!(TrieAccount::from((AccountInfo::default(), EMPTY_ROOT_HASH)), trie_account);
100 }
101
102 #[test]
103 fn test_from_genesis_account_with_values() {
104 let mut storage = BTreeMap::new();
106 storage.insert(B256::from([0x01; 32]), B256::from([0x02; 32]));
107
108 let genesis_account = GenesisAccount {
109 nonce: Some(10),
110 balance: U256::from(1000),
111 code: Some(Bytes::from(vec![0x60, 0x61])),
112 storage: Some(storage),
113 private_key: None,
114 };
115
116 let trie_account: TrieAccount = genesis_account.into();
118
119 let expected_storage_root = storage_root_unhashed(BTreeMap::from([(
120 B256::from([0x01; 32]),
121 FlaggedStorage::from(U256::from_be_bytes(*B256::from([0x02; 32]))),
122 )]));
123
124 assert_eq!(trie_account.nonce, 10);
126 assert_eq!(trie_account.balance, U256::from(1000));
127 assert_eq!(trie_account.storage_root(), expected_storage_root);
128 assert_eq!(trie_account.code_hash, keccak256([0x60, 0x61]));
129
130 assert_eq!(
132 TrieAccount::from((
133 Account {
134 nonce: 10,
135 balance: U256::from(1000),
136 bytecode_hash: Some(keccak256([0x60, 0x61]))
137 },
138 expected_storage_root
139 )),
140 trie_account
141 );
142
143 assert_eq!(
145 TrieAccount::from((
146 AccountInfo {
147 nonce: 10,
148 balance: U256::from(1000),
149 code_hash: keccak256([0x60, 0x61]),
150 ..Default::default()
151 },
152 expected_storage_root
153 )),
154 trie_account
155 );
156 }
157
158 #[test]
159 fn test_from_genesis_account_with_zeroed_storage_values() {
160 let storage = BTreeMap::from([(B256::from([0x01; 32]), B256::from([0x00; 32]))]);
162
163 let genesis_account = GenesisAccount {
164 nonce: Some(3),
165 balance: U256::from(300),
166 code: None,
167 storage: Some(storage),
168 private_key: None,
169 };
170
171 let trie_account: TrieAccount = genesis_account.into();
173
174 assert_eq!(trie_account.nonce, 3);
176 assert_eq!(trie_account.balance, U256::from(300));
177 assert_eq!(trie_account.storage_root(), EMPTY_ROOT_HASH);
179 assert_eq!(trie_account.code_hash, KECCAK_EMPTY);
181 }
182}