revm_interpreter/instructions/contract/
call_helpers.rs

1use crate::{
2    gas,
3    interpreter::Interpreter,
4    interpreter_types::{InterpreterTypes, MemoryTr, RuntimeFlag, StackTr},
5};
6use context_interface::{context::StateLoad, journaled_state::AccountLoad};
7use core::{cmp::min, ops::Range};
8use primitives::{hardfork::SpecId::*, U256};
9
10/// Gets memory input and output ranges for call instructions.
11#[inline]
12pub fn get_memory_input_and_out_ranges(
13    interpreter: &mut Interpreter<impl InterpreterTypes>,
14) -> Option<(Range<usize>, Range<usize>)> {
15    popn!([in_offset, in_len, out_offset, out_len], interpreter, None);
16
17    let mut in_range = resize_memory(interpreter, in_offset, in_len)?;
18
19    if !in_range.is_empty() {
20        let offset = interpreter.memory.local_memory_offset();
21        in_range = in_range.start.saturating_add(offset)..in_range.end.saturating_add(offset);
22    }
23
24    let ret_range = resize_memory(interpreter, out_offset, out_len)?;
25    Some((in_range, ret_range))
26}
27
28/// Resize memory and return range of memory.
29/// If `len` is 0 dont touch memory and return `usize::MAX` as offset and 0 as length.
30#[inline]
31pub fn resize_memory(
32    interpreter: &mut Interpreter<impl InterpreterTypes>,
33    offset: U256,
34    len: U256,
35) -> Option<Range<usize>> {
36    let len = as_usize_or_fail_ret!(interpreter, len, None);
37    let offset = if len != 0 {
38        let offset = as_usize_or_fail_ret!(interpreter, offset, None);
39        resize_memory!(interpreter, offset, len, None);
40        offset
41    } else {
42        usize::MAX //unrealistic value so we are sure it is not used
43    };
44    Some(offset..offset + len)
45}
46
47/// Calculates gas cost and limit for call instructions.
48#[inline]
49pub fn calc_call_gas(
50    interpreter: &mut Interpreter<impl InterpreterTypes>,
51    account_load: StateLoad<AccountLoad>,
52    has_transfer: bool,
53    local_gas_limit: u64,
54) -> Option<u64> {
55    let call_cost = gas::call_cost(
56        interpreter.runtime_flag.spec_id(),
57        has_transfer,
58        account_load,
59    );
60    gas!(interpreter, call_cost, None);
61
62    // EIP-150: Gas cost changes for IO-heavy operations
63    let gas_limit = if interpreter.runtime_flag.spec_id().is_enabled_in(TANGERINE) {
64        // Take l64 part of gas_limit
65        min(interpreter.gas.remaining_63_of_64_parts(), local_gas_limit)
66    } else {
67        local_gas_limit
68    };
69
70    Some(gas_limit)
71}