1use crate::evm::FrameTr;
2use crate::item_or_result::FrameInitOrResult;
3use crate::{precompile_provider::PrecompileProvider, ItemOrResult};
4use crate::{CallFrame, CreateFrame, FrameData, FrameResult};
5use context::result::FromStringError;
6use context_interface::context::ContextError;
7use context_interface::local::{FrameToken, OutFrame};
8use context_interface::ContextTr;
9use context_interface::{
10 journaled_state::{JournalCheckpoint, JournalTr},
11 Cfg, Database,
12};
13use core::cmp::min;
14use derive_where::derive_where;
15use interpreter::interpreter_action::FrameInit;
16use interpreter::{
17 gas,
18 interpreter::{EthInterpreter, ExtBytecode},
19 interpreter_types::ReturnData,
20 CallInput, CallInputs, CallOutcome, CallValue, CreateInputs, CreateOutcome, CreateScheme,
21 FrameInput, Gas, InputsImpl, InstructionResult, Interpreter, InterpreterAction,
22 InterpreterResult, InterpreterTypes, SharedMemory,
23};
24use primitives::{
25 constants::CALL_STACK_LIMIT,
26 hardfork::SpecId::{self, HOMESTEAD, LONDON, SPURIOUS_DRAGON},
27};
28use primitives::{keccak256, Address, Bytes, U256};
29use state::Bytecode;
30use std::{borrow::ToOwned, boxed::Box, vec::Vec};
31
32#[derive_where(Clone, Debug; IW,
34 <IW as InterpreterTypes>::Stack,
35 <IW as InterpreterTypes>::Memory,
36 <IW as InterpreterTypes>::Bytecode,
37 <IW as InterpreterTypes>::ReturnData,
38 <IW as InterpreterTypes>::Input,
39 <IW as InterpreterTypes>::RuntimeFlag,
40 <IW as InterpreterTypes>::Extend,
41)]
42pub struct EthFrame<IW: InterpreterTypes = EthInterpreter> {
43 pub data: FrameData,
45 pub input: FrameInput,
47 pub depth: usize,
49 pub checkpoint: JournalCheckpoint,
51 pub interpreter: Interpreter<IW>,
53 pub is_finished: bool,
56}
57
58impl<IT: InterpreterTypes> FrameTr for EthFrame<IT> {
59 type FrameResult = FrameResult;
60 type FrameInit = FrameInit;
61}
62
63impl Default for EthFrame<EthInterpreter> {
64 fn default() -> Self {
65 Self::do_default(Interpreter::default())
66 }
67}
68
69impl EthFrame<EthInterpreter> {
70 pub fn invalid() -> Self {
72 Self::do_default(Interpreter::invalid())
73 }
74
75 fn do_default(interpreter: Interpreter<EthInterpreter>) -> Self {
76 Self {
77 data: FrameData::Call(CallFrame {
78 return_memory_range: 0..0,
79 }),
80 input: FrameInput::Empty,
81 depth: 0,
82 checkpoint: JournalCheckpoint::default(),
83 interpreter,
84 is_finished: false,
85 }
86 }
87
88 pub fn is_finished(&self) -> bool {
90 self.is_finished
91 }
92
93 pub fn set_finished(&mut self, finished: bool) {
95 self.is_finished = finished;
96 }
97}
98
99pub type ContextTrDbError<CTX> = <<CTX as ContextTr>::Db as Database>::Error;
101
102impl EthFrame<EthInterpreter> {
103 #[allow(clippy::too_many_arguments)]
105 pub fn clear(
106 &mut self,
107 data: FrameData,
108 input: FrameInput,
109 depth: usize,
110 memory: SharedMemory,
111 bytecode: ExtBytecode,
112 inputs: InputsImpl,
113 is_static: bool,
114 spec_id: SpecId,
115 gas_limit: u64,
116 checkpoint: JournalCheckpoint,
117 ) {
118 let Self {
119 data: data_ref,
120 input: input_ref,
121 depth: depth_ref,
122 interpreter,
123 checkpoint: checkpoint_ref,
124 is_finished: is_finished_ref,
125 } = self;
126 *data_ref = data;
127 *input_ref = input;
128 *depth_ref = depth;
129 *is_finished_ref = false;
130 interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit);
131 *checkpoint_ref = checkpoint;
132 }
133
134 #[inline]
136 pub fn make_call_frame<
137 CTX: ContextTr,
138 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
139 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
140 >(
141 mut this: OutFrame<'_, Self>,
142 ctx: &mut CTX,
143 precompiles: &mut PRECOMPILES,
144 depth: usize,
145 memory: SharedMemory,
146 inputs: Box<CallInputs>,
147 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
148 let gas = Gas::new(inputs.gas_limit);
149 let return_result = |instruction_result: InstructionResult| {
150 Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
151 result: InterpreterResult {
152 result: instruction_result,
153 gas,
154 output: Bytes::new(),
155 },
156 memory_offset: inputs.return_memory_offset.clone(),
157 was_precompile_called: false,
158 precompile_call_logs: Vec::new(),
159 })))
160 };
161
162 if depth > CALL_STACK_LIMIT as usize {
164 return return_result(InstructionResult::CallTooDeep);
165 }
166
167 let checkpoint = ctx.journal_mut().checkpoint();
169
170 if let CallValue::Transfer(value) = inputs.value {
172 if let Some(i) =
175 ctx.journal_mut()
176 .transfer_loaded(inputs.caller, inputs.target_address, value)
177 {
178 ctx.journal_mut().checkpoint_revert(checkpoint);
179 return return_result(i.into());
180 }
181 }
182
183 let interpreter_input = InputsImpl {
184 target_address: inputs.target_address,
185 caller_address: inputs.caller,
186 bytecode_address: Some(inputs.bytecode_address),
187 input: inputs.input.clone(),
188 call_value: inputs.value.get(),
189 };
190 let is_static = inputs.is_static;
191 let gas_limit = inputs.gas_limit;
192
193 if let Some(result) = precompiles.run(ctx, &inputs).map_err(ERROR::from_string)? {
194 let mut logs = Vec::new();
195 if result.result.is_ok() {
196 ctx.journal_mut().checkpoint_commit();
197 } else {
198 logs = ctx.journal_mut().logs()[checkpoint.log_i..].to_vec();
201 ctx.journal_mut().checkpoint_revert(checkpoint);
202 }
203 return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
204 result,
205 memory_offset: inputs.return_memory_offset.clone(),
206 was_precompile_called: true,
207 precompile_call_logs: logs,
208 })));
209 }
210
211 let (bytecode, bytecode_hash) = if let Some((hash, code)) = inputs.known_bytecode.clone() {
213 (code, hash)
215 } else {
216 let account = ctx
218 .journal_mut()
219 .load_account_with_code(inputs.bytecode_address)?;
220 (
221 account.info.code.clone().unwrap_or_default(),
222 account.info.code_hash,
223 )
224 };
225
226 if bytecode.is_empty() {
228 ctx.journal_mut().checkpoint_commit();
229 return return_result(InstructionResult::Stop);
230 }
231
232 this.get(EthFrame::invalid).clear(
234 FrameData::Call(CallFrame {
235 return_memory_range: inputs.return_memory_offset.clone(),
236 }),
237 FrameInput::Call(inputs),
238 depth,
239 memory,
240 ExtBytecode::new_with_hash(bytecode, bytecode_hash),
241 interpreter_input,
242 is_static,
243 ctx.cfg().spec().into(),
244 gas_limit,
245 checkpoint,
246 );
247 Ok(ItemOrResult::Item(this.consume()))
248 }
249
250 #[inline]
252 pub fn make_create_frame<
253 CTX: ContextTr,
254 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
255 >(
256 mut this: OutFrame<'_, Self>,
257 context: &mut CTX,
258 depth: usize,
259 memory: SharedMemory,
260 inputs: Box<CreateInputs>,
261 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
262 let spec = context.cfg().spec().into();
263 let return_error = |e| {
264 Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome {
265 result: InterpreterResult {
266 result: e,
267 gas: Gas::new(inputs.gas_limit),
268 output: Bytes::new(),
269 },
270 address: None,
271 })))
272 };
273
274 if depth > CALL_STACK_LIMIT as usize {
276 return return_error(InstructionResult::CallTooDeep);
277 }
278
279 let mut caller_info = context.journal_mut().load_account_mut(inputs.caller)?;
281
282 if *caller_info.balance() < inputs.value {
285 return return_error(InstructionResult::OutOfFunds);
286 }
287
288 let old_nonce = caller_info.nonce();
290 if !caller_info.bump_nonce() {
291 return return_error(InstructionResult::Return);
292 };
293
294 let mut init_code_hash = None;
296 let created_address = match inputs.scheme {
297 CreateScheme::Create => inputs.caller.create(old_nonce),
298 CreateScheme::Create2 { salt } => {
299 let init_code_hash = *init_code_hash.insert(keccak256(&inputs.init_code));
300 inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
301 }
302 CreateScheme::Custom { address } => address,
303 };
304
305 context.journal_mut().load_account(created_address)?;
307
308 let checkpoint = match context.journal_mut().create_account_checkpoint(
310 inputs.caller,
311 created_address,
312 inputs.value,
313 spec,
314 ) {
315 Ok(checkpoint) => checkpoint,
316 Err(e) => return return_error(e.into()),
317 };
318
319 let bytecode = ExtBytecode::new_with_optional_hash(
320 Bytecode::new_legacy(inputs.init_code.clone()),
321 init_code_hash,
322 );
323
324 let interpreter_input = InputsImpl {
325 target_address: created_address,
326 caller_address: inputs.caller,
327 bytecode_address: None,
328 input: CallInput::Bytes(Bytes::new()),
329 call_value: inputs.value,
330 };
331 let gas_limit = inputs.gas_limit;
332
333 this.get(EthFrame::invalid).clear(
334 FrameData::Create(CreateFrame { created_address }),
335 FrameInput::Create(inputs),
336 depth,
337 memory,
338 bytecode,
339 interpreter_input,
340 false,
341 spec,
342 gas_limit,
343 checkpoint,
344 );
345 Ok(ItemOrResult::Item(this.consume()))
346 }
347
348 pub fn init_with_context<
350 CTX: ContextTr,
351 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
352 >(
353 this: OutFrame<'_, Self>,
354 ctx: &mut CTX,
355 precompiles: &mut PRECOMPILES,
356 frame_init: FrameInit,
357 ) -> Result<
358 ItemOrResult<FrameToken, FrameResult>,
359 ContextError<<<CTX as ContextTr>::Db as Database>::Error>,
360 > {
361 let FrameInit {
363 depth,
364 memory,
365 frame_input,
366 } = frame_init;
367
368 match frame_input {
369 FrameInput::Call(inputs) => {
370 Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs)
371 }
372 FrameInput::Create(inputs) => Self::make_create_frame(this, ctx, depth, memory, inputs),
373 FrameInput::Empty => unreachable!(),
374 }
375 }
376}
377
378impl EthFrame<EthInterpreter> {
379 pub fn process_next_action<
381 CTX: ContextTr,
382 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
383 >(
384 &mut self,
385 context: &mut CTX,
386 next_action: InterpreterAction,
387 ) -> Result<FrameInitOrResult<Self>, ERROR> {
388 let spec = context.cfg().spec().into();
389
390 let mut interpreter_result = match next_action {
393 InterpreterAction::NewFrame(frame_input) => {
394 let depth = self.depth + 1;
395 return Ok(ItemOrResult::Item(FrameInit {
396 frame_input,
397 depth,
398 memory: self.interpreter.memory.new_child_context(),
399 }));
400 }
401 InterpreterAction::Return(result) => result,
402 };
403
404 let result = match &self.data {
406 FrameData::Call(frame) => {
407 if interpreter_result.result.is_ok() {
410 context.journal_mut().checkpoint_commit();
411 } else {
412 context.journal_mut().checkpoint_revert(self.checkpoint);
413 }
414 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
415 interpreter_result,
416 frame.return_memory_range.clone(),
417 )))
418 }
419 FrameData::Create(frame) => {
420 let max_code_size = context.cfg().max_code_size();
421 let is_eip3541_disabled = context.cfg().is_eip3541_disabled();
422 return_create(
423 context.journal_mut(),
424 self.checkpoint,
425 &mut interpreter_result,
426 frame.created_address,
427 max_code_size,
428 is_eip3541_disabled,
429 spec,
430 );
431
432 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
433 interpreter_result,
434 Some(frame.created_address),
435 )))
436 }
437 };
438
439 Ok(result)
440 }
441
442 pub fn return_result<CTX: ContextTr, ERROR: From<ContextTrDbError<CTX>> + FromStringError>(
444 &mut self,
445 ctx: &mut CTX,
446 result: FrameResult,
447 ) -> Result<(), ERROR> {
448 self.interpreter.memory.free_child_context();
449 match core::mem::replace(ctx.error(), Ok(())) {
450 Err(ContextError::Db(e)) => return Err(e.into()),
451 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
452 Ok(_) => (),
453 }
454
455 match result {
457 FrameResult::Call(outcome) => {
458 let out_gas = outcome.gas();
459 let ins_result = *outcome.instruction_result();
460 let returned_len = outcome.result.output.len();
461
462 let interpreter = &mut self.interpreter;
463 let mem_length = outcome.memory_length();
464 let mem_start = outcome.memory_start();
465 interpreter.return_data.set_buffer(outcome.result.output);
466
467 let target_len = min(mem_length, returned_len);
468
469 if ins_result == InstructionResult::FatalExternalError {
470 panic!("Fatal external error in insert_call_outcome");
471 }
472
473 let item = if ins_result.is_ok() {
474 U256::from(1)
475 } else {
476 U256::ZERO
477 };
478 let _ = interpreter.stack.push(item);
480
481 if ins_result.is_ok_or_revert() {
483 interpreter.gas.erase_cost(out_gas.remaining());
484 interpreter
485 .memory
486 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
487 }
488
489 if ins_result.is_ok() {
490 interpreter.gas.record_refund(out_gas.refunded());
491 }
492 }
493 FrameResult::Create(outcome) => {
494 let instruction_result = *outcome.instruction_result();
495 let interpreter = &mut self.interpreter;
496
497 if instruction_result == InstructionResult::Revert {
498 interpreter
500 .return_data
501 .set_buffer(outcome.output().to_owned());
502 } else {
503 interpreter.return_data.clear();
505 };
506
507 assert_ne!(
508 instruction_result,
509 InstructionResult::FatalExternalError,
510 "Fatal external error in insert_eofcreate_outcome"
511 );
512
513 let this_gas = &mut interpreter.gas;
514 if instruction_result.is_ok_or_revert() {
515 this_gas.erase_cost(outcome.gas().remaining());
516 }
517
518 let stack_item = if instruction_result.is_ok() {
519 this_gas.record_refund(outcome.gas().refunded());
520 outcome.address.unwrap_or_default().into_word().into()
521 } else {
522 U256::ZERO
523 };
524
525 let _ = interpreter.stack.push(stack_item);
527 }
528 }
529
530 Ok(())
531 }
532}
533
534pub fn return_create<JOURNAL: JournalTr>(
536 journal: &mut JOURNAL,
537 checkpoint: JournalCheckpoint,
538 interpreter_result: &mut InterpreterResult,
539 address: Address,
540 max_code_size: usize,
541 is_eip3541_disabled: bool,
542 spec_id: SpecId,
543) {
544 if !interpreter_result.result.is_ok() {
546 journal.checkpoint_revert(checkpoint);
547 return;
548 }
549 if !is_eip3541_disabled
554 && spec_id.is_enabled_in(LONDON)
555 && interpreter_result.output.first() == Some(&0xEF)
556 {
557 journal.checkpoint_revert(checkpoint);
558 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
559 return;
560 }
561
562 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
565 journal.checkpoint_revert(checkpoint);
566 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
567 return;
568 }
569 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
570 if !interpreter_result.gas.record_cost(gas_for_code) {
571 if spec_id.is_enabled_in(HOMESTEAD) {
576 journal.checkpoint_revert(checkpoint);
577 interpreter_result.result = InstructionResult::OutOfGas;
578 return;
579 } else {
580 interpreter_result.output = Bytes::new();
581 }
582 }
583 journal.checkpoint_commit();
585
586 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
588
589 journal.set_code(address, bytecode);
591
592 interpreter_result.result = InstructionResult::Return;
593}