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: FlaggedStorage::public(1) },
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((address_a, StorageEntry { key: B256::ZERO, value: FlaggedStorage::private(1) })),
544            "Slot 0 for account A should be a private 1"
545        );
546        assert_eq!(
547            storage_cursor.next_dup().unwrap(),
548            Some((
549                address_a,
550                StorageEntry {
551                    key: B256::from(U256::from(1).to_be_bytes()),
552                    value: FlaggedStorage::private(2),
553                }
554            )),
555            "Slot 1 for account A should be a private 2"
556        );
557        assert_eq!(
558            storage_cursor.next_dup().unwrap(),
559            None,
560            "Account A should only have 2 storage slots"
561        );
562
563        assert_eq!(
564            storage_cursor.seek_exact(address_b).unwrap(),
565            Some((
566                address_b,
567                StorageEntry {
568                    key: B256::from(U256::from(1).to_be_bytes()),
569                    value: FlaggedStorage::public(2),
570                }
571            )),
572            "Slot 1 for account B should be a public 2"
573        );
574        assert_eq!(
575            storage_cursor.next_dup().unwrap(),
576            None,
577            "Account B should only have 1 storage slot"
578        );
579        assert_eq!(
580            storage_cursor.seek_exact(address_c).unwrap(),
581            Some((
582                address_c,
583                StorageEntry {
584                    key: B256::from(U256::from(3).to_be_bytes()),
585                    value: FlaggedStorage::private(2),
586                }
587            )),
588            "Slot 3 for account C should be a private 2"
589        );
590        assert_eq!(
591            storage_cursor.next_dup().unwrap(),
592            None,
593            "Account C should only have 1 storage slot"
594        );
595
596        // Check change set
597        let mut changeset_cursor = provider
598            .tx_ref()
599            .cursor_dup_read::<tables::StorageChangeSets>()
600            .expect("Could not open storage changeset cursor");
601        assert_eq!(
602            changeset_cursor.seek_exact(BlockNumberAddress((1, address_a))).unwrap(),
603            Some((
604                BlockNumberAddress((1, address_a)),
605                StorageEntry { key: B256::ZERO, value: FlaggedStorage::ZERO }
606            )),
607            "Slot 0 for account A should have changed from a public 0"
608        );
609        assert_eq!(
610            changeset_cursor.next_dup().unwrap(),
611            Some((
612                BlockNumberAddress((1, address_a)),
613                StorageEntry {
614                    key: B256::from(U256::from(1).to_be_bytes()),
615                    value: FlaggedStorage::ZERO,
616                }
617            )),
618            "Slot 1 for account A should have changed from a public 0"
619        );
620        assert_eq!(
621            changeset_cursor.next_dup().unwrap(),
622            None,
623            "Account A should only be in the changeset 2 times"
624        );
625
626        assert_eq!(
627            changeset_cursor.seek_exact(BlockNumberAddress((1, address_b))).unwrap(),
628            Some((
629                BlockNumberAddress((1, address_b)),
630                StorageEntry {
631                    key: B256::from(U256::from(1).to_be_bytes()),
632                    value: FlaggedStorage::public(1),
633                }
634            )),
635            "Slot 1 for account B should have changed from a public 1"
636        );
637        assert_eq!(
638            changeset_cursor.next_dup().unwrap(),
639            None,
640            "Account B should only be in the changeset 1 time"
641        );
642
643        assert_eq!(
644            changeset_cursor.seek_exact(BlockNumberAddress((1, address_c))).unwrap(),
645            Some((
646                BlockNumberAddress((1, address_c)),
647                StorageEntry {
648                    key: B256::from(U256::from(3).to_be_bytes()),
649                    value: FlaggedStorage::public(1),
650                }
651            )),
652            "Slot 1 for account C should have changed from a public 1"
653        );
654        assert_eq!(
655            changeset_cursor.next_dup().unwrap(),
656            None,
657            "Account C should only be in the changeset 1 time"
658        );
659
660        // Delete account A
661        let mut state = State::builder().with_bundle_update().build();
662        state.insert_account(address_a, RevmAccountInfo::default());
663
664        state.commit(HashMap::from_iter([(
665            address_a,
666            RevmAccount {
667                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
668                info: RevmAccountInfo::default(),
669                storage: HashMap::default(),
670            },
671        )]));
672
673        state.merge_transitions(BundleRetention::Reverts);
674        let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 2, Vec::new());
675        provider
676            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
677            .expect("Could not write bundle state to DB");
678
679        assert_eq!(
680            storage_cursor.seek_exact(address_a).unwrap(),
681            None,
682            "Account A should have no storage slots after deletion"
683        );
684
685        assert_eq!(
686            changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(),
687            Some((
688                BlockNumberAddress((2, address_a)),
689                StorageEntry { key: B256::ZERO, value: FlaggedStorage::private(1) }
690            )),
691            "Slot 0 for account A should have changed from a private 1 on deletion"
692        );
693        assert_eq!(
694            changeset_cursor.next_dup().unwrap(),
695            Some((
696                BlockNumberAddress((2, address_a)),
697                StorageEntry {
698                    key: B256::from(U256::from(1).to_be_bytes()),
699                    value: FlaggedStorage::private(2),
700                }
701            )),
702            "Slot 1 for account A should have changed from a private 2 on deletion"
703        );
704        assert_eq!(
705            changeset_cursor.next_dup().unwrap(),
706            None,
707            "Account A should only be in the changeset 2 times on deletion"
708        );
709    }
710
711    #[test]
712    fn write_to_db_multiple_selfdestructs() {
713        let factory = create_test_provider_factory();
714        let provider = factory.database_provider_rw().unwrap();
715
716        let address1 = Address::random();
717        let account_info = RevmAccountInfo { nonce: 1, ..Default::default() };
718
719        // Block #0: initial state.
720        let mut init_state = State::builder().with_bundle_update().build();
721        init_state.insert_not_existing(address1);
722        init_state.commit(HashMap::from_iter([(
723            address1,
724            RevmAccount {
725                info: account_info.clone(),
726                status: AccountStatus::Touched | AccountStatus::Created,
727                // 0x00 => 0 => 1
728                // 0x01 => 0 => 2
729                storage: HashMap::from_iter([
730                    (
731                        U256::ZERO,
732                        EvmStorageSlot {
733                            present_value: FlaggedStorage::public(1),
734                            ..Default::default()
735                        },
736                    ),
737                    (
738                        U256::from(1),
739                        EvmStorageSlot {
740                            present_value: FlaggedStorage::public(2),
741                            ..Default::default()
742                        },
743                    ),
744                ]),
745            },
746        )]));
747        init_state.merge_transitions(BundleRetention::Reverts);
748
749        let outcome =
750            ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
751        provider
752            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
753            .expect("Could not write bundle state to DB");
754
755        let mut state = State::builder().with_bundle_update().build();
756        state.insert_account_with_storage(
757            address1,
758            account_info.clone(),
759            HashMap::from_iter([
760                (U256::ZERO, FlaggedStorage::public(1)),
761                (U256::from(1), FlaggedStorage::public(2)),
762            ]),
763        );
764
765        // Block #1: change storage.
766        state.commit(HashMap::from_iter([(
767            address1,
768            RevmAccount {
769                status: AccountStatus::Touched,
770                info: account_info.clone(),
771                // 0x00 => 1 => 2
772                storage: HashMap::from_iter([(
773                    U256::ZERO,
774                    EvmStorageSlot {
775                        original_value: FlaggedStorage::public(1),
776                        present_value: FlaggedStorage::public(2),
777                        ..Default::default()
778                    },
779                )]),
780            },
781        )]));
782        state.merge_transitions(BundleRetention::Reverts);
783
784        // Block #2: destroy account.
785        state.commit(HashMap::from_iter([(
786            address1,
787            RevmAccount {
788                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
789                info: account_info.clone(),
790                storage: HashMap::default(),
791            },
792        )]));
793        state.merge_transitions(BundleRetention::Reverts);
794
795        // Block #3: re-create account and change storage.
796        state.commit(HashMap::from_iter([(
797            address1,
798            RevmAccount {
799                status: AccountStatus::Touched | AccountStatus::Created,
800                info: account_info.clone(),
801                storage: HashMap::default(),
802            },
803        )]));
804        state.merge_transitions(BundleRetention::Reverts);
805
806        // Block #4: change storage.
807        state.commit(HashMap::from_iter([(
808            address1,
809            RevmAccount {
810                status: AccountStatus::Touched,
811                info: account_info.clone(),
812                // 0x00 => 0 => 2
813                // 0x02 => 0 => 4
814                // 0x06 => 0 => 6
815                storage: HashMap::from_iter([
816                    (
817                        U256::ZERO,
818                        EvmStorageSlot {
819                            present_value: FlaggedStorage::public(2),
820                            ..Default::default()
821                        },
822                    ),
823                    (
824                        U256::from(2),
825                        EvmStorageSlot {
826                            present_value: FlaggedStorage::public(4),
827                            ..Default::default()
828                        },
829                    ),
830                    (
831                        U256::from(6),
832                        EvmStorageSlot {
833                            present_value: FlaggedStorage::public(6),
834                            ..Default::default()
835                        },
836                    ),
837                ]),
838            },
839        )]));
840        state.merge_transitions(BundleRetention::Reverts);
841
842        // Block #5: Destroy account again.
843        state.commit(HashMap::from_iter([(
844            address1,
845            RevmAccount {
846                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
847                info: account_info.clone(),
848                storage: HashMap::default(),
849            },
850        )]));
851        state.merge_transitions(BundleRetention::Reverts);
852
853        // Block #6: Create, change, destroy and re-create in the same block.
854        state.commit(HashMap::from_iter([(
855            address1,
856            RevmAccount {
857                status: AccountStatus::Touched | AccountStatus::Created,
858                info: account_info.clone(),
859                storage: HashMap::default(),
860            },
861        )]));
862        state.commit(HashMap::from_iter([(
863            address1,
864            RevmAccount {
865                status: AccountStatus::Touched,
866                info: account_info.clone(),
867                // 0x00 => 0 => 2
868                storage: HashMap::from_iter([(
869                    U256::ZERO,
870                    EvmStorageSlot {
871                        present_value: FlaggedStorage::public(2),
872                        ..Default::default()
873                    },
874                )]),
875            },
876        )]));
877        state.commit(HashMap::from_iter([(
878            address1,
879            RevmAccount {
880                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
881                info: account_info.clone(),
882                storage: HashMap::default(),
883            },
884        )]));
885        state.commit(HashMap::from_iter([(
886            address1,
887            RevmAccount {
888                status: AccountStatus::Touched | AccountStatus::Created,
889                info: account_info.clone(),
890                storage: HashMap::default(),
891            },
892        )]));
893        state.merge_transitions(BundleRetention::Reverts);
894
895        // Block #7: Change storage.
896        state.commit(HashMap::from_iter([(
897            address1,
898            RevmAccount {
899                status: AccountStatus::Touched,
900                info: account_info,
901                // 0x00 => 0 => 9
902                storage: HashMap::from_iter([(
903                    U256::ZERO,
904                    EvmStorageSlot {
905                        present_value: FlaggedStorage::public(9),
906                        ..Default::default()
907                    },
908                )]),
909            },
910        )]));
911        state.merge_transitions(BundleRetention::Reverts);
912
913        let bundle = state.take_bundle();
914
915        let outcome: ExecutionOutcome =
916            ExecutionOutcome::new(bundle, Default::default(), 1, Vec::new());
917        provider
918            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
919            .expect("Could not write bundle state to DB");
920
921        let mut storage_changeset_cursor = provider
922            .tx_ref()
923            .cursor_dup_read::<tables::StorageChangeSets>()
924            .expect("Could not open plain storage state cursor");
925        let mut storage_changes = storage_changeset_cursor.walk_range(..).unwrap();
926
927        // Iterate through all storage changes
928
929        // Block <number>
930        // <slot>: <expected value before>
931        // ...
932
933        // Block #0
934        // 0x00: 0
935        // 0x01: 0
936        assert_eq!(
937            storage_changes.next(),
938            Some(Ok((
939                BlockNumberAddress((0, address1)),
940                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::ZERO }
941            )))
942        );
943        assert_eq!(
944            storage_changes.next(),
945            Some(Ok((
946                BlockNumberAddress((0, address1)),
947                StorageEntry { key: B256::with_last_byte(1), value: FlaggedStorage::ZERO }
948            )))
949        );
950
951        // Block #1
952        // 0x00: 1
953        assert_eq!(
954            storage_changes.next(),
955            Some(Ok((
956                BlockNumberAddress((1, address1)),
957                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::public(1) }
958            )))
959        );
960
961        // Block #2 (destroyed)
962        // 0x00: 2
963        // 0x01: 2
964        assert_eq!(
965            storage_changes.next(),
966            Some(Ok((
967                BlockNumberAddress((2, address1)),
968                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::public(2) }
969            )))
970        );
971        assert_eq!(
972            storage_changes.next(),
973            Some(Ok((
974                BlockNumberAddress((2, address1)),
975                StorageEntry { key: B256::with_last_byte(1), value: FlaggedStorage::public(2) }
976            )))
977        );
978
979        // Block #3
980        // no storage changes
981
982        // Block #4
983        // 0x00: 0
984        // 0x02: 0
985        // 0x06: 0
986        assert_eq!(
987            storage_changes.next(),
988            Some(Ok((
989                BlockNumberAddress((4, address1)),
990                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::ZERO }
991            )))
992        );
993        assert_eq!(
994            storage_changes.next(),
995            Some(Ok((
996                BlockNumberAddress((4, address1)),
997                StorageEntry { key: B256::with_last_byte(2), value: FlaggedStorage::ZERO }
998            )))
999        );
1000        assert_eq!(
1001            storage_changes.next(),
1002            Some(Ok((
1003                BlockNumberAddress((4, address1)),
1004                StorageEntry { key: B256::with_last_byte(6), value: FlaggedStorage::ZERO }
1005            )))
1006        );
1007
1008        // Block #5 (destroyed)
1009        // 0x00: 2
1010        // 0x02: 4
1011        // 0x06: 6
1012        assert_eq!(
1013            storage_changes.next(),
1014            Some(Ok((
1015                BlockNumberAddress((5, address1)),
1016                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::public(2) }
1017            )))
1018        );
1019        assert_eq!(
1020            storage_changes.next(),
1021            Some(Ok((
1022                BlockNumberAddress((5, address1)),
1023                StorageEntry { key: B256::with_last_byte(2), value: FlaggedStorage::public(4) }
1024            )))
1025        );
1026        assert_eq!(
1027            storage_changes.next(),
1028            Some(Ok((
1029                BlockNumberAddress((5, address1)),
1030                StorageEntry { key: B256::with_last_byte(6), value: FlaggedStorage::public(6) }
1031            )))
1032        );
1033
1034        // Block #6
1035        // no storage changes (only inter block changes)
1036
1037        // Block #7
1038        // 0x00: 0
1039        assert_eq!(
1040            storage_changes.next(),
1041            Some(Ok((
1042                BlockNumberAddress((7, address1)),
1043                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::ZERO }
1044            )))
1045        );
1046        assert_eq!(storage_changes.next(), None);
1047    }
1048
1049    #[test]
1050    fn storage_change_after_selfdestruct_within_block() {
1051        let factory = create_test_provider_factory();
1052        let provider = factory.database_provider_rw().unwrap();
1053
1054        let address1 = Address::random();
1055        let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1056
1057        // Block #0: initial state.
1058        let mut init_state = State::builder().with_bundle_update().build();
1059        init_state.insert_not_existing(address1);
1060        init_state.commit(HashMap::from_iter([(
1061            address1,
1062            RevmAccount {
1063                info: account1.clone(),
1064                status: AccountStatus::Touched | AccountStatus::Created,
1065                // 0x00 => 0 => 1
1066                // 0x01 => 0 => 2
1067                storage: HashMap::from_iter([
1068                    (
1069                        U256::ZERO,
1070                        EvmStorageSlot {
1071                            present_value: FlaggedStorage::public(1),
1072                            ..Default::default()
1073                        },
1074                    ),
1075                    (
1076                        U256::from(1),
1077                        EvmStorageSlot {
1078                            present_value: FlaggedStorage::public(2),
1079                            ..Default::default()
1080                        },
1081                    ),
1082                ]),
1083            },
1084        )]));
1085        init_state.merge_transitions(BundleRetention::Reverts);
1086        let outcome =
1087            ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
1088        provider
1089            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1090            .expect("Could not write bundle state to DB");
1091
1092        let mut state = State::builder().with_bundle_update().build();
1093        state.insert_account_with_storage(
1094            address1,
1095            account1.clone(),
1096            HashMap::from_iter([
1097                (U256::ZERO, FlaggedStorage::public(1)),
1098                (U256::from(1), FlaggedStorage::public(2)),
1099            ]),
1100        );
1101
1102        // Block #1: Destroy, re-create, change storage.
1103        state.commit(HashMap::from_iter([(
1104            address1,
1105            RevmAccount {
1106                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1107                info: account1.clone(),
1108                storage: HashMap::default(),
1109            },
1110        )]));
1111
1112        state.commit(HashMap::from_iter([(
1113            address1,
1114            RevmAccount {
1115                status: AccountStatus::Touched | AccountStatus::Created,
1116                info: account1.clone(),
1117                storage: HashMap::default(),
1118            },
1119        )]));
1120
1121        state.commit(HashMap::from_iter([(
1122            address1,
1123            RevmAccount {
1124                status: AccountStatus::Touched,
1125                info: account1,
1126                // 0x01 => 0 => 5
1127                storage: HashMap::from_iter([(
1128                    U256::from(1),
1129                    EvmStorageSlot {
1130                        present_value: FlaggedStorage::public(5),
1131                        ..Default::default()
1132                    },
1133                )]),
1134            },
1135        )]));
1136
1137        // Commit block #1 changes to the database.
1138        state.merge_transitions(BundleRetention::Reverts);
1139        let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
1140        provider
1141            .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1142            .expect("Could not write bundle state to DB");
1143
1144        let mut storage_changeset_cursor = provider
1145            .tx_ref()
1146            .cursor_dup_read::<tables::StorageChangeSets>()
1147            .expect("Could not open plain storage state cursor");
1148        let range = BlockNumberAddress::range(1..=1);
1149        let mut storage_changes = storage_changeset_cursor.walk_range(range).unwrap();
1150
1151        assert_eq!(
1152            storage_changes.next(),
1153            Some(Ok((
1154                BlockNumberAddress((1, address1)),
1155                StorageEntry { key: B256::with_last_byte(0), value: FlaggedStorage::public(1) }
1156            )))
1157        );
1158        assert_eq!(
1159            storage_changes.next(),
1160            Some(Ok((
1161                BlockNumberAddress((1, address1)),
1162                StorageEntry { key: B256::with_last_byte(1), value: FlaggedStorage::public(2) }
1163            )))
1164        );
1165        assert_eq!(storage_changes.next(), None);
1166    }
1167
1168    #[test]
1169    fn revert_to_indices() {
1170        let base: ExecutionOutcome = ExecutionOutcome {
1171            bundle: BundleState::default(),
1172            receipts: vec![vec![Receipt::default(); 2]; 7],
1173            first_block: 10,
1174            requests: Vec::new(),
1175        };
1176
1177        let mut this = base.clone();
1178        assert!(this.revert_to(10));
1179        assert_eq!(this.receipts.len(), 1);
1180
1181        let mut this = base.clone();
1182        assert!(!this.revert_to(9));
1183        assert_eq!(this.receipts.len(), 7);
1184
1185        let mut this = base.clone();
1186        assert!(this.revert_to(15));
1187        assert_eq!(this.receipts.len(), 6);
1188
1189        let mut this = base.clone();
1190        assert!(this.revert_to(16));
1191        assert_eq!(this.receipts.len(), 7);
1192
1193        let mut this = base;
1194        assert!(!this.revert_to(17));
1195        assert_eq!(this.receipts.len(), 7);
1196    }
1197
1198    #[test]
1199    fn bundle_state_state_root() {
1200        type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>;
1201        let mut prestate: PreState = (0..10)
1202            .map(|key| {
1203                let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None };
1204                let storage =
1205                    (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect();
1206                (Address::with_last_byte(key), (account, storage))
1207            })
1208            .collect();
1209
1210        let provider_factory = create_test_provider_factory();
1211        let provider_rw = provider_factory.database_provider_rw().unwrap();
1212
1213        // insert initial state to the database
1214        let tx = provider_rw.tx_ref();
1215        for (address, (account, storage)) in &prestate {
1216            let hashed_address = keccak256(address);
1217            tx.put::<tables::HashedAccounts>(hashed_address, *account).unwrap();
1218            for (slot, value) in storage {
1219                tx.put::<tables::HashedStorages>(
1220                    hashed_address,
1221                    StorageEntry { key: keccak256(slot), value: FlaggedStorage::public(*value) },
1222                )
1223                .unwrap();
1224            }
1225        }
1226
1227        let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
1228        provider_rw.write_trie_updates(&updates).unwrap();
1229
1230        let mut state = State::builder().with_bundle_update().build();
1231
1232        let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
1233            assert_eq!(
1234                StateRoot::overlay_root(
1235                    tx,
1236                    provider_factory.hashed_post_state(&state.bundle_state)
1237                )
1238                .unwrap(),
1239                state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
1240                    address,
1241                    (account, storage.into_iter())
1242                ))),
1243                "{msg}"
1244            );
1245        };
1246
1247        // database only state root is correct
1248        assert_state_root(&state, &prestate, "empty");
1249
1250        // destroy account 1
1251        let address1 = Address::with_last_byte(1);
1252        let account1_old = prestate.remove(&address1).unwrap();
1253        state.insert_account(address1, account1_old.0.into());
1254        state.commit(HashMap::from_iter([(
1255            address1,
1256            RevmAccount {
1257                status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1258                info: RevmAccountInfo::default(),
1259                storage: HashMap::default(),
1260            },
1261        )]));
1262        state.merge_transitions(BundleRetention::PlainState);
1263        assert_state_root(&state, &prestate, "destroyed account");
1264
1265        // change slot 2 in account 2
1266        let address2 = Address::with_last_byte(2);
1267        let slot2 = U256::from(2);
1268        let slot2_key = B256::from(slot2);
1269        let account2 = prestate.get_mut(&address2).unwrap();
1270        let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap();
1271        state.insert_account_with_storage(
1272            address2,
1273            account2.0.into(),
1274            HashMap::from_iter([(slot2, FlaggedStorage::public(account2_slot2_old_value))]),
1275        );
1276
1277        let account2_slot2_new_value = U256::from(100);
1278        account2.1.insert(slot2_key, account2_slot2_new_value);
1279        state.commit(HashMap::from_iter([(
1280            address2,
1281            RevmAccount {
1282                status: AccountStatus::Touched,
1283                info: account2.0.into(),
1284                storage: HashMap::from_iter([(
1285                    slot2,
1286                    EvmStorageSlot::new_changed(
1287                        FlaggedStorage::public(account2_slot2_old_value),
1288                        FlaggedStorage::public(account2_slot2_new_value),
1289                    ),
1290                )]),
1291            },
1292        )]));
1293        state.merge_transitions(BundleRetention::PlainState);
1294        assert_state_root(&state, &prestate, "changed storage");
1295
1296        // change balance of account 3
1297        let address3 = Address::with_last_byte(3);
1298        let account3 = prestate.get_mut(&address3).unwrap();
1299        state.insert_account(address3, account3.0.into());
1300
1301        account3.0.balance = U256::from(24);
1302        state.commit(HashMap::from_iter([(
1303            address3,
1304            RevmAccount {
1305                status: AccountStatus::Touched,
1306                info: account3.0.into(),
1307                storage: HashMap::default(),
1308            },
1309        )]));
1310        state.merge_transitions(BundleRetention::PlainState);
1311        assert_state_root(&state, &prestate, "changed balance");
1312
1313        // change nonce of account 4
1314        let address4 = Address::with_last_byte(4);
1315        let account4 = prestate.get_mut(&address4).unwrap();
1316        state.insert_account(address4, account4.0.into());
1317
1318        account4.0.nonce = 128;
1319        state.commit(HashMap::from_iter([(
1320            address4,
1321            RevmAccount {
1322                status: AccountStatus::Touched,
1323                info: account4.0.into(),
1324                storage: HashMap::default(),
1325            },
1326        )]));
1327        state.merge_transitions(BundleRetention::PlainState);
1328        assert_state_root(&state, &prestate, "changed nonce");
1329
1330        // recreate account 1
1331        let account1_new =
1332            Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) };
1333        prestate.insert(address1, (account1_new, BTreeMap::default()));
1334        state.commit(HashMap::from_iter([(
1335            address1,
1336            RevmAccount {
1337                status: AccountStatus::Touched | AccountStatus::Created,
1338                info: account1_new.into(),
1339                storage: HashMap::default(),
1340            },
1341        )]));
1342        state.merge_transitions(BundleRetention::PlainState);
1343        assert_state_root(&state, &prestate, "recreated");
1344
1345        // update storage for account 1
1346        let slot20 = U256::from(20);
1347        let slot20_key = B256::from(slot20);
1348        let account1_slot20_value = U256::from(12345);
1349        prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value);
1350        state.commit(HashMap::from_iter([(
1351            address1,
1352            RevmAccount {
1353                status: AccountStatus::Touched | AccountStatus::Created,
1354                info: account1_new.into(),
1355                storage: HashMap::from_iter([(
1356                    slot20,
1357                    EvmStorageSlot::new_changed(
1358                        FlaggedStorage::ZERO,
1359                        FlaggedStorage::public(account1_slot20_value),
1360                    ),
1361                )]),
1362            },
1363        )]));
1364        state.merge_transitions(BundleRetention::PlainState);
1365        assert_state_root(&state, &prestate, "recreated changed storage");
1366    }
1367
1368    #[test]
1369    fn prepend_state() {
1370        let address1 = Address::random();
1371        let address2 = Address::random();
1372
1373        let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1374        let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() };
1375        let account2 = RevmAccountInfo { nonce: 1, ..Default::default() };
1376
1377        let present_state = BundleState::builder(2..=2)
1378            .state_present_account_info(address1, account1_changed.clone())
1379            .build();
1380        assert_eq!(present_state.reverts.len(), 1);
1381        let previous_state = BundleState::builder(1..=1)
1382            .state_present_account_info(address1, account1)
1383            .state_present_account_info(address2, account2.clone())
1384            .build();
1385        assert_eq!(previous_state.reverts.len(), 1);
1386
1387        let mut test: ExecutionOutcome = ExecutionOutcome {
1388            bundle: present_state,
1389            receipts: vec![vec![Receipt::default(); 2]; 1],
1390            first_block: 2,
1391            requests: Vec::new(),
1392        };
1393
1394        test.prepend_state(previous_state);
1395
1396        assert_eq!(test.receipts.len(), 1);
1397        let end_state = test.state();
1398        assert_eq!(end_state.state.len(), 2);
1399        // reverts num should stay the same.
1400        assert_eq!(end_state.reverts.len(), 1);
1401        // account1 is not overwritten.
1402        assert_eq!(end_state.state.get(&address1).unwrap().info, Some(account1_changed));
1403        // account2 got inserted
1404        assert_eq!(end_state.state.get(&address2).unwrap().info, Some(account2));
1405    }
1406
1407    #[test]
1408    fn hashed_state_storage_root() {
1409        let address = Address::random();
1410        let hashed_address = keccak256(address);
1411        let provider_factory = create_test_provider_factory();
1412        let provider_rw = provider_factory.provider_rw().unwrap();
1413        let tx = provider_rw.tx_ref();
1414
1415        // insert initial account storage
1416        let init_storage = HashedStorage::from_iter(
1417            false,
1418            [
1419                "50000000000000000000000000000004253371b55351a08cb3267d4d265530b6",
1420                "512428ed685fff57294d1a9cbb147b18ae5db9cf6ae4b312fa1946ba0561882e",
1421                "51e6784c736ef8548f856909870b38e49ef7a4e3e77e5e945e0d5e6fcaa3037f",
1422            ]
1423            .into_iter()
1424            .map(|str| (B256::from_str(str).unwrap(), FlaggedStorage::public(1))),
1425        );
1426        let mut state = HashedPostState::default();
1427        state.storages.insert(hashed_address, init_storage.clone());
1428        provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1429
1430        // calculate database storage root and write intermediate storage nodes.
1431        let (storage_root, _, storage_updates) =
1432            StorageRoot::from_tx_hashed(tx, hashed_address).calculate(true).unwrap();
1433        assert_eq!(
1434            storage_root,
1435            storage_root_prehashed(FlaggedStorage::collect_value(init_storage.storage))
1436        );
1437        assert!(!storage_updates.is_empty());
1438        provider_rw
1439            .write_individual_storage_trie_updates(hashed_address, &storage_updates)
1440            .unwrap();
1441
1442        // destroy the storage and re-create with new slots
1443        let updated_storage = HashedStorage::from_iter(
1444            true,
1445            [
1446                "00deb8486ad8edccfdedfc07109b3667b38a03a8009271aac250cce062d90917",
1447                "88d233b7380bb1bcdc866f6871c94685848f54cf0ee033b1480310b4ddb75fc9",
1448            ]
1449            .into_iter()
1450            .map(|str| (B256::from_str(str).unwrap(), FlaggedStorage::public(1))),
1451        );
1452        let mut state = HashedPostState::default();
1453        state.storages.insert(hashed_address, updated_storage.clone());
1454        provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1455
1456        // re-calculate database storage root
1457        let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap();
1458        assert_eq!(
1459            storage_root,
1460            storage_root_prehashed(FlaggedStorage::collect_value(updated_storage.storage))
1461        );
1462    }
1463}