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#[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 let block_hash = recovered_block.hash();
169 self.database()
170 .insert_block(Arc::unwrap_or_clone(recovered_block), StorageLocation::Both)?;
171
172 self.database().write_state(
175 &execution_output,
176 OriginalValuesKnown::No,
177 StorageLocation::StaticFiles,
178 )?;
179
180 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 self.database().update_history_indices(first_number..=last_block_number)?;
190
191 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 pub fn remove_blocks_above(&self, block_number: u64) -> ProviderResult<()> {
203 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 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 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,
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 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 },
340 )]));
341
342 state.commit(HashMap::from_iter([(
344 address_b,
345 RevmAccount {
346 info: account_b_changed.clone(),
347 status: AccountStatus::Touched,
348 storage: HashMap::default(),
349 },
350 )]));
351
352 state.merge_transitions(BundleRetention::Reverts);
353 let mut revm_bundle_state = state.take_bundle();
354
355 let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
357 let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
358 assert!(plain_state.storage.is_empty());
359 assert!(plain_state.contracts.is_empty());
360 provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
361
362 assert_eq!(reverts.storage, [[]]);
363 provider.write_state_reverts(reverts, 1).expect("Could not write reverts to DB");
364
365 let reth_account_a = account_a.into();
366 let reth_account_b = account_b.into();
367 let reth_account_b_changed = (&account_b_changed).into();
368
369 assert_eq!(
371 provider.basic_account(&address_a).expect("Could not read account state"),
372 Some(reth_account_a),
373 "Account A state is wrong"
374 );
375 assert_eq!(
376 provider.basic_account(&address_b).expect("Could not read account state"),
377 Some(reth_account_b_changed),
378 "Account B state is wrong"
379 );
380
381 let mut changeset_cursor = provider
383 .tx_ref()
384 .cursor_dup_read::<tables::AccountChangeSets>()
385 .expect("Could not open changeset cursor");
386 assert_eq!(
387 changeset_cursor.seek_exact(1).expect("Could not read account change set"),
388 Some((1, AccountBeforeTx { address: address_a, info: None })),
389 "Account A changeset is wrong"
390 );
391 assert_eq!(
392 changeset_cursor.next_dup().expect("Changeset table is malformed"),
393 Some((1, AccountBeforeTx { address: address_b, info: Some(reth_account_b) })),
394 "Account B changeset is wrong"
395 );
396
397 let mut state = State::builder().with_bundle_update().build();
398 state.insert_account(address_b, account_b_changed.clone());
399
400 state.commit(HashMap::from_iter([(
402 address_b,
403 RevmAccount {
404 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
405 info: account_b_changed,
406 storage: HashMap::default(),
407 },
408 )]));
409
410 state.merge_transitions(BundleRetention::Reverts);
411 let mut revm_bundle_state = state.take_bundle();
412
413 let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
415 let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
416 assert_eq!(
418 plain_state.storage,
419 [PlainStorageChangeset { address: address_b, wipe_storage: true, storage: vec![] }]
420 );
421 assert!(plain_state.contracts.is_empty());
422 provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
423
424 assert_eq!(
425 reverts.storage,
426 [[PlainStorageRevert { address: address_b, wiped: true, storage_revert: vec![] }]]
427 );
428 provider.write_state_reverts(reverts, 2).expect("Could not write reverts to DB");
429
430 assert_eq!(
432 provider.basic_account(&address_b).expect("Could not read account state"),
433 None,
434 "Account B should be deleted"
435 );
436
437 assert_eq!(
439 changeset_cursor.seek_exact(2).expect("Could not read account change set"),
440 Some((2, AccountBeforeTx { address: address_b, info: Some(reth_account_b_changed) })),
441 "Account B changeset is wrong after deletion"
442 );
443 }
444
445 #[test]
446 fn write_to_db_storage() {
447 let factory = create_test_provider_factory();
448 let provider = factory.database_provider_rw().unwrap();
449
450 let address_a = Address::ZERO;
451 let address_b = Address::repeat_byte(0xff);
452
453 let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
454
455 let mut state = State::builder().with_bundle_update().build();
456 state.insert_not_existing(address_a);
457 state.insert_account_with_storage(
458 address_b,
459 account_b.clone(),
460 HashMap::from_iter([(U256::from(1), U256::from(1))]),
461 );
462
463 state.commit(HashMap::from_iter([
464 (
465 address_a,
466 RevmAccount {
467 status: AccountStatus::Touched | AccountStatus::Created,
468 info: RevmAccountInfo::default(),
469 storage: HashMap::from_iter([
472 (
473 U256::from(0),
474 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
475 ),
476 (
477 U256::from(1),
478 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
479 ),
480 ]),
481 },
482 ),
483 (
484 address_b,
485 RevmAccount {
486 status: AccountStatus::Touched,
487 info: account_b,
488 storage: HashMap::from_iter([(
490 U256::from(1),
491 EvmStorageSlot {
492 present_value: U256::from(2),
493 original_value: U256::from(1),
494 ..Default::default()
495 },
496 )]),
497 },
498 ),
499 ]));
500
501 state.merge_transitions(BundleRetention::Reverts);
502
503 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
504 provider
505 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
506 .expect("Could not write bundle state to DB");
507
508 let mut storage_cursor = provider
510 .tx_ref()
511 .cursor_dup_read::<tables::PlainStorageState>()
512 .expect("Could not open plain storage state cursor");
513
514 assert_eq!(
515 storage_cursor.seek_exact(address_a).unwrap(),
516 Some((address_a, StorageEntry { key: B256::ZERO, value: U256::from(1) })),
517 "Slot 0 for account A should be 1"
518 );
519 assert_eq!(
520 storage_cursor.next_dup().unwrap(),
521 Some((
522 address_a,
523 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
524 )),
525 "Slot 1 for account A should be 2"
526 );
527 assert_eq!(
528 storage_cursor.next_dup().unwrap(),
529 None,
530 "Account A should only have 2 storage slots"
531 );
532
533 assert_eq!(
534 storage_cursor.seek_exact(address_b).unwrap(),
535 Some((
536 address_b,
537 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
538 )),
539 "Slot 1 for account B should be 2"
540 );
541 assert_eq!(
542 storage_cursor.next_dup().unwrap(),
543 None,
544 "Account B should only have 1 storage slot"
545 );
546
547 let mut changeset_cursor = provider
549 .tx_ref()
550 .cursor_dup_read::<tables::StorageChangeSets>()
551 .expect("Could not open storage changeset cursor");
552 assert_eq!(
553 changeset_cursor.seek_exact(BlockNumberAddress((1, address_a))).unwrap(),
554 Some((
555 BlockNumberAddress((1, address_a)),
556 StorageEntry { key: B256::ZERO, value: U256::from(0) }
557 )),
558 "Slot 0 for account A should have changed from 0"
559 );
560 assert_eq!(
561 changeset_cursor.next_dup().unwrap(),
562 Some((
563 BlockNumberAddress((1, address_a)),
564 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(0) }
565 )),
566 "Slot 1 for account A should have changed from 0"
567 );
568 assert_eq!(
569 changeset_cursor.next_dup().unwrap(),
570 None,
571 "Account A should only be in the changeset 2 times"
572 );
573
574 assert_eq!(
575 changeset_cursor.seek_exact(BlockNumberAddress((1, address_b))).unwrap(),
576 Some((
577 BlockNumberAddress((1, address_b)),
578 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(1) }
579 )),
580 "Slot 1 for account B should have changed from 1"
581 );
582 assert_eq!(
583 changeset_cursor.next_dup().unwrap(),
584 None,
585 "Account B should only be in the changeset 1 time"
586 );
587
588 let mut state = State::builder().with_bundle_update().build();
590 state.insert_account(address_a, RevmAccountInfo::default());
591
592 state.commit(HashMap::from_iter([(
593 address_a,
594 RevmAccount {
595 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
596 info: RevmAccountInfo::default(),
597 storage: HashMap::default(),
598 },
599 )]));
600
601 state.merge_transitions(BundleRetention::Reverts);
602 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 2, Vec::new());
603 provider
604 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
605 .expect("Could not write bundle state to DB");
606
607 assert_eq!(
608 storage_cursor.seek_exact(address_a).unwrap(),
609 None,
610 "Account A should have no storage slots after deletion"
611 );
612
613 assert_eq!(
614 changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(),
615 Some((
616 BlockNumberAddress((2, address_a)),
617 StorageEntry { key: B256::ZERO, value: U256::from(1) }
618 )),
619 "Slot 0 for account A should have changed from 1 on deletion"
620 );
621 assert_eq!(
622 changeset_cursor.next_dup().unwrap(),
623 Some((
624 BlockNumberAddress((2, address_a)),
625 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
626 )),
627 "Slot 1 for account A should have changed from 2 on deletion"
628 );
629 assert_eq!(
630 changeset_cursor.next_dup().unwrap(),
631 None,
632 "Account A should only be in the changeset 2 times on deletion"
633 );
634 }
635
636 #[test]
637 fn write_to_db_multiple_selfdestructs() {
638 let factory = create_test_provider_factory();
639 let provider = factory.database_provider_rw().unwrap();
640
641 let address1 = Address::random();
642 let account_info = RevmAccountInfo { nonce: 1, ..Default::default() };
643
644 let mut init_state = State::builder().with_bundle_update().build();
646 init_state.insert_not_existing(address1);
647 init_state.commit(HashMap::from_iter([(
648 address1,
649 RevmAccount {
650 info: account_info.clone(),
651 status: AccountStatus::Touched | AccountStatus::Created,
652 storage: HashMap::from_iter([
655 (
656 U256::ZERO,
657 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
658 ),
659 (
660 U256::from(1),
661 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
662 ),
663 ]),
664 },
665 )]));
666 init_state.merge_transitions(BundleRetention::Reverts);
667
668 let outcome =
669 ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
670 provider
671 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
672 .expect("Could not write bundle state to DB");
673
674 let mut state = State::builder().with_bundle_update().build();
675 state.insert_account_with_storage(
676 address1,
677 account_info.clone(),
678 HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]),
679 );
680
681 state.commit(HashMap::from_iter([(
683 address1,
684 RevmAccount {
685 status: AccountStatus::Touched,
686 info: account_info.clone(),
687 storage: HashMap::from_iter([(
689 U256::ZERO,
690 EvmStorageSlot {
691 original_value: U256::from(1),
692 present_value: U256::from(2),
693 ..Default::default()
694 },
695 )]),
696 },
697 )]));
698 state.merge_transitions(BundleRetention::Reverts);
699
700 state.commit(HashMap::from_iter([(
702 address1,
703 RevmAccount {
704 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
705 info: account_info.clone(),
706 storage: HashMap::default(),
707 },
708 )]));
709 state.merge_transitions(BundleRetention::Reverts);
710
711 state.commit(HashMap::from_iter([(
713 address1,
714 RevmAccount {
715 status: AccountStatus::Touched | AccountStatus::Created,
716 info: account_info.clone(),
717 storage: HashMap::default(),
718 },
719 )]));
720 state.merge_transitions(BundleRetention::Reverts);
721
722 state.commit(HashMap::from_iter([(
724 address1,
725 RevmAccount {
726 status: AccountStatus::Touched,
727 info: account_info.clone(),
728 storage: HashMap::from_iter([
732 (
733 U256::ZERO,
734 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
735 ),
736 (
737 U256::from(2),
738 EvmStorageSlot { present_value: U256::from(4), ..Default::default() },
739 ),
740 (
741 U256::from(6),
742 EvmStorageSlot { present_value: U256::from(6), ..Default::default() },
743 ),
744 ]),
745 },
746 )]));
747 state.merge_transitions(BundleRetention::Reverts);
748
749 state.commit(HashMap::from_iter([(
751 address1,
752 RevmAccount {
753 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
754 info: account_info.clone(),
755 storage: HashMap::default(),
756 },
757 )]));
758 state.merge_transitions(BundleRetention::Reverts);
759
760 state.commit(HashMap::from_iter([(
762 address1,
763 RevmAccount {
764 status: AccountStatus::Touched | AccountStatus::Created,
765 info: account_info.clone(),
766 storage: HashMap::default(),
767 },
768 )]));
769 state.commit(HashMap::from_iter([(
770 address1,
771 RevmAccount {
772 status: AccountStatus::Touched,
773 info: account_info.clone(),
774 storage: HashMap::from_iter([(
776 U256::ZERO,
777 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
778 )]),
779 },
780 )]));
781 state.commit(HashMap::from_iter([(
782 address1,
783 RevmAccount {
784 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
785 info: account_info.clone(),
786 storage: HashMap::default(),
787 },
788 )]));
789 state.commit(HashMap::from_iter([(
790 address1,
791 RevmAccount {
792 status: AccountStatus::Touched | AccountStatus::Created,
793 info: account_info.clone(),
794 storage: HashMap::default(),
795 },
796 )]));
797 state.merge_transitions(BundleRetention::Reverts);
798
799 state.commit(HashMap::from_iter([(
801 address1,
802 RevmAccount {
803 status: AccountStatus::Touched,
804 info: account_info,
805 storage: HashMap::from_iter([(
807 U256::ZERO,
808 EvmStorageSlot { present_value: U256::from(9), ..Default::default() },
809 )]),
810 },
811 )]));
812 state.merge_transitions(BundleRetention::Reverts);
813
814 let bundle = state.take_bundle();
815
816 let outcome: ExecutionOutcome =
817 ExecutionOutcome::new(bundle, Default::default(), 1, Vec::new());
818 provider
819 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
820 .expect("Could not write bundle state to DB");
821
822 let mut storage_changeset_cursor = provider
823 .tx_ref()
824 .cursor_dup_read::<tables::StorageChangeSets>()
825 .expect("Could not open plain storage state cursor");
826 let mut storage_changes = storage_changeset_cursor.walk_range(..).unwrap();
827
828 assert_eq!(
838 storage_changes.next(),
839 Some(Ok((
840 BlockNumberAddress((0, address1)),
841 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
842 )))
843 );
844 assert_eq!(
845 storage_changes.next(),
846 Some(Ok((
847 BlockNumberAddress((0, address1)),
848 StorageEntry { key: B256::with_last_byte(1), value: U256::ZERO }
849 )))
850 );
851
852 assert_eq!(
855 storage_changes.next(),
856 Some(Ok((
857 BlockNumberAddress((1, address1)),
858 StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) }
859 )))
860 );
861
862 assert_eq!(
866 storage_changes.next(),
867 Some(Ok((
868 BlockNumberAddress((2, address1)),
869 StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) }
870 )))
871 );
872 assert_eq!(
873 storage_changes.next(),
874 Some(Ok((
875 BlockNumberAddress((2, address1)),
876 StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) }
877 )))
878 );
879
880 assert_eq!(
888 storage_changes.next(),
889 Some(Ok((
890 BlockNumberAddress((4, address1)),
891 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
892 )))
893 );
894 assert_eq!(
895 storage_changes.next(),
896 Some(Ok((
897 BlockNumberAddress((4, address1)),
898 StorageEntry { key: B256::with_last_byte(2), value: U256::ZERO }
899 )))
900 );
901 assert_eq!(
902 storage_changes.next(),
903 Some(Ok((
904 BlockNumberAddress((4, address1)),
905 StorageEntry { key: B256::with_last_byte(6), value: U256::ZERO }
906 )))
907 );
908
909 assert_eq!(
914 storage_changes.next(),
915 Some(Ok((
916 BlockNumberAddress((5, address1)),
917 StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) }
918 )))
919 );
920 assert_eq!(
921 storage_changes.next(),
922 Some(Ok((
923 BlockNumberAddress((5, address1)),
924 StorageEntry { key: B256::with_last_byte(2), value: U256::from(4) }
925 )))
926 );
927 assert_eq!(
928 storage_changes.next(),
929 Some(Ok((
930 BlockNumberAddress((5, address1)),
931 StorageEntry { key: B256::with_last_byte(6), value: U256::from(6) }
932 )))
933 );
934
935 assert_eq!(
941 storage_changes.next(),
942 Some(Ok((
943 BlockNumberAddress((7, address1)),
944 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
945 )))
946 );
947 assert_eq!(storage_changes.next(), None);
948 }
949
950 #[test]
951 fn storage_change_after_selfdestruct_within_block() {
952 let factory = create_test_provider_factory();
953 let provider = factory.database_provider_rw().unwrap();
954
955 let address1 = Address::random();
956 let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
957
958 let mut init_state = State::builder().with_bundle_update().build();
960 init_state.insert_not_existing(address1);
961 init_state.commit(HashMap::from_iter([(
962 address1,
963 RevmAccount {
964 info: account1.clone(),
965 status: AccountStatus::Touched | AccountStatus::Created,
966 storage: HashMap::from_iter([
969 (
970 U256::ZERO,
971 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
972 ),
973 (
974 U256::from(1),
975 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
976 ),
977 ]),
978 },
979 )]));
980 init_state.merge_transitions(BundleRetention::Reverts);
981 let outcome =
982 ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
983 provider
984 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
985 .expect("Could not write bundle state to DB");
986
987 let mut state = State::builder().with_bundle_update().build();
988 state.insert_account_with_storage(
989 address1,
990 account1.clone(),
991 HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]),
992 );
993
994 state.commit(HashMap::from_iter([(
996 address1,
997 RevmAccount {
998 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
999 info: account1.clone(),
1000 storage: HashMap::default(),
1001 },
1002 )]));
1003
1004 state.commit(HashMap::from_iter([(
1005 address1,
1006 RevmAccount {
1007 status: AccountStatus::Touched | AccountStatus::Created,
1008 info: account1.clone(),
1009 storage: HashMap::default(),
1010 },
1011 )]));
1012
1013 state.commit(HashMap::from_iter([(
1014 address1,
1015 RevmAccount {
1016 status: AccountStatus::Touched,
1017 info: account1,
1018 storage: HashMap::from_iter([(
1020 U256::from(1),
1021 EvmStorageSlot { present_value: U256::from(5), ..Default::default() },
1022 )]),
1023 },
1024 )]));
1025
1026 state.merge_transitions(BundleRetention::Reverts);
1028 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
1029 provider
1030 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1031 .expect("Could not write bundle state to DB");
1032
1033 let mut storage_changeset_cursor = provider
1034 .tx_ref()
1035 .cursor_dup_read::<tables::StorageChangeSets>()
1036 .expect("Could not open plain storage state cursor");
1037 let range = BlockNumberAddress::range(1..=1);
1038 let mut storage_changes = storage_changeset_cursor.walk_range(range).unwrap();
1039
1040 assert_eq!(
1041 storage_changes.next(),
1042 Some(Ok((
1043 BlockNumberAddress((1, address1)),
1044 StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) }
1045 )))
1046 );
1047 assert_eq!(
1048 storage_changes.next(),
1049 Some(Ok((
1050 BlockNumberAddress((1, address1)),
1051 StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) }
1052 )))
1053 );
1054 assert_eq!(storage_changes.next(), None);
1055 }
1056
1057 #[test]
1058 fn revert_to_indices() {
1059 let base: ExecutionOutcome = ExecutionOutcome {
1060 bundle: BundleState::default(),
1061 receipts: vec![vec![Receipt::default(); 2]; 7],
1062 first_block: 10,
1063 requests: Vec::new(),
1064 };
1065
1066 let mut this = base.clone();
1067 assert!(this.revert_to(10));
1068 assert_eq!(this.receipts.len(), 1);
1069
1070 let mut this = base.clone();
1071 assert!(!this.revert_to(9));
1072 assert_eq!(this.receipts.len(), 7);
1073
1074 let mut this = base.clone();
1075 assert!(this.revert_to(15));
1076 assert_eq!(this.receipts.len(), 6);
1077
1078 let mut this = base.clone();
1079 assert!(this.revert_to(16));
1080 assert_eq!(this.receipts.len(), 7);
1081
1082 let mut this = base;
1083 assert!(!this.revert_to(17));
1084 assert_eq!(this.receipts.len(), 7);
1085 }
1086
1087 #[test]
1088 fn bundle_state_state_root() {
1089 type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>;
1090 let mut prestate: PreState = (0..10)
1091 .map(|key| {
1092 let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None };
1093 let storage =
1094 (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect();
1095 (Address::with_last_byte(key), (account, storage))
1096 })
1097 .collect();
1098
1099 let provider_factory = create_test_provider_factory();
1100 let provider_rw = provider_factory.database_provider_rw().unwrap();
1101
1102 let tx = provider_rw.tx_ref();
1104 for (address, (account, storage)) in &prestate {
1105 let hashed_address = keccak256(address);
1106 tx.put::<tables::HashedAccounts>(hashed_address, *account).unwrap();
1107 for (slot, value) in storage {
1108 tx.put::<tables::HashedStorages>(
1109 hashed_address,
1110 StorageEntry { key: keccak256(slot), value: *value },
1111 )
1112 .unwrap();
1113 }
1114 }
1115
1116 let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
1117 provider_rw.write_trie_updates(&updates).unwrap();
1118
1119 let mut state = State::builder().with_bundle_update().build();
1120
1121 let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
1122 assert_eq!(
1123 StateRoot::overlay_root(
1124 tx,
1125 provider_factory.hashed_post_state(&state.bundle_state)
1126 )
1127 .unwrap(),
1128 state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
1129 address,
1130 (account, storage.into_iter())
1131 ))),
1132 "{msg}"
1133 );
1134 };
1135
1136 assert_state_root(&state, &prestate, "empty");
1138
1139 let address1 = Address::with_last_byte(1);
1141 let account1_old = prestate.remove(&address1).unwrap();
1142 state.insert_account(address1, account1_old.0.into());
1143 state.commit(HashMap::from_iter([(
1144 address1,
1145 RevmAccount {
1146 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1147 info: RevmAccountInfo::default(),
1148 storage: HashMap::default(),
1149 },
1150 )]));
1151 state.merge_transitions(BundleRetention::PlainState);
1152 assert_state_root(&state, &prestate, "destroyed account");
1153
1154 let address2 = Address::with_last_byte(2);
1156 let slot2 = U256::from(2);
1157 let slot2_key = B256::from(slot2);
1158 let account2 = prestate.get_mut(&address2).unwrap();
1159 let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap();
1160 state.insert_account_with_storage(
1161 address2,
1162 account2.0.into(),
1163 HashMap::from_iter([(slot2, account2_slot2_old_value)]),
1164 );
1165
1166 let account2_slot2_new_value = U256::from(100);
1167 account2.1.insert(slot2_key, account2_slot2_new_value);
1168 state.commit(HashMap::from_iter([(
1169 address2,
1170 RevmAccount {
1171 status: AccountStatus::Touched,
1172 info: account2.0.into(),
1173 storage: HashMap::from_iter([(
1174 slot2,
1175 EvmStorageSlot::new_changed(account2_slot2_old_value, account2_slot2_new_value),
1176 )]),
1177 },
1178 )]));
1179 state.merge_transitions(BundleRetention::PlainState);
1180 assert_state_root(&state, &prestate, "changed storage");
1181
1182 let address3 = Address::with_last_byte(3);
1184 let account3 = prestate.get_mut(&address3).unwrap();
1185 state.insert_account(address3, account3.0.into());
1186
1187 account3.0.balance = U256::from(24);
1188 state.commit(HashMap::from_iter([(
1189 address3,
1190 RevmAccount {
1191 status: AccountStatus::Touched,
1192 info: account3.0.into(),
1193 storage: HashMap::default(),
1194 },
1195 )]));
1196 state.merge_transitions(BundleRetention::PlainState);
1197 assert_state_root(&state, &prestate, "changed balance");
1198
1199 let address4 = Address::with_last_byte(4);
1201 let account4 = prestate.get_mut(&address4).unwrap();
1202 state.insert_account(address4, account4.0.into());
1203
1204 account4.0.nonce = 128;
1205 state.commit(HashMap::from_iter([(
1206 address4,
1207 RevmAccount {
1208 status: AccountStatus::Touched,
1209 info: account4.0.into(),
1210 storage: HashMap::default(),
1211 },
1212 )]));
1213 state.merge_transitions(BundleRetention::PlainState);
1214 assert_state_root(&state, &prestate, "changed nonce");
1215
1216 let account1_new =
1218 Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) };
1219 prestate.insert(address1, (account1_new, BTreeMap::default()));
1220 state.commit(HashMap::from_iter([(
1221 address1,
1222 RevmAccount {
1223 status: AccountStatus::Touched | AccountStatus::Created,
1224 info: account1_new.into(),
1225 storage: HashMap::default(),
1226 },
1227 )]));
1228 state.merge_transitions(BundleRetention::PlainState);
1229 assert_state_root(&state, &prestate, "recreated");
1230
1231 let slot20 = U256::from(20);
1233 let slot20_key = B256::from(slot20);
1234 let account1_slot20_value = U256::from(12345);
1235 prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value);
1236 state.commit(HashMap::from_iter([(
1237 address1,
1238 RevmAccount {
1239 status: AccountStatus::Touched | AccountStatus::Created,
1240 info: account1_new.into(),
1241 storage: HashMap::from_iter([(
1242 slot20,
1243 EvmStorageSlot::new_changed(U256::ZERO, account1_slot20_value),
1244 )]),
1245 },
1246 )]));
1247 state.merge_transitions(BundleRetention::PlainState);
1248 assert_state_root(&state, &prestate, "recreated changed storage");
1249 }
1250
1251 #[test]
1252 fn prepend_state() {
1253 let address1 = Address::random();
1254 let address2 = Address::random();
1255
1256 let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1257 let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() };
1258 let account2 = RevmAccountInfo { nonce: 1, ..Default::default() };
1259
1260 let present_state = BundleState::builder(2..=2)
1261 .state_present_account_info(address1, account1_changed.clone())
1262 .build();
1263 assert_eq!(present_state.reverts.len(), 1);
1264 let previous_state = BundleState::builder(1..=1)
1265 .state_present_account_info(address1, account1)
1266 .state_present_account_info(address2, account2.clone())
1267 .build();
1268 assert_eq!(previous_state.reverts.len(), 1);
1269
1270 let mut test: ExecutionOutcome = ExecutionOutcome {
1271 bundle: present_state,
1272 receipts: vec![vec![Receipt::default(); 2]; 1],
1273 first_block: 2,
1274 requests: Vec::new(),
1275 };
1276
1277 test.prepend_state(previous_state);
1278
1279 assert_eq!(test.receipts.len(), 1);
1280 let end_state = test.state();
1281 assert_eq!(end_state.state.len(), 2);
1282 assert_eq!(end_state.reverts.len(), 1);
1284 assert_eq!(end_state.state.get(&address1).unwrap().info, Some(account1_changed));
1286 assert_eq!(end_state.state.get(&address2).unwrap().info, Some(account2));
1288 }
1289
1290 #[test]
1291 fn hashed_state_storage_root() {
1292 let address = Address::random();
1293 let hashed_address = keccak256(address);
1294 let provider_factory = create_test_provider_factory();
1295 let provider_rw = provider_factory.provider_rw().unwrap();
1296 let tx = provider_rw.tx_ref();
1297
1298 let init_storage = HashedStorage::from_iter(
1300 false,
1301 [
1302 "50000000000000000000000000000004253371b55351a08cb3267d4d265530b6",
1303 "512428ed685fff57294d1a9cbb147b18ae5db9cf6ae4b312fa1946ba0561882e",
1304 "51e6784c736ef8548f856909870b38e49ef7a4e3e77e5e945e0d5e6fcaa3037f",
1305 ]
1306 .into_iter()
1307 .map(|str| (B256::from_str(str).unwrap(), U256::from(1))),
1308 );
1309 let mut state = HashedPostState::default();
1310 state.storages.insert(hashed_address, init_storage.clone());
1311 provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1312
1313 let (storage_root, _, storage_updates) =
1315 StorageRoot::from_tx_hashed(tx, hashed_address).calculate(true).unwrap();
1316 assert_eq!(storage_root, storage_root_prehashed(init_storage.storage));
1317 assert!(!storage_updates.is_empty());
1318 provider_rw
1319 .write_individual_storage_trie_updates(hashed_address, &storage_updates)
1320 .unwrap();
1321
1322 let updated_storage = HashedStorage::from_iter(
1324 true,
1325 [
1326 "00deb8486ad8edccfdedfc07109b3667b38a03a8009271aac250cce062d90917",
1327 "88d233b7380bb1bcdc866f6871c94685848f54cf0ee033b1480310b4ddb75fc9",
1328 ]
1329 .into_iter()
1330 .map(|str| (B256::from_str(str).unwrap(), U256::from(1))),
1331 );
1332 let mut state = HashedPostState::default();
1333 state.storages.insert(hashed_address, updated_storage.clone());
1334 provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1335
1336 let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap();
1338 assert_eq!(storage_root, storage_root_prehashed(updated_storage.storage));
1339 }
1340}