1use crate::{
2 builder::{EvmBuilder, HandlerStage, SetGenericStage},
3 db::{Database, DatabaseCommit, EmptyDB},
4 handler::Handler,
5 interpreter::{
6 CallInputs, CreateInputs, EOFCreateInputs, Host, InterpreterAction, SharedMemory,
7 },
8 primitives::{
9 specification::SpecId, BlockEnv, CfgEnv, EVMError, EVMResult, EnvWithHandlerCfg,
10 ExecutionResult, HandlerCfg, ResultAndState, TxEnv, TxKind, EOF_MAGIC_BYTES,
11 },
12 Context, ContextWithHandlerCfg, Frame, FrameOrResult, FrameResult,
13};
14use core::fmt;
15use std::{boxed::Box, vec::Vec};
16
17pub const CALL_STACK_LIMIT: u64 = 1024;
19
20pub struct Evm<'a, EXT, DB: Database> {
23 pub context: Context<EXT, DB>,
25 pub handler: Handler<'a, Context<EXT, DB>, EXT, DB>,
28}
29
30impl<EXT, DB> fmt::Debug for Evm<'_, EXT, DB>
31where
32 EXT: fmt::Debug,
33 DB: Database + fmt::Debug,
34 DB::Error: fmt::Debug,
35{
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 f.debug_struct("Evm")
38 .field("evm context", &self.context.evm)
39 .finish_non_exhaustive()
40 }
41}
42
43impl<EXT, DB: Database + DatabaseCommit> Evm<'_, EXT, DB> {
44 pub fn transact_commit(&mut self) -> Result<ExecutionResult, EVMError<DB::Error>> {
46 let ResultAndState { result, state } = self.transact()?;
47 self.context.evm.db.commit(state);
48 Ok(result)
49 }
50}
51
52impl<'a> Evm<'a, (), EmptyDB> {
53 pub fn builder() -> EvmBuilder<'a, SetGenericStage, (), EmptyDB> {
55 EvmBuilder::default()
56 }
57}
58
59impl<'a, EXT, DB: Database> Evm<'a, EXT, DB> {
60 pub fn new(
62 mut context: Context<EXT, DB>,
63 handler: Handler<'a, Context<EXT, DB>, EXT, DB>,
64 ) -> Evm<'a, EXT, DB> {
65 context.evm.journaled_state.set_spec_id(handler.cfg.spec_id);
66 Evm { context, handler }
67 }
68
69 pub fn modify(self) -> EvmBuilder<'a, HandlerStage, EXT, DB> {
72 EvmBuilder::new(self)
73 }
74
75 #[inline]
77 pub fn run_the_loop(&mut self, first_frame: Frame) -> Result<FrameResult, EVMError<DB::Error>> {
78 let mut call_stack: Vec<Frame> = Vec::with_capacity(1025);
79 call_stack.push(first_frame);
80
81 #[cfg(feature = "memory_limit")]
82 let mut shared_memory =
83 SharedMemory::new_with_memory_limit(self.context.evm.env.cfg.memory_limit);
84 #[cfg(not(feature = "memory_limit"))]
85 let mut shared_memory = SharedMemory::new();
86
87 shared_memory.new_context();
88
89 let mut stack_frame = call_stack.last_mut().unwrap();
91
92 loop {
93 let next_action =
95 self.handler
96 .execute_frame(stack_frame, &mut shared_memory, &mut self.context)?;
97
98 self.context.evm.take_error()?;
101
102 let exec = &mut self.handler.execution;
103 let frame_or_result = match next_action {
104 InterpreterAction::Call { inputs } => exec.call(&mut self.context, inputs)?,
105 InterpreterAction::Create { inputs } => exec.create(&mut self.context, inputs)?,
106 InterpreterAction::EOFCreate { inputs } => {
107 exec.eofcreate(&mut self.context, inputs)?
108 }
109 InterpreterAction::Return { result } => {
110 shared_memory.free_context();
112
113 let returned_frame = call_stack
115 .pop()
116 .expect("We just returned from Interpreter frame");
117
118 let ctx = &mut self.context;
119 FrameOrResult::Result(match returned_frame {
120 Frame::Call(frame) => {
121 FrameResult::Call(exec.call_return(ctx, frame, result)?)
123 }
124 Frame::Create(frame) => {
125 FrameResult::Create(exec.create_return(ctx, frame, result)?)
127 }
128 Frame::EOFCreate(frame) => {
129 FrameResult::EOFCreate(exec.eofcreate_return(ctx, frame, result)?)
131 }
132 })
133 }
134 InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"),
135 };
136 match frame_or_result {
138 FrameOrResult::Frame(frame) => {
139 shared_memory.new_context();
140 call_stack.push(frame);
141 stack_frame = call_stack.last_mut().unwrap();
142 }
143 FrameOrResult::Result(result) => {
144 let Some(top_frame) = call_stack.last_mut() else {
145 return Ok(result);
147 };
148 stack_frame = top_frame;
149 let ctx = &mut self.context;
150 match result {
152 FrameResult::Call(outcome) => {
153 exec.insert_call_outcome(ctx, stack_frame, &mut shared_memory, outcome)?
155 }
156 FrameResult::Create(outcome) => {
157 exec.insert_create_outcome(ctx, stack_frame, outcome)?
159 }
160 FrameResult::EOFCreate(outcome) => {
161 exec.insert_eofcreate_outcome(ctx, stack_frame, outcome)?
163 }
164 }
165 }
166 }
167 }
168 }
169}
170
171impl<EXT, DB: Database> Evm<'_, EXT, DB> {
172 pub fn spec_id(&self) -> SpecId {
176 self.handler.cfg.spec_id
177 }
178
179 #[inline]
182 pub fn preverify_transaction(&mut self) -> Result<(), EVMError<DB::Error>> {
183 let output = self.preverify_transaction_inner().map(|_| ());
184 self.clear();
185 output
186 }
187
188 fn clear(&mut self) {
190 self.handler.post_execution().clear(&mut self.context);
191 }
192
193 #[inline]
197 pub fn transact_preverified(&mut self) -> EVMResult<DB::Error> {
198 let initial_gas_spend = self
199 .handler
200 .validation()
201 .initial_tx_gas(&self.context.evm.env)
202 .inspect_err(|_e| self.clear())?;
203 let output = self.transact_preverified_inner(initial_gas_spend);
204 let output = self.handler.post_execution().end(&mut self.context, output);
205 self.clear();
206 output
207 }
208
209 #[inline]
211 fn preverify_transaction_inner(&mut self) -> Result<u64, EVMError<DB::Error>> {
212 self.handler.validation().env(&self.context.evm.env)?;
213 let initial_gas_spend = self
214 .handler
215 .validation()
216 .initial_tx_gas(&self.context.evm.env)?;
217 self.handler
218 .validation()
219 .tx_against_state(&mut self.context)?;
220 Ok(initial_gas_spend)
221 }
222
223 #[inline]
227 pub fn transact(&mut self) -> EVMResult<DB::Error> {
228 let initial_gas_spend = self
229 .preverify_transaction_inner()
230 .inspect_err(|_e| self.clear())?;
231
232 let output = self.transact_preverified_inner(initial_gas_spend);
233 let output = self.handler.post_execution().end(&mut self.context, output);
234 self.clear();
235 output
236 }
237
238 #[inline]
240 pub fn handler_cfg(&self) -> &HandlerCfg {
241 &self.handler.cfg
242 }
243
244 #[inline]
246 pub fn cfg(&self) -> &CfgEnv {
247 &self.context.env().cfg
248 }
249
250 #[inline]
252 pub fn cfg_mut(&mut self) -> &mut CfgEnv {
253 &mut self.context.evm.env.cfg
254 }
255
256 #[inline]
258 pub fn tx(&self) -> &TxEnv {
259 &self.context.evm.env.tx
260 }
261
262 #[inline]
264 pub fn tx_mut(&mut self) -> &mut TxEnv {
265 &mut self.context.evm.env.tx
266 }
267
268 #[inline]
270 pub fn db(&self) -> &DB {
271 &self.context.evm.db
272 }
273
274 #[inline]
276 pub fn db_mut(&mut self) -> &mut DB {
277 &mut self.context.evm.db
278 }
279
280 #[inline]
282 pub fn block(&self) -> &BlockEnv {
283 &self.context.evm.env.block
284 }
285
286 #[inline]
288 pub fn block_mut(&mut self) -> &mut BlockEnv {
289 &mut self.context.evm.env.block
290 }
291
292 pub fn modify_spec_id(&mut self, spec_id: SpecId) {
294 self.handler.modify_spec_id(spec_id);
295 }
296
297 #[inline]
299 pub fn into_context(self) -> Context<EXT, DB> {
300 self.context
301 }
302
303 #[inline]
305 pub fn into_db_and_env_with_handler_cfg(self) -> (DB, EnvWithHandlerCfg) {
306 (
307 self.context.evm.inner.db,
308 EnvWithHandlerCfg {
309 env: self.context.evm.inner.env,
310 handler_cfg: self.handler.cfg,
311 },
312 )
313 }
314
315 #[inline]
317 pub fn into_context_with_handler_cfg(self) -> ContextWithHandlerCfg<EXT, DB> {
318 ContextWithHandlerCfg::new(self.context, self.handler.cfg)
319 }
320
321 fn transact_preverified_inner(&mut self, initial_gas_spend: u64) -> EVMResult<DB::Error> {
323 let spec_id = self.spec_id();
324 let ctx = &mut self.context;
325 let pre_exec = self.handler.pre_execution();
326
327 pre_exec.load_accounts(ctx)?;
329
330 let precompiles = pre_exec.load_precompiles();
332 ctx.evm.set_precompiles(precompiles);
333
334 pre_exec.deduct_caller(ctx)?;
336
337 let gas_limit = ctx.evm.env.tx.gas_limit - initial_gas_spend;
338
339 let eip7702_gas_refund = pre_exec.apply_eip7702_auth_list(ctx)? as i64;
341
342 let exec = self.handler.execution();
343 let first_frame_or_result = match ctx.evm.env.tx.transact_to {
345 TxKind::Call(_) => exec.call(
346 ctx,
347 CallInputs::new_boxed(&ctx.evm.env.tx, gas_limit).unwrap(),
348 )?,
349 TxKind::Create => {
350 if spec_id.is_enabled_in(SpecId::OSAKA)
352 && ctx.env().tx.data.starts_with(&EOF_MAGIC_BYTES)
353 {
354 exec.eofcreate(
355 ctx,
356 Box::new(EOFCreateInputs::new_tx(&ctx.evm.env.tx, gas_limit)),
357 )?
358 } else {
359 exec.create(
361 ctx,
362 CreateInputs::new_boxed(&ctx.evm.env.tx, gas_limit).unwrap(),
363 )?
364 }
365 }
366 };
367
368 let mut result = match first_frame_or_result {
370 FrameOrResult::Frame(first_frame) => self.run_the_loop(first_frame)?,
371 FrameOrResult::Result(result) => result,
372 };
373
374 let ctx = &mut self.context;
375
376 self.handler
378 .execution()
379 .last_frame_return(ctx, &mut result)?;
380
381 let post_exec = self.handler.post_execution();
382 post_exec.refund(ctx, result.gas_mut(), eip7702_gas_refund);
384 post_exec.reimburse_caller(ctx, result.gas())?;
386 post_exec.reward_beneficiary(ctx, result.gas())?;
388 post_exec.output(ctx, result)
390 }
391}
392
393#[cfg(test)]
394mod tests {
395
396 use super::*;
397 use crate::{
398 db::BenchmarkDB,
399 interpreter::opcode::{PUSH1, SSTORE},
400 primitives::{
401 address, Authorization, Bytecode, RecoveredAuthority, RecoveredAuthorization, U256,
402 },
403 };
404
405 #[test]
406 fn sanity_eip7702_tx() {
407 let caller = address!("0000000000000000000000000000000000000001");
408 let delegate = address!("0000000000000000000000000000000000000002");
409 let auth = address!("0000000000000000000000000000000000000100");
410
411 let bytecode = Bytecode::new_legacy([PUSH1, 0x01, PUSH1, 0x01, SSTORE].into());
412
413 let mut evm = Evm::builder()
414 .with_spec_id(SpecId::PRAGUE)
415 .with_db(BenchmarkDB::new_bytecode(bytecode).with_target(delegate))
416 .modify_tx_env(|tx| {
417 tx.authorization_list = Some(
418 vec![RecoveredAuthorization::new_unchecked(
419 Authorization {
420 chain_id: 1,
421 address: delegate,
422 nonce: 0,
423 },
424 RecoveredAuthority::Valid(auth),
425 )]
426 .into(),
427 );
428 tx.caller = caller;
429 tx.transact_to = TxKind::Call(auth);
430 })
431 .build();
432
433 let ok = evm.transact().unwrap();
434
435 let auth_acc = ok.state.get(&auth).unwrap();
436 assert_eq!(auth_acc.info.code, Some(Bytecode::new_eip7702(delegate)));
437 assert_eq!(auth_acc.info.nonce, 1);
438 assert_eq!(
439 auth_acc.storage.get(&U256::from(1)).unwrap().present_value,
440 U256::from(1)
441 );
442 }
443}