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, B256, 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 fn invalid() -> Self {
72 Self::do_default(Interpreter::invalid())
73 }
74
75 fn do_default(interpreter: Interpreter<EthInterpreter>) -> Self {
76 Self {
77 data: FrameData::Call(CallFrame {
78 return_memory_range: 0..0,
79 }),
80 input: FrameInput::Empty,
81 depth: 0,
82 checkpoint: JournalCheckpoint::default(),
83 interpreter,
84 is_finished: false,
85 }
86 }
87
88 pub fn is_finished(&self) -> bool {
90 self.is_finished
91 }
92
93 pub fn set_finished(&mut self, finished: bool) {
95 self.is_finished = finished;
96 }
97}
98
99pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
101
102impl EthFrame<EthInterpreter> {
103 #[allow(clippy::too_many_arguments)]
105 pub fn clear(
106 &mut self,
107 data: FrameData,
108 input: FrameInput,
109 depth: usize,
110 memory: SharedMemory,
111 bytecode: ExtBytecode,
112 inputs: InputsImpl,
113 is_static: bool,
114 spec_id: SpecId,
115 gas_limit: u64,
116 checkpoint: JournalCheckpoint,
117 ) {
118 let Self {
119 data: data_ref,
120 input: input_ref,
121 depth: depth_ref,
122 interpreter,
123 checkpoint: checkpoint_ref,
124 is_finished: is_finished_ref,
125 } = self;
126 *data_ref = data;
127 *input_ref = input;
128 *depth_ref = depth;
129 *is_finished_ref = false;
130 interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit);
131 *checkpoint_ref = checkpoint;
132 }
133
134 #[inline]
136 pub fn make_call_frame<
137 CTX: ContextTr,
138 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
139 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
140 >(
141 mut this: OutFrame<'_, Self>,
142 ctx: &mut CTX,
143 precompiles: &mut PRECOMPILES,
144 depth: usize,
145 memory: SharedMemory,
146 inputs: Box<CallInputs>,
147 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
148 let gas = Gas::new(inputs.gas_limit);
149 let return_result = |instruction_result: InstructionResult| {
150 Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
151 result: InterpreterResult {
152 result: instruction_result,
153 gas,
154 output: Bytes::new(),
155 },
156 memory_offset: inputs.return_memory_offset.clone(),
157 })))
158 };
159
160 if depth > CALL_STACK_LIMIT as usize {
162 return return_result(InstructionResult::CallTooDeep);
163 }
164
165 let _ = ctx
167 .journal_mut()
168 .load_account_delegated(inputs.bytecode_address)?;
169
170 let checkpoint = ctx.journal_mut().checkpoint();
172
173 if let CallValue::Transfer(value) = inputs.value {
175 if let Some(i) =
178 ctx.journal_mut()
179 .transfer(inputs.caller, inputs.target_address, value)?
180 {
181 ctx.journal_mut().checkpoint_revert(checkpoint);
182 return return_result(i.into());
183 }
184 }
185
186 let interpreter_input = InputsImpl {
187 target_address: inputs.target_address,
188 caller_address: inputs.caller,
189 bytecode_address: Some(inputs.bytecode_address),
190 input: inputs.input.clone(),
191 call_value: inputs.value.get(),
192 };
193 let is_static = inputs.is_static;
194 let gas_limit = inputs.gas_limit;
195
196 if let Some(result) = precompiles
197 .run(
198 ctx,
199 &inputs.bytecode_address,
200 &interpreter_input,
201 is_static,
202 gas_limit,
203 )
204 .map_err(ERROR::from_string)?
205 {
206 if result.result.is_ok() {
207 ctx.journal_mut().checkpoint_commit();
208 } else {
209 ctx.journal_mut().checkpoint_revert(checkpoint);
210 }
211 return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
212 result,
213 memory_offset: inputs.return_memory_offset.clone(),
214 })));
215 }
216
217 let account = ctx
218 .journal_mut()
219 .load_account_code(inputs.bytecode_address)?;
220
221 let mut code_hash = account.info.code_hash();
222 let mut bytecode = account.info.code.clone().unwrap_or_default();
223
224 if let Bytecode::Eip7702(eip7702_bytecode) = bytecode {
225 let account = &ctx
226 .journal_mut()
227 .load_account_code(eip7702_bytecode.delegated_address)?
228 .info;
229 bytecode = account.code.clone().unwrap_or_default();
230 code_hash = account.code_hash();
231 }
232
233 if bytecode.is_empty() {
235 ctx.journal_mut().checkpoint_commit();
236 return return_result(InstructionResult::Stop);
237 }
238
239 this.get(EthFrame::invalid).clear(
241 FrameData::Call(CallFrame {
242 return_memory_range: inputs.return_memory_offset.clone(),
243 }),
244 FrameInput::Call(inputs),
245 depth,
246 memory,
247 ExtBytecode::new_with_hash(bytecode, code_hash),
248 interpreter_input,
249 is_static,
250 ctx.cfg().spec().into(),
251 gas_limit,
252 checkpoint,
253 );
254 Ok(ItemOrResult::Item(this.consume()))
255 }
256
257 #[inline]
259 pub fn make_create_frame<
260 CTX: ContextTr,
261 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
262 >(
263 mut this: OutFrame<'_, Self>,
264 context: &mut CTX,
265 depth: usize,
266 memory: SharedMemory,
267 inputs: Box<CreateInputs>,
268 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
269 let spec = context.cfg().spec().into();
270 let return_error = |e| {
271 Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome {
272 result: InterpreterResult {
273 result: e,
274 gas: Gas::new(inputs.gas_limit),
275 output: Bytes::new(),
276 },
277 address: None,
278 })))
279 };
280
281 if depth > CALL_STACK_LIMIT as usize {
283 return return_error(InstructionResult::CallTooDeep);
284 }
285
286 let caller_info = &mut context.journal_mut().load_account(inputs.caller)?.data.info;
294
295 if caller_info.balance < inputs.value {
297 return return_error(InstructionResult::OutOfFunds);
298 }
299
300 let old_nonce = caller_info.nonce;
302 let Some(new_nonce) = old_nonce.checked_add(1) else {
303 return return_error(InstructionResult::Return);
304 };
305 caller_info.nonce = new_nonce;
306 context
307 .journal_mut()
308 .nonce_bump_journal_entry(inputs.caller);
309
310 let mut init_code_hash = B256::ZERO;
312 let created_address = match inputs.scheme {
313 CreateScheme::Create => inputs.caller.create(old_nonce),
314 CreateScheme::Create2 { salt } => {
315 init_code_hash = keccak256(&inputs.init_code);
316 inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
317 }
318 CreateScheme::Custom { address } => address,
319 };
320
321 context.journal_mut().load_account(created_address)?;
323
324 let checkpoint = match context.journal_mut().create_account_checkpoint(
326 inputs.caller,
327 created_address,
328 inputs.value,
329 spec,
330 ) {
331 Ok(checkpoint) => checkpoint,
332 Err(e) => return return_error(e.into()),
333 };
334
335 let bytecode = ExtBytecode::new_with_hash(
336 Bytecode::new_legacy(inputs.init_code.clone()),
337 init_code_hash,
338 );
339
340 let interpreter_input = InputsImpl {
341 target_address: created_address,
342 caller_address: inputs.caller,
343 bytecode_address: None,
344 input: CallInput::Bytes(Bytes::new()),
345 call_value: inputs.value,
346 };
347 let gas_limit = inputs.gas_limit;
348
349 this.get(EthFrame::invalid).clear(
350 FrameData::Create(CreateFrame { created_address }),
351 FrameInput::Create(inputs),
352 depth,
353 memory,
354 bytecode,
355 interpreter_input,
356 false,
357 spec,
358 gas_limit,
359 checkpoint,
360 );
361 Ok(ItemOrResult::Item(this.consume()))
362 }
363
364 pub fn init_with_context<
486 CTX: ContextTr,
487 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
488 >(
489 this: OutFrame<'_, Self>,
490 ctx: &mut CTX,
491 precompiles: &mut PRECOMPILES,
492 frame_init: FrameInit,
493 ) -> Result<
494 ItemOrResult<FrameToken, FrameResult>,
495 ContextError<<<CTX as ContextTr>::Db as Database>::Error>,
496 > {
497 let FrameInit {
499 depth,
500 memory,
501 frame_input,
502 } = frame_init;
503
504 match frame_input {
505 FrameInput::Call(inputs) => {
506 Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs)
507 }
508 FrameInput::Create(inputs) => Self::make_create_frame(this, ctx, depth, memory, inputs),
509 FrameInput::Empty => unreachable!(),
510 }
511 }
512}
513
514impl EthFrame<EthInterpreter> {
515 pub fn process_next_action<
517 CTX: ContextTr,
518 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
519 >(
520 &mut self,
521 context: &mut CTX,
522 next_action: InterpreterAction,
523 ) -> Result<FrameInitOrResult<Self>, ERROR> {
524 let spec = context.cfg().spec().into();
525
526 let mut interpreter_result = match next_action {
529 InterpreterAction::NewFrame(frame_input) => {
530 let depth = self.depth + 1;
531 return Ok(ItemOrResult::Item(FrameInit {
532 frame_input,
533 depth,
534 memory: self.interpreter.memory.new_child_context(),
535 }));
536 }
537 InterpreterAction::Return(result) => result,
538 };
539
540 let result = match &self.data {
542 FrameData::Call(frame) => {
543 if interpreter_result.result.is_ok() {
546 context.journal_mut().checkpoint_commit();
547 } else {
548 context.journal_mut().checkpoint_revert(self.checkpoint);
549 }
550 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
551 interpreter_result,
552 frame.return_memory_range.clone(),
553 )))
554 }
555 FrameData::Create(frame) => {
556 let max_code_size = context.cfg().max_code_size();
557 let is_eip3541_disabled = context.cfg().is_eip3541_disabled();
558 return_create(
559 context.journal_mut(),
560 self.checkpoint,
561 &mut interpreter_result,
562 frame.created_address,
563 max_code_size,
564 is_eip3541_disabled,
565 spec,
566 );
567
568 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
569 interpreter_result,
570 Some(frame.created_address),
571 )))
572 }
573 };
574
575 Ok(result)
576 }
577
578 pub fn return_result<CTX: ContextTr, ERROR: From<ContextTrDbError<CTX>> + FromStringError>(
580 &mut self,
581 ctx: &mut CTX,
582 result: FrameResult,
583 ) -> Result<(), ERROR> {
584 self.interpreter.memory.free_child_context();
585 match core::mem::replace(ctx.error(), Ok(())) {
586 Err(ContextError::Db(e)) => return Err(e.into()),
587 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
588 Ok(_) => (),
589 }
590
591 match result {
593 FrameResult::Call(outcome) => {
594 let out_gas = outcome.gas();
595 let ins_result = *outcome.instruction_result();
596 let returned_len = outcome.result.output.len();
597
598 let interpreter = &mut self.interpreter;
599 let mem_length = outcome.memory_length();
600 let mem_start = outcome.memory_start();
601 interpreter.return_data.set_buffer(outcome.result.output);
602
603 let target_len = min(mem_length, returned_len);
604
605 if ins_result == InstructionResult::FatalExternalError {
606 panic!("Fatal external error in insert_call_outcome");
607 }
608
609 let item = if ins_result.is_ok() {
610 U256::from(1)
611 } else {
612 U256::ZERO
613 };
614 let _ = interpreter.stack.push(item);
616
617 if ins_result.is_ok_or_revert() {
619 interpreter.gas.erase_cost(out_gas.remaining());
620 interpreter
621 .memory
622 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
623 }
624
625 if ins_result.is_ok() {
626 interpreter.gas.record_refund(out_gas.refunded());
627 }
628 }
629 FrameResult::Create(outcome) => {
630 let instruction_result = *outcome.instruction_result();
631 let interpreter = &mut self.interpreter;
632
633 if instruction_result == InstructionResult::Revert {
634 interpreter
636 .return_data
637 .set_buffer(outcome.output().to_owned());
638 } else {
639 interpreter.return_data.clear();
641 };
642
643 assert_ne!(
644 instruction_result,
645 InstructionResult::FatalExternalError,
646 "Fatal external error in insert_eofcreate_outcome"
647 );
648
649 let this_gas = &mut interpreter.gas;
650 if instruction_result.is_ok_or_revert() {
651 this_gas.erase_cost(outcome.gas().remaining());
652 }
653
654 let stack_item = if instruction_result.is_ok() {
655 this_gas.record_refund(outcome.gas().refunded());
656 outcome.address.unwrap_or_default().into_word().into()
657 } else {
658 U256::ZERO
659 };
660
661 let _ = interpreter.stack.push(stack_item);
663 }
664 }
665
666 Ok(())
667 }
668}
669
670pub fn return_create<JOURNAL: JournalTr>(
672 journal: &mut JOURNAL,
673 checkpoint: JournalCheckpoint,
674 interpreter_result: &mut InterpreterResult,
675 address: Address,
676 max_code_size: usize,
677 is_eip3541_disabled: bool,
678 spec_id: SpecId,
679) {
680 if !interpreter_result.result.is_ok() {
682 journal.checkpoint_revert(checkpoint);
683 return;
684 }
685 if !is_eip3541_disabled
690 && spec_id.is_enabled_in(LONDON)
691 && interpreter_result.output.first() == Some(&0xEF)
692 {
693 journal.checkpoint_revert(checkpoint);
694 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
695 return;
696 }
697
698 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
701 journal.checkpoint_revert(checkpoint);
702 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
703 return;
704 }
705 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
706 if !interpreter_result.gas.record_cost(gas_for_code) {
707 if spec_id.is_enabled_in(HOMESTEAD) {
712 journal.checkpoint_revert(checkpoint);
713 interpreter_result.result = InstructionResult::OutOfGas;
714 return;
715 } else {
716 interpreter_result.output = Bytes::new();
717 }
718 }
719 journal.checkpoint_commit();
721
722 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
724
725 journal.set_code(address, bytecode);
727
728 interpreter_result.result = InstructionResult::Return;
729}
730
731