revm_database/states/
account_status.rs

1/// AccountStatus represents the various states an account can be in after being loaded from the database.
2///
3/// After account get loaded from database it can be in a lot of different states
4/// while we execute multiple transaction and even blocks over account that is in memory.
5/// This structure models all possible states that account can be in.
6///
7/// # Variants
8///
9/// - `LoadedNotExisting`: the account has been loaded but does not exist.
10/// - `Loaded`: the account has been loaded and exists.
11/// - `LoadedEmptyEIP161`: the account is loaded and empty, as per EIP-161.
12/// - `InMemoryChange`: there are changes in the account that exist only in memory.
13/// - `Changed`: the account has been modified.
14/// - `Destroyed`: the account has been destroyed.
15/// - `DestroyedChanged`: the account has been destroyed and then modified.
16/// - `DestroyedAgain`: the account has been destroyed again.
17#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19pub enum AccountStatus {
20    /// The account has been loaded but does not exist.
21    #[default]
22    LoadedNotExisting,
23    /// The account has been loaded and exists.
24    Loaded,
25    /// The account is loaded and empty, as per EIP-161.
26    LoadedEmptyEIP161,
27    /// There are changes in the account that exist only in memory.
28    InMemoryChange,
29    /// The account has been modified.
30    Changed,
31    /// The account has been destroyed.
32    Destroyed,
33    /// The account has been destroyed and then modified.
34    DestroyedChanged,
35    /// The account has been destroyed again.
36    DestroyedAgain,
37}
38
39impl AccountStatus {
40    /// Account is not modified and just loaded from database.
41    pub fn is_not_modified(&self) -> bool {
42        matches!(
43            self,
44            Self::LoadedNotExisting | Self::Loaded | Self::LoadedEmptyEIP161
45        )
46    }
47
48    /// Account was destroyed by calling SELFDESTRUCT.
49    /// This means that full account and storage are inside memory.
50    pub fn was_destroyed(&self) -> bool {
51        matches!(
52            self,
53            Self::Destroyed | Self::DestroyedChanged | Self::DestroyedAgain
54        )
55    }
56
57    /// This means storage is known, it can be newly created or storage got destroyed.
58    pub fn is_storage_known(&self) -> bool {
59        matches!(
60            self,
61            Self::LoadedNotExisting
62                | Self::InMemoryChange
63                | Self::Destroyed
64                | Self::DestroyedChanged
65                | Self::DestroyedAgain
66        )
67    }
68
69    /// Account is modified but not destroyed.
70    /// This means that some storage values can be found in both
71    /// memory and database.
72    pub fn is_modified_and_not_destroyed(&self) -> bool {
73        matches!(self, Self::Changed | Self::InMemoryChange)
74    }
75
76    /// Returns the next account status on creation.
77    pub fn on_created(&self) -> Self {
78        match self {
79            // If account was destroyed previously just copy new info to it.
80            Self::DestroyedAgain
81            | Self::Destroyed
82            | Self::DestroyedChanged => Self::DestroyedChanged,
83            // If account is loaded from db.
84            Self::LoadedNotExisting
85            // Loaded empty eip161 to creates is not possible as CREATE2 was added after EIP-161
86            | Self::LoadedEmptyEIP161
87            | Self::Loaded
88            | Self::Changed
89            | Self::InMemoryChange => {
90                // If account is loaded and not empty this means that account has some balance.
91                // This means that account cannot be created.
92                // We are assuming that EVM did necessary checks before allowing account to be created.
93                Self::InMemoryChange
94            }
95        }
96    }
97
98    /// Returns the next account status on touched empty account post state clear EIP (EIP-161).
99    ///
100    /// # Panics
101    ///
102    /// If current status is [AccountStatus::Loaded] or [AccountStatus::Changed].
103    pub fn on_touched_empty_post_eip161(&self) -> Self {
104        match self {
105            // Account can be touched but not existing. The status should remain the same.
106            Self::LoadedNotExisting => Self::LoadedNotExisting,
107            // Account can be created empty and only then touched.
108            Self::InMemoryChange | Self::Destroyed | Self::LoadedEmptyEIP161 => Self::Destroyed,
109            // Transition to destroy the account.
110            Self::DestroyedAgain | Self::DestroyedChanged => Self::DestroyedAgain,
111            // Account statuses considered unreachable.
112            Self::Loaded | Self::Changed => {
113                unreachable!("Wrong state transition, touch empty is not possible from {self:?}");
114            }
115        }
116    }
117
118    /// Returns the next account status on touched or created account pre state clear EIP (EIP-161).
119    /// Returns `None` if the account status didn't change.
120    ///
121    /// # Panics
122    ///
123    /// If current status is [AccountStatus::Loaded] or [AccountStatus::Changed].
124    pub fn on_touched_created_pre_eip161(&self, had_no_info: bool) -> Option<Self> {
125        match self {
126            Self::LoadedEmptyEIP161 => None,
127            Self::DestroyedChanged => {
128                if had_no_info {
129                    None
130                } else {
131                    Some(Self::DestroyedChanged)
132                }
133            }
134            Self::Destroyed | Self::DestroyedAgain => Some(Self::DestroyedChanged),
135            Self::InMemoryChange | Self::LoadedNotExisting => Some(Self::InMemoryChange),
136            Self::Loaded | Self::Changed => {
137                unreachable!("Wrong state transition, touch crate is not possible from {self:?}")
138            }
139        }
140    }
141
142    /// Returns the next account status on change.
143    pub fn on_changed(&self, had_no_nonce_and_code: bool) -> Self {
144        match self {
145            // If the account was loaded as not existing, promote it to changed.
146            // This account was likely created by a balance transfer.
147            Self::LoadedNotExisting => Self::InMemoryChange,
148            // Change on empty account, should transfer storage if there is any.
149            // There is possibility that there are storage entries inside db.
150            // That storage is used in merkle tree calculation before state clear EIP.
151            Self::LoadedEmptyEIP161 => Self::InMemoryChange,
152            // The account was loaded as existing.
153            Self::Loaded => {
154                if had_no_nonce_and_code {
155                    // Account is fully in memory
156                    Self::InMemoryChange
157                } else {
158                    // Can be contract and some of storage slots can be present inside db.
159                    Self::Changed
160                }
161            }
162
163            // On change, the "changed" type account statuses are preserved.
164            // Any checks for empty accounts are done outside of this fn.
165            Self::Changed => Self::Changed,
166            Self::InMemoryChange => Self::InMemoryChange,
167            Self::DestroyedChanged => Self::DestroyedChanged,
168
169            // If account is destroyed and then changed this means this is
170            // balance transfer.
171            Self::Destroyed | Self::DestroyedAgain => Self::DestroyedChanged,
172        }
173    }
174
175    /// Returns the next account status on selfdestruct.
176    pub fn on_selfdestructed(&self) -> Self {
177        match self {
178            // Non existing account can't be destroyed.
179            Self::LoadedNotExisting => Self::LoadedNotExisting,
180            // If account is created and selfdestructed in the same block, mark it as destroyed again.
181            // Note: There is no big difference between Destroyed and DestroyedAgain in this case,
182            // but was added for clarity.
183            Self::DestroyedChanged | Self::DestroyedAgain | Self::Destroyed => Self::DestroyedAgain,
184
185            // Transition to destroyed status.
186            _ => Self::Destroyed,
187        }
188    }
189
190    /// Transition to other state while preserving invariance of this state.
191    ///
192    /// It this account was Destroyed and other account is not:
193    /// - We should mark extended account as destroyed too.
194    /// - And as other account had some changes, extended account
195    ///   should be marked as DestroyedChanged.
196    ///
197    /// If both account are not destroyed and if this account is in memory:
198    /// - This means that extended account is in memory too.
199    ///
200    /// Otherwise, if both are destroyed or other is destroyed:
201    /// -  Sets other status to extended account.
202    pub fn transition(&mut self, other: Self) {
203        *self = match (self.was_destroyed(), other.was_destroyed()) {
204            (true, false) => Self::DestroyedChanged,
205            (false, false) if *self == Self::InMemoryChange => Self::InMemoryChange,
206            _ => other,
207        };
208    }
209}
210
211#[cfg(test)]
212mod test {
213
214    use super::*;
215
216    #[test]
217    fn test_account_status() {
218        // Account not modified
219        assert!(AccountStatus::Loaded.is_not_modified());
220        assert!(AccountStatus::LoadedEmptyEIP161.is_not_modified());
221        assert!(AccountStatus::LoadedNotExisting.is_not_modified());
222        assert!(!AccountStatus::Changed.is_not_modified());
223        assert!(!AccountStatus::InMemoryChange.is_not_modified());
224        assert!(!AccountStatus::Destroyed.is_not_modified());
225        assert!(!AccountStatus::DestroyedChanged.is_not_modified());
226        assert!(!AccountStatus::DestroyedAgain.is_not_modified());
227
228        // We know full storage
229        assert!(!AccountStatus::LoadedEmptyEIP161.is_storage_known());
230        assert!(AccountStatus::LoadedNotExisting.is_storage_known());
231        assert!(AccountStatus::InMemoryChange.is_storage_known());
232        assert!(AccountStatus::Destroyed.is_storage_known());
233        assert!(AccountStatus::DestroyedChanged.is_storage_known());
234        assert!(AccountStatus::DestroyedAgain.is_storage_known());
235        assert!(!AccountStatus::Loaded.is_storage_known());
236        assert!(!AccountStatus::Changed.is_storage_known());
237
238        // Account was destroyed
239        assert!(!AccountStatus::LoadedEmptyEIP161.was_destroyed());
240        assert!(!AccountStatus::LoadedNotExisting.was_destroyed());
241        assert!(!AccountStatus::InMemoryChange.was_destroyed());
242        assert!(AccountStatus::Destroyed.was_destroyed());
243        assert!(AccountStatus::DestroyedChanged.was_destroyed());
244        assert!(AccountStatus::DestroyedAgain.was_destroyed());
245        assert!(!AccountStatus::Loaded.was_destroyed());
246        assert!(!AccountStatus::Changed.was_destroyed());
247
248        // Account modified but not destroyed
249        assert!(AccountStatus::Changed.is_modified_and_not_destroyed());
250        assert!(AccountStatus::InMemoryChange.is_modified_and_not_destroyed());
251        assert!(!AccountStatus::Loaded.is_modified_and_not_destroyed());
252        assert!(!AccountStatus::LoadedEmptyEIP161.is_modified_and_not_destroyed());
253        assert!(!AccountStatus::LoadedNotExisting.is_modified_and_not_destroyed());
254        assert!(!AccountStatus::Destroyed.is_modified_and_not_destroyed());
255        assert!(!AccountStatus::DestroyedChanged.is_modified_and_not_destroyed());
256        assert!(!AccountStatus::DestroyedAgain.is_modified_and_not_destroyed());
257    }
258
259    #[test]
260    fn test_on_created() {
261        assert_eq!(
262            AccountStatus::Destroyed.on_created(),
263            AccountStatus::DestroyedChanged
264        );
265        assert_eq!(
266            AccountStatus::DestroyedAgain.on_created(),
267            AccountStatus::DestroyedChanged
268        );
269        assert_eq!(
270            AccountStatus::DestroyedChanged.on_created(),
271            AccountStatus::DestroyedChanged
272        );
273
274        assert_eq!(
275            AccountStatus::LoadedNotExisting.on_created(),
276            AccountStatus::InMemoryChange
277        );
278        assert_eq!(
279            AccountStatus::Loaded.on_created(),
280            AccountStatus::InMemoryChange
281        );
282        assert_eq!(
283            AccountStatus::LoadedEmptyEIP161.on_created(),
284            AccountStatus::InMemoryChange
285        );
286        assert_eq!(
287            AccountStatus::Changed.on_created(),
288            AccountStatus::InMemoryChange
289        );
290        assert_eq!(
291            AccountStatus::InMemoryChange.on_created(),
292            AccountStatus::InMemoryChange
293        );
294    }
295
296    #[test]
297    fn test_on_touched_empty_post_eip161() {
298        assert_eq!(
299            AccountStatus::LoadedNotExisting.on_touched_empty_post_eip161(),
300            AccountStatus::LoadedNotExisting
301        );
302        assert_eq!(
303            AccountStatus::InMemoryChange.on_touched_empty_post_eip161(),
304            AccountStatus::Destroyed
305        );
306        assert_eq!(
307            AccountStatus::Destroyed.on_touched_empty_post_eip161(),
308            AccountStatus::Destroyed
309        );
310        assert_eq!(
311            AccountStatus::LoadedEmptyEIP161.on_touched_empty_post_eip161(),
312            AccountStatus::Destroyed
313        );
314        assert_eq!(
315            AccountStatus::DestroyedAgain.on_touched_empty_post_eip161(),
316            AccountStatus::DestroyedAgain
317        );
318        assert_eq!(
319            AccountStatus::DestroyedChanged.on_touched_empty_post_eip161(),
320            AccountStatus::DestroyedAgain
321        );
322    }
323
324    #[test]
325    fn test_on_touched_created_pre_eip161() {
326        assert_eq!(
327            AccountStatus::LoadedEmptyEIP161.on_touched_created_pre_eip161(true),
328            None
329        );
330        assert_eq!(
331            AccountStatus::LoadedEmptyEIP161.on_touched_created_pre_eip161(false),
332            None
333        );
334
335        assert_eq!(
336            AccountStatus::DestroyedChanged.on_touched_created_pre_eip161(true),
337            None
338        );
339        assert_eq!(
340            AccountStatus::DestroyedChanged.on_touched_created_pre_eip161(false),
341            Some(AccountStatus::DestroyedChanged)
342        );
343
344        assert_eq!(
345            AccountStatus::Destroyed.on_touched_created_pre_eip161(true),
346            Some(AccountStatus::DestroyedChanged)
347        );
348        assert_eq!(
349            AccountStatus::Destroyed.on_touched_created_pre_eip161(false),
350            Some(AccountStatus::DestroyedChanged)
351        );
352
353        assert_eq!(
354            AccountStatus::DestroyedAgain.on_touched_created_pre_eip161(true),
355            Some(AccountStatus::DestroyedChanged)
356        );
357        assert_eq!(
358            AccountStatus::DestroyedAgain.on_touched_created_pre_eip161(false),
359            Some(AccountStatus::DestroyedChanged)
360        );
361
362        assert_eq!(
363            AccountStatus::InMemoryChange.on_touched_created_pre_eip161(true),
364            Some(AccountStatus::InMemoryChange)
365        );
366        assert_eq!(
367            AccountStatus::InMemoryChange.on_touched_created_pre_eip161(false),
368            Some(AccountStatus::InMemoryChange)
369        );
370
371        assert_eq!(
372            AccountStatus::LoadedNotExisting.on_touched_created_pre_eip161(true),
373            Some(AccountStatus::InMemoryChange)
374        );
375        assert_eq!(
376            AccountStatus::LoadedNotExisting.on_touched_created_pre_eip161(false),
377            Some(AccountStatus::InMemoryChange)
378        );
379    }
380
381    #[test]
382    fn test_on_changed() {
383        assert_eq!(
384            AccountStatus::LoadedNotExisting.on_changed(true),
385            AccountStatus::InMemoryChange
386        );
387        assert_eq!(
388            AccountStatus::LoadedNotExisting.on_changed(false),
389            AccountStatus::InMemoryChange
390        );
391
392        assert_eq!(
393            AccountStatus::LoadedEmptyEIP161.on_changed(true),
394            AccountStatus::InMemoryChange
395        );
396        assert_eq!(
397            AccountStatus::LoadedEmptyEIP161.on_changed(false),
398            AccountStatus::InMemoryChange
399        );
400
401        assert_eq!(
402            AccountStatus::Loaded.on_changed(true),
403            AccountStatus::InMemoryChange
404        );
405        assert_eq!(
406            AccountStatus::Loaded.on_changed(false),
407            AccountStatus::Changed
408        );
409
410        assert_eq!(
411            AccountStatus::Changed.on_changed(true),
412            AccountStatus::Changed
413        );
414        assert_eq!(
415            AccountStatus::Changed.on_changed(false),
416            AccountStatus::Changed
417        );
418
419        assert_eq!(
420            AccountStatus::InMemoryChange.on_changed(true),
421            AccountStatus::InMemoryChange
422        );
423        assert_eq!(
424            AccountStatus::InMemoryChange.on_changed(false),
425            AccountStatus::InMemoryChange
426        );
427
428        assert_eq!(
429            AccountStatus::DestroyedChanged.on_changed(true),
430            AccountStatus::DestroyedChanged
431        );
432        assert_eq!(
433            AccountStatus::DestroyedChanged.on_changed(false),
434            AccountStatus::DestroyedChanged
435        );
436
437        assert_eq!(
438            AccountStatus::Destroyed.on_changed(true),
439            AccountStatus::DestroyedChanged
440        );
441        assert_eq!(
442            AccountStatus::Destroyed.on_changed(false),
443            AccountStatus::DestroyedChanged
444        );
445
446        assert_eq!(
447            AccountStatus::DestroyedAgain.on_changed(true),
448            AccountStatus::DestroyedChanged
449        );
450        assert_eq!(
451            AccountStatus::DestroyedAgain.on_changed(false),
452            AccountStatus::DestroyedChanged
453        );
454    }
455
456    #[test]
457    fn test_on_selfdestructed() {
458        assert_eq!(
459            AccountStatus::LoadedNotExisting.on_selfdestructed(),
460            AccountStatus::LoadedNotExisting
461        );
462
463        assert_eq!(
464            AccountStatus::DestroyedChanged.on_selfdestructed(),
465            AccountStatus::DestroyedAgain
466        );
467        assert_eq!(
468            AccountStatus::DestroyedAgain.on_selfdestructed(),
469            AccountStatus::DestroyedAgain
470        );
471        assert_eq!(
472            AccountStatus::Destroyed.on_selfdestructed(),
473            AccountStatus::DestroyedAgain
474        );
475
476        assert_eq!(
477            AccountStatus::Loaded.on_selfdestructed(),
478            AccountStatus::Destroyed
479        );
480        assert_eq!(
481            AccountStatus::LoadedEmptyEIP161.on_selfdestructed(),
482            AccountStatus::Destroyed
483        );
484        assert_eq!(
485            AccountStatus::InMemoryChange.on_selfdestructed(),
486            AccountStatus::Destroyed
487        );
488        assert_eq!(
489            AccountStatus::Changed.on_selfdestructed(),
490            AccountStatus::Destroyed
491        );
492    }
493
494    #[test]
495    fn test_transition() {
496        let mut status = AccountStatus::Destroyed;
497        status.transition(AccountStatus::Loaded);
498        assert_eq!(status, AccountStatus::DestroyedChanged);
499
500        let mut status = AccountStatus::DestroyedChanged;
501        status.transition(AccountStatus::InMemoryChange);
502        assert_eq!(status, AccountStatus::DestroyedChanged);
503
504        let mut status = AccountStatus::DestroyedAgain;
505        status.transition(AccountStatus::Changed);
506        assert_eq!(status, AccountStatus::DestroyedChanged);
507
508        let mut status = AccountStatus::InMemoryChange;
509        status.transition(AccountStatus::Loaded);
510        assert_eq!(status, AccountStatus::InMemoryChange);
511
512        let mut status = AccountStatus::InMemoryChange;
513        status.transition(AccountStatus::Changed);
514        assert_eq!(status, AccountStatus::InMemoryChange);
515
516        let mut status = AccountStatus::Loaded;
517        status.transition(AccountStatus::Changed);
518        assert_eq!(status, AccountStatus::Changed);
519
520        let mut status = AccountStatus::LoadedNotExisting;
521        status.transition(AccountStatus::InMemoryChange);
522        assert_eq!(status, AccountStatus::InMemoryChange);
523
524        let mut status = AccountStatus::LoadedEmptyEIP161;
525        status.transition(AccountStatus::Loaded);
526        assert_eq!(status, AccountStatus::Loaded);
527
528        let mut status = AccountStatus::Destroyed;
529        status.transition(AccountStatus::DestroyedChanged);
530        assert_eq!(status, AccountStatus::DestroyedChanged);
531
532        let mut status = AccountStatus::DestroyedAgain;
533        status.transition(AccountStatus::Destroyed);
534        assert_eq!(status, AccountStatus::Destroyed);
535
536        let mut status = AccountStatus::Loaded;
537        status.transition(AccountStatus::Destroyed);
538        assert_eq!(status, AccountStatus::Destroyed);
539
540        let mut status = AccountStatus::Changed;
541        status.transition(AccountStatus::DestroyedAgain);
542        assert_eq!(status, AccountStatus::DestroyedAgain);
543    }
544}