Skip to main content

reth_trie_common/bundle_state/
bundle_state.rs

1use super::{
2    changes::{PlainStorageChangeset, StateChangeset},
3    reverts::{AccountInfoRevert, Reverts},
4    AccountRevert, AccountStatus, BundleAccount, PlainStateReverts, RevertToSlot, StorageSlot,
5    TransitionState,
6};
7use alloc::{
8    collections::{BTreeMap, BTreeSet},
9    vec::Vec,
10};
11use alloy_primitives::{
12    map::{hash_map::Entry, AddressMap, AddressSet, B256Map, HashMap, U256Map},
13    Address, B256, KECCAK256_EMPTY, U256,
14};
15use core::{mem, ops::RangeInclusive};
16use evm2::{bytecode::Bytecode, evm::AccountInfo};
17
18/// This builder is used to help to facilitate the initialization of `BundleState` struct
19#[derive(Debug)]
20pub struct BundleBuilder {
21    states: AddressSet,
22    state_original: AddressMap<AccountInfo>,
23    state_present: AddressMap<AccountInfo>,
24    state_storage: AddressMap<U256Map<(U256, U256)>>,
25
26    reverts: BTreeSet<(u64, Address)>,
27    revert_range: RangeInclusive<u64>,
28    revert_account: HashMap<(u64, Address), Option<Option<AccountInfo>>>,
29    revert_storage: HashMap<(u64, Address), Vec<(U256, U256)>>,
30
31    contracts: B256Map<Bytecode>,
32}
33
34/// Option for [`BundleState`] when converting it to the plain state.
35#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
36pub enum OriginalValuesKnown {
37    /// Checks changed with original values that [`BundleState`] has.
38    ///
39    /// If we don't expect parent blocks to be committed or unwinded from database, this option
40    /// should be used.
41    Yes,
42    /// Doesn't check original values, see the implementation of [`BundleState::to_plain_state`]
43    /// for more info.
44    ///
45    /// If the Bundle can be split or extended, we would not be sure about original values, in that
46    /// case this option should be used.
47    No,
48}
49impl OriginalValuesKnown {
50    /// Original value is not known for sure.
51    pub const fn is_not_known(&self) -> bool {
52        matches!(self, Self::No)
53    }
54}
55
56impl Default for BundleBuilder {
57    fn default() -> Self {
58        BundleBuilder {
59            states: AddressSet::default(),
60            state_original: AddressMap::default(),
61            state_present: AddressMap::default(),
62            state_storage: AddressMap::default(),
63            reverts: BTreeSet::new(),
64            revert_range: 0..=0,
65            revert_account: HashMap::default(),
66            revert_storage: HashMap::default(),
67            contracts: B256Map::default(),
68        }
69    }
70}
71
72impl BundleBuilder {
73    /// Creates builder instance.
74    ///
75    /// `revert_range` indicates the size of BundleState `reverts` field.
76    pub fn new(revert_range: RangeInclusive<u64>) -> Self {
77        BundleBuilder { revert_range, ..Default::default() }
78    }
79
80    /// Applies a transformation to the builder.
81    pub fn apply<F>(self, f: F) -> Self
82    where
83        F: FnOnce(Self) -> Self,
84    {
85        f(self)
86    }
87
88    /// Applies a mutable transformation to the builder.
89    pub fn apply_mut<F>(&mut self, f: F) -> &mut Self
90    where
91        F: FnOnce(&mut Self),
92    {
93        f(self);
94        self
95    }
96
97    /// Collects address info of BundleState state.
98    pub fn state_address(mut self, address: Address) -> Self {
99        self.set_state_address(address);
100        self
101    }
102
103    /// Collects account info of BundleState state.
104    pub fn state_original_account_info(mut self, address: Address, original: AccountInfo) -> Self {
105        self.set_state_original_account_info(address, original);
106        self
107    }
108
109    /// Collects account info of BundleState state.
110    pub fn state_present_account_info(mut self, address: Address, present: AccountInfo) -> Self {
111        self.set_state_present_account_info(address, present);
112        self
113    }
114
115    /// Collects storage info of BundleState state.
116    pub fn state_storage(mut self, address: Address, storage: U256Map<(U256, U256)>) -> Self {
117        self.set_state_storage(address, storage);
118        self
119    }
120
121    /// Collects address info of BundleState reverts.
122    ///
123    /// `block_number` must respect `revert_range`, or the input
124    /// will be ignored during the final build process.
125    pub fn revert_address(mut self, block_number: u64, address: Address) -> Self {
126        self.set_revert_address(block_number, address);
127        self
128    }
129
130    /// Collects account info of BundleState reverts.
131    ///
132    /// `block_number` must respect `revert_range`, or the input
133    /// will be ignored during the final build process.
134    pub fn revert_account_info(
135        mut self,
136        block_number: u64,
137        address: Address,
138        account: Option<Option<AccountInfo>>,
139    ) -> Self {
140        self.set_revert_account_info(block_number, address, account);
141        self
142    }
143
144    /// Collects storage info of BundleState reverts.
145    ///
146    /// `block_number` must respect `revert_range`, or the input
147    /// will be ignored during the final build process.
148    pub fn revert_storage(
149        mut self,
150        block_number: u64,
151        address: Address,
152        storage: Vec<(U256, U256)>,
153    ) -> Self {
154        self.set_revert_storage(block_number, address, storage);
155        self
156    }
157
158    /// Collects contracts info.
159    pub fn contract(mut self, address: B256, bytecode: Bytecode) -> Self {
160        self.set_contract(address, bytecode);
161        self
162    }
163
164    /// Sets address info of BundleState state.
165    pub fn set_state_address(&mut self, address: Address) -> &mut Self {
166        self.states.insert(address);
167        self
168    }
169
170    /// Sets original account info of BundleState state.
171    pub fn set_state_original_account_info(
172        &mut self,
173        address: Address,
174        original: AccountInfo,
175    ) -> &mut Self {
176        self.states.insert(address);
177        self.state_original.insert(address, original);
178        self
179    }
180
181    /// Sets present account info of BundleState state.
182    pub fn set_state_present_account_info(
183        &mut self,
184        address: Address,
185        present: AccountInfo,
186    ) -> &mut Self {
187        self.states.insert(address);
188        self.state_present.insert(address, present);
189        self
190    }
191
192    /// Sets storage info of BundleState state.
193    pub fn set_state_storage(
194        &mut self,
195        address: Address,
196        storage: U256Map<(U256, U256)>,
197    ) -> &mut Self {
198        self.states.insert(address);
199        self.state_storage.insert(address, storage);
200        self
201    }
202
203    /// Sets address info of BundleState reverts.
204    pub fn set_revert_address(&mut self, block_number: u64, address: Address) -> &mut Self {
205        self.reverts.insert((block_number, address));
206        self
207    }
208
209    /// Sets account info of BundleState reverts.
210    pub fn set_revert_account_info(
211        &mut self,
212        block_number: u64,
213        address: Address,
214        account: Option<Option<AccountInfo>>,
215    ) -> &mut Self {
216        self.reverts.insert((block_number, address));
217        self.revert_account.insert((block_number, address), account);
218        self
219    }
220
221    /// Sets storage info of BundleState reverts.
222    pub fn set_revert_storage(
223        &mut self,
224        block_number: u64,
225        address: Address,
226        storage: Vec<(U256, U256)>,
227    ) -> &mut Self {
228        self.reverts.insert((block_number, address));
229        self.revert_storage.insert((block_number, address), storage);
230        self
231    }
232
233    /// Sets contracts info.
234    pub fn set_contract(&mut self, address: B256, bytecode: Bytecode) -> &mut Self {
235        self.contracts.insert(address, bytecode);
236        self
237    }
238
239    /// Creates `BundleState` instance based on collected information.
240    pub fn build(mut self) -> BundleState {
241        let mut state_size = 0;
242        let state = self
243            .states
244            .into_iter()
245            .map(|address| {
246                let storage = self
247                    .state_storage
248                    .remove(&address)
249                    .map(|s| {
250                        s.into_iter()
251                            .map(|(k, (o_val, p_val))| (k, StorageSlot::new_changed(o_val, p_val)))
252                            .collect()
253                    })
254                    .unwrap_or_default();
255                let bundle_account = BundleAccount::new(
256                    self.state_original.remove(&address),
257                    self.state_present.remove(&address),
258                    storage,
259                    AccountStatus::Changed,
260                );
261                state_size += bundle_account.size_hint();
262                (address, bundle_account)
263            })
264            .collect();
265
266        let mut reverts_size = 0;
267        let mut reverts_map = BTreeMap::new();
268        for block_number in self.revert_range {
269            reverts_map.insert(block_number, Vec::new());
270        }
271        self.reverts.into_iter().for_each(|(block_number, address)| {
272            let account =
273                match self.revert_account.remove(&(block_number, address)).unwrap_or_default() {
274                    Some(Some(account)) => AccountInfoRevert::RevertTo(account),
275                    Some(None) => AccountInfoRevert::DeleteIt,
276                    None => AccountInfoRevert::DoNothing,
277                };
278            let storage = self
279                .revert_storage
280                .remove(&(block_number, address))
281                .map(|s| s.into_iter().map(|(k, v)| (k, RevertToSlot::Some(v))).collect())
282                .unwrap_or_default();
283            let account_revert = AccountRevert {
284                account,
285                storage,
286                previous_status: AccountStatus::Changed,
287                wipe_storage: false,
288            };
289
290            if let Some(vec) = reverts_map.get_mut(&block_number) {
291                reverts_size += account_revert.size_hint();
292                vec.push((address, account_revert));
293            }
294        });
295
296        BundleState {
297            state,
298            contracts: self.contracts,
299            reverts: Reverts::new(reverts_map.into_values().collect()),
300            state_size,
301            reverts_size,
302        }
303    }
304
305    /// Getter for `states` field
306    pub const fn get_states(&self) -> &AddressSet {
307        &self.states
308    }
309
310    /// Mutable getter for `states` field
311    pub const fn get_states_mut(&mut self) -> &mut AddressSet {
312        &mut self.states
313    }
314
315    /// Mutable getter for `state_original` field
316    pub const fn get_state_original_mut(&mut self) -> &mut AddressMap<AccountInfo> {
317        &mut self.state_original
318    }
319
320    /// Mutable getter for `state_present` field
321    pub const fn get_state_present_mut(&mut self) -> &mut AddressMap<AccountInfo> {
322        &mut self.state_present
323    }
324
325    /// Mutable getter for `state_storage` field
326    pub const fn get_state_storage_mut(&mut self) -> &mut AddressMap<U256Map<(U256, U256)>> {
327        &mut self.state_storage
328    }
329
330    /// Mutable getter for `reverts` field
331    pub const fn get_reverts_mut(&mut self) -> &mut BTreeSet<(u64, Address)> {
332        &mut self.reverts
333    }
334
335    /// Mutable getter for `revert_range` field
336    pub const fn get_revert_range_mut(&mut self) -> &mut RangeInclusive<u64> {
337        &mut self.revert_range
338    }
339
340    /// Mutable getter for `revert_account` field
341    pub const fn get_revert_account_mut(
342        &mut self,
343    ) -> &mut HashMap<(u64, Address), Option<Option<AccountInfo>>> {
344        &mut self.revert_account
345    }
346
347    /// Mutable getter for `revert_storage` field
348    pub const fn get_revert_storage_mut(
349        &mut self,
350    ) -> &mut HashMap<(u64, Address), Vec<(U256, U256)>> {
351        &mut self.revert_storage
352    }
353
354    /// Mutable getter for `contracts` field
355    pub const fn get_contracts_mut(&mut self) -> &mut B256Map<Bytecode> {
356        &mut self.contracts
357    }
358}
359
360/// Bundle retention policy for applying substate to the bundle.
361#[derive(Debug)]
362pub enum BundleRetention {
363    /// Only plain state is updated.
364    PlainState,
365    /// Both, plain state and reverts, are retained
366    Reverts,
367}
368
369impl BundleRetention {
370    /// Returns `true` if reverts should be retained.
371    pub const fn includes_reverts(&self) -> bool {
372        matches!(self, Self::Reverts)
373    }
374}
375
376/// Bundle state contain only values that got changed
377///
378/// For every account it contains both original and present state.
379///
380/// This is needed to decide if there were any changes to the account.
381///
382/// Changes are applied and reverts are created when TransitionState is applied to BundleState.
383///
384/// And can be used to revert BundleState to the state before transition.
385#[derive(Default, Clone, Debug, PartialEq, Eq)]
386#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
387pub struct BundleState {
388    /// Account state
389    pub state: AddressMap<BundleAccount>,
390    /// All created contracts in this block.
391    pub contracts: B256Map<Bytecode>,
392    /// Changes to revert
393    ///
394    /// **Note**: Inside vector is *not* sorted by address.
395    ///
396    /// But it is unique by address.
397    pub reverts: Reverts,
398    /// The size of the plain state in the bundle state
399    pub state_size: usize,
400    /// The size of reverts in the bundle state
401    pub reverts_size: usize,
402}
403
404impl BundleState {
405    /// Returns builder instance for further manipulation.
406    pub fn builder(revert_range: RangeInclusive<u64>) -> BundleBuilder {
407        BundleBuilder::new(revert_range)
408    }
409
410    /// Creates it with new and old values of both Storage and AccountInfo.
411    pub fn new(
412        state: impl IntoIterator<
413            Item = (Address, Option<AccountInfo>, Option<AccountInfo>, HashMap<U256, (U256, U256)>),
414        >,
415        reverts: impl IntoIterator<
416            Item = impl IntoIterator<
417                Item = (
418                    Address,
419                    Option<Option<AccountInfo>>,
420                    impl IntoIterator<Item = (U256, U256)>,
421                ),
422            >,
423        >,
424        contracts: impl IntoIterator<Item = (B256, Bytecode)>,
425    ) -> Self {
426        // Create state from iterator.
427        let mut state_size = 0;
428        let state = state
429            .into_iter()
430            .map(|(address, original, present, storage)| {
431                let account = BundleAccount::new(
432                    original,
433                    present,
434                    storage
435                        .into_iter()
436                        .map(|(k, (o_val, p_val))| (k, StorageSlot::new_changed(o_val, p_val)))
437                        .collect(),
438                    AccountStatus::Changed,
439                );
440                state_size += account.size_hint();
441                (address, account)
442            })
443            .collect();
444
445        // Create reverts from iterator.
446        let mut reverts_size = 0;
447        let reverts = reverts
448            .into_iter()
449            .map(|block_reverts| {
450                block_reverts
451                    .into_iter()
452                    .map(|(address, account, storage)| {
453                        let account = match account {
454                            Some(Some(account)) => AccountInfoRevert::RevertTo(account),
455                            Some(None) => AccountInfoRevert::DeleteIt,
456                            None => AccountInfoRevert::DoNothing,
457                        };
458                        let revert = AccountRevert {
459                            account,
460                            storage: storage
461                                .into_iter()
462                                .map(|(k, v)| (k, RevertToSlot::Some(v)))
463                                .collect(),
464                            previous_status: AccountStatus::Changed,
465                            wipe_storage: false,
466                        };
467                        reverts_size += revert.size_hint();
468                        (address, revert)
469                    })
470                    .collect::<Vec<_>>()
471            })
472            .collect::<Vec<_>>();
473
474        Self {
475            state,
476            contracts: contracts.into_iter().collect(),
477            reverts: Reverts::new(reverts),
478            state_size,
479            reverts_size,
480        }
481    }
482
483    /// Returns the approximate size of changes in the bundle state.
484    ///
485    /// The estimation is not precise, because the information about the number of
486    /// destroyed entries that need to be removed is not accessible to the bundle state.
487    pub fn size_hint(&self) -> usize {
488        self.state_size + self.reverts_size + self.contracts.len()
489    }
490
491    /// Returns reference to the state.
492    pub const fn state(&self) -> &AddressMap<BundleAccount> {
493        &self.state
494    }
495
496    /// Checks whether bundle state is empty.
497    pub fn is_empty(&self) -> bool {
498        self.len() == 0
499    }
500
501    /// Return number of changed accounts.
502    pub fn len(&self) -> usize {
503        self.state.len()
504    }
505
506    /// Gets account from state.
507    pub fn account(&self, address: &Address) -> Option<&BundleAccount> {
508        self.state.get(address)
509    }
510
511    /// Gets bytecode from state.
512    pub fn bytecode(&self, hash: &B256) -> Option<Bytecode> {
513        self.contracts.get(hash).cloned()
514    }
515
516    /// Gets storage value from state.
517    ///
518    /// Returns `None` if the account is not present in the bundle state or the slot is not known.
519    pub fn storage(&self, address: &Address, storage_key: U256) -> Option<U256> {
520        self.account(address).and_then(|account| account.storage_slot(storage_key))
521    }
522
523    /// Consumes [`TransitionState`] by applying the changes and creating the
524    /// reverts.
525    ///
526    /// If [`BundleRetention::includes_reverts`] is `true`, then the reverts will
527    /// be retained.
528    pub fn apply_transitions_and_create_reverts(
529        &mut self,
530        transitions: TransitionState,
531        retention: BundleRetention,
532    ) {
533        let include_reverts = retention.includes_reverts();
534        // Pessimistically pre-allocate assuming _all_ accounts changed.
535        let reverts_capacity = if include_reverts { transitions.transitions.len() } else { 0 };
536        let mut reverts = Vec::with_capacity(reverts_capacity);
537
538        self.state.reserve(transitions.transitions.len());
539        for (address, transition) in transitions.transitions.into_iter() {
540            // Add new contract if it was created/changed.
541            if let Some((hash, new_bytecode)) = transition.has_new_contract() {
542                self.contracts.insert(hash, new_bytecode.clone());
543            }
544            // Update state and create revert.
545            let revert = match self.state.entry(address) {
546                Entry::Occupied(mut entry) => {
547                    let entry = entry.get_mut();
548                    self.state_size -= entry.size_hint();
549                    // Update and create revert if it is present
550                    let revert = entry.update_and_create_revert(transition);
551                    // Update the state size
552                    self.state_size += entry.size_hint();
553                    revert
554                }
555                Entry::Vacant(entry) => {
556                    // Make revert from transition account
557                    let present_bundle = transition.present_bundle_account();
558                    let revert = transition.create_revert();
559                    if revert.is_some() {
560                        self.state_size += present_bundle.size_hint();
561                        entry.insert(present_bundle);
562                    }
563                    revert
564                }
565            };
566
567            // Append revert if present.
568            if let Some(revert) = revert.filter(|_| include_reverts) {
569                self.reverts_size += revert.size_hint();
570                reverts.push((address, revert));
571            }
572        }
573
574        self.reverts.push(reverts);
575    }
576
577    /// Generate a [`StateChangeset`] from the bundle state without consuming
578    /// it.
579    pub fn to_plain_state(&self, is_value_known: OriginalValuesKnown) -> StateChangeset {
580        // Pessimistically pre-allocate assuming _all_ accounts changed.
581        let state_len = self.state.len();
582        let mut accounts = Vec::with_capacity(state_len);
583        let mut storage = Vec::with_capacity(state_len);
584
585        for (address, account) in &self.state {
586            // Append account info if it is changed.
587            let was_destroyed = account.was_destroyed();
588            if is_value_known.is_not_known() || account.is_info_changed() {
589                let info =
590                    account.info.as_ref().map(|info| AccountInfo { code: None, ..info.clone() });
591                accounts.push((*address, info));
592            }
593
594            // Append storage changes
595
596            // Note: Assumption is that revert is going to remove whole plain storage from
597            // database so we can check if plain state was wiped or not.
598            let mut account_storage_changed = Vec::with_capacity(account.storage.len());
599
600            for (&key, &slot) in account.storage.iter() {
601                // If storage was destroyed that means that storage was wiped.
602                // In that case we need to check if present storage value is different then ZERO.
603                let destroyed_and_not_zero = was_destroyed && !slot.present_value.is_zero();
604
605                // If account is not destroyed check if original values was changed,
606                // so we can update it.
607                let not_destroyed_and_changed = !was_destroyed && slot.is_changed();
608
609                if is_value_known.is_not_known() ||
610                    destroyed_and_not_zero ||
611                    not_destroyed_and_changed
612                {
613                    account_storage_changed.push((key, slot.present_value));
614                }
615            }
616
617            if !account_storage_changed.is_empty() || was_destroyed {
618                // Append storage changes to account.
619                storage.push(PlainStorageChangeset {
620                    address: *address,
621                    wipe_storage: was_destroyed,
622                    storage: account_storage_changed,
623                });
624            }
625        }
626
627        let contracts = self
628            .contracts
629            .iter()
630            // Remove empty bytecodes
631            .filter(|(b, _)| **b != KECCAK256_EMPTY)
632            .map(|(b, code)| (*b, code.clone()))
633            .collect::<Vec<_>>();
634        StateChangeset { accounts, storage, contracts }
635    }
636
637    /// Generates a [`StateChangeset`] and [`PlainStateReverts`] from the bundle
638    /// state.
639    pub fn to_plain_state_and_reverts(
640        &self,
641        is_value_known: OriginalValuesKnown,
642    ) -> (StateChangeset, PlainStateReverts) {
643        (self.to_plain_state(is_value_known), self.reverts.to_plain_state_reverts())
644    }
645
646    /// Consumes the bundle state and split it into a [`StateChangeset`] and a
647    /// [`PlainStateReverts`].
648    #[deprecated = "Use `to_plain_state_and_reverts` instead"]
649    pub fn into_plain_state_and_reverts(
650        self,
651        is_value_known: OriginalValuesKnown,
652    ) -> (StateChangeset, PlainStateReverts) {
653        self.to_plain_state_and_reverts(is_value_known)
654    }
655
656    /// Extends the bundle with other state.
657    ///
658    /// Updates the `other` state only if `other` is not flagged as destroyed.
659    pub fn extend_state(&mut self, other_state: AddressMap<BundleAccount>) {
660        self.state.reserve(other_state.len());
661        for (address, other_account) in other_state {
662            match self.state.entry(address) {
663                Entry::Occupied(mut entry) => {
664                    let this = entry.get_mut();
665                    self.state_size -= this.size_hint();
666
667                    // If other was destroyed. replace `this` storage with
668                    // the `other one.
669                    if other_account.was_destroyed() {
670                        this.storage = other_account.storage;
671                    } else {
672                        // Otherwise extend this storage with other
673                        this.storage.reserve(other_account.storage.len());
674                        for (key, storage_slot) in other_account.storage {
675                            // Update present value or insert storage slot.
676                            this.storage.entry(key).or_insert(storage_slot).present_value =
677                                storage_slot.present_value;
678                        }
679                    }
680                    this.info = other_account.info;
681                    this.status.transition(other_account.status);
682
683                    // Update the state size
684                    self.state_size += this.size_hint();
685                }
686                Entry::Vacant(entry) => {
687                    // Just insert if empty
688                    self.state_size += other_account.size_hint();
689                    entry.insert(other_account);
690                }
691            }
692        }
693    }
694    /// Extends the state with state that is build on top of it.
695    ///
696    /// If storage was wiped in `other` state, copy `this` plain state
697    /// and put it inside `other` revert (if there is no duplicates of course).
698    ///
699    /// If `this` and `other` accounts were both destroyed invalidate second
700    /// wipe flag (from `other`).
701    ///
702    /// As wiping from database should be done only once
703    /// and we already transferred all potentially missing storages to the `other` revert.
704    pub fn extend(&mut self, mut other: Self) {
705        // Iterate over reverts and if its storage is wiped try to add previous bundle
706        // state as there is potential missing slots.
707        let mut seen = AddressSet::default();
708        for (address, revert) in other.reverts.iter_mut().flatten() {
709            // `other` was built on a fresh bundle, so its first revert for an account records the
710            // account as freshly loaded. Revert to the status this bundle accumulated instead.
711            if seen.insert(*address) &&
712                let Some(this_account) = self.state.get(address)
713            {
714                revert.previous_status = this_account.status;
715            }
716
717            if revert.wipe_storage {
718                // If there is wipe storage in `other` revert
719                // we need to move storage from present state.
720                if let Some(this_account) = self.state.get_mut(address) {
721                    // As this account was destroyed inside `other` bundle.
722                    // We are fine to wipe/drain this storage and put it inside revert.
723                    // A `Destroyed` slot in `other` means the value before the wipe, which is
724                    // this bundle's present value, not the database value.
725                    for (key, value) in this_account.storage.drain() {
726                        let previous = RevertToSlot::Some(value.present_value);
727                        revert
728                            .storage
729                            .entry(key)
730                            .and_modify(|slot| {
731                                if *slot == RevertToSlot::Destroyed {
732                                    *slot = previous;
733                                }
734                            })
735                            .or_insert(previous);
736                    }
737
738                    // Nullify `other` wipe as primary database wipe is done in `this`.
739                    if this_account.was_destroyed() {
740                        revert.wipe_storage = false;
741                    }
742                }
743            }
744
745            // Increment reverts size for each of the updated reverts.
746            self.reverts_size += revert.size_hint();
747        }
748        // Extension of state
749        self.extend_state(other.state);
750        // Contract can be just extended, when counter is introduced we will take into account that.
751        self.contracts.extend(other.contracts);
752        // Reverts can be just extended
753        self.reverts.extend(other.reverts);
754    }
755
756    /// Takes first N raw reverts from the [`BundleState`].
757    pub fn take_n_reverts(&mut self, reverts_to_take: usize) -> Reverts {
758        // Split is done as [0, num) and [num, len].
759        if reverts_to_take > self.reverts.len() {
760            return self.take_all_reverts();
761        }
762        let this = self.reverts.split_off(reverts_to_take);
763        self.reverts_size =
764            this.iter().flatten().fold(0, |acc, (_, revert)| acc + revert.size_hint());
765        mem::replace(&mut self.reverts, Reverts::new(this))
766    }
767
768    /// Returns and clears all reverts from [`BundleState`].
769    pub fn take_all_reverts(&mut self) -> Reverts {
770        self.reverts_size = 0;
771        mem::take(&mut self.reverts)
772    }
773
774    /// Reverts the state changes of the latest transition.
775    ///
776    /// **Note**: This is the same as `BundleState::revert(1)`
777    ///
778    /// Returns true if the state was reverted.
779    pub fn revert_latest(&mut self) -> bool {
780        // Revert the latest recorded state
781        if let Some(reverts) = self.reverts.pop() {
782            for (address, revert_account) in reverts.into_iter() {
783                self.reverts_size -= revert_account.size_hint();
784                match self.state.entry(address) {
785                    Entry::Occupied(mut entry) => {
786                        let account = entry.get_mut();
787                        self.state_size -= account.size_hint();
788                        if account.revert(revert_account) {
789                            entry.remove();
790                        } else {
791                            self.state_size += account.size_hint();
792                        }
793                    }
794                    Entry::Vacant(entry) => {
795                        // Create empty account that we will revert on.
796                        // Only place where this account is not existing is if revert is DeleteIt.
797                        let mut account = BundleAccount::new(
798                            None,
799                            None,
800                            HashMap::default(),
801                            AccountStatus::LoadedNotExisting,
802                        );
803                        if !account.revert(revert_account) {
804                            self.state_size += account.size_hint();
805                            entry.insert(account);
806                        }
807                    }
808                }
809            }
810            return true;
811        }
812
813        false
814    }
815
816    /// Reverts the state changes by N transitions back.
817    ///
818    /// See also [`Self::revert_latest`]
819    pub fn revert(&mut self, mut num_transitions: usize) {
820        if num_transitions == 0 {
821            return;
822        }
823
824        while self.revert_latest() {
825            num_transitions -= 1;
826            if num_transitions == 0 {
827                // Break the loop.
828                break;
829            }
830        }
831    }
832
833    /// Prepends present the state with the given [`BundleState`].
834    ///
835    /// It adds changes from the given state but does not override any existing changes.
836    ///
837    /// Reverts are not updated.
838    pub fn prepend_state(&mut self, mut other: BundleState) {
839        // Take this bundle
840        let this_bundle = mem::take(self);
841        // Extend other bundle state with this
842        other.extend_state(this_bundle.state);
843        // Extend other contracts
844        other.contracts.extend(this_bundle.contracts);
845        // Swap bundles
846        mem::swap(self, &mut other)
847    }
848}
849
850#[cfg(test)]
851mod tests {
852    use super::*;
853    use crate::bundle_state::{StorageWithOriginalValues, TransitionAccount};
854
855    #[test]
856    fn transition_states() {
857        // Dummy data
858        let address = Address::new([0x01; 20]);
859        let acc1 = AccountInfo { balance: U256::from(10), nonce: 1, ..Default::default() };
860
861        let mut bundle_state = BundleState::default();
862
863        // Have transition from loaded to all other states
864
865        let transition = TransitionAccount {
866            info: Some(acc1),
867            status: AccountStatus::InMemoryChange,
868            previous_info: None,
869            previous_status: AccountStatus::LoadedNotExisting,
870            storage: StorageWithOriginalValues::default(),
871            storage_was_destroyed: false,
872        };
873
874        // Apply first transition
875        bundle_state.apply_transitions_and_create_reverts(
876            TransitionState::single(address, transition.clone()),
877            BundleRetention::Reverts,
878        );
879    }
880
881    const fn account1() -> Address {
882        Address::new([0x60; 20])
883    }
884
885    const fn account2() -> Address {
886        Address::new([0x61; 20])
887    }
888
889    fn slot1() -> U256 {
890        U256::from(5)
891    }
892
893    fn slot2() -> U256 {
894        U256::from(7)
895    }
896
897    /// Tests bundle one.
898    fn test_bundle1() -> BundleState {
899        // Block changes
900        BundleState::new(
901            vec![
902                (
903                    account1(),
904                    None,
905                    Some(AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() }),
906                    HashMap::from_iter([
907                        (slot1(), (U256::from(0), U256::from(10))),
908                        (slot2(), (U256::from(0), U256::from(15))),
909                    ]),
910                ),
911                (
912                    account2(),
913                    None,
914                    Some(AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() }),
915                    HashMap::default(),
916                ),
917            ],
918            vec![vec![
919                (account1(), Some(None), vec![(slot1(), U256::from(0)), (slot2(), U256::from(0))]),
920                (account2(), Some(None), vec![]),
921            ]],
922            vec![],
923        )
924    }
925
926    /// Tests bundle two.
927    fn test_bundle2() -> BundleState {
928        // Block changes
929        BundleState::new(
930            vec![(
931                account1(),
932                None,
933                Some(AccountInfo { nonce: 3, balance: U256::from(20), ..Default::default() }),
934                HashMap::from_iter([(slot1(), (U256::from(0), U256::from(15)))]),
935            )],
936            vec![vec![(
937                account1(),
938                Some(Some(AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() })),
939                vec![(slot1(), U256::from(10))],
940            )]],
941            vec![],
942        )
943    }
944
945    /// Tests bundle three.
946    fn test_bundle3() -> BundleState {
947        BundleState::builder(0..=0)
948            .state_present_account_info(
949                account1(),
950                AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() },
951            )
952            .state_storage(
953                account1(),
954                HashMap::from_iter([(slot1(), (U256::from(0), U256::from(10)))]),
955            )
956            .state_address(account2())
957            .state_present_account_info(
958                account2(),
959                AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() },
960            )
961            .revert_address(0, account1())
962            .revert_account_info(0, account1(), Some(None))
963            .revert_storage(0, account1(), vec![(slot1(), U256::from(0))])
964            .revert_account_info(0, account2(), Some(None))
965            .build()
966    }
967
968    /// Tests bundle four.
969    fn test_bundle4() -> BundleState {
970        BundleState::builder(0..=0)
971            .state_present_account_info(
972                account1(),
973                AccountInfo { nonce: 3, balance: U256::from(20), ..Default::default() },
974            )
975            .state_storage(
976                account1(),
977                HashMap::from_iter([(slot1(), (U256::from(0), U256::from(15)))]),
978            )
979            .revert_address(0, account1())
980            .revert_account_info(
981                0,
982                account1(),
983                Some(Some(AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() })),
984            )
985            .revert_storage(0, account1(), vec![(slot1(), U256::from(10))])
986            .build()
987    }
988
989    /// Per-block bundles are built on a fresh bundle, so merging them must still revert an account
990    /// to the status accumulated over the earlier blocks.
991    #[test]
992    fn extend_reverts_to_accumulated_status() {
993        let address = Address::new([0x70; 20]);
994        let info = AccountInfo { nonce: 1, balance: U256::from(10), ..Default::default() };
995        let destroy = TransitionAccount {
996            info: None,
997            status: AccountStatus::Destroyed,
998            previous_info: Some(info.clone()),
999            previous_status: AccountStatus::Loaded,
1000            storage: HashMap::from_iter([(
1001                slot1(),
1002                StorageSlot::new_changed(U256::from(3), U256::ZERO),
1003            )]),
1004            storage_was_destroyed: true,
1005        };
1006        let recreate = TransitionAccount {
1007            info: Some(info),
1008            status: AccountStatus::InMemoryChange,
1009            previous_info: None,
1010            previous_status: AccountStatus::LoadedNotExisting,
1011            storage: HashMap::from_iter([(
1012                slot2(),
1013                StorageSlot::new_changed(U256::ZERO, U256::from(5)),
1014            )]),
1015            storage_was_destroyed: false,
1016        };
1017        let block_bundle = |transition| {
1018            let mut bundle = BundleState::default();
1019            bundle.apply_transitions_and_create_reverts(
1020                TransitionState::single(address, transition),
1021                BundleRetention::Reverts,
1022            );
1023            bundle
1024        };
1025
1026        let first = block_bundle(destroy);
1027        let mut merged = first.clone();
1028        merged.extend(block_bundle(recreate.clone()));
1029
1030        // A single bundle built over both blocks tracks the status across them.
1031        let mut cumulative = first.clone();
1032        cumulative.apply_transitions_and_create_reverts(
1033            TransitionState::single(
1034                address,
1035                TransitionAccount {
1036                    status: AccountStatus::DestroyedChanged,
1037                    previous_status: AccountStatus::Destroyed,
1038                    ..recreate
1039                },
1040            ),
1041            BundleRetention::Reverts,
1042        );
1043        assert_eq!(merged.state[&address].status, AccountStatus::DestroyedChanged);
1044        assert_eq!(merged.reverts, cumulative.reverts);
1045
1046        merged.revert(1);
1047        cumulative.revert(1);
1048        let account = &merged.state[&address];
1049        assert_eq!(account.status, AccountStatus::Destroyed);
1050        assert!(account.was_destroyed());
1051        assert_eq!(merged, cumulative);
1052    }
1053
1054    fn sanity_path(bundle1: BundleState, bundle2: BundleState) {
1055        let mut extended = bundle1.clone();
1056        extended.extend(bundle2.clone());
1057
1058        let mut reverted = extended.clone();
1059        // Revert zero does nothing.
1060        reverted.revert(0);
1061        assert_eq!(reverted, extended);
1062
1063        // Revert by one gives us bundle one.
1064        reverted.revert(1);
1065        assert_eq!(reverted, bundle1);
1066
1067        // Reverted by additional one gives us empty bundle.
1068        reverted.revert(1);
1069        assert_eq!(reverted, BundleState::default());
1070
1071        let mut reverted = extended.clone();
1072
1073        // Reverted by bigger number gives us empty bundle
1074        reverted.revert(10);
1075        assert_eq!(reverted, BundleState::default());
1076    }
1077
1078    #[test]
1079    fn extend_on_destroyed_values() {
1080        let base_bundle1 = test_bundle1();
1081        let base_bundle2 = test_bundle2();
1082
1083        // test1
1084        // bundle1 has Destroyed
1085        // bundle2 has Changed
1086        // end should be DestroyedChanged.
1087        let mut b1 = base_bundle1.clone();
1088        let mut b2 = base_bundle2.clone();
1089        b1.state.get_mut(&account1()).unwrap().status = AccountStatus::Destroyed;
1090        b2.state.get_mut(&account1()).unwrap().status = AccountStatus::Changed;
1091        b1.extend(b2);
1092        assert_eq!(b1.state.get_mut(&account1()).unwrap().status, AccountStatus::DestroyedChanged);
1093
1094        // test2
1095        // bundle1 has Changed
1096        // bundle2 has Destroyed
1097        // end should be Destroyed
1098        let mut b1 = base_bundle1.clone();
1099        let mut b2 = base_bundle2.clone();
1100        b1.state.get_mut(&account1()).unwrap().status = AccountStatus::Changed;
1101        b2.state.get_mut(&account1()).unwrap().status = AccountStatus::Destroyed;
1102        b2.reverts[0][0].1.wipe_storage = true;
1103        b1.extend(b2);
1104        assert_eq!(b1.state.get_mut(&account1()).unwrap().status, AccountStatus::Destroyed);
1105
1106        // test2 extension
1107        // revert of b2 should contains plain state of b1.
1108        let mut revert1 = base_bundle2.reverts[0][0].clone();
1109        revert1.1.wipe_storage = true;
1110        revert1.1.storage.insert(slot2(), RevertToSlot::Some(U256::from(15)));
1111
1112        assert_eq!(b1.reverts.as_ref(), vec![base_bundle1.reverts[0].clone(), vec![revert1]],);
1113
1114        // test3
1115        // bundle1 has InMemoryChange
1116        // bundle2 has Change
1117        // end should be InMemoryChange.
1118
1119        let mut b1 = base_bundle1.clone();
1120        let mut b2 = base_bundle2.clone();
1121        b1.state.get_mut(&account1()).unwrap().status = AccountStatus::InMemoryChange;
1122        b2.state.get_mut(&account1()).unwrap().status = AccountStatus::Changed;
1123        b1.extend(b2);
1124        assert_eq!(b1.state.get_mut(&account1()).unwrap().status, AccountStatus::InMemoryChange);
1125    }
1126
1127    #[test]
1128    fn extend_replaces_destroyed_revert_with_previous_value() {
1129        // bundle1 writes slot1 = 10 and slot2 = 15; bundle2 selfdestructs and re-creates
1130        // account1, so its revert wipes storage and marks slot1 as destroyed.
1131        let mut b1 = test_bundle1();
1132        let mut b2 = test_bundle2();
1133        b2.state.get_mut(&account1()).unwrap().status = AccountStatus::DestroyedChanged;
1134        let revert = &mut b2.reverts[0][0].1;
1135        revert.wipe_storage = true;
1136        revert.storage.insert(slot1(), RevertToSlot::Destroyed);
1137
1138        b1.extend(b2);
1139        let revert = &b1.reverts[1][0].1;
1140        assert!(revert.wipe_storage);
1141        assert_eq!(revert.storage.get(&slot1()), Some(&RevertToSlot::Some(U256::from(10))));
1142        assert_eq!(revert.storage.get(&slot2()), Some(&RevertToSlot::Some(U256::from(15))));
1143    }
1144
1145    #[test]
1146    fn test_sanity_path() {
1147        sanity_path(test_bundle1(), test_bundle2());
1148        sanity_path(test_bundle3(), test_bundle4());
1149    }
1150
1151    #[test]
1152    fn test_multi_reverts_with_delete() {
1153        let mut state = BundleBuilder::new(0..=3)
1154            .revert_address(0, account1())
1155            .revert_account_info(2, account1(), Some(Some(AccountInfo::default())))
1156            .revert_account_info(3, account1(), Some(None))
1157            .build();
1158
1159        state.revert_latest();
1160        // State for account one was deleted
1161        assert_eq!(state.state.get(&account1()), None);
1162
1163        state.revert_latest();
1164        // State is set to
1165        assert_eq!(
1166            state.state.get(&account1()),
1167            Some(&BundleAccount::new(
1168                None,
1169                Some(AccountInfo::default()),
1170                HashMap::default(),
1171                AccountStatus::Changed
1172            ))
1173        );
1174    }
1175
1176    #[test]
1177    fn test_revert_capacity() {
1178        let state = BundleState::builder(0..=3)
1179            .revert_address(0, account1())
1180            .revert_address(2, account2())
1181            .revert_account_info(0, account1(), Some(None))
1182            .revert_account_info(2, account2(), None)
1183            .revert_storage(0, account1(), vec![(slot1(), U256::from(10))])
1184            .build();
1185
1186        assert_eq!(state.reverts.len(), 4);
1187        assert_eq!(state.reverts[1], vec![]);
1188        assert_eq!(state.reverts[3], vec![]);
1189        assert_eq!(state.reverts[0].len(), 1);
1190        assert_eq!(state.reverts[2].len(), 1);
1191
1192        let (addr1, revert1) = &state.reverts[0][0];
1193        assert_eq!(addr1, &account1());
1194        assert_eq!(revert1.account, AccountInfoRevert::DeleteIt);
1195
1196        let (addr2, revert2) = &state.reverts[2][0];
1197        assert_eq!(addr2, &account2());
1198        assert_eq!(revert2.account, AccountInfoRevert::DoNothing);
1199    }
1200
1201    #[test]
1202    fn take_reverts() {
1203        let bundle1 = test_bundle1();
1204        let bundle2 = test_bundle2();
1205
1206        let mut extended = bundle1.clone();
1207        extended.extend(bundle2.clone());
1208
1209        // Check that we have two reverts
1210        assert_eq!(extended.reverts.len(), 2);
1211
1212        // Take all by big N
1213        let mut extended2 = extended.clone();
1214        assert_eq!(extended2.take_n_reverts(100), extended.reverts);
1215
1216        // Take all reverts
1217        let mut extended2 = extended.clone();
1218        assert_eq!(extended2.take_all_reverts(), extended.reverts);
1219
1220        // Take zero revert
1221        let taken_reverts = extended.take_n_reverts(0);
1222        assert_eq!(taken_reverts, Reverts::default());
1223        assert_eq!(extended.reverts.len(), 2);
1224
1225        // Take one revert
1226        let taken_reverts = extended.take_n_reverts(1);
1227        assert_eq!(taken_reverts, bundle1.reverts);
1228
1229        // Take last revert
1230        let taken_reverts = extended.take_n_reverts(1);
1231        assert_eq!(taken_reverts, bundle2.reverts);
1232    }
1233
1234    #[test]
1235    fn prepend_state() {
1236        let address1 = account1();
1237        let address2 = account2();
1238
1239        let account1 = AccountInfo { nonce: 1, ..Default::default() };
1240        let account1_changed = AccountInfo { nonce: 1, ..Default::default() };
1241        let account2 = AccountInfo { nonce: 1, ..Default::default() };
1242
1243        let present_state = BundleState::builder(2..=2)
1244            .state_present_account_info(address1, account1_changed.clone())
1245            .build();
1246        assert_eq!(present_state.reverts.len(), 1);
1247        let previous_state = BundleState::builder(1..=1)
1248            .state_present_account_info(address1, account1)
1249            .state_present_account_info(address2, account2.clone())
1250            .build();
1251        assert_eq!(previous_state.reverts.len(), 1);
1252
1253        let mut test = present_state;
1254
1255        test.prepend_state(previous_state);
1256
1257        assert_eq!(test.state.len(), 2);
1258        // Reverts num should stay the same.
1259        assert_eq!(test.reverts.len(), 1);
1260        // Account1 is not overwritten.
1261        assert_eq!(test.state.get(&address1).unwrap().info, Some(account1_changed));
1262        // Account2 got inserted
1263        assert_eq!(test.state.get(&address2).unwrap().info, Some(account2));
1264    }
1265
1266    #[test]
1267    fn test_getters() {
1268        let mut builder = BundleBuilder::new(0..=3);
1269
1270        // Test get_states and get_states_mut
1271        assert!(builder.get_states().is_empty());
1272        builder.get_states_mut().insert(account1());
1273        assert!(builder.get_states().contains(&account1()));
1274
1275        // Test get_state_original_mut
1276        assert!(builder.get_state_original_mut().is_empty());
1277        builder.get_state_original_mut().insert(account1(), AccountInfo::default());
1278        assert!(builder.get_state_original_mut().contains_key(&account1()));
1279
1280        // Test get_state_present_mut
1281        assert!(builder.get_state_present_mut().is_empty());
1282        builder.get_state_present_mut().insert(account1(), AccountInfo::default());
1283        assert!(builder.get_state_present_mut().contains_key(&account1()));
1284
1285        // Test get_state_storage_mut
1286        assert!(builder.get_state_storage_mut().is_empty());
1287        builder.get_state_storage_mut().insert(account1(), HashMap::default());
1288        assert!(builder.get_state_storage_mut().contains_key(&account1()));
1289
1290        // Test get_reverts_mut
1291        assert!(builder.get_reverts_mut().is_empty());
1292        builder.get_reverts_mut().insert((0, account1()));
1293        assert!(builder.get_reverts_mut().contains(&(0, account1())));
1294
1295        // Test get_revert_range_mut
1296        assert_eq!(builder.get_revert_range_mut().clone(), 0..=3);
1297
1298        // Test get_revert_account_mut
1299        assert!(builder.get_revert_account_mut().is_empty());
1300        builder.get_revert_account_mut().insert((0, account1()), Some(None));
1301        assert!(builder.get_revert_account_mut().contains_key(&(0, account1())));
1302
1303        // Test get_revert_storage_mut
1304        assert!(builder.get_revert_storage_mut().is_empty());
1305        builder.get_revert_storage_mut().insert((0, account1()), vec![(slot1(), U256::from(0))]);
1306        assert!(builder.get_revert_storage_mut().contains_key(&(0, account1())));
1307
1308        // Test get_contracts_mut
1309        assert!(builder.get_contracts_mut().is_empty());
1310        builder.get_contracts_mut().insert(B256::default(), Bytecode::default());
1311        assert!(builder.get_contracts_mut().contains_key(&B256::default()));
1312    }
1313}