reth_trie_common/
added_removed_keys.rs1use crate::HashedPostState;
4use alloy_primitives::{map::B256Map, B256};
5use alloy_trie::proof::AddedRemovedKeys;
6
7#[derive(Debug, Clone)]
9pub struct MultiAddedRemovedKeys {
10 account: AddedRemovedKeys,
11 storages: B256Map<AddedRemovedKeys>,
12}
13
14fn default_added_removed_keys() -> AddedRemovedKeys {
17 AddedRemovedKeys::default().with_assume_added(true)
18}
19
20impl Default for MultiAddedRemovedKeys {
21 fn default() -> Self {
22 Self::new()
23 }
24}
25
26impl MultiAddedRemovedKeys {
27 pub fn new() -> Self {
29 Self { account: default_added_removed_keys(), storages: Default::default() }
30 }
31
32 pub fn update_with_state(&mut self, update: &HashedPostState) {
38 for (hashed_address, storage) in &update.storages {
39 let account = update
40 .accounts
41 .get(hashed_address)
42 .map(|entry| entry.unwrap_or_default())
43 .unwrap_or_default();
44
45 if storage.wiped {
46 self.storages.remove(hashed_address);
47 if account.is_empty() {
48 self.account.insert_removed(*hashed_address);
49 }
50 continue
51 }
52
53 let storage_removed_keys =
54 self.storages.entry(*hashed_address).or_insert_with(default_added_removed_keys);
55
56 for (key, val) in &storage.storage {
57 if val.is_zero() {
58 storage_removed_keys.insert_removed(*key);
59 } else {
60 storage_removed_keys.remove_removed(key);
61 }
62 }
63
64 if !account.is_empty() {
65 self.account.remove_removed(hashed_address);
66 }
67 }
68 }
69
70 pub fn get_storage(&self, hashed_address: &B256) -> Option<&AddedRemovedKeys> {
72 self.storages.get(hashed_address)
73 }
74
75 pub const fn get_accounts(&self) -> &AddedRemovedKeys {
77 &self.account
78 }
79
80 pub fn touch_accounts(&mut self, addresses: impl Iterator<Item = B256>) {
82 for address in addresses {
83 self.storages.entry(address).or_insert_with(default_added_removed_keys);
84 }
85 }
86}
87
88#[cfg(test)]
89mod tests {
90 use super::*;
91 use crate::HashedStorage;
92 use alloy_primitives::U256;
93 use reth_primitives_traits::Account;
94
95 #[test]
96 fn test_update_with_state_storage_keys_non_zero() {
97 let mut multi_keys = MultiAddedRemovedKeys::new();
98 let mut update = HashedPostState::default();
99
100 let addr = B256::random();
101 let slot1 = B256::random();
102 let slot2 = B256::random();
103
104 let mut storage = HashedStorage::default();
106 storage.storage.insert(slot1, U256::ZERO);
107 storage.storage.insert(slot2, U256::ZERO);
108 update.storages.insert(addr, storage);
109 multi_keys.update_with_state(&update);
110
111 assert!(multi_keys.get_storage(&addr).unwrap().is_removed(&slot1));
113 assert!(multi_keys.get_storage(&addr).unwrap().is_removed(&slot2));
114
115 let mut update2 = HashedPostState::default();
117 let mut storage2 = HashedStorage::default();
118 storage2.storage.insert(slot1, U256::from(100));
119 storage2.storage.insert(slot2, U256::from(200));
120 update2.storages.insert(addr, storage2);
121 multi_keys.update_with_state(&update2);
122
123 let storage_keys = multi_keys.get_storage(&addr).unwrap();
125 assert!(!storage_keys.is_removed(&slot1));
126 assert!(!storage_keys.is_removed(&slot2));
127 }
128
129 #[test]
130 fn test_update_with_state_wiped_storage() {
131 let mut multi_keys = MultiAddedRemovedKeys::new();
132 let mut update = HashedPostState::default();
133
134 let addr = B256::random();
135 let slot1 = B256::random();
136
137 let mut storage = HashedStorage::default();
139 storage.storage.insert(slot1, U256::ZERO);
140 update.storages.insert(addr, storage);
141 multi_keys.update_with_state(&update);
142 assert!(multi_keys.get_storage(&addr).is_some());
143
144 let mut update2 = HashedPostState::default();
146 let wiped_storage = HashedStorage::new(true);
147 update2.storages.insert(addr, wiped_storage);
148 multi_keys.update_with_state(&update2);
149
150 assert!(multi_keys.get_storage(&addr).is_none());
152 assert!(multi_keys.get_accounts().is_removed(&addr));
153 }
154
155 #[test]
156 fn test_update_with_state_account_tracking() {
157 let mut multi_keys = MultiAddedRemovedKeys::new();
158 let mut update = HashedPostState::default();
159
160 let addr = B256::random();
161 let slot = B256::random();
162
163 let mut storage = HashedStorage::default();
165 storage.storage.insert(slot, U256::ZERO);
166 update.storages.insert(addr, storage);
167 multi_keys.update_with_state(&update);
170
171 assert!(multi_keys.get_storage(&addr).unwrap().is_removed(&slot));
173 assert!(!multi_keys.get_accounts().is_removed(&addr));
174
175 let mut update2 = HashedPostState::default();
177 let mut storage2 = HashedStorage::default();
178 storage2.storage.insert(slot, U256::from(100)); update2.storages.insert(addr, storage2);
180
181 multi_keys.update_with_state(&update2);
182
183 assert!(!multi_keys.get_accounts().is_removed(&addr));
185 }
186
187 #[test]
188 fn test_update_with_state_account_with_balance() {
189 let mut multi_keys = MultiAddedRemovedKeys::new();
190 let mut update = HashedPostState::default();
191
192 let addr = B256::random();
193
194 let account = Account { balance: U256::from(1000), nonce: 0, bytecode_hash: None };
196 update.accounts.insert(addr, Some(account));
197
198 let storage = HashedStorage::default();
200 update.storages.insert(addr, storage);
201
202 multi_keys.update_with_state(&update);
203
204 assert!(!multi_keys.get_accounts().is_removed(&addr));
206
207 let mut update2 = HashedPostState::default();
209 let wiped_storage = HashedStorage::new(true);
210 update2.storages.insert(addr, wiped_storage);
211 update2.accounts.insert(addr, Some(account));
212 multi_keys.update_with_state(&update2);
213
214 assert!(multi_keys.get_storage(&addr).is_none());
216 assert!(!multi_keys.get_accounts().is_removed(&addr));
217 }
218}