fp_evm/
lib.rs

1// This file is part of Frontier.
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
18#![cfg_attr(not(feature = "std"), no_std)]
19#![warn(unused_crate_dependencies)]
20
21extern crate alloc;
22
23mod account_provider;
24mod precompile;
25mod storage_oog;
26mod validation;
27
28use alloc::{collections::BTreeMap, vec::Vec};
29use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight};
30use scale_codec::{Decode, DecodeWithMemTracking, Encode};
31use scale_info::TypeInfo;
32#[cfg(feature = "serde")]
33use serde::{Deserialize, Serialize};
34use sp_core::{H160, H256, U256};
35use sp_runtime::Perbill;
36
37pub use evm::{
38	backend::{Basic as Account, Log},
39	Config, ExitReason, Opcode,
40};
41
42pub use self::{
43	account_provider::AccountProvider,
44	precompile::{
45		Context, ExitError, ExitRevert, ExitSucceed, IsPrecompileResult, LinearCostPrecompile,
46		Precompile, PrecompileFailure, PrecompileHandle, PrecompileOutput, PrecompileResult,
47		PrecompileSet, Transfer,
48	},
49	storage_oog::{handle_storage_oog, set_storage_oog},
50	validation::{
51		CheckEvmTransaction, CheckEvmTransactionConfig, CheckEvmTransactionInput,
52		TransactionValidationError,
53	},
54};
55
56#[derive(Clone, Eq, PartialEq, Default, Debug, Encode, Decode)]
57#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
58/// External input from the transaction.
59pub struct Vicinity {
60	/// Current transaction gas price.
61	pub gas_price: U256,
62	/// Origin of the transaction.
63	pub origin: H160,
64}
65
66/// `System::Account` 16(hash) + 20 (key) + 72 (AccountInfo::max_encoded_len)
67pub const ACCOUNT_BASIC_PROOF_SIZE: u64 = 108;
68/// `AccountCodesMetadata` read, temtatively 16 (hash) + 20 (key) + 40 (CodeMetadata).
69pub const ACCOUNT_CODES_METADATA_PROOF_SIZE: u64 = 76;
70/// 16 (hash1) + 20 (key1) + 16 (hash2) + 32 (key2) + 32 (value)
71pub const ACCOUNT_STORAGE_PROOF_SIZE: u64 = 116;
72/// Fixed trie 32 byte hash.
73pub const WRITE_PROOF_SIZE: u64 = 32;
74/// Account basic proof size + 5 bytes max of `decode_len` call.
75pub const IS_EMPTY_CHECK_PROOF_SIZE: u64 = 93;
76/// `AccountCodes` key size. 16 (hash) + 20 (key)
77pub const ACCOUNT_CODES_KEY_SIZE: u64 = 36;
78
79pub enum AccessedStorage {
80	AccountCodes(H160),
81	AccountStorages((H160, H256)),
82}
83
84#[derive(
85	Clone,
86	Copy,
87	Eq,
88	PartialEq,
89	Debug,
90	Encode,
91	Decode,
92	DecodeWithMemTracking,
93	Default,
94	TypeInfo
95)]
96#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
97pub struct WeightInfo {
98	pub ref_time_limit: Option<u64>,
99	pub proof_size_limit: Option<u64>,
100	pub ref_time_usage: Option<u64>,
101	pub proof_size_usage: Option<u64>,
102}
103
104impl WeightInfo {
105	pub fn new_from_weight_limit(
106		weight_limit: Option<Weight>,
107		proof_size_base_cost: Option<u64>,
108	) -> Result<Option<Self>, &'static str> {
109		Ok(match (weight_limit, proof_size_base_cost) {
110			(None, _) => None,
111			(Some(weight_limit), Some(proof_size_base_cost))
112				if weight_limit.proof_size() >= proof_size_base_cost =>
113			{
114				Some(WeightInfo {
115					ref_time_limit: Some(weight_limit.ref_time()),
116					proof_size_limit: Some(weight_limit.proof_size()),
117					ref_time_usage: Some(0u64),
118					proof_size_usage: Some(proof_size_base_cost),
119				})
120			}
121			(Some(weight_limit), None) => Some(WeightInfo {
122				ref_time_limit: Some(weight_limit.ref_time()),
123				proof_size_limit: None,
124				ref_time_usage: Some(0u64),
125				proof_size_usage: None,
126			}),
127			_ => return Err("must provide Some valid weight limit or None"),
128		})
129	}
130
131	fn try_consume(&self, cost: u64, limit: u64, usage: u64) -> Result<u64, ExitError> {
132		let usage = usage.checked_add(cost).ok_or(ExitError::OutOfGas)?;
133		if usage > limit {
134			storage_oog::set_storage_oog();
135			return Err(ExitError::OutOfGas);
136		}
137		Ok(usage)
138	}
139
140	pub fn try_record_ref_time_or_fail(&mut self, cost: u64) -> Result<(), ExitError> {
141		if let (Some(ref_time_usage), Some(ref_time_limit)) =
142			(self.ref_time_usage, self.ref_time_limit)
143		{
144			match self.try_consume(cost, ref_time_limit, ref_time_usage) {
145				Ok(ref_time_usage) => {
146					self.ref_time_usage = Some(ref_time_usage);
147				}
148				Err(e) => {
149					self.ref_time_usage = Some(ref_time_limit);
150					return Err(e);
151				}
152			}
153		}
154		Ok(())
155	}
156
157	pub fn try_record_proof_size_or_fail(&mut self, cost: u64) -> Result<(), ExitError> {
158		if let (Some(proof_size_usage), Some(proof_size_limit)) =
159			(self.proof_size_usage, self.proof_size_limit)
160		{
161			match self.try_consume(cost, proof_size_limit, proof_size_usage) {
162				Ok(proof_size_usage) => {
163					self.proof_size_usage = Some(proof_size_usage);
164				}
165				Err(e) => {
166					self.proof_size_usage = Some(proof_size_limit);
167					return Err(e);
168				}
169			}
170		}
171		Ok(())
172	}
173
174	pub fn refund_proof_size(&mut self, amount: u64) {
175		if let Some(proof_size_usage) = self.proof_size_usage {
176			let proof_size_usage = proof_size_usage.saturating_sub(amount);
177			self.proof_size_usage = Some(proof_size_usage);
178		}
179	}
180
181	pub fn refund_ref_time(&mut self, amount: u64) {
182		if let Some(ref_time_usage) = self.ref_time_usage {
183			let ref_time_usage = ref_time_usage.saturating_sub(amount);
184			self.ref_time_usage = Some(ref_time_usage);
185		}
186	}
187	pub fn remaining_proof_size(&self) -> Option<u64> {
188		if let (Some(proof_size_usage), Some(proof_size_limit)) =
189			(self.proof_size_usage, self.proof_size_limit)
190		{
191			return Some(proof_size_limit.saturating_sub(proof_size_usage));
192		}
193		None
194	}
195
196	pub fn remaining_ref_time(&self) -> Option<u64> {
197		if let (Some(ref_time_usage), Some(ref_time_limit)) =
198			(self.ref_time_usage, self.ref_time_limit)
199		{
200			return Some(ref_time_limit.saturating_sub(ref_time_usage));
201		}
202		None
203	}
204}
205
206#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
207#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
208pub struct UsedGas {
209	/// The used_gas as returned by the evm gasometer on exit.
210	pub standard: U256,
211	/// The result of applying a gas ratio to the most used
212	/// external metric during the evm execution.
213	pub effective: U256,
214}
215
216#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
217#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
218pub struct ExecutionInfoV2<T> {
219	pub exit_reason: ExitReason,
220	pub value: T,
221	pub used_gas: UsedGas,
222	pub weight_info: Option<WeightInfo>,
223	pub logs: Vec<Log>,
224}
225
226pub type CallInfo = ExecutionInfoV2<Vec<u8>>;
227pub type CreateInfo = ExecutionInfoV2<H160>;
228
229#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode, TypeInfo)]
230#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
231pub enum CallOrCreateInfo {
232	Call(CallInfo),
233	Create(CreateInfo),
234}
235
236#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)]
237#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
238pub struct ExecutionInfo<T> {
239	pub exit_reason: ExitReason,
240	pub value: T,
241	pub used_gas: U256,
242	pub logs: Vec<Log>,
243}
244
245/// Account definition used for genesis block construction.
246#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)]
247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
248pub struct GenesisAccount {
249	/// Account nonce.
250	pub nonce: U256,
251	/// Account balance.
252	pub balance: U256,
253	/// Full account storage.
254	pub storage: BTreeMap<H256, H256>,
255	/// Account code.
256	pub code: Vec<u8>,
257}
258
259/// Trait that outputs the current transaction gas price.
260pub trait FeeCalculator {
261	/// Return the minimal required gas price.
262	fn min_gas_price() -> (U256, Weight);
263}
264
265impl FeeCalculator for () {
266	fn min_gas_price() -> (U256, Weight) {
267		(U256::zero(), Weight::zero())
268	}
269}
270
271/// `WeightPerGas` is an approximate ratio of the amount of Weight per Gas.
272/// u64 works for approximations because Weight is a very small unit compared to gas.
273///
274/// `GAS_PER_MILLIS * WEIGHT_MILLIS_PER_BLOCK * TXN_RATIO ~= BLOCK_GAS_LIMIT`
275/// `WEIGHT_PER_GAS = WEIGHT_REF_TIME_PER_MILLIS / GAS_PER_MILLIS
276///                 = WEIGHT_REF_TIME_PER_MILLIS / (BLOCK_GAS_LIMIT / TXN_RATIO / WEIGHT_MILLIS_PER_BLOCK)
277///                 = TXN_RATIO * (WEIGHT_REF_TIME_PER_MILLIS * WEIGHT_MILLIS_PER_BLOCK) / BLOCK_GAS_LIMIT`
278///
279/// For example, given the 2000ms Weight, from which 75% only are used for transactions,
280/// the total EVM execution gas limit is `GAS_PER_MILLIS * 2000 * 75% = BLOCK_GAS_LIMIT`.
281pub fn weight_per_gas(
282	block_gas_limit: u64,
283	txn_ratio: Perbill,
284	weight_millis_per_block: u64,
285) -> u64 {
286	let weight_per_block = WEIGHT_REF_TIME_PER_MILLIS.saturating_mul(weight_millis_per_block);
287	let weight_per_gas = (txn_ratio * weight_per_block).saturating_div(block_gas_limit);
288	assert!(
289		weight_per_gas >= 1,
290		"WeightPerGas must greater than or equal with 1"
291	);
292	weight_per_gas
293}
294
295#[cfg(test)]
296mod tests {
297	use super::*;
298
299	#[test]
300	fn test_weight_per_gas() {
301		assert_eq!(
302			weight_per_gas(15_000_000, Perbill::from_percent(75), 500),
303			25_000
304		);
305		assert_eq!(
306			weight_per_gas(75_000_000, Perbill::from_percent(75), 2_000),
307			20_000
308		);
309		assert_eq!(
310			weight_per_gas(1_500_000_000_000, Perbill::from_percent(75), 2_000),
311			1
312		);
313	}
314}