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 #[inline]
56 pub fn mark_selfdestruct(&mut self) {
57 self.status |= AccountStatus::SelfDestructed;
58 }
59
60 #[inline]
62 pub fn unmark_selfdestruct(&mut self) {
63 self.status -= AccountStatus::SelfDestructed;
64 }
65
66 #[inline]
68 pub fn is_selfdestructed(&self) -> bool {
69 self.status.contains(AccountStatus::SelfDestructed)
70 }
71
72 #[inline]
74 pub fn mark_touch(&mut self) {
75 self.status |= AccountStatus::Touched;
76 }
77
78 #[inline]
80 pub fn unmark_touch(&mut self) {
81 self.status -= AccountStatus::Touched;
82 }
83
84 #[inline]
86 pub fn is_touched(&self) -> bool {
87 self.status.contains(AccountStatus::Touched)
88 }
89
90 #[inline]
92 pub fn mark_created(&mut self) {
93 self.status |= AccountStatus::Created;
94 }
95
96 #[inline]
98 pub fn unmark_created(&mut self) {
99 self.status -= AccountStatus::Created;
100 }
101
102 #[inline]
104 pub fn mark_cold(&mut self) {
105 self.status |= AccountStatus::Cold;
106 }
107
108 #[inline]
110 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
111 let same_id = self.transaction_id == transaction_id;
112 let is_cold = self.status.contains(AccountStatus::Cold);
113
114 self.status -= AccountStatus::Cold;
115 self.transaction_id = transaction_id;
116
117 if !same_id {
118 return true;
119 }
120
121 is_cold
122 }
123
124 #[inline]
126 pub fn is_created_locally(&self) -> bool {
127 self.status.contains(AccountStatus::CreatedLocal)
128 }
129
130 #[inline]
132 pub fn is_selfdestructed_locally(&self) -> bool {
133 self.status.contains(AccountStatus::SelfDestructedLocal)
134 }
135
136 #[inline]
138 pub fn selfdestruct(&mut self) {
139 self.storage.clear();
140 self.info = AccountInfo::default();
141 }
142
143 #[inline]
147 pub fn mark_created_locally(&mut self) -> bool {
148 self.status |= AccountStatus::CreatedLocal;
149 let is_created_globaly = !self.status.contains(AccountStatus::Created);
150 self.status |= AccountStatus::Created;
151 is_created_globaly
152 }
153
154 #[inline]
156 pub fn unmark_created_locally(&mut self) {
157 self.status -= AccountStatus::CreatedLocal;
158 }
159
160 #[inline]
162 pub fn mark_selfdestructed_locally(&mut self) -> bool {
163 self.status |= AccountStatus::SelfDestructedLocal;
164 let is_global_selfdestructed = !self.status.contains(AccountStatus::SelfDestructed);
165 self.status |= AccountStatus::SelfDestructed;
166 is_global_selfdestructed
167 }
168
169 #[inline]
171 pub fn unmark_selfdestructed_locally(&mut self) {
172 self.status -= AccountStatus::SelfDestructedLocal;
173 }
174
175 pub fn is_loaded_as_not_existing(&self) -> bool {
180 self.status.contains(AccountStatus::LoadedAsNotExisting)
181 }
182
183 pub fn is_loaded_as_not_existing_not_touched(&self) -> bool {
185 self.is_loaded_as_not_existing() && !self.is_touched()
186 }
187
188 pub fn is_created(&self) -> bool {
190 self.status.contains(AccountStatus::Created)
191 }
192
193 pub fn is_empty(&self) -> bool {
195 self.info.is_empty()
196 }
197
198 pub fn changed_storage_slots(&self) -> impl Iterator<Item = (&StorageKey, &EvmStorageSlot)> {
202 self.storage.iter().filter(|(_, slot)| slot.is_changed())
203 }
204
205 pub fn with_info(mut self, info: AccountInfo) -> Self {
207 self.info = info;
208 self
209 }
210
211 pub fn with_storage<I>(mut self, storage_iter: I) -> Self
213 where
214 I: Iterator<Item = (StorageKey, EvmStorageSlot)>,
215 {
216 for (key, slot) in storage_iter {
217 self.storage.insert(key, slot);
218 }
219 self
220 }
221
222 pub fn with_selfdestruct_mark(mut self) -> Self {
224 self.mark_selfdestruct();
225 self
226 }
227
228 pub fn with_touched_mark(mut self) -> Self {
230 self.mark_touch();
231 self
232 }
233
234 pub fn with_created_mark(mut self) -> Self {
236 self.mark_created();
237 self
238 }
239
240 pub fn with_cold_mark(mut self) -> Self {
242 self.mark_cold();
243 self
244 }
245
246 pub fn with_warm_mark(mut self, transaction_id: usize) -> (Self, bool) {
249 let was_cold = self.mark_warm_with_transaction_id(transaction_id);
250 (self, was_cold)
251 }
252
253 pub fn with_warm(mut self, transaction_id: usize) -> Self {
255 self.mark_warm_with_transaction_id(transaction_id);
256 self
257 }
258}
259
260impl From<AccountInfo> for Account {
261 fn from(info: AccountInfo) -> Self {
262 Self {
263 info,
264 storage: HashMap::default(),
265 transaction_id: 0,
266 status: AccountStatus::empty(),
267 }
268 }
269}
270
271bitflags! {
273 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
305 #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
306 #[cfg_attr(feature = "serde", serde(transparent))]
307 pub struct AccountStatus: u8 {
308 const Created = 0b00000001;
311 const CreatedLocal = 0b10000000;
313 const SelfDestructed = 0b00000010;
315 const SelfDestructedLocal = 0b01000000;
317 const Touched = 0b00000100;
321 const LoadedAsNotExisting = 0b00001000;
324 const Cold = 0b00010000;
327 }
328}
329
330impl Default for AccountStatus {
331 fn default() -> Self {
332 AccountStatus::empty()
333 }
334}
335
336#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
338#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
339pub struct EvmStorageSlot {
340 pub original_value: StorageValue,
342 pub present_value: StorageValue,
344 pub transaction_id: usize,
346 pub is_cold: bool,
348}
349
350impl EvmStorageSlot {
351 pub fn new(original: StorageValue, transaction_id: usize) -> Self {
353 Self {
354 original_value: original,
355 present_value: original,
356 transaction_id,
357 is_cold: false,
358 }
359 }
360
361 pub fn new_changed(
363 original_value: StorageValue,
364 present_value: StorageValue,
365 transaction_id: usize,
366 ) -> Self {
367 Self {
368 original_value,
369 present_value,
370 transaction_id,
371 is_cold: false,
372 }
373 }
374 pub fn is_changed(&self) -> bool {
376 self.original_value != self.present_value
377 }
378
379 #[inline]
381 pub fn original_value(&self) -> StorageValue {
382 self.original_value
383 }
384
385 #[inline]
387 pub fn present_value(&self) -> StorageValue {
388 self.present_value
389 }
390
391 #[inline]
393 pub fn mark_cold(&mut self) {
394 self.is_cold = true;
395 }
396
397 #[inline]
402 pub fn mark_warm_with_transaction_id(&mut self, transaction_id: usize) -> bool {
403 let same_id = self.transaction_id == transaction_id;
404 self.transaction_id = transaction_id;
405 let was_cold = core::mem::take(&mut self.is_cold);
406
407 if same_id {
408 return was_cold;
410 }
411 true
412 }
413}
414
415#[cfg(test)]
416mod tests {
417 use super::*;
418 use crate::EvmStorageSlot;
419 use primitives::{StorageKey, KECCAK_EMPTY, U256};
420
421 #[test]
422 fn account_is_empty_balance() {
423 let mut account = Account::default();
424 assert!(account.is_empty());
425
426 account.info.balance = U256::from(1);
427 assert!(!account.is_empty());
428
429 account.info.balance = U256::ZERO;
430 assert!(account.is_empty());
431 }
432
433 #[test]
434 fn account_is_empty_nonce() {
435 let mut account = Account::default();
436 assert!(account.is_empty());
437
438 account.info.nonce = 1;
439 assert!(!account.is_empty());
440
441 account.info.nonce = 0;
442 assert!(account.is_empty());
443 }
444
445 #[test]
446 fn account_is_empty_code_hash() {
447 let mut account = Account::default();
448 assert!(account.is_empty());
449
450 account.info.code_hash = [1; 32].into();
451 assert!(!account.is_empty());
452
453 account.info.code_hash = [0; 32].into();
454 assert!(account.is_empty());
455
456 account.info.code_hash = KECCAK_EMPTY;
457 assert!(account.is_empty());
458 }
459
460 #[test]
461 fn account_state() {
462 let mut account = Account::default();
463
464 assert!(!account.is_touched());
465 assert!(!account.is_selfdestructed());
466
467 account.mark_touch();
468 assert!(account.is_touched());
469 assert!(!account.is_selfdestructed());
470
471 account.mark_selfdestruct();
472 assert!(account.is_touched());
473 assert!(account.is_selfdestructed());
474
475 account.unmark_selfdestruct();
476 assert!(account.is_touched());
477 assert!(!account.is_selfdestructed());
478 }
479
480 #[test]
481 fn account_is_cold() {
482 let mut account = Account::default();
483
484 assert!(!account.status.contains(crate::AccountStatus::Cold));
486
487 assert!(!account.mark_warm_with_transaction_id(0));
489
490 account.mark_cold();
492
493 assert!(account.status.contains(crate::AccountStatus::Cold));
495
496 assert!(account.mark_warm_with_transaction_id(0));
498 }
499
500 #[test]
501 fn test_account_with_info() {
502 let info = AccountInfo::default();
503 let account = Account::default().with_info(info.clone());
504
505 assert_eq!(account.info, info);
506 assert_eq!(account.storage, HashMap::default());
507 assert_eq!(account.status, AccountStatus::empty());
508 }
509
510 #[test]
511 fn test_account_with_storage() {
512 let mut storage = HashMap::new();
513 let key1 = StorageKey::from(1);
514 let key2 = StorageKey::from(2);
515 let slot1 = EvmStorageSlot::new(StorageValue::from(10), 0);
516 let slot2 = EvmStorageSlot::new(StorageValue::from(20), 0);
517
518 storage.insert(key1, slot1.clone());
519 storage.insert(key2, slot2.clone());
520
521 let account = Account::default().with_storage(storage.clone().into_iter());
522
523 assert_eq!(account.storage.len(), 2);
524 assert_eq!(account.storage.get(&key1), Some(&slot1));
525 assert_eq!(account.storage.get(&key2), Some(&slot2));
526 }
527
528 #[test]
529 fn test_account_with_selfdestruct_mark() {
530 let account = Account::default().with_selfdestruct_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_touched_mark() {
539 let account = Account::default().with_touched_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_created_mark() {
548 let account = Account::default().with_created_mark();
549
550 assert!(!account.is_selfdestructed());
551 assert!(!account.is_touched());
552 assert!(account.is_created());
553 }
554
555 #[test]
556 fn test_account_with_cold_mark() {
557 let account = Account::default().with_cold_mark();
558
559 assert!(account.status.contains(AccountStatus::Cold));
560 }
561
562 #[test]
563 fn test_storage_mark_warm_with_transaction_id() {
564 let mut slot = EvmStorageSlot::new(U256::ZERO, 0);
565 slot.is_cold = true;
566 slot.transaction_id = 0;
567 assert!(slot.mark_warm_with_transaction_id(1));
568
569 slot.is_cold = false;
570 slot.transaction_id = 0;
571 assert!(slot.mark_warm_with_transaction_id(1));
572
573 slot.is_cold = true;
574 slot.transaction_id = 1;
575 assert!(slot.mark_warm_with_transaction_id(1));
576
577 slot.is_cold = false;
578 slot.transaction_id = 1;
579 assert!(!slot.mark_warm_with_transaction_id(1));
581 }
582
583 #[test]
584 fn test_account_with_warm_mark() {
585 let cold_account = Account::default().with_cold_mark();
587 assert!(cold_account.status.contains(AccountStatus::Cold));
588
589 let (warm_account, was_cold) = cold_account.with_warm_mark(0);
591
592 assert!(!warm_account.status.contains(AccountStatus::Cold));
594 assert!(was_cold);
595
596 let (still_warm_account, was_cold) = warm_account.with_warm_mark(0);
598 assert!(!still_warm_account.status.contains(AccountStatus::Cold));
599 assert!(!was_cold);
600 }
601
602 #[test]
603 fn test_account_with_warm() {
604 let cold_account = Account::default().with_cold_mark();
606 assert!(cold_account.status.contains(AccountStatus::Cold));
607
608 let warm_account = cold_account.with_warm(0);
610
611 assert!(!warm_account.status.contains(AccountStatus::Cold));
613 }
614
615 #[test]
616 fn test_account_builder_chaining() {
617 let info = AccountInfo {
618 nonce: 5,
619 ..AccountInfo::default()
620 };
621
622 let slot_key = StorageKey::from(42);
623 let slot_value = EvmStorageSlot::new(StorageValue::from(123), 0);
624 let mut storage = HashMap::new();
625 storage.insert(slot_key, slot_value.clone());
626
627 let account = Account::default()
629 .with_info(info.clone())
630 .with_storage(storage.into_iter())
631 .with_created_mark()
632 .with_touched_mark()
633 .with_cold_mark()
634 .with_warm(0);
635
636 assert_eq!(account.info, info);
638 assert_eq!(account.storage.get(&slot_key), Some(&slot_value));
639 assert!(account.is_created());
640 assert!(account.is_touched());
641 assert!(!account.status.contains(AccountStatus::Cold));
642 }
643}