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