revm_handler/
frame.rs

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