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