reth_provider/writer/
mod.rs

1use crate::{
2    providers::{StaticFileProvider, StaticFileWriter as SfWriter},
3    BlockExecutionWriter, BlockWriter, HistoryWriter, StateWriter, StaticFileProviderFactory,
4    StorageLocation, TrieWriter,
5};
6use alloy_consensus::BlockHeader;
7use reth_chain_state::ExecutedBlock;
8use reth_db::transaction::{DbTx, DbTxMut};
9use reth_errors::ProviderResult;
10use reth_primitives::{NodePrimitives, StaticFileSegment};
11use reth_primitives_traits::SignedTransaction;
12use reth_storage_api::{DBProvider, StageCheckpointWriter, TransactionsProviderExt};
13use reth_storage_errors::writer::UnifiedStorageWriterError;
14use revm::db::OriginalValuesKnown;
15use std::sync::Arc;
16use tracing::debug;
17
18/// [`UnifiedStorageWriter`] is responsible for managing the writing to storage with both database
19/// and static file providers.
20#[derive(Debug)]
21pub struct UnifiedStorageWriter<'a, ProviderDB, ProviderSF> {
22    database: &'a ProviderDB,
23    static_file: Option<ProviderSF>,
24}
25
26impl<'a, ProviderDB, ProviderSF> UnifiedStorageWriter<'a, ProviderDB, ProviderSF> {
27    /// Creates a new instance of [`UnifiedStorageWriter`].
28    ///
29    /// # Parameters
30    /// - `database`: An optional reference to a database provider.
31    /// - `static_file`: An optional mutable reference to a static file instance.
32    pub const fn new(database: &'a ProviderDB, static_file: Option<ProviderSF>) -> Self {
33        Self { database, static_file }
34    }
35
36    /// Creates a new instance of [`UnifiedStorageWriter`] from a database provider and a static
37    /// file instance.
38    pub fn from<P>(database: &'a P, static_file: ProviderSF) -> Self
39    where
40        P: AsRef<ProviderDB>,
41    {
42        Self::new(database.as_ref(), Some(static_file))
43    }
44
45    /// Creates a new instance of [`UnifiedStorageWriter`] from a database provider.
46    pub fn from_database<P>(database: &'a P) -> Self
47    where
48        P: AsRef<ProviderDB>,
49    {
50        Self::new(database.as_ref(), None)
51    }
52
53    /// Returns a reference to the database writer.
54    ///
55    /// # Panics
56    /// If the database provider is not set.
57    const fn database(&self) -> &ProviderDB {
58        self.database
59    }
60
61    /// Returns a reference to the static file instance.
62    ///
63    /// # Panics
64    /// If the static file instance is not set.
65    fn static_file(&self) -> &ProviderSF {
66        self.static_file.as_ref().expect("should exist")
67    }
68
69    /// Ensures that the static file instance is set.
70    ///
71    /// # Returns
72    /// - `Ok(())` if the static file instance is set.
73    /// - `Err(StorageWriterError::MissingStaticFileWriter)` if the static file instance is not set.
74    #[allow(unused)]
75    const fn ensure_static_file(&self) -> Result<(), UnifiedStorageWriterError> {
76        if self.static_file.is_none() {
77            return Err(UnifiedStorageWriterError::MissingStaticFileWriter)
78        }
79        Ok(())
80    }
81}
82
83impl UnifiedStorageWriter<'_, (), ()> {
84    /// Commits both storage types in the right order.
85    ///
86    /// For non-unwinding operations it makes more sense to commit the static files first, since if
87    /// it is interrupted before the database commit, we can just truncate
88    /// the static files according to the checkpoints on the next
89    /// start-up.
90    ///
91    /// NOTE: If unwinding data from storage, use `commit_unwind` instead!
92    pub fn commit<P>(provider: P) -> ProviderResult<()>
93    where
94        P: DBProvider<Tx: DbTxMut> + StaticFileProviderFactory,
95    {
96        let static_file = provider.static_file_provider();
97        static_file.commit()?;
98        provider.commit()?;
99        Ok(())
100    }
101
102    /// Commits both storage types in the right order for an unwind operation.
103    ///
104    /// For unwinding it makes more sense to commit the database first, since if
105    /// it is interrupted before the static files commit, we can just
106    /// truncate the static files according to the
107    /// checkpoints on the next start-up.
108    ///
109    /// NOTE: Should only be used after unwinding data from storage!
110    pub fn commit_unwind<P>(provider: P) -> ProviderResult<()>
111    where
112        P: DBProvider<Tx: DbTxMut> + StaticFileProviderFactory,
113    {
114        let static_file = provider.static_file_provider();
115        provider.commit()?;
116        static_file.commit()?;
117        Ok(())
118    }
119}
120
121impl<ProviderDB> UnifiedStorageWriter<'_, ProviderDB, &StaticFileProvider<ProviderDB::Primitives>>
122where
123    ProviderDB: DBProvider<Tx: DbTx + DbTxMut>
124        + BlockWriter
125        + TransactionsProviderExt
126        + TrieWriter
127        + StateWriter
128        + HistoryWriter
129        + StageCheckpointWriter
130        + BlockExecutionWriter
131        + AsRef<ProviderDB>
132        + StaticFileProviderFactory,
133{
134    /// Writes executed blocks and receipts to storage.
135    pub fn save_blocks<N>(&self, blocks: Vec<ExecutedBlock<N>>) -> ProviderResult<()>
136    where
137        N: NodePrimitives<SignedTx: SignedTransaction>,
138        ProviderDB: BlockWriter<Block = N::Block> + StateWriter<Receipt = N::Receipt>,
139    {
140        if blocks.is_empty() {
141            debug!(target: "provider::storage_writer", "Attempted to write empty block range");
142            return Ok(())
143        }
144
145        // NOTE: checked non-empty above
146        let first_block = blocks.first().unwrap().block();
147
148        let last_block = blocks.last().unwrap().block();
149        let first_number = first_block.number();
150        let last_block_number = last_block.number();
151
152        debug!(target: "provider::storage_writer", block_count = %blocks.len(), "Writing blocks and execution data to storage");
153
154        // TODO: Do performant / batched writes for each type of object
155        // instead of a loop over all blocks,
156        // meaning:
157        //  * blocks
158        //  * state
159        //  * hashed state
160        //  * trie updates (cannot naively extend, need helper)
161        //  * indices (already done basically)
162        // Insert the blocks
163        for ExecutedBlock { block, senders, execution_output, hashed_state, trie } in blocks {
164            let sealed_block = Arc::unwrap_or_clone(block)
165                .try_with_senders_unchecked(Arc::unwrap_or_clone(senders))
166                .unwrap();
167            self.database().insert_block(sealed_block, StorageLocation::Both)?;
168
169            // Write state and changesets to the database.
170            // Must be written after blocks because of the receipt lookup.
171            self.database().write_state(
172                Arc::unwrap_or_clone(execution_output),
173                OriginalValuesKnown::No,
174                StorageLocation::StaticFiles,
175            )?;
176
177            // insert hashes and intermediate merkle nodes
178            self.database()
179                .write_hashed_state(&Arc::unwrap_or_clone(hashed_state).into_sorted())?;
180            self.database().write_trie_updates(&trie)?;
181        }
182
183        // update history indices
184        self.database().update_history_indices(first_number..=last_block_number)?;
185
186        // Update pipeline progress
187        self.database().update_pipeline_stages(last_block_number, false)?;
188
189        debug!(target: "provider::storage_writer", range = ?first_number..=last_block_number, "Appended block data");
190
191        Ok(())
192    }
193
194    /// Removes all block, transaction and receipt data above the given block number from the
195    /// database and static files. This is exclusive, i.e., it only removes blocks above
196    /// `block_number`, and does not remove `block_number`.
197    pub fn remove_blocks_above(&self, block_number: u64) -> ProviderResult<()> {
198        // IMPORTANT: we use `block_number+1` to make sure we remove only what is ABOVE the block
199        debug!(target: "provider::storage_writer", ?block_number, "Removing blocks from database above block_number");
200        self.database().remove_block_and_execution_above(block_number, StorageLocation::Both)?;
201
202        // Get highest static file block for the total block range
203        let highest_static_file_block = self
204            .static_file()
205            .get_highest_static_file_block(StaticFileSegment::Headers)
206            .expect("todo: error handling, headers should exist");
207
208        // IMPORTANT: we use `highest_static_file_block.saturating_sub(block_number)` to make sure
209        // we remove only what is ABOVE the block.
210        //
211        // i.e., if the highest static file block is 8, we want to remove above block 5 only, we
212        // will have three blocks to remove, which will be block 8, 7, and 6.
213        debug!(target: "provider::storage_writer", ?block_number, "Removing static file blocks above block_number");
214        self.static_file()
215            .get_writer(block_number, StaticFileSegment::Headers)?
216            .prune_headers(highest_static_file_block.saturating_sub(block_number))?;
217
218        Ok(())
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225    use crate::{
226        test_utils::create_test_provider_factory, AccountReader, StorageTrieWriter, TrieWriter,
227    };
228    use alloy_primitives::{keccak256, map::HashMap, Address, B256, U256};
229    use reth_db::tables;
230    use reth_db_api::{
231        cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO},
232        models::{AccountBeforeTx, BlockNumberAddress},
233        transaction::{DbTx, DbTxMut},
234    };
235    use reth_execution_types::ExecutionOutcome;
236    use reth_primitives::{Account, Receipt, Receipts, StorageEntry};
237    use reth_storage_api::{DatabaseProviderFactory, HashedPostStateProvider};
238    use reth_trie::{
239        test_utils::{state_root, storage_root_prehashed},
240        HashedPostState, HashedStorage, StateRoot, StorageRoot,
241    };
242    use reth_trie_db::{DatabaseStateRoot, DatabaseStorageRoot};
243    use revm::{
244        db::{
245            states::{
246                bundle_state::BundleRetention, changes::PlainStorageRevert, PlainStorageChangeset,
247            },
248            BundleState, EmptyDB,
249        },
250        primitives::{
251            Account as RevmAccount, AccountInfo as RevmAccountInfo, AccountStatus, EvmStorageSlot,
252            FlaggedStorage,
253        },
254        DatabaseCommit, State,
255    };
256    use std::{collections::BTreeMap, str::FromStr};
257
258    #[test]
259    fn wiped_entries_are_removed() {
260        let provider_factory = create_test_provider_factory();
261
262        let addresses = (0..10).map(|_| Address::random()).collect::<Vec<_>>();
263        let destroyed_address = *addresses.first().unwrap();
264        let destroyed_address_hashed = keccak256(destroyed_address);
265        let slot = B256::with_last_byte(1);
266        let hashed_slot = keccak256(slot);
267        {
268            let provider_rw = provider_factory.provider_rw().unwrap();
269            let mut accounts_cursor =
270                provider_rw.tx_ref().cursor_write::<tables::HashedAccounts>().unwrap();
271            let mut storage_cursor =
272                provider_rw.tx_ref().cursor_write::<tables::HashedStorages>().unwrap();
273
274            for address in addresses {
275                let hashed_address = keccak256(address);
276                accounts_cursor
277                    .insert(hashed_address, Account { nonce: 1, ..Default::default() })
278                    .unwrap();
279                storage_cursor
280                    .insert(
281                        hashed_address,
282                        StorageEntry { key: hashed_slot, value: U256::from(1), is_private: false },
283                    )
284                    .unwrap();
285            }
286            provider_rw.commit().unwrap();
287        }
288
289        let mut hashed_state = HashedPostState::default();
290        hashed_state.accounts.insert(destroyed_address_hashed, None);
291        hashed_state.storages.insert(destroyed_address_hashed, HashedStorage::new(true));
292
293        let provider_rw = provider_factory.provider_rw().unwrap();
294        assert_eq!(provider_rw.write_hashed_state(&hashed_state.into_sorted()), Ok(()));
295        provider_rw.commit().unwrap();
296
297        let provider = provider_factory.provider().unwrap();
298        assert_eq!(
299            provider.tx_ref().get::<tables::HashedAccounts>(destroyed_address_hashed),
300            Ok(None)
301        );
302        assert_eq!(
303            provider
304                .tx_ref()
305                .cursor_read::<tables::HashedStorages>()
306                .unwrap()
307                .seek_by_key_subkey(destroyed_address_hashed, hashed_slot),
308            Ok(None)
309        );
310    }
311
312    #[test]
313    fn write_to_db_account_info() {
314        let factory = create_test_provider_factory();
315        let provider = factory.provider_rw().unwrap();
316
317        let address_a = Address::ZERO;
318        let address_b = Address::repeat_byte(0xff);
319
320        let account_a = RevmAccountInfo { balance: U256::from(1), nonce: 1, ..Default::default() };
321        let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
322        let account_b_changed =
323            RevmAccountInfo { balance: U256::from(3), nonce: 3, ..Default::default() };
324
325        let mut state = State::builder().with_bundle_update().build();
326        state.insert_not_existing(address_a);
327        state.insert_account(address_b, account_b.clone());
328
329        // 0x00.. is created
330        state.commit(HashMap::from_iter([(
331            address_a,
332            RevmAccount {
333                info: account_a.clone(),
334                status: AccountStatus::Touched | AccountStatus::Created,
335                storage: HashMap::default(),
336            },
337        )]));
338
339        // 0xff.. is changed (balance + 1, nonce + 1)
340        state.commit(HashMap::from_iter([(
341            address_b,
342            RevmAccount {
343                info: account_b_changed.clone(),
344                status: AccountStatus::Touched,
345                storage: HashMap::default(),
346            },
347        )]));
348
349        state.merge_transitions(BundleRetention::Reverts);
350        let mut revm_bundle_state = state.take_bundle();
351
352        // Write plain state and reverts separately.
353        let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
354        let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
355        assert!(plain_state.storage.is_empty());
356        assert!(plain_state.contracts.is_empty());
357        provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
358
359        assert_eq!(reverts.storage, [[]]);
360        provider.write_state_reverts(reverts, 1).expect("Could not write reverts to DB");
361
362        let reth_account_a = account_a.into();
363        let reth_account_b = account_b.into();
364        let reth_account_b_changed = (&account_b_changed).into();
365
366        // Check plain state
367        assert_eq!(
368            provider.basic_account(address_a).expect("Could not read account state"),
369            Some(reth_account_a),
370            "Account A state is wrong"
371        );
372        assert_eq!(
373            provider.basic_account(address_b).expect("Could not read account state"),
374            Some(reth_account_b_changed),
375            "Account B state is wrong"
376        );
377
378        // Check change set
379        let mut changeset_cursor = provider
380            .tx_ref()
381            .cursor_dup_read::<tables::AccountChangeSets>()
382            .expect("Could not open changeset cursor");
383        assert_eq!(
384            changeset_cursor.seek_exact(1).expect("Could not read account change set"),
385            Some((1, AccountBeforeTx { address: address_a, info: None })),
386            "Account A changeset is wrong"
387        );
388        assert_eq!(
389            changeset_cursor.next_dup().expect("Changeset table is malformed"),
390            Some((1, AccountBeforeTx { address: address_b, info: Some(reth_account_b) })),
391            "Account B changeset is wrong"
392        );
393
394        let mut state = State::builder().with_bundle_update().build();
395        state.insert_account(address_b, account_b_changed.clone());
396
397        // 0xff.. is destroyed
398        state.commit(HashMap::from_iter([(
399            address_b,
400            RevmAccount {
401                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
402                info: account_b_changed,
403                storage: HashMap::default(),
404            },
405        )]));
406
407        state.merge_transitions(BundleRetention::Reverts);
408        let mut revm_bundle_state = state.take_bundle();
409
410        // Write plain state and reverts separately.
411        let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
412        let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
413        // Account B selfdestructed so flag for it should be present.
414        assert_eq!(
415            plain_state.storage,
416            [PlainStorageChangeset { address: address_b, wipe_storage: true, storage: vec![] }]
417        );
418        assert!(plain_state.contracts.is_empty());
419        provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
420
421        assert_eq!(
422            reverts.storage,
423            [[PlainStorageRevert { address: address_b, wiped: true, storage_revert: vec![] }]]
424        );
425        provider.write_state_reverts(reverts, 2).expect("Could not write reverts to DB");
426
427        // Check new plain state for account B
428        assert_eq!(
429            provider.basic_account(address_b).expect("Could not read account state"),
430            None,
431            "Account B should be deleted"
432        );
433
434        // Check change set
435        assert_eq!(
436            changeset_cursor.seek_exact(2).expect("Could not read account change set"),
437            Some((2, AccountBeforeTx { address: address_b, info: Some(reth_account_b_changed) })),
438            "Account B changeset is wrong after deletion"
439        );
440    }
441
442    #[test]
443    fn write_to_db_storage() {
444        let factory = create_test_provider_factory();
445        let provider = factory.database_provider_rw().unwrap();
446
447        let address_a = Address::ZERO;
448        let address_b = Address::repeat_byte(0xff);
449        let address_c = Address::random();
450
451        let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
452        let account_c = RevmAccountInfo { balance: U256::from(1), nonce: 3, ..Default::default() };
453
454        let mut state = State::builder().with_bundle_update().build();
455        state.insert_not_existing(address_a);
456        state.insert_account_with_storage(
457            address_b,
458            account_b.clone(),
459            HashMap::from_iter([(U256::from(1), FlaggedStorage::new(1, false))]),
460        );
461        state.insert_account_with_storage(
462            address_c,
463            account_c.clone(),
464            HashMap::from_iter([(U256::from(3), FlaggedStorage::new(1, false))]),
465        );
466
467        state.commit(HashMap::from_iter([
468            (
469                address_a,
470                RevmAccount {
471                    status: AccountStatus::Touched | AccountStatus::Created,
472                    info: RevmAccountInfo::default(),
473                    // 0x00 => 0 => 1
474                    // 0x01 => 0 => 2
475                    storage: HashMap::from_iter([
476                        (
477                            U256::from(0),
478                            EvmStorageSlot {
479                                present_value: FlaggedStorage::new(1, true),
480                                ..Default::default()
481                            },
482                        ),
483                        (
484                            U256::from(1),
485                            EvmStorageSlot {
486                                present_value: FlaggedStorage::new(2, true),
487                                ..Default::default()
488                            },
489                        ),
490                    ]),
491                },
492            ),
493            (
494                address_b,
495                RevmAccount {
496                    status: AccountStatus::Touched,
497                    info: account_b,
498                    // 0x01 => 1 => 2
499                    storage: HashMap::from_iter([(
500                        U256::from(1),
501                        EvmStorageSlot {
502                            present_value: FlaggedStorage::new(2, false),
503                            original_value: FlaggedStorage::new(1, false),
504                            ..Default::default()
505                        },
506                    )]),
507                },
508            ),
509            (
510                address_c,
511                RevmAccount {
512                    status: AccountStatus::Touched,
513                    info: account_c,
514                    // 0x03 => {private: false, value: 1} => {private: true, value: 2}
515                    storage: HashMap::from_iter([(
516                        U256::from(3),
517                        EvmStorageSlot {
518                            present_value: FlaggedStorage::new(2, true),
519                            original_value: FlaggedStorage::new(1, false),
520                            ..Default::default()
521                        },
522                    )]),
523                },
524            ),
525        ]));
526
527        state.merge_transitions(BundleRetention::Reverts);
528
529        let outcome =
530            ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 1, Vec::new());
531        provider
532            .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
533            .expect("Could not write bundle state to DB");
534
535        // Check plain storage state
536        let mut storage_cursor = provider
537            .tx_ref()
538            .cursor_dup_read::<tables::PlainStorageState>()
539            .expect("Could not open plain storage state cursor");
540
541        assert_eq!(
542            storage_cursor.seek_exact(address_a).unwrap(),
543            Some((
544                address_a,
545                StorageEntry { key: B256::ZERO, value: U256::from(1), is_private: true }
546            )),
547            "Slot 0 for account A should be a private 1"
548        );
549        assert_eq!(
550            storage_cursor.next_dup().unwrap(),
551            Some((
552                address_a,
553                StorageEntry {
554                    key: B256::from(U256::from(1).to_be_bytes()),
555                    value: U256::from(2),
556                    is_private: true
557                }
558            )),
559            "Slot 1 for account A should be a private 2"
560        );
561        assert_eq!(
562            storage_cursor.next_dup().unwrap(),
563            None,
564            "Account A should only have 2 storage slots"
565        );
566
567        assert_eq!(
568            storage_cursor.seek_exact(address_b).unwrap(),
569            Some((
570                address_b,
571                StorageEntry {
572                    key: B256::from(U256::from(1).to_be_bytes()),
573                    value: U256::from(2),
574                    is_private: false
575                }
576            )),
577            "Slot 1 for account B should be a public 2"
578        );
579        assert_eq!(
580            storage_cursor.next_dup().unwrap(),
581            None,
582            "Account B should only have 1 storage slot"
583        );
584        assert_eq!(
585            storage_cursor.seek_exact(address_c).unwrap(),
586            Some((
587                address_c,
588                StorageEntry {
589                    key: B256::from(U256::from(3).to_be_bytes()),
590                    value: U256::from(2),
591                    is_private: true
592                }
593            )),
594            "Slot 3 for account C should be a private 2"
595        );
596        assert_eq!(
597            storage_cursor.next_dup().unwrap(),
598            None,
599            "Account C should only have 1 storage slot"
600        );
601
602        // Check change set
603        let mut changeset_cursor = provider
604            .tx_ref()
605            .cursor_dup_read::<tables::StorageChangeSets>()
606            .expect("Could not open storage changeset cursor");
607        assert_eq!(
608            changeset_cursor.seek_exact(BlockNumberAddress((1, address_a))).unwrap(),
609            Some((
610                BlockNumberAddress((1, address_a)),
611                StorageEntry { key: B256::ZERO, value: U256::from(0), is_private: false }
612            )),
613            "Slot 0 for account A should have changed from a public 0"
614        );
615        assert_eq!(
616            changeset_cursor.next_dup().unwrap(),
617            Some((
618                BlockNumberAddress((1, address_a)),
619                StorageEntry {
620                    key: B256::from(U256::from(1).to_be_bytes()),
621                    value: U256::from(0),
622                    is_private: false
623                }
624            )),
625            "Slot 1 for account A should have changed from a public 0"
626        );
627        assert_eq!(
628            changeset_cursor.next_dup().unwrap(),
629            None,
630            "Account A should only be in the changeset 2 times"
631        );
632
633        assert_eq!(
634            changeset_cursor.seek_exact(BlockNumberAddress((1, address_b))).unwrap(),
635            Some((
636                BlockNumberAddress((1, address_b)),
637                StorageEntry {
638                    key: B256::from(U256::from(1).to_be_bytes()),
639                    value: U256::from(1),
640                    is_private: false
641                }
642            )),
643            "Slot 1 for account B should have changed from a public 1"
644        );
645        assert_eq!(
646            changeset_cursor.next_dup().unwrap(),
647            None,
648            "Account B should only be in the changeset 1 time"
649        );
650
651        assert_eq!(
652            changeset_cursor.seek_exact(BlockNumberAddress((1, address_c))).unwrap(),
653            Some((
654                BlockNumberAddress((1, address_c)),
655                StorageEntry {
656                    key: B256::from(U256::from(3).to_be_bytes()),
657                    value: U256::from(1),
658                    is_private: false
659                }
660            )),
661            "Slot 1 for account C should have changed from a public 1"
662        );
663        assert_eq!(
664            changeset_cursor.next_dup().unwrap(),
665            None,
666            "Account C should only be in the changeset 1 time"
667        );
668
669        // Delete account A
670        let mut state = State::builder().with_bundle_update().build();
671        state.insert_account(address_a, RevmAccountInfo::default());
672
673        state.commit(HashMap::from_iter([(
674            address_a,
675            RevmAccount {
676                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
677                info: RevmAccountInfo::default(),
678                storage: HashMap::default(),
679            },
680        )]));
681
682        state.merge_transitions(BundleRetention::Reverts);
683        let outcome =
684            ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 2, Vec::new());
685        provider
686            .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
687            .expect("Could not write bundle state to DB");
688
689        assert_eq!(
690            storage_cursor.seek_exact(address_a).unwrap(),
691            None,
692            "Account A should have no storage slots after deletion"
693        );
694
695        assert_eq!(
696            changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(),
697            Some((
698                BlockNumberAddress((2, address_a)),
699                StorageEntry { key: B256::ZERO, value: U256::from(1), is_private: true }
700            )),
701            "Slot 0 for account A should have changed from a private 1 on deletion"
702        );
703        assert_eq!(
704            changeset_cursor.next_dup().unwrap(),
705            Some((
706                BlockNumberAddress((2, address_a)),
707                StorageEntry {
708                    key: B256::from(U256::from(1).to_be_bytes()),
709                    value: U256::from(2),
710                    is_private: true
711                }
712            )),
713            "Slot 1 for account A should have changed from a private 2 on deletion"
714        );
715        assert_eq!(
716            changeset_cursor.next_dup().unwrap(),
717            None,
718            "Account A should only be in the changeset 2 times on deletion"
719        );
720    }
721
722    #[test]
723    fn write_to_db_multiple_selfdestructs() {
724        let factory = create_test_provider_factory();
725        let provider = factory.database_provider_rw().unwrap();
726
727        let address1 = Address::random();
728        let account_info = RevmAccountInfo { nonce: 1, ..Default::default() };
729
730        // Block #0: initial state.
731        let mut init_state = State::builder().with_bundle_update().build();
732        init_state.insert_not_existing(address1);
733        init_state.commit(HashMap::from_iter([(
734            address1,
735            RevmAccount {
736                info: account_info.clone(),
737                status: AccountStatus::Touched | AccountStatus::Created,
738                // 0x00 => 0 => 1
739                // 0x01 => 0 => 2
740                storage: HashMap::from_iter([
741                    (
742                        U256::ZERO,
743                        EvmStorageSlot {
744                            present_value: FlaggedStorage::new_from_value(1),
745                            ..Default::default()
746                        },
747                    ),
748                    (
749                        U256::from(1),
750                        EvmStorageSlot {
751                            present_value: FlaggedStorage::new_from_value(2),
752                            ..Default::default()
753                        },
754                    ),
755                ]),
756            },
757        )]));
758        init_state.merge_transitions(BundleRetention::Reverts);
759
760        let outcome =
761            ExecutionOutcome::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new());
762        provider
763            .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
764            .expect("Could not write bundle state to DB");
765
766        let mut state = State::builder().with_bundle_update().build();
767        state.insert_account_with_storage(
768            address1,
769            account_info.clone(),
770            HashMap::from_iter([
771                (U256::ZERO, FlaggedStorage::new_from_value(1)),
772                (U256::from(1), FlaggedStorage::new_from_value(2)),
773            ]),
774        );
775
776        // Block #1: change storage.
777        state.commit(HashMap::from_iter([(
778            address1,
779            RevmAccount {
780                status: AccountStatus::Touched,
781                info: account_info.clone(),
782                // 0x00 => 1 => 2
783                storage: HashMap::from_iter([(
784                    U256::ZERO,
785                    EvmStorageSlot {
786                        original_value: FlaggedStorage::new_from_value(1),
787                        present_value: FlaggedStorage::new_from_value(2),
788                        ..Default::default()
789                    },
790                )]),
791            },
792        )]));
793        state.merge_transitions(BundleRetention::Reverts);
794
795        // Block #2: destroy account.
796        state.commit(HashMap::from_iter([(
797            address1,
798            RevmAccount {
799                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
800                info: account_info.clone(),
801                storage: HashMap::default(),
802            },
803        )]));
804        state.merge_transitions(BundleRetention::Reverts);
805
806        // Block #3: re-create account and change storage.
807        state.commit(HashMap::from_iter([(
808            address1,
809            RevmAccount {
810                status: AccountStatus::Touched | AccountStatus::Created,
811                info: account_info.clone(),
812                storage: HashMap::default(),
813            },
814        )]));
815        state.merge_transitions(BundleRetention::Reverts);
816
817        // Block #4: change storage.
818        state.commit(HashMap::from_iter([(
819            address1,
820            RevmAccount {
821                status: AccountStatus::Touched,
822                info: account_info.clone(),
823                // 0x00 => 0 => 2
824                // 0x02 => 0 => 4
825                // 0x06 => 0 => 6
826                storage: HashMap::from_iter([
827                    (
828                        U256::ZERO,
829                        EvmStorageSlot {
830                            present_value: FlaggedStorage::new_from_value(2),
831                            ..Default::default()
832                        },
833                    ),
834                    (
835                        U256::from(2),
836                        EvmStorageSlot {
837                            present_value: FlaggedStorage::new_from_value(4),
838                            ..Default::default()
839                        },
840                    ),
841                    (
842                        U256::from(6),
843                        EvmStorageSlot {
844                            present_value: FlaggedStorage::new_from_value(6),
845                            ..Default::default()
846                        },
847                    ),
848                ]),
849            },
850        )]));
851        state.merge_transitions(BundleRetention::Reverts);
852
853        // Block #5: Destroy account again.
854        state.commit(HashMap::from_iter([(
855            address1,
856            RevmAccount {
857                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
858                info: account_info.clone(),
859                storage: HashMap::default(),
860            },
861        )]));
862        state.merge_transitions(BundleRetention::Reverts);
863
864        // Block #6: Create, change, destroy and re-create in the same block.
865        state.commit(HashMap::from_iter([(
866            address1,
867            RevmAccount {
868                status: AccountStatus::Touched | AccountStatus::Created,
869                info: account_info.clone(),
870                storage: HashMap::default(),
871            },
872        )]));
873        state.commit(HashMap::from_iter([(
874            address1,
875            RevmAccount {
876                status: AccountStatus::Touched,
877                info: account_info.clone(),
878                // 0x00 => 0 => 2
879                storage: HashMap::from_iter([(
880                    U256::ZERO,
881                    EvmStorageSlot {
882                        present_value: FlaggedStorage::new_from_value(2),
883                        ..Default::default()
884                    },
885                )]),
886            },
887        )]));
888        state.commit(HashMap::from_iter([(
889            address1,
890            RevmAccount {
891                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
892                info: account_info.clone(),
893                storage: HashMap::default(),
894            },
895        )]));
896        state.commit(HashMap::from_iter([(
897            address1,
898            RevmAccount {
899                status: AccountStatus::Touched | AccountStatus::Created,
900                info: account_info.clone(),
901                storage: HashMap::default(),
902            },
903        )]));
904        state.merge_transitions(BundleRetention::Reverts);
905
906        // Block #7: Change storage.
907        state.commit(HashMap::from_iter([(
908            address1,
909            RevmAccount {
910                status: AccountStatus::Touched,
911                info: account_info,
912                // 0x00 => 0 => 9
913                storage: HashMap::from_iter([(
914                    U256::ZERO,
915                    EvmStorageSlot {
916                        present_value: FlaggedStorage::new_from_value(9),
917                        ..Default::default()
918                    },
919                )]),
920            },
921        )]));
922        state.merge_transitions(BundleRetention::Reverts);
923
924        let bundle = state.take_bundle();
925
926        let outcome: ExecutionOutcome =
927            ExecutionOutcome::new(bundle, Receipts::default(), 1, Vec::new());
928        provider
929            .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
930            .expect("Could not write bundle state to DB");
931
932        let mut storage_changeset_cursor = provider
933            .tx_ref()
934            .cursor_dup_read::<tables::StorageChangeSets>()
935            .expect("Could not open plain storage state cursor");
936        let mut storage_changes = storage_changeset_cursor.walk_range(..).unwrap();
937
938        // Iterate through all storage changes
939
940        // Block <number>
941        // <slot>: <expected value before>
942        // ...
943
944        // Block #0
945        // 0x00: 0
946        // 0x01: 0
947        assert_eq!(
948            storage_changes.next(),
949            Some(Ok((
950                BlockNumberAddress((0, address1)),
951                StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO, is_private: false }
952            )))
953        );
954        assert_eq!(
955            storage_changes.next(),
956            Some(Ok((
957                BlockNumberAddress((0, address1)),
958                StorageEntry { key: B256::with_last_byte(1), value: U256::ZERO, is_private: false }
959            )))
960        );
961
962        // Block #1
963        // 0x00: 1
964        assert_eq!(
965            storage_changes.next(),
966            Some(Ok((
967                BlockNumberAddress((1, address1)),
968                StorageEntry {
969                    key: B256::with_last_byte(0),
970                    value: U256::from(1),
971                    is_private: false
972                }
973            )))
974        );
975
976        // Block #2 (destroyed)
977        // 0x00: 2
978        // 0x01: 2
979        assert_eq!(
980            storage_changes.next(),
981            Some(Ok((
982                BlockNumberAddress((2, address1)),
983                StorageEntry {
984                    key: B256::with_last_byte(0),
985                    value: U256::from(2),
986                    is_private: false
987                }
988            )))
989        );
990        assert_eq!(
991            storage_changes.next(),
992            Some(Ok((
993                BlockNumberAddress((2, address1)),
994                StorageEntry {
995                    key: B256::with_last_byte(1),
996                    value: U256::from(2),
997                    is_private: false
998                }
999            )))
1000        );
1001
1002        // Block #3
1003        // no storage changes
1004
1005        // Block #4
1006        // 0x00: 0
1007        // 0x02: 0
1008        // 0x06: 0
1009        assert_eq!(
1010            storage_changes.next(),
1011            Some(Ok((
1012                BlockNumberAddress((4, address1)),
1013                StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO, is_private: false }
1014            )))
1015        );
1016        assert_eq!(
1017            storage_changes.next(),
1018            Some(Ok((
1019                BlockNumberAddress((4, address1)),
1020                StorageEntry { key: B256::with_last_byte(2), value: U256::ZERO, is_private: false }
1021            )))
1022        );
1023        assert_eq!(
1024            storage_changes.next(),
1025            Some(Ok((
1026                BlockNumberAddress((4, address1)),
1027                StorageEntry { key: B256::with_last_byte(6), value: U256::ZERO, is_private: false }
1028            )))
1029        );
1030
1031        // Block #5 (destroyed)
1032        // 0x00: 2
1033        // 0x02: 4
1034        // 0x06: 6
1035        assert_eq!(
1036            storage_changes.next(),
1037            Some(Ok((
1038                BlockNumberAddress((5, address1)),
1039                StorageEntry {
1040                    key: B256::with_last_byte(0),
1041                    value: U256::from(2),
1042                    is_private: false
1043                }
1044            )))
1045        );
1046        assert_eq!(
1047            storage_changes.next(),
1048            Some(Ok((
1049                BlockNumberAddress((5, address1)),
1050                StorageEntry {
1051                    key: B256::with_last_byte(2),
1052                    value: U256::from(4),
1053                    is_private: false
1054                }
1055            )))
1056        );
1057        assert_eq!(
1058            storage_changes.next(),
1059            Some(Ok((
1060                BlockNumberAddress((5, address1)),
1061                StorageEntry {
1062                    key: B256::with_last_byte(6),
1063                    value: U256::from(6),
1064                    is_private: false
1065                }
1066            )))
1067        );
1068
1069        // Block #6
1070        // no storage changes (only inter block changes)
1071
1072        // Block #7
1073        // 0x00: 0
1074        assert_eq!(
1075            storage_changes.next(),
1076            Some(Ok((
1077                BlockNumberAddress((7, address1)),
1078                StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO, is_private: false }
1079            )))
1080        );
1081        assert_eq!(storage_changes.next(), None);
1082    }
1083
1084    #[test]
1085    fn storage_change_after_selfdestruct_within_block() {
1086        let factory = create_test_provider_factory();
1087        let provider = factory.database_provider_rw().unwrap();
1088
1089        let address1 = Address::random();
1090        let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1091
1092        // Block #0: initial state.
1093        let mut init_state = State::builder().with_bundle_update().build();
1094        init_state.insert_not_existing(address1);
1095        init_state.commit(HashMap::from_iter([(
1096            address1,
1097            RevmAccount {
1098                info: account1.clone(),
1099                status: AccountStatus::Touched | AccountStatus::Created,
1100                // 0x00 => 0 => 1
1101                // 0x01 => 0 => 2
1102                storage: HashMap::from_iter([
1103                    (
1104                        U256::ZERO,
1105                        EvmStorageSlot {
1106                            present_value: FlaggedStorage::new_from_value(1),
1107                            ..Default::default()
1108                        },
1109                    ),
1110                    (
1111                        U256::from(1),
1112                        EvmStorageSlot {
1113                            present_value: FlaggedStorage::new_from_value(2),
1114                            ..Default::default()
1115                        },
1116                    ),
1117                ]),
1118            },
1119        )]));
1120        init_state.merge_transitions(BundleRetention::Reverts);
1121        let outcome =
1122            ExecutionOutcome::new(init_state.take_bundle(), Receipts::default(), 0, Vec::new());
1123        provider
1124            .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1125            .expect("Could not write bundle state to DB");
1126
1127        let mut state = State::builder().with_bundle_update().build();
1128        state.insert_account_with_storage(
1129            address1,
1130            account1.clone(),
1131            HashMap::from_iter([
1132                (U256::ZERO, FlaggedStorage::new_from_value(1)),
1133                (U256::from(1), FlaggedStorage::new_from_value(2)),
1134            ]),
1135        );
1136
1137        // Block #1: Destroy, re-create, change storage.
1138        state.commit(HashMap::from_iter([(
1139            address1,
1140            RevmAccount {
1141                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1142                info: account1.clone(),
1143                storage: HashMap::default(),
1144            },
1145        )]));
1146
1147        state.commit(HashMap::from_iter([(
1148            address1,
1149            RevmAccount {
1150                status: AccountStatus::Touched | AccountStatus::Created,
1151                info: account1.clone(),
1152                storage: HashMap::default(),
1153            },
1154        )]));
1155
1156        state.commit(HashMap::from_iter([(
1157            address1,
1158            RevmAccount {
1159                status: AccountStatus::Touched,
1160                info: account1,
1161                // 0x01 => 0 => 5
1162                storage: HashMap::from_iter([(
1163                    U256::from(1),
1164                    EvmStorageSlot {
1165                        present_value: FlaggedStorage::new_from_value(5),
1166                        ..Default::default()
1167                    },
1168                )]),
1169            },
1170        )]));
1171
1172        // Commit block #1 changes to the database.
1173        state.merge_transitions(BundleRetention::Reverts);
1174        let outcome =
1175            ExecutionOutcome::new(state.take_bundle(), Receipts::default(), 1, Vec::new());
1176        provider
1177            .write_state(outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1178            .expect("Could not write bundle state to DB");
1179
1180        let mut storage_changeset_cursor = provider
1181            .tx_ref()
1182            .cursor_dup_read::<tables::StorageChangeSets>()
1183            .expect("Could not open plain storage state cursor");
1184        let range = BlockNumberAddress::range(1..=1);
1185        let mut storage_changes = storage_changeset_cursor.walk_range(range).unwrap();
1186
1187        assert_eq!(
1188            storage_changes.next(),
1189            Some(Ok((
1190                BlockNumberAddress((1, address1)),
1191                StorageEntry {
1192                    key: B256::with_last_byte(0),
1193                    value: U256::from(1),
1194                    is_private: false
1195                }
1196            )))
1197        );
1198        assert_eq!(
1199            storage_changes.next(),
1200            Some(Ok((
1201                BlockNumberAddress((1, address1)),
1202                StorageEntry {
1203                    key: B256::with_last_byte(1),
1204                    value: U256::from(2),
1205                    is_private: false
1206                }
1207            )))
1208        );
1209        assert_eq!(storage_changes.next(), None);
1210    }
1211
1212    #[test]
1213    fn revert_to_indices() {
1214        let base: ExecutionOutcome = ExecutionOutcome {
1215            bundle: BundleState::default(),
1216            receipts: vec![vec![Some(Receipt::default()); 2]; 7].into(),
1217            first_block: 10,
1218            requests: Vec::new(),
1219        };
1220
1221        let mut this = base.clone();
1222        assert!(this.revert_to(10));
1223        assert_eq!(this.receipts.len(), 1);
1224
1225        let mut this = base.clone();
1226        assert!(!this.revert_to(9));
1227        assert_eq!(this.receipts.len(), 7);
1228
1229        let mut this = base.clone();
1230        assert!(this.revert_to(15));
1231        assert_eq!(this.receipts.len(), 6);
1232
1233        let mut this = base.clone();
1234        assert!(this.revert_to(16));
1235        assert_eq!(this.receipts.len(), 7);
1236
1237        let mut this = base;
1238        assert!(!this.revert_to(17));
1239        assert_eq!(this.receipts.len(), 7);
1240    }
1241
1242    #[test]
1243    fn bundle_state_state_root() {
1244        type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>;
1245        let mut prestate: PreState = (0..10)
1246            .map(|key| {
1247                let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None };
1248                let storage =
1249                    (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect();
1250                (Address::with_last_byte(key), (account, storage))
1251            })
1252            .collect();
1253
1254        let provider_factory = create_test_provider_factory();
1255        let provider_rw = provider_factory.database_provider_rw().unwrap();
1256
1257        // insert initial state to the database
1258        let tx = provider_rw.tx_ref();
1259        for (address, (account, storage)) in &prestate {
1260            let hashed_address = keccak256(address);
1261            tx.put::<tables::HashedAccounts>(hashed_address, *account).unwrap();
1262            for (slot, value) in storage {
1263                tx.put::<tables::HashedStorages>(
1264                    hashed_address,
1265                    StorageEntry { key: keccak256(slot), value: *value, is_private: false },
1266                )
1267                .unwrap();
1268            }
1269        }
1270
1271        let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
1272        provider_rw.write_trie_updates(&updates).unwrap();
1273
1274        let mut state = State::builder().with_bundle_update().build();
1275
1276        let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
1277            assert_eq!(
1278                StateRoot::overlay_root(
1279                    tx,
1280                    provider_factory.hashed_post_state(&state.bundle_state)
1281                )
1282                .unwrap(),
1283                state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
1284                    address,
1285                    (account, storage.into_iter())
1286                ))),
1287                "{msg}"
1288            );
1289        };
1290
1291        // database only state root is correct
1292        assert_state_root(&state, &prestate, "empty");
1293
1294        // destroy account 1
1295        let address1 = Address::with_last_byte(1);
1296        let account1_old = prestate.remove(&address1).unwrap();
1297        state.insert_account(address1, account1_old.0.into());
1298        state.commit(HashMap::from_iter([(
1299            address1,
1300            RevmAccount {
1301                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1302                info: RevmAccountInfo::default(),
1303                storage: HashMap::default(),
1304            },
1305        )]));
1306        state.merge_transitions(BundleRetention::PlainState);
1307        assert_state_root(&state, &prestate, "destroyed account");
1308
1309        // change slot 2 in account 2
1310        let address2 = Address::with_last_byte(2);
1311        let slot2 = U256::from(2);
1312        let slot2_key = B256::from(slot2);
1313        let account2 = prestate.get_mut(&address2).unwrap();
1314        let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap();
1315        state.insert_account_with_storage(
1316            address2,
1317            account2.0.into(),
1318            HashMap::from_iter([(slot2, FlaggedStorage::new_from_value(account2_slot2_old_value))]),
1319        );
1320
1321        let account2_slot2_new_value = U256::from(100);
1322        account2.1.insert(slot2_key, account2_slot2_new_value);
1323        state.commit(HashMap::from_iter([(
1324            address2,
1325            RevmAccount {
1326                status: AccountStatus::Touched,
1327                info: account2.0.into(),
1328                storage: HashMap::from_iter([(
1329                    slot2,
1330                    EvmStorageSlot::new_changed(
1331                        FlaggedStorage::new_from_value(account2_slot2_old_value),
1332                        FlaggedStorage::new_from_value(account2_slot2_new_value),
1333                    ),
1334                )]),
1335            },
1336        )]));
1337        state.merge_transitions(BundleRetention::PlainState);
1338        assert_state_root(&state, &prestate, "changed storage");
1339
1340        // change balance of account 3
1341        let address3 = Address::with_last_byte(3);
1342        let account3 = prestate.get_mut(&address3).unwrap();
1343        state.insert_account(address3, account3.0.into());
1344
1345        account3.0.balance = U256::from(24);
1346        state.commit(HashMap::from_iter([(
1347            address3,
1348            RevmAccount {
1349                status: AccountStatus::Touched,
1350                info: account3.0.into(),
1351                storage: HashMap::default(),
1352            },
1353        )]));
1354        state.merge_transitions(BundleRetention::PlainState);
1355        assert_state_root(&state, &prestate, "changed balance");
1356
1357        // change nonce of account 4
1358        let address4 = Address::with_last_byte(4);
1359        let account4 = prestate.get_mut(&address4).unwrap();
1360        state.insert_account(address4, account4.0.into());
1361
1362        account4.0.nonce = 128;
1363        state.commit(HashMap::from_iter([(
1364            address4,
1365            RevmAccount {
1366                status: AccountStatus::Touched,
1367                info: account4.0.into(),
1368                storage: HashMap::default(),
1369            },
1370        )]));
1371        state.merge_transitions(BundleRetention::PlainState);
1372        assert_state_root(&state, &prestate, "changed nonce");
1373
1374        // recreate account 1
1375        let account1_new =
1376            Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) };
1377        prestate.insert(address1, (account1_new, BTreeMap::default()));
1378        state.commit(HashMap::from_iter([(
1379            address1,
1380            RevmAccount {
1381                status: AccountStatus::Touched | AccountStatus::Created,
1382                info: account1_new.into(),
1383                storage: HashMap::default(),
1384            },
1385        )]));
1386        state.merge_transitions(BundleRetention::PlainState);
1387        assert_state_root(&state, &prestate, "recreated");
1388
1389        // update storage for account 1
1390        let slot20 = U256::from(20);
1391        let slot20_key = B256::from(slot20);
1392        let account1_slot20_value = U256::from(12345);
1393        prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value);
1394        state.commit(HashMap::from_iter([(
1395            address1,
1396            RevmAccount {
1397                status: AccountStatus::Touched | AccountStatus::Created,
1398                info: account1_new.into(),
1399                storage: HashMap::from_iter([(
1400                    slot20,
1401                    EvmStorageSlot::new_changed(
1402                        FlaggedStorage::ZERO,
1403                        FlaggedStorage::new_from_value(account1_slot20_value),
1404                    ),
1405                )]),
1406            },
1407        )]));
1408        state.merge_transitions(BundleRetention::PlainState);
1409        assert_state_root(&state, &prestate, "recreated changed storage");
1410    }
1411
1412    #[test]
1413    fn prepend_state() {
1414        let address1 = Address::random();
1415        let address2 = Address::random();
1416
1417        let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1418        let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() };
1419        let account2 = RevmAccountInfo { nonce: 1, ..Default::default() };
1420
1421        let present_state = BundleState::builder(2..=2)
1422            .state_present_account_info(address1, account1_changed.clone())
1423            .build();
1424        assert_eq!(present_state.reverts.len(), 1);
1425        let previous_state = BundleState::builder(1..=1)
1426            .state_present_account_info(address1, account1)
1427            .state_present_account_info(address2, account2.clone())
1428            .build();
1429        assert_eq!(previous_state.reverts.len(), 1);
1430
1431        let mut test: ExecutionOutcome = ExecutionOutcome {
1432            bundle: present_state,
1433            receipts: vec![vec![Some(Receipt::default()); 2]; 1].into(),
1434            first_block: 2,
1435            requests: Vec::new(),
1436        };
1437
1438        test.prepend_state(previous_state);
1439
1440        assert_eq!(test.receipts.len(), 1);
1441        let end_state = test.state();
1442        assert_eq!(end_state.state.len(), 2);
1443        // reverts num should stay the same.
1444        assert_eq!(end_state.reverts.len(), 1);
1445        // account1 is not overwritten.
1446        assert_eq!(end_state.state.get(&address1).unwrap().info, Some(account1_changed));
1447        // account2 got inserted
1448        assert_eq!(end_state.state.get(&address2).unwrap().info, Some(account2));
1449    }
1450
1451    #[test]
1452    fn hashed_state_storage_root() {
1453        let address = Address::random();
1454        let hashed_address = keccak256(address);
1455        let provider_factory = create_test_provider_factory();
1456        let provider_rw = provider_factory.provider_rw().unwrap();
1457        let tx = provider_rw.tx_ref();
1458
1459        // insert initial account storage
1460        let init_storage = HashedStorage::from_iter(
1461            false,
1462            [
1463                "50000000000000000000000000000004253371b55351a08cb3267d4d265530b6",
1464                "512428ed685fff57294d1a9cbb147b18ae5db9cf6ae4b312fa1946ba0561882e",
1465                "51e6784c736ef8548f856909870b38e49ef7a4e3e77e5e945e0d5e6fcaa3037f",
1466            ]
1467            .into_iter()
1468            .map(|str| (B256::from_str(str).unwrap(), FlaggedStorage::new_from_value(1))),
1469        );
1470        let mut state = HashedPostState::default();
1471        state.storages.insert(hashed_address, init_storage.clone());
1472        provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1473
1474        // calculate database storage root and write intermediate storage nodes.
1475        let (storage_root, _, storage_updates) =
1476            StorageRoot::from_tx_hashed(tx, hashed_address).calculate(true).unwrap();
1477        assert_eq!(
1478            storage_root,
1479            storage_root_prehashed(FlaggedStorage::collect_value(init_storage.storage))
1480        );
1481        assert!(!storage_updates.is_empty());
1482        provider_rw
1483            .write_individual_storage_trie_updates(hashed_address, &storage_updates)
1484            .unwrap();
1485
1486        // destroy the storage and re-create with new slots
1487        let updated_storage = HashedStorage::from_iter(
1488            true,
1489            [
1490                "00deb8486ad8edccfdedfc07109b3667b38a03a8009271aac250cce062d90917",
1491                "88d233b7380bb1bcdc866f6871c94685848f54cf0ee033b1480310b4ddb75fc9",
1492            ]
1493            .into_iter()
1494            .map(|str| (B256::from_str(str).unwrap(), FlaggedStorage::new_from_value(1))),
1495        );
1496        let mut state = HashedPostState::default();
1497        state.storages.insert(hashed_address, updated_storage.clone());
1498        provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1499
1500        // re-calculate database storage root
1501        let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap();
1502        assert_eq!(
1503            storage_root,
1504            storage_root_prehashed(FlaggedStorage::collect_value(updated_storage.storage))
1505        );
1506    }
1507}