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
206 let interpreter_input = InputsImpl {
207 target_address: inputs.target_address,
208 caller_address: inputs.caller,
209 input: inputs.input.clone(),
210 call_value: inputs.value.get(),
211 };
212 let is_static = inputs.is_static;
213 let gas_limit = inputs.gas_limit;
214
215 let is_ext_delegate_call = inputs.scheme.is_ext_delegate_call();
216 if !is_ext_delegate_call {
217 if let Some(result) = precompiles
218 .run(
219 context,
220 &inputs.bytecode_address,
221 &interpreter_input,
222 is_static,
223 gas_limit,
224 )
225 .map_err(ERROR::from_string)?
226 {
227 if result.result.is_ok() {
228 context.journal().checkpoint_commit();
229 } else {
230 context.journal().checkpoint_revert(checkpoint);
231 }
232 return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
233 result,
234 memory_offset: inputs.return_memory_offset.clone(),
235 })));
236 }
237 }
238
239 let account = context
240 .journal()
241 .load_account_code(inputs.bytecode_address)?;
242
243 let mut code_hash = account.info.code_hash();
244 let mut bytecode = account.info.code.clone().unwrap_or_default();
245
246 if is_ext_delegate_call && !bytecode.bytes_slice().starts_with(&EOF_MAGIC_BYTES) {
248 context.journal().checkpoint_revert(checkpoint);
249 return return_result(InstructionResult::InvalidExtDelegateCallTarget);
250 }
251
252 if bytecode.is_empty() {
253 context.journal().checkpoint_commit();
254 return return_result(InstructionResult::Stop);
255 }
256
257 if let Bytecode::Eip7702(eip7702_bytecode) = bytecode {
258 let account = &context
259 .journal()
260 .load_account_code(eip7702_bytecode.delegated_address)?
261 .info;
262 bytecode = account.code.clone().unwrap_or_default();
263 code_hash = account.code_hash();
264 }
265
266 Ok(ItemOrResult::Item(Self::new(
268 FrameData::Call(CallFrame {
269 return_memory_range: inputs.return_memory_offset.clone(),
270 }),
271 FrameInput::Call(inputs),
272 depth,
273 Interpreter::new(
274 memory.clone(),
275 ExtBytecode::new_with_hash(bytecode, code_hash),
276 interpreter_input,
277 is_static,
278 false,
279 context.cfg().spec().into(),
280 gas_limit,
281 ),
282 checkpoint,
283 memory,
284 )))
285 }
286
287 #[inline]
289 pub fn make_create_frame(
290 evm: &mut EVM,
291 depth: usize,
292 memory: Rc<RefCell<SharedMemory>>,
293 inputs: Box<CreateInputs>,
294 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
295 let context = evm.ctx();
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 if depth > CALL_STACK_LIMIT as usize {
310 return return_error(InstructionResult::CallTooDeep);
311 }
312
313 if spec.is_enabled_in(OSAKA) && inputs.init_code.starts_with(&EOF_MAGIC_BYTES) {
315 return return_error(InstructionResult::CreateInitCodeStartingEF00);
316 }
317
318 let caller_balance = context
320 .journal()
321 .load_account(inputs.caller)?
322 .data
323 .info
324 .balance;
325
326 if caller_balance < inputs.value {
328 return return_error(InstructionResult::OutOfFunds);
329 }
330
331 let old_nonce;
333 if let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? {
334 old_nonce = nonce - 1;
335 } else {
336 return return_error(InstructionResult::Return);
337 }
338
339 let mut init_code_hash = B256::ZERO;
341 let created_address = match inputs.scheme {
342 CreateScheme::Create => inputs.caller.create(old_nonce),
343 CreateScheme::Create2 { salt } => {
344 init_code_hash = keccak256(&inputs.init_code);
345 inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
346 }
347 };
348
349 context.journal().load_account(created_address)?;
351
352 let checkpoint = match context.journal().create_account_checkpoint(
354 inputs.caller,
355 created_address,
356 inputs.value,
357 spec,
358 ) {
359 Ok(checkpoint) => checkpoint,
360 Err(e) => return return_error(e.into()),
361 };
362
363 let bytecode = ExtBytecode::new_with_hash(
364 Bytecode::new_legacy(inputs.init_code.clone()),
365 init_code_hash,
366 );
367
368 let interpreter_input = InputsImpl {
369 target_address: created_address,
370 caller_address: inputs.caller,
371 input: Bytes::new(),
372 call_value: inputs.value,
373 };
374 let gas_limit = inputs.gas_limit;
375 Ok(ItemOrResult::Item(Self::new(
376 FrameData::Create(CreateFrame { created_address }),
377 FrameInput::Create(inputs),
378 depth,
379 Interpreter::new(
380 memory.clone(),
381 bytecode,
382 interpreter_input,
383 false,
384 false,
385 spec,
386 gas_limit,
387 ),
388 checkpoint,
389 memory,
390 )))
391 }
392
393 #[inline]
395 pub fn make_eofcreate_frame(
396 evm: &mut EVM,
397 depth: usize,
398 memory: Rc<RefCell<SharedMemory>>,
399 inputs: Box<EOFCreateInputs>,
400 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
401 let context = evm.ctx();
402 let spec = context.cfg().spec().into();
403 let return_error = |e| {
404 Ok(ItemOrResult::Result(FrameResult::EOFCreate(
405 CreateOutcome {
406 result: InterpreterResult {
407 result: e,
408 gas: Gas::new(inputs.gas_limit),
409 output: Bytes::new(),
410 },
411 address: None,
412 },
413 )))
414 };
415
416 let (input, initcode, created_address) = match &inputs.kind {
417 EOFCreateKind::Opcode {
418 initcode,
419 input,
420 created_address,
421 } => (input.clone(), initcode.clone(), Some(*created_address)),
422 EOFCreateKind::Tx { initdata } => {
423 let Ok((eof, input)) = Eof::decode_dangling(initdata.clone()) else {
426 context.journal().inc_account_nonce(inputs.caller)?;
427 return return_error(InstructionResult::InvalidEOFInitCode);
428 };
429
430 if eof.validate().is_err() {
431 context.journal().inc_account_nonce(inputs.caller)?;
433 return return_error(InstructionResult::InvalidEOFInitCode);
434 }
435
436 let tx = context.tx();
438 let create_address = tx.caller().create(tx.nonce());
439
440 (input, eof, Some(create_address))
441 }
442 };
443
444 if depth > CALL_STACK_LIMIT as usize {
446 return return_error(InstructionResult::CallTooDeep);
447 }
448
449 let caller_balance = context
451 .journal()
452 .load_account(inputs.caller)?
453 .map(|a| a.info.balance);
454
455 if caller_balance.data < inputs.value {
457 return return_error(InstructionResult::OutOfFunds);
458 }
459
460 let Some(nonce) = context.journal().inc_account_nonce(inputs.caller)? else {
462 return return_error(InstructionResult::Return);
464 };
465 let old_nonce = nonce - 1;
466
467 let created_address = created_address.unwrap_or_else(|| inputs.caller.create(old_nonce));
468
469 context.journal().load_account(created_address)?;
471
472 let checkpoint = match context.journal().create_account_checkpoint(
474 inputs.caller,
475 created_address,
476 inputs.value,
477 spec,
478 ) {
479 Ok(checkpoint) => checkpoint,
480 Err(e) => return return_error(e.into()),
481 };
482
483 let interpreter_input = InputsImpl {
484 target_address: created_address,
485 caller_address: inputs.caller,
486 input,
487 call_value: inputs.value,
488 };
489
490 let gas_limit = inputs.gas_limit;
491 Ok(ItemOrResult::Item(Self::new(
492 FrameData::EOFCreate(EOFCreateFrame { created_address }),
493 FrameInput::EOFCreate(inputs),
494 depth,
495 Interpreter::new(
496 memory.clone(),
497 ExtBytecode::new(Bytecode::Eof(Arc::new(initcode))),
498 interpreter_input,
499 false,
500 true,
501 spec,
502 gas_limit,
503 ),
504 checkpoint,
505 memory,
506 )))
507 }
508
509 pub fn init_with_context(
510 evm: &mut EVM,
511 depth: usize,
512 frame_init: FrameInput,
513 memory: Rc<RefCell<SharedMemory>>,
514 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
515 match frame_init {
516 FrameInput::Call(inputs) => Self::make_call_frame(evm, depth, memory, inputs),
517 FrameInput::Create(inputs) => Self::make_create_frame(evm, depth, memory, inputs),
518 FrameInput::EOFCreate(inputs) => Self::make_eofcreate_frame(evm, depth, memory, inputs),
519 }
520 }
521}
522
523impl<EVM, ERROR> EthFrame<EVM, ERROR, EthInterpreter>
524where
525 EVM: EvmTr<
526 Context: ContextTr,
527 Precompiles: PrecompileProvider<EVM::Context, Output = InterpreterResult>,
528 Instructions: InstructionProvider<
529 Context = EVM::Context,
530 InterpreterTypes = EthInterpreter,
531 >,
532 >,
533 ERROR: From<ContextTrDbError<EVM::Context>> + FromStringError,
534{
535 pub fn init_first(
536 evm: &mut EVM,
537 frame_input: FrameInput,
538 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
539 let memory = Rc::new(RefCell::new(SharedMemory::new()));
540 memory.borrow_mut().new_context();
541 Self::init_with_context(evm, 0, frame_input, memory)
542 }
543
544 fn init(
545 &self,
546 evm: &mut EVM,
547 frame_init: FrameInput,
548 ) -> Result<ItemOrResult<Self, FrameResult>, ERROR> {
549 self.memory.borrow_mut().new_context();
550 Self::init_with_context(evm, self.depth + 1, frame_init, self.memory.clone())
551 }
552
553 pub fn process_next_action(
554 &mut self,
555 evm: &mut EVM,
556 next_action: InterpreterAction,
557 ) -> Result<FrameInitOrResult<Self>, ERROR> {
558 let context = evm.ctx();
559 let spec = context.cfg().spec().into();
560
561 let mut interpreter_result = match next_action {
564 InterpreterAction::NewFrame(new_frame) => return Ok(ItemOrResult::Item(new_frame)),
565 InterpreterAction::Return { result } => result,
566 InterpreterAction::None => unreachable!("InterpreterAction::None is not expected"),
567 };
568
569 let result = match &self.data {
571 FrameData::Call(frame) => {
572 if interpreter_result.result.is_ok() {
575 context.journal().checkpoint_commit();
576 } else {
577 context.journal().checkpoint_revert(self.checkpoint);
578 }
579 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
580 interpreter_result,
581 frame.return_memory_range.clone(),
582 )))
583 }
584 FrameData::Create(frame) => {
585 let max_code_size = context.cfg().max_code_size();
586 return_create(
587 context.journal(),
588 self.checkpoint,
589 &mut interpreter_result,
590 frame.created_address,
591 max_code_size,
592 spec,
593 );
594
595 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
596 interpreter_result,
597 Some(frame.created_address),
598 )))
599 }
600 FrameData::EOFCreate(frame) => {
601 let max_code_size = context.cfg().max_code_size();
602 return_eofcreate(
603 context.journal(),
604 self.checkpoint,
605 &mut interpreter_result,
606 frame.created_address,
607 max_code_size,
608 );
609
610 ItemOrResult::Result(FrameResult::EOFCreate(CreateOutcome::new(
611 interpreter_result,
612 Some(frame.created_address),
613 )))
614 }
615 };
616
617 Ok(result)
618 }
619
620 fn return_result(&mut self, evm: &mut EVM, result: FrameResult) -> Result<(), ERROR> {
621 self.memory.borrow_mut().free_context();
622 match core::mem::replace(evm.ctx().error(), Ok(())) {
623 Err(ContextError::Db(e)) => return Err(e.into()),
624 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
625 Ok(_) => (),
626 }
627
628 match result {
630 FrameResult::Call(outcome) => {
631 let out_gas = outcome.gas();
632 let ins_result = *outcome.instruction_result();
633 let returned_len = outcome.result.output.len();
634
635 let interpreter = &mut self.interpreter;
636 let mem_length = outcome.memory_length();
637 let mem_start = outcome.memory_start();
638 interpreter.return_data.set_buffer(outcome.result.output);
639
640 let target_len = min(mem_length, returned_len);
641
642 if ins_result == InstructionResult::FatalExternalError {
643 panic!("Fatal external error in insert_call_outcome");
644 }
645
646 let item = {
647 if interpreter.runtime_flag.is_eof() {
648 match ins_result {
649 return_ok!() => U256::ZERO,
650 return_revert!() => U256::from(1),
651 _ => U256::from(2),
652 }
653 } else if ins_result.is_ok() {
654 U256::from(1)
655 } else {
656 U256::ZERO
657 }
658 };
659 let _ = interpreter.stack.push(item);
661
662 if ins_result.is_ok_or_revert() {
664 interpreter
665 .control
666 .gas_mut()
667 .erase_cost(out_gas.remaining());
668 self.memory
669 .borrow_mut()
670 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
671 }
672
673 if ins_result.is_ok() {
674 interpreter
675 .control
676 .gas_mut()
677 .record_refund(out_gas.refunded());
678 }
679 }
680 FrameResult::Create(outcome) => {
681 let instruction_result = *outcome.instruction_result();
682 let interpreter = &mut self.interpreter;
683
684 if instruction_result == InstructionResult::Revert {
685 interpreter
687 .return_data
688 .set_buffer(outcome.output().to_owned());
689 } else {
690 interpreter.return_data.clear();
692 };
693
694 assert_ne!(
695 instruction_result,
696 InstructionResult::FatalExternalError,
697 "Fatal external error in insert_eofcreate_outcome"
698 );
699
700 let this_gas = interpreter.control.gas_mut();
701 if instruction_result.is_ok_or_revert() {
702 this_gas.erase_cost(outcome.gas().remaining());
703 }
704
705 let stack_item = if instruction_result.is_ok() {
706 this_gas.record_refund(outcome.gas().refunded());
707 outcome.address.unwrap_or_default().into_word().into()
708 } else {
709 U256::ZERO
710 };
711
712 let _ = interpreter.stack.push(stack_item);
714 }
715 FrameResult::EOFCreate(outcome) => {
716 let instruction_result = *outcome.instruction_result();
717 let interpreter = &mut self.interpreter;
718 if instruction_result == InstructionResult::Revert {
719 interpreter
721 .return_data
722 .set_buffer(outcome.output().to_owned());
723 } else {
724 interpreter.return_data.clear()
726 };
727
728 assert_ne!(
729 instruction_result,
730 InstructionResult::FatalExternalError,
731 "Fatal external error in insert_eofcreate_outcome"
732 );
733
734 let this_gas = interpreter.control.gas_mut();
735 if instruction_result.is_ok_or_revert() {
736 this_gas.erase_cost(outcome.gas().remaining());
737 }
738
739 let stack_item = if instruction_result.is_ok() {
740 this_gas.record_refund(outcome.gas().refunded());
741 outcome.address.expect("EOF Address").into_word().into()
742 } else {
743 U256::ZERO
744 };
745
746 let _ = interpreter.stack.push(stack_item);
748 }
749 }
750
751 Ok(())
752 }
753}
754
755pub fn return_create<JOURNAL: JournalTr>(
756 journal: &mut JOURNAL,
757 checkpoint: JournalCheckpoint,
758 interpreter_result: &mut InterpreterResult,
759 address: Address,
760 max_code_size: usize,
761 spec_id: SpecId,
762) {
763 if !interpreter_result.result.is_ok() {
765 journal.checkpoint_revert(checkpoint);
766 return;
767 }
768 if spec_id.is_enabled_in(LONDON) && interpreter_result.output.first() == Some(&0xEF) {
773 journal.checkpoint_revert(checkpoint);
774 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
775 return;
776 }
777
778 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
781 journal.checkpoint_revert(checkpoint);
782 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
783 return;
784 }
785 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
786 if !interpreter_result.gas.record_cost(gas_for_code) {
787 if spec_id.is_enabled_in(HOMESTEAD) {
792 journal.checkpoint_revert(checkpoint);
793 interpreter_result.result = InstructionResult::OutOfGas;
794 return;
795 } else {
796 interpreter_result.output = Bytes::new();
797 }
798 }
799 journal.checkpoint_commit();
801
802 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
804
805 journal.set_code(address, bytecode);
807
808 interpreter_result.result = InstructionResult::Return;
809}
810
811pub fn return_eofcreate<JOURNAL: JournalTr>(
812 journal: &mut JOURNAL,
813 checkpoint: JournalCheckpoint,
814 interpreter_result: &mut InterpreterResult,
815 address: Address,
816 max_code_size: usize,
817) {
818 if interpreter_result.result != InstructionResult::ReturnContract {
826 journal.checkpoint_revert(checkpoint);
827 return;
828 }
829
830 if interpreter_result.output.len() > max_code_size {
831 journal.checkpoint_revert(checkpoint);
832 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
833 return;
834 }
835
836 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
838 if !interpreter_result.gas.record_cost(gas_for_code) {
839 journal.checkpoint_revert(checkpoint);
840 interpreter_result.result = InstructionResult::OutOfGas;
841 return;
842 }
843
844 journal.checkpoint_commit();
845
846 let bytecode = Eof::decode(interpreter_result.output.clone()).expect("Eof is already verified");
848
849 journal.set_code(address, Bytecode::Eof(Arc::new(bytecode)));
851}