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