referrerpolicy=no-referrer-when-downgrade

pallet_revive/vm/evm/instructions/contract/
call_helpers.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18use crate::{
19	precompiles::{All as AllPrecompiles, Precompiles},
20	vm::{evm::U256Converter, Ext},
21	Pallet, RuntimeCosts,
22};
23use core::ops::Range;
24use revm::{
25	interpreter::{
26		interpreter_action::CallScheme,
27		interpreter_types::{MemoryTr, StackTr},
28		Interpreter,
29	},
30	primitives::{Address, U256},
31};
32use sp_core::H160;
33
34/// Gets memory input and output ranges for call instructions.
35#[inline]
36pub fn get_memory_input_and_out_ranges<'a, E: Ext>(
37	interpreter: &mut Interpreter<crate::vm::evm::EVMInterpreter<'a, E>>,
38) -> Option<(Range<usize>, Range<usize>)> {
39	popn!([in_offset, in_len, out_offset, out_len], interpreter, None);
40
41	let mut in_range = resize_memory(interpreter, in_offset, in_len)?;
42
43	if !in_range.is_empty() {
44		let offset = <_ as MemoryTr>::local_memory_offset(&interpreter.memory);
45		in_range = in_range.start.saturating_add(offset)..in_range.end.saturating_add(offset);
46	}
47
48	let ret_range = resize_memory(interpreter, out_offset, out_len)?;
49	Some((in_range, ret_range))
50}
51
52/// Resize memory and return range of memory.
53/// If `len` is 0 dont touch memory and return `usize::MAX` as offset and 0 as length.
54#[inline]
55pub fn resize_memory<'a, E: Ext>(
56	interpreter: &mut Interpreter<crate::vm::evm::EVMInterpreter<'a, E>>,
57	offset: U256,
58	len: U256,
59) -> Option<Range<usize>> {
60	let len = as_usize_or_fail_ret!(interpreter, len, None);
61	let offset = if len != 0 {
62		let offset = as_usize_or_fail_ret!(interpreter, offset, None);
63		resize_memory!(interpreter, offset, len, None);
64		offset
65	} else {
66		usize::MAX //unrealistic value so we are sure it is not used
67	};
68	Some(offset..offset + len)
69}
70
71/// Calculates gas cost and limit for call instructions.
72#[inline]
73pub fn calc_call_gas<'a, E: Ext>(
74	interpreter: &mut Interpreter<crate::vm::evm::EVMInterpreter<'a, E>>,
75	callee: Address,
76	scheme: CallScheme,
77	input_len: usize,
78	value: U256,
79) -> Option<u64> {
80	let callee: H160 = callee.0 .0.into();
81	let precompile = <AllPrecompiles<E::T>>::get::<E>(&callee.as_fixed_bytes());
82
83	match precompile {
84		Some(precompile) => {
85			// Base cost depending on contract info
86			let base_cost = if precompile.has_contract_info() {
87				RuntimeCosts::PrecompileWithInfoBase
88			} else {
89				RuntimeCosts::PrecompileBase
90			};
91			gas!(interpreter, base_cost, None);
92
93			// Cost for decoding input
94			gas!(interpreter, RuntimeCosts::PrecompileDecode(input_len as u32), None);
95		},
96		None => {
97			// Regular CALL / DELEGATECALL base cost / CALLCODE not supported
98			let base_cost = if scheme.is_delegate_call() {
99				RuntimeCosts::DelegateCallBase
100			} else {
101				RuntimeCosts::CallBase
102			};
103			gas!(interpreter, base_cost, None);
104
105			gas!(interpreter, RuntimeCosts::CopyFromContract(input_len as u32), None);
106		},
107	};
108	if !value.is_zero() {
109		gas!(
110			interpreter,
111			RuntimeCosts::CallTransferSurcharge {
112				dust_transfer: Pallet::<E::T>::has_dust(crate::U256::from_revm_u256(&value)),
113			},
114			None
115		);
116	}
117	Some(u64::MAX) // TODO: Set the right gas limit
118}