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 pub account: AddedRemovedKeys,
12 pub storages: B256Map<AddedRemovedKeys>,
14}
15
16fn default_added_removed_keys() -> AddedRemovedKeys {
19 AddedRemovedKeys::default().with_assume_added(true)
20}
21
22impl Default for MultiAddedRemovedKeys {
23 fn default() -> Self {
24 Self::new()
25 }
26}
27
28impl MultiAddedRemovedKeys {
29 pub fn new() -> Self {
31 Self { account: default_added_removed_keys(), storages: Default::default() }
32 }
33
34 pub fn update_with_state(&mut self, update: &HashedPostState) {
40 for (hashed_address, storage) in &update.storages {
41 let account = update
42 .accounts
43 .get(hashed_address)
44 .map(|entry| entry.unwrap_or_default())
45 .unwrap_or_default();
46
47 if storage.wiped {
48 self.storages.remove(hashed_address);
49 if account.is_empty() {
50 self.account.insert_removed(*hashed_address);
51 }
52 continue
53 }
54
55 let storage_removed_keys =
56 self.storages.entry(*hashed_address).or_insert_with(default_added_removed_keys);
57
58 for (key, val) in &storage.storage {
59 if val.is_zero() {
60 storage_removed_keys.insert_removed(*key);
61 } else {
62 storage_removed_keys.remove_removed(key);
63 }
64 }
65
66 if !account.is_empty() {
67 self.account.remove_removed(hashed_address);
68 }
69 }
70 }
71
72 pub fn get_storage(&self, hashed_address: &B256) -> Option<&AddedRemovedKeys> {
74 self.storages.get(hashed_address)
75 }
76
77 pub const fn get_accounts(&self) -> &AddedRemovedKeys {
79 &self.account
80 }
81
82 pub fn touch_accounts(&mut self, addresses: impl Iterator<Item = B256>) {
84 for address in addresses {
85 self.storages.entry(address).or_insert_with(default_added_removed_keys);
86 }
87 }
88}
89
90#[cfg(test)]
91mod tests {
92 use super::*;
93 use crate::HashedStorage;
94 use alloy_primitives::U256;
95 use reth_primitives_traits::Account;
96
97 #[test]
98 fn test_update_with_state_storage_keys_non_zero() {
99 let mut multi_keys = MultiAddedRemovedKeys::new();
100 let mut update = HashedPostState::default();
101
102 let addr = B256::random();
103 let slot1 = B256::random();
104 let slot2 = B256::random();
105
106 let mut storage = HashedStorage::default();
108 storage.storage.insert(slot1, U256::ZERO);
109 storage.storage.insert(slot2, U256::ZERO);
110 update.storages.insert(addr, storage);
111 multi_keys.update_with_state(&update);
112
113 assert!(multi_keys.get_storage(&addr).unwrap().is_removed(&slot1));
115 assert!(multi_keys.get_storage(&addr).unwrap().is_removed(&slot2));
116
117 let mut update2 = HashedPostState::default();
119 let mut storage2 = HashedStorage::default();
120 storage2.storage.insert(slot1, U256::from(100));
121 storage2.storage.insert(slot2, U256::from(200));
122 update2.storages.insert(addr, storage2);
123 multi_keys.update_with_state(&update2);
124
125 let storage_keys = multi_keys.get_storage(&addr).unwrap();
127 assert!(!storage_keys.is_removed(&slot1));
128 assert!(!storage_keys.is_removed(&slot2));
129 }
130
131 #[test]
132 fn test_update_with_state_wiped_storage() {
133 let mut multi_keys = MultiAddedRemovedKeys::new();
134 let mut update = HashedPostState::default();
135
136 let addr = B256::random();
137 let slot1 = B256::random();
138
139 let mut storage = HashedStorage::default();
141 storage.storage.insert(slot1, U256::ZERO);
142 update.storages.insert(addr, storage);
143 multi_keys.update_with_state(&update);
144 assert!(multi_keys.get_storage(&addr).is_some());
145
146 let mut update2 = HashedPostState::default();
148 let wiped_storage = HashedStorage::new(true);
149 update2.storages.insert(addr, wiped_storage);
150 multi_keys.update_with_state(&update2);
151
152 assert!(multi_keys.get_storage(&addr).is_none());
154 assert!(multi_keys.get_accounts().is_removed(&addr));
155 }
156
157 #[test]
158 fn test_update_with_state_account_tracking() {
159 let mut multi_keys = MultiAddedRemovedKeys::new();
160 let mut update = HashedPostState::default();
161
162 let addr = B256::random();
163 let slot = B256::random();
164
165 let mut storage = HashedStorage::default();
167 storage.storage.insert(slot, U256::ZERO);
168 update.storages.insert(addr, storage);
169 multi_keys.update_with_state(&update);
172
173 assert!(multi_keys.get_storage(&addr).unwrap().is_removed(&slot));
175 assert!(!multi_keys.get_accounts().is_removed(&addr));
176
177 let mut update2 = HashedPostState::default();
179 let mut storage2 = HashedStorage::default();
180 storage2.storage.insert(slot, U256::from(100)); update2.storages.insert(addr, storage2);
182
183 multi_keys.update_with_state(&update2);
184
185 assert!(!multi_keys.get_accounts().is_removed(&addr));
187 }
188
189 #[test]
190 fn test_update_with_state_account_with_balance() {
191 let mut multi_keys = MultiAddedRemovedKeys::new();
192 let mut update = HashedPostState::default();
193
194 let addr = B256::random();
195
196 let account = Account { balance: U256::from(1000), nonce: 0, bytecode_hash: None };
198 update.accounts.insert(addr, Some(account));
199
200 let storage = HashedStorage::default();
202 update.storages.insert(addr, storage);
203
204 multi_keys.update_with_state(&update);
205
206 assert!(!multi_keys.get_accounts().is_removed(&addr));
208
209 let mut update2 = HashedPostState::default();
211 let wiped_storage = HashedStorage::new(true);
212 update2.storages.insert(addr, wiped_storage);
213 update2.accounts.insert(addr, Some(account));
214 multi_keys.update_with_state(&update2);
215
216 assert!(multi_keys.get_storage(&addr).is_none());
218 assert!(!multi_keys.get_accounts().is_removed(&addr));
219 }
220}