Skip to main content

reth_trie_common/bundle_state/
account_status.rs

1/// AccountStatus represents the various states an account can be in after being loaded from the
2/// database.
3///
4/// After account get loaded from database it can be in a lot of different states
5/// while we execute multiple transaction and even blocks over account that is in memory.
6/// This structure models all possible states that account can be in.
7///
8/// # Variants
9///
10/// - `LoadedNotExisting`: the account has been loaded but does not exist.
11/// - `Loaded`: the account has been loaded and exists.
12/// - `LoadedEmptyEIP161`: the account is loaded and empty, as per EIP-161.
13/// - `InMemoryChange`: there are changes in the account that exist only in memory.
14/// - `Changed`: the account has been modified.
15/// - `Destroyed`: the account has been destroyed.
16/// - `DestroyedChanged`: the account has been destroyed and then modified.
17/// - `DestroyedAgain`: the account has been destroyed again.
18#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
19#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
20pub enum AccountStatus {
21    /// The account has been loaded but does not exist.
22    #[default]
23    LoadedNotExisting,
24    /// The account has been loaded and exists.
25    Loaded,
26    /// The account is loaded and empty, as per EIP-161.
27    LoadedEmptyEIP161,
28    /// There are changes in the account that exist only in memory.
29    InMemoryChange,
30    /// The account has been modified.
31    Changed,
32    /// The account has been destroyed.
33    Destroyed,
34    /// The account has been destroyed and then modified.
35    DestroyedChanged,
36    /// The account has been destroyed again.
37    DestroyedAgain,
38}
39
40impl AccountStatus {
41    /// Account is not modified and just loaded from database.
42    pub const fn is_not_modified(&self) -> bool {
43        matches!(self, Self::LoadedNotExisting | Self::Loaded | Self::LoadedEmptyEIP161)
44    }
45
46    /// Account was destroyed by calling SELFDESTRUCT.
47    /// This means that full account and storage are inside memory.
48    pub const fn was_destroyed(&self) -> bool {
49        matches!(self, Self::Destroyed | Self::DestroyedChanged | Self::DestroyedAgain)
50    }
51
52    /// This means storage is known, it can be newly created or storage got destroyed.
53    pub const fn is_storage_known(&self) -> bool {
54        matches!(
55            self,
56            Self::LoadedNotExisting |
57                Self::InMemoryChange |
58                Self::Destroyed |
59                Self::DestroyedChanged |
60                Self::DestroyedAgain
61        )
62    }
63
64    /// Account is modified but not destroyed.
65    /// This means that some storage values can be found in both
66    /// memory and database.
67    pub const fn is_modified_and_not_destroyed(&self) -> bool {
68        matches!(self, Self::Changed | Self::InMemoryChange)
69    }
70
71    /// Returns the next account status on creation.
72    pub const fn on_created(&self) -> Self {
73        match self {
74            // If account was destroyed previously just copy new info to it.
75            Self::DestroyedAgain
76            | Self::Destroyed
77            | Self::DestroyedChanged => Self::DestroyedChanged,
78            // If account is loaded from db.
79            Self::LoadedNotExisting
80            // Loaded empty eip161 to creates is not possible as CREATE2 was added after EIP-161
81            | Self::LoadedEmptyEIP161
82            | Self::Loaded
83            | Self::Changed
84            | Self::InMemoryChange => {
85                // If account is loaded and not empty this means that account has some balance.
86                // This means that account cannot be created.
87                // We are assuming that EVM did necessary checks before allowing account to be created.
88                Self::InMemoryChange
89            }
90        }
91    }
92
93    /// Returns the next account status on touched empty account post state clear EIP (EIP-161).
94    pub const fn on_touched_empty_post_eip161(&self) -> Self {
95        match self {
96            // Account can be touched but not existing. The status should remain the same.
97            Self::LoadedNotExisting => Self::LoadedNotExisting,
98            // Account can be created empty and only then touched.
99            Self::InMemoryChange | Self::Destroyed | Self::LoadedEmptyEIP161 => Self::Destroyed,
100            // Transition to destroy the account.
101            Self::DestroyedAgain | Self::DestroyedChanged => Self::DestroyedAgain,
102            // Account can become empty.
103            Self::Changed | Self::Loaded => Self::Destroyed,
104        }
105    }
106
107    /// Returns the next account status on change.
108    pub const fn on_changed(&self, had_no_nonce_and_code: bool) -> Self {
109        match self {
110            // If the account was loaded as not existing, promote it to changed.
111            // This account was likely created by a balance transfer.
112            Self::LoadedNotExisting => Self::InMemoryChange,
113            // Change on empty account, should transfer storage if there is any.
114            // There is possibility that there are storage entries inside db.
115            // That storage is used in merkle tree calculation before state clear EIP.
116            Self::LoadedEmptyEIP161 => Self::InMemoryChange,
117            // The account was loaded as existing.
118            Self::Loaded => {
119                if had_no_nonce_and_code {
120                    // Account is fully in memory
121                    Self::InMemoryChange
122                } else {
123                    // Can be contract and some of storage slots can be present inside db.
124                    Self::Changed
125                }
126            }
127
128            // On change, the "changed" type account statuses are preserved.
129            // Any checks for empty accounts are done outside of this fn.
130            Self::Changed => Self::Changed,
131            Self::InMemoryChange => Self::InMemoryChange,
132            Self::DestroyedChanged => Self::DestroyedChanged,
133
134            // If account is destroyed and then changed this means this is
135            // balance transfer.
136            Self::Destroyed | Self::DestroyedAgain => Self::DestroyedChanged,
137        }
138    }
139
140    /// Returns the next account status on selfdestruct.
141    pub const fn on_selfdestructed(&self) -> Self {
142        match self {
143            // Non existing account can't be destroyed.
144            Self::LoadedNotExisting => Self::LoadedNotExisting,
145            // If account is created and selfdestructed in the same block, mark it as destroyed
146            // again. Note: There is no big difference between Destroyed and
147            // DestroyedAgain in this case, but was added for clarity.
148            Self::DestroyedChanged | Self::DestroyedAgain | Self::Destroyed => Self::DestroyedAgain,
149
150            // Transition to destroyed status.
151            _ => Self::Destroyed,
152        }
153    }
154
155    /// Transition to other state while preserving invariance of this state.
156    ///
157    /// It this account was Destroyed and other account is not:
158    /// - We should mark extended account as destroyed too.
159    /// - And as other account had some changes, extended account should be marked as
160    ///   DestroyedChanged.
161    ///
162    /// If both account are not destroyed and if this account is in memory:
163    /// - This means that extended account is in memory too.
164    ///
165    /// Otherwise, if both are destroyed or other is destroyed:
166    /// - Sets other status to extended account.
167    pub fn transition(&mut self, other: Self) {
168        *self = match (self.was_destroyed(), other.was_destroyed()) {
169            (true, false) => Self::DestroyedChanged,
170            (false, false) if *self == Self::InMemoryChange => Self::InMemoryChange,
171            _ => other,
172        };
173    }
174}
175
176#[cfg(test)]
177mod test {
178
179    use super::*;
180
181    #[test]
182    fn test_account_status() {
183        // Account not modified
184        assert!(AccountStatus::Loaded.is_not_modified());
185        assert!(AccountStatus::LoadedEmptyEIP161.is_not_modified());
186        assert!(AccountStatus::LoadedNotExisting.is_not_modified());
187        assert!(!AccountStatus::Changed.is_not_modified());
188        assert!(!AccountStatus::InMemoryChange.is_not_modified());
189        assert!(!AccountStatus::Destroyed.is_not_modified());
190        assert!(!AccountStatus::DestroyedChanged.is_not_modified());
191        assert!(!AccountStatus::DestroyedAgain.is_not_modified());
192
193        // We know full storage
194        assert!(!AccountStatus::LoadedEmptyEIP161.is_storage_known());
195        assert!(AccountStatus::LoadedNotExisting.is_storage_known());
196        assert!(AccountStatus::InMemoryChange.is_storage_known());
197        assert!(AccountStatus::Destroyed.is_storage_known());
198        assert!(AccountStatus::DestroyedChanged.is_storage_known());
199        assert!(AccountStatus::DestroyedAgain.is_storage_known());
200        assert!(!AccountStatus::Loaded.is_storage_known());
201        assert!(!AccountStatus::Changed.is_storage_known());
202
203        // Account was destroyed
204        assert!(!AccountStatus::LoadedEmptyEIP161.was_destroyed());
205        assert!(!AccountStatus::LoadedNotExisting.was_destroyed());
206        assert!(!AccountStatus::InMemoryChange.was_destroyed());
207        assert!(AccountStatus::Destroyed.was_destroyed());
208        assert!(AccountStatus::DestroyedChanged.was_destroyed());
209        assert!(AccountStatus::DestroyedAgain.was_destroyed());
210        assert!(!AccountStatus::Loaded.was_destroyed());
211        assert!(!AccountStatus::Changed.was_destroyed());
212
213        // Account modified but not destroyed
214        assert!(AccountStatus::Changed.is_modified_and_not_destroyed());
215        assert!(AccountStatus::InMemoryChange.is_modified_and_not_destroyed());
216        assert!(!AccountStatus::Loaded.is_modified_and_not_destroyed());
217        assert!(!AccountStatus::LoadedEmptyEIP161.is_modified_and_not_destroyed());
218        assert!(!AccountStatus::LoadedNotExisting.is_modified_and_not_destroyed());
219        assert!(!AccountStatus::Destroyed.is_modified_and_not_destroyed());
220        assert!(!AccountStatus::DestroyedChanged.is_modified_and_not_destroyed());
221        assert!(!AccountStatus::DestroyedAgain.is_modified_and_not_destroyed());
222    }
223
224    #[test]
225    fn test_on_created() {
226        assert_eq!(AccountStatus::Destroyed.on_created(), AccountStatus::DestroyedChanged);
227        assert_eq!(AccountStatus::DestroyedAgain.on_created(), AccountStatus::DestroyedChanged);
228        assert_eq!(AccountStatus::DestroyedChanged.on_created(), AccountStatus::DestroyedChanged);
229
230        assert_eq!(AccountStatus::LoadedNotExisting.on_created(), AccountStatus::InMemoryChange);
231        assert_eq!(AccountStatus::Loaded.on_created(), AccountStatus::InMemoryChange);
232        assert_eq!(AccountStatus::LoadedEmptyEIP161.on_created(), AccountStatus::InMemoryChange);
233        assert_eq!(AccountStatus::Changed.on_created(), AccountStatus::InMemoryChange);
234        assert_eq!(AccountStatus::InMemoryChange.on_created(), AccountStatus::InMemoryChange);
235    }
236
237    #[test]
238    fn test_on_touched_empty_post_eip161() {
239        assert_eq!(
240            AccountStatus::LoadedNotExisting.on_touched_empty_post_eip161(),
241            AccountStatus::LoadedNotExisting
242        );
243        assert_eq!(
244            AccountStatus::InMemoryChange.on_touched_empty_post_eip161(),
245            AccountStatus::Destroyed
246        );
247        assert_eq!(
248            AccountStatus::Destroyed.on_touched_empty_post_eip161(),
249            AccountStatus::Destroyed
250        );
251        assert_eq!(
252            AccountStatus::LoadedEmptyEIP161.on_touched_empty_post_eip161(),
253            AccountStatus::Destroyed
254        );
255        assert_eq!(
256            AccountStatus::DestroyedAgain.on_touched_empty_post_eip161(),
257            AccountStatus::DestroyedAgain
258        );
259        assert_eq!(
260            AccountStatus::DestroyedChanged.on_touched_empty_post_eip161(),
261            AccountStatus::DestroyedAgain
262        );
263        assert_eq!(AccountStatus::Loaded.on_touched_empty_post_eip161(), AccountStatus::Destroyed);
264        assert_eq!(AccountStatus::Changed.on_touched_empty_post_eip161(), AccountStatus::Destroyed);
265    }
266
267    #[test]
268    fn test_on_changed() {
269        assert_eq!(
270            AccountStatus::LoadedNotExisting.on_changed(true),
271            AccountStatus::InMemoryChange
272        );
273        assert_eq!(
274            AccountStatus::LoadedNotExisting.on_changed(false),
275            AccountStatus::InMemoryChange
276        );
277
278        assert_eq!(
279            AccountStatus::LoadedEmptyEIP161.on_changed(true),
280            AccountStatus::InMemoryChange
281        );
282        assert_eq!(
283            AccountStatus::LoadedEmptyEIP161.on_changed(false),
284            AccountStatus::InMemoryChange
285        );
286
287        assert_eq!(AccountStatus::Loaded.on_changed(true), AccountStatus::InMemoryChange);
288        assert_eq!(AccountStatus::Loaded.on_changed(false), AccountStatus::Changed);
289
290        assert_eq!(AccountStatus::Changed.on_changed(true), AccountStatus::Changed);
291        assert_eq!(AccountStatus::Changed.on_changed(false), AccountStatus::Changed);
292
293        assert_eq!(AccountStatus::InMemoryChange.on_changed(true), AccountStatus::InMemoryChange);
294        assert_eq!(AccountStatus::InMemoryChange.on_changed(false), AccountStatus::InMemoryChange);
295
296        assert_eq!(
297            AccountStatus::DestroyedChanged.on_changed(true),
298            AccountStatus::DestroyedChanged
299        );
300        assert_eq!(
301            AccountStatus::DestroyedChanged.on_changed(false),
302            AccountStatus::DestroyedChanged
303        );
304
305        assert_eq!(AccountStatus::Destroyed.on_changed(true), AccountStatus::DestroyedChanged);
306        assert_eq!(AccountStatus::Destroyed.on_changed(false), AccountStatus::DestroyedChanged);
307
308        assert_eq!(AccountStatus::DestroyedAgain.on_changed(true), AccountStatus::DestroyedChanged);
309        assert_eq!(
310            AccountStatus::DestroyedAgain.on_changed(false),
311            AccountStatus::DestroyedChanged
312        );
313    }
314
315    #[test]
316    fn test_on_selfdestructed() {
317        assert_eq!(
318            AccountStatus::LoadedNotExisting.on_selfdestructed(),
319            AccountStatus::LoadedNotExisting
320        );
321
322        assert_eq!(
323            AccountStatus::DestroyedChanged.on_selfdestructed(),
324            AccountStatus::DestroyedAgain
325        );
326        assert_eq!(
327            AccountStatus::DestroyedAgain.on_selfdestructed(),
328            AccountStatus::DestroyedAgain
329        );
330        assert_eq!(AccountStatus::Destroyed.on_selfdestructed(), AccountStatus::DestroyedAgain);
331
332        assert_eq!(AccountStatus::Loaded.on_selfdestructed(), AccountStatus::Destroyed);
333        assert_eq!(AccountStatus::LoadedEmptyEIP161.on_selfdestructed(), AccountStatus::Destroyed);
334        assert_eq!(AccountStatus::InMemoryChange.on_selfdestructed(), AccountStatus::Destroyed);
335        assert_eq!(AccountStatus::Changed.on_selfdestructed(), AccountStatus::Destroyed);
336    }
337
338    #[test]
339    fn test_transition() {
340        let mut status = AccountStatus::Destroyed;
341        status.transition(AccountStatus::Loaded);
342        assert_eq!(status, AccountStatus::DestroyedChanged);
343
344        let mut status = AccountStatus::DestroyedChanged;
345        status.transition(AccountStatus::InMemoryChange);
346        assert_eq!(status, AccountStatus::DestroyedChanged);
347
348        let mut status = AccountStatus::DestroyedAgain;
349        status.transition(AccountStatus::Changed);
350        assert_eq!(status, AccountStatus::DestroyedChanged);
351
352        let mut status = AccountStatus::InMemoryChange;
353        status.transition(AccountStatus::Loaded);
354        assert_eq!(status, AccountStatus::InMemoryChange);
355
356        let mut status = AccountStatus::InMemoryChange;
357        status.transition(AccountStatus::Changed);
358        assert_eq!(status, AccountStatus::InMemoryChange);
359
360        let mut status = AccountStatus::Loaded;
361        status.transition(AccountStatus::Changed);
362        assert_eq!(status, AccountStatus::Changed);
363
364        let mut status = AccountStatus::LoadedNotExisting;
365        status.transition(AccountStatus::InMemoryChange);
366        assert_eq!(status, AccountStatus::InMemoryChange);
367
368        let mut status = AccountStatus::LoadedEmptyEIP161;
369        status.transition(AccountStatus::Loaded);
370        assert_eq!(status, AccountStatus::Loaded);
371
372        let mut status = AccountStatus::Destroyed;
373        status.transition(AccountStatus::DestroyedChanged);
374        assert_eq!(status, AccountStatus::DestroyedChanged);
375
376        let mut status = AccountStatus::DestroyedAgain;
377        status.transition(AccountStatus::Destroyed);
378        assert_eq!(status, AccountStatus::Destroyed);
379
380        let mut status = AccountStatus::Loaded;
381        status.transition(AccountStatus::Destroyed);
382        assert_eq!(status, AccountStatus::Destroyed);
383
384        let mut status = AccountStatus::Changed;
385        status.transition(AccountStatus::DestroyedAgain);
386        assert_eq!(status, AccountStatus::DestroyedAgain);
387    }
388}