revm_handler/
api.rs

1use crate::{
2    instructions::InstructionProvider, EthFrame, Handler, MainnetHandler, PrecompileProvider,
3};
4use context::{
5    result::{
6        EVMError, ExecutionResult, HaltReason, InvalidTransaction, ResultAndState,
7        ResultVecAndState,
8    },
9    Block, ContextSetters, ContextTr, Database, Evm, JournalTr, Transaction,
10};
11use database_interface::DatabaseCommit;
12use interpreter::{interpreter::EthInterpreter, InterpreterResult};
13use state::EvmState;
14use std::vec::Vec;
15
16/// Execute EVM transactions. Main trait for transaction execution.
17pub trait ExecuteEvm {
18    /// Output of transaction execution.
19    type ExecutionResult;
20    // Output state
21    type State;
22    /// Error type
23    type Error;
24    /// Transaction type.
25    type Tx: Transaction;
26    /// Block type.
27    type Block: Block;
28
29    /// Set the block.
30    fn set_block(&mut self, block: Self::Block);
31
32    /// Execute transaction and store state inside journal. Returns output of transaction execution.
33    ///
34    /// # Return Value
35    /// Returns only the execution result
36    ///
37    /// # Error Handling
38    /// If the transaction fails, the journal will revert all changes of given transaction.
39    /// For quicker error handling, use [`ExecuteEvm::transact_finalize`] that will drop the journal.
40    ///
41    /// # State Management
42    /// State changes are stored in the internal journal.
43    /// To retrieve the state, call [`ExecuteEvm::finalize`] after transaction execution.
44    ///
45    /// # History Note
46    /// Previously this function returned both output and state.
47    /// Now it follows a two-step process: execute then finalize.
48    fn transact(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error>;
49
50    /// Finalize execution, clearing the journal and returning the accumulated state changes.
51    ///
52    /// # State Management
53    /// Journal is cleared and can be used for next transaction.
54    fn finalize(&mut self) -> Self::State;
55
56    /// Transact the given transaction and finalize in a single operation.
57    ///
58    /// Internally calls [`ExecuteEvm::transact`] followed by [`ExecuteEvm::finalize`].
59    ///
60    /// # Outcome of Error
61    ///
62    /// If the transaction fails, the journal is considered broken.
63    fn transact_finalize(
64        &mut self,
65        tx: Self::Tx,
66    ) -> Result<ResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
67        let output_or_error = self.transact(tx);
68        // finalize will clear the journal
69        let state = self.finalize();
70        let output = output_or_error?;
71        Ok(ResultAndState::new(output, state))
72    }
73
74    /// Execute multiple transactions without finalizing the state.
75    ///
76    /// Returns a vector of execution results. State changes are accumulated in the journal
77    /// but not finalized. Call [`ExecuteEvm::finalize`] after execution to retrieve state changes.
78    ///
79    /// # Outcome of Error
80    ///
81    /// If any transaction fails, the journal is finalized and the last error is returned.
82    ///
83    /// TODO add tx index to the error.
84    fn transact_multi(
85        &mut self,
86        txs: impl Iterator<Item = Self::Tx>,
87    ) -> Result<Vec<Self::ExecutionResult>, Self::Error> {
88        let mut outputs = Vec::new();
89        for tx in txs {
90            outputs.push(self.transact(tx).inspect_err(|_| {
91                let _ = self.finalize();
92            })?);
93        }
94        Ok(outputs)
95    }
96
97    /// Execute multiple transactions and finalize the state in a single operation.
98    ///
99    /// Internally calls [`ExecuteEvm::transact_multi`] followed by [`ExecuteEvm::finalize`].
100    //#[allow(clippy::type_complexity)]
101    fn transact_multi_finalize(
102        &mut self,
103        txs: impl Iterator<Item = Self::Tx>,
104    ) -> Result<ResultVecAndState<Self::ExecutionResult, Self::State>, Self::Error> {
105        // on error transact_multi will clear the journal
106        let result = self.transact_multi(txs)?;
107        let state = self.finalize();
108        Ok(ResultAndState::new(result, state))
109    }
110
111    /// Execute previous transaction and finalize it.
112    ///
113    /// Doint it without finalization
114    fn replay(&mut self)
115        -> Result<ResultAndState<Self::ExecutionResult, Self::State>, Self::Error>;
116}
117
118/// Extension of the [`ExecuteEvm`] trait that adds a method that commits the state after execution.
119pub trait ExecuteCommitEvm: ExecuteEvm {
120    /// Commit the state.
121    fn commit(&mut self, state: Self::State);
122
123    /// Finalize the state and commit it to the database.
124    ///
125    /// Internally calls `finalize` and `commit` functions.
126    fn commit_inner(&mut self) {
127        let state = self.finalize();
128        self.commit(state);
129    }
130
131    /// Transact the transaction and commit to the state.
132    fn transact_commit(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
133        let output = self.transact(tx)?;
134        self.commit_inner();
135        Ok(output)
136    }
137
138    /// Transact multiple transactions and commit to the state.
139    ///
140    /// Internally calls `transact_multi` and `commit` functions.
141    fn transact_multi_commit(
142        &mut self,
143        txs: impl Iterator<Item = Self::Tx>,
144    ) -> Result<Vec<Self::ExecutionResult>, Self::Error> {
145        let outputs = self.transact_multi(txs)?;
146        self.commit_inner();
147        Ok(outputs)
148    }
149
150    /// Replay the transaction and commit to the state.
151    ///
152    /// Internally calls `replay` and `commit` functions.
153    fn replay_commit(&mut self) -> Result<Self::ExecutionResult, Self::Error> {
154        let result = self.replay()?;
155        self.commit(result.state);
156        Ok(result.result)
157    }
158}
159
160impl<CTX, INSP, INST, PRECOMPILES> ExecuteEvm for Evm<CTX, INSP, INST, PRECOMPILES>
161where
162    CTX: ContextTr<Journal: JournalTr<State = EvmState>> + ContextSetters,
163    INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
164    PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
165{
166    type ExecutionResult = ExecutionResult<HaltReason>;
167    type State = EvmState;
168    type Error = EVMError<<CTX::Db as Database>::Error, InvalidTransaction>;
169    type Tx = <CTX as ContextTr>::Tx;
170    type Block = <CTX as ContextTr>::Block;
171
172    fn transact(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error> {
173        self.ctx.set_tx(tx);
174        let mut t = MainnetHandler::<_, _, EthFrame<_, _, _>>::default();
175        t.run(self)
176    }
177
178    fn finalize(&mut self) -> Self::State {
179        self.journal_mut().finalize()
180    }
181
182    fn set_block(&mut self, block: Self::Block) {
183        self.ctx.set_block(block);
184    }
185
186    fn replay(
187        &mut self,
188    ) -> Result<ResultAndState<Self::ExecutionResult, Self::State>, Self::Error> {
189        let mut t = MainnetHandler::<_, _, EthFrame<_, _, _>>::default();
190        t.run(self).map(|result| {
191            let state = self.finalize();
192            ResultAndState::new(result, state)
193        })
194    }
195}
196
197impl<CTX, INSP, INST, PRECOMPILES> ExecuteCommitEvm for Evm<CTX, INSP, INST, PRECOMPILES>
198where
199    CTX: ContextTr<Journal: JournalTr<State = EvmState>, Db: DatabaseCommit> + ContextSetters,
200    INST: InstructionProvider<Context = CTX, InterpreterTypes = EthInterpreter>,
201    PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
202{
203    fn commit(&mut self, state: Self::State) {
204        self.db_mut().commit(state);
205    }
206}