Skip to main content

revm_inspector/
inspect.rs

1use context::result::ExecResultAndState;
2use handler::{system_call::SYSTEM_ADDRESS, ExecuteCommitEvm, ExecuteEvm, SystemCallEvm};
3use primitives::{Address, Bytes};
4
5/// InspectEvm is a API that allows inspecting the EVM.
6///
7/// It extends the `ExecuteEvm` trait and enabled setting inspector
8///
9pub trait InspectEvm: ExecuteEvm {
10    /// The inspector type used for inspecting EVM execution.
11    type Inspector;
12
13    /// Set the inspector for the EVM.
14    ///
15    /// this function is used to change inspector during execution.
16    /// This function can't change Inspector type, changing inspector type can be done in
17    /// `Evm` with `with_inspector` function.
18    fn set_inspector(&mut self, inspector: Self::Inspector);
19
20    /// Inspect the EVM with the given transaction.
21    fn inspect_one_tx(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error>;
22
23    /// Inspect the EVM and finalize the state.
24    ///
25    /// # Outcome of Error
26    ///
27    /// If the transaction fails, the journal is finalized (cleared) so that the
28    /// next transaction starts from a clean state. This mirrors [`ExecuteEvm::transact`].
29    fn inspect_tx(
30        &mut self,
31        tx: Self::Tx,
32    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
33        // finalize the journal unconditionally, even on error, so the
34        // EIP-2929 warm set and state do not leak into the next transaction.
35        let output_or_error = self.inspect_one_tx(tx);
36        let state = self.finalize();
37        let output = output_or_error?;
38        Ok(ExecResultAndState::new(output, state))
39    }
40
41    /// Inspect the EVM with the given inspector and transaction, and finalize the state.
42    ///
43    /// # Outcome of Error
44    ///
45    /// Same as [`InspectEvm::inspect_tx`]: the journal is finalized on error.
46    fn inspect(
47        &mut self,
48        tx: Self::Tx,
49        inspector: Self::Inspector,
50    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
51        let output_or_error = self.inspect_one(tx, inspector);
52        let state = self.finalize();
53        let output = output_or_error?;
54        Ok(ExecResultAndState::new(output, state))
55    }
56
57    /// Inspect the EVM with the given inspector and transaction.
58    fn inspect_one(
59        &mut self,
60        tx: Self::Tx,
61        inspector: Self::Inspector,
62    ) -> Result<Self::ExecutionResult, Self::Error> {
63        self.set_inspector(inspector);
64        self.inspect_one_tx(tx)
65    }
66}
67
68/// InspectCommitEvm is a API that allows inspecting similar to `InspectEvm` but it has
69/// functions that commit the state diff to the database.
70///
71/// Functions return CommitOutput from [`ExecuteCommitEvm`] trait.
72pub trait InspectCommitEvm: InspectEvm + ExecuteCommitEvm {
73    /// Inspect the EVM with the current inspector and previous transaction by replaying, similar to [`InspectEvm::inspect_tx`]
74    /// and commit the state diff to the database.
75    ///
76    /// # Outcome of Error
77    ///
78    /// If the transaction fails, the journal is finalized (not committed) so it
79    /// does not leak into the next transaction.
80    fn inspect_tx_commit(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
81        let output = self.inspect_one_tx(tx).inspect_err(|_| {
82            // finalize (clear) the journal on error; do not commit it.
83            let _ = self.finalize();
84        })?;
85        self.commit_inner();
86        Ok(output)
87    }
88
89    /// Inspect the EVM with the given transaction and inspector similar to [`InspectEvm::inspect`]
90    /// and commit the state diff to the database.
91    ///
92    /// # Outcome of Error
93    ///
94    /// Same as [`InspectCommitEvm::inspect_tx_commit`]: the journal is finalized on error.
95    fn inspect_commit(
96        &mut self,
97        tx: Self::Tx,
98        inspector: Self::Inspector,
99    ) -> Result<Self::ExecutionResult, Self::Error> {
100        let output = self.inspect_one(tx, inspector).inspect_err(|_| {
101            let _ = self.finalize();
102        })?;
103        self.commit_inner();
104        Ok(output)
105    }
106}
107
108/// InspectSystemCallEvm is an API that allows inspecting system calls in the EVM.
109///
110/// It extends [`InspectEvm`] and [`SystemCallEvm`] traits to provide inspection
111/// capabilities for system transactions, enabling tracing and debugging of
112/// system calls similar to regular transactions.
113pub trait InspectSystemCallEvm: InspectEvm + SystemCallEvm {
114    /// Inspect a system call with the current inspector.
115    ///
116    /// Similar to [`InspectEvm::inspect_one_tx`] but for system calls.
117    /// Uses [`SYSTEM_ADDRESS`] as the caller.
118    fn inspect_one_system_call(
119        &mut self,
120        system_contract_address: Address,
121        data: Bytes,
122    ) -> Result<Self::ExecutionResult, Self::Error> {
123        self.inspect_one_system_call_with_caller(SYSTEM_ADDRESS, system_contract_address, data)
124    }
125
126    /// Inspect a system call with the current inspector and a custom caller.
127    ///
128    /// Similar to [`InspectEvm::inspect_one_tx`] but for system calls with a custom caller.
129    fn inspect_one_system_call_with_caller(
130        &mut self,
131        caller: Address,
132        system_contract_address: Address,
133        data: Bytes,
134    ) -> Result<Self::ExecutionResult, Self::Error>;
135
136    /// Inspect a system call and finalize the state.
137    ///
138    /// Similar to [`InspectEvm::inspect_tx`] but for system calls.
139    ///
140    /// # Outcome of Error
141    ///
142    /// Same as [`InspectEvm::inspect_tx`]: the journal is finalized on error.
143    fn inspect_system_call(
144        &mut self,
145        system_contract_address: Address,
146        data: Bytes,
147    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
148        let output_or_error = self.inspect_one_system_call(system_contract_address, data);
149        let state = self.finalize();
150        let output = output_or_error?;
151        Ok(ExecResultAndState::new(output, state))
152    }
153
154    /// Inspect a system call with a custom caller and finalize the state.
155    ///
156    /// Similar to [`InspectEvm::inspect_tx`] but for system calls with a custom caller.
157    ///
158    /// # Outcome of Error
159    ///
160    /// Same as [`InspectEvm::inspect_tx`]: the journal is finalized on error.
161    fn inspect_system_call_with_caller(
162        &mut self,
163        caller: Address,
164        system_contract_address: Address,
165        data: Bytes,
166    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
167        let output_or_error =
168            self.inspect_one_system_call_with_caller(caller, system_contract_address, data);
169        let state = self.finalize();
170        let output = output_or_error?;
171        Ok(ExecResultAndState::new(output, state))
172    }
173
174    /// Inspect a system call with a given inspector.
175    ///
176    /// Similar to [`InspectEvm::inspect_one`] but for system calls.
177    fn inspect_one_system_call_with_inspector(
178        &mut self,
179        system_contract_address: Address,
180        data: Bytes,
181        inspector: Self::Inspector,
182    ) -> Result<Self::ExecutionResult, Self::Error> {
183        self.set_inspector(inspector);
184        self.inspect_one_system_call(system_contract_address, data)
185    }
186
187    /// Inspect a system call with a given inspector and finalize the state.
188    ///
189    /// Similar to [`InspectEvm::inspect`] but for system calls.
190    ///
191    /// # Outcome of Error
192    ///
193    /// Same as [`InspectEvm::inspect_tx`]: the journal is finalized on error.
194    fn inspect_system_call_with_inspector(
195        &mut self,
196        system_contract_address: Address,
197        data: Bytes,
198        inspector: Self::Inspector,
199    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
200        let output_or_error =
201            self.inspect_one_system_call_with_inspector(system_contract_address, data, inspector);
202        let state = self.finalize();
203        let output = output_or_error?;
204        Ok(ExecResultAndState::new(output, state))
205    }
206
207    /// Inspect a system call with a given inspector and caller.
208    ///
209    /// Similar to [`InspectEvm::inspect_one`] but for system calls.
210    fn inspect_one_system_call_with_inspector_and_caller(
211        &mut self,
212        caller: Address,
213        system_contract_address: Address,
214        data: Bytes,
215        inspector: Self::Inspector,
216    ) -> Result<Self::ExecutionResult, Self::Error> {
217        self.set_inspector(inspector);
218        self.inspect_one_system_call_with_caller(caller, system_contract_address, data)
219    }
220
221    /// Inspect a system call with a given inspector and finalize the state.
222    ///
223    /// Similar to [`InspectEvm::inspect`] but for system calls.
224    ///
225    /// # Outcome of Error
226    ///
227    /// Same as [`InspectEvm::inspect_tx`]: the journal is finalized on error.
228    fn inspect_system_call_with_inspector_and_caller(
229        &mut self,
230        caller: Address,
231        system_contract_address: Address,
232        data: Bytes,
233        inspector: Self::Inspector,
234    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
235        let output_or_error = self.inspect_one_system_call_with_inspector_and_caller(
236            caller,
237            system_contract_address,
238            data,
239            inspector,
240        );
241        let state = self.finalize();
242        let output = output_or_error?;
243        Ok(ExecResultAndState::new(output, state))
244    }
245}