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,
14};
15use core::cmp::min;
16use interpreter::{
17 gas,
18 interpreter::{EthInterpreter, ExtBytecode},
19 interpreter_types::{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_mut()
189 .load_account_delegated(inputs.bytecode_address)?;
190
191 let checkpoint = context.journal_mut().checkpoint();
193
194 if let CallValue::Transfer(value) = inputs.value {
196 if let Some(i) =
199 context
200 .journal_mut()
201 .transfer(inputs.caller, inputs.target_address, value)?
202 {
203 context.journal_mut().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_mut().checkpoint_commit();
232 } else {
233 context.journal_mut().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_mut()
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_mut()
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_mut().checkpoint_revert(checkpoint);
261 return return_result(InstructionResult::InvalidExtDelegateCallTarget);
262 }
263
264 if bytecode.is_empty() {
266 context.journal_mut().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_info = &mut context.journal_mut().load_account(inputs.caller)?.data.info;
324
325 if caller_info.balance < inputs.value {
327 return return_error(InstructionResult::OutOfFunds);
328 }
329
330 let old_nonce = caller_info.nonce;
332 let Some(new_nonce) = old_nonce.checked_add(1) else {
333 return return_error(InstructionResult::Return);
334 };
335 caller_info.nonce = new_nonce;
336 context
337 .journal_mut()
338 .nonce_bump_journal_entry(inputs.caller);
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 CreateScheme::Custom { address } => address,
349 };
350
351 context.journal_mut().load_account(created_address)?;
353
354 let checkpoint = match context.journal_mut().create_account_checkpoint(
356 inputs.caller,
357 created_address,
358 inputs.value,
359 spec,
360 ) {
361 Ok(checkpoint) => checkpoint,
362 Err(e) => return return_error(e.into()),
363 };
364
365 let bytecode = ExtBytecode::new_with_hash(
366 Bytecode::new_legacy(inputs.init_code.clone()),
367 init_code_hash,
368 );
369
370 let interpreter_input = InputsImpl {
371 target_address: created_address,
372 caller_address: inputs.caller,
373 bytecode_address: None,
374 input: CallInput::Bytes(Bytes::new()),
375 call_value: inputs.value,
376 };
377 let gas_limit = inputs.gas_limit;
378
379 Ok(ItemOrResult::Item(Self::new(
380 FrameData::Create(CreateFrame { created_address }),
381 FrameInput::Create(inputs),
382 depth,
383 Interpreter::new(
384 memory,
385 bytecode,
386 interpreter_input,
387 false,
388 false,
389 spec,
390 gas_limit,
391 ),
392 checkpoint,
393 )))
394 }
395
396 #[inline]
398 pub fn make_eofcreate_frame(
399 evm: &mut EVM,
400 depth: usize,
401 memory: SharedMemory,
402 inputs: Box<EOFCreateInputs>,
403 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
404 let context = evm.ctx();
405 let spec = context.cfg().spec().into();
406 let return_error = |e| {
407 Ok(ItemOrResult::Result(FrameResult::EOFCreate(
408 CreateOutcome {
409 result: InterpreterResult {
410 result: e,
411 gas: Gas::new(inputs.gas_limit),
412 output: Bytes::new(),
413 },
414 address: None,
415 },
416 )))
417 };
418
419 let (input, initcode, created_address) = match &inputs.kind {
420 EOFCreateKind::Opcode {
421 initcode,
422 input,
423 created_address,
424 } => (input.clone(), initcode.clone(), Some(*created_address)),
425 EOFCreateKind::Tx { .. } => {
426 unreachable!("EOF is disabled");
443 }
445 };
446
447 if depth > CALL_STACK_LIMIT as usize {
449 return return_error(InstructionResult::CallTooDeep);
450 }
451
452 let caller = context.journal_mut().load_account(inputs.caller)?.data;
454
455 if caller.info.balance < inputs.value {
457 return return_error(InstructionResult::OutOfFunds);
458 }
459
460 let Some(new_nonce) = caller.info.nonce.checked_add(1) else {
462 return return_error(InstructionResult::Return);
464 };
465 caller.info.nonce = new_nonce;
466 context
467 .journal_mut()
468 .nonce_bump_journal_entry(inputs.caller);
469
470 let old_nonce = new_nonce - 1;
471
472 let created_address = created_address.unwrap_or_else(|| inputs.caller.create(old_nonce));
473
474 context.journal_mut().load_account(created_address)?;
476
477 let checkpoint = match context.journal_mut().create_account_checkpoint(
479 inputs.caller,
480 created_address,
481 inputs.value,
482 spec,
483 ) {
484 Ok(checkpoint) => checkpoint,
485 Err(e) => return return_error(e.into()),
486 };
487
488 let interpreter_input = InputsImpl {
489 target_address: created_address,
490 caller_address: inputs.caller,
491 bytecode_address: None,
492 input,
493 call_value: inputs.value,
494 };
495
496 let gas_limit = inputs.gas_limit;
497 Ok(ItemOrResult::Item(Self::new(
498 FrameData::EOFCreate(EOFCreateFrame { created_address }),
499 FrameInput::EOFCreate(inputs),
500 depth,
501 Interpreter::new(
502 memory,
503 ExtBytecode::new(Bytecode::Eof(initcode)),
504 interpreter_input,
505 false,
506 true,
507 spec,
508 gas_limit,
509 ),
510 checkpoint,
511 )))
512 }
513
514 pub fn init_with_context(
515 evm: &mut EVM,
516 depth: usize,
517 frame_init: FrameInput,
518 memory: SharedMemory,
519 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
520 match frame_init {
521 FrameInput::Call(inputs) => Self::make_call_frame(evm, depth, memory, inputs),
522 FrameInput::Create(inputs) => Self::make_create_frame(evm, depth, memory, inputs),
523 FrameInput::EOFCreate(inputs) => Self::make_eofcreate_frame(evm, depth, memory, inputs),
524 }
525 }
526}
527
528impl<EVM, ERROR> EthFrame<EVM, ERROR, EthInterpreter>
529where
530 EVM: EvmTr<
531 Context: ContextTr,
532 Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
533 Instructions: InstructionProvider<
534 Context = EVM::Context,
535 InterpreterTypes = EthInterpreter,
536 >,
537 >,
538 ERROR: From<ContextTrDbError<EVM::Context>> + FromStringError,
539{
540 pub fn process_next_action(
541 &mut self,
542 evm: &mut EVM,
543 next_action: InterpreterAction,
544 ) -> Result<FrameInitOrResult<Self>, ERROR> {
545 let context = evm.ctx();
546 let spec = context.cfg().spec().into();
547
548 let mut interpreter_result = match next_action {
551 InterpreterAction::NewFrame(new_frame) => return Ok(ItemOrResult::Item(new_frame)),
552 InterpreterAction::Return(result) => result,
553 };
554
555 let result = match &self.data {
557 FrameData::Call(frame) => {
558 if interpreter_result.result.is_ok() {
561 context.journal_mut().checkpoint_commit();
562 } else {
563 context.journal_mut().checkpoint_revert(self.checkpoint);
564 }
565 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
566 interpreter_result,
567 frame.return_memory_range.clone(),
568 )))
569 }
570 FrameData::Create(frame) => {
571 let max_code_size = context.cfg().max_code_size();
572 return_create(
573 context.journal_mut(),
574 self.checkpoint,
575 &mut interpreter_result,
576 frame.created_address,
577 max_code_size,
578 spec,
579 );
580
581 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
582 interpreter_result,
583 Some(frame.created_address),
584 )))
585 }
586 FrameData::EOFCreate(frame) => {
587 let max_code_size = context.cfg().max_code_size();
588 return_eofcreate(
589 context.journal_mut(),
590 self.checkpoint,
591 &mut interpreter_result,
592 frame.created_address,
593 max_code_size,
594 );
595
596 ItemOrResult::Result(FrameResult::EOFCreate(CreateOutcome::new(
597 interpreter_result,
598 Some(frame.created_address),
599 )))
600 }
601 };
602
603 Ok(result)
604 }
605
606 fn return_result(&mut self, evm: &mut EVM, result: FrameResult) -> Result<(), ERROR> {
607 self.interpreter.memory.free_child_context();
608 match core::mem::replace(evm.ctx().error(), Ok(())) {
609 Err(ContextError::Db(e)) => return Err(e.into()),
610 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
611 Ok(_) => (),
612 }
613
614 match result {
616 FrameResult::Call(outcome) => {
617 let out_gas = outcome.gas();
618 let ins_result = *outcome.instruction_result();
619 let returned_len = outcome.result.output.len();
620
621 let interpreter = &mut self.interpreter;
622 let mem_length = outcome.memory_length();
623 let mem_start = outcome.memory_start();
624 interpreter.return_data.set_buffer(outcome.result.output);
625
626 let target_len = min(mem_length, returned_len);
627
628 if ins_result == InstructionResult::FatalExternalError {
629 panic!("Fatal external error in insert_call_outcome");
630 }
631
632 let item = {
633 if interpreter.runtime_flag.is_eof() {
634 match ins_result {
635 return_ok!() => U256::ZERO,
636 return_revert!() => U256::from(1),
637 _ => U256::from(2),
638 }
639 } else if ins_result.is_ok() {
640 U256::from(1)
641 } else {
642 U256::ZERO
643 }
644 };
645 let _ = interpreter.stack.push(item);
647
648 if ins_result.is_ok_or_revert() {
650 interpreter.gas.erase_cost(out_gas.remaining());
651 interpreter
652 .memory
653 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
654 }
655
656 if ins_result.is_ok() {
657 interpreter.gas.record_refund(out_gas.refunded());
658 }
659 }
660 FrameResult::Create(outcome) => {
661 let instruction_result = *outcome.instruction_result();
662 let interpreter = &mut self.interpreter;
663
664 if instruction_result == InstructionResult::Revert {
665 interpreter
667 .return_data
668 .set_buffer(outcome.output().to_owned());
669 } else {
670 interpreter.return_data.clear();
672 };
673
674 assert_ne!(
675 instruction_result,
676 InstructionResult::FatalExternalError,
677 "Fatal external error in insert_eofcreate_outcome"
678 );
679
680 let this_gas = &mut interpreter.gas;
681 if instruction_result.is_ok_or_revert() {
682 this_gas.erase_cost(outcome.gas().remaining());
683 }
684
685 let stack_item = if instruction_result.is_ok() {
686 this_gas.record_refund(outcome.gas().refunded());
687 outcome.address.unwrap_or_default().into_word().into()
688 } else {
689 U256::ZERO
690 };
691
692 let _ = interpreter.stack.push(stack_item);
694 }
695 FrameResult::EOFCreate(outcome) => {
696 let instruction_result = *outcome.instruction_result();
697 let interpreter = &mut self.interpreter;
698 if instruction_result == InstructionResult::Revert {
699 interpreter
701 .return_data
702 .set_buffer(outcome.output().to_owned());
703 } else {
704 interpreter.return_data.clear()
706 };
707
708 assert_ne!(
709 instruction_result,
710 InstructionResult::FatalExternalError,
711 "Fatal external error in insert_eofcreate_outcome"
712 );
713
714 let this_gas = &mut interpreter.gas;
715 if instruction_result.is_ok_or_revert() {
716 this_gas.erase_cost(outcome.gas().remaining());
717 }
718
719 let stack_item = if instruction_result.is_ok() {
720 this_gas.record_refund(outcome.gas().refunded());
721 outcome.address.expect("EOF Address").into_word().into()
722 } else {
723 U256::ZERO
724 };
725
726 let _ = interpreter.stack.push(stack_item);
728 }
729 }
730
731 Ok(())
732 }
733}
734
735pub fn return_create<JOURNAL: JournalTr>(
736 journal: &mut JOURNAL,
737 checkpoint: JournalCheckpoint,
738 interpreter_result: &mut InterpreterResult,
739 address: Address,
740 max_code_size: usize,
741 spec_id: SpecId,
742) {
743 if !interpreter_result.result.is_ok() {
745 journal.checkpoint_revert(checkpoint);
746 return;
747 }
748 if spec_id.is_enabled_in(LONDON) && interpreter_result.output.first() == Some(&0xEF) {
753 journal.checkpoint_revert(checkpoint);
754 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
755 return;
756 }
757
758 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
761 journal.checkpoint_revert(checkpoint);
762 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
763 return;
764 }
765 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
766 if !interpreter_result.gas.record_cost(gas_for_code) {
767 if spec_id.is_enabled_in(HOMESTEAD) {
772 journal.checkpoint_revert(checkpoint);
773 interpreter_result.result = InstructionResult::OutOfGas;
774 return;
775 } else {
776 interpreter_result.output = Bytes::new();
777 }
778 }
779 journal.checkpoint_commit();
781
782 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
784
785 journal.set_code(address, bytecode);
787
788 interpreter_result.result = InstructionResult::Return;
789}
790
791pub fn return_eofcreate<JOURNAL: JournalTr>(
792 journal: &mut JOURNAL,
793 checkpoint: JournalCheckpoint,
794 interpreter_result: &mut InterpreterResult,
795 address: Address,
796 max_code_size: usize,
797) {
798 if interpreter_result.result != InstructionResult::ReturnContract {
806 journal.checkpoint_revert(checkpoint);
807 return;
808 }
809
810 if interpreter_result.output.len() > max_code_size {
811 journal.checkpoint_revert(checkpoint);
812 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
813 return;
814 }
815
816 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
818 if !interpreter_result.gas.record_cost(gas_for_code) {
819 journal.checkpoint_revert(checkpoint);
820 interpreter_result.result = InstructionResult::OutOfGas;
821 return;
822 }
823
824 journal.checkpoint_commit();
825
826 let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
828
829 journal.set_code(address, Bytecode::Eof(Arc::new(bytecode)));
831}