reth_provider/bundle_state/
state_reverts.rs

1use alloy_primitives::B256;
2use revm_database::states::RevertToSlot;
3use revm_state::FlaggedStorage;
4use std::iter::Peekable;
5
6/// Iterator over storage reverts.
7/// See [`StorageRevertsIter::next`] for more details.
8#[expect(missing_debug_implementations)]
9pub struct StorageRevertsIter<R: Iterator, W: Iterator> {
10    reverts: Peekable<R>,
11    wiped: Peekable<W>,
12}
13
14impl<R, W> StorageRevertsIter<R, W>
15where
16    R: Iterator<Item = (B256, RevertToSlot)>,
17    W: Iterator<Item = (B256, FlaggedStorage)>,
18{
19    /// Create a new iterator over storage reverts.
20    pub fn new(
21        reverts: impl IntoIterator<IntoIter = R>,
22        wiped: impl IntoIterator<IntoIter = W>,
23    ) -> Self {
24        Self { reverts: reverts.into_iter().peekable(), wiped: wiped.into_iter().peekable() }
25    }
26
27    /// Consume next revert and return it.
28    fn next_revert(&mut self) -> Option<(B256, FlaggedStorage)> {
29        self.reverts.next().map(|(key, revert)| (key, revert.to_previous_value()))
30    }
31
32    /// Consume next wiped storage and return it.
33    fn next_wiped(&mut self) -> Option<(B256, FlaggedStorage)> {
34        self.wiped.next()
35    }
36}
37
38impl<R, W> Iterator for StorageRevertsIter<R, W>
39where
40    R: Iterator<Item = (B256, RevertToSlot)>,
41    W: Iterator<Item = (B256, FlaggedStorage)>,
42{
43    type Item = (B256, FlaggedStorage);
44
45    /// Iterate over storage reverts and wiped entries and return items in the sorted order.
46    /// NOTE: The implementation assumes that inner iterators are already sorted.
47    fn next(&mut self) -> Option<Self::Item> {
48        match (self.reverts.peek(), self.wiped.peek()) {
49            (Some(revert), Some(wiped)) => {
50                // Compare the keys and return the lesser.
51                use std::cmp::Ordering;
52                match revert.0.cmp(&wiped.0) {
53                    Ordering::Less => self.next_revert(),
54                    Ordering::Greater => self.next_wiped(),
55                    Ordering::Equal => {
56                        // Keys are the same, decide which one to return.
57                        let (key, revert_to) = *revert;
58
59                        let value = match revert_to {
60                            // If the slot is some, prefer the revert value.
61                            RevertToSlot::Some(value) => value,
62                            // If the slot was destroyed, prefer the database value.
63                            RevertToSlot::Destroyed => wiped.1,
64                        };
65
66                        // Consume both values from inner iterators.
67                        self.next_revert();
68                        self.next_wiped();
69
70                        Some((key, value))
71                    }
72                }
73            }
74            (Some(_revert), None) => self.next_revert(),
75            (None, Some(_wiped)) => self.next_wiped(),
76            (None, None) => None,
77        }
78    }
79}
80
81#[cfg(test)]
82mod tests {
83    use super::*;
84
85    #[test]
86    fn test_storage_reverts_iter_empty() {
87        // Create empty sample data for reverts and wiped entries.
88        let reverts: Vec<(B256, RevertToSlot)> = vec![];
89        let wiped: Vec<(B256, FlaggedStorage)> = vec![];
90
91        // Create the iterator with the empty data.
92        let iter = StorageRevertsIter::new(reverts, wiped);
93
94        // Iterate and collect results into a vector for verification.
95        let results: Vec<_> = iter.collect();
96
97        // Verify that the results are empty.
98        assert_eq!(results, vec![]);
99    }
100
101    #[test]
102    fn test_storage_reverts_iter_reverts_only() {
103        // Create sample data for only reverts.
104        let reverts = vec![
105            (B256::from_slice(&[4; 32]), RevertToSlot::Destroyed),
106            (B256::from_slice(&[5; 32]), RevertToSlot::Some(FlaggedStorage::new_from_value(40))),
107        ];
108
109        // Create the iterator with only reverts and no wiped entries.
110        let iter = StorageRevertsIter::new(reverts, vec![]);
111
112        // Iterate and collect results into a vector for verification.
113        let results: Vec<_> = iter.collect();
114
115        // Verify the output order and values.
116        assert_eq!(
117            results,
118            vec![
119                (B256::from_slice(&[4; 32]), FlaggedStorage::ZERO), // Revert slot previous value
120                (B256::from_slice(&[5; 32]), FlaggedStorage::new_from_value(40)), /* Only revert
121                                                                     * present. */
122            ]
123        );
124    }
125
126    #[test]
127    fn test_storage_reverts_iter_wiped_only() {
128        // Create sample data for only wiped entries.
129        let wiped = vec![
130            (B256::from_slice(&[6; 32]), FlaggedStorage::new_from_value(50)),
131            (B256::from_slice(&[7; 32]), FlaggedStorage::new_from_value(60)),
132        ];
133
134        // Create the iterator with only wiped entries and no reverts.
135        let iter = StorageRevertsIter::new(vec![], wiped);
136
137        // Iterate and collect results into a vector for verification.
138        let results: Vec<_> = iter.collect();
139
140        // Verify the output order and values.
141        assert_eq!(
142            results,
143            vec![
144                (B256::from_slice(&[6; 32]), FlaggedStorage::new_from_value(50)), /* Only wiped
145                                                                                   * present. */
146                (B256::from_slice(&[7; 32]), FlaggedStorage::new_from_value(60)), /* Only wiped
147                                                                                   * present. */
148            ]
149        );
150    }
151
152    #[test]
153    fn test_storage_reverts_iter_interleaved() {
154        // Create sample data for interleaved reverts and wiped entries.
155        let reverts = vec![
156            (B256::from_slice(&[8; 32]), RevertToSlot::Some(FlaggedStorage::new_from_value(70))),
157            (B256::from_slice(&[9; 32]), RevertToSlot::Some(FlaggedStorage::new_from_value(80))),
158            // Some higher key than wiped
159            (B256::from_slice(&[15; 32]), RevertToSlot::Some(FlaggedStorage::new_from_value(90))),
160        ];
161
162        let wiped = vec![
163            (B256::from_slice(&[8; 32]), FlaggedStorage::new_from_value(75)), // Same key as revert
164            (B256::from_slice(&[10; 32]), FlaggedStorage::new_from_value(85)), // Wiped with new key
165        ];
166
167        // Create the iterator with the sample data.
168        let iter = StorageRevertsIter::new(reverts, wiped);
169
170        // Iterate and collect results into a vector for verification.
171        let results: Vec<_> = iter.collect();
172
173        // Verify the output order and values.
174        assert_eq!(
175            results,
176            vec![
177                (B256::from_slice(&[8; 32]), FlaggedStorage::new_from_value(70)), /* Revert takes priority. */
178                (B256::from_slice(&[9; 32]), FlaggedStorage::new_from_value(80)), /* Only revert
179                                                                                   * present. */
180                (B256::from_slice(&[10; 32]), FlaggedStorage::new_from_value(85)), // Wiped entry.
181                (B256::from_slice(&[15; 32]), FlaggedStorage::new_from_value(90)), /* WGreater revert entry */
182            ]
183        );
184    }
185}