revm_rwasm_handler/
frame.rs

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