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