revm_handler/
frame.rs

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_interface::context::ContextError;
9use context_interface::ContextTr;
10use context_interface::{
11    journaled_state::{JournalCheckpoint, JournalTr},
12    Cfg, Database, Transaction,
13};
14use core::{cell::RefCell, cmp::min};
15use interpreter::{
16    gas,
17    interpreter::{EthInterpreter, ExtBytecode},
18    interpreter_types::{LoopControl, ReturnData, RuntimeFlag},
19    return_ok, return_revert, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome,
20    CreateScheme, EOFCreateInputs, EOFCreateKind, FrameInput, Gas, InputsImpl, InstructionResult,
21    Interpreter, InterpreterAction, InterpreterResult, InterpreterTypes, SharedMemory,
22};
23use primitives::{
24    constants::CALL_STACK_LIMIT,
25    hardfork::SpecId::{self, HOMESTEAD, LONDON, OSAKA, SPURIOUS_DRAGON},
26};
27use primitives::{keccak256, Address, Bytes, B256, U256};
28use state::Bytecode;
29use std::borrow::ToOwned;
30use std::{boxed::Box, rc::Rc, sync::Arc};
31
32/// Call frame trait
33pub trait Frame: Sized {
34    type Evm;
35    type FrameInit;
36    type FrameResult;
37    type Error;
38
39    fn init_first(
40        evm: &mut Self::Evm,
41        frame_input: Self::FrameInit,
42    ) -> Result<FrameOrResult<Self>, Self::Error>;
43
44    fn init(
45        &self,
46        evm: &mut Self::Evm,
47        frame_input: Self::FrameInit,
48    ) -> Result<FrameOrResult<Self>, Self::Error>;
49
50    fn run(&mut self, evm: &mut Self::Evm) -> Result<FrameInitOrResult<Self>, Self::Error>;
51
52    fn return_result(
53        &mut self,
54        evm: &mut Self::Evm,
55        result: Self::FrameResult,
56    ) -> Result<(), Self::Error>;
57}
58
59pub struct EthFrame<EVM, ERROR, IW: InterpreterTypes> {
60    phantom: core::marker::PhantomData<(EVM, ERROR)>,
61    /// Data of the frame.
62    data: FrameData,
63    /// Input data for the frame.
64    pub input: FrameInput,
65    /// Depth of the call frame.
66    depth: usize,
67    /// Journal checkpoint.
68    pub checkpoint: JournalCheckpoint,
69    /// Interpreter.
70    pub interpreter: Interpreter<IW>,
71    // This is worth making as a generic type FrameSharedContext.
72    pub memory: Rc<RefCell<SharedMemory>>,
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        EthFrame::init_first(evm, frame_input)
96    }
97
98    fn init(
99        &self,
100        evm: &mut Self::Evm,
101        frame_input: Self::FrameInit,
102    ) -> Result<FrameOrResult<Self>, Self::Error> {
103        self.init(evm, frame_input)
104    }
105
106    fn run(&mut self, context: &mut Self::Evm) -> Result<FrameInitOrResult<Self>, Self::Error> {
107        let next_action = context.run_interpreter(&mut self.interpreter);
108        self.process_next_action(context, next_action)
109    }
110
111    fn return_result(
112        &mut self,
113        context: &mut Self::Evm,
114        result: Self::FrameResult,
115    ) -> Result<(), Self::Error> {
116        self.return_result(context, result)
117    }
118}
119
120pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
121
122impl<CTX, ERROR, IW> EthFrame<CTX, ERROR, IW>
123where
124    IW: InterpreterTypes,
125{
126    pub fn new(
127        data: FrameData,
128        input: FrameInput,
129        depth: usize,
130        interpreter: Interpreter<IW>,
131        checkpoint: JournalCheckpoint,
132        memory: Rc<RefCell<SharedMemory>>,
133    ) -> Self {
134        Self {
135            phantom: Default::default(),
136            input,
137            data,
138            depth,
139            interpreter,
140            checkpoint,
141            memory,
142        }
143    }
144}
145
146impl<EVM, ERROR> EthFrame<EVM, ERROR, EthInterpreter>
147where
148    EVM: EvmTr<
149        Context: ContextTr,
150        Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
151        Instructions: InstructionProvider,
152    >,
153    ERROR: From<ContextTrDbError<EVM::Context>>,
154    ERROR: FromStringError,
155{
156    /// Make call frame
157    #[inline]
158    pub fn make_call_frame(
159        evm: &mut EVM,
160        depth: usize,
161        memory: Rc<RefCell<SharedMemory>>,
162        inputs: Box<CallInputs>,
163    ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
164        let gas = Gas::new(inputs.gas_limit);
165
166        let (context, precompiles) = evm.ctx_precompiles();
167
168        let return_result = |instruction_result: InstructionResult| {
169            Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
170                result: InterpreterResult {
171                    result: instruction_result,
172                    gas,
173                    output: Bytes::new(),
174                },
175                memory_offset: inputs.return_memory_offset.clone(),
176            })))
177        };
178
179        // Check depth
180        if depth > CALL_STACK_LIMIT as usize {
181            return return_result(InstructionResult::CallTooDeep);
182        }
183
184        // Make account warm and loaded
185        let _ = context
186            .journal()
187            .load_account_delegated(inputs.bytecode_address)?;
188
189        // Create subroutine checkpoint
190        let checkpoint = context.journal().checkpoint();
191
192        // Touch address. For "EIP-158 State Clear", this will erase empty accounts.
193        if let CallValue::Transfer(value) = inputs.value {
194            // Transfer value from caller to called account
195            // Target will get touched even if balance transferred is zero.
196            if let Some(i) =
197                context
198                    .journal()
199                    .transfer(&inputs.caller, &inputs.target_address, value)?
200            {
201                context.journal().checkpoint_revert(checkpoint);
202                return return_result(i.into());
203            }
204        }
205        let is_ext_delegate_call = inputs.scheme.is_ext_delegate_call();
206        if !is_ext_delegate_call {
207            if let Some(result) = precompiles
208                .run(
209                    context,
210                    &inputs.bytecode_address,
211                    &inputs.input,
212                    inputs.gas_limit,
213                )
214                .map_err(ERROR::from_string)?
215            {
216                if result.result.is_ok() {
217                    context.journal().checkpoint_commit();
218                } else {
219                    context.journal().checkpoint_revert(checkpoint);
220                }
221                return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
222                    result,
223                    memory_offset: inputs.return_memory_offset.clone(),
224                })));
225            }
226        }
227
228        let account = context
229            .journal()
230            .load_account_code(inputs.bytecode_address)?;
231
232        let mut code_hash = account.info.code_hash();
233        let mut bytecode = account.info.code.clone().unwrap_or_default();
234
235        // ExtDelegateCall is not allowed to call non-EOF contracts.
236        if is_ext_delegate_call && !bytecode.bytes_slice().starts_with(&EOF_MAGIC_BYTES) {
237            context.journal().checkpoint_revert(checkpoint);
238            return return_result(InstructionResult::InvalidExtDelegateCallTarget);
239        }
240
241        if bytecode.is_empty() {
242            context.journal().checkpoint_commit();
243            return return_result(InstructionResult::Stop);
244        }
245
246        if let Bytecode::Eip7702(eip7702_bytecode) = bytecode {
247            let account = &context
248                .journal()
249                .load_account_code(eip7702_bytecode.delegated_address)?
250                .info;
251            bytecode = account.code.clone().unwrap_or_default();
252            code_hash = account.code_hash();
253        }
254
255        // Create interpreter and executes call and push new CallStackFrame.
256        let interpreter_input = InputsImpl {
257            target_address: inputs.target_address,
258            caller_address: inputs.caller,
259            input: inputs.input.clone(),
260            call_value: inputs.value.get(),
261        };
262        let is_static = inputs.is_static;
263        let gas_limit = inputs.gas_limit;
264        Ok(ItemOrResult::Item(Self::new(
265            FrameData::Call(CallFrame {
266                return_memory_range: inputs.return_memory_offset.clone(),
267            }),
268            FrameInput::Call(inputs),
269            depth,
270            Interpreter::new(
271                memory.clone(),
272                ExtBytecode::new_with_hash(bytecode, code_hash),
273                interpreter_input,
274                is_static,
275                false,
276                context.cfg().spec().into(),
277                gas_limit,
278            ),
279            checkpoint,
280            memory,
281        )))
282    }
283
284    /// Make create frame.
285    #[inline]
286    pub fn make_create_frame(
287        evm: &mut EVM,
288        depth: usize,
289        memory: Rc<RefCell<SharedMemory>>,
290        inputs: Box<CreateInputs>,
291    ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
292        let context = evm.ctx();
293        let spec = context.cfg().spec().into();
294        let return_error = |e| {
295            Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome {
296                result: InterpreterResult {
297                    result: e,
298                    gas: Gas::new(inputs.gas_limit),
299                    output: Bytes::new(),
300                },
301                address: None,
302            })))
303        };
304
305        // Check depth
306        if depth > CALL_STACK_LIMIT as usize {
307            return return_error(InstructionResult::CallTooDeep);
308        }
309
310        // Prague EOF
311        if spec.is_enabled_in(OSAKA) && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) {
312            return return_error(InstructionResult::CreateInitCodeStartingEF00);
313        }
314
315        // Fetch balance of caller.
316        let caller_balance = context
317            .journal()
318            .load_account(inputs.caller)?
319            .data
320            .info
321            .balance;
322
323        // Check if caller has enough balance to send to the created contract.
324        if caller_balance < inputs.value {
325            return return_error(InstructionResult::OutOfFunds);
326        }
327
328        // Increase nonce of caller and check if it overflows
329        let old_nonce;
330        if let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? {
331            old_nonce = nonce - 1;
332        } else {
333            return return_error(InstructionResult::Return);
334        }
335
336        // Create address
337        let mut init_code_hash = B256::ZERO;
338        let created_address = match inputs.scheme {
339            CreateScheme::Create => inputs.caller.create(old_nonce),
340            CreateScheme::Create2 { salt } => {
341                init_code_hash = keccak256(&inputs.init_code);
342                inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
343            }
344        };
345
346        // warm load account.
347        context.journal().load_account(created_address)?;
348
349        // Create account, transfer funds and make the journal checkpoint.
350        let checkpoint = match context.journal().create_account_checkpoint(
351            inputs.caller,
352            created_address,
353            inputs.value,
354            spec,
355        ) {
356            Ok(checkpoint) => checkpoint,
357            Err(e) => return return_error(e.into()),
358        };
359
360        let bytecode = ExtBytecode::new_with_hash(
361            Bytecode::new_legacy(inputs.init_code.clone()),
362            init_code_hash,
363        );
364
365        let interpreter_input = InputsImpl {
366            target_address: created_address,
367            caller_address: inputs.caller,
368            input: Bytes::new(),
369            call_value: inputs.value,
370        };
371        let gas_limit = inputs.gas_limit;
372        Ok(ItemOrResult::Item(Self::new(
373            FrameData::Create(CreateFrame { created_address }),
374            FrameInput::Create(inputs),
375            depth,
376            Interpreter::new(
377                memory.clone(),
378                bytecode,
379                interpreter_input,
380                false,
381                false,
382                spec,
383                gas_limit,
384            ),
385            checkpoint,
386            memory,
387        )))
388    }
389
390    /// Make create frame.
391    #[inline]
392    pub fn make_eofcreate_frame(
393        evm: &mut EVM,
394        depth: usize,
395        memory: Rc<RefCell<SharedMemory>>,
396        inputs: Box<EOFCreateInputs>,
397    ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
398        let context = evm.ctx();
399        let spec = context.cfg().spec().into();
400        let return_error = |e| {
401            Ok(ItemOrResult::Result(FrameResult::EOFCreate(
402                CreateOutcome {
403                    result: InterpreterResult {
404                        result: e,
405                        gas: Gas::new(inputs.gas_limit),
406                        output: Bytes::new(),
407                    },
408                    address: None,
409                },
410            )))
411        };
412
413        let (input, initcode, created_address) = match &inputs.kind {
414            EOFCreateKind::Opcode {
415                initcode,
416                input,
417                created_address,
418            } => (input.clone(), initcode.clone(), Some(*created_address)),
419            EOFCreateKind::Tx { initdata } => {
420                // Decode eof and init code.
421                // TODO : Handle inc_nonce handling more gracefully.
422                let Ok((eof, input)) = Eof::decode_dangling(initdata.clone()) else {
423                    context.journal().inc_account_nonce(inputs.caller)?;
424                    return return_error(InstructionResult::InvalidEOFInitCode);
425                };
426
427                if eof.validate().is_err() {
428                    // TODO : (EOF) New error type.
429                    context.journal().inc_account_nonce(inputs.caller)?;
430                    return return_error(InstructionResult::InvalidEOFInitCode);
431                }
432
433                // Use nonce from tx to calculate address.
434                let tx = context.tx();
435                let create_address = tx.caller().create(tx.nonce());
436
437                (input, eof, Some(create_address))
438            }
439        };
440
441        // Check depth
442        if depth > CALL_STACK_LIMIT as usize {
443            return return_error(InstructionResult::CallTooDeep);
444        }
445
446        // Fetch balance of caller.
447        let caller_balance = context
448            .journal()
449            .load_account(inputs.caller)?
450            .map(|a| a.info.balance);
451
452        // Check if caller has enough balance to send to the created contract.
453        if caller_balance.data < inputs.value {
454            return return_error(InstructionResult::OutOfFunds);
455        }
456
457        // Increase nonce of caller and check if it overflows
458        let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? else {
459            // Can't happen on mainnet.
460            return return_error(InstructionResult::Return);
461        };
462        let old_nonce = nonce - 1;
463
464        let created_address = created_address.unwrap_or_else(|| inputs.caller.create(old_nonce));
465
466        // Load account so it needs to be marked as warm for access list.
467        context.journal().load_account(created_address)?;
468
469        // Create account, transfer funds and make the journal checkpoint.
470        let checkpoint = match context.journal().create_account_checkpoint(
471            inputs.caller,
472            created_address,
473            inputs.value,
474            spec,
475        ) {
476            Ok(checkpoint) => checkpoint,
477            Err(e) => return return_error(e.into()),
478        };
479
480        let interpreter_input = InputsImpl {
481            target_address: created_address,
482            caller_address: inputs.caller,
483            input,
484            call_value: inputs.value,
485        };
486
487        let gas_limit = inputs.gas_limit;
488        Ok(ItemOrResult::Item(Self::new(
489            FrameData::EOFCreate(EOFCreateFrame { created_address }),
490            FrameInput::EOFCreate(inputs),
491            depth,
492            Interpreter::new(
493                memory.clone(),
494                ExtBytecode::new(Bytecode::Eof(Arc::new(initcode))),
495                interpreter_input,
496                false,
497                true,
498                spec,
499                gas_limit,
500            ),
501            checkpoint,
502            memory,
503        )))
504    }
505
506    pub fn init_with_context(
507        evm: &mut EVM,
508        depth: usize,
509        frame_init: FrameInput,
510        memory: Rc<RefCell<SharedMemory>>,
511    ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
512        match frame_init {
513            FrameInput::Call(inputs) => Self::make_call_frame(evm, depth, memory, inputs),
514            FrameInput::Create(inputs) => Self::make_create_frame(evm, depth, memory, inputs),
515            FrameInput::EOFCreate(inputs) => Self::make_eofcreate_frame(evm, depth, memory, inputs),
516        }
517    }
518}
519
520impl<EVM, ERROR> EthFrame<EVM, ERROR, EthInterpreter>
521where
522    EVM: EvmTr<
523        Context: ContextTr,
524        Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
525        Instructions: InstructionProvider<
526            Context = EVM::Context,
527            InterpreterTypes = EthInterpreter,
528        >,
529    >,
530    ERROR: From<ContextTrDbError<EVM::Context>> + FromStringError,
531{
532    pub fn init_first(
533        evm: &mut EVM,
534        frame_input: FrameInput,
535    ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
536        let memory = Rc::new(RefCell::new(SharedMemory::new()));
537        let (context, precompiles) = evm.ctx_precompiles();
538        precompiles.set_spec(context.cfg().spec());
539        context
540            .journal()
541            .warm_precompiles(precompiles.warm_addresses().collect());
542
543        memory.borrow_mut().new_context();
544        Self::init_with_context(evm, 0, frame_input, memory)
545    }
546
547    fn init(
548        &self,
549        evm: &mut EVM,
550        frame_init: FrameInput,
551    ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
552        self.memory.borrow_mut().new_context();
553        Self::init_with_context(evm, self.depth + 1, frame_init, self.memory.clone())
554    }
555
556    pub fn process_next_action(
557        &mut self,
558        evm: &mut EVM,
559        next_action: InterpreterAction,
560    ) -> Result<FrameInitOrResult<Self>, ERROR> {
561        let context = evm.ctx();
562        let spec = context.cfg().spec().into();
563
564        // Run interpreter
565
566        let mut interpreter_result = match next_action {
567            InterpreterAction::NewFrame(new_frame) => return Ok(ItemOrResult::Item(new_frame)),
568            InterpreterAction::Return { result } => result,
569            InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"),
570        };
571
572        // Handle return from frame
573        let result = match &self.data {
574            FrameData::Call(frame) => {
575                // return_call
576                // Revert changes or not.
577                if interpreter_result.result.is_ok() {
578                    context.journal().checkpoint_commit();
579                } else {
580                    context.journal().checkpoint_revert(self.checkpoint);
581                }
582                ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
583                    interpreter_result,
584                    frame.return_memory_range.clone(),
585                )))
586            }
587            FrameData::Create(frame) => {
588                let max_code_size = context.cfg().max_code_size();
589                return_create(
590                    context.journal(),
591                    self.checkpoint,
592                    &mut interpreter_result,
593                    frame.created_address,
594                    max_code_size,
595                    spec,
596                );
597
598                ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
599                    interpreter_result,
600                    Some(frame.created_address),
601                )))
602            }
603            FrameData::EOFCreate(frame) => {
604                let max_code_size = context.cfg().max_code_size();
605                return_eofcreate(
606                    context.journal(),
607                    self.checkpoint,
608                    &mut interpreter_result,
609                    frame.created_address,
610                    max_code_size,
611                );
612
613                ItemOrResult::Result(FrameResult::EOFCreate(CreateOutcome::new(
614                    interpreter_result,
615                    Some(frame.created_address),
616                )))
617            }
618        };
619
620        Ok(result)
621    }
622
623    fn return_result(&mut self, evm: &mut EVM, result: FrameResult) -> Result<(), ERROR> {
624        self.memory.borrow_mut().free_context();
625        match core::mem::replace(evm.ctx().error(), Ok(())) {
626            Err(ContextError::Db(e)) => return Err(e.into()),
627            Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
628            Ok(_) => (),
629        }
630
631        // Insert result to the top frame.
632        match result {
633            FrameResult::Call(outcome) => {
634                let out_gas = outcome.gas();
635                let ins_result = *outcome.instruction_result();
636                let returned_len = outcome.result.output.len();
637
638                let interpreter = &mut self.interpreter;
639                let mem_length = outcome.memory_length();
640                let mem_start = outcome.memory_start();
641                interpreter.return_data.set_buffer(outcome.result.output);
642
643                let target_len = min(mem_length, returned_len);
644
645                if ins_result == InstructionResult::FatalExternalError {
646                    panic!("Fatal external error in insert_call_outcome");
647                }
648
649                let item = {
650                    if interpreter.runtime_flag.is_eof() {
651                        match ins_result {
652                            return_ok!() => U256::ZERO,
653                            return_revert!() => U256::from(1),
654                            _ => U256::from(2),
655                        }
656                    } else if ins_result.is_ok() {
657                        U256::from(1)
658                    } else {
659                        U256::ZERO
660                    }
661                };
662                // Safe to push without stack limit check
663                let _ = interpreter.stack.push(item);
664
665                // Return unspend gas.
666                if ins_result.is_ok_or_revert() {
667                    interpreter
668                        .control
669                        .gas_mut()
670                        .erase_cost(out_gas.remaining());
671                    self.memory
672                        .borrow_mut()
673                        .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
674                }
675
676                if ins_result.is_ok() {
677                    interpreter
678                        .control
679                        .gas_mut()
680                        .record_refund(out_gas.refunded());
681                }
682            }
683            FrameResult::Create(outcome) => {
684                let instruction_result = *outcome.instruction_result();
685                let interpreter = &mut self.interpreter;
686
687                if instruction_result == InstructionResult::Revert {
688                    // Save data to return data buffer if the create reverted
689                    interpreter
690                        .return_data
691                        .set_buffer(outcome.output().to_owned());
692                } else {
693                    // Otherwise clear it. Note that RETURN opcode should abort.
694                    interpreter.return_data.clear();
695                };
696
697                assert_ne!(
698                    instruction_result,
699                    InstructionResult::FatalExternalError,
700                    "Fatal external error in insert_eofcreate_outcome"
701                );
702
703                let this_gas = interpreter.control.gas_mut();
704                if instruction_result.is_ok_or_revert() {
705                    this_gas.erase_cost(outcome.gas().remaining());
706                }
707
708                let stack_item = if instruction_result.is_ok() {
709                    this_gas.record_refund(outcome.gas().refunded());
710                    outcome.address.unwrap_or_default().into_word().into()
711                } else {
712                    U256::ZERO
713                };
714
715                // Safe to push without stack limit check
716                let _ = interpreter.stack.push(stack_item);
717            }
718            FrameResult::EOFCreate(outcome) => {
719                let instruction_result = *outcome.instruction_result();
720                let interpreter = &mut self.interpreter;
721                if instruction_result == InstructionResult::Revert {
722                    // Save data to return data buffer if the create reverted
723                    interpreter
724                        .return_data
725                        .set_buffer(outcome.output().to_owned());
726                } else {
727                    // Otherwise clear it. Note that RETURN opcode should abort.
728                    interpreter.return_data.clear()
729                };
730
731                assert_ne!(
732                    instruction_result,
733                    InstructionResult::FatalExternalError,
734                    "Fatal external error in insert_eofcreate_outcome"
735                );
736
737                let this_gas = interpreter.control.gas_mut();
738                if instruction_result.is_ok_or_revert() {
739                    this_gas.erase_cost(outcome.gas().remaining());
740                }
741
742                let stack_item = if instruction_result.is_ok() {
743                    this_gas.record_refund(outcome.gas().refunded());
744                    outcome.address.expect("EOF Address").into_word().into()
745                } else {
746                    U256::ZERO
747                };
748
749                // Safe to push without stack limit check
750                let _ = interpreter.stack.push(stack_item);
751            }
752        }
753
754        Ok(())
755    }
756}
757
758pub fn return_create<JOURNAL: JournalTr>(
759    journal: &mut JOURNAL,
760    checkpoint: JournalCheckpoint,
761    interpreter_result: &mut InterpreterResult,
762    address: Address,
763    max_code_size: usize,
764    spec_id: SpecId,
765) {
766    // If return is not ok revert and return.
767    if !interpreter_result.result.is_ok() {
768        journal.checkpoint_revert(checkpoint);
769        return;
770    }
771    // Host error if present on execution
772    // If ok, check contract creation limit and calculate gas deduction on output len.
773    //
774    // EIP-3541: Reject new contract code starting with the 0xEF byte
775    if spec_id.is_enabled_in(LONDON) && interpreter_result.output.first() == Some(&0xEF) {
776        journal.checkpoint_revert(checkpoint);
777        interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
778        return;
779    }
780
781    // EIP-170: Contract code size limit
782    // By default limit is 0x6000 (~25kb)
783    if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
784        journal.checkpoint_revert(checkpoint);
785        interpreter_result.result = InstructionResult::CreateContractSizeLimit;
786        return;
787    }
788    let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
789    if !interpreter_result.gas.record_cost(gas_for_code) {
790        // Record code deposit gas cost and check if we are out of gas.
791        // EIP-2 point 3: If contract creation does not have enough gas to pay for the
792        // final gas fee for adding the contract code to the state, the contract
793        // creation fails (i.e. goes out-of-gas) rather than leaving an empty contract.
794        if spec_id.is_enabled_in(HOMESTEAD) {
795            journal.checkpoint_revert(checkpoint);
796            interpreter_result.result = InstructionResult::OutOfGas;
797            return;
798        } else {
799            interpreter_result.output = Bytes::new();
800        }
801    }
802    // If we have enough gas we can commit changes.
803    journal.checkpoint_commit();
804
805    // Do analysis of bytecode straight away.
806    let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
807
808    // Set code
809    journal.set_code(address, bytecode);
810
811    interpreter_result.result = InstructionResult::Return;
812}
813
814pub fn return_eofcreate<JOURNAL: JournalTr>(
815    journal: &mut JOURNAL,
816    checkpoint: JournalCheckpoint,
817    interpreter_result: &mut InterpreterResult,
818    address: Address,
819    max_code_size: usize,
820) {
821    // Note we still execute RETURN opcode and return the bytes.
822    // In EOF those opcodes should abort execution.
823    //
824    // In RETURN gas is still protecting us from ddos and in oog,
825    // behaviour will be same as if it failed on return.
826    //
827    // Bytes of RETURN will drained in `insert_eofcreate_outcome`.
828    if interpreter_result.result != InstructionResult::ReturnContract {
829        journal.checkpoint_revert(checkpoint);
830        return;
831    }
832
833    if interpreter_result.output.len() > max_code_size {
834        journal.checkpoint_revert(checkpoint);
835        interpreter_result.result = InstructionResult::CreateContractSizeLimit;
836        return;
837    }
838
839    // Deduct gas for code deployment.
840    let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
841    if !interpreter_result.gas.record_cost(gas_for_code) {
842        journal.checkpoint_revert(checkpoint);
843        interpreter_result.result = InstructionResult::OutOfGas;
844        return;
845    }
846
847    journal.checkpoint_commit();
848
849    // Decode bytecode has a performance hit, but it has reasonable restrains.
850    let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
851
852    // Eof bytecode is going to be hashed.
853    journal.set_code(address, Bytecode::Eof(Arc::new(bytecode)));
854}