Skip to main content

revm_database/states/
transition_state.rs

1use std::borrow::Cow;
2
3use super::{StorageSlot, TransitionAccount};
4use primitives::{hash_map::Entry, Address, AddressMap, HashMap};
5use state::EvmStorage;
6
7/// State of accounts in transition between transaction executions.
8#[derive(Clone, Default, Debug, PartialEq, Eq)]
9pub struct TransitionState {
10    /// Block state account with account state
11    pub transitions: AddressMap<TransitionAccount>,
12}
13
14impl TransitionState {
15    /// Create new transition state containing one [`TransitionAccount`].
16    pub fn single(address: Address, transition: TransitionAccount) -> Self {
17        let mut transitions = HashMap::default();
18        transitions.insert(address, transition);
19        TransitionState { transitions }
20    }
21
22    /// Take the contents of this [`TransitionState`] and replace it with an
23    /// empty one.
24    ///
25    /// See [core::mem::take].
26    pub fn take(&mut self) -> TransitionState {
27        core::mem::take(self)
28    }
29
30    /// Clear the transition state.
31    pub fn clear(&mut self) {
32        self.transitions.clear();
33    }
34
35    /// Add transitions to the transition state.
36    ///
37    /// This will insert new [`TransitionAccount`]s, or update existing ones via
38    /// [`update`][TransitionAccount::update].
39    pub fn add_transitions<'a>(
40        &mut self,
41        transitions: impl IntoIterator<Item = (Address, TransitionAccount<Option<Cow<'a, EvmStorage>>>)>,
42    ) {
43        let transitions = transitions.into_iter();
44        if let Some(upper) = transitions.size_hint().1 {
45            self.transitions.reserve(upper);
46        }
47        for (address, account) in transitions {
48            self.add_transition(address, account);
49        }
50    }
51
52    /// Add one transition to the transition state.
53    pub fn add_transition(
54        &mut self,
55        address: Address,
56        account: TransitionAccount<Option<Cow<'_, EvmStorage>>>,
57    ) {
58        match self.transitions.entry(address) {
59            Entry::Occupied(entry) => entry.into_mut().update(account),
60            Entry::Vacant(entry) => {
61                _ = entry.insert(account.map_storage(|storage| {
62                    storage
63                        .map(|storage| {
64                            storage
65                                .iter()
66                                .filter_map(|(key, slot)| {
67                                    slot.is_changed().then_some((
68                                        *key,
69                                        StorageSlot::new_changed(
70                                            slot.original_value,
71                                            slot.present_value,
72                                        ),
73                                    ))
74                                })
75                                .collect()
76                        })
77                        .unwrap_or_default()
78                }))
79            }
80        }
81    }
82}