revm_trace/evm/reset.rs
1use crate::{
2 errors::EvmError,
3 traits::{ResetBlock, ResetDB},
4 types::AllDBType,
5 TraceEvm,
6};
7use alloy::eips::{BlockId, BlockNumberOrTag};
8use revm::{
9 context::BlockEnv,
10 context_interface::ContextTr,
11 database::{CacheDB, DatabaseRef},
12 ExecuteEvm,
13};
14// ========================= Database Management =========================
15
16/// Implementation for TraceEvm instances with CacheDB
17///
18/// Provides database cache management utilities specifically for EVM instances
19/// that use `CacheDB` as their database layer.
20impl<DB, INSP> ResetDB for TraceEvm<CacheDB<DB>, INSP>
21where
22 DB: DatabaseRef,
23{
24 /// Reset the database cache to clear all cached state
25 ///
26 /// This method clears all cached data from the `CacheDB` layer, including:
27 /// - Account states and balances
28 /// - Contract bytecode and storage
29 /// - Event logs
30 /// - Block hashes
31 ///
32 /// # Use Cases
33 /// - Resetting state between independent transaction simulations
34 /// - Clearing cache when switching to a different block context
35 /// - Memory management in long-running applications
36 /// - Testing scenarios requiring clean state
37 ///
38 /// # Performance Impact
39 /// After calling this method, subsequent database queries will need to
40 /// fetch data from the underlying database layer, which may be slower
41 /// until the cache is repopulated.
42 ///
43 /// # Example
44 /// ```no_run
45 /// # async fn example() -> Result<(), Box<dyn std::error::Error>> {
46 /// use revm_trace::{create_evm, traits::ResetDB};
47 ///
48 /// let mut evm = create_evm("https://eth.llamarpc.com").await?;
49 ///
50 /// // Clear cache before processing a new batch of transactions
51 /// evm.reset_db();
52 /// # Ok(())
53 /// # }
54 /// ```
55 fn reset_db(&mut self) {
56 let cached_db = &mut self.0.ctx.db().cache;
57 cached_db.accounts.clear();
58 cached_db.contracts.clear();
59 cached_db.logs = Vec::new();
60 cached_db.block_hashes.clear();
61 }
62}
63
64impl ResetBlock for AllDBType {
65 type Error = EvmError;
66 fn reset_block(&mut self, block_number: u64) -> Result<(), EvmError> {
67 // Reset the block number in the EVM context
68 let db = self.get_db_mut();
69 db.set_block_number(BlockId::Number(BlockNumberOrTag::Number(block_number)));
70 Ok(())
71 }
72}
73
74// Generic set_db_block implementation for any database type implementing ResetBlock
75impl<DB, INSP> TraceEvm<CacheDB<DB>, INSP>
76where
77 DB: DatabaseRef + ResetBlock,
78 <DB as ResetBlock>::Error: Into<EvmError>,
79{
80 /// Reset the underlying database to a specific block, clear cache, and update EVM context
81 ///
82 /// Steps:
83 /// 1. Reset the underlying database's block state
84 /// 2. Clear the outer CacheDB cache
85 /// 3. Update the EVM's block context
86 pub fn set_db_block(&mut self, block_env: BlockEnv) -> Result<(), EvmError> {
87 // Step 1: Reset the underlying database's block state
88 {
89 let cache_db = &mut self.0.ctx.db().db;
90 cache_db.reset_block(block_env.number).map_err(Into::into)?;
91 }
92 // Step 2: Clear the outer CacheDB cache
93 self.reset_db();
94
95 // Step 3: Update the EVM's block context
96 self.set_block(block_env);
97
98 Ok(())
99 }
100}
101
102#[cfg(feature = "foundry-fork")]
103use foundry_fork_db::backend::SharedBackend;
104
105#[cfg(feature = "foundry-fork")]
106use crate::errors::InitError;
107
108#[cfg(feature = "foundry-fork")]
109impl ResetBlock for SharedBackend {
110 type Error = EvmError;
111 fn reset_block(&mut self, block_number: u64) -> Result<(), EvmError> {
112 // Reset the block number in the EVM context
113 self.set_pinned_block(BlockId::Number(BlockNumberOrTag::Number(block_number)))
114 .map_err(|e| EvmError::Init(InitError::DatabaseError(e.to_string())))?;
115 // Clear the cache
116 let data = self.data();
117 data.clear();
118 Ok(())
119 }
120}