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
31pub 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: FrameData,
62 pub input: FrameInput,
64 depth: usize,
66 pub checkpoint: JournalCheckpoint,
68 pub interpreter: Interpreter<IW>,
70 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 #[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 if depth > CALL_STACK_LIMIT as usize {
180 return return_result(InstructionResult::CallTooDeep);
181 }
182
183 let _ = context
185 .journal()
186 .load_account_delegated(inputs.bytecode_address)?;
187
188 let checkpoint = context.journal().checkpoint();
190
191 if let CallValue::Transfer(value) = inputs.value {
193 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 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 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 #[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 if depth > CALL_STACK_LIMIT as usize {
303 return return_error(InstructionResult::CallTooDeep);
304 }
305
306 if spec.is_enabled_in(OSAKA) && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) {
308 return return_error(InstructionResult::CreateInitCodeStartingEF00);
309 }
310
311 let caller_balance = context
313 .journal()
314 .load_account(inputs.caller)?
315 .map(|a| a.info.balance);
316
317 if caller_balance.data < inputs.value {
319 return return_error(InstructionResult::OutOfFunds);
320 }
321
322 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 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 context.journal().load_account(created_address)?;
342
343 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 #[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 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 context.journal().inc_account_nonce(inputs.caller)?;
424 return return_error(InstructionResult::InvalidEOFInitCode);
425 }
426
427 let tx = context.tx();
429 let create_address = tx.caller().create(tx.nonce());
430
431 (input, eof, Some(create_address))
432 }
433 };
434
435 if depth > CALL_STACK_LIMIT as usize {
437 return return_error(InstructionResult::CallTooDeep);
438 }
439
440 let caller_balance = context
442 .journal()
443 .load_account(inputs.caller)?
444 .map(|a| a.info.balance);
445
446 if caller_balance.data < inputs.value {
448 return return_error(InstructionResult::OutOfFunds);
449 }
450
451 let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? else {
453 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 context.journal().load_account(created_address)?;
462
463 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 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 let result = match &self.data {
569 FrameData::Call(frame) => {
570 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 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 let _ = interpreter.stack.push(item);
655
656 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 *buffer = outcome.output().to_owned()
676 } else {
677 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 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 *interpreter.return_data.buffer_mut() = outcome.output().to_owned()
708 } else {
709 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 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 !interpreter_result.result.is_ok() {
750 journal.checkpoint_revert(checkpoint);
751 return;
752 }
753 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 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 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 journal.checkpoint_commit();
786
787 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
789
790 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 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 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 let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
833
834 journal.set_code(address, Bytecode::Eof(Arc::new(bytecode)));
836}