Skip to main content

revm_handler/
api.rs

1use crate::{
2    frame::EthFrame, instructions::InstructionProvider, Handler, MainnetHandler, PrecompileProvider,
3};
4use context::{
5    result::{
6        EVMError, ExecResultAndState, ExecutionResult, HaltReason, InvalidTransaction,
7        ResultAndState, ResultVecAndState, TransactionIndexedError,
8    },
9    Block, ContextSetters, ContextTr, Database, Evm, JournalTr, Transaction,
10};
11#[cfg(feature = "asyncdb")]
12use database_interface::async_db::{on_fiber_result_with_stack, AsyncResult};
13use database_interface::DatabaseCommit;
14use interpreter::{interpreter::EthInterpreter, InterpreterResult};
15use state::EvmState;
16#[cfg(feature = "asyncdb")]
17use std::ptr::NonNull;
18use std::vec::Vec;
19
20/// Type alias for the result of transact_many_finalize to reduce type complexity.
21type TransactManyFinalizeResult<ExecutionResult, State, Error> =
22    Result<ResultVecAndState<ExecutionResult, State>, TransactionIndexedError<Error>>;
23
24/// Execute EVM transactions. Main trait for transaction execution.
25pub trait ExecuteEvm {
26    /// Output of transaction execution.
27    type ExecutionResult;
28    /// Output state type representing changes after execution.
29    type State;
30    /// Error type
31    type Error;
32    /// Transaction type.
33    type Tx: Transaction;
34    /// Block type.
35    type Block: Block;
36
37    /// Set the block.
38    fn set_block(&mut self, block: Self::Block);
39
40    /// Execute transaction and store state inside journal. Returns output of transaction execution.
41    ///
42    /// # Return Value
43    /// Returns only the execution result
44    ///
45    /// # Error Handling
46    /// If the transaction fails, the journal will revert all changes of given transaction.
47    /// For quicker error handling, use [`ExecuteEvm::transact`] that will drop the journal.
48    ///
49    /// # State Management
50    /// State changes are stored in the internal journal.
51    /// To retrieve the state, call [`ExecuteEvm::finalize`] after transaction execution.
52    ///
53    /// # History Note
54    /// Previously this function returned both output and state.
55    /// Now it follows a two-step process: execute then finalize.
56    fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error>;
57
58    /// Finalize execution, clearing the journal and returning the accumulated state changes.
59    ///
60    /// # State Management
61    /// Journal is cleared and can be used for next transaction.
62    fn finalize(&mut self) -> Self::State;
63
64    /// Transact the given transaction and finalize in a single operation.
65    ///
66    /// Internally calls [`ExecuteEvm::transact_one`] followed by [`ExecuteEvm::finalize`].
67    ///
68    /// # Outcome of Error
69    ///
70    /// If the transaction fails, the journal is considered broken.
71    #[inline]
72    fn transact(
73        &mut self,
74        tx: Self::Tx,
75    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
76        let output_or_error = self.transact_one(tx);
77        // finalize will clear the journal
78        let state = self.finalize();
79        let output = output_or_error?;
80        Ok(ExecResultAndState::new(output, state))
81    }
82
83    /// Execute multiple transactions without finalizing the state.
84    ///
85    /// Returns a vector of execution results. State changes are accumulated in the journal
86    /// but not finalized. Call [`ExecuteEvm::finalize`] after execution to retrieve state changes.
87    ///
88    /// # Outcome of Error
89    ///
90    /// If any transaction fails, the journal is finalized and the error is returned with the
91    /// transaction index that failed.
92    #[inline]
93    fn transact_many(
94        &mut self,
95        txs: impl Iterator<Item = Self::Tx>,
96    ) -> Result<Vec<Self::ExecutionResult>, TransactionIndexedError<Self::Error>> {
97        let (lower, _) = txs.size_hint();
98        let mut outputs = Vec::with_capacity(lower);
99        for (index, tx) in txs.enumerate() {
100            outputs.push(
101                self.transact_one(tx)
102                    .inspect_err(|_| {
103                        let _ = self.finalize();
104                    })
105                    .map_err(|error| TransactionIndexedError::new(error, index))?,
106            );
107        }
108        Ok(outputs)
109    }
110
111    /// Execute multiple transactions and finalize the state in a single operation.
112    ///
113    /// Internally calls [`ExecuteEvm::transact_many`] followed by [`ExecuteEvm::finalize`].
114    #[inline]
115    fn transact_many_finalize(
116        &mut self,
117        txs: impl Iterator<Item = Self::Tx>,
118    ) -> TransactManyFinalizeResult<Self::ExecutionResult, Self::State, Self::Error> {
119        // on error transact_multi will clear the journal
120        let result = self.transact_many(txs)?;
121        let state = self.finalize();
122        Ok(ExecResultAndState::new(result, state))
123    }
124
125    /// Execute previous transaction and finalize it.
126    fn replay(
127        &mut self,
128    ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>;
129}
130
131/// Extension of the [`ExecuteEvm`] trait that adds a method that commits the state after execution.
132pub trait ExecuteCommitEvm: ExecuteEvm {
133    /// Commit the state.
134    fn commit(&mut self, state: Self::State);
135
136    /// Finalize the state and commit it to the database.
137    ///
138    /// Internally calls `finalize` and `commit` functions.
139    #[inline]
140    fn commit_inner(&mut self) {
141        let state = self.finalize();
142        self.commit(state);
143    }
144
145    /// Transact the transaction and commit to the state.
146    ///
147    /// # Outcome of Error
148    ///
149    /// If the transaction fails, the journal is finalized (not committed) so it
150    /// does not leak into the next transaction.
151    #[inline]
152    fn transact_commit(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
153        let output = self.transact_one(tx).inspect_err(|_| {
154            // finalize (clear) the journal on error; do not commit it.
155            let _ = self.finalize();
156        })?;
157        self.commit_inner();
158        Ok(output)
159    }
160
161    /// Transact multiple transactions and commit to the state.
162    ///
163    /// Internally calls `transact_many` and `commit_inner` functions.
164    #[inline]
165    fn transact_many_commit(
166        &mut self,
167        txs: impl Iterator<Item = Self::Tx>,
168    ) -> Result<Vec<Self::ExecutionResult>, TransactionIndexedError<Self::Error>> {
169        let outputs = self.transact_many(txs)?;
170        self.commit_inner();
171        Ok(outputs)
172    }
173
174    /// Replay the transaction and commit to the state.
175    ///
176    /// Internally calls `replay` and `commit` functions.
177    #[inline]
178    fn replay_commit(&mut self) -> Result<Self::ExecutionResult, Self::Error> {
179        let result = self.replay()?;
180        self.commit(result.state);
181        Ok(result.result)
182    }
183}
184
185/// Async extension of the [`ExecuteEvm`] trait that runs execution on an async fiber.
186#[cfg(feature = "asyncdb")]
187pub trait ExecuteEvmAsync: ExecuteEvm {
188    /// Execute transaction and store state inside journal on an async fiber.
189    fn transact_one_async(
190        &mut self,
191        tx: Self::Tx,
192    ) -> impl core::future::Future<Output = AsyncResult<Self::ExecutionResult, Self::Error>> + Send + '_;
193
194    /// Transact the given transaction and finalize in a single operation on an async fiber.
195    fn transact_async(
196        &mut self,
197        tx: Self::Tx,
198    ) -> impl core::future::Future<
199        Output = AsyncResult<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>,
200    > + Send
201           + '_;
202}
203
204impl<CTX, INSP, INST, PRECOMPILES> ExecuteEvm
205    for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
206where
207    CTX: ContextTr<Journal: JournalTr<State = EvmState>> + ContextSetters,
208    INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
209    PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
210{
211    type ExecutionResult = ExecutionResult<HaltReason>;
212    type State = EvmState;
213    type Error = EVMError<<CTX::Db as Database>::Error, InvalidTransaction>;
214    type Tx = <CTX as ContextTr>::Tx;
215    type Block = <CTX as ContextTr>::Block;
216
217    #[inline]
218    fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
219        self.ctx.set_tx(tx);
220        MainnetHandler::default().run(self)
221    }
222
223    #[inline]
224    fn finalize(&mut self) -> Self::State {
225        self.journal_mut().finalize()
226    }
227
228    #[inline]
229    fn set_block(&mut self, block: Self::Block) {
230        self.ctx.set_block(block);
231    }
232
233    #[inline]
234    fn replay(&mut self) -> Result<ResultAndState<HaltReason>, Self::Error> {
235        MainnetHandler::default()
236            .run(self)
237            // finalize (clear) the journal on error; on success the `map`
238            // branch below finalizes it.
239            .inspect_err(|_| {
240                let _ = self.finalize();
241            })
242            .map(|result| {
243                let state = self.finalize();
244                ResultAndState::new(result, state)
245            })
246    }
247}
248
249#[cfg(feature = "asyncdb")]
250impl<CTX, INSP, INST, PRECOMPILES> ExecuteEvmAsync
251    for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
252where
253    CTX: ContextTr<Journal: JournalTr<State = EvmState>> + ContextSetters,
254    INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
255    PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
256    ExecutionResult<HaltReason>: Send,
257    EvmState: Send,
258    EVMError<<CTX::Db as Database>::Error, InvalidTransaction>: Send,
259    <CTX as ContextTr>::Tx: Send,
260{
261    #[inline]
262    fn transact_one_async(
263        &mut self,
264        tx: Self::Tx,
265    ) -> impl core::future::Future<Output = AsyncResult<Self::ExecutionResult, Self::Error>> + Send + '_
266    {
267        let stack = NonNull::from(&mut self.async_stack);
268        // SAFETY: The returned future owns the exclusive `&mut self` borrow, so nothing else can
269        // access the EVM stack slot until that future is dropped.
270        unsafe { on_fiber_result_with_stack(stack, move || self.transact_one(tx)) }
271    }
272
273    #[inline]
274    fn transact_async(
275        &mut self,
276        tx: Self::Tx,
277    ) -> impl core::future::Future<
278        Output = AsyncResult<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>,
279    > + Send
280           + '_ {
281        let stack = NonNull::from(&mut self.async_stack);
282        // SAFETY: The returned future owns the exclusive `&mut self` borrow, so nothing else can
283        // access the EVM stack slot until that future is dropped.
284        unsafe { on_fiber_result_with_stack(stack, move || self.transact(tx)) }
285    }
286}
287
288impl<CTX, INSP, INST, PRECOMPILES> ExecuteCommitEvm
289    for Evm<CTX, INSP, INST, PRECOMPILES, EthFrame<EthInterpreter>>
290where
291    CTX: ContextTr<Journal: JournalTr<State = EvmState>, Db: DatabaseCommit> + ContextSetters,
292    INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
293    PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
294{
295    #[inline]
296    fn commit(&mut self, state: Self::State) {
297        self.db_mut().commit(state);
298    }
299}