diff --git a/frame/ethereum/src/lib.rs b/frame/ethereum/src/lib.rs index 56eb6b3fd4..f5d4740c30 100644 --- a/frame/ethereum/src/lib.rs +++ b/frame/ethereum/src/lib.rs @@ -690,8 +690,8 @@ impl Pallet { true, ); if let Some(weight_info) = weight_info { - if let Some(proof_size_usage) = weight_info.proof_size_usage { - *gas_to_weight.proof_size_mut() = proof_size_usage; + if let Some(proof_size_meter) = weight_info.proof_size_meter { + *gas_to_weight.proof_size_mut() = proof_size_meter.usage(); } } Some(gas_to_weight) diff --git a/frame/evm/src/lib.rs b/frame/evm/src/lib.rs index fb3a0388f8..569642068c 100644 --- a/frame/evm/src/lib.rs +++ b/frame/evm/src/lib.rs @@ -268,8 +268,8 @@ pub mod pallet { true, ); if let Some(weight_info) = info.weight_info { - if let Some(proof_size_usage) = weight_info.proof_size_usage { - *gas_to_weight.proof_size_mut() = proof_size_usage; + if let Some(proof_size_meter) = weight_info.proof_size_meter { + *gas_to_weight.proof_size_mut() = proof_size_meter.usage(); } } Some(gas_to_weight) @@ -355,8 +355,8 @@ pub mod pallet { true, ); if let Some(weight_info) = info.weight_info { - if let Some(proof_size_usage) = weight_info.proof_size_usage { - *gas_to_weight.proof_size_mut() = proof_size_usage; + if let Some(proof_size_meter) = weight_info.proof_size_meter { + *gas_to_weight.proof_size_mut() = proof_size_meter.usage(); } } Some(gas_to_weight) @@ -443,8 +443,8 @@ pub mod pallet { true, ); if let Some(weight_info) = info.weight_info { - if let Some(proof_size_usage) = weight_info.proof_size_usage { - *gas_to_weight.proof_size_mut() = proof_size_usage; + if let Some(proof_size_meter) = weight_info.proof_size_meter { + *gas_to_weight.proof_size_mut() = proof_size_meter.usage(); } } Some(gas_to_weight) diff --git a/frame/evm/src/runner/stack.rs b/frame/evm/src/runner/stack.rs index 7af212593a..9eeece6297 100644 --- a/frame/evm/src/runner/stack.rs +++ b/frame/evm/src/runner/stack.rs @@ -254,8 +254,7 @@ where Some(weight_info) => U256::from(sp_std::cmp::max( used_gas, weight_info - .proof_size_usage - .unwrap_or_default() + .proof_size_usage() .saturating_mul(T::GasLimitPovSizeRatio::get()), )), _ => used_gas.into(), @@ -1057,8 +1056,8 @@ where // Record proof_size // Return if proof size recording is disabled - let proof_size_limit = if let Some(proof_size_limit) = weight_info.proof_size_limit { - proof_size_limit + let proof_size_limit = if let Some(proof_size_meter) = weight_info.proof_size_meter { + proof_size_meter.limit() } else { return Ok(()); }; diff --git a/frame/evm/src/tests.rs b/frame/evm/src/tests.rs index bb1850708c..4e3d5a7416 100644 --- a/frame/evm/src/tests.rs +++ b/frame/evm/src/tests.rs @@ -184,8 +184,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); @@ -245,8 +244,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); @@ -302,8 +300,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); @@ -351,8 +348,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); @@ -401,8 +397,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); @@ -458,9 +453,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); - + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); } @@ -528,8 +521,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(expected_proof_size, actual_proof_size); }); @@ -615,8 +607,7 @@ mod proof_size_test { let actual_proof_size = result .weight_info .expect("weight info") - .proof_size_usage - .expect("proof size usage"); + .proof_size_usage(); assert_eq!(used_gas.standard, U256::from(21_000)); assert_eq!(used_gas.effective, U256::from(actual_proof_size * ratio)); diff --git a/primitives/evm/src/lib.rs b/primitives/evm/src/lib.rs index 138ae72536..9e2765ff77 100644 --- a/primitives/evm/src/lib.rs +++ b/primitives/evm/src/lib.rs @@ -18,11 +18,12 @@ #![cfg_attr(not(feature = "std"), no_std)] #![deny(unused_crate_dependencies)] +mod metric; mod precompile; mod validation; -mod metric; use frame_support::weights::{constants::WEIGHT_REF_TIME_PER_MILLIS, Weight}; +use metric::ProofSizeMeter; use scale_codec::{Decode, Encode}; use scale_info::TypeInfo; #[cfg(feature = "serde")] @@ -78,9 +79,8 @@ pub enum AccessedStorage { #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] pub struct WeightInfo { pub ref_time_limit: Option, - pub proof_size_limit: Option, pub ref_time_usage: Option, - pub proof_size_usage: Option, + pub proof_size_meter: Option, } impl WeightInfo { @@ -95,16 +95,17 @@ impl WeightInfo { { Some(WeightInfo { ref_time_limit: Some(weight_limit.ref_time()), - proof_size_limit: Some(weight_limit.proof_size()), ref_time_usage: Some(0u64), - proof_size_usage: Some(proof_size_base_cost), + proof_size_meter: Some( + ProofSizeMeter::new(proof_size_base_cost, weight_limit.proof_size()) + .map_err(|_| "invalid proof size base cost")?, + ), }) } (Some(weight_limit), None) => Some(WeightInfo { ref_time_limit: Some(weight_limit.ref_time()), - proof_size_limit: None, ref_time_usage: Some(0u64), - proof_size_usage: None, + proof_size_meter: None, }), _ => return Err("must provide Some valid weight limit or None"), }) @@ -129,22 +130,23 @@ impl WeightInfo { Ok(()) } pub fn try_record_proof_size_or_fail(&mut self, cost: u64) -> Result<(), ExitError> { - if let (Some(proof_size_usage), Some(proof_size_limit)) = - (self.proof_size_usage, self.proof_size_limit) - { - let proof_size_usage = self.try_consume(cost, proof_size_limit, proof_size_usage)?; - if proof_size_usage > proof_size_limit { - return Err(ExitError::OutOfGas); - } - self.proof_size_usage = Some(proof_size_usage); + if let Some(proof_size_meter) = self.proof_size_meter.as_mut() { + proof_size_meter + .record_proof_size(cost) + .map_err(|_| ExitError::OutOfGas)?; } + Ok(()) } pub fn refund_proof_size(&mut self, amount: u64) { - if let Some(proof_size_usage) = self.proof_size_usage { - let proof_size_usage = proof_size_usage.saturating_sub(amount); - self.proof_size_usage = Some(proof_size_usage); - } + self.proof_size_meter.as_mut().map(|proof_size_meter| { + proof_size_meter.refund(amount); + }); + } + + pub fn proof_size_usage(&self) -> u64 { + self.proof_size_meter + .map_or(0, |proof_size_meter| proof_size_meter.usage()) } pub fn refund_ref_time(&mut self, amount: u64) { if let Some(ref_time_usage) = self.ref_time_usage { diff --git a/primitives/evm/src/metric.rs b/primitives/evm/src/metric.rs index 15f8b43e03..885e1df9b1 100644 --- a/primitives/evm/src/metric.rs +++ b/primitives/evm/src/metric.rs @@ -1,6 +1,13 @@ -use evm::{gasometer::GasCost, ExitError, Opcode}; +use evm::{gasometer::GasCost, Opcode}; +use scale_codec::{Decode, Encode}; +use scale_info::TypeInfo; +#[cfg(feature = "serde")] +use serde::{Deserialize, Serialize}; +use sp_core::U256; use sp_runtime::{traits::CheckedAdd, Saturating}; +use crate::AccessedStorage; + #[derive(Debug, PartialEq)] /// Metric error. pub enum MetricError { @@ -10,14 +17,8 @@ pub enum MetricError { InvalidBaseCost, } -impl Into for MetricError { - fn into(self) -> ExitError { - match self { - MetricError::LimitExceeded | MetricError::InvalidBaseCost => ExitError::OutOfGas, - } - } -} - +#[derive(Clone, Copy, Encode, Decode, PartialEq, Eq, Debug, TypeInfo)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] /// A struct that keeps track of metric usage and limit. pub struct Metric { limit: T, @@ -65,12 +66,26 @@ where fn refund(&mut self, amount: T) { self.usage = self.usage.saturating_sub(amount); } + + /// Returns the usage. + fn usage(&self) -> T { + self.usage + } } -/// A struct that keeps track of the size of the proof. +#[derive(Clone, Copy, Encode, Decode, PartialEq, Eq, Debug, TypeInfo)] +#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))] +/// A struct that keeps track of the proof size and limit. pub struct ProofSizeMeter(Metric); impl ProofSizeMeter { + /// `System::Account` 16(hash) + 20 (key) + 60 (AccountInfo::max_encoded_len) + pub const ACCOUNT_BASIC_PROOF_SIZE: u64 = 96; + /// `AccountCodesMetadata` read, temptatively 16 (hash) + 20 (key) + 40 (CodeMetadata). + pub const ACCOUNT_CODES_METADATA_PROOF_SIZE: u64 = 76; + /// Account basic proof size + 5 bytes max of `decode_len` call. + pub const IS_EMPTY_CHECK_PROOF_SIZE: u64 = 93; + /// Creates a new `ProofSizeMetric` instance with the given limit. pub fn new(base_cost: u64, limit: u64) -> Result { Ok(Self(Metric::new(base_cost, limit)?)) @@ -81,9 +96,24 @@ impl ProofSizeMeter { /// # Errors /// /// Returns `MetricError::LimitExceeded` if the proof size exceeds the limit. - fn record_proof_size(&mut self, size: u64) -> Result<(), MetricError> { + pub fn record_proof_size(&mut self, size: u64) -> Result<(), MetricError> { self.0.record_cost(size) } + + /// Refunds the given amount of proof size. + pub fn refund(&mut self, amount: u64) { + self.0.refund(amount) + } + + /// Returns the proof size usage. + pub fn usage(&self) -> u64 { + self.0.usage() + } + + /// Returns the proof size limit. + pub fn limit(&self) -> u64 { + self.0.limit + } } /// A struct that keeps track of storage usage (newly created storage) and limit.