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