1#![cfg_attr(not(test), warn(unused_crate_dependencies))]
3#![cfg_attr(not(feature = "std"), no_std)]
4
5mod account_info;
6mod types;
7pub use bytecode;
8
9pub use account_info::AccountInfo;
10pub use bytecode::Bytecode;
11pub use primitives;
12pub use types::{EvmState, EvmStorage, TransientStorage};
13
14use bitflags::bitflags;
15use core::hash::Hash;
16use primitives::hardfork::SpecId;
17use primitives::{HashMap, U256};
18
19#[derive(Debug, Clone, PartialEq, Eq, Default)]
20#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
21pub struct Account {
22 pub info: AccountInfo,
24 pub storage: EvmStorage,
26 pub status: AccountStatus,
28}
29
30impl Account {
31 pub fn new_not_existing() -> Self {
33 Self {
34 info: AccountInfo::default(),
35 storage: HashMap::default(),
36 status: AccountStatus::LoadedAsNotExisting,
37 }
38 }
39
40 #[inline]
42 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
43 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
44 self.is_empty()
45 } else {
46 let loaded_not_existing = self.is_loaded_as_not_existing();
47 let is_not_touched = !self.is_touched();
48 loaded_not_existing && is_not_touched
49 }
50 }
51
52 pub fn mark_selfdestruct(&mut self) {
54 self.status |= AccountStatus::SelfDestructed;
55 }
56
57 pub fn unmark_selfdestruct(&mut self) {
59 self.status -= AccountStatus::SelfDestructed;
60 }
61
62 pub fn is_selfdestructed(&self) -> bool {
64 self.status.contains(AccountStatus::SelfDestructed)
65 }
66
67 pub fn mark_touch(&mut self) {
69 self.status |= AccountStatus::Touched;
70 }
71
72 pub fn unmark_touch(&mut self) {
74 self.status -= AccountStatus::Touched;
75 }
76
77 pub fn is_touched(&self) -> bool {
79 self.status.contains(AccountStatus::Touched)
80 }
81
82 pub fn mark_created(&mut self) {
84 self.status |= AccountStatus::Created;
85 }
86
87 pub fn unmark_created(&mut self) {
89 self.status -= AccountStatus::Created;
90 }
91
92 pub fn mark_cold(&mut self) {
94 self.status |= AccountStatus::Cold;
95 }
96
97 pub fn mark_warm(&mut self) -> bool {
99 if self.status.contains(AccountStatus::Cold) {
100 self.status -= AccountStatus::Cold;
101 true
102 } else {
103 false
104 }
105 }
106
107 pub fn is_loaded_as_not_existing(&self) -> bool {
112 self.status.contains(AccountStatus::LoadedAsNotExisting)
113 }
114
115 pub fn is_created(&self) -> bool {
117 self.status.contains(AccountStatus::Created)
118 }
119
120 pub fn is_empty(&self) -> bool {
122 self.info.is_empty()
123 }
124
125 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&U256, &EvmStorageSlot)> {
129 self.storage.iter().filter(|(_, slot)| slot.is_changed())
130 }
131
132 pub fn with_info(mut self, info: AccountInfo) -> Self {
134 self.info = info;
135 self
136 }
137
138 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
140 where
141 I: Iterator<Item = (U256, EvmStorageSlot)>,
142 {
143 for (key, slot) in storage_iter {
144 self.storage.insert(key, slot);
145 }
146 self
147 }
148
149 pub fn with_selfdestruct_mark(mut self) -> Self {
151 self.mark_selfdestruct();
152 self
153 }
154
155 pub fn with_touched_mark(mut self) -> Self {
157 self.mark_touch();
158 self
159 }
160
161 pub fn with_created_mark(mut self) -> Self {
163 self.mark_created();
164 self
165 }
166
167 pub fn with_cold_mark(mut self) -> Self {
169 self.mark_cold();
170 self
171 }
172
173 pub fn with_warm_mark(mut self) -> (Self, bool) {
176 let was_cold = self.mark_warm();
177 (self, was_cold)
178 }
179
180 pub fn with_warm(mut self) -> Self {
182 self.mark_warm();
183 self
184 }
185}
186
187impl From<AccountInfo> for Account {
188 fn from(info: AccountInfo) -> Self {
189 Self {
190 info,
191 storage: HashMap::default(),
192 status: AccountStatus::Loaded,
193 }
194 }
195}
196
197bitflags! {
199 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
200 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
201 #[cfg_attr(feature = "serde", serde(transparent))]
202 pub struct AccountStatus: u8 {
203 const Loaded = 0b00000000;
206 const Created = 0b00000001;
209 const SelfDestructed = 0b00000010;
211 const Touched = 0b00000100;
213 const LoadedAsNotExisting = 0b0001000;
216 const Cold = 0b0010000;
218 }
219}
220
221impl Default for AccountStatus {
222 fn default() -> Self {
223 Self::Loaded
224 }
225}
226
227#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
229#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
230pub struct EvmStorageSlot {
231 pub original_value: U256,
233 pub present_value: U256,
235 pub is_cold: bool,
237}
238
239impl EvmStorageSlot {
240 pub fn new(original: U256) -> Self {
242 Self {
243 original_value: original,
244 present_value: original,
245 is_cold: false,
246 }
247 }
248
249 pub fn new_changed(original_value: U256, present_value: U256) -> Self {
251 Self {
252 original_value,
253 present_value,
254 is_cold: false,
255 }
256 }
257 pub fn is_changed(&self) -> bool {
259 self.original_value != self.present_value
260 }
261
262 pub fn original_value(&self) -> U256 {
264 self.original_value
265 }
266
267 pub fn present_value(&self) -> U256 {
269 self.present_value
270 }
271
272 pub fn mark_cold(&mut self) {
274 self.is_cold = true;
275 }
276
277 pub fn mark_warm(&mut self) -> bool {
279 core::mem::replace(&mut self.is_cold, false)
280 }
281}
282
283#[cfg(test)]
284mod tests {
285 use super::*;
286 use crate::EvmStorageSlot;
287 use primitives::KECCAK_EMPTY;
288
289 #[test]
290 fn account_is_empty_balance() {
291 let mut account = Account::default();
292 assert!(account.is_empty());
293
294 account.info.balance = U256::from(1);
295 assert!(!account.is_empty());
296
297 account.info.balance = U256::ZERO;
298 assert!(account.is_empty());
299 }
300
301 #[test]
302 fn account_is_empty_nonce() {
303 let mut account = Account::default();
304 assert!(account.is_empty());
305
306 account.info.nonce = 1;
307 assert!(!account.is_empty());
308
309 account.info.nonce = 0;
310 assert!(account.is_empty());
311 }
312
313 #[test]
314 fn account_is_empty_code_hash() {
315 let mut account = Account::default();
316 assert!(account.is_empty());
317
318 account.info.code_hash = [1; 32].into();
319 assert!(!account.is_empty());
320
321 account.info.code_hash = [0; 32].into();
322 assert!(account.is_empty());
323
324 account.info.code_hash = KECCAK_EMPTY;
325 assert!(account.is_empty());
326 }
327
328 #[test]
329 fn account_state() {
330 let mut account = Account::default();
331
332 assert!(!account.is_touched());
333 assert!(!account.is_selfdestructed());
334
335 account.mark_touch();
336 assert!(account.is_touched());
337 assert!(!account.is_selfdestructed());
338
339 account.mark_selfdestruct();
340 assert!(account.is_touched());
341 assert!(account.is_selfdestructed());
342
343 account.unmark_selfdestruct();
344 assert!(account.is_touched());
345 assert!(!account.is_selfdestructed());
346 }
347
348 #[test]
349 fn account_is_cold() {
350 let mut account = Account::default();
351
352 assert!(!account.status.contains(crate::AccountStatus::Cold));
354
355 assert!(!account.mark_warm());
357
358 account.mark_cold();
360
361 assert!(account.status.contains(crate::AccountStatus::Cold));
363
364 assert!(account.mark_warm());
366 }
367
368 #[test]
369 fn test_account_with_info() {
370 let info = AccountInfo::default();
371 let account = Account::default().with_info(info.clone());
372
373 assert_eq!(account.info, info);
374 assert_eq!(account.storage, HashMap::default());
375 assert_eq!(account.status, AccountStatus::Loaded);
376 }
377
378 #[test]
379 fn test_account_with_storage() {
380 let mut storage = HashMap::new();
381 let key1 = U256::from(1);
382 let key2 = U256::from(2);
383 let slot1 = EvmStorageSlot::new(U256::from(10));
384 let slot2 = EvmStorageSlot::new(U256::from(20));
385
386 storage.insert(key1, slot1.clone());
387 storage.insert(key2, slot2.clone());
388
389 let account = Account::default().with_storage(storage.clone().into_iter());
390
391 assert_eq!(account.storage.len(), 2);
392 assert_eq!(account.storage.get(&key1), Some(&slot1));
393 assert_eq!(account.storage.get(&key2), Some(&slot2));
394 }
395
396 #[test]
397 fn test_account_with_selfdestruct_mark() {
398 let account = Account::default().with_selfdestruct_mark();
399
400 assert!(account.is_selfdestructed());
401 assert!(!account.is_touched());
402 assert!(!account.is_created());
403 }
404
405 #[test]
406 fn test_account_with_touched_mark() {
407 let account = Account::default().with_touched_mark();
408
409 assert!(!account.is_selfdestructed());
410 assert!(account.is_touched());
411 assert!(!account.is_created());
412 }
413
414 #[test]
415 fn test_account_with_created_mark() {
416 let account = Account::default().with_created_mark();
417
418 assert!(!account.is_selfdestructed());
419 assert!(!account.is_touched());
420 assert!(account.is_created());
421 }
422
423 #[test]
424 fn test_account_with_cold_mark() {
425 let account = Account::default().with_cold_mark();
426
427 assert!(account.status.contains(AccountStatus::Cold));
428 }
429
430 #[test]
431 fn test_account_with_warm_mark() {
432 let cold_account = Account::default().with_cold_mark();
434 assert!(cold_account.status.contains(AccountStatus::Cold));
435
436 let (warm_account, was_cold) = cold_account.with_warm_mark();
438
439 assert!(!warm_account.status.contains(AccountStatus::Cold));
441 assert!(was_cold);
442
443 let (still_warm_account, was_cold) = warm_account.with_warm_mark();
445 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
446 assert!(!was_cold);
447 }
448
449 #[test]
450 fn test_account_with_warm() {
451 let cold_account = Account::default().with_cold_mark();
453 assert!(cold_account.status.contains(AccountStatus::Cold));
454
455 let warm_account = cold_account.with_warm();
457
458 assert!(!warm_account.status.contains(AccountStatus::Cold));
460 }
461
462 #[test]
463 fn test_account_builder_chaining() {
464 let info = AccountInfo {
465 nonce: 5,
466 ..AccountInfo::default()
467 };
468
469 let slot_key = U256::from(42);
470 let slot_value = EvmStorageSlot::new(U256::from(123));
471 let mut storage = HashMap::new();
472 storage.insert(slot_key, slot_value.clone());
473
474 let account = Account::default()
476 .with_info(info.clone())
477 .with_storage(storage.into_iter())
478 .with_created_mark()
479 .with_touched_mark()
480 .with_cold_mark()
481 .with_warm();
482
483 assert_eq!(account.info, info);
485 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
486 assert!(account.is_created());
487 assert!(account.is_touched());
488 assert!(!account.status.contains(AccountStatus::Cold));
489 }
490}