diff --git a/Cargo.lock b/Cargo.lock index 4f7bce5aaa3c6..f11953213d01e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4799,6 +4799,7 @@ dependencies = [ "rand 0.8.3", "rand_pcg 0.3.0", "serde", + "smallvec 1.6.1", "sp-core", "sp-io", "sp-runtime", diff --git a/bin/node/runtime/src/lib.rs b/bin/node/runtime/src/lib.rs index 2e54301493731..05f75b14b9603 100644 --- a/bin/node/runtime/src/lib.rs +++ b/bin/node/runtime/src/lib.rs @@ -782,7 +782,6 @@ parameter_types! { pub RentFraction: Perbill = Perbill::from_rational(1u32, 30 * DAYS); pub const SurchargeReward: Balance = 150 * MILLICENTS; pub const SignedClaimHandicap: u32 = 2; - pub const MaxDepth: u32 = 32; pub const MaxValueSize: u32 = 16 * 1024; // The lazy deletion runs inside on_initialize. pub DeletionWeightLimit: Weight = AVERAGE_ON_INITIALIZE_RATIO * @@ -809,7 +808,7 @@ impl pallet_contracts::Config for Runtime { type DepositPerStorageItem = DepositPerStorageItem; type RentFraction = RentFraction; type SurchargeReward = SurchargeReward; - type MaxDepth = MaxDepth; + type CallStack = [pallet_contracts::Frame; 31]; type MaxValueSize = MaxValueSize; type WeightPrice = pallet_transaction_payment::Module; type WeightInfo = pallet_contracts::weights::SubstrateWeight; diff --git a/frame/contracts/Cargo.toml b/frame/contracts/Cargo.toml index ba8069604a77b..9381f3be5c934 100644 --- a/frame/contracts/Cargo.toml +++ b/frame/contracts/Cargo.toml @@ -18,6 +18,7 @@ log = { version = "0.4", default-features = false } parity-wasm = { version = "0.42", default-features = false } pwasm-utils = { version = "0.17", default-features = false } serde = { version = "1", optional = true, features = ["derive"] } +smallvec = { version = "1", default-features = false, features = ["const_generics"] } wasmi-validation = { version = "0.4", default-features = false } # Only used in benchmarking to generate random contract code diff --git a/frame/contracts/src/benchmarking/mod.rs b/frame/contracts/src/benchmarking/mod.rs index 3db04d3caf3dd..107f35e610813 100644 --- a/frame/contracts/src/benchmarking/mod.rs +++ b/frame/contracts/src/benchmarking/mod.rs @@ -166,16 +166,17 @@ where /// Store the supplied storage items into this contracts storage. fn store(&self, items: &Vec<(StorageKey, Vec)>) -> Result<(), &'static str> { - let info = self.alive_info()?; + let mut info = self.alive_info()?; for item in items { Storage::::write( - &self.account_id, - &info.trie_id, + >::block_number(), + &mut info, &item.0, Some(item.1.clone()), ) .map_err(|_| "Failed to write storage to restoration dest")?; } + >::insert(&self.account_id, ContractInfo::Alive(info.clone())); Ok(()) } @@ -1148,16 +1149,17 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![], Endow::Max)?; - let trie_id = instance.alive_info()?.trie_id; + let mut info = instance.alive_info()?; for key in keys { Storage::::write( - &instance.account_id, - &trie_id, + >::block_number(), + &mut info, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, Some(vec![42; T::MaxValueSize::get() as usize]) ) .map_err(|_| "Failed to write to storage during setup.")?; } + >::insert(&instance.account_id, ContractInfo::Alive(info.clone())); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) @@ -1193,16 +1195,17 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![], Endow::Max)?; - let trie_id = instance.alive_info()?.trie_id; + let mut info = instance.alive_info()?; for key in keys { Storage::::write( - &instance.account_id, - &trie_id, + >::block_number(), + &mut info, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, Some(vec![]) ) .map_err(|_| "Failed to write to storage during setup.")?; } + >::insert(&instance.account_id, ContractInfo::Alive(info.clone())); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) @@ -1238,14 +1241,15 @@ benchmarks! { .. Default::default() }); let instance = Contract::::new(code, vec![], Endow::Max)?; - let trie_id = instance.alive_info()?.trie_id; + let mut info = instance.alive_info()?; Storage::::write( - &instance.account_id, - &trie_id, + >::block_number(), + &mut info, key.as_slice().try_into().map_err(|e| "Key has wrong length")?, Some(vec![42u8; (n * 1024) as usize]) ) .map_err(|_| "Failed to write to storage during setup.")?; + >::insert(&instance.account_id, ContractInfo::Alive(info.clone())); let origin = RawOrigin::Signed(instance.caller.clone()); }: call(origin, instance.addr, 0u32.into(), Weight::max_value(), vec![]) diff --git a/frame/contracts/src/chain_extension.rs b/frame/contracts/src/chain_extension.rs index 4ac5300d57d7f..d2839dfdbc2e1 100644 --- a/frame/contracts/src/chain_extension.rs +++ b/frame/contracts/src/chain_extension.rs @@ -56,7 +56,7 @@ use crate::{ Error, - wasm::{Runtime, RuntimeToken}, + wasm::{Runtime, RuntimeCosts}, }; use codec::Decode; use frame_support::weights::Weight; @@ -171,7 +171,7 @@ where /// /// Weight is synonymous with gas in substrate. pub fn charge_weight(&mut self, amount: Weight) -> Result<()> { - self.inner.runtime.charge_gas(RuntimeToken::ChainExtension(amount)).map(|_| ()) + self.inner.runtime.charge_gas(RuntimeCosts::ChainExtension(amount)).map(|_| ()) } /// Grants access to the execution environment of the current contract call. @@ -349,7 +349,7 @@ where buffer, allow_skip, |len| { - weight_per_byte.map(|w| RuntimeToken::ChainExtension(w.saturating_mul(len.into()))) + weight_per_byte.map(|w| RuntimeCosts::ChainExtension(w.saturating_mul(len.into()))) }, ) } diff --git a/frame/contracts/src/exec.rs b/frame/contracts/src/exec.rs index be471ed0c72ea..eea6acf1bfb4e 100644 --- a/frame/contracts/src/exec.rs +++ b/frame/contracts/src/exec.rs @@ -17,22 +17,25 @@ use crate::{ CodeHash, Event, Config, Pallet as Contracts, - TrieId, BalanceOf, ContractInfo, gas::GasMeter, rent::Rent, storage::{self, Storage}, - Error, ContractInfoOf, Schedule, AliveContractInfo, + BalanceOf, ContractInfo, gas::GasMeter, rent::Rent, storage::Storage, + Error, ContractInfoOf, Schedule, AliveContractInfo, AccountCounter, }; use sp_core::crypto::UncheckedFrom; use sp_std::{ prelude::*, marker::PhantomData, + mem, }; -use sp_runtime::{Perbill, traits::{Bounded, Zero, Convert, Saturating}}; +use sp_runtime::{Perbill, traits::{Convert, Saturating}}; use frame_support::{ dispatch::{DispatchResult, DispatchError}, + storage::{with_transaction, TransactionOutcome}, traits::{ExistenceRequirement, Currency, Time, Randomness, Get}, weights::Weight, ensure, }; -use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; +use pallet_contracts_primitives::{ExecReturnValue}; +use smallvec::{SmallVec, Array}; pub type AccountIdOf = ::AccountId; pub type MomentOf = <::Time as Time>::Moment; @@ -113,14 +116,18 @@ where T: Config, T::AccountId: UncheckedFrom + AsRef<[u8]>, { + /// Derive new `RentParams` from the passed in data. + /// + /// `value` is added to the current free and total balance of the contracts' account. fn new>( account_id: &T::AccountId, + value: &BalanceOf, contract: &AliveContractInfo, executable: &E ) -> Self { Self { - total_balance: T::Currency::total_balance(account_id), - free_balance: T::Currency::free_balance(account_id), + total_balance: T::Currency::total_balance(account_id).saturating_add(*value), + free_balance: T::Currency::free_balance(account_id).saturating_add(*value), subsistence_threshold: >::subsistence_threshold(), deposit_per_contract: T::DepositPerContract::get(), deposit_per_storage_byte: T::DepositPerStorageByte::get(), @@ -168,15 +175,20 @@ impl Default for RentParams { pub trait Ext: sealing::Sealed { type T: Config; - /// Returns the storage entry of the executing account by the given `key`. + /// Call (possibly transferring some amount of funds) into the specified account. /// - /// Returns `None` if the `key` wasn't previously set by `set_storage` or - /// was deleted. - fn get_storage(&self, key: &StorageKey) -> Option>; - - /// Sets the storage entry by the given key to the specified value. If `value` is `None` then - /// the storage entry is deleted. - fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult; + /// Returns the original code size of the called contract. + /// + /// # Return Value + /// + /// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)> + fn call( + &mut self, + gas_limit: Weight, + to: AccountIdOf, + value: BalanceOf, + input_data: Vec, + ) -> Result<(ExecReturnValue, u32), (ExecError, u32)>; /// Instantiate a contract from the given code. /// @@ -189,20 +201,13 @@ pub trait Ext: sealing::Sealed { /// Result<(AccountId, ExecReturnValue, CodeSize), (ExecError, CodeSize)> fn instantiate( &mut self, + gas_limit: Weight, code: CodeHash, value: BalanceOf, - gas_meter: &mut GasMeter, input_data: Vec, salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue, u32), (ExecError, u32)>; - /// Transfer some amount of funds into the specified account. - fn transfer( - &mut self, - to: &AccountIdOf, - value: BalanceOf, - ) -> DispatchResult; - /// Transfer all funds to `beneficiary` and delete the contract. /// /// Returns the original code size of the terminated contract. @@ -220,21 +225,6 @@ pub trait Ext: sealing::Sealed { beneficiary: &AccountIdOf, ) -> Result; - /// Call (possibly transferring some amount of funds) into the specified account. - /// - /// Returns the original code size of the called contract. - /// - /// # Return Value - /// - /// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)> - fn call( - &mut self, - to: &AccountIdOf, - value: BalanceOf, - gas_meter: &mut GasMeter, - input_data: Vec, - ) -> Result<(ExecReturnValue, u32), (ExecError, u32)>; - /// Restores the given destination contract sacrificing the current one. /// /// Since this function removes the self contract eagerly, if succeeded, no further actions should @@ -254,6 +244,23 @@ pub trait Ext: sealing::Sealed { delta: Vec, ) -> Result<(u32, u32), (DispatchError, u32, u32)>; + /// Transfer some amount of funds into the specified account. + fn transfer( + &mut self, + to: &AccountIdOf, + value: BalanceOf, + ) -> DispatchResult; + + /// Returns the storage entry of the executing account by the given `key`. + /// + /// Returns `None` if the `key` wasn't previously set by `set_storage` or + /// was deleted. + fn get_storage(&mut self, key: &StorageKey) -> Option>; + + /// Sets the storage entry by the given key to the specified value. If `value` is `None` then + /// the storage entry is deleted. + fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult; + /// Returns a reference to the account id of the caller. fn caller(&self) -> &AccountIdOf; @@ -289,7 +296,7 @@ pub trait Ext: sealing::Sealed { fn set_rent_allowance(&mut self, rent_allowance: BalanceOf); /// Rent allowance of the contract - fn rent_allowance(&self) -> BalanceOf; + fn rent_allowance(&mut self) -> BalanceOf; /// Returns the current block number. fn block_number(&self) -> BlockNumberOf; @@ -305,10 +312,13 @@ pub trait Ext: sealing::Sealed { /// Information needed for rent calculations. fn rent_params(&self) -> &RentParams; + + /// Get a mutable reference to the nested gas meter. + fn gas_meter(&mut self) -> &mut GasMeter; } /// Describes the different functions that can be exported by an [`Executable`]. -#[cfg_attr(test, derive(Clone, Copy, PartialEq))] +#[derive(Clone, Copy, PartialEq)] pub enum ExportedFunction { /// The constructor function which is executed on deployment of a contract. Constructor, @@ -359,15 +369,23 @@ pub trait Executable: Sized { /// all of its emitted storage changes. fn execute>( self, - ext: E, + ext: &mut E, function: &ExportedFunction, input_data: Vec, - gas_meter: &mut GasMeter, ) -> ExecResult; /// The code hash of the executable. fn code_hash(&self) -> &CodeHash; + /// Size of the instrumented code in bytes. + fn code_len(&self) -> u32; + + /// Sum of instrumented and pristine code len. + fn aggregate_code_len(&self) -> u32; + + // The number of contracts using this executable. + fn refcount(&self) -> u32; + /// The storage that is occupied by the instrumented executable and its pristine source. /// /// The returned size is already divided by the number of users who share the code. @@ -378,456 +396,685 @@ pub trait Executable: Sized { /// This works with the current in-memory value of refcount. When calling any contract /// without refetching this from storage the result can be inaccurate as it might be /// working with a stale value. Usually this inaccuracy is tolerable. - fn occupied_storage(&self) -> u32; - - /// Size of the instrumented code in bytes. - fn code_len(&self) -> u32; - - /// Sum of instrumented and pristine code len. - fn aggregate_code_len(&self) -> u32; - - // The number of contracts using this executable. - fn refcount(&self) -> u32; + fn occupied_storage(&self) -> u32 { + // We disregard the size of the struct itself as the size is completely + // dominated by the code size. + let len = self.aggregate_code_len(); + len.checked_div(self.refcount()).unwrap_or(len) + } } -pub struct ExecutionContext<'a, T: Config + 'a, E> { - caller: Option<&'a ExecutionContext<'a, T, E>>, - self_account: T::AccountId, - self_trie_id: Option, - depth: usize, +/// The complete call stack of a contract execution. +/// +/// The call stack is initiated by either a signed origin or one of the contract RPC calls. +/// This type implements `Ext` and by that exposes the business logic of contract execution to +/// the runtime module which interfaces with the contract (the wasm blob) itself. +pub struct Stack<'a, T: Config, E> { + /// The account id of a plain account that initiated the call stack. + /// + /// # Note + /// + /// Please note that it is possible that the id belongs to a contract rather than a plain + /// account when being called through one of the contract RPCs where the client can freely + /// choose the origin. This usually makes no sense but is still possible. + origin: T::AccountId, + /// The cost schedule used when charging from the gas meter. schedule: &'a Schedule, + /// The gas meter where costs are charged to. + gas_meter: &'a mut GasMeter, + /// The timestamp at the point of call stack instantiation. timestamp: MomentOf, + /// The block number at the time of call stack instantiation. block_number: T::BlockNumber, + /// The account counter is cached here when accessed. It is written back when the call stack + /// finishes executing. + account_counter: Option, + /// The actual call stack. One entry per nested contract called/instantiated. + /// This does **not** include the [`Self::first_frame`]. + frames: SmallVec, + /// Statically guarantee that each call stack has at least one frame. + first_frame: Frame, + /// No executable is held by the struct but influences its behaviour. _phantom: PhantomData, } -impl<'a, T, E> ExecutionContext<'a, T, E> -where - T: Config, - T::AccountId: UncheckedFrom + AsRef<[u8]>, - E: Executable, -{ - /// Create the top level execution context. +/// Represents one entry in the call stack. +/// +/// For each nested contract call or instantiate one frame is created. It holds specific +/// information for the said call and caches the in-storage `ContractInfo` data structure. +pub struct Frame { + /// The account id of the executing contract. + account_id: T::AccountId, + /// The cached in-storage data of the contract. + contract_info: CachedContract, + /// The amount of balance transferred by the caller as part of the call. + value_transferred: BalanceOf, + /// Snapshotted rent information that can be copied to the contract if requested. + rent_params: RentParams, + /// Determines whether this is a call or instantiate frame. + entry_point: ExportedFunction, + /// The gas meter capped to the supplied gas limit. + nested_meter: GasMeter, +} + +/// Parameter passed in when creating a new `Frame`. +/// +/// It determines whether the new frame is for a call or an instantiate. +enum FrameArgs<'a, T: Config, E> { + Call { + /// The account id of the contract that is to be called. + dest: T::AccountId, + /// If `None` the contract info needs to be reloaded from storage. + cached_info: Option>, + }, + Instantiate { + /// The contract or signed origin which instantiates the new contract. + sender: T::AccountId, + /// The seed that should be used to derive a new trie id for the contract. + trie_seed: u64, + /// The executable whose `deploy` function is run. + executable: E, + /// A salt used in the contract address deriviation of the new contract. + salt: &'a [u8], + }, +} + +/// Describes the different states of a contract as contained in a `Frame`. +enum CachedContract { + /// The cached contract is up to date with the in-storage value. + Cached(AliveContractInfo), + /// A recursive call into the same contract did write to the contract info. /// - /// The specified `origin` address will be used as `sender` for. The `origin` must be a regular - /// account (not a contract). - pub fn top_level(origin: T::AccountId, schedule: &'a Schedule) -> Self { - ExecutionContext { - caller: None, - self_trie_id: None, - self_account: origin, - depth: 0, - schedule, - timestamp: T::Time::now(), - block_number: >::block_number(), - _phantom: Default::default(), - } + /// In this case the cached contract is stale and needs to be reloaded from storage. + Invalidated, + /// The current contract executed `terminate` or `restore_to` and removed the contract. + /// + /// In this case a reload is neither allowed nor possible. Please note that recursive + /// calls cannot remove a contract as this is checked and denied. + Terminated, +} + +impl Frame { + /// Return the `contract_info` of the current contract. + fn contract_info(&mut self) -> &mut AliveContractInfo { + self.contract_info.as_alive(&self.account_id) } - fn nested<'b, 'c: 'b>(&'c self, dest: T::AccountId, trie_id: TrieId) - -> ExecutionContext<'b, T, E> - { - ExecutionContext { - caller: Some(self), - self_trie_id: Some(trie_id), - self_account: dest, - depth: self.depth + 1, - schedule: self.schedule, - timestamp: self.timestamp.clone(), - block_number: self.block_number.clone(), - _phantom: Default::default(), + /// Invalidate and return the `contract_info` of the current contract. + fn invalidate(&mut self) -> AliveContractInfo { + self.contract_info.invalidate(&self.account_id) + } + + /// Terminate and return the `contract_info` of the current contract. + /// + /// # Note + /// + /// Under no circumstances the contract is allowed to access the `contract_info` after + /// a call to this function. This would constitute a programming error in the exec module. + fn terminate(&mut self) -> AliveContractInfo { + self.contract_info.terminate(&self.account_id) + } +} + +/// Extract the contract info after loading it from storage. +/// +/// This assumes that `load` was executed before calling this macro. +macro_rules! get_cached_or_panic_after_load { + ($c:expr) => {{ + if let CachedContract::Cached(contract) = $c { + contract + } else { + panic!( + "It is impossible to remove a contract that is on the call stack;\ + See implementations of terminate and restore_to;\ + Therefore fetching a contract will never fail while using an account id + that is currently active on the call stack;\ + qed" + ); } + }} +} + +impl CachedContract { + /// Load the `contract_info` from storage if necessary. + fn load(&mut self, account_id: &T::AccountId) { + if let CachedContract::Invalidated = self { + let contract = >::get(&account_id) + .and_then(|contract| contract.get_alive()); + if let Some(contract) = contract { + *self = CachedContract::Cached(contract); + } + } + } + + /// Return the cached contract_info as alive contract info. + fn as_alive(&mut self, account_id: &T::AccountId) -> &mut AliveContractInfo { + self.load(account_id); + get_cached_or_panic_after_load!(self) } - /// Make a call to the specified address, optionally transferring some funds. + /// Invalidate and return the contract info. + fn invalidate(&mut self, account_id: &T::AccountId) -> AliveContractInfo { + self.load(account_id); + get_cached_or_panic_after_load!(mem::replace(self, Self::Invalidated)) + } + + /// Terminate and return the contract info. + fn terminate(&mut self, account_id: &T::AccountId) -> AliveContractInfo { + self.load(account_id); + get_cached_or_panic_after_load!(mem::replace(self, Self::Terminated)) + } +} + +impl<'a, T, E> Stack<'a, T, E> +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]>, + E: Executable, +{ + /// Create an run a new call stack by calling into `dest`. /// /// # Return Value /// /// Result<(ExecReturnValue, CodeSize), (ExecError, CodeSize)> - pub fn call( - &mut self, + pub fn run_call( + origin: T::AccountId, dest: T::AccountId, + gas_meter: &'a mut GasMeter, + schedule: &'a Schedule, value: BalanceOf, - gas_meter: &mut GasMeter, input_data: Vec, ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { - if self.depth == T::MaxDepth::get() as usize { - return Err((Error::::MaxCallDepthReached.into(), 0)); - } + let (mut stack, executable) = Self::new( + FrameArgs::Call{dest, cached_info: None}, + origin, + gas_meter, + schedule, + value, + )?; + stack.run(executable, input_data) + } - let contract = >::get(&dest) - .and_then(|contract| contract.get_alive()) - .ok_or((Error::::NotCallable.into(), 0))?; + /// Create and run a new call stack by instantiating a new contract. + /// + /// # Return Value + /// + /// Result<(NewContractAccountId, ExecReturnValue), ExecError)> + pub fn run_instantiate( + origin: T::AccountId, + executable: E, + gas_meter: &'a mut GasMeter, + schedule: &'a Schedule, + value: BalanceOf, + input_data: Vec, + salt: &[u8], + ) -> Result<(T::AccountId, ExecReturnValue), ExecError> { + let (mut stack, executable) = Self::new( + FrameArgs::Instantiate { + sender: origin.clone(), + trie_seed: Self::initial_trie_seed(), + executable, + salt, + }, + origin, + gas_meter, + schedule, + value, + ).map_err(|(e, _code_len)| e)?; + let account_id = stack.top_frame().account_id.clone(); + stack.run(executable, input_data) + .map(|(ret, _code_len)| (account_id, ret)) + .map_err(|(err, _code_len)| err) + } - let executable = E::from_storage(contract.code_hash, &self.schedule, gas_meter) - .map_err(|e| (e.into(), 0))?; - let code_len = executable.code_len(); - - // This charges the rent and denies access to a contract that is in need of - // eviction by returning `None`. We cannot evict eagerly here because those - // changes would be rolled back in case this contract is called by another - // contract. - // See: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324 - let contract = Rent::::charge(&dest, contract, executable.occupied_storage()) - .map_err(|e| (e.into(), code_len))? - .ok_or((Error::::NotCallable.into(), code_len))?; - - let transactor_kind = self.transactor_kind(); - let caller = self.self_account.clone(); - - let result = self.with_nested_context(dest.clone(), contract.trie_id.clone(), |nested| { - if value > BalanceOf::::zero() { - transfer::( - TransferCause::Call, - transactor_kind, - &caller, - &dest, - value, - )? + /// Create a new call stack. + fn new( + args: FrameArgs, + origin: T::AccountId, + gas_meter: &'a mut GasMeter, + schedule: &'a Schedule, + value: BalanceOf, + ) -> Result<(Self, E), (ExecError, u32)> { + let (first_frame, executable) = Self::new_frame(args, value, gas_meter, 0, &schedule)?; + let stack = Self { + origin, + schedule, + gas_meter, + timestamp: T::Time::now(), + block_number: >::block_number(), + account_counter: None, + first_frame, + frames: Default::default(), + _phantom: Default::default(), + }; + + Ok((stack, executable)) + } + + /// Construct a new frame. + /// + /// This does not take `self` because when constructing the first frame `self` is + /// not initialized, yet. + fn new_frame( + frame_args: FrameArgs, + value_transferred: BalanceOf, + gas_meter: &mut GasMeter, + gas_limit: Weight, + schedule: &Schedule + ) -> Result<(Frame, E), (ExecError, u32)> { + let (account_id, contract_info, executable, entry_point) = match frame_args { + FrameArgs::Call{dest, cached_info} => { + let contract = if let Some(contract) = cached_info { + contract + } else { + >::get(&dest) + .and_then(|contract| contract.get_alive()) + .ok_or((Error::::NotCallable.into(), 0))? + }; + + let executable = E::from_storage(contract.code_hash, schedule, gas_meter) + .map_err(|e| (e.into(), 0))?; + + // This charges the rent and denies access to a contract that is in need of + // eviction by returning `None`. We cannot evict eagerly here because those + // changes would be rolled back in case this contract is called by another + // contract. + // See: https://github.com/paritytech/substrate/issues/6439#issuecomment-648754324 + let contract = Rent:: + ::charge(&dest, contract, executable.occupied_storage()) + .map_err(|e| (e.into(), executable.code_len()))? + .ok_or((Error::::NotCallable.into(), executable.code_len()))?; + (dest, contract, executable, ExportedFunction::Call) + } + FrameArgs::Instantiate{sender, trie_seed, executable, salt} => { + let account_id = >::contract_address( + &sender, executable.code_hash(), &salt, + ); + let trie_id = Storage::::generate_trie_id(&account_id, trie_seed); + let contract = Storage::::new_contract( + &account_id, + trie_id, + executable.code_hash().clone(), + ).map_err(|e| (e.into(), executable.code_len()))?; + (account_id, contract, executable, ExportedFunction::Constructor) } + }; + + let frame = Frame { + rent_params: RentParams::new( + &account_id, &value_transferred, &contract_info, &executable, + ), + value_transferred, + contract_info: CachedContract::Cached(contract_info), + account_id, + entry_point, + nested_meter: gas_meter.nested(gas_limit) + .map_err(|e| (e.into(), executable.code_len()))?, + }; + + Ok((frame, executable)) + } - let call_context = nested.new_call_context( - caller, &dest, value, &contract, &executable, + /// Create a subsequent nested frame. + fn push_frame( + &mut self, + frame_args: FrameArgs, + value_transferred: BalanceOf, + gas_limit: Weight, + ) -> Result { + if self.frames.len() == T::CallStack::size() { + return Err((Error::::MaxCallDepthReached.into(), 0)); + } + + // We need to make sure that changes made to the contract info are not discarded. + // See the `in_memory_changes_not_discarded` test for more information. + // We do not store on instantiate because we do not allow to call into a contract + // from its own constructor. + let frame = self.top_frame(); + if let (CachedContract::Cached(contract), ExportedFunction::Call) = + (&frame.contract_info, frame.entry_point) + { + >::insert( + frame.account_id.clone(), + ContractInfo::Alive(contract.clone()), ); + } - let output = executable.execute( - call_context, - &ExportedFunction::Call, - input_data, - gas_meter, - ).map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?; - Ok(output) - }).map_err(|e| (e, code_len))?; - Ok((result, code_len)) + let nested_meter = &mut self.frames + .last_mut() + .unwrap_or(&mut self.first_frame) + .nested_meter; + let (frame, executable) = Self::new_frame( + frame_args, + value_transferred, + nested_meter, + gas_limit, + self.schedule, + )?; + self.frames.push(frame); + Ok(executable) } - pub fn instantiate( + /// Run the current (top) frame. + /// + /// This can be either a call or an instantiate. + fn run( &mut self, - endowment: BalanceOf, - gas_meter: &mut GasMeter, executable: E, - input_data: Vec, - salt: &[u8], - ) -> Result<(T::AccountId, ExecReturnValue), ExecError> { - if self.depth == T::MaxDepth::get() as usize { - Err(Error::::MaxCallDepthReached)? - } - - let transactor_kind = self.transactor_kind(); - let caller = self.self_account.clone(); - let dest = Contracts::::contract_address(&caller, executable.code_hash(), salt); - - let output = frame_support::storage::with_transaction(|| { - // Generate the trie id in a new transaction to only increment the counter on success. - let dest_trie_id = Storage::::generate_trie_id(&dest); - - let output = self.with_nested_context(dest.clone(), dest_trie_id, |nested| { - let contract = Storage::::place_contract( - &dest, - nested - .self_trie_id - .clone() - .expect("the nested context always has to have self_trie_id"), - executable.code_hash().clone() - )?; - - // Send funds unconditionally here. If the `endowment` is below existential_deposit - // then error will be returned here. - transfer::( - TransferCause::Instantiate, - transactor_kind, - &caller, - &dest, - endowment, - )?; - - // Cache the value before calling into the constructor because that - // consumes the value. If the constructor creates additional contracts using - // the same code hash we still charge the "1 block rent" as if they weren't - // spawned. This is OK as overcharging is always safe. - let occupied_storage = executable.occupied_storage(); - - let call_context = nested.new_call_context( - caller.clone(), - &dest, - endowment, - &contract, - &executable, - ); + input_data: Vec + ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { + let entry_point = self.top_frame().entry_point; + let do_transaction = || { + // Cache the value before calling into the constructor because that + // consumes the value. If the constructor creates additional contracts using + // the same code hash we still charge the "1 block rent" as if they weren't + // spawned. This is OK as overcharging is always safe. + let occupied_storage = executable.occupied_storage(); + let code_len = executable.code_len(); + + // Every call or instantiate also optionally transferres balance. + self.initial_transfer().map_err(|e| (ExecError::from(e), 0))?; + + // Call into the wasm blob. + let output = executable.execute( + self, + &entry_point, + input_data, + ).map_err(|e| (ExecError { error: e.error, origin: ErrorOrigin::Callee }, code_len))?; - let output = executable.execute( - call_context, - &ExportedFunction::Constructor, - input_data, - gas_meter, - ).map_err(|e| ExecError { error: e.error, origin: ErrorOrigin::Callee })?; + // Additional work needs to be performed in case of an instantiation. + if output.is_success() && entry_point == ExportedFunction::Constructor { + let frame = self.top_frame_mut(); + let account_id = frame.account_id.clone(); - // We need to re-fetch the contract because changes are written to storage - // eagerly during execution. - let contract = >::get(&dest) - .and_then(|contract| contract.get_alive()) - .ok_or(Error::::NotCallable)?; + // It is not allowed to terminate a contract inside its constructor. + if let CachedContract::Terminated = frame.contract_info { + return Err((Error::::TerminatedInConstructor.into(), code_len)); + } // Collect the rent for the first block to prevent the creation of very large // contracts that never intended to pay for even one block. // This also makes sure that it is above the subsistence threshold // in order to keep up the guarantuee that we always leave a tombstone behind // with the exception of a contract that called `seal_terminate`. - Rent::::charge(&dest, contract, occupied_storage)? - .ok_or(Error::::NewContractNotFunded)?; + let contract = Rent:: + ::charge(&account_id, frame.invalidate(), occupied_storage) + .map_err(|e| (e.into(), code_len))? + .ok_or((Error::::NewContractNotFunded.into(), code_len))?; + frame.contract_info = CachedContract::Cached(contract); // Deposit an instantiation event. - deposit_event::(vec![], Event::Instantiated(caller.clone(), dest.clone())); + deposit_event::(vec![], Event::Instantiated( + self.caller().clone(), + account_id, + )); + } - Ok(output) - }); + Ok((output, code_len)) + }; - use frame_support::storage::TransactionOutcome::*; + // All changes performed by the contract are executed under a storage transaction. + // This allows for roll back on error. Changes to the cached contract_info are + // comitted or rolled back when popping the frame. + let (success, output) = with_transaction(|| { + let output = do_transaction(); match output { - Ok(_) => Commit(output), - Err(_) => Rollback(output), + Ok((ref result, _)) if result.is_success() => { + TransactionOutcome::Commit((true, output)) + }, + _ => TransactionOutcome::Rollback((false, output)), } - })?; + }); + self.pop_frame(success); + output + } - Ok((dest, output)) + /// Remove the current (top) frame from the stack. + /// + /// This is called after running the current frame. It commits cached values to storage + /// and invalidates all stale references to it that might exist further down the call stack. + fn pop_frame(&mut self, persist: bool) { + // Revert the account counter in case of a failed instantiation. + if !persist && self.top_frame().entry_point == ExportedFunction::Constructor { + self.account_counter.as_mut().map(|c| *c = c.wrapping_sub(1)); + } + + // Pop the current frame from the stack and return it in case it needs to interact + // with duplicates that might exist on the stack. + let frame = self.frames.pop(); + + if let Some(frame) = frame { + let prev = self.top_frame_mut(); + let account_id = &frame.account_id; + prev.nested_meter.absorb_nested(frame.nested_meter); + // Only gas counter changes are persisted in case of a failure. + if !persist { + return; + } + if let CachedContract::Cached(contract) = frame.contract_info { + // optimization: Predecessor is the same contract. + // We can just copy the contract into the predecessor without a storage write. + // This is possible when there is no other contract in-between that could + // trigger a rollback. + if prev.account_id == *account_id { + prev.contract_info = CachedContract::Cached(contract); + return; + } + + // Predecessor is a different contract: We persist the info and invalidate the first + // stale cache we find. This triggers a reload from storage on next use. We skip(1) + // because that case is already handled by the optimization above. Only the first + // cache needs to be invalidated because that one will invalidate the next cache + // when it is popped from the stack. + >::insert(account_id, ContractInfo::Alive(contract)); + if let Some(c) = self.frames_mut().skip(1).find(|f| f.account_id == *account_id) { + c.contract_info = CachedContract::Invalidated; + } + } + } else { + // Write back to the root gas meter. + self.gas_meter.absorb_nested(mem::take(&mut self.first_frame.nested_meter)); + // Only gas counter changes are persisted in case of a failure. + if !persist { + return; + } + if let CachedContract::Cached(contract) = &self.first_frame.contract_info { + >::insert( + &self.first_frame.account_id, + ContractInfo::Alive(contract.clone()) + ); + } + if let Some(counter) = self.account_counter { + >::set(counter); + } + } } - fn new_call_context<'b>( - &'b mut self, - caller: T::AccountId, - dest: &T::AccountId, + /// Transfer some funds from `from` to `to`. + /// + /// We only allow allow for draining all funds of the sender if `allow_death` is + /// is specified as `true`. Otherwise, any transfer that would bring the sender below the + /// subsistence threshold (for contracts) or the existential deposit (for plain accounts) + /// results in an error. + fn transfer( + sender_is_contract: bool, + allow_death: bool, + from: &T::AccountId, + to: &T::AccountId, value: BalanceOf, - contract: &AliveContractInfo, - executable: &E, - ) -> CallContext<'b, 'a, T, E> { - let timestamp = self.timestamp.clone(); - let block_number = self.block_number.clone(); - CallContext { - ctx: self, - caller, - value_transferred: value, - timestamp, - block_number, - rent_params: RentParams::new(dest, contract, executable), - _phantom: Default::default(), + ) -> DispatchResult { + if value == 0u32.into() { + return Ok(()); } + + let existence_requirement = match (allow_death, sender_is_contract) { + (true, _) => ExistenceRequirement::AllowDeath, + (false, true) => { + ensure!( + T::Currency::total_balance(from).saturating_sub(value) >= + Contracts::::subsistence_threshold(), + Error::::BelowSubsistenceThreshold, + ); + ExistenceRequirement::KeepAlive + }, + (false, false) => ExistenceRequirement::KeepAlive, + }; + + T::Currency::transfer(from, to, value, existence_requirement) + .map_err(|_| Error::::TransferFailed)?; + + Ok(()) } - /// Execute the given closure within a nested execution context. - fn with_nested_context(&mut self, dest: T::AccountId, trie_id: TrieId, func: F) - -> ExecResult - where F: FnOnce(&mut ExecutionContext) -> ExecResult - { - use frame_support::storage::TransactionOutcome::*; - let mut nested = self.nested(dest, trie_id); - frame_support::storage::with_transaction(|| { - let output = func(&mut nested); - match output { - Ok(ref rv) if !rv.flags.contains(ReturnFlags::REVERT) => Commit(output), - _ => Rollback(output), - } - }) + // The transfer as performed by a call or instantiate. + fn initial_transfer(&self) -> DispatchResult { + Self::transfer( + self.caller_is_origin(), + false, + self.caller(), + &self.top_frame().account_id, + self.top_frame().value_transferred, + ) } - /// Returns whether a contract, identified by address, is currently live in the execution - /// stack, meaning it is in the middle of an execution. - fn is_live(&self, account: &T::AccountId) -> bool { - &self.self_account == account || - self.caller.map_or(false, |caller| caller.is_live(account)) + /// Wether the caller is the initiator of the call stack. + fn caller_is_origin(&self) -> bool { + !self.frames.is_empty() } - fn transactor_kind(&self) -> TransactorKind { - if self.depth == 0 { - debug_assert!(self.self_trie_id.is_none()); - debug_assert!(self.caller.is_none()); - debug_assert!(ContractInfoOf::::get(&self.self_account).is_none()); - TransactorKind::PlainAccount - } else { - TransactorKind::Contract - } + /// Reference to the current (top) frame. + fn top_frame(&self) -> &Frame { + self.frames.last().unwrap_or(&self.first_frame) } -} -/// Describes whether we deal with a contract or a plain account. -enum TransactorKind { - /// Transaction was initiated from a plain account. That can be either be through a - /// signed transaction or through RPC. - PlainAccount, - /// The call was initiated by a contract account. - Contract, -} + /// Mutable reference to the current (top) frame. + fn top_frame_mut(&mut self) -> &mut Frame { + self.frames.last_mut().unwrap_or(&mut self.first_frame) + } -/// Describes possible transfer causes. -enum TransferCause { - Call, - Instantiate, - Terminate, -} + /// Iterator over all frames. + /// + /// The iterator starts with the top frame and ends with the root frame. + fn frames(&self) -> impl Iterator> { + sp_std::iter::once(&self.first_frame) + .chain(&self.frames) + .rev() + } -/// Transfer some funds from `transactor` to `dest`. -/// -/// We only allow allow for draining all funds of the sender if `cause` is -/// is specified as `Terminate`. Otherwise, any transfer that would bring the sender below the -/// subsistence threshold (for contracts) or the existential deposit (for plain accounts) -/// results in an error. -fn transfer( - cause: TransferCause, - origin: TransactorKind, - transactor: &T::AccountId, - dest: &T::AccountId, - value: BalanceOf, -) -> DispatchResult -where - T::AccountId: UncheckedFrom + AsRef<[u8]>, -{ - use self::TransferCause::*; - use self::TransactorKind::*; - - // Only seal_terminate is allowed to bring the sender below the subsistence - // threshold or even existential deposit. - let existence_requirement = match (cause, origin) { - (Terminate, _) => ExistenceRequirement::AllowDeath, - (_, Contract) => { - ensure!( - T::Currency::total_balance(transactor).saturating_sub(value) >= - Contracts::::subsistence_threshold(), - Error::::BelowSubsistenceThreshold, - ); - ExistenceRequirement::KeepAlive - }, - (_, PlainAccount) => ExistenceRequirement::KeepAlive, - }; + /// Same as `frames` but with a mutable reference as iterator item. + fn frames_mut(&mut self) -> impl Iterator> { + sp_std::iter::once(&mut self.first_frame) + .chain(&mut self.frames) + .rev() + } - T::Currency::transfer(transactor, dest, value, existence_requirement) - .map_err(|_| Error::::TransferFailed)?; + /// Returns whether the current contract is on the stack multiple times. + fn is_recursive(&self) -> bool { + let account_id = &self.top_frame().account_id; + self.frames().skip(1).any(|f| &f.account_id == account_id) + } - Ok(()) -} + /// Increments the cached account id and returns the value to be used for the trie_id. + fn next_trie_seed(&mut self) -> u64 { + let next = if let Some(current) = self.account_counter { + current + 1 + } else { + Self::initial_trie_seed() + }; + self.account_counter = Some(next); + next + } -/// A context that is active within a call. -/// -/// This context has some invariants that must be held at all times. Specifically: -///`ctx` always points to a context of an alive contract. That implies that it has an existent -/// `self_trie_id`. -/// -/// Be advised that there are brief time spans where these invariants could be invalidated. -/// For example, when a contract requests self-termination the contract is removed eagerly. That -/// implies that the control won't be returned to the contract anymore, but there is still some code -/// on the path of the return from that call context. Therefore, care must be taken in these -/// situations. -struct CallContext<'a, 'b: 'a, T: Config + 'b, E> { - ctx: &'a mut ExecutionContext<'b, T, E>, - caller: T::AccountId, - value_transferred: BalanceOf, - timestamp: MomentOf, - block_number: T::BlockNumber, - rent_params: RentParams, - _phantom: PhantomData, + /// The account seed to be used to instantiate the account counter cache. + fn initial_trie_seed() -> u64 { + >::get().wrapping_add(1) + } } -impl<'a, 'b: 'a, T, E> Ext for CallContext<'a, 'b, T, E> +impl<'a, T, E> Ext for Stack<'a, T, E> where - T: Config + 'b, + T: Config, T::AccountId: UncheckedFrom + AsRef<[u8]>, E: Executable, { type T = T; - fn get_storage(&self, key: &StorageKey) -> Option> { - let trie_id = self.ctx.self_trie_id.as_ref().expect( - "`ctx.self_trie_id` points to an alive contract within the `CallContext`;\ - it cannot be `None`;\ - expect can't fail;\ - qed", - ); - Storage::::read(trie_id, key) - } - - fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { - let trie_id = self.ctx.self_trie_id.as_ref().expect( - "`ctx.self_trie_id` points to an alive contract within the `CallContext`;\ - it cannot be `None`;\ - expect can't fail;\ - qed", - ); - // write panics if the passed account is not alive. - // the contract must be in the alive state within the `CallContext`;\ - // the contract cannot be absent in storage; - // write cannot return `None`; - // qed - Storage::::write(&self.ctx.self_account, trie_id, &key, value) + fn call( + &mut self, + gas_limit: Weight, + to: T::AccountId, + value: BalanceOf, + input_data: Vec, + ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { + // We ignore instantiate frames in our search for a cached contract. + // Otherwise it would be possible to recursively call a contract from its own + // constructor: We disallow calling not fully constructed contracts. + let cached_info = self + .frames() + .find(|f| f.entry_point == ExportedFunction::Call && f.account_id == to) + .and_then(|f| { + match &f.contract_info { + CachedContract::Cached(contract) => Some(contract.clone()), + _ => None, + } + }); + let executable = self.push_frame( + FrameArgs::Call{dest: to, cached_info}, + value, + gas_limit + )?; + self.run(executable, input_data) } fn instantiate( &mut self, + gas_limit: Weight, code_hash: CodeHash, endowment: BalanceOf, - gas_meter: &mut GasMeter, input_data: Vec, salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue, u32), (ExecError, u32)> { - let executable = E::from_storage(code_hash, &self.ctx.schedule, gas_meter) + let executable = E::from_storage(code_hash, &self.schedule, self.gas_meter()) .map_err(|e| (e.into(), 0))?; - let code_len = executable.code_len(); - self.ctx.instantiate(endowment, gas_meter, executable, input_data, salt) - .map(|r| (r.0, r.1, code_len)) - .map_err(|e| (e, code_len)) - } - - fn transfer( - &mut self, - to: &T::AccountId, - value: BalanceOf, - ) -> DispatchResult { - transfer::( - TransferCause::Call, - TransactorKind::Contract, - &self.ctx.self_account.clone(), - to, - value, - ) + let trie_seed = self.next_trie_seed(); + let executable = self.push_frame( + FrameArgs::Instantiate { + sender: self.top_frame().account_id.clone(), + trie_seed, + executable, + salt, + }, + endowment, + gas_limit, + )?; + let account_id = self.top_frame().account_id.clone(); + self.run(executable, input_data) + .map(|(ret, code_len)| (account_id, ret, code_len)) } fn terminate( &mut self, beneficiary: &AccountIdOf, ) -> Result { - let self_id = self.ctx.self_account.clone(); - let value = T::Currency::free_balance(&self_id); - if let Some(caller_ctx) = self.ctx.caller { - if caller_ctx.is_live(&self_id) { - return Err((Error::::ReentranceDenied.into(), 0)); - } + if self.is_recursive() { + return Err((Error::::ReentranceDenied.into(), 0)); } - transfer::( - TransferCause::Terminate, - TransactorKind::Contract, - &self_id, + let frame = self.top_frame_mut(); + let info = frame.terminate(); + Storage::::queue_trie_for_deletion(&info).map_err(|e| (e, 0))?; + >::transfer( + true, + true, + &frame.account_id, beneficiary, - value, + T::Currency::free_balance(&frame.account_id), ).map_err(|e| (e, 0))?; - if let Some(ContractInfo::Alive(info)) = ContractInfoOf::::take(&self_id) { - Storage::::queue_trie_for_deletion(&info).map_err(|e| (e, 0))?; - let code_len = E::remove_user(info.code_hash); - Contracts::::deposit_event(Event::Terminated(self_id, beneficiary.clone())); - Ok(code_len) - } else { - panic!( - "this function is only invoked by in the context of a contract;\ - this contract is therefore alive;\ - qed" - ); - } - } - - fn call( - &mut self, - to: &T::AccountId, - value: BalanceOf, - gas_meter: &mut GasMeter, - input_data: Vec, - ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { - self.ctx.call(to.clone(), value, gas_meter, input_data) + ContractInfoOf::::remove(&frame.account_id); + let code_len = E::remove_user(info.code_hash); + Contracts::::deposit_event( + Event::Terminated(frame.account_id.clone(), beneficiary.clone()), + ); + Ok(code_len) } fn restore_to( @@ -837,14 +1084,13 @@ where rent_allowance: BalanceOf, delta: Vec, ) -> Result<(u32, u32), (DispatchError, u32, u32)> { - if let Some(caller_ctx) = self.ctx.caller { - if caller_ctx.is_live(&self.ctx.self_account) { - return Err((Error::::ReentranceDenied.into(), 0, 0)); - } + if self.is_recursive() { + return Err((Error::::ReentranceDenied.into(), 0, 0)); } - + let origin_contract = self.top_frame_mut().contract_info().clone(); let result = Rent::::restore_to( - self.ctx.self_account.clone(), + &self.top_frame().account_id, + origin_contract, dest.clone(), code_hash.clone(), rent_allowance, @@ -854,30 +1100,51 @@ where deposit_event::( vec![], Event::Restored( - self.ctx.self_account.clone(), + self.top_frame().account_id.clone(), dest, code_hash, rent_allowance, ), ); + self.top_frame_mut().terminate(); } result } + fn transfer( + &mut self, + to: &T::AccountId, + value: BalanceOf, + ) -> DispatchResult { + Self::transfer(true, false, &self.top_frame().account_id, to, value) + } + + fn get_storage(&mut self, key: &StorageKey) -> Option> { + Storage::::read(&self.top_frame_mut().contract_info().trie_id, key) + } + + fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { + let block_number = self.block_number; + let frame = self.top_frame_mut(); + Storage::::write( + block_number, frame.contract_info(), &key, value, + ) + } + fn address(&self) -> &T::AccountId { - &self.ctx.self_account + &self.top_frame().account_id } fn caller(&self) -> &T::AccountId { - &self.caller + self.frames().nth(1).map(|f| &f.account_id).unwrap_or(&self.origin) } fn balance(&self) -> BalanceOf { - T::Currency::free_balance(&self.ctx.self_account) + T::Currency::free_balance(&self.top_frame().account_id) } fn value_transferred(&self) -> BalanceOf { - self.value_transferred + self.top_frame().value_transferred } fn random(&self, subject: &[u8]) -> (SeedOf, BlockNumberOf) { @@ -899,24 +1166,16 @@ where fn deposit_event(&mut self, topics: Vec, data: Vec) { deposit_event::( topics, - Event::ContractEmitted(self.ctx.self_account.clone(), data) + Event::ContractEmitted(self.top_frame().account_id.clone(), data) ); } fn set_rent_allowance(&mut self, rent_allowance: BalanceOf) { - if let Err(storage::ContractAbsentError) = - Storage::::set_rent_allowance(&self.ctx.self_account, rent_allowance) - { - panic!( - "`self_account` points to an alive contract within the `CallContext`; - set_rent_allowance cannot return `Err`; qed" - ); - } + self.top_frame_mut().contract_info().rent_allowance = rent_allowance; } - fn rent_allowance(&self) -> BalanceOf { - Storage::::rent_allowance(&self.ctx.self_account) - .unwrap_or_else(|_| >::max_value()) // Must never be triggered actually + fn rent_allowance(&mut self) -> BalanceOf { + self.top_frame_mut().contract_info().rent_allowance } fn block_number(&self) -> T::BlockNumber { self.block_number } @@ -930,11 +1189,15 @@ where } fn schedule(&self) -> &Schedule { - &self.ctx.schedule + &self.schedule } fn rent_params(&self) -> &RentParams { - &self.rent_params + &self.top_frame().rent_params + } + + fn gas_meter(&mut self) -> &mut GasMeter { + &mut self.top_frame_mut().nested_meter } } @@ -953,7 +1216,7 @@ mod sealing { pub trait Sealed {} - impl<'a, 'b: 'a, T: Config, E> Sealed for CallContext<'a, 'b, T, E> {} + impl<'a, T: Config, E> Sealed for Stack<'a, T, E> {} #[cfg(test)] impl Sealed for crate::wasm::MockExt {} @@ -972,7 +1235,7 @@ mod tests { use super::*; use crate::{ gas::GasMeter, tests::{ExtBuilder, Test, Event as MetaEvent}, - storage::{Storage, ContractAbsentError}, + storage::Storage, tests::{ ALICE, BOB, CHARLIE, test_utils::{place_contract, set_balance, get_balance}, @@ -981,13 +1244,13 @@ mod tests { Error, Weight, CurrentSchedule, }; use sp_core::Bytes; - use frame_support::assert_noop; use sp_runtime::DispatchError; use assert_matches::assert_matches; use std::{cell::RefCell, collections::HashMap, rc::Rc}; use pretty_assertions::{assert_eq, assert_ne}; + use pallet_contracts_primitives::ReturnFlags; - type MockContext<'a> = ExecutionContext<'a, Test, MockExecutable>; + type MockStack<'a> = Stack<'a, Test, MockExecutable>; const GAS_LIMIT: Weight = 10_000_000_000; @@ -1008,7 +1271,6 @@ mod tests { struct MockCtx<'a> { ext: &'a mut dyn Ext, input_data: Vec, - gas_meter: &'a mut GasMeter, } #[derive(Clone)] @@ -1028,8 +1290,8 @@ mod tests { impl MockLoader { fn insert( func_type: ExportedFunction, - f: impl Fn(MockCtx, &MockExecutable, - ) -> ExecResult + 'static) -> CodeHash { + f: impl Fn(MockCtx, &MockExecutable) -> ExecResult + 'static, + ) -> CodeHash { LOADER.with(|loader| { let mut loader = loader.borrow_mut(); // Generate code hashes as monotonically increasing values. @@ -1118,19 +1380,17 @@ mod tests { fn execute>( self, - mut ext: E, + ext: &mut E, function: &ExportedFunction, input_data: Vec, - gas_meter: &mut GasMeter, ) -> ExecResult { if let &Constructor = function { MockLoader::increment_refcount(self.code_hash); } if function == &self.func_type { (self.func)(MockCtx { - ext: &mut ext, + ext, input_data, - gas_meter, }, &self) } else { exec_success() @@ -1141,10 +1401,6 @@ mod tests { &self.code_hash } - fn occupied_storage(&self) -> u32 { - 0 - } - fn code_len(&self) -> u32 { 0 } @@ -1162,6 +1418,10 @@ mod tests { Ok(ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }) } + fn exec_trapped() -> ExecResult { + Err(ExecError { error: >::ContractTrapped.into(), origin: ErrorOrigin::Callee }) + } + #[test] fn it_works() { thread_local! { @@ -1177,11 +1437,12 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); place_contract(&BOB, exec_ch); assert_matches!( - ctx.call(BOB, value, &mut gas_meter, vec![]), + MockStack::run_call( + ALICE, BOB, &mut gas_meter, &schedule, value, vec![], + ), Ok(_) ); }); @@ -1200,9 +1461,9 @@ mod tests { set_balance(&origin, 100); set_balance(&dest, 0); - super::transfer::( - super::TransferCause::Call, - super::TransactorKind::PlainAccount, + MockStack::transfer( + true, + false, &origin, &dest, 55, @@ -1227,15 +1488,16 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(origin.clone(), &schedule); place_contract(&BOB, return_ch); set_balance(&origin, 100); let balance = get_balance(&dest); - let output = ctx.call( + let output = MockStack::run_call( + origin.clone(), dest.clone(), - 55, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 55, vec![], ).unwrap(); @@ -1257,9 +1519,9 @@ mod tests { ExtBuilder::default().build().execute_with(|| { set_balance(&origin, 0); - let result = super::transfer::( - super::TransferCause::Call, - super::TransactorKind::PlainAccount, + let result = MockStack::transfer( + false, + false, &origin, &dest, 100, @@ -1287,13 +1549,14 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(origin, &schedule); place_contract(&BOB, return_ch); - let result = ctx.call( + let result = MockStack::run_call( + origin, dest, - 0, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 0, vec![], ); @@ -1316,13 +1579,14 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(origin, &schedule); - place_contract(&BOB, return_ch); + place_contract(&dest, return_ch); - let result = ctx.call( + let result = MockStack::run_call( + origin, dest, - 0, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 0, vec![], ); @@ -1342,13 +1606,14 @@ mod tests { // This one tests passing the input data into a contract via call. ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); place_contract(&BOB, input_data_ch); - let result = ctx.call( + let result = MockStack::run_call( + ALICE, BOB, - 0, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 0, vec![1, 2, 3, 4], ); assert_matches!(result, Ok(_)); @@ -1366,7 +1631,6 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); let subsistence = Contracts::::subsistence_threshold(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage( input_data_ch, &schedule, &mut gas_meter @@ -1374,10 +1638,12 @@ mod tests { set_balance(&ALICE, subsistence * 10); - let result = ctx.instantiate( - subsistence * 3, - &mut gas_meter, + let result = MockStack::run_instantiate( + ALICE, executable, + &mut gas_meter, + &schedule, + subsistence * 3, vec![1, 2, 3, 4], &[], ); @@ -1395,7 +1661,7 @@ mod tests { let value = Default::default(); let recurse_ch = MockLoader::insert(Call, |ctx, _| { // Try to call into yourself. - let r = ctx.ext.call(&BOB, 0, ctx.gas_meter, vec![]); + let r = ctx.ext.call(0, BOB, 0, vec![]); REACHED_BOTTOM.with(|reached_bottom| { let mut reached_bottom = reached_bottom.borrow_mut(); @@ -1418,14 +1684,15 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); set_balance(&BOB, 1); place_contract(&BOB, recurse_ch); - let result = ctx.call( + let result = MockStack::run_call( + ALICE, BOB, - value, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + value, vec![], ); @@ -1451,7 +1718,7 @@ mod tests { // Call into CHARLIE contract. assert_matches!( - ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), + ctx.ext.call(0, CHARLIE, 0, vec![]), Ok(_) ); exec_success() @@ -1466,14 +1733,15 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(origin.clone(), &schedule); place_contract(&dest, bob_ch); place_contract(&CHARLIE, charlie_ch); - let result = ctx.call( + let result = MockStack::run_call( + origin.clone(), dest.clone(), - 0, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 0, vec![], ); @@ -1492,7 +1760,7 @@ mod tests { // Call into charlie contract. assert_matches!( - ctx.ext.call(&CHARLIE, 0, ctx.gas_meter, vec![]), + ctx.ext.call(0, CHARLIE, 0, vec![]), Ok(_) ); exec_success() @@ -1504,14 +1772,15 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); place_contract(&BOB, bob_ch); place_contract(&CHARLIE, charlie_ch); - let result = ctx.call( + let result = MockStack::run_call( + ALICE, BOB, - 0, &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 0, vec![], ); @@ -1525,17 +1794,18 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage( dummy_ch, &schedule, &mut gas_meter ).unwrap(); assert_matches!( - ctx.instantiate( - 0, // <- zero endowment - &mut gas_meter, + MockStack::run_instantiate( + ALICE, executable, + &mut gas_meter, + &schedule, + 0, // <- zero endowment vec![], &[], ), @@ -1553,7 +1823,6 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage( dummy_ch, &schedule, &mut gas_meter @@ -1561,10 +1830,12 @@ mod tests { set_balance(&ALICE, 1000); let instantiated_contract_address = assert_matches!( - ctx.instantiate( - 100, - &mut gas_meter, + MockStack::run_instantiate( + ALICE, executable, + &mut gas_meter, + &schedule, + 100, vec![], &[], ), @@ -1589,7 +1860,6 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage( dummy_ch, &schedule, &mut gas_meter @@ -1597,10 +1867,12 @@ mod tests { set_balance(&ALICE, 1000); let instantiated_contract_address = assert_matches!( - ctx.instantiate( - 100, - &mut gas_meter, + MockStack::run_instantiate( + ALICE, executable, + &mut gas_meter, + &schedule, + 100, vec![], &[], ), @@ -1608,10 +1880,7 @@ mod tests { ); // Check that the account has not been created. - assert_noop!( - Storage::::code_hash(&instantiated_contract_address), - ContractAbsentError, - ); + assert!(Storage::::code_hash(&instantiated_contract_address).is_none()); assert!(events().is_empty()); }); } @@ -1626,9 +1895,9 @@ mod tests { move |ctx, _| { // Instantiate a contract and save it's address in `instantiated_contract_address`. let (address, output, _) = ctx.ext.instantiate( + 0, dummy_ch, Contracts::::subsistence_threshold() * 3, - ctx.gas_meter, vec![], &[48, 49, 50], ).unwrap(); @@ -1640,12 +1909,13 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); set_balance(&ALICE, Contracts::::subsistence_threshold() * 100); place_contract(&BOB, instantiator_ch); assert_matches!( - ctx.call(BOB, 20, &mut GasMeter::::new(GAS_LIMIT), vec![]), + MockStack::run_call( + ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), &schedule, 20, vec![], + ), Ok(_) ); @@ -1671,9 +1941,9 @@ mod tests { // Instantiate a contract and save it's address in `instantiated_contract_address`. assert_matches!( ctx.ext.instantiate( + 0, dummy_ch, 15u64, - ctx.gas_meter, vec![], &[], ), @@ -1689,13 +1959,14 @@ mod tests { ExtBuilder::default().existential_deposit(15).build().execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); set_balance(&ALICE, 1000); set_balance(&BOB, 100); place_contract(&BOB, instantiator_ch); assert_matches!( - ctx.call(BOB, 20, &mut GasMeter::::new(GAS_LIMIT), vec![]), + MockStack::run_call( + ALICE, BOB, &mut GasMeter::::new(GAS_LIMIT), &schedule, 20, vec![], + ), Ok(_) ); @@ -1717,7 +1988,6 @@ mod tests { .build() .execute_with(|| { let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage( terminate_ch, &schedule, &mut gas_meter @@ -1725,14 +1995,16 @@ mod tests { set_balance(&ALICE, 1000); assert_eq!( - ctx.instantiate( - 100, - &mut gas_meter, + MockStack::run_instantiate( + ALICE, executable, + &mut gas_meter, + &schedule, + 100, vec![], &[], ), - Err(Error::::NotCallable.into()) + Err(Error::::TerminatedInConstructor.into()) ); assert_eq!( @@ -1756,17 +2028,18 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let subsistence = Contracts::::subsistence_threshold(); let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); let executable = MockExecutable::from_storage( rent_allowance_ch, &schedule, &mut gas_meter ).unwrap(); set_balance(&ALICE, subsistence * 10); - let result = ctx.instantiate( - subsistence * 5, - &mut gas_meter, + let result = MockStack::run_instantiate( + ALICE, executable, + &mut gas_meter, + &schedule, + subsistence * 5, vec![], &[], ); @@ -1781,21 +2054,22 @@ mod tests { let contract = >::get(address) .and_then(|c| c.get_alive()) .unwrap(); - assert_eq!(ctx.ext.rent_params(), &RentParams::new(address, &contract, executable)); + assert_eq!(ctx.ext.rent_params(), &RentParams::new(address, &0, &contract, executable)); exec_success() }); ExtBuilder::default().build().execute_with(|| { let subsistence = Contracts::::subsistence_threshold(); let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); set_balance(&ALICE, subsistence * 10); place_contract(&BOB, code_hash); - ctx.call( + MockStack::run_call( + ALICE, BOB, - 0, &mut gas_meter, + &schedule, + 0, vec![], ).unwrap(); }); @@ -1809,7 +2083,7 @@ mod tests { let contract = >::get(address) .and_then(|c| c.get_alive()) .unwrap(); - let rent_params = RentParams::new(address, &contract, executable); + let rent_params = RentParams::new(address, &0, &contract, executable); // Changing the allowance during the call: rent params stay unchanged. let allowance = 42; @@ -1821,9 +2095,9 @@ mod tests { // This is also not reflected in the rent params. assert_eq!(MockLoader::refcount(&executable.code_hash), 1); ctx.ext.instantiate( + 0, executable.code_hash, subsistence * 25, - &mut GasMeter::::new(GAS_LIMIT), vec![], &[], ).unwrap(); @@ -1836,16 +2110,100 @@ mod tests { ExtBuilder::default().build().execute_with(|| { let subsistence = Contracts::::subsistence_threshold(); let schedule = >::get(); - let mut ctx = MockContext::top_level(ALICE, &schedule); let mut gas_meter = GasMeter::::new(GAS_LIMIT); set_balance(&ALICE, subsistence * 100); place_contract(&BOB, code_hash); - ctx.call( + MockStack::run_call( + ALICE, BOB, - subsistence * 50, &mut gas_meter, + &schedule, + subsistence * 50, vec![], ).unwrap(); }); } + + #[test] + fn in_memory_changes_not_discarded() { + // Call stack: BOB -> CHARLIE (trap) -> BOB' (success) + // This tests verfies some edge case of the contract info cache: + // We change some value in our contract info before calling into a contract + // that calls into ourself. This triggers a case where BOBs contract info + // is written to storage and invalidated by the successful execution of BOB'. + // The trap of CHARLIE reverts the storage changes to BOB. When the root BOB regains + // control it reloads its contract info from storage. We check that changes that + // are made before calling into CHARLIE are not discarded. + let code_bob = MockLoader::insert(Call, |ctx, _| { + if ctx.input_data[0] == 0 { + let original_allowance = ctx.ext.rent_allowance(); + let changed_allowance = >::max_value() / 2; + assert_ne!(original_allowance, changed_allowance); + ctx.ext.set_rent_allowance(changed_allowance); + assert_eq!( + ctx.ext.call(0, CHARLIE, 0, vec![]).map(|v| v.0).map_err(|e| e.0), + exec_trapped() + ); + assert_eq!(ctx.ext.rent_allowance(), changed_allowance); + assert_ne!(ctx.ext.rent_allowance(), original_allowance); + } + exec_success() + }); + let code_charlie = MockLoader::insert(Call, |ctx, _| { + assert!(ctx.ext.call(0, BOB, 0, vec![99]).is_ok()); + exec_trapped() + }); + + // This one tests passing the input data into a contract via call. + ExtBuilder::default().build().execute_with(|| { + let schedule = >::get(); + place_contract(&BOB, code_bob); + place_contract(&CHARLIE, code_charlie); + + let result = MockStack::run_call( + ALICE, + BOB, + &mut GasMeter::::new(GAS_LIMIT), + &schedule, + 0, + vec![0], + ); + assert_matches!(result, Ok(_)); + }); + } + + #[test] + fn recursive_call_during_constructor_fails() { + let code = MockLoader::insert(Constructor, |ctx, executable| { + let my_hash = >::contract_address(&ALICE, &executable.code_hash, &[]); + assert_matches!( + ctx.ext.call(0, my_hash, 0, vec![]), + Err((ExecError{error, ..}, _)) if error == >::NotCallable.into() + ); + exec_success() + }); + + // This one tests passing the input data into a contract via instantiate. + ExtBuilder::default().build().execute_with(|| { + let schedule = >::get(); + let subsistence = Contracts::::subsistence_threshold(); + let mut gas_meter = GasMeter::::new(GAS_LIMIT); + let executable = MockExecutable::from_storage( + code, &schedule, &mut gas_meter + ).unwrap(); + + set_balance(&ALICE, subsistence * 10); + + let result = MockStack::run_instantiate( + ALICE, + executable, + &mut gas_meter, + &schedule, + subsistence * 3, + vec![], + &[], + ); + assert_matches!(result, Ok(_)); + }); + } } diff --git a/frame/contracts/src/gas.rs b/frame/contracts/src/gas.rs index 31cc5fad30c93..21b9cce38c2ba 100644 --- a/frame/contracts/src/gas.rs +++ b/frame/contracts/src/gas.rs @@ -55,12 +55,7 @@ impl TestAuxiliaries for T {} /// for consistency). If inlined there should be no observable difference compared /// to a hand-written code. pub trait Token: Copy + Clone + TestAuxiliaries { - /// Metadata type, which the token can require for calculating the amount - /// of gas to charge. Can be a some configuration type or - /// just the `()`. - type Metadata; - - /// Calculate amount of gas that should be taken by this token. + /// Return the amount of gas that should be taken by this token. /// /// This function should be really lightweight and must not fail. It is not /// expected that implementors will query the storage or do any kinds of heavy operations. @@ -68,7 +63,7 @@ pub trait Token: Copy + Clone + TestAuxiliaries { /// That said, implementors of this function still can run into overflows /// while calculating the amount. In this case it is ok to use saturating operations /// since on overflow they will return `max_value` which should consume all gas. - fn calculate_amount(&self, metadata: &Self::Metadata) -> Weight; + fn weight(&self) -> Weight; } /// A wrapper around a type-erased trait object of what used to be a `Token`. @@ -87,6 +82,18 @@ pub struct GasMeter { tokens: Vec, } +impl Default for GasMeter { + fn default() -> Self { + Self { + gas_limit: Default::default(), + gas_left: Default::default(), + _phantom: Default::default(), + #[cfg(test)] + tokens: Default::default(), + } + } +} + impl GasMeter where T::AccountId: UncheckedFrom<::Hash> + AsRef<[u8]> @@ -101,6 +108,33 @@ where } } + /// Create a new gas meter by removing gas from the current meter. + /// + /// # Note + /// + /// Passing `0` as amount is interpreted as "all remaining gas". + pub fn nested(&mut self, amount: Weight) -> Result { + let amount = if amount == 0 { + self.gas_left + } else { + amount + }; + + // NOTE that it is ok to allocate all available gas since it still ensured + // by `charge` that it doesn't reach zero. + if self.gas_left < amount { + Err(>::OutOfGas.into()) + } else { + self.gas_left = self.gas_left - amount; + Ok(GasMeter::new(amount)) + } + } + + /// Absorb the remaining gas of a nested meter after we are done using it. + pub fn absorb_nested(&mut self, nested: Self) { + self.gas_left += nested.gas_left; + } + /// Account for used gas. /// /// Amount is calculated by the given `token`. @@ -111,11 +145,7 @@ where /// NOTE that amount is always consumed, i.e. if there is not enough gas /// then the counter will be set to zero. #[inline] - pub fn charge>( - &mut self, - metadata: &Tok::Metadata, - token: Tok, - ) -> Result { + pub fn charge>(&mut self, token: Tok) -> Result { #[cfg(test)] { // Unconditionally add the token to the storage. @@ -126,7 +156,7 @@ where self.tokens.push(erased_tok); } - let amount = token.calculate_amount(metadata); + let amount = token.weight(); let new_value = self.gas_left.checked_sub(amount); // We always consume the gas even if there is not enough gas. @@ -142,13 +172,8 @@ where /// /// This is when a maximum a priori amount was charged and then should be partially /// refunded to match the actual amount. - pub fn adjust_gas>( - &mut self, - charged_amount: ChargedAmount, - metadata: &Tok::Metadata, - token: Tok, - ) { - let adjustment = charged_amount.0.saturating_sub(token.calculate_amount(metadata)); + pub fn adjust_gas>(&mut self, charged_amount: ChargedAmount, token: Tok) { + let adjustment = charged_amount.0.saturating_sub(token.weight()); self.gas_left = self.gas_left.saturating_add(adjustment).min(self.gas_limit); } @@ -161,34 +186,6 @@ where self.gas_left = self.gas_left.saturating_add(amount.0).min(self.gas_limit) } - /// Allocate some amount of gas and perform some work with - /// a newly created nested gas meter. - /// - /// Invokes `f` with either the gas meter that has `amount` gas left or - /// with `None`, if this gas meter has not enough gas to allocate given `amount`. - /// - /// All unused gas in the nested gas meter is returned to this gas meter. - pub fn with_nested>) -> R>( - &mut self, - amount: Weight, - f: F, - ) -> R { - // NOTE that it is ok to allocate all available gas since it still ensured - // by `charge` that it doesn't reach zero. - if self.gas_left < amount { - f(None) - } else { - self.gas_left = self.gas_left - amount; - let mut nested = GasMeter::new(amount); - - let r = f(Some(&mut nested)); - - self.gas_left = self.gas_left + nested.gas_left; - - r - } - } - /// Returns how much gas was used. pub fn gas_spent(&self) -> Weight { self.gas_limit - self.gas_left @@ -269,24 +266,7 @@ mod tests { #[derive(Copy, Clone, PartialEq, Eq, Debug)] struct SimpleToken(u64); impl Token for SimpleToken { - type Metadata = (); - fn calculate_amount(&self, _metadata: &()) -> u64 { self.0 } - } - - struct MultiplierTokenMetadata { - multiplier: u64, - } - /// A simple token that charges for the given amount multiplied to - /// a multiplier taken from a given metadata. - #[derive(Copy, Clone, PartialEq, Eq, Debug)] - struct MultiplierToken(u64); - - impl Token for MultiplierToken { - type Metadata = MultiplierTokenMetadata; - fn calculate_amount(&self, metadata: &MultiplierTokenMetadata) -> u64 { - // Probably you want to use saturating mul in production code. - self.0 * metadata.multiplier - } + fn weight(&self) -> u64 { self.0 } } #[test] @@ -295,34 +275,20 @@ mod tests { assert_eq!(gas_meter.gas_left(), 50000); } - #[test] - fn simple() { - let mut gas_meter = GasMeter::::new(50000); - - let result = gas_meter - .charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10)); - assert!(!result.is_err()); - - assert_eq!(gas_meter.gas_left(), 49_970); - } - #[test] fn tracing() { let mut gas_meter = GasMeter::::new(50000); - assert!(!gas_meter.charge(&(), SimpleToken(1)).is_err()); - assert!(!gas_meter - .charge(&MultiplierTokenMetadata { multiplier: 3 }, MultiplierToken(10)) - .is_err()); + assert!(!gas_meter.charge(SimpleToken(1)).is_err()); - let mut tokens = gas_meter.tokens()[0..2].iter(); - match_tokens!(tokens, SimpleToken(1), MultiplierToken(10),); + let mut tokens = gas_meter.tokens().iter(); + match_tokens!(tokens, SimpleToken(1),); } // This test makes sure that nothing can be executed if there is no gas. #[test] fn refuse_to_execute_anything_if_zero() { let mut gas_meter = GasMeter::::new(0); - assert!(gas_meter.charge(&(), SimpleToken(1)).is_err()); + assert!(gas_meter.charge(SimpleToken(1)).is_err()); } // Make sure that if the gas meter is charged by exceeding amount then not only an error @@ -335,10 +301,10 @@ mod tests { let mut gas_meter = GasMeter::::new(200); // The first charge is should lead to OOG. - assert!(gas_meter.charge(&(), SimpleToken(300)).is_err()); + assert!(gas_meter.charge(SimpleToken(300)).is_err()); // The gas meter is emptied at this moment, so this should also fail. - assert!(gas_meter.charge(&(), SimpleToken(1)).is_err()); + assert!(gas_meter.charge(SimpleToken(1)).is_err()); } @@ -347,6 +313,6 @@ mod tests { #[test] fn charge_exact_amount() { let mut gas_meter = GasMeter::::new(25); - assert!(!gas_meter.charge(&(), SimpleToken(25)).is_err()); + assert!(!gas_meter.charge(SimpleToken(25)).is_err()); } } diff --git a/frame/contracts/src/lib.rs b/frame/contracts/src/lib.rs index 2aa6b8f2ec7b9..33844a41cc7c7 100644 --- a/frame/contracts/src/lib.rs +++ b/frame/contracts/src/lib.rs @@ -103,10 +103,10 @@ pub mod weights; #[cfg(test)] mod tests; -pub use crate::{pallet::*, schedule::Schedule}; +pub use crate::{pallet::*, schedule::Schedule, exec::Frame}; use crate::{ gas::GasMeter, - exec::{ExecutionContext, Executable}, + exec::{Stack as ExecStack, Executable}, rent::Rent, storage::{Storage, DeletedContract, ContractInfo, AliveContractInfo, TombstoneContractInfo}, weights::WeightInfo, @@ -210,9 +210,12 @@ pub mod pallet { #[pallet::constant] type SurchargeReward: Get>; - /// The maximum nesting level of a call/instantiate stack. - #[pallet::constant] - type MaxDepth: Get; + /// The type of the call stack determines the maximum nesting depth of contract calls. + /// + /// The allowed depth is `CallStack::size() + 1`. + /// Therefore a size of `0` means that a contract cannot use call or instantiate. + /// In other words only the origin called "root contract" is allowed to execute then. + type CallStack: smallvec::Array>; /// The maximum size of a storage value and event payload in bytes. #[pallet::constant] @@ -313,8 +316,9 @@ pub mod pallet { let dest = T::Lookup::lookup(dest)?; let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::get(); - let mut ctx = ExecutionContext::>::top_level(origin, &schedule); - let (result, code_len) = match ctx.call(dest, value, &mut gas_meter, data) { + let (result, code_len) = match ExecStack::>::run_call( + origin, dest, &mut gas_meter, &schedule, value, data + ) { Ok((output, len)) => (Ok(output), len), Err((err, len)) => (Err(err), len), }; @@ -365,9 +369,9 @@ pub mod pallet { let executable = PrefabWasmModule::from_code(code, &schedule)?; let code_len = executable.code_len(); ensure!(code_len <= T::MaxCodeSize::get(), Error::::CodeTooLarge); - let mut ctx = ExecutionContext::>::top_level(origin, &schedule); - let result = ctx.instantiate(endowment, &mut gas_meter, executable, data, &salt) - .map(|(_address, output)| output); + let result = ExecStack::>::run_instantiate( + origin, executable, &mut gas_meter, &schedule, endowment, data, &salt, + ).map(|(_address, output)| output); gas_meter.into_dispatch_result( result, T::WeightInfo::instantiate_with_code(code_len / 1024, salt.len() as u32 / 1024) @@ -395,10 +399,10 @@ pub mod pallet { let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::get(); let executable = PrefabWasmModule::from_storage(code_hash, &schedule, &mut gas_meter)?; - let mut ctx = ExecutionContext::>::top_level(origin, &schedule); let code_len = executable.code_len(); - let result = ctx.instantiate(endowment, &mut gas_meter, executable, data, &salt) - .map(|(_address, output)| output); + let result = ExecStack::>::run_instantiate( + origin, executable, &mut gas_meter, &schedule, endowment, data, &salt, + ).map(|(_address, output)| output); gas_meter.into_dispatch_result( result, T::WeightInfo::instantiate(code_len / 1024, salt.len() as u32 / 1024), @@ -606,6 +610,10 @@ pub mod pallet { StorageExhausted, /// A contract with the same AccountId already exists. DuplicateContract, + /// A contract self destructed in its constructor. + /// + /// This can be triggered by a call to `seal_terminate` or `seal_restore_to`. + TerminatedInConstructor, } /// Current cost schedule for contracts. @@ -680,8 +688,9 @@ where ) -> ContractExecResult { let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::get(); - let mut ctx = ExecutionContext::>::top_level(origin, &schedule); - let result = ctx.call(dest, value, &mut gas_meter, input_data); + let result = ExecStack::>::run_call( + origin, dest, &mut gas_meter, &schedule, value, input_data, + ); let gas_consumed = gas_meter.gas_spent(); ContractExecResult { result: result.map(|r| r.0).map_err(|r| r.0.error), @@ -711,7 +720,6 @@ where ) -> ContractInstantiateResult { let mut gas_meter = GasMeter::new(gas_limit); let schedule = >::get(); - let mut ctx = ExecutionContext::>::top_level(origin, &schedule); let executable = match code { Code::Upload(Bytes(binary)) => PrefabWasmModule::from_code(binary, &schedule), Code::Existing(hash) => PrefabWasmModule::from_storage(hash, &schedule, &mut gas_meter), @@ -724,20 +732,21 @@ where debug_message: Bytes(Vec::new()), } }; - let result = ctx.instantiate(endowment, &mut gas_meter, executable, data, &salt) - .and_then(|(account_id, result)| { - let rent_projection = if compute_projection { - Some(Rent::>::compute_projection(&account_id) - .map_err(|_| >::NewContractNotFunded)?) - } else { - None - }; - - Ok(InstantiateReturnValue { - result, - account_id, - rent_projection, - }) + let result = ExecStack::>::run_instantiate( + origin, executable, &mut gas_meter, &schedule, endowment, data, &salt, + ).and_then(|(account_id, result)| { + let rent_projection = if compute_projection { + Some(Rent::>::compute_projection(&account_id) + .map_err(|_| >::NewContractNotFunded)?) + } else { + None + }; + + Ok(InstantiateReturnValue { + result, + account_id, + rent_projection, + }) }); ContractInstantiateResult { result: result.map_err(|e| e.error), diff --git a/frame/contracts/src/rent.rs b/frame/contracts/src/rent.rs index 6e268c48bc824..d57a3004aa0c9 100644 --- a/frame/contracts/src/rent.rs +++ b/frame/contracts/src/rent.rs @@ -460,16 +460,13 @@ where /// /// Result<(CallerCodeSize, DestCodeSize), (DispatchError, CallerCodeSize, DestCodesize)> pub fn restore_to( - origin: T::AccountId, + origin: &T::AccountId, + mut origin_contract: AliveContractInfo, dest: T::AccountId, code_hash: CodeHash, rent_allowance: BalanceOf, delta: Vec, ) -> Result<(u32, u32), (DispatchError, u32, u32)> { - let mut origin_contract = >::get(&origin) - .and_then(|c| c.get_alive()) - .ok_or((Error::::InvalidSourceContract.into(), 0, 0))?; - let child_trie_info = origin_contract.child_trie_info(); let current_block = >::block_number(); diff --git a/frame/contracts/src/storage.rs b/frame/contracts/src/storage.rs index d78551f8f170e..bb3553529befe 100644 --- a/frame/contracts/src/storage.rs +++ b/frame/contracts/src/storage.rs @@ -19,8 +19,7 @@ use crate::{ exec::{AccountIdOf, StorageKey}, - BalanceOf, CodeHash, ContractInfoOf, Config, TrieId, - AccountCounter, DeletionQueue, Error, + BalanceOf, CodeHash, ContractInfoOf, Config, TrieId, DeletionQueue, Error, weights::WeightInfo, }; use codec::{Codec, Encode, Decode}; @@ -61,7 +60,9 @@ impl ContractInfo { None } } + /// If contract is alive then return some reference to alive info + #[cfg(test)] pub fn as_alive(&self) -> Option<&AliveContractInfo> { if let ContractInfo::Alive(ref alive) = self { Some(alive) @@ -144,11 +145,6 @@ impl From> for ContractInfo { } } -/// An error that means that the account requested either doesn't exist or represents a tombstone -/// account. -#[cfg_attr(test, derive(PartialEq, Eq, Debug))] -pub struct ContractAbsentError; - #[derive(Encode, Decode)] pub struct DeletedContract { pair_count: u32, @@ -177,25 +173,14 @@ where /// This function also updates the bookkeeping info such as: number of total non-empty pairs a /// contract owns, the last block the storage was written to, etc. That's why, in contrast to /// `read`, this function also requires the `account` ID. - /// - /// If the contract specified by the id `account` doesn't exist `Err` is returned.` - /// - /// # Panics - /// - /// Panics iff the `account` specified is not alive and in storage. pub fn write( - account: &AccountIdOf, - trie_id: &TrieId, + block_number: T::BlockNumber, + new_info: &mut AliveContractInfo, key: &StorageKey, opt_new_value: Option>, ) -> DispatchResult { - let mut new_info = match >::get(account) { - Some(ContractInfo::Alive(alive)) => alive, - None | Some(ContractInfo::Tombstone(_)) => panic!("Contract not found"), - }; - let hashed_key = blake2_256(key); - let child_trie_info = &child_trie_info(&trie_id); + let child_trie_info = &child_trie_info(&new_info.trie_id); let opt_prev_len = child::len(&child_trie_info, &hashed_key); @@ -225,8 +210,7 @@ where .and_then(|val| val.checked_add(new_value_len)) .ok_or_else(|| Error::::StorageExhausted)?; - new_info.last_write = Some(>::block_number()); - >::insert(&account, ContractInfo::Alive(new_info)); + new_info.last_write = Some(block_number); // Finally, perform the change on the storage. match opt_new_value { @@ -237,65 +221,35 @@ where Ok(()) } - /// Returns the rent allowance set for the contract give by the account id. - pub fn rent_allowance( - account: &AccountIdOf, - ) -> Result, ContractAbsentError> - { - >::get(account) - .and_then(|i| i.as_alive().map(|i| i.rent_allowance)) - .ok_or(ContractAbsentError) - } - - /// Set the rent allowance for the contract given by the account id. - /// - /// Returns `Err` if the contract doesn't exist or is a tombstone. - pub fn set_rent_allowance( - account: &AccountIdOf, - rent_allowance: BalanceOf, - ) -> Result<(), ContractAbsentError> { - >::mutate(account, |maybe_contract_info| match maybe_contract_info { - Some(ContractInfo::Alive(ref mut alive_info)) => { - alive_info.rent_allowance = rent_allowance; - Ok(()) - } - _ => Err(ContractAbsentError), - }) - } - /// Creates a new contract descriptor in the storage with the given code hash at the given address. /// /// Returns `Err` if there is already a contract (or a tombstone) exists at the given address. - pub fn place_contract( + pub fn new_contract( account: &AccountIdOf, trie_id: TrieId, ch: CodeHash, ) -> Result, DispatchError> { - >::try_mutate(account, |existing| { - if existing.is_some() { - return Err(Error::::DuplicateContract.into()); - } + if >::contains_key(account) { + return Err(Error::::DuplicateContract.into()); + } - let contract = AliveContractInfo:: { - code_hash: ch, - storage_size: 0, - trie_id, - deduct_block: - // We want to charge rent for the first block in advance. Therefore we - // treat the contract as if it was created in the last block and then - // charge rent for it during instantiation. - >::block_number().saturating_sub(1u32.into()), - rent_allowance: >::max_value(), - rent_payed: >::zero(), - pair_count: 0, - last_write: None, - _reserved: None, - }; - - *existing = Some(contract.clone().into()); - - Ok(contract) - }) + let contract = AliveContractInfo:: { + code_hash: ch, + storage_size: 0, + trie_id, + deduct_block: + // We want to charge rent for the first block in advance. Therefore we + // treat the contract as if it was created in the last block and then + // charge rent for it during instantiation. + >::block_number().saturating_sub(1u32.into()), + rent_allowance: >::max_value(), + rent_payed: >::zero(), + pair_count: 0, + last_write: None, + _reserved: None, + }; + + Ok(contract) } /// Push a contract's trie to the deletion queue for lazy removal. @@ -397,16 +351,9 @@ where /// This generator uses inner counter for account id and applies the hash over `AccountId + /// accountid_counter`. - pub fn generate_trie_id(account_id: &AccountIdOf) -> TrieId { - // Note that skipping a value due to error is not an issue here. - // We only need uniqueness, not sequence. - let new_seed = >::mutate(|v| { - *v = v.wrapping_add(1); - *v - }); - + pub fn generate_trie_id(account_id: &AccountIdOf, seed: u64) -> TrieId { let buf: Vec<_> = account_id.as_ref().iter() - .chain(&new_seed.to_le_bytes()) + .chain(&seed.to_le_bytes()) .cloned() .collect(); T::Hashing::hash(&buf).as_ref().into() @@ -414,11 +361,10 @@ where /// Returns the code hash of the contract specified by `account` ID. #[cfg(test)] - pub fn code_hash(account: &AccountIdOf) -> Result, ContractAbsentError> + pub fn code_hash(account: &AccountIdOf) -> Option> { >::get(account) .and_then(|i| i.as_alive().map(|i| i.code_hash)) - .ok_or(ContractAbsentError) } /// Fill up the queue in order to exercise the limits during testing. diff --git a/frame/contracts/src/tests.rs b/frame/contracts/src/tests.rs index a36e96dfe12b9..ef3d65f506c5b 100644 --- a/frame/contracts/src/tests.rs +++ b/frame/contracts/src/tests.rs @@ -23,7 +23,7 @@ use crate::{ Result as ExtensionResult, Environment, ChainExtension, Ext, SysConfig, RetVal, UncheckedFrom, InitState, ReturnFlags, }, - exec::{AccountIdOf, Executable}, wasm::PrefabWasmModule, + exec::{AccountIdOf, Executable, Frame}, wasm::PrefabWasmModule, weights::WeightInfo, wasm::ReturnCode as RuntimeReturnCode, storage::RawAliveContractInfo, @@ -69,27 +69,37 @@ frame_support::construct_runtime!( #[macro_use] pub mod test_utils { - use super::{Test, Balances}; + use super::{Test, Balances, System}; use crate::{ ContractInfoOf, CodeHash, - storage::Storage, + storage::{Storage, ContractInfo}, exec::{StorageKey, AccountIdOf}, Pallet as Contracts, + TrieId, AccountCounter, }; use frame_support::traits::Currency; pub fn set_storage(addr: &AccountIdOf, key: &StorageKey, value: Option>) { - let contract_info = >::get(&addr).unwrap().get_alive().unwrap(); - Storage::::write(addr, &contract_info.trie_id, key, value).unwrap(); + let mut contract_info = >::get(&addr).unwrap().get_alive().unwrap(); + let block_number = System::block_number(); + Storage::::write(block_number, &mut contract_info, key, value).unwrap(); } pub fn get_storage(addr: &AccountIdOf, key: &StorageKey) -> Option> { let contract_info = >::get(&addr).unwrap().get_alive().unwrap(); Storage::::read(&contract_info.trie_id, key) } + pub fn generate_trie_id(address: &AccountIdOf) -> TrieId { + let seed = >::mutate(|counter| { + *counter += 1; + *counter + }); + Storage::::generate_trie_id(address, seed) + } pub fn place_contract(address: &AccountIdOf, code_hash: CodeHash) { - let trie_id = Storage::::generate_trie_id(address); + let trie_id = generate_trie_id(address); set_balance(address, Contracts::::subsistence_threshold() * 10); - Storage::::place_contract(&address, trie_id, code_hash).unwrap(); + let contract = Storage::::new_contract(&address, trie_id, code_hash).unwrap(); + >::insert(address, ContractInfo::Alive(contract)); } pub fn set_balance(who: &AccountIdOf, amount: u64) { let imbalance = Balances::deposit_creating(who, amount); @@ -251,7 +261,6 @@ parameter_types! { pub const DepositPerStorageItem: u64 = 10_000; pub RentFraction: Perbill = Perbill::from_rational(4u32, 10_000u32); pub const SurchargeReward: u64 = 500_000; - pub const MaxDepth: u32 = 100; pub const MaxValueSize: u32 = 16_384; pub const DeletionQueueDepth: u32 = 1024; pub const DeletionWeightLimit: Weight = 500_000_000_000; @@ -281,7 +290,7 @@ impl Config for Test { type DepositPerStorageItem = DepositPerStorageItem; type RentFraction = RentFraction; type SurchargeReward = SurchargeReward; - type MaxDepth = MaxDepth; + type CallStack = [Frame; 31]; type MaxValueSize = MaxValueSize; type WeightPrice = Self; type WeightInfo = (); @@ -379,8 +388,8 @@ fn account_removal_does_not_remove_storage() { use self::test_utils::{set_storage, get_storage}; ExtBuilder::default().existential_deposit(100).build().execute_with(|| { - let trie_id1 = Storage::::generate_trie_id(&ALICE); - let trie_id2 = Storage::::generate_trie_id(&BOB); + let trie_id1 = test_utils::generate_trie_id(&ALICE); + let trie_id2 = test_utils::generate_trie_id(&BOB); let key1 = &[1; 32]; let key2 = &[2; 32]; @@ -1835,7 +1844,7 @@ fn cannot_self_destruct_in_constructor() { vec![], vec![], ), - Error::::NotCallable, + Error::::TerminatedInConstructor, ); }); } @@ -2326,18 +2335,18 @@ fn lazy_removal_partial_remove_works() { ); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap().get_alive().unwrap(); - let trie = &info.child_trie_info(); + let mut info = >::get(&addr).unwrap().get_alive().unwrap(); // Put value into the contracts child trie for val in &vals { Storage::::write( - &addr, - &info.trie_id, + System::block_number(), + &mut info, &val.0, Some(val.2.clone()), ).unwrap(); } + >::insert(&addr, ContractInfo::Alive(info.clone())); // Terminate the contract assert_ok!(Contracts::call( @@ -2351,9 +2360,11 @@ fn lazy_removal_partial_remove_works() { // Contract info should be gone assert!(!>::contains_key(&addr)); + let trie = info.child_trie_info(); + // But value should be still there as the lazy removal did not run, yet. for val in &vals { - assert_eq!(child::get::(trie, &blake2_256(&val.0)), Some(val.1)); + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); } trie.clone() @@ -2407,8 +2418,7 @@ fn lazy_removal_does_no_run_on_full_block() { ); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap().get_alive().unwrap(); - let trie = &info.child_trie_info(); + let mut info = >::get(&addr).unwrap().get_alive().unwrap(); let max_keys = 30; // Create some storage items for the contract. @@ -2420,12 +2430,13 @@ fn lazy_removal_does_no_run_on_full_block() { // Put value into the contracts child trie for val in &vals { Storage::::write( - &addr, - &info.trie_id, + System::block_number(), + &mut info, &val.0, Some(val.2.clone()), ).unwrap(); } + >::insert(&addr, ContractInfo::Alive(info.clone())); // Terminate the contract assert_ok!(Contracts::call( @@ -2439,9 +2450,11 @@ fn lazy_removal_does_no_run_on_full_block() { // Contract info should be gone assert!(!>::contains_key(&addr)); + let trie = info.child_trie_info(); + // But value should be still there as the lazy removal did not run, yet. for val in &vals { - assert_eq!(child::get::(trie, &blake2_256(&val.0)), Some(val.1)); + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); } // Fill up the block which should prevent the lazy storage removal from running. @@ -2458,7 +2471,7 @@ fn lazy_removal_does_no_run_on_full_block() { // All the keys are still in place for val in &vals { - assert_eq!(child::get::(trie, &blake2_256(&val.0)), Some(val.1)); + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); } // Run the lazy removal directly which disregards the block limits @@ -2466,7 +2479,7 @@ fn lazy_removal_does_no_run_on_full_block() { // Now the keys should be gone for val in &vals { - assert_eq!(child::get::(trie, &blake2_256(&val.0)), None); + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); } }); } @@ -2491,8 +2504,7 @@ fn lazy_removal_does_not_use_all_weight() { ); let addr = Contracts::contract_address(&ALICE, &hash, &[]); - let info = >::get(&addr).unwrap().get_alive().unwrap(); - let trie = &info.child_trie_info(); + let mut info = >::get(&addr).unwrap().get_alive().unwrap(); let weight_limit = 5_000_000_000; let (weight_per_key, max_keys) = Storage::::deletion_budget(1, weight_limit); @@ -2505,12 +2517,13 @@ fn lazy_removal_does_not_use_all_weight() { // Put value into the contracts child trie for val in &vals { Storage::::write( - &addr, - &info.trie_id, + System::block_number(), + &mut info, &val.0, Some(val.2.clone()), ).unwrap(); } + >::insert(&addr, ContractInfo::Alive(info.clone())); // Terminate the contract assert_ok!(Contracts::call( @@ -2524,9 +2537,11 @@ fn lazy_removal_does_not_use_all_weight() { // Contract info should be gone assert!(!>::contains_key(&addr)); + let trie = info.child_trie_info(); + // But value should be still there as the lazy removal did not run, yet. for val in &vals { - assert_eq!(child::get::(trie, &blake2_256(&val.0)), Some(val.1)); + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), Some(val.1)); } // Run the lazy removal @@ -2537,7 +2552,7 @@ fn lazy_removal_does_not_use_all_weight() { // All the keys are removed for val in vals { - assert_eq!(child::get::(trie, &blake2_256(&val.0)), None); + assert_eq!(child::get::(&trie, &blake2_256(&val.0)), None); } }); } diff --git a/frame/contracts/src/wasm/code_cache.rs b/frame/contracts/src/wasm/code_cache.rs index f9513afe51f4f..e81e595697aa9 100644 --- a/frame/contracts/src/wasm/code_cache.rs +++ b/frame/contracts/src/wasm/code_cache.rs @@ -137,7 +137,7 @@ where // in the storage. // // We need to re-instrument the code with the latest schedule here. - gas_meter.charge(&(), InstrumentToken(prefab_module.original_code_len))?; + gas_meter.charge(InstrumentToken(prefab_module.original_code_len))?; private::reinstrument(&mut prefab_module, schedule)?; } } @@ -194,9 +194,7 @@ fn increment_64(refcount: &mut u64) { struct InstrumentToken(u32); impl Token for InstrumentToken { - type Metadata = (); - - fn calculate_amount(&self, _metadata: &Self::Metadata) -> Weight { + fn weight(&self) -> Weight { T::WeightInfo::instrument(self.0 / 1024) } } diff --git a/frame/contracts/src/wasm/mod.rs b/frame/contracts/src/wasm/mod.rs index 969336b59fa39..f30a30ae87250 100644 --- a/frame/contracts/src/wasm/mod.rs +++ b/frame/contracts/src/wasm/mod.rs @@ -34,7 +34,7 @@ use sp_std::prelude::*; use sp_core::crypto::UncheckedFrom; use codec::{Encode, Decode}; use frame_support::dispatch::DispatchError; -pub use self::runtime::{ReturnCode, Runtime, RuntimeToken}; +pub use self::runtime::{ReturnCode, Runtime, RuntimeCosts}; #[cfg(feature = "runtime-benchmarks")] pub use self::code_cache::reinstrument; #[cfg(test)] @@ -172,10 +172,9 @@ where fn execute>( self, - mut ext: E, + ext: &mut E, function: &ExportedFunction, input_data: Vec, - gas_meter: &mut GasMeter, ) -> ExecResult { let memory = sp_sandbox::Memory::new(self.initial, Some(self.maximum)) @@ -196,10 +195,9 @@ where }); let mut runtime = Runtime::new( - &mut ext, + ext, input_data, memory, - gas_meter, ); // We store before executing so that the code hash is available in the constructor. @@ -220,13 +218,6 @@ where &self.code_hash } - fn occupied_storage(&self) -> u32 { - // We disregard the size of the struct itself as the size is completely - // dominated by the code size. - let len = self.aggregate_code_len(); - len.checked_div(self.refcount as u32).unwrap_or(len) - } - fn code_len(&self) -> u32 { self.code.len() as u32 } @@ -260,8 +251,7 @@ mod tests { use assert_matches::assert_matches; use pallet_contracts_primitives::{ExecReturnValue, ReturnFlags}; use pretty_assertions::assert_eq; - - const GAS_LIMIT: Weight = 10_000_000_000; + use sp_std::borrow::BorrowMut; #[derive(Debug, PartialEq, Eq)] struct DispatchEntry(Call); @@ -295,7 +285,6 @@ mod tests { data: Vec, } - #[derive(Default)] pub struct MockExt { storage: HashMap>, rent_allowance: u64, @@ -307,23 +296,48 @@ mod tests { events: Vec<(Vec, Vec)>, schedule: Schedule, rent_params: RentParams, + gas_meter: GasMeter, + } + + impl Default for MockExt { + fn default() -> Self { + Self { + storage: Default::default(), + rent_allowance: Default::default(), + instantiates: Default::default(), + terminations: Default::default(), + transfers: Default::default(), + restores: Default::default(), + events: Default::default(), + schedule: Default::default(), + rent_params: Default::default(), + gas_meter: GasMeter::new(10_000_000_000), + } + } } impl Ext for MockExt { type T = Test; - fn get_storage(&self, key: &StorageKey) -> Option> { - self.storage.get(key).cloned() - } - fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { - *self.storage.entry(key).or_insert(Vec::new()) = value.unwrap_or(Vec::new()); - Ok(()) + fn call( + &mut self, + _gas_limit: Weight, + to: AccountIdOf, + value: u64, + data: Vec, + ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { + self.transfers.push(TransferEntry { + to, + value, + data: data, + }); + Ok((ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }, 0)) } fn instantiate( &mut self, + gas_limit: Weight, code_hash: CodeHash, endowment: u64, - gas_meter: &mut GasMeter, data: Vec, salt: &[u8], ) -> Result<(AccountIdOf, ExecReturnValue, u32), (ExecError, u32)> { @@ -331,7 +345,7 @@ mod tests { code_hash: code_hash.clone(), endowment, data: data.to_vec(), - gas_left: gas_meter.gas_left(), + gas_left: gas_limit, salt: salt.to_vec(), }); Ok(( @@ -355,22 +369,6 @@ mod tests { }); Ok(()) } - fn call( - &mut self, - to: &AccountIdOf, - value: u64, - _gas_meter: &mut GasMeter, - data: Vec, - ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { - self.transfers.push(TransferEntry { - to: to.clone(), - value, - data: data, - }); - // Assume for now that it was just a plain transfer. - // TODO: Add tests for different call outcomes. - Ok((ExecReturnValue { flags: ReturnFlags::empty(), data: Bytes(Vec::new()) }, 0)) - } fn terminate( &mut self, beneficiary: &AccountIdOf, @@ -395,6 +393,13 @@ mod tests { }); Ok((0, 0)) } + fn get_storage(&mut self, key: &StorageKey) -> Option> { + self.storage.get(key).cloned() + } + fn set_storage(&mut self, key: StorageKey, value: Option>) -> DispatchResult { + *self.storage.entry(key).or_insert(Vec::new()) = value.unwrap_or(Vec::new()); + Ok(()) + } fn caller(&self) -> &AccountIdOf { &ALICE } @@ -425,7 +430,7 @@ mod tests { fn set_rent_allowance(&mut self, rent_allowance: u64) { self.rent_allowance = rent_allowance; } - fn rent_allowance(&self) -> u64 { + fn rent_allowance(&mut self) -> u64 { self.rent_allowance } fn block_number(&self) -> u64 { 121 } @@ -439,127 +444,22 @@ mod tests { fn rent_params(&self) -> &RentParams { &self.rent_params } - } - - impl Ext for &mut MockExt { - type T = ::T; - - fn get_storage(&self, key: &[u8; 32]) -> Option> { - (**self).get_storage(key) - } - fn set_storage(&mut self, key: [u8; 32], value: Option>) -> DispatchResult { - (**self).set_storage(key, value) - } - fn instantiate( - &mut self, - code: CodeHash, - value: u64, - gas_meter: &mut GasMeter, - input_data: Vec, - salt: &[u8], - ) -> Result<(AccountIdOf, ExecReturnValue, u32), (ExecError, u32)> { - (**self).instantiate(code, value, gas_meter, input_data, salt) - } - fn transfer( - &mut self, - to: &AccountIdOf, - value: u64, - ) -> Result<(), DispatchError> { - (**self).transfer(to, value) - } - fn terminate( - &mut self, - beneficiary: &AccountIdOf, - ) -> Result { - (**self).terminate(beneficiary) - } - fn call( - &mut self, - to: &AccountIdOf, - value: u64, - gas_meter: &mut GasMeter, - input_data: Vec, - ) -> Result<(ExecReturnValue, u32), (ExecError, u32)> { - (**self).call(to, value, gas_meter, input_data) - } - fn restore_to( - &mut self, - dest: AccountIdOf, - code_hash: H256, - rent_allowance: u64, - delta: Vec, - ) -> Result<(u32, u32), (DispatchError, u32, u32)> { - (**self).restore_to( - dest, - code_hash, - rent_allowance, - delta, - ) - } - fn caller(&self) -> &AccountIdOf { - (**self).caller() - } - fn address(&self) -> &AccountIdOf { - (**self).address() - } - fn balance(&self) -> u64 { - (**self).balance() - } - fn value_transferred(&self) -> u64 { - (**self).value_transferred() - } - fn now(&self) -> &u64 { - (**self).now() - } - fn minimum_balance(&self) -> u64 { - (**self).minimum_balance() - } - fn tombstone_deposit(&self) -> u64 { - (**self).tombstone_deposit() - } - fn random(&self, subject: &[u8]) -> (SeedOf, BlockNumberOf) { - (**self).random(subject) - } - fn deposit_event(&mut self, topics: Vec, data: Vec) { - (**self).deposit_event(topics, data) - } - fn set_rent_allowance(&mut self, rent_allowance: u64) { - (**self).set_rent_allowance(rent_allowance) - } - fn rent_allowance(&self) -> u64 { - (**self).rent_allowance() - } - fn block_number(&self) -> u64 { - (**self).block_number() - } - fn max_value_size(&self) -> u32 { - (**self).max_value_size() - } - fn get_weight_price(&self, weight: Weight) -> BalanceOf { - (**self).get_weight_price(weight) - } - fn schedule(&self) -> &Schedule { - (**self).schedule() - } - fn rent_params(&self) -> &RentParams { - (**self).rent_params() + fn gas_meter(&mut self) -> &mut GasMeter { + &mut self.gas_meter } } - fn execute( + fn execute>( wat: &str, input_data: Vec, - ext: E, - gas_meter: &mut GasMeter, + mut ext: E, ) -> ExecResult - where - ::AccountId: - UncheckedFrom<::Hash> + AsRef<[u8]> { let wasm = wat::parse_str(wat).unwrap(); let schedule = crate::Schedule::default(); - let executable = PrefabWasmModule::::from_code(wasm, &schedule).unwrap(); - executable.execute(ext, &ExportedFunction::Call, input_data, gas_meter) + let executable = PrefabWasmModule::<::T>::from_code(wasm, &schedule) + .unwrap(); + executable.execute(ext.borrow_mut(), &ExportedFunction::Call, input_data) } const CODE_TRANSFER: &str = r#" @@ -603,7 +503,6 @@ mod tests { CODE_TRANSFER, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), )); assert_eq!( @@ -669,7 +568,6 @@ mod tests { CODE_CALL, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), )); assert_eq!( @@ -745,7 +643,6 @@ mod tests { CODE_INSTANTIATE, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), )); assert_matches!( @@ -794,7 +691,6 @@ mod tests { CODE_TERMINATE, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); assert_eq!( @@ -857,7 +753,6 @@ mod tests { &CODE_TRANSFER_LIMITED_GAS, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), )); assert_eq!( @@ -945,7 +840,6 @@ mod tests { CODE_GET_STORAGE, vec![], mock_ext, - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); assert_eq!(output, ExecReturnValue { @@ -1003,7 +897,6 @@ mod tests { CODE_CALLER, vec![], MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), )); } @@ -1056,7 +949,6 @@ mod tests { CODE_ADDRESS, vec![], MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), )); } @@ -1103,12 +995,10 @@ mod tests { #[test] fn balance() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_BALANCE, vec![], MockExt::default(), - &mut gas_meter, )); } @@ -1155,12 +1045,10 @@ mod tests { #[test] fn gas_price() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_GAS_PRICE, vec![], MockExt::default(), - &mut gas_meter, )); } @@ -1205,18 +1093,19 @@ mod tests { #[test] fn gas_left() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); + let mut ext = MockExt::default(); + let gas_limit = ext.gas_meter.gas_left(); let output = execute( CODE_GAS_LEFT, vec![], - MockExt::default(), - &mut gas_meter, + &mut ext, ).unwrap(); let gas_left = Weight::decode(&mut &*output.data).unwrap(); - assert!(gas_left < GAS_LIMIT, "gas_left must be less than initial"); - assert!(gas_left > gas_meter.gas_left(), "gas_left must be greater than final"); + let actual_left = ext.gas_meter.gas_left(); + assert!(gas_left < gas_limit, "gas_left must be less than initial"); + assert!(gas_left > actual_left, "gas_left must be greater than final"); } const CODE_VALUE_TRANSFERRED: &str = r#" @@ -1262,12 +1151,10 @@ mod tests { #[test] fn value_transferred() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_VALUE_TRANSFERRED, vec![], MockExt::default(), - &mut gas_meter, )); } @@ -1301,7 +1188,6 @@ mod tests { CODE_RETURN_FROM_START_FN, vec![], MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); assert_eq!( @@ -1356,12 +1242,10 @@ mod tests { #[test] fn now() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_TIMESTAMP_NOW, vec![], MockExt::default(), - &mut gas_meter, )); } @@ -1407,12 +1291,10 @@ mod tests { #[test] fn minimum_balance() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_MINIMUM_BALANCE, vec![], MockExt::default(), - &mut gas_meter, )); } @@ -1458,12 +1340,10 @@ mod tests { #[test] fn tombstone_deposit() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_TOMBSTONE_DEPOSIT, vec![], MockExt::default(), - &mut gas_meter, )); } @@ -1523,13 +1403,10 @@ mod tests { #[test] fn random() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); - let output = execute( CODE_RANDOM, vec![], MockExt::default(), - &mut gas_meter, ).unwrap(); // The mock ext just returns the same data that was passed as the subject. @@ -1601,13 +1478,10 @@ mod tests { #[test] fn random_v1() { - let mut gas_meter = GasMeter::new(GAS_LIMIT); - let output = execute( CODE_RANDOM_V1, vec![], MockExt::default(), - &mut gas_meter, ).unwrap(); // The mock ext just returns the same data that was passed as the subject. @@ -1650,12 +1524,10 @@ mod tests { #[test] fn deposit_event() { let mut mock_ext = MockExt::default(); - let mut gas_meter = GasMeter::new(GAS_LIMIT); assert_ok!(execute( CODE_DEPOSIT_EVENT, vec![], &mut mock_ext, - &mut gas_meter )); assert_eq!(mock_ext.events, vec![ @@ -1663,7 +1535,7 @@ mod tests { vec![0x00, 0x01, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe5, 0x14, 0x00]) ]); - assert!(gas_meter.gas_left() > 0); + assert!(mock_ext.gas_meter.gas_left() > 0); } const CODE_DEPOSIT_EVENT_MAX_TOPICS: &str = r#" @@ -1693,17 +1565,14 @@ mod tests { ) "#; + /// Checks that the runtime traps if there are more than `max_topic_events` topics. #[test] fn deposit_event_max_topics() { - // Checks that the runtime traps if there are more than `max_topic_events` topics. - let mut gas_meter = GasMeter::new(GAS_LIMIT); - assert_eq!( execute( CODE_DEPOSIT_EVENT_MAX_TOPICS, vec![], MockExt::default(), - &mut gas_meter ), Err(ExecError { error: Error::::TooManyTopics.into(), @@ -1738,17 +1607,14 @@ mod tests { ) "#; + /// Checks that the runtime traps if there are duplicates. #[test] fn deposit_event_duplicates() { - // Checks that the runtime traps if there are duplicates. - let mut gas_meter = GasMeter::new(GAS_LIMIT); - assert_eq!( execute( CODE_DEPOSIT_EVENT_DUPLICATES, vec![], MockExt::default(), - &mut gas_meter ), Err(ExecError { error: Error::::DuplicateTopics.into(), @@ -1806,7 +1672,6 @@ mod tests { CODE_BLOCK_NUMBER, vec![], MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); } @@ -1848,7 +1713,6 @@ mod tests { CODE_RETURN_WITH_DATA, hex!("00000000445566778899").to_vec(), MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); assert_eq!(output, ExecReturnValue { @@ -1864,7 +1728,6 @@ mod tests { CODE_RETURN_WITH_DATA, hex!("010000005566778899").to_vec(), MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); assert_eq!(output, ExecReturnValue { @@ -1897,7 +1760,6 @@ mod tests { CODE_OUT_OF_BOUNDS_ACCESS, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), ); assert_eq!( @@ -1932,7 +1794,6 @@ mod tests { CODE_DECODE_FAILURE, vec![], &mut mock_ext, - &mut GasMeter::new(GAS_LIMIT), ); assert_eq!( @@ -1980,7 +1841,6 @@ mod tests { CODE_RENT_PARAMS, vec![], MockExt::default(), - &mut GasMeter::new(GAS_LIMIT), ).unwrap(); let rent_params = Bytes(>::default().encode()); assert_eq!(output, ExecReturnValue { flags: ReturnFlags::empty(), data: rent_params }); diff --git a/frame/contracts/src/wasm/runtime.rs b/frame/contracts/src/wasm/runtime.rs index bed56f409d579..da8784b23cdcb 100644 --- a/frame/contracts/src/wasm/runtime.rs +++ b/frame/contracts/src/wasm/runtime.rs @@ -20,7 +20,7 @@ use crate::{ Config, CodeHash, BalanceOf, Error, exec::{Ext, StorageKey, TopicOf, ExecResult, ExecError}, - gas::{GasMeter, Token, ChargedAmount}, + gas::{Token, ChargedAmount}, wasm::env_def::ConvertibleToWasm, schedule::HostFnWeights, }; @@ -28,7 +28,6 @@ use parity_wasm::elements::ValueType; use frame_support::{dispatch::DispatchError, ensure, traits::Get, weights::Weight}; use sp_std::prelude::*; use codec::{Decode, DecodeAll, Encode}; -use sp_runtime::traits::SaturatedConversion; use sp_core::{Bytes, crypto::UncheckedFrom}; use sp_io::hashing::{ keccak_256, @@ -132,7 +131,7 @@ impl> From for TrapReason { #[cfg_attr(test, derive(Debug, PartialEq, Eq))] #[derive(Copy, Clone)] -pub enum RuntimeToken { +pub enum RuntimeCosts { /// Charge the gas meter with the cost of a metering block. The charged costs are /// the supplied cost of the block plus the overhead of the metering itself. MeteringBlock(u32), @@ -220,15 +219,14 @@ pub enum RuntimeToken { RentParams, } -impl Token for RuntimeToken -where - T::AccountId: UncheckedFrom, T::AccountId: AsRef<[u8]> -{ - type Metadata = HostFnWeights; - - fn calculate_amount(&self, s: &Self::Metadata) -> Weight { - use self::RuntimeToken::*; - match *self { +impl RuntimeCosts { + fn token(&self, s: &HostFnWeights) -> RuntimeToken + where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]> + { + use self::RuntimeCosts::*; + let weight = match *self { MeteringBlock(amount) => s.gas.saturating_add(amount.into()), Caller => s.caller, Address => s.address, @@ -287,14 +285,37 @@ where ChainExtension(amount) => amount, CopyIn(len) => s.return_per_byte.saturating_mul(len.into()), RentParams => s.rent_params, + }; + RuntimeToken { + #[cfg(test)] + _created_from: *self, + weight, } } } +#[cfg_attr(test, derive(Debug, PartialEq, Eq))] +#[derive(Copy, Clone)] +struct RuntimeToken { + #[cfg(test)] + _created_from: RuntimeCosts, + weight: Weight, +} + +impl Token for RuntimeToken +where + T: Config, + T::AccountId: UncheckedFrom + AsRef<[u8]> +{ + fn weight(&self) -> Weight { + self.weight + } +} + /// This is only appropriate when writing out data of constant size that does not depend on user /// input. In this case the costs for this copy was already charged as part of the token at /// the beginning of the API entry point. -fn already_charged(_: u32) -> Option { +fn already_charged(_: u32) -> Option { None } @@ -303,7 +324,6 @@ pub struct Runtime<'a, E: Ext + 'a> { ext: &'a mut E, input_data: Option>, memory: sp_sandbox::Memory, - gas_meter: &'a mut GasMeter, trap_reason: Option, } @@ -317,13 +337,11 @@ where ext: &'a mut E, input_data: Vec, memory: sp_sandbox::Memory, - gas_meter: &'a mut GasMeter, ) -> Self { Runtime { ext, input_data: Some(input_data), memory, - gas_meter, trap_reason: None, } } @@ -406,21 +424,16 @@ where /// Charge the gas meter with the specified token. /// /// Returns `Err(HostError)` if there is not enough gas. - pub fn charge_gas(&mut self, token: Tok) -> Result - where - Tok: Token>, - { - self.gas_meter.charge(&self.ext.schedule().host_fn_weights, token) + pub fn charge_gas(&mut self, costs: RuntimeCosts) -> Result { + let token = costs.token(&self.ext.schedule().host_fn_weights); + self.ext.gas_meter().charge(token) } /// Correct previously charged gas amount. - pub fn adjust_gas(&mut self, charged_amount: ChargedAmount, adjusted_amount: Tok) - where - Tok: Token>, - { - self.gas_meter.adjust_gas( + pub fn adjust_gas(&mut self, charged_amount: ChargedAmount, adjusted_amount: RuntimeCosts) { + let adjusted_amount = adjusted_amount.token(&self.ext.schedule().host_fn_weights); + self.ext.gas_meter().adjust_gas( charged_amount, - &self.ext.schedule().host_fn_weights, adjusted_amount, ); } @@ -474,11 +487,11 @@ where pub fn read_sandbox_memory_as(&mut self, ptr: u32, len: u32) -> Result { - let amount = self.charge_gas(RuntimeToken::CopyIn(len))?; + let amount = self.charge_gas(RuntimeCosts::CopyIn(len))?; let buf = self.read_sandbox_memory(ptr, len)?; let decoded = D::decode_all(&mut &buf[..]) .map_err(|_| DispatchError::from(Error::::DecodingFailed))?; - self.gas_meter.refund(amount); + self.ext.gas_meter().refund(amount); Ok(decoded) } @@ -507,7 +520,7 @@ where out_len_ptr: u32, buf: &[u8], allow_skip: bool, - create_token: impl FnOnce(u32) -> Option, + create_token: impl FnOnce(u32) -> Option, ) -> Result<(), DispatchError> { if allow_skip && out_ptr == u32::max_value() { @@ -521,8 +534,8 @@ where Err(Error::::OutputBufferTooSmall)? } - if let Some(token) = create_token(buf_len) { - self.charge_gas(token)?; + if let Some(costs) = create_token(buf_len) { + self.charge_gas(costs)?; } self.memory.set(out_ptr, buf).and_then(|_| { @@ -631,7 +644,7 @@ define_env!(Env, , // // - amount: How much gas is used. [seal0] gas(ctx, amount: u32) => { - ctx.charge_gas(RuntimeToken::MeteringBlock(amount))?; + ctx.charge_gas(RuntimeCosts::MeteringBlock(amount))?; Ok(()) }, @@ -651,7 +664,7 @@ define_env!(Env, , // - If value length exceeds the configured maximum value length of a storage entry. // - Upon trying to set an empty storage entry (value length is 0). [seal0] seal_set_storage(ctx, key_ptr: u32, value_ptr: u32, value_len: u32) => { - ctx.charge_gas(RuntimeToken::SetStorage(value_len))?; + ctx.charge_gas(RuntimeCosts::SetStorage(value_len))?; if value_len > ctx.ext.max_value_size() { Err(Error::::ValueTooLarge)?; } @@ -667,7 +680,7 @@ define_env!(Env, , // // - `key_ptr`: pointer into the linear memory where the location to clear the value is placed. [seal0] seal_clear_storage(ctx, key_ptr: u32) => { - ctx.charge_gas(RuntimeToken::ClearStorage)?; + ctx.charge_gas(RuntimeCosts::ClearStorage)?; let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; ctx.ext.set_storage(key, None).map_err(Into::into) @@ -686,12 +699,12 @@ define_env!(Env, , // // `ReturnCode::KeyNotFound` [seal0] seal_get_storage(ctx, key_ptr: u32, out_ptr: u32, out_len_ptr: u32) -> ReturnCode => { - ctx.charge_gas(RuntimeToken::GetStorageBase)?; + ctx.charge_gas(RuntimeCosts::GetStorageBase)?; let mut key: StorageKey = [0; 32]; ctx.read_sandbox_memory_into_buf(key_ptr, &mut key)?; if let Some(value) = ctx.ext.get_storage(&key) { ctx.write_sandbox_output(out_ptr, out_len_ptr, &value, false, |len| { - Some(RuntimeToken::GetStorageCopyOut(len)) + Some(RuntimeCosts::GetStorageCopyOut(len)) })?; Ok(ReturnCode::Success) } else { @@ -721,7 +734,7 @@ define_env!(Env, , value_ptr: u32, value_len: u32 ) -> ReturnCode => { - ctx.charge_gas(RuntimeToken::Transfer)?; + ctx.charge_gas(RuntimeCosts::Transfer)?; let callee: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(account_ptr, account_len)?; let value: BalanceOf<::T> = @@ -780,45 +793,27 @@ define_env!(Env, , output_ptr: u32, output_len_ptr: u32 ) -> ReturnCode => { - ctx.charge_gas(RuntimeToken::CallBase(input_data_len))?; + ctx.charge_gas(RuntimeCosts::CallBase(input_data_len))?; let callee: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(callee_ptr, callee_len)?; let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(value_ptr, value_len)?; let input_data = ctx.read_sandbox_memory(input_data_ptr, input_data_len)?; if value > 0u32.into() { - ctx.charge_gas(RuntimeToken::CallSurchargeTransfer)?; + ctx.charge_gas(RuntimeCosts::CallSurchargeTransfer)?; } let charged = ctx.charge_gas( - RuntimeToken::CallSurchargeCodeSize(::MaxCodeSize::get()) + RuntimeCosts::CallSurchargeCodeSize(::MaxCodeSize::get()) )?; - let nested_gas_limit = if gas == 0 { - ctx.gas_meter.gas_left() - } else { - gas.saturated_into() - }; let ext = &mut ctx.ext; - let call_outcome = ctx.gas_meter.with_nested(nested_gas_limit, |nested_meter| { - match nested_meter { - Some(nested_meter) => { - ext.call( - &callee, - value, - nested_meter, - input_data, - ) - } - // there is not enough gas to allocate for the nested call. - None => Err((Error::<::T>::OutOfGas.into(), 0)), - } - }); + let call_outcome = ext.call(gas, callee, value, input_data); let code_len = match &call_outcome { Ok((_, len)) => len, Err((_, len)) => len, }; - ctx.adjust_gas(charged, RuntimeToken::CallSurchargeCodeSize(*code_len)); + ctx.adjust_gas(charged, RuntimeCosts::CallSurchargeCodeSize(*code_len)); if let Ok((output, _)) = &call_outcome { ctx.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| { - Some(RuntimeToken::CallCopyOut(len)) + Some(RuntimeCosts::CallCopyOut(len)) })?; } Ok(Runtime::::exec_into_return_code(call_outcome.map(|r| r.0).map_err(|r| r.0))?) @@ -885,41 +880,22 @@ define_env!(Env, , salt_ptr: u32, salt_len: u32 ) -> ReturnCode => { - ctx.charge_gas(RuntimeToken::InstantiateBase {input_data_len, salt_len})?; + ctx.charge_gas(RuntimeCosts::InstantiateBase {input_data_len, salt_len})?; let code_hash: CodeHash<::T> = ctx.read_sandbox_memory_as(code_hash_ptr, code_hash_len)?; let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(value_ptr, value_len)?; let input_data = ctx.read_sandbox_memory(input_data_ptr, input_data_len)?; let salt = ctx.read_sandbox_memory(salt_ptr, salt_len)?; let charged = ctx.charge_gas( - RuntimeToken::InstantiateSurchargeCodeSize(::MaxCodeSize::get()) + RuntimeCosts::InstantiateSurchargeCodeSize(::MaxCodeSize::get()) )?; - let nested_gas_limit = if gas == 0 { - ctx.gas_meter.gas_left() - } else { - gas.saturated_into() - }; let ext = &mut ctx.ext; - let instantiate_outcome = ctx.gas_meter.with_nested(nested_gas_limit, |nested_meter| { - match nested_meter { - Some(nested_meter) => { - ext.instantiate( - code_hash, - value, - nested_meter, - input_data, - &salt, - ) - } - // there is not enough gas to allocate for the nested call. - None => Err((Error::<::T>::OutOfGas.into(), 0)), - } - }); + let instantiate_outcome = ext.instantiate(gas, code_hash, value, input_data, &salt); let code_len = match &instantiate_outcome { Ok((_, _, code_len)) => code_len, Err((_, code_len)) => code_len, }; - ctx.adjust_gas(charged, RuntimeToken::InstantiateSurchargeCodeSize(*code_len)); + ctx.adjust_gas(charged, RuntimeCosts::InstantiateSurchargeCodeSize(*code_len)); if let Ok((address, output, _)) = &instantiate_outcome { if !output.flags.contains(ReturnFlags::REVERT) { ctx.write_sandbox_output( @@ -927,7 +903,7 @@ define_env!(Env, , )?; } ctx.write_sandbox_output(output_ptr, output_len_ptr, &output.data, true, |len| { - Some(RuntimeToken::InstantiateCopyOut(len)) + Some(RuntimeCosts::InstantiateCopyOut(len)) })?; } Ok(Runtime::::exec_into_return_code( @@ -956,18 +932,18 @@ define_env!(Env, , beneficiary_ptr: u32, beneficiary_len: u32 ) => { - ctx.charge_gas(RuntimeToken::Terminate)?; + ctx.charge_gas(RuntimeCosts::Terminate)?; let beneficiary: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(beneficiary_ptr, beneficiary_len)?; let charged = ctx.charge_gas( - RuntimeToken::TerminateSurchargeCodeSize(::MaxCodeSize::get()) + RuntimeCosts::TerminateSurchargeCodeSize(::MaxCodeSize::get()) )?; let (result, code_len) = match ctx.ext.terminate(&beneficiary) { Ok(len) => (Ok(()), len), Err((err, len)) => (Err(err), len), }; - ctx.adjust_gas(charged, RuntimeToken::TerminateSurchargeCodeSize(code_len)); + ctx.adjust_gas(charged, RuntimeCosts::TerminateSurchargeCodeSize(code_len)); result?; Err(TrapReason::Termination) }, @@ -983,10 +959,10 @@ define_env!(Env, , // // This function can only be called once. Calling it multiple times will trigger a trap. [seal0] seal_input(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::InputBase)?; + ctx.charge_gas(RuntimeCosts::InputBase)?; if let Some(input) = ctx.input_data.take() { ctx.write_sandbox_output(out_ptr, out_len_ptr, &input, false, |len| { - Some(RuntimeToken::InputCopyOut(len)) + Some(RuntimeCosts::InputCopyOut(len)) })?; Ok(()) } else { @@ -1012,7 +988,7 @@ define_env!(Env, , // // Using a reserved bit triggers a trap. [seal0] seal_return(ctx, flags: u32, data_ptr: u32, data_len: u32) => { - ctx.charge_gas(RuntimeToken::Return(data_len))?; + ctx.charge_gas(RuntimeCosts::Return(data_len))?; Err(TrapReason::Return(ReturnData { flags, data: ctx.read_sandbox_memory(data_ptr, data_len)?, @@ -1030,7 +1006,7 @@ define_env!(Env, , // extrinsic will be returned. Otherwise, if this call is initiated by another contract then the // address of the contract will be returned. The value is encoded as T::AccountId. [seal0] seal_caller(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::Caller)?; + ctx.charge_gas(RuntimeCosts::Caller)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.caller().encode(), false, already_charged )?) @@ -1043,7 +1019,7 @@ define_env!(Env, , // `out_ptr`. This call overwrites it with the size of the value. If the available // space at `out_ptr` is less than the size of the value a trap is triggered. [seal0] seal_address(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::Address)?; + ctx.charge_gas(RuntimeCosts::Address)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.address().encode(), false, already_charged )?) @@ -1063,7 +1039,7 @@ define_env!(Env, , // It is recommended to avoid specifying very small values for `gas` as the prices for a single // gas can be smaller than one. [seal0] seal_weight_to_fee(ctx, gas: u64, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::WeightToFee)?; + ctx.charge_gas(RuntimeCosts::WeightToFee)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.get_weight_price(gas).encode(), false, already_charged )?) @@ -1078,9 +1054,10 @@ define_env!(Env, , // // The data is encoded as Gas. [seal0] seal_gas_left(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::GasLeft)?; + ctx.charge_gas(RuntimeCosts::GasLeft)?; + let gas_left = &ctx.ext.gas_meter().gas_left().encode(); Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.gas_meter.gas_left().encode(), false, already_charged + out_ptr, out_len_ptr, &gas_left, false, already_charged, )?) }, @@ -1093,7 +1070,7 @@ define_env!(Env, , // // The data is encoded as T::Balance. [seal0] seal_balance(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::Balance)?; + ctx.charge_gas(RuntimeCosts::Balance)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.balance().encode(), false, already_charged )?) @@ -1108,7 +1085,7 @@ define_env!(Env, , // // The data is encoded as T::Balance. [seal0] seal_value_transferred(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::ValueTransferred)?; + ctx.charge_gas(RuntimeCosts::ValueTransferred)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.value_transferred().encode(), false, already_charged )?) @@ -1127,7 +1104,7 @@ define_env!(Env, , // // This function is deprecated. Users should migrate to the version in the "seal1" module. [seal0] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::Random)?; + ctx.charge_gas(RuntimeCosts::Random)?; if subject_len > ctx.ext.schedule().limits.subject_len { Err(Error::::RandomSubjectTooLong)?; } @@ -1159,7 +1136,7 @@ define_env!(Env, , // call this on later blocks until the block number returned is later than the latest // commitment. [seal1] seal_random(ctx, subject_ptr: u32, subject_len: u32, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::Random)?; + ctx.charge_gas(RuntimeCosts::Random)?; if subject_len > ctx.ext.schedule().limits.subject_len { Err(Error::::RandomSubjectTooLong)?; } @@ -1176,7 +1153,7 @@ define_env!(Env, , // `out_ptr`. This call overwrites it with the size of the value. If the available // space at `out_ptr` is less than the size of the value a trap is triggered. [seal0] seal_now(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::Now)?; + ctx.charge_gas(RuntimeCosts::Now)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.now().encode(), false, already_charged )?) @@ -1186,7 +1163,7 @@ define_env!(Env, , // // The data is encoded as T::Balance. [seal0] seal_minimum_balance(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::MinimumBalance)?; + ctx.charge_gas(RuntimeCosts::MinimumBalance)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.minimum_balance().encode(), false, already_charged )?) @@ -1208,7 +1185,7 @@ define_env!(Env, , // below the sum of existential deposit and the tombstone deposit. The sum // is commonly referred as subsistence threshold in code. [seal0] seal_tombstone_deposit(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::TombstoneDeposit)?; + ctx.charge_gas(RuntimeCosts::TombstoneDeposit)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.tombstone_deposit().encode(), false, already_charged )?) @@ -1256,7 +1233,7 @@ define_env!(Env, , delta_ptr: u32, delta_count: u32 ) => { - ctx.charge_gas(RuntimeToken::RestoreTo(delta_count))?; + ctx.charge_gas(RuntimeCosts::RestoreTo(delta_count))?; let dest: <::T as frame_system::Config>::AccountId = ctx.read_sandbox_memory_as(dest_ptr, dest_len)?; let code_hash: CodeHash<::T> = @@ -1290,7 +1267,7 @@ define_env!(Env, , }; let max_len = ::MaxCodeSize::get(); - let charged = ctx.charge_gas(RuntimeToken::RestoreToSurchargeCodeSize { + let charged = ctx.charge_gas(RuntimeCosts::RestoreToSurchargeCodeSize { caller_code: max_len, tombstone_code: max_len, })?; @@ -1300,7 +1277,7 @@ define_env!(Env, , Ok((code, tomb)) => (Ok(()), code, tomb), Err((err, code, tomb)) => (Err(err), code, tomb), }; - ctx.adjust_gas(charged, RuntimeToken::RestoreToSurchargeCodeSize { + ctx.adjust_gas(charged, RuntimeCosts::RestoreToSurchargeCodeSize { caller_code, tombstone_code, }); @@ -1341,7 +1318,7 @@ define_env!(Env, , let num_topic = topics_len .checked_div(sp_std::mem::size_of::>() as u32) .ok_or_else(|| "Zero sized topics are not allowed")?; - ctx.charge_gas(RuntimeToken::DepositEvent { + ctx.charge_gas(RuntimeCosts::DepositEvent { num_topic, len: data_len, })?; @@ -1379,7 +1356,7 @@ define_env!(Env, , // Should be decodable as a `T::Balance`. Traps otherwise. // - value_len: length of the value buffer. [seal0] seal_set_rent_allowance(ctx, value_ptr: u32, value_len: u32) => { - ctx.charge_gas(RuntimeToken::SetRentAllowance)?; + ctx.charge_gas(RuntimeCosts::SetRentAllowance)?; let value: BalanceOf<::T> = ctx.read_sandbox_memory_as(value_ptr, value_len)?; ctx.ext.set_rent_allowance(value); @@ -1396,9 +1373,10 @@ define_env!(Env, , // // The data is encoded as T::Balance. [seal0] seal_rent_allowance(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::RentAllowance)?; + ctx.charge_gas(RuntimeCosts::RentAllowance)?; + let rent_allowance = ctx.ext.rent_allowance().encode(); Ok(ctx.write_sandbox_output( - out_ptr, out_len_ptr, &ctx.ext.rent_allowance().encode(), false, already_charged + out_ptr, out_len_ptr, &rent_allowance, false, already_charged )?) }, @@ -1420,7 +1398,7 @@ define_env!(Env, , // `out_ptr`. This call overwrites it with the size of the value. If the available // space at `out_ptr` is less than the size of the value a trap is triggered. [seal0] seal_block_number(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::BlockNumber)?; + ctx.charge_gas(RuntimeCosts::BlockNumber)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.block_number().encode(), false, already_charged )?) @@ -1447,7 +1425,7 @@ define_env!(Env, , // data is placed. The function will write the result // directly into this buffer. [seal0] seal_hash_sha2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { - ctx.charge_gas(RuntimeToken::HashSha256(input_len))?; + ctx.charge_gas(RuntimeCosts::HashSha256(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(sha2_256, input_ptr, input_len, output_ptr)?) }, @@ -1472,7 +1450,7 @@ define_env!(Env, , // data is placed. The function will write the result // directly into this buffer. [seal0] seal_hash_keccak_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { - ctx.charge_gas(RuntimeToken::HashKeccak256(input_len))?; + ctx.charge_gas(RuntimeCosts::HashKeccak256(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(keccak_256, input_ptr, input_len, output_ptr)?) }, @@ -1497,7 +1475,7 @@ define_env!(Env, , // data is placed. The function will write the result // directly into this buffer. [seal0] seal_hash_blake2_256(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { - ctx.charge_gas(RuntimeToken::HashBlake256(input_len))?; + ctx.charge_gas(RuntimeCosts::HashBlake256(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(blake2_256, input_ptr, input_len, output_ptr)?) }, @@ -1522,7 +1500,7 @@ define_env!(Env, , // data is placed. The function will write the result // directly into this buffer. [seal0] seal_hash_blake2_128(ctx, input_ptr: u32, input_len: u32, output_ptr: u32) => { - ctx.charge_gas(RuntimeToken::HashBlake128(input_len))?; + ctx.charge_gas(RuntimeCosts::HashBlake128(input_len))?; Ok(ctx.compute_hash_on_intermediate_buffer(blake2_128, input_ptr, input_len, output_ptr)?) }, @@ -1574,7 +1552,7 @@ define_env!(Env, , // started execution. Any change to those values that happens due to actions of the // current call or contracts that are called by this contract are not considered. [seal0] seal_rent_params(ctx, out_ptr: u32, out_len_ptr: u32) => { - ctx.charge_gas(RuntimeToken::RentParams)?; + ctx.charge_gas(RuntimeCosts::RentParams)?; Ok(ctx.write_sandbox_output( out_ptr, out_len_ptr, &ctx.ext.rent_params().encode(), false, already_charged )?) diff --git a/frame/contracts/src/weights.rs b/frame/contracts/src/weights.rs index dd9f082a18dcf..a4cf9b41553b6 100644 --- a/frame/contracts/src/weights.rs +++ b/frame/contracts/src/weights.rs @@ -18,7 +18,7 @@ //! Autogenerated weights for pallet_contracts //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 3.0.0 -//! DATE: 2021-02-18, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: [], HIGH RANGE: [] +//! DATE: 2021-04-23, STEPS: `[50, ]`, REPEAT: 20, LOW RANGE: `[]`, HIGH RANGE: `[]` //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 128 // Executed Command: @@ -153,1251 +153,1321 @@ pub trait WeightInfo { pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { fn on_initialize() -> Weight { - (3_850_000 as Weight) + (3_610_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) } fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (52_925_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_297_000 as Weight).saturating_mul(k as Weight)) + (0 as Weight) + // Standard Error: 2_000 + .saturating_add((2_307_000 as Weight).saturating_mul(k as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (434_698_000 as Weight) - // Standard Error: 210_000 - .saturating_add((166_559_000 as Weight).saturating_mul(q as Weight)) + (18_635_000 as Weight) + // Standard Error: 8_000 + .saturating_add((33_246_000 as Weight).saturating_mul(q as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instrument(c: u32, ) -> Weight { - (29_918_000 as Weight) - // Standard Error: 185_000 - .saturating_add((123_774_000 as Weight).saturating_mul(c as Weight)) + (36_950_000 as Weight) + // Standard Error: 198_000 + .saturating_add((116_526_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn update_schedule() -> Weight { - (29_795_000 as Weight) + (28_095_000 as Weight) .saturating_add(T::DbWeight::get().reads(1 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (225_834_000 as Weight) - // Standard Error: 144_000 - .saturating_add((165_632_000 as Weight).saturating_mul(c as Weight)) + (230_039_000 as Weight) + // Standard Error: 143_000 + .saturating_add((157_483_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 9_000 - .saturating_add((2_563_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_992_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn instantiate(c: u32, s: u32, ) -> Weight { - (190_482_000 as Weight) - // Standard Error: 12_000 - .saturating_add((8_724_000 as Weight).saturating_mul(c as Weight)) + (203_983_000 as Weight) + // Standard Error: 11_000 + .saturating_add((8_639_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 1_000 - .saturating_add((2_512_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_918_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) - .saturating_add(T::DbWeight::get().writes(4 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) } fn call(c: u32, ) -> Weight { - (195_414_000 as Weight) - // Standard Error: 2_000 - .saturating_add((3_920_000 as Weight).saturating_mul(c as Weight)) + (198_905_000 as Weight) + // Standard Error: 1_000 + .saturating_add((3_913_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn claim_surcharge(c: u32, ) -> Weight { - (336_867_000 as Weight) - // Standard Error: 10_000 - .saturating_add((5_262_000 as Weight).saturating_mul(c as Weight)) + (132_586_000 as Weight) + // Standard Error: 1_000 + .saturating_add((4_732_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(4 as Weight)) } fn seal_caller(r: u32, ) -> Weight { - (143_935_000 as Weight) - // Standard Error: 128_000 - .saturating_add((266_876_000 as Weight).saturating_mul(r as Weight)) + (179_629_000 as Weight) + // Standard Error: 318_000 + .saturating_add((250_628_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_address(r: u32, ) -> Weight { - (150_342_000 as Weight) - // Standard Error: 127_000 - .saturating_add((266_051_000 as Weight).saturating_mul(r as Weight)) + (144_806_000 as Weight) + // Standard Error: 71_000 + .saturating_add((251_588_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_gas_left(r: u32, ) -> Weight { - (144_833_000 as Weight) - // Standard Error: 124_000 - .saturating_add((259_279_000 as Weight).saturating_mul(r as Weight)) + (151_919_000 as Weight) + // Standard Error: 90_000 + .saturating_add((243_733_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_balance(r: u32, ) -> Weight { - (152_032_000 as Weight) - // Standard Error: 218_000 - .saturating_add((573_038_000 as Weight).saturating_mul(r as Weight)) + (157_448_000 as Weight) + // Standard Error: 211_000 + .saturating_add((559_875_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_value_transferred(r: u32, ) -> Weight { - (148_831_000 as Weight) - // Standard Error: 147_000 - .saturating_add((260_718_000 as Weight).saturating_mul(r as Weight)) + (145_161_000 as Weight) + // Standard Error: 71_000 + .saturating_add((246_729_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_minimum_balance(r: u32, ) -> Weight { - (142_925_000 as Weight) - // Standard Error: 130_000 - .saturating_add((260_426_000 as Weight).saturating_mul(r as Weight)) + (147_920_000 as Weight) + // Standard Error: 60_000 + .saturating_add((245_135_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_tombstone_deposit(r: u32, ) -> Weight { - (143_151_000 as Weight) - // Standard Error: 119_000 - .saturating_add((260_964_000 as Weight).saturating_mul(r as Weight)) + (141_105_000 as Weight) + // Standard Error: 138_000 + .saturating_add((247_840_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_rent_allowance(r: u32, ) -> Weight { - (155_126_000 as Weight) - // Standard Error: 225_000 - .saturating_add((599_056_000 as Weight).saturating_mul(r as Weight)) + (147_393_000 as Weight) + // Standard Error: 77_000 + .saturating_add((247_593_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_block_number(r: u32, ) -> Weight { - (144_566_000 as Weight) - // Standard Error: 110_000 - .saturating_add((257_620_000 as Weight).saturating_mul(r as Weight)) + (151_560_000 as Weight) + // Standard Error: 92_000 + .saturating_add((242_469_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_now(r: u32, ) -> Weight { - (147_274_000 as Weight) - // Standard Error: 115_000 - .saturating_add((258_627_000 as Weight).saturating_mul(r as Weight)) + (145_917_000 as Weight) + // Standard Error: 80_000 + .saturating_add((244_335_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_rent_params(r: u32, ) -> Weight { - (168_575_000 as Weight) - // Standard Error: 394_000 - .saturating_add((397_754_000 as Weight).saturating_mul(r as Weight)) + (150_399_000 as Weight) + // Standard Error: 90_000 + .saturating_add((381_505_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_weight_to_fee(r: u32, ) -> Weight { - (148_102_000 as Weight) - // Standard Error: 201_000 - .saturating_add((537_088_000 as Weight).saturating_mul(r as Weight)) + (152_906_000 as Weight) + // Standard Error: 418_000 + .saturating_add((486_338_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_gas(r: u32, ) -> Weight { - (125_122_000 as Weight) - // Standard Error: 89_000 - .saturating_add((122_350_000 as Weight).saturating_mul(r as Weight)) + (130_020_000 as Weight) + // Standard Error: 48_000 + .saturating_add((120_792_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_input(r: u32, ) -> Weight { - (137_334_000 as Weight) - // Standard Error: 99_000 - .saturating_add((7_359_000 as Weight).saturating_mul(r as Weight)) + (142_031_000 as Weight) + // Standard Error: 83_000 + .saturating_add((7_205_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_input_per_kb(n: u32, ) -> Weight { - (145_094_000 as Weight) + (151_770_000 as Weight) // Standard Error: 0 - .saturating_add((283_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((247_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_return(r: u32, ) -> Weight { - (127_544_000 as Weight) - // Standard Error: 138_000 - .saturating_add((4_640_000 as Weight).saturating_mul(r as Weight)) + (131_023_000 as Weight) + // Standard Error: 69_000 + .saturating_add((4_823_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_return_per_kb(n: u32, ) -> Weight { - (137_517_000 as Weight) - // Standard Error: 0 - .saturating_add((783_000 as Weight).saturating_mul(n as Weight)) + (142_885_000 as Weight) + // Standard Error: 1_000 + .saturating_add((751_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_terminate(r: u32, ) -> Weight { - (138_292_000 as Weight) - // Standard Error: 689_000 - .saturating_add((111_698_000 as Weight).saturating_mul(r as Weight)) + (142_165_000 as Weight) + // Standard Error: 100_000 + .saturating_add((99_133_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((2 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((4 as Weight).saturating_mul(r as Weight))) } fn seal_terminate_per_code_kb(c: u32, ) -> Weight { - (263_507_000 as Weight) - // Standard Error: 12_000 - .saturating_add((8_409_000 as Weight).saturating_mul(c as Weight)) + (243_348_000 as Weight) + // Standard Error: 6_000 + .saturating_add((8_560_000 as Weight).saturating_mul(c as Weight)) .saturating_add(T::DbWeight::get().reads(7 as Weight)) .saturating_add(T::DbWeight::get().writes(5 as Weight)) } fn seal_restore_to(r: u32, ) -> Weight { - (232_291_000 as Weight) - // Standard Error: 301_000 - .saturating_add((136_379_000 as Weight).saturating_mul(r as Weight)) + (171_766_000 as Weight) + // Standard Error: 372_000 + .saturating_add((100_243_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes((6 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } fn seal_restore_to_per_code_kb_delta(c: u32, t: u32, d: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 162_000 - .saturating_add((8_619_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 162_000 - .saturating_add((4_877_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 1_433_000 - .saturating_add((3_762_810_000 as Weight).saturating_mul(d as Weight)) + (112_646_000 as Weight) + // Standard Error: 142_000 + .saturating_add((7_922_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 142_000 + .saturating_add((3_590_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 1_255_000 + .saturating_add((3_716_501_000 as Weight).saturating_mul(d as Weight)) .saturating_add(T::DbWeight::get().reads(8 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(d as Weight))) .saturating_add(T::DbWeight::get().writes(7 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(d as Weight))) } fn seal_random(r: u32, ) -> Weight { - (153_634_000 as Weight) - // Standard Error: 267_000 - .saturating_add((650_160_000 as Weight).saturating_mul(r as Weight)) + (152_470_000 as Weight) + // Standard Error: 146_000 + .saturating_add((619_676_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_deposit_event(r: u32, ) -> Weight { - (137_080_000 as Weight) - // Standard Error: 1_009_000 - .saturating_add((949_228_000 as Weight).saturating_mul(r as Weight)) + (151_008_000 as Weight) + // Standard Error: 167_000 + .saturating_add((899_677_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_259_129_000 as Weight) - // Standard Error: 2_542_000 - .saturating_add((609_859_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 501_000 - .saturating_add((249_496_000 as Weight).saturating_mul(n as Weight)) + (1_227_526_000 as Weight) + // Standard Error: 2_767_000 + .saturating_add((586_284_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 545_000 + .saturating_add((247_578_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) } fn seal_set_rent_allowance(r: u32, ) -> Weight { - (170_417_000 as Weight) - // Standard Error: 434_000 - .saturating_add((721_511_000 as Weight).saturating_mul(r as Weight)) + (142_734_000 as Weight) + // Standard Error: 53_000 + .saturating_add((167_026_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_set_storage(r: u32, ) -> Weight { - (1_870_542_000 as Weight) - // Standard Error: 26_871_000 - .saturating_add((18_312_239_000 as Weight).saturating_mul(r as Weight)) + (21_198_000 as Weight) + // Standard Error: 2_062_000 + .saturating_add((3_836_800_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (1_763_732_000 as Weight) - // Standard Error: 258_000 - .saturating_add((74_848_000 as Weight).saturating_mul(n as Weight)) + (589_829_000 as Weight) + // Standard Error: 223_000 + .saturating_add((71_242_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().writes(2 as Weight)) } fn seal_clear_storage(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_745_000 - .saturating_add((2_316_433_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_950_000 + .saturating_add((1_267_479_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(T::DbWeight::get().writes(1 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_get_storage(r: u32, ) -> Weight { - (87_218_000 as Weight) - // Standard Error: 745_000 - .saturating_add((948_121_000 as Weight).saturating_mul(r as Weight)) + (3_466_000 as Weight) + // Standard Error: 1_248_000 + .saturating_add((920_416_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (719_050_000 as Weight) - // Standard Error: 266_000 - .saturating_add((154_812_000 as Weight).saturating_mul(n as Weight)) + (618_423_000 as Weight) + // Standard Error: 231_000 + .saturating_add((153_218_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_transfer(r: u32, ) -> Weight { - (19_439_000 as Weight) - // Standard Error: 2_468_000 - .saturating_add((5_674_822_000 as Weight).saturating_mul(r as Weight)) + (76_247_000 as Weight) + // Standard Error: 2_153_000 + .saturating_add((5_509_779_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) .saturating_add(T::DbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes(2 as Weight)) .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_465_000 - .saturating_add((11_066_530_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 8_294_000 + .saturating_add((11_951_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((200 as Weight).saturating_mul(r as Weight))) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) + .saturating_add(T::DbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_call_per_code_transfer_input_output_kb(c: u32, t: u32, i: u32, o: u32, ) -> Weight { - (9_916_288_000 as Weight) - // Standard Error: 552_000 - .saturating_add((397_842_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 229_902_000 - .saturating_add((5_243_673_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 72_000 - .saturating_add((59_737_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 77_000 - .saturating_add((82_259_000 as Weight).saturating_mul(o as Weight)) + (10_875_657_000 as Weight) + // Standard Error: 253_000 + .saturating_add((392_140_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 105_395_000 + .saturating_add((3_581_966_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 33_000 + .saturating_add((59_352_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 35_000 + .saturating_add((79_149_000 as Weight).saturating_mul(o as Weight)) .saturating_add(T::DbWeight::get().reads(206 as Weight)) + .saturating_add(T::DbWeight::get().writes(101 as Weight)) .saturating_add(T::DbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) } fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_016_000 - .saturating_add((22_206_489_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 31_795_000 + .saturating_add((21_908_561_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(6 as Weight)) .saturating_add(T::DbWeight::get().reads((300 as Weight).saturating_mul(r as Weight))) - .saturating_add(T::DbWeight::get().writes(2 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) .saturating_add(T::DbWeight::get().writes((300 as Weight).saturating_mul(r as Weight))) } fn seal_instantiate_per_code_input_output_salt_kb(c: u32, i: u32, o: u32, s: u32, ) -> Weight { - (9_991_947_000 as Weight) - // Standard Error: 637_000 - .saturating_add((881_981_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 90_000 - .saturating_add((63_638_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 90_000 - .saturating_add((87_288_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 90_000 - .saturating_add((311_808_000 as Weight).saturating_mul(s as Weight)) + (10_580_308_000 as Weight) + // Standard Error: 611_000 + .saturating_add((875_153_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 86_000 + .saturating_add((62_540_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 86_000 + .saturating_add((83_080_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 86_000 + .saturating_add((350_970_000 as Weight).saturating_mul(s as Weight)) .saturating_add(T::DbWeight::get().reads(207 as Weight)) - .saturating_add(T::DbWeight::get().writes(203 as Weight)) + .saturating_add(T::DbWeight::get().writes(204 as Weight)) } fn seal_hash_sha2_256(r: u32, ) -> Weight { - (132_452_000 as Weight) - // Standard Error: 227_000 - .saturating_add((239_671_000 as Weight).saturating_mul(r as Weight)) + (143_987_000 as Weight) + // Standard Error: 90_000 + .saturating_add((232_215_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (756_802_000 as Weight) - // Standard Error: 48_000 - .saturating_add((429_454_000 as Weight).saturating_mul(n as Weight)) + (762_075_000 as Weight) + // Standard Error: 64_000 + .saturating_add((475_112_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_keccak_256(r: u32, ) -> Weight { - (139_440_000 as Weight) - // Standard Error: 128_000 - .saturating_add((249_514_000 as Weight).saturating_mul(r as Weight)) + (145_456_000 as Weight) + // Standard Error: 203_000 + .saturating_add((241_831_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (658_595_000 as Weight) - // Standard Error: 35_000 - .saturating_add((343_814_000 as Weight).saturating_mul(n as Weight)) + (660_371_000 as Weight) + // Standard Error: 30_000 + .saturating_add((342_147_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_256(r: u32, ) -> Weight { - (138_124_000 as Weight) - // Standard Error: 140_000 - .saturating_add((223_189_000 as Weight).saturating_mul(r as Weight)) + (149_472_000 as Weight) + // Standard Error: 101_000 + .saturating_add((212_899_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (689_667_000 as Weight) - // Standard Error: 41_000 - .saturating_add((160_006_000 as Weight).saturating_mul(n as Weight)) + (643_371_000 as Weight) + // Standard Error: 31_000 + .saturating_add((159_244_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_128(r: u32, ) -> Weight { - (140_225_000 as Weight) - // Standard Error: 156_000 - .saturating_add((223_696_000 as Weight).saturating_mul(r as Weight)) + (147_732_000 as Weight) + // Standard Error: 91_000 + .saturating_add((210_975_000 as Weight).saturating_mul(r as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (693_756_000 as Weight) - // Standard Error: 40_000 - .saturating_add((159_996_000 as Weight).saturating_mul(n as Weight)) + (684_085_000 as Weight) + // Standard Error: 38_000 + .saturating_add((159_213_000 as Weight).saturating_mul(n as Weight)) .saturating_add(T::DbWeight::get().reads(5 as Weight)) + .saturating_add(T::DbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (24_250_000 as Weight) - // Standard Error: 14_000 - .saturating_add((3_134_000 as Weight).saturating_mul(r as Weight)) + (25_332_000 as Weight) + // Standard Error: 12_000 + .saturating_add((3_087_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (26_509_000 as Weight) - // Standard Error: 27_000 - .saturating_add((161_556_000 as Weight).saturating_mul(r as Weight)) + (27_404_000 as Weight) + // Standard Error: 22_000 + .saturating_add((136_046_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (26_499_000 as Weight) - // Standard Error: 59_000 - .saturating_add((233_755_000 as Weight).saturating_mul(r as Weight)) + (27_422_000 as Weight) + // Standard Error: 24_000 + .saturating_add((204_925_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (24_175_000 as Weight) + (25_289_000 as Weight) // Standard Error: 16_000 - .saturating_add((12_450_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((12_375_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (24_219_000 as Weight) - // Standard Error: 26_000 - .saturating_add((12_058_000 as Weight).saturating_mul(r as Weight)) + (25_278_000 as Weight) + // Standard Error: 14_000 + .saturating_add((11_447_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (24_146_000 as Weight) - // Standard Error: 20_000 - .saturating_add((6_017_000 as Weight).saturating_mul(r as Weight)) + (25_283_000 as Weight) + // Standard Error: 15_000 + .saturating_add((5_615_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (24_229_000 as Weight) - // Standard Error: 24_000 - .saturating_add((13_726_000 as Weight).saturating_mul(r as Weight)) + (25_377_000 as Weight) + // Standard Error: 20_000 + .saturating_add((13_248_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (24_219_000 as Weight) - // Standard Error: 27_000 - .saturating_add((15_115_000 as Weight).saturating_mul(r as Weight)) + (25_318_000 as Weight) + // Standard Error: 14_000 + .saturating_add((14_962_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (34_981_000 as Weight) + (37_040_000 as Weight) // Standard Error: 1_000 - .saturating_add((156_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (24_599_000 as Weight) - // Standard Error: 102_000 - .saturating_add((95_771_000 as Weight).saturating_mul(r as Weight)) + (25_529_000 as Weight) + // Standard Error: 114_000 + .saturating_add((91_613_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (32_584_000 as Weight) - // Standard Error: 176_000 - .saturating_add((193_216_000 as Weight).saturating_mul(r as Weight)) + (33_242_000 as Weight) + // Standard Error: 188_000 + .saturating_add((191_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (240_739_000 as Weight) - // Standard Error: 6_000 - .saturating_add((3_407_000 as Weight).saturating_mul(p as Weight)) + (228_146_000 as Weight) + // Standard Error: 4_000 + .saturating_add((3_917_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (41_963_000 as Weight) - // Standard Error: 15_000 - .saturating_add((3_110_000 as Weight).saturating_mul(r as Weight)) + (44_304_000 as Weight) + // Standard Error: 22_000 + .saturating_add((3_146_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (41_956_000 as Weight) - // Standard Error: 9_000 - .saturating_add((3_460_000 as Weight).saturating_mul(r as Weight)) + (44_314_000 as Weight) + // Standard Error: 17_000 + .saturating_add((3_474_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (42_002_000 as Weight) - // Standard Error: 20_000 - .saturating_add((4_591_000 as Weight).saturating_mul(r as Weight)) + (44_234_000 as Weight) + // Standard Error: 14_000 + .saturating_add((4_725_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (27_646_000 as Weight) - // Standard Error: 23_000 - .saturating_add((7_821_000 as Weight).saturating_mul(r as Weight)) + (28_754_000 as Weight) + // Standard Error: 20_000 + .saturating_add((7_898_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (27_615_000 as Weight) - // Standard Error: 27_000 - .saturating_add((11_807_000 as Weight).saturating_mul(r as Weight)) + (28_737_000 as Weight) + // Standard Error: 26_000 + .saturating_add((8_531_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (27_106_000 as Weight) - // Standard Error: 78_000 - .saturating_add((2_952_000 as Weight).saturating_mul(r as Weight)) + (27_338_000 as Weight) + // Standard Error: 22_000 + .saturating_add((3_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (24_956_000 as Weight) - // Standard Error: 3_541_000 - .saturating_add((2_332_414_000 as Weight).saturating_mul(r as Weight)) + (25_943_000 as Weight) + // Standard Error: 299_000 + .saturating_add((2_094_164_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (24_183_000 as Weight) - // Standard Error: 18_000 - .saturating_add((5_166_000 as Weight).saturating_mul(r as Weight)) + (25_269_000 as Weight) + // Standard Error: 14_000 + .saturating_add((5_135_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (24_142_000 as Weight) - // Standard Error: 17_000 - .saturating_add((5_146_000 as Weight).saturating_mul(r as Weight)) + (25_281_000 as Weight) + // Standard Error: 16_000 + .saturating_add((5_069_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (24_161_000 as Weight) - // Standard Error: 23_000 - .saturating_add((5_807_000 as Weight).saturating_mul(r as Weight)) + (25_243_000 as Weight) + // Standard Error: 9_000 + .saturating_add((5_809_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (24_167_000 as Weight) - // Standard Error: 24_000 - .saturating_add((5_288_000 as Weight).saturating_mul(r as Weight)) + (25_259_000 as Weight) + // Standard Error: 13_000 + .saturating_add((5_120_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (24_252_000 as Weight) - // Standard Error: 9_000 - .saturating_add((5_091_000 as Weight).saturating_mul(r as Weight)) + (25_249_000 as Weight) + // Standard Error: 14_000 + .saturating_add((5_167_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (24_243_000 as Weight) - // Standard Error: 16_000 - .saturating_add((5_076_000 as Weight).saturating_mul(r as Weight)) + (25_247_000 as Weight) + // Standard Error: 10_000 + .saturating_add((5_118_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (24_227_000 as Weight) - // Standard Error: 15_000 - .saturating_add((5_135_000 as Weight).saturating_mul(r as Weight)) + (25_285_000 as Weight) + // Standard Error: 19_000 + .saturating_add((5_051_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (24_278_000 as Weight) - // Standard Error: 15_000 - .saturating_add((7_124_000 as Weight).saturating_mul(r as Weight)) + (25_312_000 as Weight) + // Standard Error: 19_000 + .saturating_add((7_207_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (24_254_000 as Weight) - // Standard Error: 19_000 - .saturating_add((7_067_000 as Weight).saturating_mul(r as Weight)) + (25_311_000 as Weight) + // Standard Error: 14_000 + .saturating_add((6_982_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (24_220_000 as Weight) - // Standard Error: 14_000 - .saturating_add((7_122_000 as Weight).saturating_mul(r as Weight)) + (25_327_000 as Weight) + // Standard Error: 19_000 + .saturating_add((7_009_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (24_221_000 as Weight) - // Standard Error: 19_000 - .saturating_add((7_221_000 as Weight).saturating_mul(r as Weight)) + (25_318_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_180_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (24_259_000 as Weight) + (25_330_000 as Weight) // Standard Error: 13_000 - .saturating_add((7_135_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((7_065_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (24_245_000 as Weight) - // Standard Error: 10_000 - .saturating_add((7_193_000 as Weight).saturating_mul(r as Weight)) + (25_284_000 as Weight) + // Standard Error: 16_000 + .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (24_289_000 as Weight) - // Standard Error: 22_000 - .saturating_add((7_023_000 as Weight).saturating_mul(r as Weight)) + (25_310_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_080_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (24_239_000 as Weight) - // Standard Error: 21_000 - .saturating_add((7_065_000 as Weight).saturating_mul(r as Weight)) + (25_262_000 as Weight) + // Standard Error: 11_000 + .saturating_add((7_079_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (24_256_000 as Weight) - // Standard Error: 13_000 - .saturating_add((7_119_000 as Weight).saturating_mul(r as Weight)) + (25_295_000 as Weight) + // Standard Error: 10_000 + .saturating_add((7_151_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (24_240_000 as Weight) + (25_326_000 as Weight) // Standard Error: 18_000 - .saturating_add((7_225_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((7_200_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (24_266_000 as Weight) - // Standard Error: 24_000 - .saturating_add((6_996_000 as Weight).saturating_mul(r as Weight)) + (25_320_000 as Weight) + // Standard Error: 23_000 + .saturating_add((7_020_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (24_265_000 as Weight) - // Standard Error: 17_000 - .saturating_add((6_974_000 as Weight).saturating_mul(r as Weight)) + (25_303_000 as Weight) + // Standard Error: 15_000 + .saturating_add((7_189_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (24_232_000 as Weight) - // Standard Error: 15_000 - .saturating_add((7_103_000 as Weight).saturating_mul(r as Weight)) + (25_311_000 as Weight) + // Standard Error: 16_000 + .saturating_add((7_054_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (24_245_000 as Weight) - // Standard Error: 20_000 - .saturating_add((12_915_000 as Weight).saturating_mul(r as Weight)) + (25_342_000 as Weight) + // Standard Error: 10_000 + .saturating_add((12_860_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (24_177_000 as Weight) - // Standard Error: 21_000 - .saturating_add((12_232_000 as Weight).saturating_mul(r as Weight)) + (25_307_000 as Weight) + // Standard Error: 17_000 + .saturating_add((12_162_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (24_171_000 as Weight) - // Standard Error: 15_000 - .saturating_add((12_939_000 as Weight).saturating_mul(r as Weight)) + (25_354_000 as Weight) + // Standard Error: 12_000 + .saturating_add((12_855_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (24_788_000 as Weight) - // Standard Error: 22_000 - .saturating_add((11_657_000 as Weight).saturating_mul(r as Weight)) + (25_319_000 as Weight) + // Standard Error: 16_000 + .saturating_add((11_982_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (24_252_000 as Weight) - // Standard Error: 19_000 - .saturating_add((7_003_000 as Weight).saturating_mul(r as Weight)) + (25_351_000 as Weight) + // Standard Error: 20_000 + .saturating_add((7_124_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (24_263_000 as Weight) - // Standard Error: 12_000 - .saturating_add((7_005_000 as Weight).saturating_mul(r as Weight)) + (25_333_000 as Weight) + // Standard Error: 20_000 + .saturating_add((7_060_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (24_239_000 as Weight) - // Standard Error: 17_000 - .saturating_add((7_020_000 as Weight).saturating_mul(r as Weight)) + (25_332_000 as Weight) + // Standard Error: 13_000 + .saturating_add((7_080_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (24_212_000 as Weight) - // Standard Error: 13_000 - .saturating_add((7_172_000 as Weight).saturating_mul(r as Weight)) + (25_279_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_193_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (24_220_000 as Weight) - // Standard Error: 27_000 - .saturating_add((7_246_000 as Weight).saturating_mul(r as Weight)) + (25_315_000 as Weight) + // Standard Error: 13_000 + .saturating_add((7_157_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (24_213_000 as Weight) + (25_354_000 as Weight) // Standard Error: 14_000 - .saturating_add((7_191_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((7_238_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (24_221_000 as Weight) - // Standard Error: 18_000 - .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight)) + (25_353_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_160_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (24_235_000 as Weight) - // Standard Error: 12_000 - .saturating_add((7_106_000 as Weight).saturating_mul(r as Weight)) + (25_363_000 as Weight) + // Standard Error: 16_000 + .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight)) } } // For backwards compatibility and tests impl WeightInfo for () { fn on_initialize() -> Weight { - (3_850_000 as Weight) + (3_610_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) } fn on_initialize_per_trie_key(k: u32, ) -> Weight { - (52_925_000 as Weight) - // Standard Error: 5_000 - .saturating_add((2_297_000 as Weight).saturating_mul(k as Weight)) + (0 as Weight) + // Standard Error: 2_000 + .saturating_add((2_307_000 as Weight).saturating_mul(k as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((1 as Weight).saturating_mul(k as Weight))) } fn on_initialize_per_queue_item(q: u32, ) -> Weight { - (434_698_000 as Weight) - // Standard Error: 210_000 - .saturating_add((166_559_000 as Weight).saturating_mul(q as Weight)) + (18_635_000 as Weight) + // Standard Error: 8_000 + .saturating_add((33_246_000 as Weight).saturating_mul(q as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instrument(c: u32, ) -> Weight { - (29_918_000 as Weight) - // Standard Error: 185_000 - .saturating_add((123_774_000 as Weight).saturating_mul(c as Weight)) + (36_950_000 as Weight) + // Standard Error: 198_000 + .saturating_add((116_526_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn update_schedule() -> Weight { - (29_795_000 as Weight) + (28_095_000 as Weight) .saturating_add(RocksDbWeight::get().reads(1 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instantiate_with_code(c: u32, s: u32, ) -> Weight { - (225_834_000 as Weight) - // Standard Error: 144_000 - .saturating_add((165_632_000 as Weight).saturating_mul(c as Weight)) + (230_039_000 as Weight) + // Standard Error: 143_000 + .saturating_add((157_483_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 9_000 - .saturating_add((2_563_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_992_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn instantiate(c: u32, s: u32, ) -> Weight { - (190_482_000 as Weight) - // Standard Error: 12_000 - .saturating_add((8_724_000 as Weight).saturating_mul(c as Weight)) + (203_983_000 as Weight) + // Standard Error: 11_000 + .saturating_add((8_639_000 as Weight).saturating_mul(c as Weight)) // Standard Error: 1_000 - .saturating_add((2_512_000 as Weight).saturating_mul(s as Weight)) + .saturating_add((2_918_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) - .saturating_add(RocksDbWeight::get().writes(4 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) } fn call(c: u32, ) -> Weight { - (195_414_000 as Weight) - // Standard Error: 2_000 - .saturating_add((3_920_000 as Weight).saturating_mul(c as Weight)) + (198_905_000 as Weight) + // Standard Error: 1_000 + .saturating_add((3_913_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn claim_surcharge(c: u32, ) -> Weight { - (336_867_000 as Weight) - // Standard Error: 10_000 - .saturating_add((5_262_000 as Weight).saturating_mul(c as Weight)) + (132_586_000 as Weight) + // Standard Error: 1_000 + .saturating_add((4_732_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(4 as Weight)) } fn seal_caller(r: u32, ) -> Weight { - (143_935_000 as Weight) - // Standard Error: 128_000 - .saturating_add((266_876_000 as Weight).saturating_mul(r as Weight)) + (179_629_000 as Weight) + // Standard Error: 318_000 + .saturating_add((250_628_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_address(r: u32, ) -> Weight { - (150_342_000 as Weight) - // Standard Error: 127_000 - .saturating_add((266_051_000 as Weight).saturating_mul(r as Weight)) + (144_806_000 as Weight) + // Standard Error: 71_000 + .saturating_add((251_588_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_gas_left(r: u32, ) -> Weight { - (144_833_000 as Weight) - // Standard Error: 124_000 - .saturating_add((259_279_000 as Weight).saturating_mul(r as Weight)) + (151_919_000 as Weight) + // Standard Error: 90_000 + .saturating_add((243_733_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_balance(r: u32, ) -> Weight { - (152_032_000 as Weight) - // Standard Error: 218_000 - .saturating_add((573_038_000 as Weight).saturating_mul(r as Weight)) + (157_448_000 as Weight) + // Standard Error: 211_000 + .saturating_add((559_875_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_value_transferred(r: u32, ) -> Weight { - (148_831_000 as Weight) - // Standard Error: 147_000 - .saturating_add((260_718_000 as Weight).saturating_mul(r as Weight)) + (145_161_000 as Weight) + // Standard Error: 71_000 + .saturating_add((246_729_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_minimum_balance(r: u32, ) -> Weight { - (142_925_000 as Weight) - // Standard Error: 130_000 - .saturating_add((260_426_000 as Weight).saturating_mul(r as Weight)) + (147_920_000 as Weight) + // Standard Error: 60_000 + .saturating_add((245_135_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_tombstone_deposit(r: u32, ) -> Weight { - (143_151_000 as Weight) - // Standard Error: 119_000 - .saturating_add((260_964_000 as Weight).saturating_mul(r as Weight)) + (141_105_000 as Weight) + // Standard Error: 138_000 + .saturating_add((247_840_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_rent_allowance(r: u32, ) -> Weight { - (155_126_000 as Weight) - // Standard Error: 225_000 - .saturating_add((599_056_000 as Weight).saturating_mul(r as Weight)) + (147_393_000 as Weight) + // Standard Error: 77_000 + .saturating_add((247_593_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_block_number(r: u32, ) -> Weight { - (144_566_000 as Weight) - // Standard Error: 110_000 - .saturating_add((257_620_000 as Weight).saturating_mul(r as Weight)) + (151_560_000 as Weight) + // Standard Error: 92_000 + .saturating_add((242_469_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_now(r: u32, ) -> Weight { - (147_274_000 as Weight) - // Standard Error: 115_000 - .saturating_add((258_627_000 as Weight).saturating_mul(r as Weight)) + (145_917_000 as Weight) + // Standard Error: 80_000 + .saturating_add((244_335_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_rent_params(r: u32, ) -> Weight { - (168_575_000 as Weight) - // Standard Error: 394_000 - .saturating_add((397_754_000 as Weight).saturating_mul(r as Weight)) + (150_399_000 as Weight) + // Standard Error: 90_000 + .saturating_add((381_505_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_weight_to_fee(r: u32, ) -> Weight { - (148_102_000 as Weight) - // Standard Error: 201_000 - .saturating_add((537_088_000 as Weight).saturating_mul(r as Weight)) + (152_906_000 as Weight) + // Standard Error: 418_000 + .saturating_add((486_338_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_gas(r: u32, ) -> Weight { - (125_122_000 as Weight) - // Standard Error: 89_000 - .saturating_add((122_350_000 as Weight).saturating_mul(r as Weight)) + (130_020_000 as Weight) + // Standard Error: 48_000 + .saturating_add((120_792_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_input(r: u32, ) -> Weight { - (137_334_000 as Weight) - // Standard Error: 99_000 - .saturating_add((7_359_000 as Weight).saturating_mul(r as Weight)) + (142_031_000 as Weight) + // Standard Error: 83_000 + .saturating_add((7_205_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_input_per_kb(n: u32, ) -> Weight { - (145_094_000 as Weight) + (151_770_000 as Weight) // Standard Error: 0 - .saturating_add((283_000 as Weight).saturating_mul(n as Weight)) + .saturating_add((247_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_return(r: u32, ) -> Weight { - (127_544_000 as Weight) - // Standard Error: 138_000 - .saturating_add((4_640_000 as Weight).saturating_mul(r as Weight)) + (131_023_000 as Weight) + // Standard Error: 69_000 + .saturating_add((4_823_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_return_per_kb(n: u32, ) -> Weight { - (137_517_000 as Weight) - // Standard Error: 0 - .saturating_add((783_000 as Weight).saturating_mul(n as Weight)) + (142_885_000 as Weight) + // Standard Error: 1_000 + .saturating_add((751_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_terminate(r: u32, ) -> Weight { - (138_292_000 as Weight) - // Standard Error: 689_000 - .saturating_add((111_698_000 as Weight).saturating_mul(r as Weight)) + (142_165_000 as Weight) + // Standard Error: 100_000 + .saturating_add((99_133_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((2 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((4 as Weight).saturating_mul(r as Weight))) } fn seal_terminate_per_code_kb(c: u32, ) -> Weight { - (263_507_000 as Weight) - // Standard Error: 12_000 - .saturating_add((8_409_000 as Weight).saturating_mul(c as Weight)) + (243_348_000 as Weight) + // Standard Error: 6_000 + .saturating_add((8_560_000 as Weight).saturating_mul(c as Weight)) .saturating_add(RocksDbWeight::get().reads(7 as Weight)) .saturating_add(RocksDbWeight::get().writes(5 as Weight)) } fn seal_restore_to(r: u32, ) -> Weight { - (232_291_000 as Weight) - // Standard Error: 301_000 - .saturating_add((136_379_000 as Weight).saturating_mul(r as Weight)) + (171_766_000 as Weight) + // Standard Error: 372_000 + .saturating_add((100_243_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((4 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes((6 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((5 as Weight).saturating_mul(r as Weight))) } fn seal_restore_to_per_code_kb_delta(c: u32, t: u32, d: u32, ) -> Weight { - (0 as Weight) - // Standard Error: 162_000 - .saturating_add((8_619_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 162_000 - .saturating_add((4_877_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 1_433_000 - .saturating_add((3_762_810_000 as Weight).saturating_mul(d as Weight)) + (112_646_000 as Weight) + // Standard Error: 142_000 + .saturating_add((7_922_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 142_000 + .saturating_add((3_590_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 1_255_000 + .saturating_add((3_716_501_000 as Weight).saturating_mul(d as Weight)) .saturating_add(RocksDbWeight::get().reads(8 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(d as Weight))) .saturating_add(RocksDbWeight::get().writes(7 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(d as Weight))) } fn seal_random(r: u32, ) -> Weight { - (153_634_000 as Weight) - // Standard Error: 267_000 - .saturating_add((650_160_000 as Weight).saturating_mul(r as Weight)) + (152_470_000 as Weight) + // Standard Error: 146_000 + .saturating_add((619_676_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_deposit_event(r: u32, ) -> Weight { - (137_080_000 as Weight) - // Standard Error: 1_009_000 - .saturating_add((949_228_000 as Weight).saturating_mul(r as Weight)) + (151_008_000 as Weight) + // Standard Error: 167_000 + .saturating_add((899_677_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_deposit_event_per_topic_and_kb(t: u32, n: u32, ) -> Weight { - (1_259_129_000 as Weight) - // Standard Error: 2_542_000 - .saturating_add((609_859_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 501_000 - .saturating_add((249_496_000 as Weight).saturating_mul(n as Weight)) + (1_227_526_000 as Weight) + // Standard Error: 2_767_000 + .saturating_add((586_284_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 545_000 + .saturating_add((247_578_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(t as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(t as Weight))) } fn seal_set_rent_allowance(r: u32, ) -> Weight { - (170_417_000 as Weight) - // Standard Error: 434_000 - .saturating_add((721_511_000 as Weight).saturating_mul(r as Weight)) + (142_734_000 as Weight) + // Standard Error: 53_000 + .saturating_add((167_026_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_set_storage(r: u32, ) -> Weight { - (1_870_542_000 as Weight) - // Standard Error: 26_871_000 - .saturating_add((18_312_239_000 as Weight).saturating_mul(r as Weight)) + (21_198_000 as Weight) + // Standard Error: 2_062_000 + .saturating_add((3_836_800_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_set_storage_per_kb(n: u32, ) -> Weight { - (1_763_732_000 as Weight) - // Standard Error: 258_000 - .saturating_add((74_848_000 as Weight).saturating_mul(n as Weight)) + (589_829_000 as Weight) + // Standard Error: 223_000 + .saturating_add((71_242_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().writes(2 as Weight)) } fn seal_clear_storage(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 2_745_000 - .saturating_add((2_316_433_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 1_950_000 + .saturating_add((1_267_479_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) .saturating_add(RocksDbWeight::get().writes(1 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_get_storage(r: u32, ) -> Weight { - (87_218_000 as Weight) - // Standard Error: 745_000 - .saturating_add((948_121_000 as Weight).saturating_mul(r as Weight)) + (3_466_000 as Weight) + // Standard Error: 1_248_000 + .saturating_add((920_416_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_get_storage_per_kb(n: u32, ) -> Weight { - (719_050_000 as Weight) - // Standard Error: 266_000 - .saturating_add((154_812_000 as Weight).saturating_mul(n as Weight)) + (618_423_000 as Weight) + // Standard Error: 231_000 + .saturating_add((153_218_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_transfer(r: u32, ) -> Weight { - (19_439_000 as Weight) - // Standard Error: 2_468_000 - .saturating_add((5_674_822_000 as Weight).saturating_mul(r as Weight)) + (76_247_000 as Weight) + // Standard Error: 2_153_000 + .saturating_add((5_509_779_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) .saturating_add(RocksDbWeight::get().reads((100 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes(2 as Weight)) .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_call(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 7_465_000 - .saturating_add((11_066_530_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 8_294_000 + .saturating_add((11_951_311_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((200 as Weight).saturating_mul(r as Weight))) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) + .saturating_add(RocksDbWeight::get().writes((100 as Weight).saturating_mul(r as Weight))) } fn seal_call_per_code_transfer_input_output_kb(c: u32, t: u32, i: u32, o: u32, ) -> Weight { - (9_916_288_000 as Weight) - // Standard Error: 552_000 - .saturating_add((397_842_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 229_902_000 - .saturating_add((5_243_673_000 as Weight).saturating_mul(t as Weight)) - // Standard Error: 72_000 - .saturating_add((59_737_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 77_000 - .saturating_add((82_259_000 as Weight).saturating_mul(o as Weight)) + (10_875_657_000 as Weight) + // Standard Error: 253_000 + .saturating_add((392_140_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 105_395_000 + .saturating_add((3_581_966_000 as Weight).saturating_mul(t as Weight)) + // Standard Error: 33_000 + .saturating_add((59_352_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 35_000 + .saturating_add((79_149_000 as Weight).saturating_mul(o as Weight)) .saturating_add(RocksDbWeight::get().reads(206 as Weight)) + .saturating_add(RocksDbWeight::get().writes(101 as Weight)) .saturating_add(RocksDbWeight::get().writes((101 as Weight).saturating_mul(t as Weight))) } fn seal_instantiate(r: u32, ) -> Weight { (0 as Weight) - // Standard Error: 32_016_000 - .saturating_add((22_206_489_000 as Weight).saturating_mul(r as Weight)) + // Standard Error: 31_795_000 + .saturating_add((21_908_561_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(6 as Weight)) .saturating_add(RocksDbWeight::get().reads((300 as Weight).saturating_mul(r as Weight))) - .saturating_add(RocksDbWeight::get().writes(2 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) .saturating_add(RocksDbWeight::get().writes((300 as Weight).saturating_mul(r as Weight))) } fn seal_instantiate_per_code_input_output_salt_kb(c: u32, i: u32, o: u32, s: u32, ) -> Weight { - (9_991_947_000 as Weight) - // Standard Error: 637_000 - .saturating_add((881_981_000 as Weight).saturating_mul(c as Weight)) - // Standard Error: 90_000 - .saturating_add((63_638_000 as Weight).saturating_mul(i as Weight)) - // Standard Error: 90_000 - .saturating_add((87_288_000 as Weight).saturating_mul(o as Weight)) - // Standard Error: 90_000 - .saturating_add((311_808_000 as Weight).saturating_mul(s as Weight)) + (10_580_308_000 as Weight) + // Standard Error: 611_000 + .saturating_add((875_153_000 as Weight).saturating_mul(c as Weight)) + // Standard Error: 86_000 + .saturating_add((62_540_000 as Weight).saturating_mul(i as Weight)) + // Standard Error: 86_000 + .saturating_add((83_080_000 as Weight).saturating_mul(o as Weight)) + // Standard Error: 86_000 + .saturating_add((350_970_000 as Weight).saturating_mul(s as Weight)) .saturating_add(RocksDbWeight::get().reads(207 as Weight)) - .saturating_add(RocksDbWeight::get().writes(203 as Weight)) + .saturating_add(RocksDbWeight::get().writes(204 as Weight)) } fn seal_hash_sha2_256(r: u32, ) -> Weight { - (132_452_000 as Weight) - // Standard Error: 227_000 - .saturating_add((239_671_000 as Weight).saturating_mul(r as Weight)) + (143_987_000 as Weight) + // Standard Error: 90_000 + .saturating_add((232_215_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_sha2_256_per_kb(n: u32, ) -> Weight { - (756_802_000 as Weight) - // Standard Error: 48_000 - .saturating_add((429_454_000 as Weight).saturating_mul(n as Weight)) + (762_075_000 as Weight) + // Standard Error: 64_000 + .saturating_add((475_112_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_keccak_256(r: u32, ) -> Weight { - (139_440_000 as Weight) - // Standard Error: 128_000 - .saturating_add((249_514_000 as Weight).saturating_mul(r as Weight)) + (145_456_000 as Weight) + // Standard Error: 203_000 + .saturating_add((241_831_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_keccak_256_per_kb(n: u32, ) -> Weight { - (658_595_000 as Weight) - // Standard Error: 35_000 - .saturating_add((343_814_000 as Weight).saturating_mul(n as Weight)) + (660_371_000 as Weight) + // Standard Error: 30_000 + .saturating_add((342_147_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_256(r: u32, ) -> Weight { - (138_124_000 as Weight) - // Standard Error: 140_000 - .saturating_add((223_189_000 as Weight).saturating_mul(r as Weight)) + (149_472_000 as Weight) + // Standard Error: 101_000 + .saturating_add((212_899_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_256_per_kb(n: u32, ) -> Weight { - (689_667_000 as Weight) - // Standard Error: 41_000 - .saturating_add((160_006_000 as Weight).saturating_mul(n as Weight)) + (643_371_000 as Weight) + // Standard Error: 31_000 + .saturating_add((159_244_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_128(r: u32, ) -> Weight { - (140_225_000 as Weight) - // Standard Error: 156_000 - .saturating_add((223_696_000 as Weight).saturating_mul(r as Weight)) + (147_732_000 as Weight) + // Standard Error: 91_000 + .saturating_add((210_975_000 as Weight).saturating_mul(r as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn seal_hash_blake2_128_per_kb(n: u32, ) -> Weight { - (693_756_000 as Weight) - // Standard Error: 40_000 - .saturating_add((159_996_000 as Weight).saturating_mul(n as Weight)) + (684_085_000 as Weight) + // Standard Error: 38_000 + .saturating_add((159_213_000 as Weight).saturating_mul(n as Weight)) .saturating_add(RocksDbWeight::get().reads(5 as Weight)) + .saturating_add(RocksDbWeight::get().writes(1 as Weight)) } fn instr_i64const(r: u32, ) -> Weight { - (24_250_000 as Weight) - // Standard Error: 14_000 - .saturating_add((3_134_000 as Weight).saturating_mul(r as Weight)) + (25_332_000 as Weight) + // Standard Error: 12_000 + .saturating_add((3_087_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64load(r: u32, ) -> Weight { - (26_509_000 as Weight) - // Standard Error: 27_000 - .saturating_add((161_556_000 as Weight).saturating_mul(r as Weight)) + (27_404_000 as Weight) + // Standard Error: 22_000 + .saturating_add((136_046_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64store(r: u32, ) -> Weight { - (26_499_000 as Weight) - // Standard Error: 59_000 - .saturating_add((233_755_000 as Weight).saturating_mul(r as Weight)) + (27_422_000 as Weight) + // Standard Error: 24_000 + .saturating_add((204_925_000 as Weight).saturating_mul(r as Weight)) } fn instr_select(r: u32, ) -> Weight { - (24_175_000 as Weight) + (25_289_000 as Weight) // Standard Error: 16_000 - .saturating_add((12_450_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((12_375_000 as Weight).saturating_mul(r as Weight)) } fn instr_if(r: u32, ) -> Weight { - (24_219_000 as Weight) - // Standard Error: 26_000 - .saturating_add((12_058_000 as Weight).saturating_mul(r as Weight)) + (25_278_000 as Weight) + // Standard Error: 14_000 + .saturating_add((11_447_000 as Weight).saturating_mul(r as Weight)) } fn instr_br(r: u32, ) -> Weight { - (24_146_000 as Weight) - // Standard Error: 20_000 - .saturating_add((6_017_000 as Weight).saturating_mul(r as Weight)) + (25_283_000 as Weight) + // Standard Error: 15_000 + .saturating_add((5_615_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_if(r: u32, ) -> Weight { - (24_229_000 as Weight) - // Standard Error: 24_000 - .saturating_add((13_726_000 as Weight).saturating_mul(r as Weight)) + (25_377_000 as Weight) + // Standard Error: 20_000 + .saturating_add((13_248_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table(r: u32, ) -> Weight { - (24_219_000 as Weight) - // Standard Error: 27_000 - .saturating_add((15_115_000 as Weight).saturating_mul(r as Weight)) + (25_318_000 as Weight) + // Standard Error: 14_000 + .saturating_add((14_962_000 as Weight).saturating_mul(r as Weight)) } fn instr_br_table_per_entry(e: u32, ) -> Weight { - (34_981_000 as Weight) + (37_040_000 as Weight) // Standard Error: 1_000 - .saturating_add((156_000 as Weight).saturating_mul(e as Weight)) + .saturating_add((150_000 as Weight).saturating_mul(e as Weight)) } fn instr_call(r: u32, ) -> Weight { - (24_599_000 as Weight) - // Standard Error: 102_000 - .saturating_add((95_771_000 as Weight).saturating_mul(r as Weight)) + (25_529_000 as Weight) + // Standard Error: 114_000 + .saturating_add((91_613_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect(r: u32, ) -> Weight { - (32_584_000 as Weight) - // Standard Error: 176_000 - .saturating_add((193_216_000 as Weight).saturating_mul(r as Weight)) + (33_242_000 as Weight) + // Standard Error: 188_000 + .saturating_add((191_383_000 as Weight).saturating_mul(r as Weight)) } fn instr_call_indirect_per_param(p: u32, ) -> Weight { - (240_739_000 as Weight) - // Standard Error: 6_000 - .saturating_add((3_407_000 as Weight).saturating_mul(p as Weight)) + (228_146_000 as Weight) + // Standard Error: 4_000 + .saturating_add((3_917_000 as Weight).saturating_mul(p as Weight)) } fn instr_local_get(r: u32, ) -> Weight { - (41_963_000 as Weight) - // Standard Error: 15_000 - .saturating_add((3_110_000 as Weight).saturating_mul(r as Weight)) + (44_304_000 as Weight) + // Standard Error: 22_000 + .saturating_add((3_146_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_set(r: u32, ) -> Weight { - (41_956_000 as Weight) - // Standard Error: 9_000 - .saturating_add((3_460_000 as Weight).saturating_mul(r as Weight)) + (44_314_000 as Weight) + // Standard Error: 17_000 + .saturating_add((3_474_000 as Weight).saturating_mul(r as Weight)) } fn instr_local_tee(r: u32, ) -> Weight { - (42_002_000 as Weight) - // Standard Error: 20_000 - .saturating_add((4_591_000 as Weight).saturating_mul(r as Weight)) + (44_234_000 as Weight) + // Standard Error: 14_000 + .saturating_add((4_725_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_get(r: u32, ) -> Weight { - (27_646_000 as Weight) - // Standard Error: 23_000 - .saturating_add((7_821_000 as Weight).saturating_mul(r as Weight)) + (28_754_000 as Weight) + // Standard Error: 20_000 + .saturating_add((7_898_000 as Weight).saturating_mul(r as Weight)) } fn instr_global_set(r: u32, ) -> Weight { - (27_615_000 as Weight) - // Standard Error: 27_000 - .saturating_add((11_807_000 as Weight).saturating_mul(r as Weight)) + (28_737_000 as Weight) + // Standard Error: 26_000 + .saturating_add((8_531_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_current(r: u32, ) -> Weight { - (27_106_000 as Weight) - // Standard Error: 78_000 - .saturating_add((2_952_000 as Weight).saturating_mul(r as Weight)) + (27_338_000 as Weight) + // Standard Error: 22_000 + .saturating_add((3_499_000 as Weight).saturating_mul(r as Weight)) } fn instr_memory_grow(r: u32, ) -> Weight { - (24_956_000 as Weight) - // Standard Error: 3_541_000 - .saturating_add((2_332_414_000 as Weight).saturating_mul(r as Weight)) + (25_943_000 as Weight) + // Standard Error: 299_000 + .saturating_add((2_094_164_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64clz(r: u32, ) -> Weight { - (24_183_000 as Weight) - // Standard Error: 18_000 - .saturating_add((5_166_000 as Weight).saturating_mul(r as Weight)) + (25_269_000 as Weight) + // Standard Error: 14_000 + .saturating_add((5_135_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ctz(r: u32, ) -> Weight { - (24_142_000 as Weight) - // Standard Error: 17_000 - .saturating_add((5_146_000 as Weight).saturating_mul(r as Weight)) + (25_281_000 as Weight) + // Standard Error: 16_000 + .saturating_add((5_069_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64popcnt(r: u32, ) -> Weight { - (24_161_000 as Weight) - // Standard Error: 23_000 - .saturating_add((5_807_000 as Weight).saturating_mul(r as Weight)) + (25_243_000 as Weight) + // Standard Error: 9_000 + .saturating_add((5_809_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eqz(r: u32, ) -> Weight { - (24_167_000 as Weight) - // Standard Error: 24_000 - .saturating_add((5_288_000 as Weight).saturating_mul(r as Weight)) + (25_259_000 as Weight) + // Standard Error: 13_000 + .saturating_add((5_120_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendsi32(r: u32, ) -> Weight { - (24_252_000 as Weight) - // Standard Error: 9_000 - .saturating_add((5_091_000 as Weight).saturating_mul(r as Weight)) + (25_249_000 as Weight) + // Standard Error: 14_000 + .saturating_add((5_167_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64extendui32(r: u32, ) -> Weight { - (24_243_000 as Weight) - // Standard Error: 16_000 - .saturating_add((5_076_000 as Weight).saturating_mul(r as Weight)) + (25_247_000 as Weight) + // Standard Error: 10_000 + .saturating_add((5_118_000 as Weight).saturating_mul(r as Weight)) } fn instr_i32wrapi64(r: u32, ) -> Weight { - (24_227_000 as Weight) - // Standard Error: 15_000 - .saturating_add((5_135_000 as Weight).saturating_mul(r as Weight)) + (25_285_000 as Weight) + // Standard Error: 19_000 + .saturating_add((5_051_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64eq(r: u32, ) -> Weight { - (24_278_000 as Weight) - // Standard Error: 15_000 - .saturating_add((7_124_000 as Weight).saturating_mul(r as Weight)) + (25_312_000 as Weight) + // Standard Error: 19_000 + .saturating_add((7_207_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ne(r: u32, ) -> Weight { - (24_254_000 as Weight) - // Standard Error: 19_000 - .saturating_add((7_067_000 as Weight).saturating_mul(r as Weight)) + (25_311_000 as Weight) + // Standard Error: 14_000 + .saturating_add((6_982_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64lts(r: u32, ) -> Weight { - (24_220_000 as Weight) - // Standard Error: 14_000 - .saturating_add((7_122_000 as Weight).saturating_mul(r as Weight)) + (25_327_000 as Weight) + // Standard Error: 19_000 + .saturating_add((7_009_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ltu(r: u32, ) -> Weight { - (24_221_000 as Weight) - // Standard Error: 19_000 - .saturating_add((7_221_000 as Weight).saturating_mul(r as Weight)) + (25_318_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_180_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gts(r: u32, ) -> Weight { - (24_259_000 as Weight) + (25_330_000 as Weight) // Standard Error: 13_000 - .saturating_add((7_135_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((7_065_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64gtu(r: u32, ) -> Weight { - (24_245_000 as Weight) - // Standard Error: 10_000 - .saturating_add((7_193_000 as Weight).saturating_mul(r as Weight)) + (25_284_000 as Weight) + // Standard Error: 16_000 + .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64les(r: u32, ) -> Weight { - (24_289_000 as Weight) - // Standard Error: 22_000 - .saturating_add((7_023_000 as Weight).saturating_mul(r as Weight)) + (25_310_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_080_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64leu(r: u32, ) -> Weight { - (24_239_000 as Weight) - // Standard Error: 21_000 - .saturating_add((7_065_000 as Weight).saturating_mul(r as Weight)) + (25_262_000 as Weight) + // Standard Error: 11_000 + .saturating_add((7_079_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64ges(r: u32, ) -> Weight { - (24_256_000 as Weight) - // Standard Error: 13_000 - .saturating_add((7_119_000 as Weight).saturating_mul(r as Weight)) + (25_295_000 as Weight) + // Standard Error: 10_000 + .saturating_add((7_151_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64geu(r: u32, ) -> Weight { - (24_240_000 as Weight) + (25_326_000 as Weight) // Standard Error: 18_000 - .saturating_add((7_225_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((7_200_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64add(r: u32, ) -> Weight { - (24_266_000 as Weight) - // Standard Error: 24_000 - .saturating_add((6_996_000 as Weight).saturating_mul(r as Weight)) + (25_320_000 as Weight) + // Standard Error: 23_000 + .saturating_add((7_020_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64sub(r: u32, ) -> Weight { - (24_265_000 as Weight) - // Standard Error: 17_000 - .saturating_add((6_974_000 as Weight).saturating_mul(r as Weight)) + (25_303_000 as Weight) + // Standard Error: 15_000 + .saturating_add((7_189_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64mul(r: u32, ) -> Weight { - (24_232_000 as Weight) - // Standard Error: 15_000 - .saturating_add((7_103_000 as Weight).saturating_mul(r as Weight)) + (25_311_000 as Weight) + // Standard Error: 16_000 + .saturating_add((7_054_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divs(r: u32, ) -> Weight { - (24_245_000 as Weight) - // Standard Error: 20_000 - .saturating_add((12_915_000 as Weight).saturating_mul(r as Weight)) + (25_342_000 as Weight) + // Standard Error: 10_000 + .saturating_add((12_860_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64divu(r: u32, ) -> Weight { - (24_177_000 as Weight) - // Standard Error: 21_000 - .saturating_add((12_232_000 as Weight).saturating_mul(r as Weight)) + (25_307_000 as Weight) + // Standard Error: 17_000 + .saturating_add((12_162_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rems(r: u32, ) -> Weight { - (24_171_000 as Weight) - // Standard Error: 15_000 - .saturating_add((12_939_000 as Weight).saturating_mul(r as Weight)) + (25_354_000 as Weight) + // Standard Error: 12_000 + .saturating_add((12_855_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64remu(r: u32, ) -> Weight { - (24_788_000 as Weight) - // Standard Error: 22_000 - .saturating_add((11_657_000 as Weight).saturating_mul(r as Weight)) + (25_319_000 as Weight) + // Standard Error: 16_000 + .saturating_add((11_982_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64and(r: u32, ) -> Weight { - (24_252_000 as Weight) - // Standard Error: 19_000 - .saturating_add((7_003_000 as Weight).saturating_mul(r as Weight)) + (25_351_000 as Weight) + // Standard Error: 20_000 + .saturating_add((7_124_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64or(r: u32, ) -> Weight { - (24_263_000 as Weight) - // Standard Error: 12_000 - .saturating_add((7_005_000 as Weight).saturating_mul(r as Weight)) + (25_333_000 as Weight) + // Standard Error: 20_000 + .saturating_add((7_060_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64xor(r: u32, ) -> Weight { - (24_239_000 as Weight) - // Standard Error: 17_000 - .saturating_add((7_020_000 as Weight).saturating_mul(r as Weight)) + (25_332_000 as Weight) + // Standard Error: 13_000 + .saturating_add((7_080_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shl(r: u32, ) -> Weight { - (24_212_000 as Weight) - // Standard Error: 13_000 - .saturating_add((7_172_000 as Weight).saturating_mul(r as Weight)) + (25_279_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_193_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shrs(r: u32, ) -> Weight { - (24_220_000 as Weight) - // Standard Error: 27_000 - .saturating_add((7_246_000 as Weight).saturating_mul(r as Weight)) + (25_315_000 as Weight) + // Standard Error: 13_000 + .saturating_add((7_157_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64shru(r: u32, ) -> Weight { - (24_213_000 as Weight) + (25_354_000 as Weight) // Standard Error: 14_000 - .saturating_add((7_191_000 as Weight).saturating_mul(r as Weight)) + .saturating_add((7_238_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotl(r: u32, ) -> Weight { - (24_221_000 as Weight) - // Standard Error: 18_000 - .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight)) + (25_353_000 as Weight) + // Standard Error: 14_000 + .saturating_add((7_160_000 as Weight).saturating_mul(r as Weight)) } fn instr_i64rotr(r: u32, ) -> Weight { - (24_235_000 as Weight) - // Standard Error: 12_000 - .saturating_add((7_106_000 as Weight).saturating_mul(r as Weight)) + (25_363_000 as Weight) + // Standard Error: 16_000 + .saturating_add((7_192_000 as Weight).saturating_mul(r as Weight)) } }