revm_handler/
frame.rs

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