1use crate::{
2 providers::{StaticFileProvider, StaticFileWriter as SfWriter},
3 BlockExecutionWriter, BlockWriter, HistoryWriter, StateWriter, StaticFileProviderFactory,
4 StorageLocation, TrieWriter,
5};
6use alloy_consensus::BlockHeader;
7use reth_chain_state::{ExecutedBlock, ExecutedBlockWithTrieUpdates};
8use reth_db_api::transaction::{DbTx, DbTxMut};
9use reth_errors::ProviderResult;
10use reth_primitives_traits::{NodePrimitives, SignedTransaction};
11use reth_static_file_types::StaticFileSegment;
12use reth_storage_api::{DBProvider, StageCheckpointWriter, TransactionsProviderExt};
13use reth_storage_errors::writer::UnifiedStorageWriterError;
14use revm_database::OriginalValuesKnown;
15use std::sync::Arc;
16use tracing::debug;
17
18#[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 const fn static_file(&self) -> &ProviderSF {
66 self.static_file.as_ref().expect("should exist")
67 }
68
69 #[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 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<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 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 for ExecutedBlockWithTrieUpdates {
164 block: ExecutedBlock { recovered_block, execution_output, hashed_state },
165 trie,
166 } in blocks
167 {
168 self.database()
169 .insert_block(Arc::unwrap_or_clone(recovered_block), StorageLocation::Both)?;
170
171 self.database().write_state(
174 &execution_output,
175 OriginalValuesKnown::No,
176 StorageLocation::StaticFiles,
177 )?;
178
179 self.database()
181 .write_hashed_state(&Arc::unwrap_or_clone(hashed_state).into_sorted())?;
182 self.database().write_trie_updates(&trie)?;
183 }
184
185 self.database().update_history_indices(first_number..=last_block_number)?;
187
188 self.database().update_pipeline_stages(last_block_number, false)?;
190
191 debug!(target: "provider::storage_writer", range = ?first_number..=last_block_number, "Appended block data");
192
193 Ok(())
194 }
195
196 pub fn remove_blocks_above(&self, block_number: u64) -> ProviderResult<()> {
200 debug!(target: "provider::storage_writer", ?block_number, "Removing blocks from database above block_number");
202 self.database().remove_block_and_execution_above(block_number, StorageLocation::Both)?;
203
204 let highest_static_file_block = self
206 .static_file()
207 .get_highest_static_file_block(StaticFileSegment::Headers)
208 .expect("todo: error handling, headers should exist");
209
210 debug!(target: "provider::storage_writer", ?block_number, "Removing static file blocks above block_number");
216 self.static_file()
217 .get_writer(block_number, StaticFileSegment::Headers)?
218 .prune_headers(highest_static_file_block.saturating_sub(block_number))?;
219
220 Ok(())
221 }
222}
223
224#[cfg(test)]
225mod tests {
226 use super::*;
227 use crate::{
228 test_utils::create_test_provider_factory, AccountReader, StorageTrieWriter, TrieWriter,
229 };
230 use alloy_primitives::{keccak256, map::HashMap, Address, B256, U256};
231 use reth_db_api::{
232 cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO},
233 models::{AccountBeforeTx, BlockNumberAddress},
234 tables,
235 transaction::{DbTx, DbTxMut},
236 };
237 use reth_ethereum_primitives::Receipt;
238 use reth_execution_types::ExecutionOutcome;
239 use reth_primitives_traits::{Account, StorageEntry};
240 use reth_storage_api::{DatabaseProviderFactory, HashedPostStateProvider};
241 use reth_trie::{
242 test_utils::{state_root, storage_root_prehashed},
243 HashedPostState, HashedStorage, StateRoot, StorageRoot,
244 };
245 use reth_trie_db::{DatabaseStateRoot, DatabaseStorageRoot};
246 use revm_database::{
247 states::{
248 bundle_state::BundleRetention, changes::PlainStorageRevert, PlainStorageChangeset,
249 },
250 BundleState, State,
251 };
252 use revm_database_interface::{DatabaseCommit, EmptyDB};
253 use revm_state::{
254 Account as RevmAccount, AccountInfo as RevmAccountInfo, AccountStatus, EvmStorageSlot,
255 };
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) },
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!(matches!(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
450 let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
451
452 let mut state = State::builder().with_bundle_update().build();
453 state.insert_not_existing(address_a);
454 state.insert_account_with_storage(
455 address_b,
456 account_b.clone(),
457 HashMap::from_iter([(U256::from(1), U256::from(1))]),
458 );
459
460 state.commit(HashMap::from_iter([
461 (
462 address_a,
463 RevmAccount {
464 status: AccountStatus::Touched | AccountStatus::Created,
465 info: RevmAccountInfo::default(),
466 storage: HashMap::from_iter([
469 (
470 U256::from(0),
471 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
472 ),
473 (
474 U256::from(1),
475 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
476 ),
477 ]),
478 },
479 ),
480 (
481 address_b,
482 RevmAccount {
483 status: AccountStatus::Touched,
484 info: account_b,
485 storage: HashMap::from_iter([(
487 U256::from(1),
488 EvmStorageSlot {
489 present_value: U256::from(2),
490 original_value: U256::from(1),
491 ..Default::default()
492 },
493 )]),
494 },
495 ),
496 ]));
497
498 state.merge_transitions(BundleRetention::Reverts);
499
500 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
501 provider
502 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
503 .expect("Could not write bundle state to DB");
504
505 let mut storage_cursor = provider
507 .tx_ref()
508 .cursor_dup_read::<tables::PlainStorageState>()
509 .expect("Could not open plain storage state cursor");
510
511 assert_eq!(
512 storage_cursor.seek_exact(address_a).unwrap(),
513 Some((address_a, StorageEntry { key: B256::ZERO, value: U256::from(1) })),
514 "Slot 0 for account A should be 1"
515 );
516 assert_eq!(
517 storage_cursor.next_dup().unwrap(),
518 Some((
519 address_a,
520 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
521 )),
522 "Slot 1 for account A should be 2"
523 );
524 assert_eq!(
525 storage_cursor.next_dup().unwrap(),
526 None,
527 "Account A should only have 2 storage slots"
528 );
529
530 assert_eq!(
531 storage_cursor.seek_exact(address_b).unwrap(),
532 Some((
533 address_b,
534 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
535 )),
536 "Slot 1 for account B should be 2"
537 );
538 assert_eq!(
539 storage_cursor.next_dup().unwrap(),
540 None,
541 "Account B should only have 1 storage slot"
542 );
543
544 let mut changeset_cursor = provider
546 .tx_ref()
547 .cursor_dup_read::<tables::StorageChangeSets>()
548 .expect("Could not open storage changeset cursor");
549 assert_eq!(
550 changeset_cursor.seek_exact(BlockNumberAddress((1, address_a))).unwrap(),
551 Some((
552 BlockNumberAddress((1, address_a)),
553 StorageEntry { key: B256::ZERO, value: U256::from(0) }
554 )),
555 "Slot 0 for account A should have changed from 0"
556 );
557 assert_eq!(
558 changeset_cursor.next_dup().unwrap(),
559 Some((
560 BlockNumberAddress((1, address_a)),
561 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(0) }
562 )),
563 "Slot 1 for account A should have changed from 0"
564 );
565 assert_eq!(
566 changeset_cursor.next_dup().unwrap(),
567 None,
568 "Account A should only be in the changeset 2 times"
569 );
570
571 assert_eq!(
572 changeset_cursor.seek_exact(BlockNumberAddress((1, address_b))).unwrap(),
573 Some((
574 BlockNumberAddress((1, address_b)),
575 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(1) }
576 )),
577 "Slot 1 for account B should have changed from 1"
578 );
579 assert_eq!(
580 changeset_cursor.next_dup().unwrap(),
581 None,
582 "Account B should only be in the changeset 1 time"
583 );
584
585 let mut state = State::builder().with_bundle_update().build();
587 state.insert_account(address_a, RevmAccountInfo::default());
588
589 state.commit(HashMap::from_iter([(
590 address_a,
591 RevmAccount {
592 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
593 info: RevmAccountInfo::default(),
594 storage: HashMap::default(),
595 },
596 )]));
597
598 state.merge_transitions(BundleRetention::Reverts);
599 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 2, Vec::new());
600 provider
601 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
602 .expect("Could not write bundle state to DB");
603
604 assert_eq!(
605 storage_cursor.seek_exact(address_a).unwrap(),
606 None,
607 "Account A should have no storage slots after deletion"
608 );
609
610 assert_eq!(
611 changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(),
612 Some((
613 BlockNumberAddress((2, address_a)),
614 StorageEntry { key: B256::ZERO, value: U256::from(1) }
615 )),
616 "Slot 0 for account A should have changed from 1 on deletion"
617 );
618 assert_eq!(
619 changeset_cursor.next_dup().unwrap(),
620 Some((
621 BlockNumberAddress((2, address_a)),
622 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
623 )),
624 "Slot 1 for account A should have changed from 2 on deletion"
625 );
626 assert_eq!(
627 changeset_cursor.next_dup().unwrap(),
628 None,
629 "Account A should only be in the changeset 2 times on deletion"
630 );
631 }
632
633 #[test]
634 fn write_to_db_multiple_selfdestructs() {
635 let factory = create_test_provider_factory();
636 let provider = factory.database_provider_rw().unwrap();
637
638 let address1 = Address::random();
639 let account_info = RevmAccountInfo { nonce: 1, ..Default::default() };
640
641 let mut init_state = State::builder().with_bundle_update().build();
643 init_state.insert_not_existing(address1);
644 init_state.commit(HashMap::from_iter([(
645 address1,
646 RevmAccount {
647 info: account_info.clone(),
648 status: AccountStatus::Touched | AccountStatus::Created,
649 storage: HashMap::from_iter([
652 (
653 U256::ZERO,
654 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
655 ),
656 (
657 U256::from(1),
658 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
659 ),
660 ]),
661 },
662 )]));
663 init_state.merge_transitions(BundleRetention::Reverts);
664
665 let outcome =
666 ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
667 provider
668 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
669 .expect("Could not write bundle state to DB");
670
671 let mut state = State::builder().with_bundle_update().build();
672 state.insert_account_with_storage(
673 address1,
674 account_info.clone(),
675 HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]),
676 );
677
678 state.commit(HashMap::from_iter([(
680 address1,
681 RevmAccount {
682 status: AccountStatus::Touched,
683 info: account_info.clone(),
684 storage: HashMap::from_iter([(
686 U256::ZERO,
687 EvmStorageSlot {
688 original_value: U256::from(1),
689 present_value: U256::from(2),
690 ..Default::default()
691 },
692 )]),
693 },
694 )]));
695 state.merge_transitions(BundleRetention::Reverts);
696
697 state.commit(HashMap::from_iter([(
699 address1,
700 RevmAccount {
701 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
702 info: account_info.clone(),
703 storage: HashMap::default(),
704 },
705 )]));
706 state.merge_transitions(BundleRetention::Reverts);
707
708 state.commit(HashMap::from_iter([(
710 address1,
711 RevmAccount {
712 status: AccountStatus::Touched | AccountStatus::Created,
713 info: account_info.clone(),
714 storage: HashMap::default(),
715 },
716 )]));
717 state.merge_transitions(BundleRetention::Reverts);
718
719 state.commit(HashMap::from_iter([(
721 address1,
722 RevmAccount {
723 status: AccountStatus::Touched,
724 info: account_info.clone(),
725 storage: HashMap::from_iter([
729 (
730 U256::ZERO,
731 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
732 ),
733 (
734 U256::from(2),
735 EvmStorageSlot { present_value: U256::from(4), ..Default::default() },
736 ),
737 (
738 U256::from(6),
739 EvmStorageSlot { present_value: U256::from(6), ..Default::default() },
740 ),
741 ]),
742 },
743 )]));
744 state.merge_transitions(BundleRetention::Reverts);
745
746 state.commit(HashMap::from_iter([(
748 address1,
749 RevmAccount {
750 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
751 info: account_info.clone(),
752 storage: HashMap::default(),
753 },
754 )]));
755 state.merge_transitions(BundleRetention::Reverts);
756
757 state.commit(HashMap::from_iter([(
759 address1,
760 RevmAccount {
761 status: AccountStatus::Touched | AccountStatus::Created,
762 info: account_info.clone(),
763 storage: HashMap::default(),
764 },
765 )]));
766 state.commit(HashMap::from_iter([(
767 address1,
768 RevmAccount {
769 status: AccountStatus::Touched,
770 info: account_info.clone(),
771 storage: HashMap::from_iter([(
773 U256::ZERO,
774 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
775 )]),
776 },
777 )]));
778 state.commit(HashMap::from_iter([(
779 address1,
780 RevmAccount {
781 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
782 info: account_info.clone(),
783 storage: HashMap::default(),
784 },
785 )]));
786 state.commit(HashMap::from_iter([(
787 address1,
788 RevmAccount {
789 status: AccountStatus::Touched | AccountStatus::Created,
790 info: account_info.clone(),
791 storage: HashMap::default(),
792 },
793 )]));
794 state.merge_transitions(BundleRetention::Reverts);
795
796 state.commit(HashMap::from_iter([(
798 address1,
799 RevmAccount {
800 status: AccountStatus::Touched,
801 info: account_info,
802 storage: HashMap::from_iter([(
804 U256::ZERO,
805 EvmStorageSlot { present_value: U256::from(9), ..Default::default() },
806 )]),
807 },
808 )]));
809 state.merge_transitions(BundleRetention::Reverts);
810
811 let bundle = state.take_bundle();
812
813 let outcome: ExecutionOutcome =
814 ExecutionOutcome::new(bundle, Default::default(), 1, Vec::new());
815 provider
816 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
817 .expect("Could not write bundle state to DB");
818
819 let mut storage_changeset_cursor = provider
820 .tx_ref()
821 .cursor_dup_read::<tables::StorageChangeSets>()
822 .expect("Could not open plain storage state cursor");
823 let mut storage_changes = storage_changeset_cursor.walk_range(..).unwrap();
824
825 assert_eq!(
835 storage_changes.next(),
836 Some(Ok((
837 BlockNumberAddress((0, address1)),
838 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
839 )))
840 );
841 assert_eq!(
842 storage_changes.next(),
843 Some(Ok((
844 BlockNumberAddress((0, address1)),
845 StorageEntry { key: B256::with_last_byte(1), value: U256::ZERO }
846 )))
847 );
848
849 assert_eq!(
852 storage_changes.next(),
853 Some(Ok((
854 BlockNumberAddress((1, address1)),
855 StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) }
856 )))
857 );
858
859 assert_eq!(
863 storage_changes.next(),
864 Some(Ok((
865 BlockNumberAddress((2, address1)),
866 StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) }
867 )))
868 );
869 assert_eq!(
870 storage_changes.next(),
871 Some(Ok((
872 BlockNumberAddress((2, address1)),
873 StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) }
874 )))
875 );
876
877 assert_eq!(
885 storage_changes.next(),
886 Some(Ok((
887 BlockNumberAddress((4, address1)),
888 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
889 )))
890 );
891 assert_eq!(
892 storage_changes.next(),
893 Some(Ok((
894 BlockNumberAddress((4, address1)),
895 StorageEntry { key: B256::with_last_byte(2), value: U256::ZERO }
896 )))
897 );
898 assert_eq!(
899 storage_changes.next(),
900 Some(Ok((
901 BlockNumberAddress((4, address1)),
902 StorageEntry { key: B256::with_last_byte(6), value: U256::ZERO }
903 )))
904 );
905
906 assert_eq!(
911 storage_changes.next(),
912 Some(Ok((
913 BlockNumberAddress((5, address1)),
914 StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) }
915 )))
916 );
917 assert_eq!(
918 storage_changes.next(),
919 Some(Ok((
920 BlockNumberAddress((5, address1)),
921 StorageEntry { key: B256::with_last_byte(2), value: U256::from(4) }
922 )))
923 );
924 assert_eq!(
925 storage_changes.next(),
926 Some(Ok((
927 BlockNumberAddress((5, address1)),
928 StorageEntry { key: B256::with_last_byte(6), value: U256::from(6) }
929 )))
930 );
931
932 assert_eq!(
938 storage_changes.next(),
939 Some(Ok((
940 BlockNumberAddress((7, address1)),
941 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
942 )))
943 );
944 assert_eq!(storage_changes.next(), None);
945 }
946
947 #[test]
948 fn storage_change_after_selfdestruct_within_block() {
949 let factory = create_test_provider_factory();
950 let provider = factory.database_provider_rw().unwrap();
951
952 let address1 = Address::random();
953 let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
954
955 let mut init_state = State::builder().with_bundle_update().build();
957 init_state.insert_not_existing(address1);
958 init_state.commit(HashMap::from_iter([(
959 address1,
960 RevmAccount {
961 info: account1.clone(),
962 status: AccountStatus::Touched | AccountStatus::Created,
963 storage: HashMap::from_iter([
966 (
967 U256::ZERO,
968 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
969 ),
970 (
971 U256::from(1),
972 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
973 ),
974 ]),
975 },
976 )]));
977 init_state.merge_transitions(BundleRetention::Reverts);
978 let outcome =
979 ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
980 provider
981 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
982 .expect("Could not write bundle state to DB");
983
984 let mut state = State::builder().with_bundle_update().build();
985 state.insert_account_with_storage(
986 address1,
987 account1.clone(),
988 HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]),
989 );
990
991 state.commit(HashMap::from_iter([(
993 address1,
994 RevmAccount {
995 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
996 info: account1.clone(),
997 storage: HashMap::default(),
998 },
999 )]));
1000
1001 state.commit(HashMap::from_iter([(
1002 address1,
1003 RevmAccount {
1004 status: AccountStatus::Touched | AccountStatus::Created,
1005 info: account1.clone(),
1006 storage: HashMap::default(),
1007 },
1008 )]));
1009
1010 state.commit(HashMap::from_iter([(
1011 address1,
1012 RevmAccount {
1013 status: AccountStatus::Touched,
1014 info: account1,
1015 storage: HashMap::from_iter([(
1017 U256::from(1),
1018 EvmStorageSlot { present_value: U256::from(5), ..Default::default() },
1019 )]),
1020 },
1021 )]));
1022
1023 state.merge_transitions(BundleRetention::Reverts);
1025 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
1026 provider
1027 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1028 .expect("Could not write bundle state to DB");
1029
1030 let mut storage_changeset_cursor = provider
1031 .tx_ref()
1032 .cursor_dup_read::<tables::StorageChangeSets>()
1033 .expect("Could not open plain storage state cursor");
1034 let range = BlockNumberAddress::range(1..=1);
1035 let mut storage_changes = storage_changeset_cursor.walk_range(range).unwrap();
1036
1037 assert_eq!(
1038 storage_changes.next(),
1039 Some(Ok((
1040 BlockNumberAddress((1, address1)),
1041 StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) }
1042 )))
1043 );
1044 assert_eq!(
1045 storage_changes.next(),
1046 Some(Ok((
1047 BlockNumberAddress((1, address1)),
1048 StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) }
1049 )))
1050 );
1051 assert_eq!(storage_changes.next(), None);
1052 }
1053
1054 #[test]
1055 fn revert_to_indices() {
1056 let base: ExecutionOutcome = ExecutionOutcome {
1057 bundle: BundleState::default(),
1058 receipts: vec![vec![Receipt::default(); 2]; 7],
1059 first_block: 10,
1060 requests: Vec::new(),
1061 };
1062
1063 let mut this = base.clone();
1064 assert!(this.revert_to(10));
1065 assert_eq!(this.receipts.len(), 1);
1066
1067 let mut this = base.clone();
1068 assert!(!this.revert_to(9));
1069 assert_eq!(this.receipts.len(), 7);
1070
1071 let mut this = base.clone();
1072 assert!(this.revert_to(15));
1073 assert_eq!(this.receipts.len(), 6);
1074
1075 let mut this = base.clone();
1076 assert!(this.revert_to(16));
1077 assert_eq!(this.receipts.len(), 7);
1078
1079 let mut this = base;
1080 assert!(!this.revert_to(17));
1081 assert_eq!(this.receipts.len(), 7);
1082 }
1083
1084 #[test]
1085 fn bundle_state_state_root() {
1086 type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>;
1087 let mut prestate: PreState = (0..10)
1088 .map(|key| {
1089 let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None };
1090 let storage =
1091 (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect();
1092 (Address::with_last_byte(key), (account, storage))
1093 })
1094 .collect();
1095
1096 let provider_factory = create_test_provider_factory();
1097 let provider_rw = provider_factory.database_provider_rw().unwrap();
1098
1099 let tx = provider_rw.tx_ref();
1101 for (address, (account, storage)) in &prestate {
1102 let hashed_address = keccak256(address);
1103 tx.put::<tables::HashedAccounts>(hashed_address, *account).unwrap();
1104 for (slot, value) in storage {
1105 tx.put::<tables::HashedStorages>(
1106 hashed_address,
1107 StorageEntry { key: keccak256(slot), value: *value },
1108 )
1109 .unwrap();
1110 }
1111 }
1112
1113 let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
1114 provider_rw.write_trie_updates(&updates).unwrap();
1115
1116 let mut state = State::builder().with_bundle_update().build();
1117
1118 let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
1119 assert_eq!(
1120 StateRoot::overlay_root(
1121 tx,
1122 provider_factory.hashed_post_state(&state.bundle_state)
1123 )
1124 .unwrap(),
1125 state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
1126 address,
1127 (account, storage.into_iter())
1128 ))),
1129 "{msg}"
1130 );
1131 };
1132
1133 assert_state_root(&state, &prestate, "empty");
1135
1136 let address1 = Address::with_last_byte(1);
1138 let account1_old = prestate.remove(&address1).unwrap();
1139 state.insert_account(address1, account1_old.0.into());
1140 state.commit(HashMap::from_iter([(
1141 address1,
1142 RevmAccount {
1143 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1144 info: RevmAccountInfo::default(),
1145 storage: HashMap::default(),
1146 },
1147 )]));
1148 state.merge_transitions(BundleRetention::PlainState);
1149 assert_state_root(&state, &prestate, "destroyed account");
1150
1151 let address2 = Address::with_last_byte(2);
1153 let slot2 = U256::from(2);
1154 let slot2_key = B256::from(slot2);
1155 let account2 = prestate.get_mut(&address2).unwrap();
1156 let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap();
1157 state.insert_account_with_storage(
1158 address2,
1159 account2.0.into(),
1160 HashMap::from_iter([(slot2, account2_slot2_old_value)]),
1161 );
1162
1163 let account2_slot2_new_value = U256::from(100);
1164 account2.1.insert(slot2_key, account2_slot2_new_value);
1165 state.commit(HashMap::from_iter([(
1166 address2,
1167 RevmAccount {
1168 status: AccountStatus::Touched,
1169 info: account2.0.into(),
1170 storage: HashMap::from_iter([(
1171 slot2,
1172 EvmStorageSlot::new_changed(account2_slot2_old_value, account2_slot2_new_value),
1173 )]),
1174 },
1175 )]));
1176 state.merge_transitions(BundleRetention::PlainState);
1177 assert_state_root(&state, &prestate, "changed storage");
1178
1179 let address3 = Address::with_last_byte(3);
1181 let account3 = prestate.get_mut(&address3).unwrap();
1182 state.insert_account(address3, account3.0.into());
1183
1184 account3.0.balance = U256::from(24);
1185 state.commit(HashMap::from_iter([(
1186 address3,
1187 RevmAccount {
1188 status: AccountStatus::Touched,
1189 info: account3.0.into(),
1190 storage: HashMap::default(),
1191 },
1192 )]));
1193 state.merge_transitions(BundleRetention::PlainState);
1194 assert_state_root(&state, &prestate, "changed balance");
1195
1196 let address4 = Address::with_last_byte(4);
1198 let account4 = prestate.get_mut(&address4).unwrap();
1199 state.insert_account(address4, account4.0.into());
1200
1201 account4.0.nonce = 128;
1202 state.commit(HashMap::from_iter([(
1203 address4,
1204 RevmAccount {
1205 status: AccountStatus::Touched,
1206 info: account4.0.into(),
1207 storage: HashMap::default(),
1208 },
1209 )]));
1210 state.merge_transitions(BundleRetention::PlainState);
1211 assert_state_root(&state, &prestate, "changed nonce");
1212
1213 let account1_new =
1215 Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) };
1216 prestate.insert(address1, (account1_new, BTreeMap::default()));
1217 state.commit(HashMap::from_iter([(
1218 address1,
1219 RevmAccount {
1220 status: AccountStatus::Touched | AccountStatus::Created,
1221 info: account1_new.into(),
1222 storage: HashMap::default(),
1223 },
1224 )]));
1225 state.merge_transitions(BundleRetention::PlainState);
1226 assert_state_root(&state, &prestate, "recreated");
1227
1228 let slot20 = U256::from(20);
1230 let slot20_key = B256::from(slot20);
1231 let account1_slot20_value = U256::from(12345);
1232 prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value);
1233 state.commit(HashMap::from_iter([(
1234 address1,
1235 RevmAccount {
1236 status: AccountStatus::Touched | AccountStatus::Created,
1237 info: account1_new.into(),
1238 storage: HashMap::from_iter([(
1239 slot20,
1240 EvmStorageSlot::new_changed(U256::ZERO, account1_slot20_value),
1241 )]),
1242 },
1243 )]));
1244 state.merge_transitions(BundleRetention::PlainState);
1245 assert_state_root(&state, &prestate, "recreated changed storage");
1246 }
1247
1248 #[test]
1249 fn prepend_state() {
1250 let address1 = Address::random();
1251 let address2 = Address::random();
1252
1253 let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1254 let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() };
1255 let account2 = RevmAccountInfo { nonce: 1, ..Default::default() };
1256
1257 let present_state = BundleState::builder(2..=2)
1258 .state_present_account_info(address1, account1_changed.clone())
1259 .build();
1260 assert_eq!(present_state.reverts.len(), 1);
1261 let previous_state = BundleState::builder(1..=1)
1262 .state_present_account_info(address1, account1)
1263 .state_present_account_info(address2, account2.clone())
1264 .build();
1265 assert_eq!(previous_state.reverts.len(), 1);
1266
1267 let mut test: ExecutionOutcome = ExecutionOutcome {
1268 bundle: present_state,
1269 receipts: vec![vec![Receipt::default(); 2]; 1],
1270 first_block: 2,
1271 requests: Vec::new(),
1272 };
1273
1274 test.prepend_state(previous_state);
1275
1276 assert_eq!(test.receipts.len(), 1);
1277 let end_state = test.state();
1278 assert_eq!(end_state.state.len(), 2);
1279 assert_eq!(end_state.reverts.len(), 1);
1281 assert_eq!(end_state.state.get(&address1).unwrap().info, Some(account1_changed));
1283 assert_eq!(end_state.state.get(&address2).unwrap().info, Some(account2));
1285 }
1286
1287 #[test]
1288 fn hashed_state_storage_root() {
1289 let address = Address::random();
1290 let hashed_address = keccak256(address);
1291 let provider_factory = create_test_provider_factory();
1292 let provider_rw = provider_factory.provider_rw().unwrap();
1293 let tx = provider_rw.tx_ref();
1294
1295 let init_storage = HashedStorage::from_iter(
1297 false,
1298 [
1299 "50000000000000000000000000000004253371b55351a08cb3267d4d265530b6",
1300 "512428ed685fff57294d1a9cbb147b18ae5db9cf6ae4b312fa1946ba0561882e",
1301 "51e6784c736ef8548f856909870b38e49ef7a4e3e77e5e945e0d5e6fcaa3037f",
1302 ]
1303 .into_iter()
1304 .map(|str| (B256::from_str(str).unwrap(), U256::from(1))),
1305 );
1306 let mut state = HashedPostState::default();
1307 state.storages.insert(hashed_address, init_storage.clone());
1308 provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1309
1310 let (storage_root, _, storage_updates) =
1312 StorageRoot::from_tx_hashed(tx, hashed_address).calculate(true).unwrap();
1313 assert_eq!(storage_root, storage_root_prehashed(init_storage.storage));
1314 assert!(!storage_updates.is_empty());
1315 provider_rw
1316 .write_individual_storage_trie_updates(hashed_address, &storage_updates)
1317 .unwrap();
1318
1319 let updated_storage = HashedStorage::from_iter(
1321 true,
1322 [
1323 "00deb8486ad8edccfdedfc07109b3667b38a03a8009271aac250cce062d90917",
1324 "88d233b7380bb1bcdc866f6871c94685848f54cf0ee033b1480310b4ddb75fc9",
1325 ]
1326 .into_iter()
1327 .map(|str| (B256::from_str(str).unwrap(), U256::from(1))),
1328 );
1329 let mut state = HashedPostState::default();
1330 state.storages.insert(hashed_address, updated_storage.clone());
1331 provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1332
1333 let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap();
1335 assert_eq!(storage_root, storage_root_prehashed(updated_storage.storage));
1336 }
1337}