Skip to main content

reth_trie_common/bundle_state/
transition_account.rs

1use super::{AccountRevert, AccountStatus, BundleAccount, StorageWithOriginalValues};
2use alloy_primitives::{B256, U256};
3use evm2::{bytecode::Bytecode, evm::AccountInfo};
4
5/// Account Created when EVM state is merged to cache state.
6/// And it is sent to Block state.
7///
8/// It is used when block state gets merged to bundle state to
9/// create needed Reverts.
10#[derive(Clone, Debug, PartialEq, Eq, Default)]
11pub struct TransitionAccount<S = StorageWithOriginalValues> {
12    /// Account information, if account exists.
13    pub info: Option<AccountInfo>,
14    /// Current account status.
15    pub status: AccountStatus,
16    /// Previous account info is needed for account that got initially loaded.
17    /// Initially loaded account are not present inside bundle and are needed
18    /// to generate Reverts.
19    pub previous_info: Option<AccountInfo>,
20    /// Mostly needed when previous status Loaded/LoadedEmpty.
21    pub previous_status: AccountStatus,
22    /// Storage contains both old and new account
23    pub storage: S,
24    /// If there is transition that clears the storage we should mark it here and
25    /// delete all storages in BundleState. This flag is needed if we have transition
26    /// between Destroyed states from DestroyedChanged-> DestroyedAgain-> DestroyedChanged
27    /// in the end transition that we would have would be `DestroyedChanged->DestroyedChanged`
28    /// and with only that info we couldn't decide what to do.
29    pub storage_was_destroyed: bool,
30}
31
32impl TransitionAccount {
33    /// Create new LoadedEmpty account.
34    pub fn new_empty_eip161(storage: StorageWithOriginalValues) -> Self {
35        Self {
36            info: Some(AccountInfo::default()),
37            status: AccountStatus::InMemoryChange,
38            previous_info: None,
39            previous_status: AccountStatus::LoadedNotExisting,
40            storage,
41            storage_was_destroyed: false,
42        }
43    }
44
45    /// Return new contract bytecode if it is changed or newly created.
46    pub fn has_new_contract(&self) -> Option<(B256, &Bytecode)> {
47        let present_new_codehash = self.info.as_ref().map(|info| &info.code_hash);
48        let previous_codehash = self.previous_info.as_ref().map(|info| &info.code_hash);
49        if present_new_codehash != previous_codehash {
50            return self
51                .info
52                .as_ref()
53                .and_then(|info| info.code.as_ref().map(|c| (info.code_hash, c)));
54        }
55        None
56    }
57
58    /// Return the balance of account before transition.
59    pub fn previous_balance(&self) -> U256 {
60        self.previous_info.as_ref().map(|info| info.balance).unwrap_or_default()
61    }
62
63    /// Return the balance of account after transition.
64    pub fn current_balance(&self) -> U256 {
65        self.info.as_ref().map(|info| info.balance).unwrap_or_default()
66    }
67
68    /// Consume Self and create account revert from it.
69    pub fn create_revert(self) -> Option<AccountRevert> {
70        let mut previous_account = self.original_bundle_account();
71        previous_account.update_and_create_revert(self)
72    }
73
74    /// Present bundle account
75    pub fn present_bundle_account(&self) -> BundleAccount {
76        BundleAccount {
77            info: self.info.clone(),
78            original_info: self.previous_info.clone(),
79            storage: self.storage.clone(),
80            status: self.status,
81        }
82    }
83
84    /// Original bundle account
85    fn original_bundle_account(&self) -> BundleAccount {
86        BundleAccount {
87            info: self.previous_info.clone(),
88            original_info: self.previous_info.clone(),
89            storage: StorageWithOriginalValues::default(),
90            status: self.previous_status,
91        }
92    }
93}
94
95impl<S> TransitionAccount<S> {
96    /// Map the storage of the transition account.
97    pub fn map_storage<F, N>(self, f: F) -> TransitionAccount<N>
98    where
99        F: FnOnce(S) -> N,
100    {
101        let Self { info, status, previous_info, previous_status, storage, storage_was_destroyed } =
102            self;
103        TransitionAccount {
104            info,
105            status,
106            previous_info,
107            previous_status,
108            storage: f(storage),
109            storage_was_destroyed,
110        }
111    }
112}