use crate::{
precompiles::{All as AllPrecompiles, Precompiles},
vm::{
evm::{interpreter::Halt, util::as_usize_or_halt, Interpreter},
Ext,
},
Pallet, RuntimeCosts,
};
use core::ops::{ControlFlow, Range};
use revm::interpreter::interpreter_action::CallScheme;
use sp_core::{H160, U256};
pub fn get_memory_in_and_out_ranges<'a, E: Ext>(
interpreter: &mut Interpreter<'a, E>,
) -> ControlFlow<Halt, (Range<usize>, Range<usize>)> {
let [in_offset, in_len, out_offset, out_len] = interpreter.stack.popn()?;
let in_range = resize_memory(interpreter, in_offset, in_len)?;
let ret_range = resize_memory(interpreter, out_offset, out_len)?;
ControlFlow::Continue((in_range, ret_range))
}
pub fn resize_memory<'a, E: Ext>(
interpreter: &mut Interpreter<'a, E>,
offset: U256,
len: U256,
) -> ControlFlow<Halt, Range<usize>> {
let len = as_usize_or_halt::<E::T>(len)?;
if len != 0 {
let offset = as_usize_or_halt::<E::T>(offset)?;
interpreter.memory.resize(offset, len)?;
ControlFlow::Continue(offset..offset + len)
} else {
ControlFlow::Continue(usize::MAX..usize::MAX)
}
}
pub fn charge_call_gas<'a, E: Ext>(
interpreter: &mut Interpreter<'a, E>,
callee: H160,
scheme: CallScheme,
input_len: usize,
value: U256,
) -> ControlFlow<Halt, ()> {
let precompile = <AllPrecompiles<E::T>>::get::<E>(&callee.as_fixed_bytes());
match precompile {
Some(precompile) => {
interpreter.ext.frame_meter_mut().charge_or_halt(
if precompile.has_contract_info() {
RuntimeCosts::PrecompileWithInfoBase
} else {
RuntimeCosts::PrecompileBase
},
)?;
interpreter
.ext
.frame_meter_mut()
.charge_or_halt(RuntimeCosts::PrecompileDecode(input_len as u32))?;
},
None => {
interpreter.ext.charge_or_halt(if scheme.is_delegate_call() {
RuntimeCosts::DelegateCallBase
} else {
RuntimeCosts::CallBase
})?;
interpreter
.ext
.frame_meter_mut()
.charge_or_halt(RuntimeCosts::CopyFromContract(input_len as u32))?;
},
};
if !value.is_zero() {
interpreter
.ext
.frame_meter_mut()
.charge_or_halt(RuntimeCosts::CallTransferSurcharge {
dust_transfer: Pallet::<E::T>::has_dust(value),
})?;
}
ControlFlow::Continue(())
}