1use crate::evm::FrameTr;
2use crate::item_or_result::FrameInitOrResult;
3use crate::{precompile_provider::PrecompileProvider, ItemOrResult};
4use crate::{CallFrame, CreateFrame, FrameData, FrameResult};
5use context::result::FromStringError;
6use context_interface::context::ContextError;
7use context_interface::local::{FrameToken, OutFrame};
8use context_interface::ContextTr;
9use context_interface::{
10 journaled_state::{JournalCheckpoint, JournalTr},
11 Cfg, Database,
12};
13use core::cmp::min;
14use derive_where::derive_where;
15use interpreter::interpreter_action::FrameInit;
16use interpreter::{
17 gas,
18 interpreter::{EthInterpreter, ExtBytecode},
19 interpreter_types::ReturnData,
20 CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme,
21 FrameInput, Gas, InputsImpl, InstructionResult, Interpreter, InterpreterAction,
22 InterpreterResult, InterpreterTypes, SharedMemory,
23};
24use primitives::{
25 constants::CALL_STACK_LIMIT,
26 hardfork::SpecId::{self, HOMESTEAD, LONDON, SPURIOUS_DRAGON},
27};
28use primitives::{keccak256, Address, Bytes, U256};
29use state::Bytecode;
30use std::borrow::ToOwned;
31use std::boxed::Box;
32
33#[derive_where(Clone, Debug; IW,
35 <IW as InterpreterTypes>::Stack,
36 <IW as InterpreterTypes>::Memory,
37 <IW as InterpreterTypes>::Bytecode,
38 <IW as InterpreterTypes>::ReturnData,
39 <IW as InterpreterTypes>::Input,
40 <IW as InterpreterTypes>::RuntimeFlag,
41 <IW as InterpreterTypes>::Extend,
42)]
43pub struct EthFrame<IW: InterpreterTypes = EthInterpreter> {
44 pub data: FrameData,
46 pub input: FrameInput,
48 pub depth: usize,
50 pub checkpoint: JournalCheckpoint,
52 pub interpreter: Interpreter<IW>,
54 pub is_finished: bool,
57}
58
59impl<IT: InterpreterTypes> FrameTr for EthFrame<IT> {
60 type FrameResult = FrameResult;
61 type FrameInit = FrameInit;
62}
63
64impl Default for EthFrame<EthInterpreter> {
65 fn default() -> Self {
66 Self::do_default(Interpreter::default())
67 }
68}
69
70impl EthFrame<EthInterpreter> {
71 pub fn invalid() -> Self {
73 Self::do_default(Interpreter::invalid())
74 }
75
76 fn do_default(interpreter: Interpreter<EthInterpreter>) -> Self {
77 Self {
78 data: FrameData::Call(CallFrame {
79 return_memory_range: 0..0,
80 }),
81 input: FrameInput::Empty,
82 depth: 0,
83 checkpoint: JournalCheckpoint::default(),
84 interpreter,
85 is_finished: false,
86 }
87 }
88
89 pub fn is_finished(&self) -> bool {
91 self.is_finished
92 }
93
94 pub fn set_finished(&mut self, finished: bool) {
96 self.is_finished = finished;
97 }
98}
99
100pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
102
103impl EthFrame<EthInterpreter> {
104 #[allow(clippy::too_many_arguments)]
106 pub fn clear(
107 &mut self,
108 data: FrameData,
109 input: FrameInput,
110 depth: usize,
111 memory: SharedMemory,
112 bytecode: ExtBytecode,
113 inputs: InputsImpl,
114 is_static: bool,
115 spec_id: SpecId,
116 gas_limit: u64,
117 checkpoint: JournalCheckpoint,
118 ) {
119 let Self {
120 data: data_ref,
121 input: input_ref,
122 depth: depth_ref,
123 interpreter,
124 checkpoint: checkpoint_ref,
125 is_finished: is_finished_ref,
126 } = self;
127 *data_ref = data;
128 *input_ref = input;
129 *depth_ref = depth;
130 *is_finished_ref = false;
131 interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit);
132 *checkpoint_ref = checkpoint;
133 }
134
135 #[inline]
137 pub fn make_call_frame<
138 CTX: ContextTr,
139 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
140 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
141 >(
142 mut this: OutFrame<'_, Self>,
143 ctx: &mut CTX,
144 precompiles: &mut PRECOMPILES,
145 depth: usize,
146 memory: SharedMemory,
147 inputs: Box<CallInputs>,
148 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
149 let gas = Gas::new(inputs.gas_limit);
150 let return_result = |instruction_result: InstructionResult| {
151 Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
152 result: InterpreterResult {
153 result: instruction_result,
154 gas,
155 output: Bytes::new(),
156 },
157 memory_offset: inputs.return_memory_offset.clone(),
158 })))
159 };
160
161 if depth > CALL_STACK_LIMIT as usize {
163 return return_result(InstructionResult::CallTooDeep);
164 }
165
166 let _ = ctx
168 .journal_mut()
169 .load_account_delegated(inputs.bytecode_address)?;
170
171 let checkpoint = ctx.journal_mut().checkpoint();
173
174 if let CallValue::Transfer(value) = inputs.value {
176 if let Some(i) =
179 ctx.journal_mut()
180 .transfer(inputs.caller, inputs.target_address, value)?
181 {
182 ctx.journal_mut().checkpoint_revert(checkpoint);
183 return return_result(i.into());
184 }
185 }
186
187 let interpreter_input = InputsImpl {
188 target_address: inputs.target_address,
189 caller_address: inputs.caller,
190 bytecode_address: Some(inputs.bytecode_address),
191 input: inputs.input.clone(),
192 call_value: inputs.value.get(),
193 };
194 let is_static = inputs.is_static;
195 let gas_limit = inputs.gas_limit;
196
197 if let Some(result) = precompiles.run(ctx, &inputs).map_err(ERROR::from_string)? {
198 if result.result.is_ok() {
199 ctx.journal_mut().checkpoint_commit();
200 } else {
201 ctx.journal_mut().checkpoint_revert(checkpoint);
202 }
203 return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
204 result,
205 memory_offset: inputs.return_memory_offset.clone(),
206 })));
207 }
208
209 let account = ctx
210 .journal_mut()
211 .load_account_code(inputs.bytecode_address)?;
212
213 let mut code_hash = account.info.code_hash();
214 let mut bytecode = account.info.code.clone().unwrap_or_default();
215
216 if let Bytecode::Eip7702(eip7702_bytecode) = bytecode {
217 let account = &ctx
218 .journal_mut()
219 .load_account_code(eip7702_bytecode.delegated_address)?
220 .info;
221 bytecode = account.code.clone().unwrap_or_default();
222 code_hash = account.code_hash();
223 }
224
225 if bytecode.is_empty() {
227 ctx.journal_mut().checkpoint_commit();
228 return return_result(InstructionResult::Stop);
229 }
230
231 this.get(EthFrame::invalid).clear(
233 FrameData::Call(CallFrame {
234 return_memory_range: inputs.return_memory_offset.clone(),
235 }),
236 FrameInput::Call(inputs),
237 depth,
238 memory,
239 ExtBytecode::new_with_hash(bytecode, code_hash),
240 interpreter_input,
241 is_static,
242 ctx.cfg().spec().into(),
243 gas_limit,
244 checkpoint,
245 );
246 Ok(ItemOrResult::Item(this.consume()))
247 }
248
249 #[inline]
251 pub fn make_create_frame<
252 CTX: ContextTr,
253 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
254 >(
255 mut this: OutFrame<'_, Self>,
256 context: &mut CTX,
257 depth: usize,
258 memory: SharedMemory,
259 inputs: Box<CreateInputs>,
260 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
261 let spec = context.cfg().spec().into();
262 let return_error = |e| {
263 Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome {
264 result: InterpreterResult {
265 result: e,
266 gas: Gas::new(inputs.gas_limit),
267 output: Bytes::new(),
268 },
269 address: None,
270 })))
271 };
272
273 if depth > CALL_STACK_LIMIT as usize {
275 return return_error(InstructionResult::CallTooDeep);
276 }
277
278 let caller_info = &mut context.journal_mut().load_account(inputs.caller)?.data.info;
286
287 if caller_info.balance < inputs.value {
289 return return_error(InstructionResult::OutOfFunds);
290 }
291
292 let old_nonce = caller_info.nonce;
294 let Some(new_nonce) = old_nonce.checked_add(1) else {
295 return return_error(InstructionResult::Return);
296 };
297 caller_info.nonce = new_nonce;
298 context
299 .journal_mut()
300 .nonce_bump_journal_entry(inputs.caller);
301
302 let mut init_code_hash = None;
304 let created_address = match inputs.scheme {
305 CreateScheme::Create => inputs.caller.create(old_nonce),
306 CreateScheme::Create2 { salt } => {
307 let init_code_hash = *init_code_hash.insert(keccak256(&inputs.init_code));
308 inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
309 }
310 CreateScheme::Custom { address } => address,
311 };
312
313 context.journal_mut().load_account(created_address)?;
315
316 let checkpoint = match context.journal_mut().create_account_checkpoint(
318 inputs.caller,
319 created_address,
320 inputs.value,
321 spec,
322 ) {
323 Ok(checkpoint) => checkpoint,
324 Err(e) => return return_error(e.into()),
325 };
326
327 let bytecode = ExtBytecode::new_with_optional_hash(
328 Bytecode::new_legacy(inputs.init_code.clone()),
329 init_code_hash,
330 );
331
332 let interpreter_input = InputsImpl {
333 target_address: created_address,
334 caller_address: inputs.caller,
335 bytecode_address: None,
336 input: CallInput::Bytes(Bytes::new()),
337 call_value: inputs.value,
338 };
339 let gas_limit = inputs.gas_limit;
340
341 this.get(EthFrame::invalid).clear(
342 FrameData::Create(CreateFrame { created_address }),
343 FrameInput::Create(inputs),
344 depth,
345 memory,
346 bytecode,
347 interpreter_input,
348 false,
349 spec,
350 gas_limit,
351 checkpoint,
352 );
353 Ok(ItemOrResult::Item(this.consume()))
354 }
355
356 pub fn init_with_context<
358 CTX: ContextTr,
359 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
360 >(
361 this: OutFrame<'_, Self>,
362 ctx: &mut CTX,
363 precompiles: &mut PRECOMPILES,
364 frame_init: FrameInit,
365 ) -> Result<
366 ItemOrResult<FrameToken, FrameResult>,
367 ContextError<<<CTX as ContextTr>::Db as Database>::Error>,
368 > {
369 let FrameInit {
371 depth,
372 memory,
373 frame_input,
374 } = frame_init;
375
376 match frame_input {
377 FrameInput::Call(inputs) => {
378 Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs)
379 }
380 FrameInput::Create(inputs) => Self::make_create_frame(this, ctx, depth, memory, inputs),
381 FrameInput::Empty => unreachable!(),
382 }
383 }
384}
385
386impl EthFrame<EthInterpreter> {
387 pub fn process_next_action<
389 CTX: ContextTr,
390 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
391 >(
392 &mut self,
393 context: &mut CTX,
394 next_action: InterpreterAction,
395 ) -> Result<FrameInitOrResult<Self>, ERROR> {
396 let spec = context.cfg().spec().into();
397
398 let mut interpreter_result = match next_action {
401 InterpreterAction::NewFrame(frame_input) => {
402 let depth = self.depth + 1;
403 return Ok(ItemOrResult::Item(FrameInit {
404 frame_input,
405 depth,
406 memory: self.interpreter.memory.new_child_context(),
407 }));
408 }
409 InterpreterAction::Return(result) => result,
410 };
411
412 let result = match &self.data {
414 FrameData::Call(frame) => {
415 if interpreter_result.result.is_ok() {
418 context.journal_mut().checkpoint_commit();
419 } else {
420 context.journal_mut().checkpoint_revert(self.checkpoint);
421 }
422 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
423 interpreter_result,
424 frame.return_memory_range.clone(),
425 )))
426 }
427 FrameData::Create(frame) => {
428 let max_code_size = context.cfg().max_code_size();
429 let is_eip3541_disabled = context.cfg().is_eip3541_disabled();
430 return_create(
431 context.journal_mut(),
432 self.checkpoint,
433 &mut interpreter_result,
434 frame.created_address,
435 max_code_size,
436 is_eip3541_disabled,
437 spec,
438 );
439
440 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
441 interpreter_result,
442 Some(frame.created_address),
443 )))
444 }
445 };
446
447 Ok(result)
448 }
449
450 pub fn return_result<CTX: ContextTr, ERROR: From<ContextTrDbError<CTX>> + FromStringError>(
452 &mut self,
453 ctx: &mut CTX,
454 result: FrameResult,
455 ) -> Result<(), ERROR> {
456 self.interpreter.memory.free_child_context();
457 match core::mem::replace(ctx.error(), Ok(())) {
458 Err(ContextError::Db(e)) => return Err(e.into()),
459 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
460 Ok(_) => (),
461 }
462
463 match result {
465 FrameResult::Call(outcome) => {
466 let out_gas = outcome.gas();
467 let ins_result = *outcome.instruction_result();
468 let returned_len = outcome.result.output.len();
469
470 let interpreter = &mut self.interpreter;
471 let mem_length = outcome.memory_length();
472 let mem_start = outcome.memory_start();
473 interpreter.return_data.set_buffer(outcome.result.output);
474
475 let target_len = min(mem_length, returned_len);
476
477 if ins_result == InstructionResult::FatalExternalError {
478 panic!("Fatal external error in insert_call_outcome");
479 }
480
481 let item = if ins_result.is_ok() {
482 U256::from(1)
483 } else {
484 U256::ZERO
485 };
486 let _ = interpreter.stack.push(item);
488
489 if ins_result.is_ok_or_revert() {
491 interpreter.gas.erase_cost(out_gas.remaining());
492 interpreter
493 .memory
494 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
495 }
496
497 if ins_result.is_ok() {
498 interpreter.gas.record_refund(out_gas.refunded());
499 }
500 }
501 FrameResult::Create(outcome) => {
502 let instruction_result = *outcome.instruction_result();
503 let interpreter = &mut self.interpreter;
504
505 if instruction_result == InstructionResult::Revert {
506 interpreter
508 .return_data
509 .set_buffer(outcome.output().to_owned());
510 } else {
511 interpreter.return_data.clear();
513 };
514
515 assert_ne!(
516 instruction_result,
517 InstructionResult::FatalExternalError,
518 "Fatal external error in insert_eofcreate_outcome"
519 );
520
521 let this_gas = &mut interpreter.gas;
522 if instruction_result.is_ok_or_revert() {
523 this_gas.erase_cost(outcome.gas().remaining());
524 }
525
526 let stack_item = if instruction_result.is_ok() {
527 this_gas.record_refund(outcome.gas().refunded());
528 outcome.address.unwrap_or_default().into_word().into()
529 } else {
530 U256::ZERO
531 };
532
533 let _ = interpreter.stack.push(stack_item);
535 }
536 }
537
538 Ok(())
539 }
540}
541
542pub fn return_create<JOURNAL: JournalTr>(
544 journal: &mut JOURNAL,
545 checkpoint: JournalCheckpoint,
546 interpreter_result: &mut InterpreterResult,
547 address: Address,
548 max_code_size: usize,
549 is_eip3541_disabled: bool,
550 spec_id: SpecId,
551) {
552 if !interpreter_result.result.is_ok() {
554 journal.checkpoint_revert(checkpoint);
555 return;
556 }
557 if !is_eip3541_disabled
562 && spec_id.is_enabled_in(LONDON)
563 && interpreter_result.output.first() == Some(&0xEF)
564 {
565 journal.checkpoint_revert(checkpoint);
566 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
567 return;
568 }
569
570 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
573 journal.checkpoint_revert(checkpoint);
574 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
575 return;
576 }
577 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
578 if !interpreter_result.gas.record_cost(gas_for_code) {
579 if spec_id.is_enabled_in(HOMESTEAD) {
584 journal.checkpoint_revert(checkpoint);
585 interpreter_result.result = InstructionResult::OutOfGas;
586 return;
587 } else {
588 interpreter_result.output = Bytes::new();
589 }
590 }
591 journal.checkpoint_commit();
593
594 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
596
597 journal.set_code(address, bytecode);
599
600 interpreter_result.result = InstructionResult::Return;
601}