Skip to main content

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    pub fn on_touched_empty_post_eip161(&self) -> Self {
100        match self {
101            // Account can be touched but not existing. The status should remain the same.
102            Self::LoadedNotExisting => Self::LoadedNotExisting,
103            // Account can be created empty and only then touched.
104            Self::InMemoryChange | Self::Destroyed | Self::LoadedEmptyEIP161 => Self::Destroyed,
105            // Transition to destroy the account.
106            Self::DestroyedAgain | Self::DestroyedChanged => Self::DestroyedAgain,
107            // Account can become empty.
108            Self::Changed | Self::Loaded => Self::Destroyed,
109        }
110    }
111
112    /// Returns the next account status on change.
113    pub fn on_changed(&self, had_no_nonce_and_code: bool) -> Self {
114        match self {
115            // If the account was loaded as not existing, promote it to changed.
116            // This account was likely created by a balance transfer.
117            Self::LoadedNotExisting => Self::InMemoryChange,
118            // Change on empty account, should transfer storage if there is any.
119            // There is possibility that there are storage entries inside db.
120            // That storage is used in merkle tree calculation before state clear EIP.
121            Self::LoadedEmptyEIP161 => Self::InMemoryChange,
122            // The account was loaded as existing.
123            Self::Loaded => {
124                if had_no_nonce_and_code {
125                    // Account is fully in memory
126                    Self::InMemoryChange
127                } else {
128                    // Can be contract and some of storage slots can be present inside db.
129                    Self::Changed
130                }
131            }
132
133            // On change, the "changed" type account statuses are preserved.
134            // Any checks for empty accounts are done outside of this fn.
135            Self::Changed => Self::Changed,
136            Self::InMemoryChange => Self::InMemoryChange,
137            Self::DestroyedChanged => Self::DestroyedChanged,
138
139            // If account is destroyed and then changed this means this is
140            // balance transfer.
141            Self::Destroyed | Self::DestroyedAgain => Self::DestroyedChanged,
142        }
143    }
144
145    /// Returns the next account status on selfdestruct.
146    pub fn on_selfdestructed(&self) -> Self {
147        match self {
148            // Non existing account can't be destroyed.
149            Self::LoadedNotExisting => Self::LoadedNotExisting,
150            // If account is created and selfdestructed in the same block, mark it as destroyed again.
151            // Note: There is no big difference between Destroyed and DestroyedAgain in this case,
152            // but was added for clarity.
153            Self::DestroyedChanged | Self::DestroyedAgain | Self::Destroyed => Self::DestroyedAgain,
154
155            // Transition to destroyed status.
156            _ => Self::Destroyed,
157        }
158    }
159
160    /// Transition to other state while preserving invariance of this state.
161    ///
162    /// It this account was Destroyed and other account is not:
163    /// - We should mark extended account as destroyed too.
164    /// - And as other account had some changes, extended account
165    ///   should be marked as DestroyedChanged.
166    ///
167    /// If both account are not destroyed and if this account is in memory:
168    /// - This means that extended account is in memory too.
169    ///
170    /// Otherwise, if both are destroyed or other is destroyed:
171    /// -  Sets other status to extended account.
172    pub fn transition(&mut self, other: Self) {
173        *self = match (self.was_destroyed(), other.was_destroyed()) {
174            (true, false) => Self::DestroyedChanged,
175            (false, false) if *self == Self::InMemoryChange => Self::InMemoryChange,
176            _ => other,
177        };
178    }
179}
180
181#[cfg(test)]
182mod test {
183
184    use super::*;
185
186    #[test]
187    fn test_account_status() {
188        // Account not modified
189        assert!(AccountStatus::Loaded.is_not_modified());
190        assert!(AccountStatus::LoadedEmptyEIP161.is_not_modified());
191        assert!(AccountStatus::LoadedNotExisting.is_not_modified());
192        assert!(!AccountStatus::Changed.is_not_modified());
193        assert!(!AccountStatus::InMemoryChange.is_not_modified());
194        assert!(!AccountStatus::Destroyed.is_not_modified());
195        assert!(!AccountStatus::DestroyedChanged.is_not_modified());
196        assert!(!AccountStatus::DestroyedAgain.is_not_modified());
197
198        // We know full storage
199        assert!(!AccountStatus::LoadedEmptyEIP161.is_storage_known());
200        assert!(AccountStatus::LoadedNotExisting.is_storage_known());
201        assert!(AccountStatus::InMemoryChange.is_storage_known());
202        assert!(AccountStatus::Destroyed.is_storage_known());
203        assert!(AccountStatus::DestroyedChanged.is_storage_known());
204        assert!(AccountStatus::DestroyedAgain.is_storage_known());
205        assert!(!AccountStatus::Loaded.is_storage_known());
206        assert!(!AccountStatus::Changed.is_storage_known());
207
208        // Account was destroyed
209        assert!(!AccountStatus::LoadedEmptyEIP161.was_destroyed());
210        assert!(!AccountStatus::LoadedNotExisting.was_destroyed());
211        assert!(!AccountStatus::InMemoryChange.was_destroyed());
212        assert!(AccountStatus::Destroyed.was_destroyed());
213        assert!(AccountStatus::DestroyedChanged.was_destroyed());
214        assert!(AccountStatus::DestroyedAgain.was_destroyed());
215        assert!(!AccountStatus::Loaded.was_destroyed());
216        assert!(!AccountStatus::Changed.was_destroyed());
217
218        // Account modified but not destroyed
219        assert!(AccountStatus::Changed.is_modified_and_not_destroyed());
220        assert!(AccountStatus::InMemoryChange.is_modified_and_not_destroyed());
221        assert!(!AccountStatus::Loaded.is_modified_and_not_destroyed());
222        assert!(!AccountStatus::LoadedEmptyEIP161.is_modified_and_not_destroyed());
223        assert!(!AccountStatus::LoadedNotExisting.is_modified_and_not_destroyed());
224        assert!(!AccountStatus::Destroyed.is_modified_and_not_destroyed());
225        assert!(!AccountStatus::DestroyedChanged.is_modified_and_not_destroyed());
226        assert!(!AccountStatus::DestroyedAgain.is_modified_and_not_destroyed());
227    }
228
229    #[test]
230    fn test_on_created() {
231        assert_eq!(
232            AccountStatus::Destroyed.on_created(),
233            AccountStatus::DestroyedChanged
234        );
235        assert_eq!(
236            AccountStatus::DestroyedAgain.on_created(),
237            AccountStatus::DestroyedChanged
238        );
239        assert_eq!(
240            AccountStatus::DestroyedChanged.on_created(),
241            AccountStatus::DestroyedChanged
242        );
243
244        assert_eq!(
245            AccountStatus::LoadedNotExisting.on_created(),
246            AccountStatus::InMemoryChange
247        );
248        assert_eq!(
249            AccountStatus::Loaded.on_created(),
250            AccountStatus::InMemoryChange
251        );
252        assert_eq!(
253            AccountStatus::LoadedEmptyEIP161.on_created(),
254            AccountStatus::InMemoryChange
255        );
256        assert_eq!(
257            AccountStatus::Changed.on_created(),
258            AccountStatus::InMemoryChange
259        );
260        assert_eq!(
261            AccountStatus::InMemoryChange.on_created(),
262            AccountStatus::InMemoryChange
263        );
264    }
265
266    #[test]
267    fn test_on_touched_empty_post_eip161() {
268        assert_eq!(
269            AccountStatus::LoadedNotExisting.on_touched_empty_post_eip161(),
270            AccountStatus::LoadedNotExisting
271        );
272        assert_eq!(
273            AccountStatus::InMemoryChange.on_touched_empty_post_eip161(),
274            AccountStatus::Destroyed
275        );
276        assert_eq!(
277            AccountStatus::Destroyed.on_touched_empty_post_eip161(),
278            AccountStatus::Destroyed
279        );
280        assert_eq!(
281            AccountStatus::LoadedEmptyEIP161.on_touched_empty_post_eip161(),
282            AccountStatus::Destroyed
283        );
284        assert_eq!(
285            AccountStatus::DestroyedAgain.on_touched_empty_post_eip161(),
286            AccountStatus::DestroyedAgain
287        );
288        assert_eq!(
289            AccountStatus::DestroyedChanged.on_touched_empty_post_eip161(),
290            AccountStatus::DestroyedAgain
291        );
292        assert_eq!(
293            AccountStatus::Loaded.on_touched_empty_post_eip161(),
294            AccountStatus::Destroyed
295        );
296        assert_eq!(
297            AccountStatus::Changed.on_touched_empty_post_eip161(),
298            AccountStatus::Destroyed
299        );
300    }
301
302    #[test]
303    fn test_on_changed() {
304        assert_eq!(
305            AccountStatus::LoadedNotExisting.on_changed(true),
306            AccountStatus::InMemoryChange
307        );
308        assert_eq!(
309            AccountStatus::LoadedNotExisting.on_changed(false),
310            AccountStatus::InMemoryChange
311        );
312
313        assert_eq!(
314            AccountStatus::LoadedEmptyEIP161.on_changed(true),
315            AccountStatus::InMemoryChange
316        );
317        assert_eq!(
318            AccountStatus::LoadedEmptyEIP161.on_changed(false),
319            AccountStatus::InMemoryChange
320        );
321
322        assert_eq!(
323            AccountStatus::Loaded.on_changed(true),
324            AccountStatus::InMemoryChange
325        );
326        assert_eq!(
327            AccountStatus::Loaded.on_changed(false),
328            AccountStatus::Changed
329        );
330
331        assert_eq!(
332            AccountStatus::Changed.on_changed(true),
333            AccountStatus::Changed
334        );
335        assert_eq!(
336            AccountStatus::Changed.on_changed(false),
337            AccountStatus::Changed
338        );
339
340        assert_eq!(
341            AccountStatus::InMemoryChange.on_changed(true),
342            AccountStatus::InMemoryChange
343        );
344        assert_eq!(
345            AccountStatus::InMemoryChange.on_changed(false),
346            AccountStatus::InMemoryChange
347        );
348
349        assert_eq!(
350            AccountStatus::DestroyedChanged.on_changed(true),
351            AccountStatus::DestroyedChanged
352        );
353        assert_eq!(
354            AccountStatus::DestroyedChanged.on_changed(false),
355            AccountStatus::DestroyedChanged
356        );
357
358        assert_eq!(
359            AccountStatus::Destroyed.on_changed(true),
360            AccountStatus::DestroyedChanged
361        );
362        assert_eq!(
363            AccountStatus::Destroyed.on_changed(false),
364            AccountStatus::DestroyedChanged
365        );
366
367        assert_eq!(
368            AccountStatus::DestroyedAgain.on_changed(true),
369            AccountStatus::DestroyedChanged
370        );
371        assert_eq!(
372            AccountStatus::DestroyedAgain.on_changed(false),
373            AccountStatus::DestroyedChanged
374        );
375    }
376
377    #[test]
378    fn test_on_selfdestructed() {
379        assert_eq!(
380            AccountStatus::LoadedNotExisting.on_selfdestructed(),
381            AccountStatus::LoadedNotExisting
382        );
383
384        assert_eq!(
385            AccountStatus::DestroyedChanged.on_selfdestructed(),
386            AccountStatus::DestroyedAgain
387        );
388        assert_eq!(
389            AccountStatus::DestroyedAgain.on_selfdestructed(),
390            AccountStatus::DestroyedAgain
391        );
392        assert_eq!(
393            AccountStatus::Destroyed.on_selfdestructed(),
394            AccountStatus::DestroyedAgain
395        );
396
397        assert_eq!(
398            AccountStatus::Loaded.on_selfdestructed(),
399            AccountStatus::Destroyed
400        );
401        assert_eq!(
402            AccountStatus::LoadedEmptyEIP161.on_selfdestructed(),
403            AccountStatus::Destroyed
404        );
405        assert_eq!(
406            AccountStatus::InMemoryChange.on_selfdestructed(),
407            AccountStatus::Destroyed
408        );
409        assert_eq!(
410            AccountStatus::Changed.on_selfdestructed(),
411            AccountStatus::Destroyed
412        );
413    }
414
415    #[test]
416    fn test_transition() {
417        let mut status = AccountStatus::Destroyed;
418        status.transition(AccountStatus::Loaded);
419        assert_eq!(status, AccountStatus::DestroyedChanged);
420
421        let mut status = AccountStatus::DestroyedChanged;
422        status.transition(AccountStatus::InMemoryChange);
423        assert_eq!(status, AccountStatus::DestroyedChanged);
424
425        let mut status = AccountStatus::DestroyedAgain;
426        status.transition(AccountStatus::Changed);
427        assert_eq!(status, AccountStatus::DestroyedChanged);
428
429        let mut status = AccountStatus::InMemoryChange;
430        status.transition(AccountStatus::Loaded);
431        assert_eq!(status, AccountStatus::InMemoryChange);
432
433        let mut status = AccountStatus::InMemoryChange;
434        status.transition(AccountStatus::Changed);
435        assert_eq!(status, AccountStatus::InMemoryChange);
436
437        let mut status = AccountStatus::Loaded;
438        status.transition(AccountStatus::Changed);
439        assert_eq!(status, AccountStatus::Changed);
440
441        let mut status = AccountStatus::LoadedNotExisting;
442        status.transition(AccountStatus::InMemoryChange);
443        assert_eq!(status, AccountStatus::InMemoryChange);
444
445        let mut status = AccountStatus::LoadedEmptyEIP161;
446        status.transition(AccountStatus::Loaded);
447        assert_eq!(status, AccountStatus::Loaded);
448
449        let mut status = AccountStatus::Destroyed;
450        status.transition(AccountStatus::DestroyedChanged);
451        assert_eq!(status, AccountStatus::DestroyedChanged);
452
453        let mut status = AccountStatus::DestroyedAgain;
454        status.transition(AccountStatus::Destroyed);
455        assert_eq!(status, AccountStatus::Destroyed);
456
457        let mut status = AccountStatus::Loaded;
458        status.transition(AccountStatus::Destroyed);
459        assert_eq!(status, AccountStatus::Destroyed);
460
461        let mut status = AccountStatus::Changed;
462        status.transition(AccountStatus::DestroyedAgain);
463        assert_eq!(status, AccountStatus::DestroyedAgain);
464    }
465}