revm_database/states/
reverts.rs

1use super::{
2    changes::PlainStorageRevert, AccountStatus, BundleAccount, PlainStateReverts,
3    StorageWithOriginalValues,
4};
5use core::{
6    cmp::Ordering,
7    ops::{Deref, DerefMut},
8};
9use primitives::{Address, HashMap, U256};
10use state::AccountInfo;
11use std::vec::Vec;
12
13/// Contains reverts of multiple account in multiple transitions (Transitions as a block).
14#[derive(Clone, Debug, Default, Eq)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
16pub struct Reverts(Vec<Vec<(Address, AccountRevert)>>);
17
18impl Deref for Reverts {
19    type Target = Vec<Vec<(Address, AccountRevert)>>;
20
21    fn deref(&self) -> &Self::Target {
22        &self.0
23    }
24}
25
26impl DerefMut for Reverts {
27    fn deref_mut(&mut self) -> &mut Self::Target {
28        &mut self.0
29    }
30}
31
32impl Reverts {
33    /// Creates new reverts.
34    pub fn new(reverts: Vec<Vec<(Address, AccountRevert)>>) -> Self {
35        Self(reverts)
36    }
37
38    /// Sorts account inside transition by their address.
39    pub fn sort(&mut self) {
40        for revert in &mut self.0 {
41            revert.sort_by_key(|(address, _)| *address);
42        }
43    }
44
45    /// Extends reverts with other reverts.
46    pub fn extend(&mut self, other: Reverts) {
47        self.0.extend(other.0);
48    }
49
50    /// Generates a [`PlainStateReverts`].
51    ///
52    /// Note that account are sorted by address.
53    pub fn to_plain_state_reverts(&self) -> PlainStateReverts {
54        let mut state_reverts = PlainStateReverts::with_capacity(self.0.len());
55        for reverts in &self.0 {
56            // Pessimistically pre-allocate assuming _all_ accounts changed.
57            let mut accounts = Vec::with_capacity(reverts.len());
58            let mut storage = Vec::with_capacity(reverts.len());
59            for (address, revert_account) in reverts {
60                match &revert_account.account {
61                    AccountInfoRevert::RevertTo(acc) => {
62                        // Cloning is cheap, because account info has 3 small
63                        // fields and a Bytes
64                        accounts.push((*address, Some(acc.clone())))
65                    }
66                    AccountInfoRevert::DeleteIt => accounts.push((*address, None)),
67                    AccountInfoRevert::DoNothing => (),
68                }
69                if revert_account.wipe_storage || !revert_account.storage.is_empty() {
70                    storage.push(PlainStorageRevert {
71                        address: *address,
72                        wiped: revert_account.wipe_storage,
73                        storage_revert: revert_account
74                            .storage
75                            .iter()
76                            .map(|(k, v)| (*k, *v))
77                            .collect::<Vec<_>>(),
78                    });
79                }
80            }
81            state_reverts.accounts.push(accounts);
82            state_reverts.storage.push(storage);
83        }
84        state_reverts
85    }
86
87    /// Compare two Reverts instances, ignoring the order of elements
88    pub fn content_eq(&self, other: &Self) -> bool {
89        if self.0.len() != other.0.len() {
90            return false;
91        }
92
93        for (self_transition, other_transition) in self.0.iter().zip(other.0.iter()) {
94            if self_transition.len() != other_transition.len() {
95                return false;
96            }
97
98            let mut self_transition = self_transition.clone();
99            let mut other_transition = other_transition.clone();
100            // Sort both transitions
101            self_transition.sort_by(|(addr1, revert1), (addr2, revert2)| {
102                addr1.cmp(addr2).then_with(|| revert1.cmp(revert2))
103            });
104            other_transition.sort_by(|(addr1, revert1), (addr2, revert2)| {
105                addr1.cmp(addr2).then_with(|| revert1.cmp(revert2))
106            });
107
108            // Compare sorted transitions
109            if self_transition != other_transition {
110                return false;
111            }
112        }
113
114        true
115    }
116
117    /// Consume reverts and create [`PlainStateReverts`].
118    ///
119    /// Note that account are sorted by address.
120    #[deprecated = "Use `to_plain_state_reverts` instead"]
121    pub fn into_plain_state_reverts(self) -> PlainStateReverts {
122        self.to_plain_state_reverts()
123    }
124}
125
126impl PartialEq for Reverts {
127    fn eq(&self, other: &Self) -> bool {
128        self.content_eq(other)
129    }
130}
131
132/// Assumption is that Revert can return full state from any future state to any past state.
133///
134/// # Note
135/// It is created when new account state is applied to old account state.
136///
137/// And it is used to revert new account state to the old account state.
138///
139/// [AccountRevert] is structured in this way as we need to save it inside database.
140///
141/// And we need to be able to read it from database.
142#[derive(Clone, Default, Debug, PartialEq, Eq)]
143#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
144pub struct AccountRevert {
145    pub account: AccountInfoRevert,
146    pub storage: HashMap<U256, RevertToSlot>,
147    pub previous_status: AccountStatus,
148    pub wipe_storage: bool,
149}
150
151impl AccountRevert {
152    /// The approximate size of changes needed to store this account revert.
153    ///
154    /// `1 + storage_reverts_len`
155    pub fn size_hint(&self) -> usize {
156        1 + self.storage.len()
157    }
158
159    /// Very similar to new_selfdestructed but it will add additional zeros ([RevertToSlot::Destroyed])
160    /// for the storage that are set if account is again created.
161    pub fn new_selfdestructed_again(
162        status: AccountStatus,
163        account: AccountInfoRevert,
164        mut previous_storage: StorageWithOriginalValues,
165        updated_storage: StorageWithOriginalValues,
166    ) -> Self {
167        // Take present storage values as the storages that we are going to revert to.
168        // As those values got destroyed.
169        let mut previous_storage: HashMap<U256, RevertToSlot> = previous_storage
170            .drain()
171            .map(|(key, value)| (key, RevertToSlot::Some(value.present_value)))
172            .collect();
173        for (key, _) in updated_storage {
174            previous_storage
175                .entry(key)
176                .or_insert(RevertToSlot::Destroyed);
177        }
178        AccountRevert {
179            account,
180            storage: previous_storage,
181            previous_status: status,
182            wipe_storage: false,
183        }
184    }
185
186    /// Creates revert for states that were before selfdestruct.
187    pub fn new_selfdestructed_from_bundle(
188        account_info_revert: AccountInfoRevert,
189        bundle_account: &mut BundleAccount,
190        updated_storage: &StorageWithOriginalValues,
191    ) -> Option<Self> {
192        match bundle_account.status {
193            AccountStatus::InMemoryChange
194            | AccountStatus::Changed
195            | AccountStatus::LoadedEmptyEIP161
196            | AccountStatus::Loaded => {
197                let mut ret = AccountRevert::new_selfdestructed_again(
198                    bundle_account.status,
199                    account_info_revert,
200                    bundle_account.storage.drain().collect(),
201                    updated_storage.clone(),
202                );
203                ret.wipe_storage = true;
204                Some(ret)
205            }
206            _ => None,
207        }
208    }
209
210    /// Create new selfdestruct revert.
211    pub fn new_selfdestructed(
212        status: AccountStatus,
213        account: AccountInfoRevert,
214        mut storage: StorageWithOriginalValues,
215    ) -> Self {
216        // Zero all present storage values and save present values to AccountRevert.
217        let previous_storage = storage
218            .iter_mut()
219            .map(|(key, value)| {
220                // Take previous value and set ZERO as storage got destroyed.
221                (*key, RevertToSlot::Some(value.present_value))
222            })
223            .collect();
224
225        Self {
226            account,
227            storage: previous_storage,
228            previous_status: status,
229            wipe_storage: true,
230        }
231    }
232
233    /// Returns `true` if there is nothing to revert,
234    /// by checking that:
235    /// * both account info and storage have been left untouched
236    /// * we don't need to wipe storage
237    pub fn is_empty(&self) -> bool {
238        self.account == AccountInfoRevert::DoNothing
239            && self.storage.is_empty()
240            && !self.wipe_storage
241    }
242}
243
244/// Implements partial ordering for AccountRevert
245impl PartialOrd for AccountRevert {
246    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
247        Some(self.cmp(other))
248    }
249}
250
251/// Implements total ordering for AccountRevert
252impl Ord for AccountRevert {
253    fn cmp(&self, other: &Self) -> Ordering {
254        // First compare accounts
255        if let Some(ord) = self.account.partial_cmp(&other.account) {
256            if ord != Ordering::Equal {
257                return ord;
258            }
259        }
260
261        // Convert HashMaps to sorted vectors for comparison
262        let mut self_storage: Vec<_> = self.storage.iter().collect();
263        let mut other_storage: Vec<_> = other.storage.iter().collect();
264
265        // Sort by key and then by value
266        self_storage.sort_by(|(k1, v1), (k2, v2)| k1.cmp(k2).then_with(|| v1.cmp(v2)));
267        other_storage.sort_by(|(k1, v1), (k2, v2)| k1.cmp(k2).then_with(|| v1.cmp(v2)));
268
269        // Compare each element
270        for (self_entry, other_entry) in self_storage.iter().zip(other_storage.iter()) {
271            let key_ord = self_entry.0.cmp(other_entry.0);
272            if key_ord != Ordering::Equal {
273                return key_ord;
274            }
275            let value_ord = self_entry.1.cmp(other_entry.1);
276            if value_ord != Ordering::Equal {
277                return value_ord;
278            }
279        }
280
281        // If one vector is longer than the other, or if all elements are equal
282        self_storage
283            .len()
284            .cmp(&other_storage.len())
285            .then_with(|| self.previous_status.cmp(&other.previous_status))
286            .then_with(|| self.wipe_storage.cmp(&other.wipe_storage))
287    }
288}
289
290/// Depending on previous state of account info this
291/// will tell us what to do on revert.
292#[derive(Clone, Default, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
293#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
294pub enum AccountInfoRevert {
295    #[default]
296    /// Nothing changed
297    DoNothing,
298    /// Account was created and on revert we need to remove it with all storage.
299    DeleteIt,
300    /// Account was changed and on revert we need to put old state.
301    RevertTo(AccountInfo),
302}
303
304/// So storage can have multiple types:
305/// * Zero, on revert remove plain state.
306/// * Value, on revert set this value
307/// * Destroyed, should be removed on revert but on Revert set it as zero.
308///
309/// **Note**: It is completely different state if Storage is Zero or Some or if Storage was
310/// Destroyed.
311///
312/// Because if it is destroyed, previous values can be found in database or it can be zero.
313#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
314#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
315pub enum RevertToSlot {
316    Some(U256),
317    Destroyed,
318}
319
320impl RevertToSlot {
321    pub fn to_previous_value(self) -> U256 {
322        match self {
323            RevertToSlot::Some(value) => value,
324            RevertToSlot::Destroyed => U256::ZERO,
325        }
326    }
327}