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, ExecutedBlockWithTrieUpdates};
8use reth_db_api::transaction::{DbTx, DbTxMut};
9use reth_errors::ProviderResult;
10use reth_primitives_traits::{NodePrimitives, SignedTransaction};
11use reth_static_file_types::StaticFileSegment;
12use reth_storage_api::{DBProvider, StageCheckpointWriter, TransactionsProviderExt};
13use reth_storage_errors::writer::UnifiedStorageWriterError;
14use revm_database::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    const 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    #[expect(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<ExecutedBlockWithTrieUpdates<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().recovered_block();
147
148        let last_block = blocks.last().unwrap().recovered_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 ExecutedBlockWithTrieUpdates {
164            block: ExecutedBlock { recovered_block, execution_output, hashed_state },
165            trie,
166        } in blocks
167        {
168            self.database()
169                .insert_block(Arc::unwrap_or_clone(recovered_block), StorageLocation::Both)?;
170
171            // Write state and changesets to the database.
172            // Must be written after blocks because of the receipt lookup.
173            self.database().write_state(
174                &execution_output,
175                OriginalValuesKnown::No,
176                StorageLocation::StaticFiles,
177            )?;
178
179            // insert hashes and intermediate merkle nodes
180            self.database()
181                .write_hashed_state(&Arc::unwrap_or_clone(hashed_state).into_sorted())?;
182            self.database().write_trie_updates(&trie)?;
183        }
184
185        // update history indices
186        self.database().update_history_indices(first_number..=last_block_number)?;
187
188        // Update pipeline progress
189        self.database().update_pipeline_stages(last_block_number, false)?;
190
191        debug!(target: "provider::storage_writer", range = ?first_number..=last_block_number, "Appended block data");
192
193        Ok(())
194    }
195
196    /// Removes all block, transaction and receipt data above the given block number from the
197    /// database and static files. This is exclusive, i.e., it only removes blocks above
198    /// `block_number`, and does not remove `block_number`.
199    pub fn remove_blocks_above(&self, block_number: u64) -> ProviderResult<()> {
200        // IMPORTANT: we use `block_number+1` to make sure we remove only what is ABOVE the block
201        debug!(target: "provider::storage_writer", ?block_number, "Removing blocks from database above block_number");
202        self.database().remove_block_and_execution_above(block_number, StorageLocation::Both)?;
203
204        // Get highest static file block for the total block range
205        let highest_static_file_block = self
206            .static_file()
207            .get_highest_static_file_block(StaticFileSegment::Headers)
208            .expect("todo: error handling, headers should exist");
209
210        // IMPORTANT: we use `highest_static_file_block.saturating_sub(block_number)` to make sure
211        // we remove only what is ABOVE the block.
212        //
213        // i.e., if the highest static file block is 8, we want to remove above block 5 only, we
214        // will have three blocks to remove, which will be block 8, 7, and 6.
215        debug!(target: "provider::storage_writer", ?block_number, "Removing static file blocks above block_number");
216        self.static_file()
217            .get_writer(block_number, StaticFileSegment::Headers)?
218            .prune_headers(highest_static_file_block.saturating_sub(block_number))?;
219
220        Ok(())
221    }
222}
223
224#[cfg(test)]
225mod tests {
226    use super::*;
227    use crate::{
228        test_utils::create_test_provider_factory, AccountReader, StorageTrieWriter, TrieWriter,
229    };
230    use alloy_primitives::{keccak256, map::HashMap, Address, B256, U256};
231    use reth_db_api::{
232        cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO},
233        models::{AccountBeforeTx, BlockNumberAddress},
234        tables,
235        transaction::{DbTx, DbTxMut},
236    };
237    use reth_ethereum_primitives::Receipt;
238    use reth_execution_types::ExecutionOutcome;
239    use reth_primitives_traits::{Account, StorageEntry};
240    use reth_storage_api::{DatabaseProviderFactory, HashedPostStateProvider};
241    use reth_trie::{
242        test_utils::{state_root, storage_root_prehashed},
243        HashedPostState, HashedStorage, StateRoot, StorageRoot,
244    };
245    use reth_trie_db::{DatabaseStateRoot, DatabaseStorageRoot};
246    use revm_database::{
247        states::{
248            bundle_state::BundleRetention, changes::PlainStorageRevert, PlainStorageChangeset,
249        },
250        BundleState, State,
251    };
252    use revm_database_interface::{DatabaseCommit, EmptyDB};
253    use revm_state::{
254        Account as RevmAccount, AccountInfo as RevmAccountInfo, AccountStatus, EvmStorageSlot,
255        FlaggedStorage,
256    };
257    use std::{collections::BTreeMap, str::FromStr};
258
259    #[test]
260    fn wiped_entries_are_removed() {
261        let provider_factory = create_test_provider_factory();
262
263        let addresses = (0..10).map(|_| Address::random()).collect::<Vec<_>>();
264        let destroyed_address = *addresses.first().unwrap();
265        let destroyed_address_hashed = keccak256(destroyed_address);
266        let slot = B256::with_last_byte(1);
267        let hashed_slot = keccak256(slot);
268        {
269            let provider_rw = provider_factory.provider_rw().unwrap();
270            let mut accounts_cursor =
271                provider_rw.tx_ref().cursor_write::<tables::HashedAccounts>().unwrap();
272            let mut storage_cursor =
273                provider_rw.tx_ref().cursor_write::<tables::HashedStorages>().unwrap();
274
275            for address in addresses {
276                let hashed_address = keccak256(address);
277                accounts_cursor
278                    .insert(hashed_address, &Account { nonce: 1, ..Default::default() })
279                    .unwrap();
280                storage_cursor
281                    .insert(
282                        hashed_address,
283                        &StorageEntry { key: hashed_slot, value: U256::from(1), is_private: false },
284                    )
285                    .unwrap();
286            }
287            provider_rw.commit().unwrap();
288        }
289
290        let mut hashed_state = HashedPostState::default();
291        hashed_state.accounts.insert(destroyed_address_hashed, None);
292        hashed_state.storages.insert(destroyed_address_hashed, HashedStorage::new(true));
293
294        let provider_rw = provider_factory.provider_rw().unwrap();
295        assert!(matches!(provider_rw.write_hashed_state(&hashed_state.into_sorted()), Ok(())));
296        provider_rw.commit().unwrap();
297
298        let provider = provider_factory.provider().unwrap();
299        assert_eq!(
300            provider.tx_ref().get::<tables::HashedAccounts>(destroyed_address_hashed),
301            Ok(None)
302        );
303        assert_eq!(
304            provider
305                .tx_ref()
306                .cursor_read::<tables::HashedStorages>()
307                .unwrap()
308                .seek_by_key_subkey(destroyed_address_hashed, hashed_slot),
309            Ok(None)
310        );
311    }
312
313    #[test]
314    fn write_to_db_account_info() {
315        let factory = create_test_provider_factory();
316        let provider = factory.provider_rw().unwrap();
317
318        let address_a = Address::ZERO;
319        let address_b = Address::repeat_byte(0xff);
320
321        let account_a = RevmAccountInfo { balance: U256::from(1), nonce: 1, ..Default::default() };
322        let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
323        let account_b_changed =
324            RevmAccountInfo { balance: U256::from(3), nonce: 3, ..Default::default() };
325
326        let mut state = State::builder().with_bundle_update().build();
327        state.insert_not_existing(address_a);
328        state.insert_account(address_b, account_b.clone());
329
330        // 0x00.. is created
331        state.commit(HashMap::from_iter([(
332            address_a,
333            RevmAccount {
334                info: account_a.clone(),
335                status: AccountStatus::Touched | AccountStatus::Created,
336                storage: HashMap::default(),
337            },
338        )]));
339
340        // 0xff.. is changed (balance + 1, nonce + 1)
341        state.commit(HashMap::from_iter([(
342            address_b,
343            RevmAccount {
344                info: account_b_changed.clone(),
345                status: AccountStatus::Touched,
346                storage: HashMap::default(),
347            },
348        )]));
349
350        state.merge_transitions(BundleRetention::Reverts);
351        let mut revm_bundle_state = state.take_bundle();
352
353        // Write plain state and reverts separately.
354        let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
355        let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
356        assert!(plain_state.storage.is_empty());
357        assert!(plain_state.contracts.is_empty());
358        provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
359
360        assert_eq!(reverts.storage, [[]]);
361        provider.write_state_reverts(reverts, 1).expect("Could not write reverts to DB");
362
363        let reth_account_a = account_a.into();
364        let reth_account_b = account_b.into();
365        let reth_account_b_changed = (&account_b_changed).into();
366
367        // Check plain state
368        assert_eq!(
369            provider.basic_account(&address_a).expect("Could not read account state"),
370            Some(reth_account_a),
371            "Account A state is wrong"
372        );
373        assert_eq!(
374            provider.basic_account(&address_b).expect("Could not read account state"),
375            Some(reth_account_b_changed),
376            "Account B state is wrong"
377        );
378
379        // Check change set
380        let mut changeset_cursor = provider
381            .tx_ref()
382            .cursor_dup_read::<tables::AccountChangeSets>()
383            .expect("Could not open changeset cursor");
384        assert_eq!(
385            changeset_cursor.seek_exact(1).expect("Could not read account change set"),
386            Some((1, AccountBeforeTx { address: address_a, info: None })),
387            "Account A changeset is wrong"
388        );
389        assert_eq!(
390            changeset_cursor.next_dup().expect("Changeset table is malformed"),
391            Some((1, AccountBeforeTx { address: address_b, info: Some(reth_account_b) })),
392            "Account B changeset is wrong"
393        );
394
395        let mut state = State::builder().with_bundle_update().build();
396        state.insert_account(address_b, account_b_changed.clone());
397
398        // 0xff.. is destroyed
399        state.commit(HashMap::from_iter([(
400            address_b,
401            RevmAccount {
402                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
403                info: account_b_changed,
404                storage: HashMap::default(),
405            },
406        )]));
407
408        state.merge_transitions(BundleRetention::Reverts);
409        let mut revm_bundle_state = state.take_bundle();
410
411        // Write plain state and reverts separately.
412        let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
413        let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
414        // Account B selfdestructed so flag for it should be present.
415        assert_eq!(
416            plain_state.storage,
417            [PlainStorageChangeset { address: address_b, wipe_storage: true, storage: vec![] }]
418        );
419        assert!(plain_state.contracts.is_empty());
420        provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
421
422        assert_eq!(
423            reverts.storage,
424            [[PlainStorageRevert { address: address_b, wiped: true, storage_revert: vec![] }]]
425        );
426        provider.write_state_reverts(reverts, 2).expect("Could not write reverts to DB");
427
428        // Check new plain state for account B
429        assert_eq!(
430            provider.basic_account(&address_b).expect("Could not read account state"),
431            None,
432            "Account B should be deleted"
433        );
434
435        // Check change set
436        assert_eq!(
437            changeset_cursor.seek_exact(2).expect("Could not read account change set"),
438            Some((2, AccountBeforeTx { address: address_b, info: Some(reth_account_b_changed) })),
439            "Account B changeset is wrong after deletion"
440        );
441    }
442
443    #[test]
444    fn write_to_db_storage() {
445        let factory = create_test_provider_factory();
446        let provider = factory.database_provider_rw().unwrap();
447
448        let address_a = Address::ZERO;
449        let address_b = Address::repeat_byte(0xff);
450        let address_c = Address::random();
451
452        let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
453        let account_c = RevmAccountInfo { balance: U256::from(1), nonce: 3, ..Default::default() };
454
455        let mut state = State::builder().with_bundle_update().build();
456        state.insert_not_existing(address_a);
457        state.insert_account_with_storage(
458            address_b,
459            account_b.clone(),
460            HashMap::from_iter([(U256::from(1), FlaggedStorage::new(1, false))]),
461        );
462        state.insert_account_with_storage(
463            address_c,
464            account_c.clone(),
465            HashMap::from_iter([(U256::from(3), FlaggedStorage::new(1, false))]),
466        );
467
468        state.commit(HashMap::from_iter([
469            (
470                address_a,
471                RevmAccount {
472                    status: AccountStatus::Touched | AccountStatus::Created,
473                    info: RevmAccountInfo::default(),
474                    // 0x00 => 0 => 1
475                    // 0x01 => 0 => 2
476                    storage: HashMap::from_iter([
477                        (
478                            U256::from(0),
479                            EvmStorageSlot {
480                                present_value: FlaggedStorage::new(1, true),
481                                ..Default::default()
482                            },
483                        ),
484                        (
485                            U256::from(1),
486                            EvmStorageSlot {
487                                present_value: FlaggedStorage::new(2, true),
488                                ..Default::default()
489                            },
490                        ),
491                    ]),
492                },
493            ),
494            (
495                address_b,
496                RevmAccount {
497                    status: AccountStatus::Touched,
498                    info: account_b,
499                    // 0x01 => 1 => 2
500                    storage: HashMap::from_iter([(
501                        U256::from(1),
502                        EvmStorageSlot {
503                            present_value: FlaggedStorage::new(2, false),
504                            original_value: FlaggedStorage::new(1, false),
505                            ..Default::default()
506                        },
507                    )]),
508                },
509            ),
510            (
511                address_c,
512                RevmAccount {
513                    status: AccountStatus::Touched,
514                    info: account_c,
515                    // 0x03 => {private: false, value: 1} => {private: true, value: 2}
516                    storage: HashMap::from_iter([(
517                        U256::from(3),
518                        EvmStorageSlot {
519                            present_value: FlaggedStorage::new(2, true),
520                            original_value: FlaggedStorage::new(1, false),
521                            ..Default::default()
522                        },
523                    )]),
524                },
525            ),
526        ]));
527
528        state.merge_transitions(BundleRetention::Reverts);
529
530        let outcome = ExecutionOutcome::new(state.take_bundle(), Default::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 = ExecutionOutcome::new(state.take_bundle(), Default::default(), 2, Vec::new());
684        provider
685            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
686            .expect("Could not write bundle state to DB");
687
688        assert_eq!(
689            storage_cursor.seek_exact(address_a).unwrap(),
690            None,
691            "Account A should have no storage slots after deletion"
692        );
693
694        assert_eq!(
695            changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(),
696            Some((
697                BlockNumberAddress((2, address_a)),
698                StorageEntry { key: B256::ZERO, value: U256::from(1), is_private: true }
699            )),
700            "Slot 0 for account A should have changed from a private 1 on deletion"
701        );
702        assert_eq!(
703            changeset_cursor.next_dup().unwrap(),
704            Some((
705                BlockNumberAddress((2, address_a)),
706                StorageEntry {
707                    key: B256::from(U256::from(1).to_be_bytes()),
708                    value: U256::from(2),
709                    is_private: true
710                }
711            )),
712            "Slot 1 for account A should have changed from a private 2 on deletion"
713        );
714        assert_eq!(
715            changeset_cursor.next_dup().unwrap(),
716            None,
717            "Account A should only be in the changeset 2 times on deletion"
718        );
719    }
720
721    #[test]
722    fn write_to_db_multiple_selfdestructs() {
723        let factory = create_test_provider_factory();
724        let provider = factory.database_provider_rw().unwrap();
725
726        let address1 = Address::random();
727        let account_info = RevmAccountInfo { nonce: 1, ..Default::default() };
728
729        // Block #0: initial state.
730        let mut init_state = State::builder().with_bundle_update().build();
731        init_state.insert_not_existing(address1);
732        init_state.commit(HashMap::from_iter([(
733            address1,
734            RevmAccount {
735                info: account_info.clone(),
736                status: AccountStatus::Touched | AccountStatus::Created,
737                // 0x00 => 0 => 1
738                // 0x01 => 0 => 2
739                storage: HashMap::from_iter([
740                    (
741                        U256::ZERO,
742                        EvmStorageSlot {
743                            present_value: FlaggedStorage::new_from_value(1),
744                            ..Default::default()
745                        },
746                    ),
747                    (
748                        U256::from(1),
749                        EvmStorageSlot {
750                            present_value: FlaggedStorage::new_from_value(2),
751                            ..Default::default()
752                        },
753                    ),
754                ]),
755            },
756        )]));
757        init_state.merge_transitions(BundleRetention::Reverts);
758
759        let outcome =
760            ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
761        provider
762            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
763            .expect("Could not write bundle state to DB");
764
765        let mut state = State::builder().with_bundle_update().build();
766        state.insert_account_with_storage(
767            address1,
768            account_info.clone(),
769            HashMap::from_iter([
770                (U256::ZERO, FlaggedStorage::new_from_value(1)),
771                (U256::from(1), FlaggedStorage::new_from_value(2)),
772            ]),
773        );
774
775        // Block #1: change storage.
776        state.commit(HashMap::from_iter([(
777            address1,
778            RevmAccount {
779                status: AccountStatus::Touched,
780                info: account_info.clone(),
781                // 0x00 => 1 => 2
782                storage: HashMap::from_iter([(
783                    U256::ZERO,
784                    EvmStorageSlot {
785                        original_value: FlaggedStorage::new_from_value(1),
786                        present_value: FlaggedStorage::new_from_value(2),
787                        ..Default::default()
788                    },
789                )]),
790            },
791        )]));
792        state.merge_transitions(BundleRetention::Reverts);
793
794        // Block #2: destroy account.
795        state.commit(HashMap::from_iter([(
796            address1,
797            RevmAccount {
798                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
799                info: account_info.clone(),
800                storage: HashMap::default(),
801            },
802        )]));
803        state.merge_transitions(BundleRetention::Reverts);
804
805        // Block #3: re-create account and change storage.
806        state.commit(HashMap::from_iter([(
807            address1,
808            RevmAccount {
809                status: AccountStatus::Touched | AccountStatus::Created,
810                info: account_info.clone(),
811                storage: HashMap::default(),
812            },
813        )]));
814        state.merge_transitions(BundleRetention::Reverts);
815
816        // Block #4: change storage.
817        state.commit(HashMap::from_iter([(
818            address1,
819            RevmAccount {
820                status: AccountStatus::Touched,
821                info: account_info.clone(),
822                // 0x00 => 0 => 2
823                // 0x02 => 0 => 4
824                // 0x06 => 0 => 6
825                storage: HashMap::from_iter([
826                    (
827                        U256::ZERO,
828                        EvmStorageSlot {
829                            present_value: FlaggedStorage::new_from_value(2),
830                            ..Default::default()
831                        },
832                    ),
833                    (
834                        U256::from(2),
835                        EvmStorageSlot {
836                            present_value: FlaggedStorage::new_from_value(4),
837                            ..Default::default()
838                        },
839                    ),
840                    (
841                        U256::from(6),
842                        EvmStorageSlot {
843                            present_value: FlaggedStorage::new_from_value(6),
844                            ..Default::default()
845                        },
846                    ),
847                ]),
848            },
849        )]));
850        state.merge_transitions(BundleRetention::Reverts);
851
852        // Block #5: Destroy account again.
853        state.commit(HashMap::from_iter([(
854            address1,
855            RevmAccount {
856                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
857                info: account_info.clone(),
858                storage: HashMap::default(),
859            },
860        )]));
861        state.merge_transitions(BundleRetention::Reverts);
862
863        // Block #6: Create, change, destroy and re-create in the same block.
864        state.commit(HashMap::from_iter([(
865            address1,
866            RevmAccount {
867                status: AccountStatus::Touched | AccountStatus::Created,
868                info: account_info.clone(),
869                storage: HashMap::default(),
870            },
871        )]));
872        state.commit(HashMap::from_iter([(
873            address1,
874            RevmAccount {
875                status: AccountStatus::Touched,
876                info: account_info.clone(),
877                // 0x00 => 0 => 2
878                storage: HashMap::from_iter([(
879                    U256::ZERO,
880                    EvmStorageSlot {
881                        present_value: FlaggedStorage::new_from_value(2),
882                        ..Default::default()
883                    },
884                )]),
885            },
886        )]));
887        state.commit(HashMap::from_iter([(
888            address1,
889            RevmAccount {
890                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
891                info: account_info.clone(),
892                storage: HashMap::default(),
893            },
894        )]));
895        state.commit(HashMap::from_iter([(
896            address1,
897            RevmAccount {
898                status: AccountStatus::Touched | AccountStatus::Created,
899                info: account_info.clone(),
900                storage: HashMap::default(),
901            },
902        )]));
903        state.merge_transitions(BundleRetention::Reverts);
904
905        // Block #7: Change storage.
906        state.commit(HashMap::from_iter([(
907            address1,
908            RevmAccount {
909                status: AccountStatus::Touched,
910                info: account_info,
911                // 0x00 => 0 => 9
912                storage: HashMap::from_iter([(
913                    U256::ZERO,
914                    EvmStorageSlot {
915                        present_value: FlaggedStorage::new_from_value(9),
916                        ..Default::default()
917                    },
918                )]),
919            },
920        )]));
921        state.merge_transitions(BundleRetention::Reverts);
922
923        let bundle = state.take_bundle();
924
925        let outcome: ExecutionOutcome =
926            ExecutionOutcome::new(bundle, Default::default(), 1, Vec::new());
927        provider
928            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
929            .expect("Could not write bundle state to DB");
930
931        let mut storage_changeset_cursor = provider
932            .tx_ref()
933            .cursor_dup_read::<tables::StorageChangeSets>()
934            .expect("Could not open plain storage state cursor");
935        let mut storage_changes = storage_changeset_cursor.walk_range(..).unwrap();
936
937        // Iterate through all storage changes
938
939        // Block <number>
940        // <slot>: <expected value before>
941        // ...
942
943        // Block #0
944        // 0x00: 0
945        // 0x01: 0
946        assert_eq!(
947            storage_changes.next(),
948            Some(Ok((
949                BlockNumberAddress((0, address1)),
950                StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO, is_private: false }
951            )))
952        );
953        assert_eq!(
954            storage_changes.next(),
955            Some(Ok((
956                BlockNumberAddress((0, address1)),
957                StorageEntry { key: B256::with_last_byte(1), value: U256::ZERO, is_private: false }
958            )))
959        );
960
961        // Block #1
962        // 0x00: 1
963        assert_eq!(
964            storage_changes.next(),
965            Some(Ok((
966                BlockNumberAddress((1, address1)),
967                StorageEntry {
968                    key: B256::with_last_byte(0),
969                    value: U256::from(1),
970                    is_private: false
971                }
972            )))
973        );
974
975        // Block #2 (destroyed)
976        // 0x00: 2
977        // 0x01: 2
978        assert_eq!(
979            storage_changes.next(),
980            Some(Ok((
981                BlockNumberAddress((2, address1)),
982                StorageEntry {
983                    key: B256::with_last_byte(0),
984                    value: U256::from(2),
985                    is_private: false
986                }
987            )))
988        );
989        assert_eq!(
990            storage_changes.next(),
991            Some(Ok((
992                BlockNumberAddress((2, address1)),
993                StorageEntry {
994                    key: B256::with_last_byte(1),
995                    value: U256::from(2),
996                    is_private: false
997                }
998            )))
999        );
1000
1001        // Block #3
1002        // no storage changes
1003
1004        // Block #4
1005        // 0x00: 0
1006        // 0x02: 0
1007        // 0x06: 0
1008        assert_eq!(
1009            storage_changes.next(),
1010            Some(Ok((
1011                BlockNumberAddress((4, address1)),
1012                StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO, is_private: false }
1013            )))
1014        );
1015        assert_eq!(
1016            storage_changes.next(),
1017            Some(Ok((
1018                BlockNumberAddress((4, address1)),
1019                StorageEntry { key: B256::with_last_byte(2), value: U256::ZERO, is_private: false }
1020            )))
1021        );
1022        assert_eq!(
1023            storage_changes.next(),
1024            Some(Ok((
1025                BlockNumberAddress((4, address1)),
1026                StorageEntry { key: B256::with_last_byte(6), value: U256::ZERO, is_private: false }
1027            )))
1028        );
1029
1030        // Block #5 (destroyed)
1031        // 0x00: 2
1032        // 0x02: 4
1033        // 0x06: 6
1034        assert_eq!(
1035            storage_changes.next(),
1036            Some(Ok((
1037                BlockNumberAddress((5, address1)),
1038                StorageEntry {
1039                    key: B256::with_last_byte(0),
1040                    value: U256::from(2),
1041                    is_private: false
1042                }
1043            )))
1044        );
1045        assert_eq!(
1046            storage_changes.next(),
1047            Some(Ok((
1048                BlockNumberAddress((5, address1)),
1049                StorageEntry {
1050                    key: B256::with_last_byte(2),
1051                    value: U256::from(4),
1052                    is_private: false
1053                }
1054            )))
1055        );
1056        assert_eq!(
1057            storage_changes.next(),
1058            Some(Ok((
1059                BlockNumberAddress((5, address1)),
1060                StorageEntry {
1061                    key: B256::with_last_byte(6),
1062                    value: U256::from(6),
1063                    is_private: false
1064                }
1065            )))
1066        );
1067
1068        // Block #6
1069        // no storage changes (only inter block changes)
1070
1071        // Block #7
1072        // 0x00: 0
1073        assert_eq!(
1074            storage_changes.next(),
1075            Some(Ok((
1076                BlockNumberAddress((7, address1)),
1077                StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO, is_private: false }
1078            )))
1079        );
1080        assert_eq!(storage_changes.next(), None);
1081    }
1082
1083    #[test]
1084    fn storage_change_after_selfdestruct_within_block() {
1085        let factory = create_test_provider_factory();
1086        let provider = factory.database_provider_rw().unwrap();
1087
1088        let address1 = Address::random();
1089        let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1090
1091        // Block #0: initial state.
1092        let mut init_state = State::builder().with_bundle_update().build();
1093        init_state.insert_not_existing(address1);
1094        init_state.commit(HashMap::from_iter([(
1095            address1,
1096            RevmAccount {
1097                info: account1.clone(),
1098                status: AccountStatus::Touched | AccountStatus::Created,
1099                // 0x00 => 0 => 1
1100                // 0x01 => 0 => 2
1101                storage: HashMap::from_iter([
1102                    (
1103                        U256::ZERO,
1104                        EvmStorageSlot {
1105                            present_value: FlaggedStorage::new_from_value(1),
1106                            ..Default::default()
1107                        },
1108                    ),
1109                    (
1110                        U256::from(1),
1111                        EvmStorageSlot {
1112                            present_value: FlaggedStorage::new_from_value(2),
1113                            ..Default::default()
1114                        },
1115                    ),
1116                ]),
1117            },
1118        )]));
1119        init_state.merge_transitions(BundleRetention::Reverts);
1120        let outcome =
1121            ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
1122        provider
1123            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1124            .expect("Could not write bundle state to DB");
1125
1126        let mut state = State::builder().with_bundle_update().build();
1127        state.insert_account_with_storage(
1128            address1,
1129            account1.clone(),
1130            HashMap::from_iter([
1131                (U256::ZERO, FlaggedStorage::new_from_value(1)),
1132                (U256::from(1), FlaggedStorage::new_from_value(2)),
1133            ]),
1134        );
1135
1136        // Block #1: Destroy, re-create, change storage.
1137        state.commit(HashMap::from_iter([(
1138            address1,
1139            RevmAccount {
1140                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1141                info: account1.clone(),
1142                storage: HashMap::default(),
1143            },
1144        )]));
1145
1146        state.commit(HashMap::from_iter([(
1147            address1,
1148            RevmAccount {
1149                status: AccountStatus::Touched | AccountStatus::Created,
1150                info: account1.clone(),
1151                storage: HashMap::default(),
1152            },
1153        )]));
1154
1155        state.commit(HashMap::from_iter([(
1156            address1,
1157            RevmAccount {
1158                status: AccountStatus::Touched,
1159                info: account1,
1160                // 0x01 => 0 => 5
1161                storage: HashMap::from_iter([(
1162                    U256::from(1),
1163                    EvmStorageSlot {
1164                        present_value: FlaggedStorage::new_from_value(5),
1165                        ..Default::default()
1166                    },
1167                )]),
1168            },
1169        )]));
1170
1171        // Commit block #1 changes to the database.
1172        state.merge_transitions(BundleRetention::Reverts);
1173        let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
1174        provider
1175            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1176            .expect("Could not write bundle state to DB");
1177
1178        let mut storage_changeset_cursor = provider
1179            .tx_ref()
1180            .cursor_dup_read::<tables::StorageChangeSets>()
1181            .expect("Could not open plain storage state cursor");
1182        let range = BlockNumberAddress::range(1..=1);
1183        let mut storage_changes = storage_changeset_cursor.walk_range(range).unwrap();
1184
1185        assert_eq!(
1186            storage_changes.next(),
1187            Some(Ok((
1188                BlockNumberAddress((1, address1)),
1189                StorageEntry {
1190                    key: B256::with_last_byte(0),
1191                    value: U256::from(1),
1192                    is_private: false
1193                }
1194            )))
1195        );
1196        assert_eq!(
1197            storage_changes.next(),
1198            Some(Ok((
1199                BlockNumberAddress((1, address1)),
1200                StorageEntry {
1201                    key: B256::with_last_byte(1),
1202                    value: U256::from(2),
1203                    is_private: false
1204                }
1205            )))
1206        );
1207        assert_eq!(storage_changes.next(), None);
1208    }
1209
1210    #[test]
1211    fn revert_to_indices() {
1212        let base: ExecutionOutcome = ExecutionOutcome {
1213            bundle: BundleState::default(),
1214            receipts: vec![vec![Receipt::default(); 2]; 7],
1215            first_block: 10,
1216            requests: Vec::new(),
1217        };
1218
1219        let mut this = base.clone();
1220        assert!(this.revert_to(10));
1221        assert_eq!(this.receipts.len(), 1);
1222
1223        let mut this = base.clone();
1224        assert!(!this.revert_to(9));
1225        assert_eq!(this.receipts.len(), 7);
1226
1227        let mut this = base.clone();
1228        assert!(this.revert_to(15));
1229        assert_eq!(this.receipts.len(), 6);
1230
1231        let mut this = base.clone();
1232        assert!(this.revert_to(16));
1233        assert_eq!(this.receipts.len(), 7);
1234
1235        let mut this = base;
1236        assert!(!this.revert_to(17));
1237        assert_eq!(this.receipts.len(), 7);
1238    }
1239
1240    #[test]
1241    fn bundle_state_state_root() {
1242        type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>;
1243        let mut prestate: PreState = (0..10)
1244            .map(|key| {
1245                let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None };
1246                let storage =
1247                    (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect();
1248                (Address::with_last_byte(key), (account, storage))
1249            })
1250            .collect();
1251
1252        let provider_factory = create_test_provider_factory();
1253        let provider_rw = provider_factory.database_provider_rw().unwrap();
1254
1255        // insert initial state to the database
1256        let tx = provider_rw.tx_ref();
1257        for (address, (account, storage)) in &prestate {
1258            let hashed_address = keccak256(address);
1259            tx.put::<tables::HashedAccounts>(hashed_address, *account).unwrap();
1260            for (slot, value) in storage {
1261                tx.put::<tables::HashedStorages>(
1262                    hashed_address,
1263                    StorageEntry { key: keccak256(slot), value: *value, is_private: false },
1264                )
1265                .unwrap();
1266            }
1267        }
1268
1269        let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
1270        provider_rw.write_trie_updates(&updates).unwrap();
1271
1272        let mut state = State::builder().with_bundle_update().build();
1273
1274        let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
1275            assert_eq!(
1276                StateRoot::overlay_root(
1277                    tx,
1278                    provider_factory.hashed_post_state(&state.bundle_state)
1279                )
1280                .unwrap(),
1281                state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
1282                    address,
1283                    (account, storage.into_iter())
1284                ))),
1285                "{msg}"
1286            );
1287        };
1288
1289        // database only state root is correct
1290        assert_state_root(&state, &prestate, "empty");
1291
1292        // destroy account 1
1293        let address1 = Address::with_last_byte(1);
1294        let account1_old = prestate.remove(&address1).unwrap();
1295        state.insert_account(address1, account1_old.0.into());
1296        state.commit(HashMap::from_iter([(
1297            address1,
1298            RevmAccount {
1299                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1300                info: RevmAccountInfo::default(),
1301                storage: HashMap::default(),
1302            },
1303        )]));
1304        state.merge_transitions(BundleRetention::PlainState);
1305        assert_state_root(&state, &prestate, "destroyed account");
1306
1307        // change slot 2 in account 2
1308        let address2 = Address::with_last_byte(2);
1309        let slot2 = U256::from(2);
1310        let slot2_key = B256::from(slot2);
1311        let account2 = prestate.get_mut(&address2).unwrap();
1312        let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap();
1313        state.insert_account_with_storage(
1314            address2,
1315            account2.0.into(),
1316            HashMap::from_iter([(slot2, FlaggedStorage::new_from_value(account2_slot2_old_value))]),
1317        );
1318
1319        let account2_slot2_new_value = U256::from(100);
1320        account2.1.insert(slot2_key, account2_slot2_new_value);
1321        state.commit(HashMap::from_iter([(
1322            address2,
1323            RevmAccount {
1324                status: AccountStatus::Touched,
1325                info: account2.0.into(),
1326                storage: HashMap::from_iter([(
1327                    slot2,
1328                    EvmStorageSlot::new_changed(
1329                        FlaggedStorage::new_from_value(account2_slot2_old_value),
1330                        FlaggedStorage::new_from_value(account2_slot2_new_value),
1331                    ),
1332                )]),
1333            },
1334        )]));
1335        state.merge_transitions(BundleRetention::PlainState);
1336        assert_state_root(&state, &prestate, "changed storage");
1337
1338        // change balance of account 3
1339        let address3 = Address::with_last_byte(3);
1340        let account3 = prestate.get_mut(&address3).unwrap();
1341        state.insert_account(address3, account3.0.into());
1342
1343        account3.0.balance = U256::from(24);
1344        state.commit(HashMap::from_iter([(
1345            address3,
1346            RevmAccount {
1347                status: AccountStatus::Touched,
1348                info: account3.0.into(),
1349                storage: HashMap::default(),
1350            },
1351        )]));
1352        state.merge_transitions(BundleRetention::PlainState);
1353        assert_state_root(&state, &prestate, "changed balance");
1354
1355        // change nonce of account 4
1356        let address4 = Address::with_last_byte(4);
1357        let account4 = prestate.get_mut(&address4).unwrap();
1358        state.insert_account(address4, account4.0.into());
1359
1360        account4.0.nonce = 128;
1361        state.commit(HashMap::from_iter([(
1362            address4,
1363            RevmAccount {
1364                status: AccountStatus::Touched,
1365                info: account4.0.into(),
1366                storage: HashMap::default(),
1367            },
1368        )]));
1369        state.merge_transitions(BundleRetention::PlainState);
1370        assert_state_root(&state, &prestate, "changed nonce");
1371
1372        // recreate account 1
1373        let account1_new =
1374            Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) };
1375        prestate.insert(address1, (account1_new, BTreeMap::default()));
1376        state.commit(HashMap::from_iter([(
1377            address1,
1378            RevmAccount {
1379                status: AccountStatus::Touched | AccountStatus::Created,
1380                info: account1_new.into(),
1381                storage: HashMap::default(),
1382            },
1383        )]));
1384        state.merge_transitions(BundleRetention::PlainState);
1385        assert_state_root(&state, &prestate, "recreated");
1386
1387        // update storage for account 1
1388        let slot20 = U256::from(20);
1389        let slot20_key = B256::from(slot20);
1390        let account1_slot20_value = U256::from(12345);
1391        prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value);
1392        state.commit(HashMap::from_iter([(
1393            address1,
1394            RevmAccount {
1395                status: AccountStatus::Touched | AccountStatus::Created,
1396                info: account1_new.into(),
1397                storage: HashMap::from_iter([(
1398                    slot20,
1399                    EvmStorageSlot::new_changed(
1400                        FlaggedStorage::ZERO,
1401                        FlaggedStorage::new_from_value(account1_slot20_value),
1402                    ),
1403                )]),
1404            },
1405        )]));
1406        state.merge_transitions(BundleRetention::PlainState);
1407        assert_state_root(&state, &prestate, "recreated changed storage");
1408    }
1409
1410    #[test]
1411    fn prepend_state() {
1412        let address1 = Address::random();
1413        let address2 = Address::random();
1414
1415        let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1416        let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() };
1417        let account2 = RevmAccountInfo { nonce: 1, ..Default::default() };
1418
1419        let present_state = BundleState::builder(2..=2)
1420            .state_present_account_info(address1, account1_changed.clone())
1421            .build();
1422        assert_eq!(present_state.reverts.len(), 1);
1423        let previous_state = BundleState::builder(1..=1)
1424            .state_present_account_info(address1, account1)
1425            .state_present_account_info(address2, account2.clone())
1426            .build();
1427        assert_eq!(previous_state.reverts.len(), 1);
1428
1429        let mut test: ExecutionOutcome = ExecutionOutcome {
1430            bundle: present_state,
1431            receipts: vec![vec![Receipt::default(); 2]; 1],
1432            first_block: 2,
1433            requests: Vec::new(),
1434        };
1435
1436        test.prepend_state(previous_state);
1437
1438        assert_eq!(test.receipts.len(), 1);
1439        let end_state = test.state();
1440        assert_eq!(end_state.state.len(), 2);
1441        // reverts num should stay the same.
1442        assert_eq!(end_state.reverts.len(), 1);
1443        // account1 is not overwritten.
1444        assert_eq!(end_state.state.get(&address1).unwrap().info, Some(account1_changed));
1445        // account2 got inserted
1446        assert_eq!(end_state.state.get(&address2).unwrap().info, Some(account2));
1447    }
1448
1449    #[test]
1450    fn hashed_state_storage_root() {
1451        let address = Address::random();
1452        let hashed_address = keccak256(address);
1453        let provider_factory = create_test_provider_factory();
1454        let provider_rw = provider_factory.provider_rw().unwrap();
1455        let tx = provider_rw.tx_ref();
1456
1457        // insert initial account storage
1458        let init_storage = HashedStorage::from_iter(
1459            false,
1460            [
1461                "50000000000000000000000000000004253371b55351a08cb3267d4d265530b6",
1462                "512428ed685fff57294d1a9cbb147b18ae5db9cf6ae4b312fa1946ba0561882e",
1463                "51e6784c736ef8548f856909870b38e49ef7a4e3e77e5e945e0d5e6fcaa3037f",
1464            ]
1465            .into_iter()
1466            .map(|str| (B256::from_str(str).unwrap(), FlaggedStorage::new_from_value(1))),
1467        );
1468        let mut state = HashedPostState::default();
1469        state.storages.insert(hashed_address, init_storage.clone());
1470        provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1471
1472        // calculate database storage root and write intermediate storage nodes.
1473        let (storage_root, _, storage_updates) =
1474            StorageRoot::from_tx_hashed(tx, hashed_address).calculate(true).unwrap();
1475        assert_eq!(
1476            storage_root,
1477            storage_root_prehashed(FlaggedStorage::collect_value(init_storage.storage))
1478        );
1479        assert!(!storage_updates.is_empty());
1480        provider_rw
1481            .write_individual_storage_trie_updates(hashed_address, &storage_updates)
1482            .unwrap();
1483
1484        // destroy the storage and re-create with new slots
1485        let updated_storage = HashedStorage::from_iter(
1486            true,
1487            [
1488                "00deb8486ad8edccfdedfc07109b3667b38a03a8009271aac250cce062d90917",
1489                "88d233b7380bb1bcdc866f6871c94685848f54cf0ee033b1480310b4ddb75fc9",
1490            ]
1491            .into_iter()
1492            .map(|str| (B256::from_str(str).unwrap(), FlaggedStorage::new_from_value(1))),
1493        );
1494        let mut state = HashedPostState::default();
1495        state.storages.insert(hashed_address, updated_storage.clone());
1496        provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1497
1498        // re-calculate database storage root
1499        let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap();
1500        assert_eq!(
1501            storage_root,
1502            storage_root_prehashed(FlaggedStorage::collect_value(updated_storage.storage))
1503        );
1504    }
1505}