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
20type TransactManyFinalizeResult<ExecutionResult, State, Error> =
22 Result<ResultVecAndState<ExecutionResult, State>, TransactionIndexedError<Error>>;
23
24pub trait ExecuteEvm {
26 type ExecutionResult;
28 type State;
30 type Error;
32 type Tx: Transaction;
34 type Block: Block;
36
37 fn set_block(&mut self, block: Self::Block);
39
40 fn transact_one(&mut self, tx: Self::Tx) -> Result<Self::ExecutionResult, Self::Error>;
57
58 fn finalize(&mut self) -> Self::State;
63
64 #[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 let state = self.finalize();
79 let output = output_or_error?;
80 Ok(ExecResultAndState::new(output, state))
81 }
82
83 #[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 #[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 let result = self.transact_many(txs)?;
121 let state = self.finalize();
122 Ok(ExecResultAndState::new(result, state))
123 }
124
125 fn replay(
127 &mut self,
128 ) -> Result<ExecResultAndState<Self::ExecutionResult, Self::State>, Self::Error>;
129}
130
131pub trait ExecuteCommitEvm: ExecuteEvm {
133 fn commit(&mut self, state: Self::State);
135
136 #[inline]
140 fn commit_inner(&mut self) {
141 let state = self.finalize();
142 self.commit(state);
143 }
144
145 #[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 let _ = self.finalize();
156 })?;
157 self.commit_inner();
158 Ok(output)
159 }
160
161 #[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 #[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#[cfg(feature = "asyncdb")]
187pub trait ExecuteEvmAsync: ExecuteEvm {
188 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 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 .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 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 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}