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::{JournalCheckpoint, JournalTr},
9 local::{FrameToken, OutFrame},
10 Cfg, ContextTr, Database,
11};
12use core::cmp::min;
13use derive_where::derive_where;
14use interpreter::{
15 gas,
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 pub fn clear(
105 &mut self,
106 data: FrameData,
107 input: FrameInput,
108 depth: usize,
109 memory: SharedMemory,
110 bytecode: ExtBytecode,
111 inputs: InputsImpl,
112 is_static: bool,
113 spec_id: SpecId,
114 gas_limit: u64,
115 checkpoint: JournalCheckpoint,
116 ) {
117 let Self {
118 data: data_ref,
119 input: input_ref,
120 depth: depth_ref,
121 interpreter,
122 checkpoint: checkpoint_ref,
123 is_finished: is_finished_ref,
124 } = self;
125 *data_ref = data;
126 *input_ref = input;
127 *depth_ref = depth;
128 *is_finished_ref = false;
129 interpreter.clear(memory, bytecode, inputs, is_static, spec_id, gas_limit);
130 *checkpoint_ref = checkpoint;
131 }
132
133 #[inline]
135 pub fn make_call_frame<
136 CTX: ContextTr,
137 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
138 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
139 >(
140 mut this: OutFrame<'_, Self>,
141 ctx: &mut CTX,
142 precompiles: &mut PRECOMPILES,
143 depth: usize,
144 memory: SharedMemory,
145 inputs: Box<CallInputs>,
146 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
147 let gas = Gas::new(inputs.gas_limit);
148 let return_result = |instruction_result: InstructionResult| {
149 Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
150 result: InterpreterResult {
151 result: instruction_result,
152 gas,
153 output: Bytes::new(),
154 },
155 memory_offset: inputs.return_memory_offset.clone(),
156 was_precompile_called: false,
157 precompile_call_logs: Vec::new(),
158 })))
159 };
160
161 if depth > CALL_STACK_LIMIT as usize {
163 return return_result(InstructionResult::CallTooDeep);
164 }
165
166 let checkpoint = ctx.journal_mut().checkpoint();
168
169 if let CallValue::Transfer(value) = inputs.value {
171 if let Some(i) =
174 ctx.journal_mut()
175 .transfer_loaded(inputs.caller, inputs.target_address, value)
176 {
177 ctx.journal_mut().checkpoint_revert(checkpoint);
178 return return_result(i.into());
179 }
180 }
181
182 let interpreter_input = InputsImpl {
183 target_address: inputs.target_address,
184 caller_address: inputs.caller,
185 bytecode_address: Some(inputs.bytecode_address),
186 input: inputs.input.clone(),
187 call_value: inputs.value.get(),
188 };
189 let is_static = inputs.is_static;
190 let gas_limit = inputs.gas_limit;
191
192 if let Some(result) = precompiles.run(ctx, &inputs).map_err(ERROR::from_string)? {
193 let mut logs = Vec::new();
194 if result.result.is_ok() {
195 ctx.journal_mut().checkpoint_commit();
196 } else {
197 logs = ctx.journal_mut().logs()[checkpoint.log_i..].to_vec();
200 ctx.journal_mut().checkpoint_revert(checkpoint);
201 }
202 return Ok(ItemOrResult::Result(FrameResult::Call(CallOutcome {
203 result,
204 memory_offset: inputs.return_memory_offset.clone(),
205 was_precompile_called: true,
206 precompile_call_logs: logs,
207 })));
208 }
209
210 let (bytecode, bytecode_hash) = if let Some((hash, code)) = inputs.known_bytecode.clone() {
212 (code, hash)
214 } else {
215 let account = ctx
217 .journal_mut()
218 .load_account_with_code(inputs.bytecode_address)?;
219 (
220 account.info.code.clone().unwrap_or_default(),
221 account.info.code_hash,
222 )
223 };
224
225 if bytecode.is_empty() {
227 ctx.journal_mut().checkpoint_commit();
228 return return_result(InstructionResult::Stop);
229 }
230
231 this.get(EthFrame::invalid).clear(
233 FrameData::Call(CallFrame {
234 return_memory_range: inputs.return_memory_offset.clone(),
235 }),
236 FrameInput::Call(inputs),
237 depth,
238 memory,
239 ExtBytecode::new_with_hash(bytecode, bytecode_hash),
240 interpreter_input,
241 is_static,
242 ctx.cfg().spec().into(),
243 gas_limit,
244 checkpoint,
245 );
246 Ok(ItemOrResult::Item(this.consume()))
247 }
248
249 #[inline]
251 pub fn make_create_frame<
252 CTX: ContextTr,
253 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
254 >(
255 mut this: OutFrame<'_, Self>,
256 context: &mut CTX,
257 depth: usize,
258 memory: SharedMemory,
259 inputs: Box<CreateInputs>,
260 ) -> Result<ItemOrResult<FrameToken, FrameResult>, ERROR> {
261 let spec = context.cfg().spec().into();
262 let return_error = |e| {
263 Ok(ItemOrResult::Result(FrameResult::Create(CreateOutcome {
264 result: InterpreterResult {
265 result: e,
266 gas: Gas::new(inputs.gas_limit),
267 output: Bytes::new(),
268 },
269 address: None,
270 })))
271 };
272
273 if depth > CALL_STACK_LIMIT as usize {
275 return return_error(InstructionResult::CallTooDeep);
276 }
277
278 let mut caller_info = context.journal_mut().load_account_mut(inputs.caller)?;
280
281 if *caller_info.balance() < inputs.value {
284 return return_error(InstructionResult::OutOfFunds);
285 }
286
287 let old_nonce = caller_info.nonce();
289 if !caller_info.bump_nonce() {
290 return return_error(InstructionResult::Return);
291 };
292
293 let mut init_code_hash = None;
295 let created_address = match inputs.scheme {
296 CreateScheme::Create => inputs.caller.create(old_nonce),
297 CreateScheme::Create2 { salt } => {
298 let init_code_hash = *init_code_hash.insert(keccak256(&inputs.init_code));
299 inputs.caller.create2(salt.to_be_bytes(), init_code_hash)
300 }
301 CreateScheme::Custom { address } => address,
302 };
303
304 context.journal_mut().load_account(created_address)?;
306
307 let checkpoint = match context.journal_mut().create_account_checkpoint(
309 inputs.caller,
310 created_address,
311 inputs.value,
312 spec,
313 ) {
314 Ok(checkpoint) => checkpoint,
315 Err(e) => return return_error(e.into()),
316 };
317
318 let bytecode = ExtBytecode::new_with_optional_hash(
319 Bytecode::new_legacy(inputs.init_code.clone()),
320 init_code_hash,
321 );
322
323 let interpreter_input = InputsImpl {
324 target_address: created_address,
325 caller_address: inputs.caller,
326 bytecode_address: None,
327 input: CallInput::Bytes(Bytes::new()),
328 call_value: inputs.value,
329 };
330 let gas_limit = inputs.gas_limit;
331
332 this.get(EthFrame::invalid).clear(
333 FrameData::Create(CreateFrame { created_address }),
334 FrameInput::Create(inputs),
335 depth,
336 memory,
337 bytecode,
338 interpreter_input,
339 false,
340 spec,
341 gas_limit,
342 checkpoint,
343 );
344 Ok(ItemOrResult::Item(this.consume()))
345 }
346
347 pub fn init_with_context<
349 CTX: ContextTr,
350 PRECOMPILES: PrecompileProvider<CTX, Output = InterpreterResult>,
351 >(
352 this: OutFrame<'_, Self>,
353 ctx: &mut CTX,
354 precompiles: &mut PRECOMPILES,
355 frame_init: FrameInit,
356 ) -> Result<
357 ItemOrResult<FrameToken, FrameResult>,
358 ContextError<<<CTX as ContextTr>::Db as Database>::Error>,
359 > {
360 let FrameInit {
362 depth,
363 memory,
364 frame_input,
365 } = frame_init;
366
367 match frame_input {
368 FrameInput::Call(inputs) => {
369 Self::make_call_frame(this, ctx, precompiles, depth, memory, inputs)
370 }
371 FrameInput::Create(inputs) => Self::make_create_frame(this, ctx, depth, memory, inputs),
372 FrameInput::Empty => unreachable!(),
373 }
374 }
375}
376
377impl EthFrame<EthInterpreter> {
378 pub fn process_next_action<
380 CTX: ContextTr,
381 ERROR: From<ContextTrDbError<CTX>> + FromStringError,
382 >(
383 &mut self,
384 context: &mut CTX,
385 next_action: InterpreterAction,
386 ) -> Result<FrameInitOrResult<Self>, ERROR> {
387 let spec = context.cfg().spec().into();
388
389 let mut interpreter_result = match next_action {
392 InterpreterAction::NewFrame(frame_input) => {
393 let depth = self.depth + 1;
394 return Ok(ItemOrResult::Item(FrameInit {
395 frame_input,
396 depth,
397 memory: self.interpreter.memory.new_child_context(),
398 }));
399 }
400 InterpreterAction::Return(result) => result,
401 };
402
403 let result = match &self.data {
405 FrameData::Call(frame) => {
406 if interpreter_result.result.is_ok() {
409 context.journal_mut().checkpoint_commit();
410 } else {
411 context.journal_mut().checkpoint_revert(self.checkpoint);
412 }
413 ItemOrResult::Result(FrameResult::Call(CallOutcome::new(
414 interpreter_result,
415 frame.return_memory_range.clone(),
416 )))
417 }
418 FrameData::Create(frame) => {
419 let max_code_size = context.cfg().max_code_size();
420 let is_eip3541_disabled = context.cfg().is_eip3541_disabled();
421 return_create(
422 context.journal_mut(),
423 self.checkpoint,
424 &mut interpreter_result,
425 frame.created_address,
426 max_code_size,
427 is_eip3541_disabled,
428 spec,
429 );
430
431 ItemOrResult::Result(FrameResult::Create(CreateOutcome::new(
432 interpreter_result,
433 Some(frame.created_address),
434 )))
435 }
436 };
437
438 Ok(result)
439 }
440
441 pub fn return_result<CTX: ContextTr, ERROR: From<ContextTrDbError<CTX>> + FromStringError>(
443 &mut self,
444 ctx: &mut CTX,
445 result: FrameResult,
446 ) -> Result<(), ERROR> {
447 self.interpreter.memory.free_child_context();
448 match core::mem::replace(ctx.error(), Ok(())) {
449 Err(ContextError::Db(e)) => return Err(e.into()),
450 Err(ContextError::Custom(e)) => return Err(ERROR::from_string(e)),
451 Ok(_) => (),
452 }
453
454 match result {
456 FrameResult::Call(outcome) => {
457 let out_gas = outcome.gas();
458 let ins_result = *outcome.instruction_result();
459 let returned_len = outcome.result.output.len();
460
461 let interpreter = &mut self.interpreter;
462 let mem_length = outcome.memory_length();
463 let mem_start = outcome.memory_start();
464 interpreter.return_data.set_buffer(outcome.result.output);
465
466 let target_len = min(mem_length, returned_len);
467
468 if ins_result == InstructionResult::FatalExternalError {
469 panic!("Fatal external error in insert_call_outcome");
470 }
471
472 let item = if ins_result.is_ok() {
473 U256::from(1)
474 } else {
475 U256::ZERO
476 };
477 let _ = interpreter.stack.push(item);
479
480 if ins_result.is_ok_or_revert() {
482 interpreter.gas.erase_cost(out_gas.remaining());
483 interpreter
484 .memory
485 .set(mem_start, &interpreter.return_data.buffer()[..target_len]);
486 }
487
488 if ins_result.is_ok() {
489 interpreter.gas.record_refund(out_gas.refunded());
490 }
491 }
492 FrameResult::Create(outcome) => {
493 let instruction_result = *outcome.instruction_result();
494 let interpreter = &mut self.interpreter;
495
496 if instruction_result == InstructionResult::Revert {
497 interpreter
499 .return_data
500 .set_buffer(outcome.output().to_owned());
501 } else {
502 interpreter.return_data.clear();
504 };
505
506 assert_ne!(
507 instruction_result,
508 InstructionResult::FatalExternalError,
509 "Fatal external error in insert_eofcreate_outcome"
510 );
511
512 let this_gas = &mut interpreter.gas;
513 if instruction_result.is_ok_or_revert() {
514 this_gas.erase_cost(outcome.gas().remaining());
515 }
516
517 let stack_item = if instruction_result.is_ok() {
518 this_gas.record_refund(outcome.gas().refunded());
519 outcome.address.unwrap_or_default().into_word().into()
520 } else {
521 U256::ZERO
522 };
523
524 let _ = interpreter.stack.push(stack_item);
526 }
527 }
528
529 Ok(())
530 }
531}
532
533pub fn return_create<JOURNAL: JournalTr>(
535 journal: &mut JOURNAL,
536 checkpoint: JournalCheckpoint,
537 interpreter_result: &mut InterpreterResult,
538 address: Address,
539 max_code_size: usize,
540 is_eip3541_disabled: bool,
541 spec_id: SpecId,
542) {
543 if !interpreter_result.result.is_ok() {
545 journal.checkpoint_revert(checkpoint);
546 return;
547 }
548 if !is_eip3541_disabled
553 && spec_id.is_enabled_in(LONDON)
554 && interpreter_result.output.first() == Some(&0xEF)
555 {
556 journal.checkpoint_revert(checkpoint);
557 interpreter_result.result = InstructionResult::CreateContractStartingWithEF;
558 return;
559 }
560
561 if spec_id.is_enabled_in(SPURIOUS_DRAGON) && interpreter_result.output.len() > max_code_size {
564 journal.checkpoint_revert(checkpoint);
565 interpreter_result.result = InstructionResult::CreateContractSizeLimit;
566 return;
567 }
568 let gas_for_code = interpreter_result.output.len() as u64 * gas::CODEDEPOSIT;
569 if !interpreter_result.gas.record_cost(gas_for_code) {
570 if spec_id.is_enabled_in(HOMESTEAD) {
575 journal.checkpoint_revert(checkpoint);
576 interpreter_result.result = InstructionResult::OutOfGas;
577 return;
578 } else {
579 interpreter_result.output = Bytes::new();
580 }
581 }
582 journal.checkpoint_commit();
584
585 let bytecode = Bytecode::new_legacy(interpreter_result.output.clone());
587
588 journal.set_code(address, bytecode);
590
591 interpreter_result.result = InstructionResult::Return;
592}