1#![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))]
58pub struct Vicinity {
60 pub gas_price: U256,
62 pub origin: H160,
64}
65
66pub const ACCOUNT_BASIC_PROOF_SIZE: u64 = 108;
68pub const ACCOUNT_CODES_METADATA_PROOF_SIZE: u64 = 76;
70pub const ACCOUNT_STORAGE_PROOF_SIZE: u64 = 116;
72pub const WRITE_PROOF_SIZE: u64 = 32;
74pub const IS_EMPTY_CHECK_PROOF_SIZE: u64 = 93;
76pub 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 pub standard: U256,
211 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#[derive(Clone, Eq, PartialEq, Debug, Encode, Decode)]
247#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
248pub struct GenesisAccount {
249 pub nonce: U256,
251 pub balance: U256,
253 pub storage: BTreeMap<H256, H256>,
255 pub code: Vec<u8>,
257}
258
259pub trait FeeCalculator {
261 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
271pub 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}