stratus/eth/primitives/
execution_account_changes.rs

1use derive_more::Deref;
2use display_json::DebugAsJson;
3
4use crate::alias::RevmBytecode;
5use crate::eth::primitives::Account;
6use crate::eth::primitives::Address;
7use crate::eth::primitives::Nonce;
8use crate::eth::primitives::Wei;
9
10#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default, Deref)]
11#[cfg_attr(test, derive(fake::Dummy))]
12pub struct Change<T>
13where
14    T: PartialEq + Eq + Default,
15{
16    #[deref]
17    value: T,
18    changed: bool,
19}
20
21impl<T> Change<T>
22where
23    T: PartialEq + Eq + Default,
24{
25    /// Updates the value and marks it as changed if the new value differs from the current one.
26    ///
27    /// This method will only update the internal value and set the `changed` flag to `true`
28    /// if the provided value is different from the current value.
29    pub fn apply(&mut self, changed_value: T) {
30        if self.value != changed_value {
31            self.value = changed_value;
32            self.changed = true;
33        }
34    }
35
36    /// Sets the original value only if no changes have been applied yet.
37    ///
38    /// This method will update the internal value only if the `changed` flag is `false`,
39    /// preserving any modifications that may have been made.
40    fn apply_original(&mut self, value: T) {
41        if !self.changed {
42            self.value = value;
43        }
44    }
45
46    /// Returns whether the value has been changed.
47    pub fn is_changed(&self) -> bool {
48        self.changed
49    }
50
51    /// Returns a reference to the current value.
52    pub fn value(&self) -> &T {
53        &self.value
54    }
55}
56
57impl<T, U> From<Option<U>> for Change<T>
58where
59    T: PartialEq + Eq + Default,
60    U: Into<T>,
61{
62    fn from(value: Option<U>) -> Self {
63        match value {
64            Some(value) => Self {
65                value: value.into(),
66                changed: true,
67            },
68            None => Self {
69                changed: false,
70                ..Default::default()
71            },
72        }
73    }
74}
75
76/// Changes that happened to an account during a transaction.
77#[derive(DebugAsJson, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize, Default)]
78#[cfg_attr(test, derive(fake::Dummy))]
79pub struct ExecutionAccountChanges {
80    pub nonce: Change<Nonce>,
81    pub balance: Change<Wei>,
82    #[cfg_attr(test, dummy(default))]
83    pub bytecode: Change<Option<RevmBytecode>>,
84}
85
86impl ExecutionAccountChanges {
87    /// Updates an existing account state with changes that happened during the transaction.
88    pub fn apply_modifications(&mut self, modified_account: Account) {
89        self.nonce.apply(modified_account.nonce);
90        self.balance.apply(modified_account.balance);
91        self.bytecode.apply(modified_account.bytecode);
92    }
93
94    pub fn merge(&mut self, other: ExecutionAccountChanges) {
95        if other.nonce.is_changed() {
96            self.nonce = other.nonce;
97        }
98        if other.balance.is_changed() {
99            self.balance = other.balance;
100        }
101        if other.bytecode.is_changed() {
102            self.bytecode = other.bytecode;
103        }
104    }
105
106    pub fn apply_original(&mut self, original_account: Account) {
107        self.nonce.apply_original(original_account.nonce);
108        self.balance.apply_original(original_account.balance);
109        self.bytecode.apply_original(original_account.bytecode);
110    }
111
112    /// Checks if account nonce, balance or bytecode were modified.
113    pub fn is_modified(&self) -> bool {
114        self.nonce.changed || self.balance.changed || self.bytecode.changed
115    }
116
117    pub fn to_account(self, address: Address) -> Account {
118        Account {
119            address,
120            nonce: self.nonce.value,
121            balance: self.balance.value,
122            bytecode: self.bytecode.value,
123        }
124    }
125
126    pub fn from_changed(account: Account) -> Self {
127        Self {
128            nonce: Change {
129                value: account.nonce,
130                changed: true,
131            },
132            balance: Change {
133                value: account.balance,
134                changed: true,
135            },
136            bytecode: Change {
137                value: account.bytecode,
138                changed: true,
139            },
140        }
141    }
142
143    pub fn from_unchanged(account: Account) -> Self {
144        Self {
145            nonce: Change {
146                value: account.nonce,
147                changed: false,
148            },
149            balance: Change {
150                value: account.balance,
151                changed: false,
152            },
153            bytecode: Change {
154                value: account.bytecode,
155                changed: false,
156            },
157        }
158    }
159}
160
161impl From<(Address, ExecutionAccountChanges)> for Account {
162    fn from((address, change): (Address, ExecutionAccountChanges)) -> Self {
163        Self {
164            address,
165            nonce: change.nonce.value,
166            balance: change.balance.value,
167            bytecode: change.bytecode.value,
168        }
169    }
170}