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, StorageKey, StorageValue};
18
19#[derive(Debug, Clone, PartialEq, Eq, Default)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Account {
23 pub info: AccountInfo,
25 pub transaction_id: usize,
27 pub storage: EvmStorage,
29 pub status: AccountStatus,
31}
32
33impl Account {
34 pub fn new_not_existing(transaction_id: usize) -> Self {
36 Self {
37 info: AccountInfo::default(),
38 storage: HashMap::default(),
39 transaction_id,
40 status: AccountStatus::LoadedAsNotExisting,
41 }
42 }
43
44 #[inline]
46 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
47 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
48 self.is_empty()
49 } else {
50 self.is_loaded_as_not_existing_not_touched()
51 }
52 }
53
54 pub fn mark_selfdestruct(&mut self) {
56 self.status |= AccountStatus::SelfDestructed;
57 }
58
59 pub fn unmark_selfdestruct(&mut self) {
61 self.status -= AccountStatus::SelfDestructed;
62 }
63
64 pub fn is_selfdestructed(&self) -> bool {
66 self.status.contains(AccountStatus::SelfDestructed)
67 }
68
69 pub fn mark_touch(&mut self) {
71 self.status |= AccountStatus::Touched;
72 }
73
74 pub fn unmark_touch(&mut self) {
76 self.status -= AccountStatus::Touched;
77 }
78
79 pub fn is_touched(&self) -> bool {
81 self.status.contains(AccountStatus::Touched)
82 }
83
84 pub fn mark_created(&mut self) {
86 self.status |= AccountStatus::Created;
87 }
88
89 pub fn unmark_created(&mut self) {
91 self.status -= AccountStatus::Created;
92 }
93
94 pub fn mark_cold(&mut self) {
96 self.status |= AccountStatus::Cold;
97 }
98
99 #[inline]
101 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
102 let same_id = self.transaction_id == transaction_id;
103 let is_cold = self.status.contains(AccountStatus::Cold);
104
105 self.status -= AccountStatus::Cold;
106 self.transaction_id = transaction_id;
107
108 if !same_id {
109 return true;
110 }
111
112 is_cold
113 }
114
115 #[inline]
117 pub fn is_created_locally(&self) -> bool {
118 self.status.contains(AccountStatus::CreatedLocal)
119 }
120
121 #[inline]
123 pub fn is_selfdestructed_locally(&self) -> bool {
124 self.status.contains(AccountStatus::SelfDestructedLocal)
125 }
126
127 #[inline]
129 pub fn selfdestruct(&mut self) {
130 self.storage.clear();
131 self.info = AccountInfo::default();
132 }
133
134 #[inline]
138 pub fn mark_created_locally(&mut self) -> bool {
139 self.status |= AccountStatus::CreatedLocal;
140 let is_created_globaly = !self.status.contains(AccountStatus::Created);
141 self.status |= AccountStatus::Created;
142 is_created_globaly
143 }
144
145 #[inline]
147 pub fn unmark_created_locally(&mut self) {
148 self.status -= AccountStatus::CreatedLocal;
149 }
150
151 #[inline]
153 pub fn mark_selfdestructed_locally(&mut self) -> bool {
154 self.status |= AccountStatus::SelfDestructedLocal;
155 let is_global_selfdestructed = !self.status.contains(AccountStatus::SelfDestructed);
156 self.status |= AccountStatus::SelfDestructed;
157 is_global_selfdestructed
158 }
159
160 #[inline]
162 pub fn unmark_selfdestructed_locally(&mut self) {
163 self.status -= AccountStatus::SelfDestructedLocal;
164 }
165
166 pub fn is_loaded_as_not_existing(&self) -> bool {
171 self.status.contains(AccountStatus::LoadedAsNotExisting)
172 }
173
174 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
176 self.is_loaded_as_not_existing() && !self.is_touched()
177 }
178
179 pub fn is_created(&self) -> bool {
181 self.status.contains(AccountStatus::Created)
182 }
183
184 pub fn is_empty(&self) -> bool {
186 self.info.is_empty()
187 }
188
189 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
193 self.storage.iter().filter(|(_, slot)| slot.is_changed())
194 }
195
196 pub fn with_info(mut self, info: AccountInfo) -> Self {
198 self.info = info;
199 self
200 }
201
202 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
204 where
205 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
206 {
207 for (key, slot) in storage_iter {
208 self.storage.insert(key, slot);
209 }
210 self
211 }
212
213 pub fn with_selfdestruct_mark(mut self) -> Self {
215 self.mark_selfdestruct();
216 self
217 }
218
219 pub fn with_touched_mark(mut self) -> Self {
221 self.mark_touch();
222 self
223 }
224
225 pub fn with_created_mark(mut self) -> Self {
227 self.mark_created();
228 self
229 }
230
231 pub fn with_cold_mark(mut self) -> Self {
233 self.mark_cold();
234 self
235 }
236
237 pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) {
240 let was_cold = self.mark_warm_with_transaction_id(transaction_id);
241 (self, was_cold)
242 }
243
244 pub fn with_warm(mut self, transaction_id: usize) -> Self {
246 self.mark_warm_with_transaction_id(transaction_id);
247 self
248 }
249}
250
251impl From<AccountInfo> for Account {
252 fn from(info: AccountInfo) -> Self {
253 Self {
254 info,
255 storage: HashMap::default(),
256 transaction_id: 0,
257 status: AccountStatus::empty(),
258 }
259 }
260}
261
262bitflags! {
264 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
296 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
297 #[cfg_attr(feature = "serde", serde(transparent))]
298 pub struct AccountStatus: u8 {
299 const Created = 0b00000001;
302 const CreatedLocal = 0b10000000;
304 const SelfDestructed = 0b00000010;
306 const SelfDestructedLocal = 0b01000000;
308 const Touched = 0b00000100;
312 const LoadedAsNotExisting = 0b00001000;
315 const Cold = 0b00010000;
318 }
319}
320
321impl Default for AccountStatus {
322 fn default() -> Self {
323 AccountStatus::empty()
324 }
325}
326
327#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
329#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
330pub struct EvmStorageSlot {
331 pub original_value: StorageValue,
333 pub present_value: StorageValue,
335 pub transaction_id: usize,
337 pub is_cold: bool,
339}
340
341impl EvmStorageSlot {
342 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
344 Self {
345 original_value: original,
346 present_value: original,
347 transaction_id,
348 is_cold: false,
349 }
350 }
351
352 pub fn new_changed(
354 original_value: StorageValue,
355 present_value: StorageValue,
356 transaction_id: usize,
357 ) -> Self {
358 Self {
359 original_value,
360 present_value,
361 transaction_id,
362 is_cold: false,
363 }
364 }
365 pub fn is_changed(&self) -> bool {
367 self.original_value != self.present_value
368 }
369
370 #[inline]
372 pub fn original_value(&self) -> StorageValue {
373 self.original_value
374 }
375
376 #[inline]
378 pub fn present_value(&self) -> StorageValue {
379 self.present_value
380 }
381
382 #[inline]
384 pub fn mark_cold(&mut self) {
385 self.is_cold = true;
386 }
387
388 #[inline]
393 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
394 let same_id = self.transaction_id == transaction_id;
395 self.transaction_id = transaction_id;
396 let was_cold = core::mem::replace(&mut self.is_cold, false);
397
398 if same_id {
399 return was_cold;
401 }
402 true
403 }
404}
405
406#[cfg(test)]
407mod tests {
408 use super::*;
409 use crate::EvmStorageSlot;
410 use primitives::{StorageKey, KECCAK_EMPTY, U256};
411
412 #[test]
413 fn account_is_empty_balance() {
414 let mut account = Account::default();
415 assert!(account.is_empty());
416
417 account.info.balance = U256::from(1);
418 assert!(!account.is_empty());
419
420 account.info.balance = U256::ZERO;
421 assert!(account.is_empty());
422 }
423
424 #[test]
425 fn account_is_empty_nonce() {
426 let mut account = Account::default();
427 assert!(account.is_empty());
428
429 account.info.nonce = 1;
430 assert!(!account.is_empty());
431
432 account.info.nonce = 0;
433 assert!(account.is_empty());
434 }
435
436 #[test]
437 fn account_is_empty_code_hash() {
438 let mut account = Account::default();
439 assert!(account.is_empty());
440
441 account.info.code_hash = [1; 32].into();
442 assert!(!account.is_empty());
443
444 account.info.code_hash = [0; 32].into();
445 assert!(account.is_empty());
446
447 account.info.code_hash = KECCAK_EMPTY;
448 assert!(account.is_empty());
449 }
450
451 #[test]
452 fn account_state() {
453 let mut account = Account::default();
454
455 assert!(!account.is_touched());
456 assert!(!account.is_selfdestructed());
457
458 account.mark_touch();
459 assert!(account.is_touched());
460 assert!(!account.is_selfdestructed());
461
462 account.mark_selfdestruct();
463 assert!(account.is_touched());
464 assert!(account.is_selfdestructed());
465
466 account.unmark_selfdestruct();
467 assert!(account.is_touched());
468 assert!(!account.is_selfdestructed());
469 }
470
471 #[test]
472 fn account_is_cold() {
473 let mut account = Account::default();
474
475 assert!(!account.status.contains(crate::AccountStatus::Cold));
477
478 assert!(!account.mark_warm_with_transaction_id(0));
480
481 account.mark_cold();
483
484 assert!(account.status.contains(crate::AccountStatus::Cold));
486
487 assert!(account.mark_warm_with_transaction_id(0));
489 }
490
491 #[test]
492 fn test_account_with_info() {
493 let info = AccountInfo::default();
494 let account = Account::default().with_info(info.clone());
495
496 assert_eq!(account.info, info);
497 assert_eq!(account.storage, HashMap::default());
498 assert_eq!(account.status, AccountStatus::empty());
499 }
500
501 #[test]
502 fn test_account_with_storage() {
503 let mut storage = HashMap::new();
504 let key1 = StorageKey::from(1);
505 let key2 = StorageKey::from(2);
506 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
507 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
508
509 storage.insert(key1, slot1.clone());
510 storage.insert(key2, slot2.clone());
511
512 let account = Account::default().with_storage(storage.clone().into_iter());
513
514 assert_eq!(account.storage.len(), 2);
515 assert_eq!(account.storage.get(&key1), Some(&slot1));
516 assert_eq!(account.storage.get(&key2), Some(&slot2));
517 }
518
519 #[test]
520 fn test_account_with_selfdestruct_mark() {
521 let account = Account::default().with_selfdestruct_mark();
522
523 assert!(account.is_selfdestructed());
524 assert!(!account.is_touched());
525 assert!(!account.is_created());
526 }
527
528 #[test]
529 fn test_account_with_touched_mark() {
530 let account = Account::default().with_touched_mark();
531
532 assert!(!account.is_selfdestructed());
533 assert!(account.is_touched());
534 assert!(!account.is_created());
535 }
536
537 #[test]
538 fn test_account_with_created_mark() {
539 let account = Account::default().with_created_mark();
540
541 assert!(!account.is_selfdestructed());
542 assert!(!account.is_touched());
543 assert!(account.is_created());
544 }
545
546 #[test]
547 fn test_account_with_cold_mark() {
548 let account = Account::default().with_cold_mark();
549
550 assert!(account.status.contains(AccountStatus::Cold));
551 }
552
553 #[test]
554 fn test_storage_mark_warm_with_transaction_id() {
555 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
556 slot.is_cold = true;
557 slot.transaction_id = 0;
558 assert!(slot.mark_warm_with_transaction_id(1));
559
560 slot.is_cold = false;
561 slot.transaction_id = 0;
562 assert!(slot.mark_warm_with_transaction_id(1));
563
564 slot.is_cold = true;
565 slot.transaction_id = 1;
566 assert!(slot.mark_warm_with_transaction_id(1));
567
568 slot.is_cold = false;
569 slot.transaction_id = 1;
570 assert!(!slot.mark_warm_with_transaction_id(1));
572 }
573
574 #[test]
575 fn test_account_with_warm_mark() {
576 let cold_account = Account::default().with_cold_mark();
578 assert!(cold_account.status.contains(AccountStatus::Cold));
579
580 let (warm_account, was_cold) = cold_account.with_warm_mark(0);
582
583 assert!(!warm_account.status.contains(AccountStatus::Cold));
585 assert!(was_cold);
586
587 let (still_warm_account, was_cold) = warm_account.with_warm_mark(0);
589 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
590 assert!(!was_cold);
591 }
592
593 #[test]
594 fn test_account_with_warm() {
595 let cold_account = Account::default().with_cold_mark();
597 assert!(cold_account.status.contains(AccountStatus::Cold));
598
599 let warm_account = cold_account.with_warm(0);
601
602 assert!(!warm_account.status.contains(AccountStatus::Cold));
604 }
605
606 #[test]
607 fn test_account_builder_chaining() {
608 let info = AccountInfo {
609 nonce: 5,
610 ..AccountInfo::default()
611 };
612
613 let slot_key = StorageKey::from(42);
614 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
615 let mut storage = HashMap::new();
616 storage.insert(slot_key, slot_value.clone());
617
618 let account = Account::default()
620 .with_info(info.clone())
621 .with_storage(storage.into_iter())
622 .with_created_mark()
623 .with_touched_mark()
624 .with_cold_mark()
625 .with_warm(0);
626
627 assert_eq!(account.info, info);
629 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
630 assert!(account.is_created());
631 assert!(account.is_touched());
632 assert!(!account.status.contains(AccountStatus::Cold));
633 }
634}