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::{NodePrimitives, StaticFileSegment};
11use reth_primitives_traits::SignedTransaction;
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 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<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_execution_types::ExecutionOutcome;
238 use reth_primitives::{Account, Receipt, StorageEntry};
239 use reth_storage_api::{DatabaseProviderFactory, HashedPostStateProvider};
240 use reth_trie::{
241 test_utils::{state_root, storage_root_prehashed},
242 HashedPostState, HashedStorage, StateRoot, StorageRoot,
243 };
244 use reth_trie_db::{DatabaseStateRoot, DatabaseStorageRoot};
245 use revm_database::{
246 states::{
247 bundle_state::BundleRetention, changes::PlainStorageRevert, PlainStorageChangeset,
248 },
249 BundleState, State,
250 };
251 use revm_database_interface::{DatabaseCommit, EmptyDB};
252 use revm_state::{
253 Account as RevmAccount, AccountInfo as RevmAccountInfo, AccountStatus, EvmStorageSlot,
254 };
255 use std::{collections::BTreeMap, str::FromStr};
256
257 #[test]
258 fn wiped_entries_are_removed() {
259 let provider_factory = create_test_provider_factory();
260
261 let addresses = (0..10).map(|_| Address::random()).collect::<Vec<_>>();
262 let destroyed_address = *addresses.first().unwrap();
263 let destroyed_address_hashed = keccak256(destroyed_address);
264 let slot = B256::with_last_byte(1);
265 let hashed_slot = keccak256(slot);
266 {
267 let provider_rw = provider_factory.provider_rw().unwrap();
268 let mut accounts_cursor =
269 provider_rw.tx_ref().cursor_write::<tables::HashedAccounts>().unwrap();
270 let mut storage_cursor =
271 provider_rw.tx_ref().cursor_write::<tables::HashedStorages>().unwrap();
272
273 for address in addresses {
274 let hashed_address = keccak256(address);
275 accounts_cursor
276 .insert(hashed_address, &Account { nonce: 1, ..Default::default() })
277 .unwrap();
278 storage_cursor
279 .insert(
280 hashed_address,
281 &StorageEntry { key: hashed_slot, value: U256::from(1) },
282 )
283 .unwrap();
284 }
285 provider_rw.commit().unwrap();
286 }
287
288 let mut hashed_state = HashedPostState::default();
289 hashed_state.accounts.insert(destroyed_address_hashed, None);
290 hashed_state.storages.insert(destroyed_address_hashed, HashedStorage::new(true));
291
292 let provider_rw = provider_factory.provider_rw().unwrap();
293 assert!(matches!(provider_rw.write_hashed_state(&hashed_state.into_sorted()), Ok(())));
294 provider_rw.commit().unwrap();
295
296 let provider = provider_factory.provider().unwrap();
297 assert_eq!(
298 provider.tx_ref().get::<tables::HashedAccounts>(destroyed_address_hashed),
299 Ok(None)
300 );
301 assert_eq!(
302 provider
303 .tx_ref()
304 .cursor_read::<tables::HashedStorages>()
305 .unwrap()
306 .seek_by_key_subkey(destroyed_address_hashed, hashed_slot),
307 Ok(None)
308 );
309 }
310
311 #[test]
312 fn write_to_db_account_info() {
313 let factory = create_test_provider_factory();
314 let provider = factory.provider_rw().unwrap();
315
316 let address_a = Address::ZERO;
317 let address_b = Address::repeat_byte(0xff);
318
319 let account_a = RevmAccountInfo { balance: U256::from(1), nonce: 1, ..Default::default() };
320 let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
321 let account_b_changed =
322 RevmAccountInfo { balance: U256::from(3), nonce: 3, ..Default::default() };
323
324 let mut state = State::builder().with_bundle_update().build();
325 state.insert_not_existing(address_a);
326 state.insert_account(address_b, account_b.clone());
327
328 state.commit(HashMap::from_iter([(
330 address_a,
331 RevmAccount {
332 info: account_a.clone(),
333 status: AccountStatus::Touched | AccountStatus::Created,
334 storage: HashMap::default(),
335 },
336 )]));
337
338 state.commit(HashMap::from_iter([(
340 address_b,
341 RevmAccount {
342 info: account_b_changed.clone(),
343 status: AccountStatus::Touched,
344 storage: HashMap::default(),
345 },
346 )]));
347
348 state.merge_transitions(BundleRetention::Reverts);
349 let mut revm_bundle_state = state.take_bundle();
350
351 let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
353 let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
354 assert!(plain_state.storage.is_empty());
355 assert!(plain_state.contracts.is_empty());
356 provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
357
358 assert_eq!(reverts.storage, [[]]);
359 provider.write_state_reverts(reverts, 1).expect("Could not write reverts to DB");
360
361 let reth_account_a = account_a.into();
362 let reth_account_b = account_b.into();
363 let reth_account_b_changed = (&account_b_changed).into();
364
365 assert_eq!(
367 provider.basic_account(&address_a).expect("Could not read account state"),
368 Some(reth_account_a),
369 "Account A state is wrong"
370 );
371 assert_eq!(
372 provider.basic_account(&address_b).expect("Could not read account state"),
373 Some(reth_account_b_changed),
374 "Account B state is wrong"
375 );
376
377 let mut changeset_cursor = provider
379 .tx_ref()
380 .cursor_dup_read::<tables::AccountChangeSets>()
381 .expect("Could not open changeset cursor");
382 assert_eq!(
383 changeset_cursor.seek_exact(1).expect("Could not read account change set"),
384 Some((1, AccountBeforeTx { address: address_a, info: None })),
385 "Account A changeset is wrong"
386 );
387 assert_eq!(
388 changeset_cursor.next_dup().expect("Changeset table is malformed"),
389 Some((1, AccountBeforeTx { address: address_b, info: Some(reth_account_b) })),
390 "Account B changeset is wrong"
391 );
392
393 let mut state = State::builder().with_bundle_update().build();
394 state.insert_account(address_b, account_b_changed.clone());
395
396 state.commit(HashMap::from_iter([(
398 address_b,
399 RevmAccount {
400 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
401 info: account_b_changed,
402 storage: HashMap::default(),
403 },
404 )]));
405
406 state.merge_transitions(BundleRetention::Reverts);
407 let mut revm_bundle_state = state.take_bundle();
408
409 let reverts = revm_bundle_state.take_all_reverts().to_plain_state_reverts();
411 let plain_state = revm_bundle_state.to_plain_state(OriginalValuesKnown::Yes);
412 assert_eq!(
414 plain_state.storage,
415 [PlainStorageChangeset { address: address_b, wipe_storage: true, storage: vec![] }]
416 );
417 assert!(plain_state.contracts.is_empty());
418 provider.write_state_changes(plain_state).expect("Could not write plain state to DB");
419
420 assert_eq!(
421 reverts.storage,
422 [[PlainStorageRevert { address: address_b, wiped: true, storage_revert: vec![] }]]
423 );
424 provider.write_state_reverts(reverts, 2).expect("Could not write reverts to DB");
425
426 assert_eq!(
428 provider.basic_account(&address_b).expect("Could not read account state"),
429 None,
430 "Account B should be deleted"
431 );
432
433 assert_eq!(
435 changeset_cursor.seek_exact(2).expect("Could not read account change set"),
436 Some((2, AccountBeforeTx { address: address_b, info: Some(reth_account_b_changed) })),
437 "Account B changeset is wrong after deletion"
438 );
439 }
440
441 #[test]
442 fn write_to_db_storage() {
443 let factory = create_test_provider_factory();
444 let provider = factory.database_provider_rw().unwrap();
445
446 let address_a = Address::ZERO;
447 let address_b = Address::repeat_byte(0xff);
448
449 let account_b = RevmAccountInfo { balance: U256::from(2), nonce: 2, ..Default::default() };
450
451 let mut state = State::builder().with_bundle_update().build();
452 state.insert_not_existing(address_a);
453 state.insert_account_with_storage(
454 address_b,
455 account_b.clone(),
456 HashMap::from_iter([(U256::from(1), U256::from(1))]),
457 );
458
459 state.commit(HashMap::from_iter([
460 (
461 address_a,
462 RevmAccount {
463 status: AccountStatus::Touched | AccountStatus::Created,
464 info: RevmAccountInfo::default(),
465 storage: HashMap::from_iter([
468 (
469 U256::from(0),
470 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
471 ),
472 (
473 U256::from(1),
474 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
475 ),
476 ]),
477 },
478 ),
479 (
480 address_b,
481 RevmAccount {
482 status: AccountStatus::Touched,
483 info: account_b,
484 storage: HashMap::from_iter([(
486 U256::from(1),
487 EvmStorageSlot {
488 present_value: U256::from(2),
489 original_value: U256::from(1),
490 ..Default::default()
491 },
492 )]),
493 },
494 ),
495 ]));
496
497 state.merge_transitions(BundleRetention::Reverts);
498
499 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
500 provider
501 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
502 .expect("Could not write bundle state to DB");
503
504 let mut storage_cursor = provider
506 .tx_ref()
507 .cursor_dup_read::<tables::PlainStorageState>()
508 .expect("Could not open plain storage state cursor");
509
510 assert_eq!(
511 storage_cursor.seek_exact(address_a).unwrap(),
512 Some((address_a, StorageEntry { key: B256::ZERO, value: U256::from(1) })),
513 "Slot 0 for account A should be 1"
514 );
515 assert_eq!(
516 storage_cursor.next_dup().unwrap(),
517 Some((
518 address_a,
519 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
520 )),
521 "Slot 1 for account A should be 2"
522 );
523 assert_eq!(
524 storage_cursor.next_dup().unwrap(),
525 None,
526 "Account A should only have 2 storage slots"
527 );
528
529 assert_eq!(
530 storage_cursor.seek_exact(address_b).unwrap(),
531 Some((
532 address_b,
533 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
534 )),
535 "Slot 1 for account B should be 2"
536 );
537 assert_eq!(
538 storage_cursor.next_dup().unwrap(),
539 None,
540 "Account B should only have 1 storage slot"
541 );
542
543 let mut changeset_cursor = provider
545 .tx_ref()
546 .cursor_dup_read::<tables::StorageChangeSets>()
547 .expect("Could not open storage changeset cursor");
548 assert_eq!(
549 changeset_cursor.seek_exact(BlockNumberAddress((1, address_a))).unwrap(),
550 Some((
551 BlockNumberAddress((1, address_a)),
552 StorageEntry { key: B256::ZERO, value: U256::from(0) }
553 )),
554 "Slot 0 for account A should have changed from 0"
555 );
556 assert_eq!(
557 changeset_cursor.next_dup().unwrap(),
558 Some((
559 BlockNumberAddress((1, address_a)),
560 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(0) }
561 )),
562 "Slot 1 for account A should have changed from 0"
563 );
564 assert_eq!(
565 changeset_cursor.next_dup().unwrap(),
566 None,
567 "Account A should only be in the changeset 2 times"
568 );
569
570 assert_eq!(
571 changeset_cursor.seek_exact(BlockNumberAddress((1, address_b))).unwrap(),
572 Some((
573 BlockNumberAddress((1, address_b)),
574 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(1) }
575 )),
576 "Slot 1 for account B should have changed from 1"
577 );
578 assert_eq!(
579 changeset_cursor.next_dup().unwrap(),
580 None,
581 "Account B should only be in the changeset 1 time"
582 );
583
584 let mut state = State::builder().with_bundle_update().build();
586 state.insert_account(address_a, RevmAccountInfo::default());
587
588 state.commit(HashMap::from_iter([(
589 address_a,
590 RevmAccount {
591 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
592 info: RevmAccountInfo::default(),
593 storage: HashMap::default(),
594 },
595 )]));
596
597 state.merge_transitions(BundleRetention::Reverts);
598 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 2, Vec::new());
599 provider
600 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
601 .expect("Could not write bundle state to DB");
602
603 assert_eq!(
604 storage_cursor.seek_exact(address_a).unwrap(),
605 None,
606 "Account A should have no storage slots after deletion"
607 );
608
609 assert_eq!(
610 changeset_cursor.seek_exact(BlockNumberAddress((2, address_a))).unwrap(),
611 Some((
612 BlockNumberAddress((2, address_a)),
613 StorageEntry { key: B256::ZERO, value: U256::from(1) }
614 )),
615 "Slot 0 for account A should have changed from 1 on deletion"
616 );
617 assert_eq!(
618 changeset_cursor.next_dup().unwrap(),
619 Some((
620 BlockNumberAddress((2, address_a)),
621 StorageEntry { key: B256::from(U256::from(1).to_be_bytes()), value: U256::from(2) }
622 )),
623 "Slot 1 for account A should have changed from 2 on deletion"
624 );
625 assert_eq!(
626 changeset_cursor.next_dup().unwrap(),
627 None,
628 "Account A should only be in the changeset 2 times on deletion"
629 );
630 }
631
632 #[test]
633 fn write_to_db_multiple_selfdestructs() {
634 let factory = create_test_provider_factory();
635 let provider = factory.database_provider_rw().unwrap();
636
637 let address1 = Address::random();
638 let account_info = RevmAccountInfo { nonce: 1, ..Default::default() };
639
640 let mut init_state = State::builder().with_bundle_update().build();
642 init_state.insert_not_existing(address1);
643 init_state.commit(HashMap::from_iter([(
644 address1,
645 RevmAccount {
646 info: account_info.clone(),
647 status: AccountStatus::Touched | AccountStatus::Created,
648 storage: HashMap::from_iter([
651 (
652 U256::ZERO,
653 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
654 ),
655 (
656 U256::from(1),
657 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
658 ),
659 ]),
660 },
661 )]));
662 init_state.merge_transitions(BundleRetention::Reverts);
663
664 let outcome =
665 ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
666 provider
667 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
668 .expect("Could not write bundle state to DB");
669
670 let mut state = State::builder().with_bundle_update().build();
671 state.insert_account_with_storage(
672 address1,
673 account_info.clone(),
674 HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]),
675 );
676
677 state.commit(HashMap::from_iter([(
679 address1,
680 RevmAccount {
681 status: AccountStatus::Touched,
682 info: account_info.clone(),
683 storage: HashMap::from_iter([(
685 U256::ZERO,
686 EvmStorageSlot {
687 original_value: U256::from(1),
688 present_value: U256::from(2),
689 ..Default::default()
690 },
691 )]),
692 },
693 )]));
694 state.merge_transitions(BundleRetention::Reverts);
695
696 state.commit(HashMap::from_iter([(
698 address1,
699 RevmAccount {
700 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
701 info: account_info.clone(),
702 storage: HashMap::default(),
703 },
704 )]));
705 state.merge_transitions(BundleRetention::Reverts);
706
707 state.commit(HashMap::from_iter([(
709 address1,
710 RevmAccount {
711 status: AccountStatus::Touched | AccountStatus::Created,
712 info: account_info.clone(),
713 storage: HashMap::default(),
714 },
715 )]));
716 state.merge_transitions(BundleRetention::Reverts);
717
718 state.commit(HashMap::from_iter([(
720 address1,
721 RevmAccount {
722 status: AccountStatus::Touched,
723 info: account_info.clone(),
724 storage: HashMap::from_iter([
728 (
729 U256::ZERO,
730 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
731 ),
732 (
733 U256::from(2),
734 EvmStorageSlot { present_value: U256::from(4), ..Default::default() },
735 ),
736 (
737 U256::from(6),
738 EvmStorageSlot { present_value: U256::from(6), ..Default::default() },
739 ),
740 ]),
741 },
742 )]));
743 state.merge_transitions(BundleRetention::Reverts);
744
745 state.commit(HashMap::from_iter([(
747 address1,
748 RevmAccount {
749 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
750 info: account_info.clone(),
751 storage: HashMap::default(),
752 },
753 )]));
754 state.merge_transitions(BundleRetention::Reverts);
755
756 state.commit(HashMap::from_iter([(
758 address1,
759 RevmAccount {
760 status: AccountStatus::Touched | AccountStatus::Created,
761 info: account_info.clone(),
762 storage: HashMap::default(),
763 },
764 )]));
765 state.commit(HashMap::from_iter([(
766 address1,
767 RevmAccount {
768 status: AccountStatus::Touched,
769 info: account_info.clone(),
770 storage: HashMap::from_iter([(
772 U256::ZERO,
773 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
774 )]),
775 },
776 )]));
777 state.commit(HashMap::from_iter([(
778 address1,
779 RevmAccount {
780 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
781 info: account_info.clone(),
782 storage: HashMap::default(),
783 },
784 )]));
785 state.commit(HashMap::from_iter([(
786 address1,
787 RevmAccount {
788 status: AccountStatus::Touched | AccountStatus::Created,
789 info: account_info.clone(),
790 storage: HashMap::default(),
791 },
792 )]));
793 state.merge_transitions(BundleRetention::Reverts);
794
795 state.commit(HashMap::from_iter([(
797 address1,
798 RevmAccount {
799 status: AccountStatus::Touched,
800 info: account_info,
801 storage: HashMap::from_iter([(
803 U256::ZERO,
804 EvmStorageSlot { present_value: U256::from(9), ..Default::default() },
805 )]),
806 },
807 )]));
808 state.merge_transitions(BundleRetention::Reverts);
809
810 let bundle = state.take_bundle();
811
812 let outcome: ExecutionOutcome =
813 ExecutionOutcome::new(bundle, Default::default(), 1, Vec::new());
814 provider
815 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
816 .expect("Could not write bundle state to DB");
817
818 let mut storage_changeset_cursor = provider
819 .tx_ref()
820 .cursor_dup_read::<tables::StorageChangeSets>()
821 .expect("Could not open plain storage state cursor");
822 let mut storage_changes = storage_changeset_cursor.walk_range(..).unwrap();
823
824 assert_eq!(
834 storage_changes.next(),
835 Some(Ok((
836 BlockNumberAddress((0, address1)),
837 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
838 )))
839 );
840 assert_eq!(
841 storage_changes.next(),
842 Some(Ok((
843 BlockNumberAddress((0, address1)),
844 StorageEntry { key: B256::with_last_byte(1), value: U256::ZERO }
845 )))
846 );
847
848 assert_eq!(
851 storage_changes.next(),
852 Some(Ok((
853 BlockNumberAddress((1, address1)),
854 StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) }
855 )))
856 );
857
858 assert_eq!(
862 storage_changes.next(),
863 Some(Ok((
864 BlockNumberAddress((2, address1)),
865 StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) }
866 )))
867 );
868 assert_eq!(
869 storage_changes.next(),
870 Some(Ok((
871 BlockNumberAddress((2, address1)),
872 StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) }
873 )))
874 );
875
876 assert_eq!(
884 storage_changes.next(),
885 Some(Ok((
886 BlockNumberAddress((4, address1)),
887 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
888 )))
889 );
890 assert_eq!(
891 storage_changes.next(),
892 Some(Ok((
893 BlockNumberAddress((4, address1)),
894 StorageEntry { key: B256::with_last_byte(2), value: U256::ZERO }
895 )))
896 );
897 assert_eq!(
898 storage_changes.next(),
899 Some(Ok((
900 BlockNumberAddress((4, address1)),
901 StorageEntry { key: B256::with_last_byte(6), value: U256::ZERO }
902 )))
903 );
904
905 assert_eq!(
910 storage_changes.next(),
911 Some(Ok((
912 BlockNumberAddress((5, address1)),
913 StorageEntry { key: B256::with_last_byte(0), value: U256::from(2) }
914 )))
915 );
916 assert_eq!(
917 storage_changes.next(),
918 Some(Ok((
919 BlockNumberAddress((5, address1)),
920 StorageEntry { key: B256::with_last_byte(2), value: U256::from(4) }
921 )))
922 );
923 assert_eq!(
924 storage_changes.next(),
925 Some(Ok((
926 BlockNumberAddress((5, address1)),
927 StorageEntry { key: B256::with_last_byte(6), value: U256::from(6) }
928 )))
929 );
930
931 assert_eq!(
937 storage_changes.next(),
938 Some(Ok((
939 BlockNumberAddress((7, address1)),
940 StorageEntry { key: B256::with_last_byte(0), value: U256::ZERO }
941 )))
942 );
943 assert_eq!(storage_changes.next(), None);
944 }
945
946 #[test]
947 fn storage_change_after_selfdestruct_within_block() {
948 let factory = create_test_provider_factory();
949 let provider = factory.database_provider_rw().unwrap();
950
951 let address1 = Address::random();
952 let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
953
954 let mut init_state = State::builder().with_bundle_update().build();
956 init_state.insert_not_existing(address1);
957 init_state.commit(HashMap::from_iter([(
958 address1,
959 RevmAccount {
960 info: account1.clone(),
961 status: AccountStatus::Touched | AccountStatus::Created,
962 storage: HashMap::from_iter([
965 (
966 U256::ZERO,
967 EvmStorageSlot { present_value: U256::from(1), ..Default::default() },
968 ),
969 (
970 U256::from(1),
971 EvmStorageSlot { present_value: U256::from(2), ..Default::default() },
972 ),
973 ]),
974 },
975 )]));
976 init_state.merge_transitions(BundleRetention::Reverts);
977 let outcome =
978 ExecutionOutcome::new(init_state.take_bundle(), Default::default(), 0, Vec::new());
979 provider
980 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
981 .expect("Could not write bundle state to DB");
982
983 let mut state = State::builder().with_bundle_update().build();
984 state.insert_account_with_storage(
985 address1,
986 account1.clone(),
987 HashMap::from_iter([(U256::ZERO, U256::from(1)), (U256::from(1), U256::from(2))]),
988 );
989
990 state.commit(HashMap::from_iter([(
992 address1,
993 RevmAccount {
994 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
995 info: account1.clone(),
996 storage: HashMap::default(),
997 },
998 )]));
999
1000 state.commit(HashMap::from_iter([(
1001 address1,
1002 RevmAccount {
1003 status: AccountStatus::Touched | AccountStatus::Created,
1004 info: account1.clone(),
1005 storage: HashMap::default(),
1006 },
1007 )]));
1008
1009 state.commit(HashMap::from_iter([(
1010 address1,
1011 RevmAccount {
1012 status: AccountStatus::Touched,
1013 info: account1,
1014 storage: HashMap::from_iter([(
1016 U256::from(1),
1017 EvmStorageSlot { present_value: U256::from(5), ..Default::default() },
1018 )]),
1019 },
1020 )]));
1021
1022 state.merge_transitions(BundleRetention::Reverts);
1024 let outcome = ExecutionOutcome::new(state.take_bundle(), Default::default(), 1, Vec::new());
1025 provider
1026 .write_state(&outcome, OriginalValuesKnown::Yes, StorageLocation::Database)
1027 .expect("Could not write bundle state to DB");
1028
1029 let mut storage_changeset_cursor = provider
1030 .tx_ref()
1031 .cursor_dup_read::<tables::StorageChangeSets>()
1032 .expect("Could not open plain storage state cursor");
1033 let range = BlockNumberAddress::range(1..=1);
1034 let mut storage_changes = storage_changeset_cursor.walk_range(range).unwrap();
1035
1036 assert_eq!(
1037 storage_changes.next(),
1038 Some(Ok((
1039 BlockNumberAddress((1, address1)),
1040 StorageEntry { key: B256::with_last_byte(0), value: U256::from(1) }
1041 )))
1042 );
1043 assert_eq!(
1044 storage_changes.next(),
1045 Some(Ok((
1046 BlockNumberAddress((1, address1)),
1047 StorageEntry { key: B256::with_last_byte(1), value: U256::from(2) }
1048 )))
1049 );
1050 assert_eq!(storage_changes.next(), None);
1051 }
1052
1053 #[test]
1054 fn revert_to_indices() {
1055 let base: ExecutionOutcome = ExecutionOutcome {
1056 bundle: BundleState::default(),
1057 receipts: vec![vec![Receipt::default(); 2]; 7],
1058 first_block: 10,
1059 requests: Vec::new(),
1060 };
1061
1062 let mut this = base.clone();
1063 assert!(this.revert_to(10));
1064 assert_eq!(this.receipts.len(), 1);
1065
1066 let mut this = base.clone();
1067 assert!(!this.revert_to(9));
1068 assert_eq!(this.receipts.len(), 7);
1069
1070 let mut this = base.clone();
1071 assert!(this.revert_to(15));
1072 assert_eq!(this.receipts.len(), 6);
1073
1074 let mut this = base.clone();
1075 assert!(this.revert_to(16));
1076 assert_eq!(this.receipts.len(), 7);
1077
1078 let mut this = base;
1079 assert!(!this.revert_to(17));
1080 assert_eq!(this.receipts.len(), 7);
1081 }
1082
1083 #[test]
1084 fn bundle_state_state_root() {
1085 type PreState = BTreeMap<Address, (Account, BTreeMap<B256, U256>)>;
1086 let mut prestate: PreState = (0..10)
1087 .map(|key| {
1088 let account = Account { nonce: 1, balance: U256::from(key), bytecode_hash: None };
1089 let storage =
1090 (1..11).map(|key| (B256::with_last_byte(key), U256::from(key))).collect();
1091 (Address::with_last_byte(key), (account, storage))
1092 })
1093 .collect();
1094
1095 let provider_factory = create_test_provider_factory();
1096 let provider_rw = provider_factory.database_provider_rw().unwrap();
1097
1098 let tx = provider_rw.tx_ref();
1100 for (address, (account, storage)) in &prestate {
1101 let hashed_address = keccak256(address);
1102 tx.put::<tables::HashedAccounts>(hashed_address, *account).unwrap();
1103 for (slot, value) in storage {
1104 tx.put::<tables::HashedStorages>(
1105 hashed_address,
1106 StorageEntry { key: keccak256(slot), value: *value },
1107 )
1108 .unwrap();
1109 }
1110 }
1111
1112 let (_, updates) = StateRoot::from_tx(tx).root_with_updates().unwrap();
1113 provider_rw.write_trie_updates(&updates).unwrap();
1114
1115 let mut state = State::builder().with_bundle_update().build();
1116
1117 let assert_state_root = |state: &State<EmptyDB>, expected: &PreState, msg| {
1118 assert_eq!(
1119 StateRoot::overlay_root(
1120 tx,
1121 provider_factory.hashed_post_state(&state.bundle_state)
1122 )
1123 .unwrap(),
1124 state_root(expected.clone().into_iter().map(|(address, (account, storage))| (
1125 address,
1126 (account, storage.into_iter())
1127 ))),
1128 "{msg}"
1129 );
1130 };
1131
1132 assert_state_root(&state, &prestate, "empty");
1134
1135 let address1 = Address::with_last_byte(1);
1137 let account1_old = prestate.remove(&address1).unwrap();
1138 state.insert_account(address1, account1_old.0.into());
1139 state.commit(HashMap::from_iter([(
1140 address1,
1141 RevmAccount {
1142 status: AccountStatus::Touched | AccountStatus::SelfDestructed,
1143 info: RevmAccountInfo::default(),
1144 storage: HashMap::default(),
1145 },
1146 )]));
1147 state.merge_transitions(BundleRetention::PlainState);
1148 assert_state_root(&state, &prestate, "destroyed account");
1149
1150 let address2 = Address::with_last_byte(2);
1152 let slot2 = U256::from(2);
1153 let slot2_key = B256::from(slot2);
1154 let account2 = prestate.get_mut(&address2).unwrap();
1155 let account2_slot2_old_value = *account2.1.get(&slot2_key).unwrap();
1156 state.insert_account_with_storage(
1157 address2,
1158 account2.0.into(),
1159 HashMap::from_iter([(slot2, account2_slot2_old_value)]),
1160 );
1161
1162 let account2_slot2_new_value = U256::from(100);
1163 account2.1.insert(slot2_key, account2_slot2_new_value);
1164 state.commit(HashMap::from_iter([(
1165 address2,
1166 RevmAccount {
1167 status: AccountStatus::Touched,
1168 info: account2.0.into(),
1169 storage: HashMap::from_iter([(
1170 slot2,
1171 EvmStorageSlot::new_changed(account2_slot2_old_value, account2_slot2_new_value),
1172 )]),
1173 },
1174 )]));
1175 state.merge_transitions(BundleRetention::PlainState);
1176 assert_state_root(&state, &prestate, "changed storage");
1177
1178 let address3 = Address::with_last_byte(3);
1180 let account3 = prestate.get_mut(&address3).unwrap();
1181 state.insert_account(address3, account3.0.into());
1182
1183 account3.0.balance = U256::from(24);
1184 state.commit(HashMap::from_iter([(
1185 address3,
1186 RevmAccount {
1187 status: AccountStatus::Touched,
1188 info: account3.0.into(),
1189 storage: HashMap::default(),
1190 },
1191 )]));
1192 state.merge_transitions(BundleRetention::PlainState);
1193 assert_state_root(&state, &prestate, "changed balance");
1194
1195 let address4 = Address::with_last_byte(4);
1197 let account4 = prestate.get_mut(&address4).unwrap();
1198 state.insert_account(address4, account4.0.into());
1199
1200 account4.0.nonce = 128;
1201 state.commit(HashMap::from_iter([(
1202 address4,
1203 RevmAccount {
1204 status: AccountStatus::Touched,
1205 info: account4.0.into(),
1206 storage: HashMap::default(),
1207 },
1208 )]));
1209 state.merge_transitions(BundleRetention::PlainState);
1210 assert_state_root(&state, &prestate, "changed nonce");
1211
1212 let account1_new =
1214 Account { nonce: 56, balance: U256::from(123), bytecode_hash: Some(B256::random()) };
1215 prestate.insert(address1, (account1_new, BTreeMap::default()));
1216 state.commit(HashMap::from_iter([(
1217 address1,
1218 RevmAccount {
1219 status: AccountStatus::Touched | AccountStatus::Created,
1220 info: account1_new.into(),
1221 storage: HashMap::default(),
1222 },
1223 )]));
1224 state.merge_transitions(BundleRetention::PlainState);
1225 assert_state_root(&state, &prestate, "recreated");
1226
1227 let slot20 = U256::from(20);
1229 let slot20_key = B256::from(slot20);
1230 let account1_slot20_value = U256::from(12345);
1231 prestate.get_mut(&address1).unwrap().1.insert(slot20_key, account1_slot20_value);
1232 state.commit(HashMap::from_iter([(
1233 address1,
1234 RevmAccount {
1235 status: AccountStatus::Touched | AccountStatus::Created,
1236 info: account1_new.into(),
1237 storage: HashMap::from_iter([(
1238 slot20,
1239 EvmStorageSlot::new_changed(U256::ZERO, account1_slot20_value),
1240 )]),
1241 },
1242 )]));
1243 state.merge_transitions(BundleRetention::PlainState);
1244 assert_state_root(&state, &prestate, "recreated changed storage");
1245 }
1246
1247 #[test]
1248 fn prepend_state() {
1249 let address1 = Address::random();
1250 let address2 = Address::random();
1251
1252 let account1 = RevmAccountInfo { nonce: 1, ..Default::default() };
1253 let account1_changed = RevmAccountInfo { nonce: 1, ..Default::default() };
1254 let account2 = RevmAccountInfo { nonce: 1, ..Default::default() };
1255
1256 let present_state = BundleState::builder(2..=2)
1257 .state_present_account_info(address1, account1_changed.clone())
1258 .build();
1259 assert_eq!(present_state.reverts.len(), 1);
1260 let previous_state = BundleState::builder(1..=1)
1261 .state_present_account_info(address1, account1)
1262 .state_present_account_info(address2, account2.clone())
1263 .build();
1264 assert_eq!(previous_state.reverts.len(), 1);
1265
1266 let mut test: ExecutionOutcome = ExecutionOutcome {
1267 bundle: present_state,
1268 receipts: vec![vec![Receipt::default(); 2]; 1],
1269 first_block: 2,
1270 requests: Vec::new(),
1271 };
1272
1273 test.prepend_state(previous_state);
1274
1275 assert_eq!(test.receipts.len(), 1);
1276 let end_state = test.state();
1277 assert_eq!(end_state.state.len(), 2);
1278 assert_eq!(end_state.reverts.len(), 1);
1280 assert_eq!(end_state.state.get(&address1).unwrap().info, Some(account1_changed));
1282 assert_eq!(end_state.state.get(&address2).unwrap().info, Some(account2));
1284 }
1285
1286 #[test]
1287 fn hashed_state_storage_root() {
1288 let address = Address::random();
1289 let hashed_address = keccak256(address);
1290 let provider_factory = create_test_provider_factory();
1291 let provider_rw = provider_factory.provider_rw().unwrap();
1292 let tx = provider_rw.tx_ref();
1293
1294 let init_storage = HashedStorage::from_iter(
1296 false,
1297 [
1298 "50000000000000000000000000000004253371b55351a08cb3267d4d265530b6",
1299 "512428ed685fff57294d1a9cbb147b18ae5db9cf6ae4b312fa1946ba0561882e",
1300 "51e6784c736ef8548f856909870b38e49ef7a4e3e77e5e945e0d5e6fcaa3037f",
1301 ]
1302 .into_iter()
1303 .map(|str| (B256::from_str(str).unwrap(), U256::from(1))),
1304 );
1305 let mut state = HashedPostState::default();
1306 state.storages.insert(hashed_address, init_storage.clone());
1307 provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1308
1309 let (storage_root, _, storage_updates) =
1311 StorageRoot::from_tx_hashed(tx, hashed_address).calculate(true).unwrap();
1312 assert_eq!(storage_root, storage_root_prehashed(init_storage.storage));
1313 assert!(!storage_updates.is_empty());
1314 provider_rw
1315 .write_individual_storage_trie_updates(hashed_address, &storage_updates)
1316 .unwrap();
1317
1318 let updated_storage = HashedStorage::from_iter(
1320 true,
1321 [
1322 "00deb8486ad8edccfdedfc07109b3667b38a03a8009271aac250cce062d90917",
1323 "88d233b7380bb1bcdc866f6871c94685848f54cf0ee033b1480310b4ddb75fc9",
1324 ]
1325 .into_iter()
1326 .map(|str| (B256::from_str(str).unwrap(), U256::from(1))),
1327 );
1328 let mut state = HashedPostState::default();
1329 state.storages.insert(hashed_address, updated_storage.clone());
1330 provider_rw.write_hashed_state(&state.clone().into_sorted()).unwrap();
1331
1332 let storage_root = StorageRoot::overlay_root(tx, address, updated_storage.clone()).unwrap();
1334 assert_eq!(storage_root, storage_root_prehashed(updated_storage.storage));
1335 }
1336}