1use super::frame_data::*;
2use crate::{
3 instructions::InstructionProvider, precompile_provider::PrecompileProvider, EvmTr,
4 FrameInitOrResult, FrameOrResult, ItemOrResult,
5};
6use bytecode::{Eof, EOF_MAGIC_BYTES};
7use context::result::FromStringError;
8use context::LocalContextTr;
9use context_interface::context::ContextError;
10use context_interface::ContextTr;
11use context_interface::{
12 journaled_state::{JournalCheckpoint, JournalTr},
13 Cfg, Database, Transaction,
14};
15use core::cmp::min;
16use interpreter::{
17 gas,
18 interpreter::{EthInterpreter, ExtBytecode},
19 interpreter_types::{LoopControl, ReturnData, RuntimeFlag},
20 return_ok, return_revert, CallInput, CallInputs, CallOutcome, CallValue, CreateInputs,
21 CreateOutcome, CreateScheme, EOFCreateInputs, EOFCreateKind, FrameInput, Gas, InputsImpl,
22 InstructionResult, Interpreter, InterpreterAction, InterpreterResult, InterpreterTypes,
23 SharedMemory,
24};
25use primitives::{
26 constants::CALL_STACK_LIMIT,
27 hardfork::SpecId::{self, HOMESTEAD, LONDON, SPURIOUS_DRAGON},
28};
29use primitives::{keccak256, Address, Bytes, B256, U256};
30use state::Bytecode;
31use std::borrow::ToOwned;
32use std::{boxed::Box, sync::Arc};
33
34pub trait Frame: Sized {
36 type Evm;
37 type FrameInit;
38 type FrameResult;
39 type Error;
40
41 fn init_first(
42 evm: &mut Self::Evm,
43 frame_input: Self::FrameInit,
44 ) -> Result<FrameOrResult<Self>, Self::Error>;
45
46 fn init(
47 &mut self,
48 evm: &mut Self::Evm,
49 frame_input: Self::FrameInit,
50 ) -> Result<FrameOrResult<Self>, Self::Error>;
51
52 fn run(&mut self, evm: &mut Self::Evm) -> Result<FrameInitOrResult<Self>, Self::Error>;
53
54 fn return_result(
55 &mut self,
56 evm: &mut Self::Evm,
57 result: Self::FrameResult,
58 ) -> Result<(), Self::Error>;
59}
60
61pub struct EthFrame<EVM, ERROR, IW: InterpreterTypes> {
62 phantom: core::marker::PhantomData<(EVM, ERROR)>,
63 data: FrameData,
65 pub input: FrameInput,
67 depth: usize,
69 pub checkpoint: JournalCheckpoint,
71 pub interpreter: Interpreter<IW>,
73}
74
75impl<EVM, ERROR> Frame for EthFrame<EVM, ERROR, EthInterpreter>
76where
77 EVM: EvmTr<
78 Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
79 Instructions: InstructionProvider<
80 Context = EVM::Context,
81 InterpreterTypes = EthInterpreter,
82 >,
83 >,
84 ERROR: From<ContextTrDbError<EVM::Context>> + FromStringError,
85{
86 type Evm = EVM;
87 type FrameInit = FrameInput;
88 type FrameResult = FrameResult;
89 type Error = ERROR;
90
91 fn init_first(
92 evm: &mut Self::Evm,
93 frame_input: Self::FrameInit,
94 ) -> Result<FrameOrResult<Self>, Self::Error> {
95 let memory =
96 SharedMemory::new_with_buffer(evm.ctx().local().shared_memory_buffer().clone());
97 Self::init_with_context(evm, 0, frame_input, memory)
98 }
99
100 fn init(
101 &mut self,
102 evm: &mut Self::Evm,
103 frame_input: Self::FrameInit,
104 ) -> Result<FrameOrResult<Self>, Self::Error> {
105 let memory = self.interpreter.memory.new_child_context();
107 EthFrame::init_with_context(evm, self.depth + 1, frame_input, memory)
108 }
109
110 fn run(&mut self, context: &mut Self::Evm) -> Result<FrameInitOrResult<Self>, Self::Error> {
111 let next_action = context.run_interpreter(&mut self.interpreter);
112 self.process_next_action(context, next_action)
113 }
114
115 fn return_result(
116 &mut self,
117 context: &mut Self::Evm,
118 result: Self::FrameResult,
119 ) -> Result<(), Self::Error> {
120 self.return_result(context, result)
121 }
122}
123
124pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
125
126impl<CTX, ERROR, IW> EthFrame<CTX, ERROR, IW>
127where
128 IW: InterpreterTypes,
129{
130 pub fn new(
131 data: FrameData,
132 input: FrameInput,
133 depth: usize,
134 interpreter: Interpreter<IW>,
135 checkpoint: JournalCheckpoint,
136 ) -> Self {
137 Self {
138 phantom: Default::default(),
139 input,
140 data,
141 depth,
142 interpreter,
143 checkpoint,
144 }
145 }
146}
147
148impl<EVM, ERROR> EthFrame<EVM, ERROR, EthInterpreter>
149where
150 EVM: EvmTr<
151 Context: ContextTr,
152 Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
153 Instructions: InstructionProvider,
154 >,
155 ERROR: From<ContextTrDbError<EVM::Context>>,
156 ERROR: FromStringError,
157{
158 #[inline]
160 pub fn make_call_frame(
161 evm: &mut EVM,
162 depth: usize,
163 memory: SharedMemory,
164 inputs: Box<CallInputs>,
165 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
166 let gas = Gas::new(inputs.gas_limit);
167
168 let (context, precompiles) = evm.ctx_precompiles();
169
170 let return_result = |instruction_result: InstructionResult| {
171 Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
172 result: InterpreterResult {
173 result: instruction_result,
174 gas,
175 output: Bytes::new(),
176 },
177 memory_offset: inputs.return_memory_offset.clone(),
178 })))
179 };
180
181 if depth > CALL_STACK_LIMIT as usize {
183 return return_result(InstructionResult::CallTooDeep);
184 }
185
186 let _ = context
188 .journal()
189 .load_account_delegated(inputs.bytecode_address)?;
190
191 let checkpoint = context.journal().checkpoint();
193
194 if let CallValue::Transfer(value) = inputs.value {
196 if let Some(i) =
199 context
200 .journal()
201 .transfer(inputs.caller, inputs.target_address, value)?
202 {
203 context.journal().checkpoint_revert(checkpoint);
204 return return_result(i.into());
205 }
206 }
207
208 let interpreter_input = InputsImpl {
209 target_address: inputs.target_address,
210 caller_address: inputs.caller,
211 bytecode_address: Some(inputs.bytecode_address),
212 input: inputs.input.clone(),
213 call_value: inputs.value.get(),
214 };
215 let is_static = inputs.is_static;
216 let gas_limit = inputs.gas_limit;
217
218 let is_ext_delegate_call = inputs.scheme.is_ext_delegate_call();
219 if !is_ext_delegate_call {
220 if let Some(result) = precompiles
221 .run(
222 context,
223 &inputs.bytecode_address,
224 &interpreter_input,
225 is_static,
226 gas_limit,
227 )
228 .map_err(ERROR::from_string)?
229 {
230 if result.result.is_ok() {
231 context.journal().checkpoint_commit();
232 } else {
233 context.journal().checkpoint_revert(checkpoint);
234 }
235 return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
236 result,
237 memory_offset: inputs.return_memory_offset.clone(),
238 })));
239 }
240 }
241
242 let account = context
243 .journal()
244 .load_account_code(inputs.bytecode_address)?;
245
246 let mut code_hash = account.info.code_hash();
247 let mut bytecode = account.info.code.clone().unwrap_or_default();
248
249 if let Bytecode::Eip7702(eip7702_bytecode) = bytecode {
250 let account = &context
251 .journal()
252 .load_account_code(eip7702_bytecode.delegated_address)?
253 .info;
254 bytecode = account.code.clone().unwrap_or_default();
255 code_hash = account.code_hash();
256 }
257
258 if is_ext_delegate_call && !bytecode.bytes_slice().starts_with(&EOF_MAGIC_BYTES) {
260 context.journal().checkpoint_revert(checkpoint);
261 return return_result(InstructionResult::InvalidExtDelegateCallTarget);
262 }
263
264 if bytecode.is_empty() {
266 context.journal().checkpoint_commit();
267 return return_result(InstructionResult::Stop);
268 }
269
270 Ok(ItemOrResult::Item(Self::new(
272 FrameData::Call(CallFrame {
273 return_memory_range: inputs.return_memory_offset.clone(),
274 }),
275 FrameInput::Call(inputs),
276 depth,
277 Interpreter::new(
278 memory,
279 ExtBytecode::new_with_hash(bytecode, code_hash),
280 interpreter_input,
281 is_static,
282 false,
283 context.cfg().spec().into(),
284 gas_limit,
285 ),
286 checkpoint,
287 )))
288 }
289
290 #[inline]
292 pub fn make_create_frame(
293 evm: &mut EVM,
294 depth: usize,
295 memory: SharedMemory,
296 inputs: Box<CreateInputs>,
297 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
298 let context = evm.ctx();
299 let spec = context.cfg().spec().into();
300 let return_error = |e| {
301 Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome {
302 result: InterpreterResult {
303 result: e,
304 gas: Gas::new(inputs.gas_limit),
305 output: Bytes::new(),
306 },
307 address: None,
308 })))
309 };
310
311 if depth > CALL_STACK_LIMIT as usize {
313 return return_error(InstructionResult::CallTooDeep);
314 }
315
316 let caller_balance = context
324 .journal()
325 .load_account(inputs.caller)?
326 .data
327 .info
328 .balance;
329
330 if caller_balance < inputs.value {
332 return return_error(InstructionResult::OutOfFunds);
333 }
334
335 let old_nonce;
337 if let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? {
338 old_nonce = nonce - 1;
339 } else {
340 return return_error(InstructionResult::Return);
341 }
342
343 let mut init_code_hash = B256::ZERO;
345 let created_address = match inputs.scheme {
346 CreateScheme::Create => inputs.caller.create(old_nonce),
347 CreateScheme::Create2 { salt } => {
348 init_code_hash = keccak256(&inputs.init_code);
349 inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
350 }
351 CreateScheme::Custom { address } => address,
352 };
353
354 context.journal().load_account(created_address)?;
356
357 let checkpoint = match context.journal().create_account_checkpoint(
359 inputs.caller,
360 created_address,
361 inputs.value,
362 spec,
363 ) {
364 Ok(checkpoint) => checkpoint,
365 Err(e) => return return_error(e.into()),
366 };
367
368 let bytecode = ExtBytecode::new_with_hash(
369 Bytecode::new_legacy(inputs.init_code.clone()),
370 init_code_hash,
371 );
372
373 let interpreter_input = InputsImpl {
374 target_address: created_address,
375 caller_address: inputs.caller,
376 bytecode_address: None,
377 input: CallInput::Bytes(Bytes::new()),
378 call_value: inputs.value,
379 };
380 let gas_limit = inputs.gas_limit;
381
382 Ok(ItemOrResult::Item(Self::new(
383 FrameData::Create(CreateFrame { created_address }),
384 FrameInput::Create(inputs),
385 depth,
386 Interpreter::new(
387 memory,
388 bytecode,
389 interpreter_input,
390 false,
391 false,
392 spec,
393 gas_limit,
394 ),
395 checkpoint,
396 )))
397 }
398
399 #[inline]
401 pub fn make_eofcreate_frame(
402 evm: &mut EVM,
403 depth: usize,
404 memory: SharedMemory,
405 inputs: Box<EOFCreateInputs>,
406 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
407 let context = evm.ctx();
408 let spec = context.cfg().spec().into();
409 let return_error = |e| {
410 Ok(ItemOrResult::Result(FrameResult::EOFCreate(
411 CreateOutcome {
412 result: InterpreterResult {
413 result: e,
414 gas: Gas::new(inputs.gas_limit),
415 output: Bytes::new(),
416 },
417 address: None,
418 },
419 )))
420 };
421
422 let (input, initcode, created_address) = match &inputs.kind {
423 EOFCreateKind::Opcode {
424 initcode,
425 input,
426 created_address,
427 } => (input.clone(), initcode.clone(), Some(*created_address)),
428 EOFCreateKind::Tx { initdata } => {
429 let Ok((eof, input)) = Eof::decode_dangling(initdata.clone()) else {
432 context.journal().inc_account_nonce(inputs.caller)?;
433 return return_error(InstructionResult::InvalidEOFInitCode);
434 };
435
436 if eof.validate().is_err() {
437 context.journal().inc_account_nonce(inputs.caller)?;
439 return return_error(InstructionResult::InvalidEOFInitCode);
440 }
441
442 let tx = context.tx();
444 let create_address = tx.caller().create(tx.nonce());
445
446 (CallInput::Bytes(input), eof, Some(create_address))
447 }
448 };
449
450 if depth > CALL_STACK_LIMIT as usize {
452 return return_error(InstructionResult::CallTooDeep);
453 }
454
455 let caller_balance = context
457 .journal()
458 .load_account(inputs.caller)?
459 .map(|a| a.info.balance);
460
461 if caller_balance.data < inputs.value {
463 return return_error(InstructionResult::OutOfFunds);
464 }
465
466 let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? else {
468 return return_error(InstructionResult::Return);
470 };
471 let old_nonce = nonce - 1;
472
473 let created_address = created_address.unwrap_or_else(|| inputs.caller.create(old_nonce));
474
475 context.journal().load_account(created_address)?;
477
478 let checkpoint = match context.journal().create_account_checkpoint(
480 inputs.caller,
481 created_address,
482 inputs.value,
483 spec,
484 ) {
485 Ok(checkpoint) => checkpoint,
486 Err(e) => return return_error(e.into()),
487 };
488
489 let interpreter_input = InputsImpl {
490 target_address: created_address,
491 caller_address: inputs.caller,
492 bytecode_address: None,
493 input,
494 call_value: inputs.value,
495 };
496
497 let gas_limit = inputs.gas_limit;
498 Ok(ItemOrResult::Item(Self::new(
499 FrameData::EOFCreate(EOFCreateFrame { created_address }),
500 FrameInput::EOFCreate(inputs),
501 depth,
502 Interpreter::new(
503 memory,
504 ExtBytecode::new(Bytecode::Eof(Arc::new(initcode))),
505 interpreter_input,
506 false,
507 true,
508 spec,
509 gas_limit,
510 ),
511 checkpoint,
512 )))
513 }
514
515 pub fn init_with_context(
516 evm: &mut EVM,
517 depth: usize,
518 frame_init: FrameInput,
519 memory: SharedMemory,
520 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
521 match frame_init {
522 FrameInput::Call(inputs) => Self::make_call_frame(evm, depth, memory, inputs),
523 FrameInput::Create(inputs) => Self::make_create_frame(evm, depth, memory, inputs),
524 FrameInput::EOFCreate(inputs) => Self::make_eofcreate_frame(evm, depth, memory, inputs),
525 }
526 }
527}
528
529impl<EVM, ERROR> EthFrame<EVM, ERROR, EthInterpreter>
530where
531 EVM: EvmTr<
532 Context: ContextTr,
533 Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
534 Instructions: InstructionProvider<
535 Context = EVM::Context,
536 InterpreterTypes = EthInterpreter,
537 >,
538 >,
539 ERROR: From<ContextTrDbError<EVM::Context>> + FromStringError,
540{
541 pub fn process_next_action(
542 &mut self,
543 evm: &mut EVM,
544 next_action: InterpreterAction,
545 ) -> Result<FrameInitOrResult<Self>, ERROR> {
546 let context = evm.ctx();
547 let spec = context.cfg().spec().into();
548
549 let mut interpreter_result = match next_action {
552 InterpreterAction::NewFrame(new_frame) => return Ok(ItemOrResult::Item(new_frame)),
553 InterpreterAction::Return { result } => result,
554 InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"),
555 };
556
557 let result = match &self.data {
559 FrameData::Call(frame) => {
560 if interpreter_result.result.is_ok() {
563 context.journal().checkpoint_commit();
564 } else {
565 context.journal().checkpoint_revert(self.checkpoint);
566 }
567 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
568 interpreter_result,
569 frame.return_memory_range.clone(),
570 )))
571 }
572 FrameData::Create(frame) => {
573 let max_code_size = context.cfg().max_code_size();
574 return_create(
575 context.journal(),
576 self.checkpoint,
577 &mut interpreter_result,
578 frame.created_address,
579 max_code_size,
580 spec,
581 );
582
583 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
584 interpreter_result,
585 Some(frame.created_address),
586 )))
587 }
588 FrameData::EOFCreate(frame) => {
589 let max_code_size = context.cfg().max_code_size();
590 return_eofcreate(
591 context.journal(),
592 self.checkpoint,
593 &mut interpreter_result,
594 frame.created_address,
595 max_code_size,
596 );
597
598 ItemOrResult::Result(FrameResult::EOFCreate(CreateOutcome::new(
599 interpreter_result,
600 Some(frame.created_address),
601 )))
602 }
603 };
604
605 Ok(result)
606 }
607
608 fn return_result(&mut self, evm: &mut EVM, result: FrameResult) -> Result<(), ERROR> {
609 self.interpreter.memory.free_child_context();
610 match core::mem::replace(evm.ctx().error(), Ok(())) {
611 Err(ContextError::Db(e)) => return Err(e.into()),
612 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
613 Ok(_) => (),
614 }
615
616 match result {
618 FrameResult::Call(outcome) => {
619 let out_gas = outcome.gas();
620 let ins_result = *outcome.instruction_result();
621 let returned_len = outcome.result.output.len();
622
623 let interpreter = &mut self.interpreter;
624 let mem_length = outcome.memory_length();
625 let mem_start = outcome.memory_start();
626 interpreter.return_data.set_buffer(outcome.result.output);
627
628 let target_len = min(mem_length, returned_len);
629
630 if ins_result == InstructionResult::FatalExternalError {
631 panic!("Fatal external error in insert_call_outcome");
632 }
633
634 let item = {
635 if interpreter.runtime_flag.is_eof() {
636 match ins_result {
637 return_ok!() => U256::ZERO,
638 return_revert!() => U256::from(1),
639 _ => U256::from(2),
640 }
641 } else if ins_result.is_ok() {
642 U256::from(1)
643 } else {
644 U256::ZERO
645 }
646 };
647 let _ = interpreter.stack.push(item);
649
650 if ins_result.is_ok_or_revert() {
652 interpreter
653 .control
654 .gas_mut()
655 .erase_cost(out_gas.remaining());
656 interpreter
657 .memory
658 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
659 }
660
661 if ins_result.is_ok() {
662 interpreter
663 .control
664 .gas_mut()
665 .record_refund(out_gas.refunded());
666 }
667 }
668 FrameResult::Create(outcome) => {
669 let instruction_result = *outcome.instruction_result();
670 let interpreter = &mut self.interpreter;
671
672 if instruction_result == InstructionResult::Revert {
673 interpreter
675 .return_data
676 .set_buffer(outcome.output().to_owned());
677 } else {
678 interpreter.return_data.clear();
680 };
681
682 assert_ne!(
683 instruction_result,
684 InstructionResult::FatalExternalError,
685 "Fatal external error in insert_eofcreate_outcome"
686 );
687
688 let this_gas = interpreter.control.gas_mut();
689 if instruction_result.is_ok_or_revert() {
690 this_gas.erase_cost(outcome.gas().remaining());
691 }
692
693 let stack_item = if instruction_result.is_ok() {
694 this_gas.record_refund(outcome.gas().refunded());
695 outcome.address.unwrap_or_default().into_word().into()
696 } else {
697 U256::ZERO
698 };
699
700 let _ = interpreter.stack.push(stack_item);
702 }
703 FrameResult::EOFCreate(outcome) => {
704 let instruction_result = *outcome.instruction_result();
705 let interpreter = &mut self.interpreter;
706 if instruction_result == InstructionResult::Revert {
707 interpreter
709 .return_data
710 .set_buffer(outcome.output().to_owned());
711 } else {
712 interpreter.return_data.clear()
714 };
715
716 assert_ne!(
717 instruction_result,
718 InstructionResult::FatalExternalError,
719 "Fatal external error in insert_eofcreate_outcome"
720 );
721
722 let this_gas = interpreter.control.gas_mut();
723 if instruction_result.is_ok_or_revert() {
724 this_gas.erase_cost(outcome.gas().remaining());
725 }
726
727 let stack_item = if instruction_result.is_ok() {
728 this_gas.record_refund(outcome.gas().refunded());
729 outcome.address.expect("EOF Address").into_word().into()
730 } else {
731 U256::ZERO
732 };
733
734 let _ = interpreter.stack.push(stack_item);
736 }
737 }
738
739 Ok(())
740 }
741}
742
743pub fn return_create<JOURNAL: JournalTr>(
744 journal: &mut JOURNAL,
745 checkpoint: JournalCheckpoint,
746 interpreter_result: &mut InterpreterResult,
747 address: Address,
748 max_code_size: usize,
749 spec_id: SpecId,
750) {
751 if !interpreter_result.result.is_ok() {
753 journal.checkpoint_revert(checkpoint);
754 return;
755 }
756 if spec_id.is_enabled_in(LONDON) && interpreter_result.output.first() == Some(&0xEF) {
761 journal.checkpoint_revert(checkpoint);
762 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
763 return;
764 }
765
766 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
769 journal.checkpoint_revert(checkpoint);
770 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
771 return;
772 }
773 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
774 if !interpreter_result.gas.record_cost(gas_for_code) {
775 if spec_id.is_enabled_in(HOMESTEAD) {
780 journal.checkpoint_revert(checkpoint);
781 interpreter_result.result = InstructionResult::OutOfGas;
782 return;
783 } else {
784 interpreter_result.output = Bytes::new();
785 }
786 }
787 journal.checkpoint_commit();
789
790 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
792
793 journal.set_code(address, bytecode);
795
796 interpreter_result.result = InstructionResult::Return;
797}
798
799pub fn return_eofcreate<JOURNAL: JournalTr>(
800 journal: &mut JOURNAL,
801 checkpoint: JournalCheckpoint,
802 interpreter_result: &mut InterpreterResult,
803 address: Address,
804 max_code_size: usize,
805) {
806 if interpreter_result.result != InstructionResult::ReturnContract {
814 journal.checkpoint_revert(checkpoint);
815 return;
816 }
817
818 if interpreter_result.output.len() > max_code_size {
819 journal.checkpoint_revert(checkpoint);
820 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
821 return;
822 }
823
824 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
826 if !interpreter_result.gas.record_cost(gas_for_code) {
827 journal.checkpoint_revert(checkpoint);
828 interpreter_result.result = InstructionResult::OutOfGas;
829 return;
830 }
831
832 journal.checkpoint_commit();
833
834 let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
836
837 journal.set_code(address, Bytecode::Eof(Arc::new(bytecode)));
839}