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::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
34/// Call frame trait
35pub 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 of the frame.
64    data: FrameData,
65    /// Input data for the frame.
66    pub input: FrameInput,
67    /// Depth of the call frame.
68    depth: usize,
69    /// Journal checkpoint.
70    pub checkpoint: JournalCheckpoint,
71    /// Interpreter.
72    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        // Create new context from shared memory.
106        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    /// Make call frame
159    #[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        // Check depth
182        if depth > CALL_STACK_LIMIT as usize {
183            return return_result(InstructionResult::CallTooDeep);
184        }
185
186        // Make account warm and loaded.
187        let _ = context
188            .journal_mut()
189            .load_account_delegated(inputs.bytecode_address)?;
190
191        // Create subroutine checkpoint
192        let checkpoint = context.journal_mut().checkpoint();
193
194        // Touch address. For "EIP-158 State Clear", this will erase empty accounts.
195        if let CallValue::Transfer(value) = inputs.value {
196            // Transfer value from caller to called account
197            // Target will get touched even if balance transferred is zero.
198            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        // ExtDelegateCall is not allowed to call non-EOF contracts.
259        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        // Returns success if bytecode is empty.
265        if bytecode.is_empty() {
266            context.journal_mut().checkpoint_commit();
267            return return_result(InstructionResult::Stop);
268        }
269
270        // Create interpreter and executes call and push new CallStackFrame.
271        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    /// Make create frame.
291    #[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        // Check depth
312        if depth > CALL_STACK_LIMIT as usize {
313            return return_error(InstructionResult::CallTooDeep);
314        }
315
316        // Prague EOF
317        // TODO(EOF)
318        // if spec.is_enabled_in(OSAKA) && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) {
319        //     return return_error(InstructionResult::CreateInitCodeStartingEF00);
320        // }
321
322        // Fetch balance of caller.
323        let caller_info = &mut context.journal_mut().load_account(inputs.caller)?.data.info;
324
325        // Check if caller has enough balance to send to the created contract.
326        if caller_info.balance < inputs.value {
327            return return_error(InstructionResult::OutOfFunds);
328        }
329
330        // Increase nonce of caller and check if it overflows
331        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        // Create address
341        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        // warm load account.
352        context.journal_mut().load_account(created_address)?;
353
354        // Create account, transfer funds and make the journal checkpoint.
355        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    /// Make create frame.
397    #[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                // Decode eof and init code.
427                // TODO : Handle inc_nonce handling more gracefully.
428                // let Ok((eof, input)) = Eof::decode_dangling(initdata.clone()) else {
429                //     context.journal_mut().inc_account_nonce(inputs.caller)?;
430                //     return return_error(InstructionResult::InvalidEOFInitCode);
431                // };
432
433                // if eof.validate().is_err() {
434                //     // TODO : (EOF) New error type.
435                //     context.journal_mut().inc_account_nonce(inputs.caller)?;
436                //     return return_error(InstructionResult::InvalidEOFInitCode);
437                // }
438
439                // // Use nonce from tx to calculate address.
440                // let tx = context.tx();
441                // let create_address = tx.caller().create(tx.nonce());
442                unreachable!("EOF is disabled");
443                //(CallInput::Bytes(input), eof, Some(create_address))
444            }
445        };
446
447        // Check depth
448        if depth > CALL_STACK_LIMIT as usize {
449            return return_error(InstructionResult::CallTooDeep);
450        }
451
452        // Fetch balance of caller.
453        let caller = context.journal_mut().load_account(inputs.caller)?.data;
454
455        // Check if caller has enough balance to send to the created contract.
456        if caller.info.balance < inputs.value {
457            return return_error(InstructionResult::OutOfFunds);
458        }
459
460        // Increase nonce of caller and check if it overflows
461        let Some(new_nonce) = caller.info.nonce.checked_add(1) else {
462            // Can't happen on mainnet.
463            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        // Load account so it needs to be marked as warm for access list.
475        context.journal_mut().load_account(created_address)?;
476
477        // Create account, transfer funds and make the journal checkpoint.
478        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        // Run interpreter
549
550        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        // Handle return from frame
556        let result = match &self.data {
557            FrameData::Call(frame) => {
558                // return_call
559                // Revert changes or not.
560                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        // Insert result to the top frame.
615        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                // Safe to push without stack limit check
646                let _ = interpreter.stack.push(item);
647
648                // Return unspend gas.
649                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                    // Save data to return data buffer if the create reverted
666                    interpreter
667                        .return_data
668                        .set_buffer(outcome.output().to_owned());
669                } else {
670                    // Otherwise clear it. Note that RETURN opcode should abort.
671                    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                // Safe to push without stack limit check
693                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                    // Save data to return data buffer if the create reverted
700                    interpreter
701                        .return_data
702                        .set_buffer(outcome.output().to_owned());
703                } else {
704                    // Otherwise clear it. Note that RETURN opcode should abort.
705                    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                // Safe to push without stack limit check
727                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 return is not ok revert and return.
744    if !interpreter_result.result.is_ok() {
745        journal.checkpoint_revert(checkpoint);
746        return;
747    }
748    // Host error if present on execution
749    // If ok, check contract creation limit and calculate gas deduction on output len.
750    //
751    // EIP-3541: Reject new contract code starting with the 0xEF byte
752    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    // EIP-170: Contract code size limit
759    // By default limit is 0x6000 (~25kb)
760    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        // Record code deposit gas cost and check if we are out of gas.
768        // EIP-2 point 3: If contract creation does not have enough gas to pay for the
769        // final gas fee for adding the contract code to the state, the contract
770        // creation fails (i.e. goes out-of-gas) rather than leaving an empty contract.
771        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    // If we have enough gas we can commit changes.
780    journal.checkpoint_commit();
781
782    // Do analysis of bytecode straight away.
783    let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
784
785    // Set code
786    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    // Note we still execute RETURN opcode and return the bytes.
799    // In EOF those opcodes should abort execution.
800    //
801    // In RETURN gas is still protecting us from ddos and in oog,
802    // behaviour will be same as if it failed on return.
803    //
804    // Bytes of RETURN will drained in `insert_eofcreate_outcome`.
805    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    // Deduct gas for code deployment.
817    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    // Decode bytecode has a performance hit, but it has reasonable restrains.
827    let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
828
829    // Eof bytecode is going to be hashed.
830    journal.set_code(address, Bytecode::Eof(Arc::new(bytecode)));
831}