1use super::{
2 plain_account::PlainStorage, AccountStatus, BundleAccount, PlainAccount,
3 StorageWithOriginalValues, TransitionAccount,
4};
5use primitives::{HashMap, U256};
6use state::AccountInfo;
7
8#[derive(Clone, Debug, PartialEq, Eq)]
11pub struct CacheAccount {
12 pub account: Option<PlainAccount>,
13 pub status: AccountStatus,
14}
15
16impl From<BundleAccount> for CacheAccount {
17 fn from(account: BundleAccount) -> Self {
18 let storage = account
19 .storage
20 .iter()
21 .map(|(k, v)| (*k, v.present_value))
22 .collect();
23 let plain_account = account
24 .account_info()
25 .map(|info| PlainAccount { info, storage });
26 Self {
27 account: plain_account,
28 status: account.status,
29 }
30 }
31}
32
33impl CacheAccount {
34 pub fn new_loaded(info: AccountInfo, storage: PlainStorage) -> Self {
36 Self {
37 account: Some(PlainAccount { info, storage }),
38 status: AccountStatus::Loaded,
39 }
40 }
41
42 pub fn new_loaded_empty_eip161(storage: PlainStorage) -> Self {
44 Self {
45 account: Some(PlainAccount::new_empty_with_storage(storage)),
46 status: AccountStatus::LoadedEmptyEIP161,
47 }
48 }
49
50 pub fn new_loaded_not_existing() -> Self {
52 Self {
53 account: None,
54 status: AccountStatus::LoadedNotExisting,
55 }
56 }
57
58 pub fn new_newly_created(info: AccountInfo, storage: PlainStorage) -> Self {
60 Self {
61 account: Some(PlainAccount { info, storage }),
62 status: AccountStatus::InMemoryChange,
63 }
64 }
65
66 pub fn new_destroyed() -> Self {
68 Self {
69 account: None,
70 status: AccountStatus::Destroyed,
71 }
72 }
73
74 pub fn new_changed(info: AccountInfo, storage: PlainStorage) -> Self {
76 Self {
77 account: Some(PlainAccount { info, storage }),
78 status: AccountStatus::Changed,
79 }
80 }
81
82 pub fn is_some(&self) -> bool {
84 matches!(
85 self.status,
86 AccountStatus::Changed
87 | AccountStatus::InMemoryChange
88 | AccountStatus::DestroyedChanged
89 | AccountStatus::Loaded
90 | AccountStatus::LoadedEmptyEIP161
91 )
92 }
93
94 pub fn storage_slot(&self, slot: U256) -> Option<U256> {
96 self.account
97 .as_ref()
98 .and_then(|a| a.storage.get(&slot).cloned())
99 }
100
101 pub fn account_info(&self) -> Option<AccountInfo> {
103 self.account.as_ref().map(|a| a.info.clone())
104 }
105
106 pub fn into_components(self) -> (Option<(AccountInfo, PlainStorage)>, AccountStatus) {
108 (self.account.map(|a| a.into_components()), self.status)
109 }
110
111 pub fn touch_create_pre_eip161(
113 &mut self,
114 storage: StorageWithOriginalValues,
115 ) -> Option<TransitionAccount> {
116 let previous_status = self.status;
117
118 let had_no_info = self
119 .account
120 .as_ref()
121 .map(|a| a.info.is_empty())
122 .unwrap_or_default();
123 self.status = self.status.on_touched_created_pre_eip161(had_no_info)?;
124
125 let plain_storage = storage.iter().map(|(k, v)| (*k, v.present_value)).collect();
126 let previous_info = self.account.take().map(|a| a.info);
127
128 self.account = Some(PlainAccount::new_empty_with_storage(plain_storage));
129
130 Some(TransitionAccount {
131 info: Some(AccountInfo::default()),
132 status: self.status,
133 previous_info,
134 previous_status,
135 storage,
136 storage_was_destroyed: false,
137 })
138 }
139
140 pub fn touch_empty_eip161(&mut self) -> Option<TransitionAccount> {
144 let previous_status = self.status;
145
146 let previous_info = self.account.take().map(|acc| acc.info);
148
149 self.status = self.status.on_touched_empty_post_eip161();
151
152 if matches!(
153 previous_status,
154 AccountStatus::LoadedNotExisting
155 | AccountStatus::Destroyed
156 | AccountStatus::DestroyedAgain
157 ) {
158 None
159 } else {
160 Some(TransitionAccount {
161 info: None,
162 status: self.status,
163 previous_info,
164 previous_status,
165 storage: HashMap::default(),
166 storage_was_destroyed: true,
167 })
168 }
169 }
170
171 pub fn selfdestruct(&mut self) -> Option<TransitionAccount> {
175 let previous_info = self.account.take().map(|a| a.info);
177 let previous_status = self.status;
178
179 self.status = self.status.on_selfdestructed();
180
181 if previous_status == AccountStatus::LoadedNotExisting {
182 None
183 } else {
184 Some(TransitionAccount {
185 info: None,
186 status: self.status,
187 previous_info,
188 previous_status,
189 storage: HashMap::default(),
190 storage_was_destroyed: true,
191 })
192 }
193 }
194
195 pub fn newly_created(
197 &mut self,
198 new_info: AccountInfo,
199 new_storage: StorageWithOriginalValues,
200 ) -> TransitionAccount {
201 let previous_status = self.status;
202 let previous_info = self.account.take().map(|a| a.info);
203
204 let new_bundle_storage = new_storage
205 .iter()
206 .map(|(k, s)| (*k, s.present_value))
207 .collect();
208
209 self.status = self.status.on_created();
210 let transition_account = TransitionAccount {
211 info: Some(new_info.clone()),
212 status: self.status,
213 previous_status,
214 previous_info,
215 storage: new_storage,
216 storage_was_destroyed: false,
217 };
218 self.account = Some(PlainAccount {
219 info: new_info,
220 storage: new_bundle_storage,
221 });
222 transition_account
223 }
224
225 pub fn increment_balance(&mut self, balance: u128) -> Option<TransitionAccount> {
230 if balance == 0 {
231 return None;
232 }
233 let (_, transition) = self.account_info_change(|info| {
234 info.balance = info.balance.saturating_add(U256::from(balance));
235 });
236 Some(transition)
237 }
238
239 fn account_info_change<T, F: FnOnce(&mut AccountInfo) -> T>(
240 &mut self,
241 change: F,
242 ) -> (T, TransitionAccount) {
243 let previous_status = self.status;
244 let previous_info = self.account_info();
245 let mut account = self.account.take().unwrap_or_default();
246 let output = change(&mut account.info);
247 self.account = Some(account);
248
249 let had_no_nonce_and_code = previous_info
250 .as_ref()
251 .map(AccountInfo::has_no_code_and_nonce)
252 .unwrap_or_default();
253 self.status = self.status.on_changed(had_no_nonce_and_code);
254
255 (
256 output,
257 TransitionAccount {
258 info: self.account_info(),
259 status: self.status,
260 previous_info,
261 previous_status,
262 storage: HashMap::default(),
263 storage_was_destroyed: false,
264 },
265 )
266 }
267
268 pub fn drain_balance(&mut self) -> (u128, TransitionAccount) {
272 self.account_info_change(|info| {
273 let output = info.balance;
274 info.balance = U256::ZERO;
275 output.try_into().unwrap()
276 })
277 }
278
279 pub fn change(
283 &mut self,
284 new: AccountInfo,
285 storage: StorageWithOriginalValues,
286 ) -> TransitionAccount {
287 let previous_status = self.status;
288 let (previous_info, mut this_storage) = if let Some(account) = self.account.take() {
289 (Some(account.info), account.storage)
290 } else {
291 (None, Default::default())
292 };
293
294 this_storage.extend(storage.iter().map(|(k, s)| (*k, s.present_value)));
295 let changed_account = PlainAccount {
296 info: new,
297 storage: this_storage,
298 };
299
300 let had_no_nonce_and_code = previous_info
301 .as_ref()
302 .map(AccountInfo::has_no_code_and_nonce)
303 .unwrap_or_default();
304 self.status = self.status.on_changed(had_no_nonce_and_code);
305 self.account = Some(changed_account);
306
307 TransitionAccount {
308 info: self.account.as_ref().map(|a| a.info.clone()),
309 status: self.status,
310 previous_info,
311 previous_status,
312 storage,
313 storage_was_destroyed: false,
314 }
315 }
316}