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 primitives::hardfork::SpecId;
16use primitives::{HashMap, StorageKey, StorageValue, U256};
17
18#[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 transaction_id: usize,
26 pub storage: EvmStorage,
28 pub status: AccountStatus,
30}
31
32impl Account {
33 pub fn new_not_existing(transaction_id: usize) -> Self {
35 Self {
36 info: AccountInfo::default(),
37 storage: HashMap::default(),
38 transaction_id,
39 status: AccountStatus::LoadedAsNotExisting,
40 }
41 }
42
43 #[inline]
49 pub fn caller_initial_modification(&mut self, new_balance: U256, is_call: bool) -> U256 {
50 self.mark_touch();
52
53 if is_call {
54 self.info.nonce = self.info.nonce.saturating_add(1);
56 }
57
58 core::mem::replace(&mut self.info.balance, new_balance)
59 }
60
61 #[inline]
63 pub fn state_clear_aware_is_empty(&self, spec: SpecId) -> bool {
64 if SpecId::is_enabled_in(spec, SpecId::SPURIOUS_DRAGON) {
65 self.is_empty()
66 } else {
67 self.is_loaded_as_not_existing_not_touched()
68 }
69 }
70
71 #[inline]
73 pub fn mark_selfdestruct(&mut self) {
74 self.status |= AccountStatus::SelfDestructed;
75 }
76
77 #[inline]
79 pub fn unmark_selfdestruct(&mut self) {
80 self.status -= AccountStatus::SelfDestructed;
81 }
82
83 #[inline]
85 pub fn is_selfdestructed(&self) -> bool {
86 self.status.contains(AccountStatus::SelfDestructed)
87 }
88
89 #[inline]
91 pub fn mark_touch(&mut self) {
92 self.status |= AccountStatus::Touched;
93 }
94
95 #[inline]
97 pub fn unmark_touch(&mut self) {
98 self.status -= AccountStatus::Touched;
99 }
100
101 #[inline]
103 pub fn is_touched(&self) -> bool {
104 self.status.contains(AccountStatus::Touched)
105 }
106
107 #[inline]
109 pub fn mark_created(&mut self) {
110 self.status |= AccountStatus::Created;
111 }
112
113 #[inline]
115 pub fn unmark_created(&mut self) {
116 self.status -= AccountStatus::Created;
117 }
118
119 #[inline]
121 pub fn mark_cold(&mut self) {
122 self.status |= AccountStatus::Cold;
123 }
124
125 #[inline]
127 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
128 self.transaction_id != transaction_id || self.status.contains(AccountStatus::Cold)
129 }
130
131 #[inline]
133 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
134 let is_cold = self.is_cold_transaction_id(transaction_id);
135 self.status -= AccountStatus::Cold;
136 self.transaction_id = transaction_id;
137 is_cold
138 }
139
140 #[inline]
142 pub fn is_created_locally(&self) -> bool {
143 self.status.contains(AccountStatus::CreatedLocal)
144 }
145
146 #[inline]
148 pub fn is_selfdestructed_locally(&self) -> bool {
149 self.status.contains(AccountStatus::SelfDestructedLocal)
150 }
151
152 #[inline]
154 pub fn selfdestruct(&mut self) {
155 self.storage.clear();
156 self.info = AccountInfo::default();
157 }
158
159 #[inline]
163 pub fn mark_created_locally(&mut self) -> bool {
164 self.status |= AccountStatus::CreatedLocal;
165 let is_created_globaly = !self.status.contains(AccountStatus::Created);
166 self.status |= AccountStatus::Created;
167 is_created_globaly
168 }
169
170 #[inline]
172 pub fn unmark_created_locally(&mut self) {
173 self.status -= AccountStatus::CreatedLocal;
174 }
175
176 #[inline]
178 pub fn mark_selfdestructed_locally(&mut self) -> bool {
179 self.status |= AccountStatus::SelfDestructedLocal;
180 let is_global_selfdestructed = !self.status.contains(AccountStatus::SelfDestructed);
181 self.status |= AccountStatus::SelfDestructed;
182 is_global_selfdestructed
183 }
184
185 #[inline]
187 pub fn unmark_selfdestructed_locally(&mut self) {
188 self.status -= AccountStatus::SelfDestructedLocal;
189 }
190
191 pub fn is_loaded_as_not_existing(&self) -> bool {
196 self.status.contains(AccountStatus::LoadedAsNotExisting)
197 }
198
199 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
201 self.is_loaded_as_not_existing() && !self.is_touched()
202 }
203
204 pub fn is_created(&self) -> bool {
206 self.status.contains(AccountStatus::Created)
207 }
208
209 pub fn is_empty(&self) -> bool {
211 self.info.is_empty()
212 }
213
214 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
218 self.storage.iter().filter(|(_, slot)| slot.is_changed())
219 }
220
221 pub fn with_info(mut self, info: AccountInfo) -> Self {
223 self.info = info;
224 self
225 }
226
227 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
229 where
230 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
231 {
232 for (key, slot) in storage_iter {
233 self.storage.insert(key, slot);
234 }
235 self
236 }
237
238 pub fn with_selfdestruct_mark(mut self) -> Self {
240 self.mark_selfdestruct();
241 self
242 }
243
244 pub fn with_touched_mark(mut self) -> Self {
246 self.mark_touch();
247 self
248 }
249
250 pub fn with_created_mark(mut self) -> Self {
252 self.mark_created();
253 self
254 }
255
256 pub fn with_cold_mark(mut self) -> Self {
258 self.mark_cold();
259 self
260 }
261
262 pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) {
265 let was_cold = self.mark_warm_with_transaction_id(transaction_id);
266 (self, was_cold)
267 }
268
269 pub fn with_warm(mut self, transaction_id: usize) -> Self {
271 self.mark_warm_with_transaction_id(transaction_id);
272 self
273 }
274}
275
276impl From<AccountInfo> for Account {
277 fn from(info: AccountInfo) -> Self {
278 Self {
279 info,
280 storage: HashMap::default(),
281 transaction_id: 0,
282 status: AccountStatus::empty(),
283 }
284 }
285}
286
287bitflags! {
289 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
321 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
322 #[cfg_attr(feature = "serde", serde(transparent))]
323 pub struct AccountStatus: u8 {
324 const Created = 0b00000001;
327 const CreatedLocal = 0b10000000;
329 const SelfDestructed = 0b00000010;
331 const SelfDestructedLocal = 0b01000000;
333 const Touched = 0b00000100;
337 const LoadedAsNotExisting = 0b00001000;
340 const Cold = 0b00010000;
343 }
344}
345
346impl AccountStatus {
347 #[inline]
349 pub fn is_touched(&self) -> bool {
350 self.contains(AccountStatus::Touched)
351 }
352}
353
354impl Default for AccountStatus {
355 fn default() -> Self {
356 AccountStatus::empty()
357 }
358}
359
360#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
362#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
363pub struct EvmStorageSlot {
364 pub original_value: StorageValue,
366 pub present_value: StorageValue,
368 pub transaction_id: usize,
370 pub is_cold: bool,
372}
373
374impl EvmStorageSlot {
375 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
377 Self {
378 original_value: original,
379 present_value: original,
380 transaction_id,
381 is_cold: false,
382 }
383 }
384
385 pub fn new_changed(
387 original_value: StorageValue,
388 present_value: StorageValue,
389 transaction_id: usize,
390 ) -> Self {
391 Self {
392 original_value,
393 present_value,
394 transaction_id,
395 is_cold: false,
396 }
397 }
398 pub fn is_changed(&self) -> bool {
400 self.original_value != self.present_value
401 }
402
403 #[inline]
405 pub fn original_value(&self) -> StorageValue {
406 self.original_value
407 }
408
409 #[inline]
411 pub fn present_value(&self) -> StorageValue {
412 self.present_value
413 }
414
415 #[inline]
417 pub fn mark_cold(&mut self) {
418 self.is_cold = true;
419 }
420
421 #[inline]
423 pub fn is_cold_transaction_id(&self, transaction_id: usize) -> bool {
424 self.transaction_id != transaction_id || self.is_cold
425 }
426
427 #[inline]
432 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
433 let is_cold = self.is_cold_transaction_id(transaction_id);
434 self.transaction_id = transaction_id;
435 self.is_cold = false;
436 is_cold
437 }
438}
439
440#[cfg(test)]
441mod tests {
442 use super::*;
443 use crate::EvmStorageSlot;
444 use primitives::{StorageKey, KECCAK_EMPTY, U256};
445
446 #[test]
447 fn account_is_empty_balance() {
448 let mut account = Account::default();
449 assert!(account.is_empty());
450
451 account.info.balance = U256::from(1);
452 assert!(!account.is_empty());
453
454 account.info.balance = U256::ZERO;
455 assert!(account.is_empty());
456 }
457
458 #[test]
459 fn account_is_empty_nonce() {
460 let mut account = Account::default();
461 assert!(account.is_empty());
462
463 account.info.nonce = 1;
464 assert!(!account.is_empty());
465
466 account.info.nonce = 0;
467 assert!(account.is_empty());
468 }
469
470 #[test]
471 fn account_is_empty_code_hash() {
472 let mut account = Account::default();
473 assert!(account.is_empty());
474
475 account.info.code_hash = [1; 32].into();
476 assert!(!account.is_empty());
477
478 account.info.code_hash = [0; 32].into();
479 assert!(account.is_empty());
480
481 account.info.code_hash = KECCAK_EMPTY;
482 assert!(account.is_empty());
483 }
484
485 #[test]
486 fn account_state() {
487 let mut account = Account::default();
488
489 assert!(!account.is_touched());
490 assert!(!account.is_selfdestructed());
491
492 account.mark_touch();
493 assert!(account.is_touched());
494 assert!(!account.is_selfdestructed());
495
496 account.mark_selfdestruct();
497 assert!(account.is_touched());
498 assert!(account.is_selfdestructed());
499
500 account.unmark_selfdestruct();
501 assert!(account.is_touched());
502 assert!(!account.is_selfdestructed());
503 }
504
505 #[test]
506 fn account_is_cold() {
507 let mut account = Account::default();
508
509 assert!(!account.status.contains(crate::AccountStatus::Cold));
511
512 assert!(!account.mark_warm_with_transaction_id(0));
514
515 account.mark_cold();
517
518 assert!(account.status.contains(crate::AccountStatus::Cold));
520
521 assert!(account.mark_warm_with_transaction_id(0));
523 }
524
525 #[test]
526 fn test_account_with_info() {
527 let info = AccountInfo::default();
528 let account = Account::default().with_info(info.clone());
529
530 assert_eq!(account.info, info);
531 assert_eq!(account.storage, HashMap::default());
532 assert_eq!(account.status, AccountStatus::empty());
533 }
534
535 #[test]
536 fn test_account_with_storage() {
537 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
538 let key1 = StorageKey::from(1);
539 let key2 = StorageKey::from(2);
540 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
541 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
542
543 storage.insert(key1, slot1.clone());
544 storage.insert(key2, slot2.clone());
545
546 let account = Account::default().with_storage(storage.clone().into_iter());
547
548 assert_eq!(account.storage.len(), 2);
549 assert_eq!(account.storage.get(&key1), Some(&slot1));
550 assert_eq!(account.storage.get(&key2), Some(&slot2));
551 }
552
553 #[test]
554 fn test_account_with_selfdestruct_mark() {
555 let account = Account::default().with_selfdestruct_mark();
556
557 assert!(account.is_selfdestructed());
558 assert!(!account.is_touched());
559 assert!(!account.is_created());
560 }
561
562 #[test]
563 fn test_account_with_touched_mark() {
564 let account = Account::default().with_touched_mark();
565
566 assert!(!account.is_selfdestructed());
567 assert!(account.is_touched());
568 assert!(!account.is_created());
569 }
570
571 #[test]
572 fn test_account_with_created_mark() {
573 let account = Account::default().with_created_mark();
574
575 assert!(!account.is_selfdestructed());
576 assert!(!account.is_touched());
577 assert!(account.is_created());
578 }
579
580 #[test]
581 fn test_account_with_cold_mark() {
582 let account = Account::default().with_cold_mark();
583
584 assert!(account.status.contains(AccountStatus::Cold));
585 }
586
587 #[test]
588 fn test_storage_mark_warm_with_transaction_id() {
589 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
590 slot.is_cold = true;
591 slot.transaction_id = 0;
592 assert!(slot.mark_warm_with_transaction_id(1));
593
594 slot.is_cold = false;
595 slot.transaction_id = 0;
596 assert!(slot.mark_warm_with_transaction_id(1));
597
598 slot.is_cold = true;
599 slot.transaction_id = 1;
600 assert!(slot.mark_warm_with_transaction_id(1));
601
602 slot.is_cold = false;
603 slot.transaction_id = 1;
604 assert!(!slot.mark_warm_with_transaction_id(1));
606 }
607
608 #[test]
609 fn test_account_with_warm_mark() {
610 let cold_account = Account::default().with_cold_mark();
612 assert!(cold_account.status.contains(AccountStatus::Cold));
613
614 let (warm_account, was_cold) = cold_account.with_warm_mark(0);
616
617 assert!(!warm_account.status.contains(AccountStatus::Cold));
619 assert!(was_cold);
620
621 let (still_warm_account, was_cold) = warm_account.with_warm_mark(0);
623 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
624 assert!(!was_cold);
625 }
626
627 #[test]
628 fn test_account_with_warm() {
629 let cold_account = Account::default().with_cold_mark();
631 assert!(cold_account.status.contains(AccountStatus::Cold));
632
633 let warm_account = cold_account.with_warm(0);
635
636 assert!(!warm_account.status.contains(AccountStatus::Cold));
638 }
639
640 #[test]
641 fn test_account_builder_chaining() {
642 let info = AccountInfo {
643 nonce: 5,
644 ..AccountInfo::default()
645 };
646
647 let slot_key = StorageKey::from(42);
648 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
649 let mut storage = HashMap::<StorageKey, EvmStorageSlot>::default();
650 storage.insert(slot_key, slot_value.clone());
651
652 let account = Account::default()
654 .with_info(info.clone())
655 .with_storage(storage.into_iter())
656 .with_created_mark()
657 .with_touched_mark()
658 .with_cold_mark()
659 .with_warm(0);
660
661 assert_eq!(account.info, info);
663 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
664 assert!(account.is_created());
665 assert!(account.is_touched());
666 assert!(!account.status.contains(AccountStatus::Cold));
667 }
668
669 #[test]
670 fn test_account_is_cold_transaction_id() {
671 let mut account = Account::default();
672 assert!(!account.is_cold_transaction_id(0));
674
675 assert!(account.is_cold_transaction_id(1));
677 account.mark_cold();
678 assert!(account.is_cold_transaction_id(0));
679 assert!(account.is_cold_transaction_id(1));
680 }
681}