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