From 437764b749e77be70fb1d13b070030bac87551e7 Mon Sep 17 00:00:00 2001 From: Daniel Shiposha Date: Thu, 05 Oct 2023 19:17:44 +0000 Subject: [PATCH] refactor: property writer / fix set_token_props weight --- --- a/pallets/balances-adapter/src/common.rs +++ b/pallets/balances-adapter/src/common.rs @@ -30,15 +30,7 @@ Weight::default() } - fn delete_collection_properties(_amount: u32) -> Weight { - Weight::default() - } - fn set_token_properties(_amount: u32) -> Weight { - Weight::default() - } - - fn delete_token_properties(_amount: u32) -> Weight { Weight::default() } @@ -63,18 +55,6 @@ } fn burn_from() -> Weight { - Weight::default() - } - - fn burn_recursively_self_raw() -> Weight { - Weight::default() - } - - fn burn_recursively_breadth_raw(_amount: u32) -> Weight { - Weight::default() - } - - fn token_owner() -> Weight { Weight::default() } @@ -124,16 +104,6 @@ _sender: ::CrossAccountId, _token: TokenId, _amount: u128, - ) -> frame_support::pallet_prelude::DispatchResultWithPostInfo { - fail!(>::UnsupportedOperation); - } - - fn burn_item_recursively( - &self, - _sender: ::CrossAccountId, - _token: TokenId, - _self_budget: &dyn up_data_structs::budget::Budget, - _breadth_budget: &dyn up_data_structs::budget::Budget, ) -> frame_support::pallet_prelude::DispatchResultWithPostInfo { fail!(>::UnsupportedOperation); } --- a/pallets/common/src/benchmarking.rs +++ b/pallets/common/src/benchmarking.rs @@ -34,7 +34,7 @@ MAX_TOKEN_PREFIX_LENGTH, }; -use crate::{CollectionHandle, Config, Pallet}; +use crate::{BenchmarkPropertyWriter, CollectionHandle, Config, Pallet}; const SEED: u32 = 1; @@ -123,16 +123,6 @@ CollectionMode::NFT, |owner: T::CrossAccountId, data| >::init_collection(owner.clone(), owner, data), |h| h, - ) -} - -pub fn load_is_admin_and_property_permissions( - collection: &CollectionHandle, - sender: &T::CrossAccountId, -) -> (bool, PropertiesPermissionMap) { - ( - collection.is_owner_or_admin(sender), - >::property_permissions(collection.id), ) } @@ -272,7 +262,7 @@ #[block] { - load_is_admin_and_property_permissions(&collection, &sender); + >::load_collection_info(&&collection, &sender); } Ok(()) --- a/pallets/common/src/lib.rs +++ b/pallets/common/src/lib.rs @@ -872,7 +872,7 @@ } /// Value representation with delayed initialization time. -pub struct LazyValue T> { +pub struct LazyValue { value: Option, f: Option, } @@ -1902,7 +1902,9 @@ /// Collection property deletion weight. /// /// * `amount`- The number of properties to set. - fn delete_collection_properties(amount: u32) -> Weight; + fn delete_collection_properties(amount: u32) -> Weight { + Self::set_collection_properties(amount) + } /// Token property setting weight. /// @@ -1912,7 +1914,9 @@ /// Token property deletion weight. /// /// * `amount`- The number of properties to delete. - fn delete_token_properties(amount: u32) -> Weight; + fn delete_token_properties(amount: u32) -> Weight { + Self::set_token_properties(amount) + } /// Token property permissions set weight. /// @@ -1934,30 +1938,6 @@ /// The price of burning a token from another user. fn burn_from() -> Weight; - /// Differs from burn_item in case of Fungible and Refungible, as it should burn - /// whole users's balance. - /// - /// This method shouldn't be used directly, as it doesn't count breadth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead - fn burn_recursively_self_raw() -> Weight; - - /// Cost of iterating over `amount` children while burning, without counting child burning itself. - /// - /// This method shouldn't be used directly, as it doesn't count depth price, use [burn_recursively](CommonWeightInfo::burn_recursively) instead - fn burn_recursively_breadth_raw(amount: u32) -> Weight; - - /// The price of recursive burning a token. - /// - /// `max_selfs` - The maximum burning weight of the token itself. - /// `max_breadth` - The maximum number of nested tokens to burn. - fn burn_recursively(max_selfs: u32, max_breadth: u32) -> Weight { - Self::burn_recursively_self_raw() - .saturating_mul(max_selfs.max(1) as u64) - .saturating_add(Self::burn_recursively_breadth_raw(max_breadth)) - } - - /// The price of retrieving token owner - fn token_owner() -> Weight; - /// The price of setting approval for all fn set_allowance_for_all() -> Weight; @@ -2029,20 +2009,6 @@ amount: u128, ) -> DispatchResultWithPostInfo; - /// Burn token and all nested tokens recursievly. - /// - /// * `sender` - The user who owns the token. - /// * `token` - Token id that will burned. - /// * `self_budget` - The budget that can be spent on burning tokens. - /// * `breadth_budget` - The budget that can be spent on burning nested tokens. - fn burn_item_recursively( - &self, - sender: T::CrossAccountId, - token: TokenId, - self_budget: &dyn Budget, - breadth_budget: &dyn Budget, - ) -> DispatchResultWithPostInfo; - /// Set collection properties. /// /// * `sender` - Must be either the owner of the collection or its admin. @@ -2373,14 +2339,6 @@ } } } - -/// A marker structure that enables the writer implementation -/// to provide the interface to write properties to **newly created** tokens. -pub struct NewTokenPropertyWriter; - -/// A marker structure that enables the writer implementation -/// to provide the interface to write properties to **already existing** tokens. -pub struct ExistingTokenPropertyWriter; /// The type-safe interface for writing properties (setting or deleting) to tokens. /// It has two distinct implementations for newly created tokens and existing ones. @@ -2388,146 +2346,39 @@ /// This type utilizes the lazy evaluation to avoid repeating the computation /// of several performance-heavy or PoV-heavy tasks, /// such as checking the indirect ownership or reading the token property permissions. -pub struct PropertyWriter< - 'a, - T, - Handle, - WriterVariant, - FIsAdmin, - FPropertyPermissions, - FCheckTokenExist, - FGetProperties, -> where - T: Config, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, -{ +pub struct PropertyWriter<'a, WriterVariant, T, Handle, FIsAdmin, FPropertyPermissions> { collection: &'a Handle, - is_collection_admin: LazyValue, - property_permissions: LazyValue, - check_token_exist: FCheckTokenExist, - get_properties: FGetProperties, + collection_lazy_info: PropertyWriterLazyCollectionInfo, _phantom: PhantomData<(T, WriterVariant)>, } -impl<'a, T, Handle, FIsAdmin, FPropertyPermissions, FCheckTokenExist, FGetProperties> - PropertyWriter< - 'a, - T, - Handle, - NewTokenPropertyWriter, - FIsAdmin, - FPropertyPermissions, - FCheckTokenExist, - FGetProperties, - > where +impl<'a, T, Handle, WriterVariant, FIsAdmin, FPropertyPermissions> + PropertyWriter<'a, WriterVariant, T, Handle, FIsAdmin, FPropertyPermissions> +where T: Config, Handle: CommonCollectionOperations + Deref>, FIsAdmin: FnOnce() -> bool, FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, - FCheckTokenExist: Copy + FnOnce(TokenId) -> bool, - FGetProperties: Copy + FnOnce(TokenId) -> TokenProperties, { - /// A function to write properties to a **newly created** token. - pub fn write_token_properties( + fn internal_write_token_properties( &mut self, - mint_target_is_sender: bool, token_id: TokenId, - properties_updates: impl Iterator, - log: evm_coder::ethereum::Log, - ) -> DispatchResult { - self.internal_write_token_properties( - token_id, - properties_updates.map(|p| (p.key, Some(p.value))), - |_| Ok(mint_target_is_sender), - log, - ) - } -} - -impl<'a, T, Handle, FIsAdmin, FPropertyPermissions, FCheckTokenExist, FGetProperties> - PropertyWriter< - 'a, - T, - Handle, - ExistingTokenPropertyWriter, - FIsAdmin, - FPropertyPermissions, - FCheckTokenExist, - FGetProperties, - > where - T: Config, - Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, - FCheckTokenExist: Copy + FnOnce(TokenId) -> bool, - FGetProperties: Copy + FnOnce(TokenId) -> TokenProperties, -{ - /// A function to write properties to an **already existing** token. - pub fn write_token_properties( - &mut self, - sender: &T::CrossAccountId, - token_id: TokenId, - properties_updates: impl Iterator)>, - nesting_budget: &dyn Budget, - log: evm_coder::ethereum::Log, - ) -> DispatchResult { - self.internal_write_token_properties( - token_id, - properties_updates, - |collection| collection.check_token_indirect_owner(token_id, sender, nesting_budget), - log, - ) - } -} - -impl< - 'a, - T, - Handle, - WriterVariant, - FIsAdmin, - FPropertyPermissions, - FCheckTokenExist, - FGetProperties, - > - PropertyWriter< - 'a, - T, - Handle, - WriterVariant, - FIsAdmin, - FPropertyPermissions, - FCheckTokenExist, - FGetProperties, - > where - T: Config, - Handle: CommonCollectionOperations + Deref>, - FIsAdmin: FnOnce() -> bool, - FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, - FCheckTokenExist: Copy + FnOnce(TokenId) -> bool, - FGetProperties: Copy + FnOnce(TokenId) -> TokenProperties, -{ - fn internal_write_token_properties( - &mut self, - token_id: TokenId, + mut token_lazy_info: PropertyWriterLazyTokenInfo< + FCheckTokenExist, + FCheckTokenOwner, + FGetProperties, + >, properties_updates: impl Iterator)>, - check_token_owner: FCheckTokenOwner, log: evm_coder::ethereum::Log, ) -> DispatchResult where - FCheckTokenOwner: FnOnce(&Handle) -> Result, + FCheckTokenExist: FnOnce() -> bool, + FCheckTokenOwner: FnOnce() -> Result, + FGetProperties: FnOnce() -> TokenProperties, { - let get_properties = self.get_properties; - let mut stored_properties = LazyValue::new(move || get_properties(token_id)); - - let mut is_token_owner = LazyValue::new(|| check_token_owner(self.collection)); - - let check_token_exist = self.check_token_exist; - let mut is_token_exist = LazyValue::new(move || check_token_exist(token_id)); - for (key, value) in properties_updates { let permission = self + .collection_lazy_info .property_permissions .value() .get(&key) @@ -2536,7 +2387,11 @@ match permission { PropertyPermission { mutable: false, .. } - if stored_properties.value().get(&key).is_some() => + if token_lazy_info + .stored_properties + .value() + .get(&key) + .is_some() => { return Err(>::NoPermission.into()); } @@ -2548,15 +2403,16 @@ } => check_token_permissions::( collection_admin, token_owner, - &mut self.is_collection_admin, - &mut is_token_owner, - &mut is_token_exist, + &mut self.collection_lazy_info.is_collection_admin, + &mut token_lazy_info.is_token_owner, + &mut token_lazy_info.is_token_exist, )?, } match value { Some(value) => { - stored_properties + token_lazy_info + .stored_properties .value_mut() .try_set(key.clone(), value) .map_err(>::from)?; @@ -2568,7 +2424,8 @@ )); } None => { - stored_properties + token_lazy_info + .stored_properties .value_mut() .remove(&key) .map_err(>::from)?; @@ -2582,142 +2439,330 @@ } } - let properties_changed = stored_properties.has_value(); + let properties_changed = token_lazy_info.stored_properties.has_value(); if properties_changed { >::deposit_log(log); self.collection - .set_token_properties_raw(token_id, stored_properties.into_inner()); + .set_token_properties_raw(token_id, token_lazy_info.stored_properties.into_inner()); } Ok(()) } } -/// Create a [`PropertyWriter`] for newly created tokens. -pub fn property_writer_for_new_token<'a, T, Handle>( - collection: &'a Handle, - sender: &'a T::CrossAccountId, -) -> PropertyWriter< - 'a, - T, - Handle, - NewTokenPropertyWriter, - impl FnOnce() -> bool + 'a, - impl FnOnce() -> PropertiesPermissionMap + 'a, - impl Copy + FnOnce(TokenId) -> bool + 'a, - impl Copy + FnOnce(TokenId) -> TokenProperties + 'a, -> +/// A helper structure for the [`PropertyWriter`] that holds +/// the collection-related info. The info is loaded using lazy evaluation. +/// This info is common for any token for which we write properties. +pub struct PropertyWriterLazyCollectionInfo { + is_collection_admin: LazyValue, + property_permissions: LazyValue, +} + +/// A helper structure for the [`PropertyWriter`] that holds +/// the token-related info. The info is loaded using lazy evaluation. +pub struct PropertyWriterLazyTokenInfo { + is_token_exist: LazyValue, + is_token_owner: LazyValue, FCheckTokenOwner>, + stored_properties: LazyValue, +} + +impl + PropertyWriterLazyTokenInfo where + FCheckTokenExist: FnOnce() -> bool, + FCheckTokenOwner: FnOnce() -> Result, + FGetProperties: FnOnce() -> TokenProperties, +{ + /// Create a lazy token info. + pub fn new( + check_token_exist: FCheckTokenExist, + check_token_owner: FCheckTokenOwner, + get_token_properties: FGetProperties, + ) -> Self { + Self { + is_token_exist: LazyValue::new(check_token_exist), + is_token_owner: LazyValue::new(check_token_owner), + stored_properties: LazyValue::new(get_token_properties), + } + } +} + +/// A marker structure that enables the writer implementation +/// to provide the interface to write properties to **newly created** tokens. +pub struct NewTokenPropertyWriter(PhantomData); +impl NewTokenPropertyWriter { + /// Creates a [`PropertyWriter`] for **newly created** tokens. + pub fn new<'a, Handle>( + collection: &'a Handle, + sender: &'a T::CrossAccountId, + ) -> PropertyWriter< + 'a, + Self, + T, + Handle, + impl FnOnce() -> bool + 'a, + impl FnOnce() -> PropertiesPermissionMap + 'a, + > + where + T: Config, + Handle: CommonCollectionOperations + Deref>, + { + PropertyWriter { + collection, + collection_lazy_info: PropertyWriterLazyCollectionInfo { + is_collection_admin: LazyValue::new(|| collection.is_owner_or_admin(sender)), + property_permissions: LazyValue::new(|| { + >::property_permissions(collection.id) + }), + }, + _phantom: PhantomData, + } + } +} + +impl<'a, T, Handle, FIsAdmin, FPropertyPermissions> + PropertyWriter<'a, NewTokenPropertyWriter, T, Handle, FIsAdmin, FPropertyPermissions> +where T: Config, Handle: CommonCollectionOperations + Deref>, + FIsAdmin: FnOnce() -> bool, + FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { - PropertyWriter { - collection, - is_collection_admin: LazyValue::new(|| collection.is_owner_or_admin(sender)), - property_permissions: LazyValue::new(|| >::property_permissions(collection.id)), - check_token_exist: |token_id| { - debug_assert!(collection.token_exists(token_id)); + /// A function to write properties to a **newly created** token. + pub fn write_token_properties( + &mut self, + mint_target_is_sender: bool, + token_id: TokenId, + properties_updates: impl Iterator, + log: evm_coder::ethereum::Log, + ) -> DispatchResult { + let check_token_exist = || { + debug_assert!(self.collection.token_exists(token_id)); true - }, - get_properties: |token_id| { - debug_assert!(collection.get_token_properties_raw(token_id).is_none()); + }; + + let check_token_owner = || Ok(mint_target_is_sender); + + let get_token_properties = || { + debug_assert!(self.collection.get_token_properties_raw(token_id).is_none()); TokenProperties::new() - }, - _phantom: PhantomData, + }; + + self.internal_write_token_properties( + token_id, + PropertyWriterLazyTokenInfo::new( + check_token_exist, + check_token_owner, + get_token_properties, + ), + properties_updates.map(|p| (p.key, Some(p.value))), + log, + ) } } -#[cfg(feature = "runtime-benchmarks")] -/// Create a `PropertyWriter` with preloaded `is_collection_admin` and `property_permissions. -/// Also: -/// * it will return `true` for the token ownership check. -/// * it will return empty stored properties without reading them from the storage. -pub fn collection_info_loaded_property_writer( - collection: &Handle, - is_collection_admin: bool, - property_permissions: PropertiesPermissionMap, -) -> PropertyWriter< - T, - Handle, - NewTokenPropertyWriter, - impl FnOnce() -> bool, - impl FnOnce() -> PropertiesPermissionMap, - impl Copy + FnOnce(TokenId) -> bool, - impl Copy + FnOnce(TokenId) -> TokenProperties, -> +/// A marker structure that enables the writer implementation +/// to provide the interface to write properties to **already existing** tokens. +pub struct ExistingTokenPropertyWriter(PhantomData); +impl ExistingTokenPropertyWriter { + /// Creates a [`PropertyWriter`] for **already existing** tokens. + pub fn new<'a, Handle>( + collection: &'a Handle, + sender: &'a T::CrossAccountId, + ) -> PropertyWriter< + 'a, + Self, + T, + Handle, + impl FnOnce() -> bool + 'a, + impl FnOnce() -> PropertiesPermissionMap + 'a, + > + where + Handle: CommonCollectionOperations + Deref>, + { + PropertyWriter { + collection, + collection_lazy_info: PropertyWriterLazyCollectionInfo { + is_collection_admin: LazyValue::new(|| collection.is_owner_or_admin(sender)), + property_permissions: LazyValue::new(|| { + >::property_permissions(collection.id) + }), + }, + _phantom: PhantomData, + } + } +} + +impl<'a, T, Handle, FIsAdmin, FPropertyPermissions> + PropertyWriter<'a, ExistingTokenPropertyWriter, T, Handle, FIsAdmin, FPropertyPermissions> where T: Config, Handle: CommonCollectionOperations + Deref>, + FIsAdmin: FnOnce() -> bool, + FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { - PropertyWriter { - collection, - is_collection_admin: LazyValue::new(move || is_collection_admin), - property_permissions: LazyValue::new(move || property_permissions), - check_token_exist: |_token_id| true, - get_properties: |_token_id| TokenProperties::new(), - _phantom: PhantomData, + /// A function to write properties to an **already existing** token. + pub fn write_token_properties( + &mut self, + sender: &T::CrossAccountId, + token_id: TokenId, + properties_updates: impl Iterator)>, + nesting_budget: &dyn Budget, + log: evm_coder::ethereum::Log, + ) -> DispatchResult { + let check_token_exist = || self.collection.token_exists(token_id); + let check_token_owner = || { + self.collection + .check_token_indirect_owner(token_id, sender, nesting_budget) + }; + let get_token_properties = || { + self.collection + .get_token_properties_raw(token_id) + .unwrap_or_default() + }; + + self.internal_write_token_properties( + token_id, + PropertyWriterLazyTokenInfo::new( + check_token_exist, + check_token_owner, + get_token_properties, + ), + properties_updates, + log, + ) } } -/// Create a [`PropertyWriter`] for already existing tokens. -pub fn property_writer_for_existing_token<'a, T, Handle>( - collection: &'a Handle, - sender: &'a T::CrossAccountId, -) -> PropertyWriter< - 'a, - T, - Handle, - ExistingTokenPropertyWriter, - impl FnOnce() -> bool + 'a, - impl FnOnce() -> PropertiesPermissionMap + 'a, - impl Copy + FnOnce(TokenId) -> bool + 'a, - impl Copy + FnOnce(TokenId) -> TokenProperties + 'a, -> +/// A marker structure that enables the writer implementation +/// to benchmark the token properties writing. +#[cfg(feature = "runtime-benchmarks")] +pub struct BenchmarkPropertyWriter(PhantomData); + +#[cfg(feature = "runtime-benchmarks")] +impl BenchmarkPropertyWriter { + /// Creates a [`PropertyWriter`] for benchmarking tokens properties writing. + pub fn new<'a, Handle, FIsAdmin, FPropertyPermissions>( + collection: &Handle, + collection_lazy_info: PropertyWriterLazyCollectionInfo, + ) -> PropertyWriter + where + Handle: CommonCollectionOperations + Deref>, + FIsAdmin: FnOnce() -> bool, + FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, + { + PropertyWriter { + collection, + collection_lazy_info, + _phantom: PhantomData, + } + } + + /// Load the [`PropertyWriterLazyCollectionInfo`] from the storage. + pub fn load_collection_info( + collection_handle: &Handle, + sender: &T::CrossAccountId, + ) -> PropertyWriterLazyCollectionInfo< + impl FnOnce() -> bool, + impl FnOnce() -> PropertiesPermissionMap, + > + where + Handle: Deref>, + { + let is_collection_admin = collection_handle.is_owner_or_admin(sender); + let property_permissions = >::property_permissions(collection_handle.id); + + PropertyWriterLazyCollectionInfo { + is_collection_admin: LazyValue::new(move || is_collection_admin), + property_permissions: LazyValue::new(move || property_permissions), + } + } + + /// Load the [`PropertyWriterLazyTokenInfo`] with token properties from the storage. + pub fn load_token_properties( + collection: &Handle, + token_id: TokenId, + ) -> PropertyWriterLazyTokenInfo< + impl FnOnce() -> bool, + impl FnOnce() -> Result, + impl FnOnce() -> TokenProperties, + > + where + Handle: CommonCollectionOperations, + { + let stored_properties = collection + .get_token_properties_raw(token_id) + .unwrap_or_default(); + + PropertyWriterLazyTokenInfo { + is_token_exist: LazyValue::new(|| true), + is_token_owner: LazyValue::new(|| Ok(true)), + stored_properties: LazyValue::new(move || stored_properties), + } + } +} + +#[cfg(feature = "runtime-benchmarks")] +impl<'a, T, Handle, FIsAdmin, FPropertyPermissions> + PropertyWriter<'a, BenchmarkPropertyWriter, T, Handle, FIsAdmin, FPropertyPermissions> where T: Config, Handle: CommonCollectionOperations + Deref>, + FIsAdmin: FnOnce() -> bool, + FPropertyPermissions: FnOnce() -> PropertiesPermissionMap, { - PropertyWriter { - collection, - is_collection_admin: LazyValue::new(|| collection.is_owner_or_admin(sender)), - property_permissions: LazyValue::new(|| >::property_permissions(collection.id)), - check_token_exist: |token_id| collection.token_exists(token_id), - get_properties: |token_id| { - collection - .get_token_properties_raw(token_id) - .unwrap_or_default() - }, - _phantom: PhantomData, + /// A function to benchmark the writing of token properties. + pub fn write_token_properties( + &mut self, + token_id: TokenId, + properties_updates: impl Iterator, + log: evm_coder::ethereum::Log, + ) -> DispatchResult { + let check_token_exist = || true; + let check_token_owner = || Ok(true); + let get_token_properties = || TokenProperties::new(); + + self.internal_write_token_properties( + token_id, + PropertyWriterLazyTokenInfo::new( + check_token_exist, + check_token_owner, + get_token_properties, + ), + properties_updates.map(|p| (p.key, Some(p.value))), + log, + ) } } -/// Computes the weight delta for newly created tokens with properties. +/// Computes the weight of writing properties to tokens. /// * `properties_nums` - The properties num of each created token. -/// * `init_token_properties` - The function to obtain the weight from a token's properties num. -pub fn init_token_properties_delta Weight>( +/// * `per_token_weight_weight` - The function to obtain the weight +/// of writing properties from a token's properties num. +pub fn write_token_properties_total_weight Weight>( properties_nums: impl Iterator, - init_token_properties: I, + per_token_weight: I, ) -> Weight { - let mut delta = properties_nums + let mut weight = properties_nums .filter_map(|properties_num| { if properties_num > 0 { - Some(init_token_properties(properties_num)) + Some(per_token_weight(properties_num)) } else { None } }) .fold(Weight::zero(), |a, b| a.saturating_add(b)); - // If at least once the `init_token_properties` was called, - // it means at least one newly created token has properties. - // Becuase of that, some common collection data also was loaded and we need to add this weight. - // However, these common data was loaded only once which is guaranteed by the `PropertyWriter`. - if !delta.is_zero() { - delta = delta.saturating_add(>::init_token_properties_common()) + if !weight.is_zero() { + // If we are here, it means the token properties were written at least once. + // Because of that, some common collection data was also loaded; we must add this weight. + // However, this common data was loaded only once, which is guaranteed by the `PropertyWriter`. + + weight = weight.saturating_add(>::property_writer_load_collection_info()); } - delta + weight } #[cfg(any(feature = "tests", test))] --- a/pallets/common/src/weights.rs +++ b/pallets/common/src/weights.rs @@ -3,9 +3,9 @@ //! Autogenerated weights for pallet_common //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-30, STEPS: `50`, REPEAT: `400`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-05, STEPS: `50`, REPEAT: `80`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bench-host`, CPU: `Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz` +//! HOSTNAME: `hearthstone`, CPU: `AMD Ryzen 9 7950X3D 16-Core Processor` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -20,7 +20,7 @@ // * // --template=.maintain/frame-weight-template.hbs // --steps=50 -// --repeat=400 +// --repeat=80 // --heap-pages=4096 // --output=./pallets/common/src/weights.rs @@ -36,7 +36,7 @@ fn set_collection_properties(b: u32, ) -> Weight; fn delete_collection_properties(b: u32, ) -> Weight; fn check_accesslist() -> Weight; - fn init_token_properties_common() -> Weight; + fn property_writer_load_collection_info() -> Weight; } /// Weights for pallet_common using the Substrate node and recommended hardware. @@ -49,10 +49,10 @@ // Proof Size summary in bytes: // Measured: `298` // Estimated: `44457` - // Minimum execution time: 4_987_000 picoseconds. - Weight::from_parts(5_119_000, 44457) - // Standard Error: 7_609 - .saturating_add(Weight::from_parts(5_750_459, 0).saturating_mul(b.into())) + // Minimum execution time: 2_840_000 picoseconds. + Weight::from_parts(1_988_405, 44457) + // Standard Error: 7_834 + .saturating_add(Weight::from_parts(3_053_965, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -63,10 +63,10 @@ // Proof Size summary in bytes: // Measured: `303 + b * (33030 ±0)` // Estimated: `44457` - // Minimum execution time: 4_923_000 picoseconds. - Weight::from_parts(5_074_000, 44457) - // Standard Error: 36_651 - .saturating_add(Weight::from_parts(23_145_677, 0).saturating_mul(b.into())) + // Minimum execution time: 2_770_000 picoseconds. + Weight::from_parts(2_940_000, 44457) + // Standard Error: 30_686 + .saturating_add(Weight::from_parts(9_801_835, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -76,20 +76,20 @@ // Proof Size summary in bytes: // Measured: `373` // Estimated: `3535` - // Minimum execution time: 4_271_000 picoseconds. - Weight::from_parts(4_461_000, 3535) + // Minimum execution time: 2_830_000 picoseconds. + Weight::from_parts(2_950_000, 3535) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Common IsAdmin (r:1 w:0) /// Proof: Common IsAdmin (max_values: None, max_size: Some(70), added: 2545, mode: MaxEncodedLen) /// Storage: Common CollectionPropertyPermissions (r:1 w:0) /// Proof: Common CollectionPropertyPermissions (max_values: None, max_size: Some(16726), added: 19201, mode: MaxEncodedLen) - fn init_token_properties_common() -> Weight { + fn property_writer_load_collection_info() -> Weight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `20191` - // Minimum execution time: 5_889_000 picoseconds. - Weight::from_parts(6_138_000, 20191) + // Minimum execution time: 3_970_000 picoseconds. + Weight::from_parts(4_140_000, 20191) .saturating_add(T::DbWeight::get().reads(2_u64)) } } @@ -103,10 +103,10 @@ // Proof Size summary in bytes: // Measured: `298` // Estimated: `44457` - // Minimum execution time: 4_987_000 picoseconds. - Weight::from_parts(5_119_000, 44457) - // Standard Error: 7_609 - .saturating_add(Weight::from_parts(5_750_459, 0).saturating_mul(b.into())) + // Minimum execution time: 2_840_000 picoseconds. + Weight::from_parts(1_988_405, 44457) + // Standard Error: 7_834 + .saturating_add(Weight::from_parts(3_053_965, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -117,10 +117,10 @@ // Proof Size summary in bytes: // Measured: `303 + b * (33030 ±0)` // Estimated: `44457` - // Minimum execution time: 4_923_000 picoseconds. - Weight::from_parts(5_074_000, 44457) - // Standard Error: 36_651 - .saturating_add(Weight::from_parts(23_145_677, 0).saturating_mul(b.into())) + // Minimum execution time: 2_770_000 picoseconds. + Weight::from_parts(2_940_000, 44457) + // Standard Error: 30_686 + .saturating_add(Weight::from_parts(9_801_835, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -130,20 +130,20 @@ // Proof Size summary in bytes: // Measured: `373` // Estimated: `3535` - // Minimum execution time: 4_271_000 picoseconds. - Weight::from_parts(4_461_000, 3535) + // Minimum execution time: 2_830_000 picoseconds. + Weight::from_parts(2_950_000, 3535) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Common IsAdmin (r:1 w:0) /// Proof: Common IsAdmin (max_values: None, max_size: Some(70), added: 2545, mode: MaxEncodedLen) /// Storage: Common CollectionPropertyPermissions (r:1 w:0) /// Proof: Common CollectionPropertyPermissions (max_values: None, max_size: Some(16726), added: 19201, mode: MaxEncodedLen) - fn init_token_properties_common() -> Weight { + fn property_writer_load_collection_info() -> Weight { // Proof Size summary in bytes: // Measured: `326` // Estimated: `20191` - // Minimum execution time: 5_889_000 picoseconds. - Weight::from_parts(6_138_000, 20191) + // Minimum execution time: 3_970_000 picoseconds. + Weight::from_parts(4_140_000, 20191) .saturating_add(RocksDbWeight::get().reads(2_u64)) } } --- a/pallets/evm-coder-substrate/src/lib.rs +++ b/pallets/evm-coder-substrate/src/lib.rs @@ -84,7 +84,7 @@ } impl budget::Budget for GasCallsBudget<'_, T> { fn consume_custom(&self, calls: u32) -> bool { - let (gas, overflown) = (calls as u64).overflowing_add(self.gas_per_call); + let (gas, overflown) = (calls as u64).overflowing_mul(self.gas_per_call); if overflown { return false; } --- a/pallets/foreign-assets/src/impl_fungibles.rs +++ b/pallets/foreign-assets/src/impl_fungibles.rs @@ -23,7 +23,7 @@ use pallet_common::{CollectionHandle, CommonCollectionOperations}; use pallet_fungible::FungibleHandle; use sp_runtime::traits::{CheckedAdd, CheckedSub}; -use up_data_structs::budget::Value; +use up_data_structs::budget; use super::*; @@ -327,7 +327,7 @@ &collection, &account, amount_data, - &Value::new(0), + &budget::Value::new(0), )?; Ok(amount) @@ -440,7 +440,7 @@ &T::CrossAccountId::from_sub(source.clone()), &T::CrossAccountId::from_sub(dest.clone()), amount.into(), - &Value::new(0), + &budget::Value::new(0), ) .map_err(|e| e.error)?; --- a/pallets/fungible/src/common.rs +++ b/pallets/fungible/src/common.rs @@ -16,14 +16,11 @@ use core::marker::PhantomData; -use frame_support::{ - dispatch::DispatchResultWithPostInfo, ensure, fail, traits::Get, weights::Weight, -}; +use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight}; use pallet_common::{ weights::WeightInfo as _, with_weight, CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, SelfWeightOf as PalletCommonWeightOf, }; -use pallet_structure::Error as StructureError; use sp_runtime::{ArithmeticError, DispatchError}; use sp_std::{vec, vec::Vec}; use up_data_structs::{ @@ -58,18 +55,9 @@ fn set_collection_properties(amount: u32) -> Weight { >::set_collection_properties(amount) - } - - fn delete_collection_properties(amount: u32) -> Weight { - >::delete_collection_properties(amount) } fn set_token_properties(_amount: u32) -> Weight { - // Error - Weight::zero() - } - - fn delete_token_properties(_amount: u32) -> Weight { // Error Weight::zero() } @@ -80,7 +68,8 @@ } fn transfer() -> Weight { - >::transfer_raw() + >::check_accesslist() * 2 + >::transfer_raw() + .saturating_add(>::check_accesslist().saturating_mul(2)) } fn approve() -> Weight { @@ -93,28 +82,14 @@ fn transfer_from() -> Weight { Self::transfer() - + >::check_allowed_raw() - + >::set_allowance_unchecked_raw() + .saturating_add(>::check_allowed_raw()) + .saturating_add(>::set_allowance_unchecked_raw()) } fn burn_from() -> Weight { >::burn_from() } - fn burn_recursively_self_raw() -> Weight { - // Read to get total balance - Self::burn_item() + T::DbWeight::get().reads(1) - } - - fn burn_recursively_breadth_raw(_amount: u32) -> Weight { - // Fungible tokens can't have children - Weight::zero() - } - - fn token_owner() -> Weight { - Weight::zero() - } - fn set_allowance_for_all() -> Weight { Weight::zero() } @@ -200,26 +175,6 @@ with_weight( >::burn(self, &sender, amount), >::burn_item(), - ) - } - - fn burn_item_recursively( - &self, - sender: T::CrossAccountId, - token: TokenId, - self_budget: &dyn Budget, - _breadth_budget: &dyn Budget, - ) -> DispatchResultWithPostInfo { - // Should not happen? - ensure!( - token == TokenId::default(), - >::FungibleItemsHaveNoId - ); - ensure!(self_budget.consume(), >::DepthLimit,); - - with_weight( - >::burn(self, &sender, >::get((self.id, &sender))), - >::burn_recursively_self_raw(), ) } --- a/pallets/fungible/src/erc.rs +++ b/pallets/fungible/src/erc.rs @@ -32,12 +32,12 @@ use pallet_evm_coder_substrate::{ call, dispatch_to_evm, execution::{PreDispatch, Result}, - frontier_contract, + frontier_contract, SubstrateRecorder, }; use pallet_structure::{weights::WeightInfo as _, SelfWeightOf as StructureWeight}; use sp_core::{Get, U256}; use sp_std::vec::Vec; -use up_data_structs::CollectionMode; +use up_data_structs::{budget::Budget, CollectionMode}; use crate::{ common::CommonWeights, weights::WeightInfo, Allowance, Balance, Config, FungibleHandle, Pallet, @@ -73,6 +73,10 @@ amount: U256, } +fn nesting_budget(recorder: &SubstrateRecorder) -> impl Budget + '_ { + recorder.weight_calls_budget(>::find_parent()) +} + #[solidity_interface(name = ERC20, events(ERC20Events), enum(derive(PreDispatch)), enum_attr(weight), expect_selector = 0x942e8b22)] impl FungibleHandle { fn name(&self) -> Result { @@ -106,11 +110,8 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer(self, &caller, &to, amount, &budget) + >::transfer(self, &caller, &to, amount, &nesting_budget(&self.recorder)) .map_err(|e| dispatch_to_evm::(e.error))?; Ok(true) } @@ -127,12 +128,16 @@ let from = T::CrossAccountId::from_eth(from); let to = T::CrossAccountId::from_eth(to); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer_from(self, &caller, &from, &to, amount, &budget) - .map_err(|e| dispatch_to_evm::(e.error))?; + >::transfer_from( + self, + &caller, + &from, + &to, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(|e| dispatch_to_evm::(e.error))?; Ok(true) } #[weight(>::approve())] @@ -164,10 +169,8 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::create_item(self, &caller, (to, amount), &budget) + + >::create_item(self, &caller, (to, amount), &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -201,10 +204,8 @@ let caller = T::CrossAccountId::from_eth(caller); let to = to.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::create_item(self, &caller, (to, amount), &budget) + + >::create_item(self, &caller, (to, amount), &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -236,12 +237,15 @@ let caller = T::CrossAccountId::from_eth(caller); let from = T::CrossAccountId::from_eth(from); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::burn_from(self, &caller, &from, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::burn_from( + self, + &caller, + &from, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -260,12 +264,15 @@ let caller = T::CrossAccountId::from_eth(caller); let from = from.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::burn_from(self, &caller, &from, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::burn_from( + self, + &caller, + &from, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -274,9 +281,6 @@ #[weight(>::create_multiple_items_ex(amounts.len() as u32))] fn mint_bulk(&mut self, caller: Caller, amounts: Vec) -> Result { let caller = T::CrossAccountId::from_eth(caller); - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let amounts = amounts .into_iter() .map(|AmountForAddress { to, amount }| { @@ -287,7 +291,7 @@ }) .collect::>()?; - >::create_multiple_items(self, &caller, amounts, &budget) + >::create_multiple_items(self, &caller, amounts, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -297,11 +301,9 @@ let caller = T::CrossAccountId::from_eth(caller); let to = to.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer(self, &caller, &to, amount, &budget).map_err(|_| "transfer error")?; + >::transfer(self, &caller, &to, amount, &nesting_budget(&self.recorder)) + .map_err(|_| "transfer error")?; Ok(true) } @@ -317,12 +319,16 @@ let from = from.into_sub_cross_account::()?; let to = to.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer_from(self, &caller, &from, &to, amount, &budget) - .map_err(|e| dispatch_to_evm::(e.error))?; + >::transfer_from( + self, + &caller, + &from, + &to, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(|e| dispatch_to_evm::(e.error))?; Ok(true) } --- a/pallets/nonfungible/src/benchmarking.rs +++ b/pallets/nonfungible/src/benchmarking.rs @@ -262,9 +262,82 @@ { >::burn_from(&collection, &burner, &sender, item, &Unlimited)?; } + } - Ok(()) - } + // set_token_properties { + // let b in 0..MAX_PROPERTIES_PER_ITEM; + // bench_init!{ + // owner: sub; collection: collection(owner); + // owner: cross_from_sub; + // }; + // let perms = (0..b).map(|k| PropertyKeyPermission { + // key: property_key(k as usize), + // permission: PropertyPermission { + // mutable: false, + // collection_admin: true, + // token_owner: true, + // }, + // }).collect::>(); + // >::set_token_property_permissions(&collection, &owner, perms)?; + // let props = (0..b).map(|k| Property { + // key: property_key(k as usize), + // value: property_value(), + // }).collect::>(); + // let item = create_max_item(&collection, &owner, owner.clone())?; + // }: {>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?} + + // load_token_properties { + // bench_init!{ + // owner: sub; collection: collection(owner); + // owner: cross_from_sub; + // }; + + // let item = create_max_item(&collection, &owner, owner.clone())?; + // }: { + // pallet_common::BenchmarkPropertyWriter::::load_token_properties( + // &collection, + // item, + // ) + // } + + // write_token_properties { + // let b in 0..MAX_PROPERTIES_PER_ITEM; + // bench_init!{ + // owner: sub; collection: collection(owner); + // owner: cross_from_sub; + // }; + + // let perms = (0..b).map(|k| PropertyKeyPermission { + // key: property_key(k as usize), + // permission: PropertyPermission { + // mutable: false, + // collection_admin: true, + // token_owner: true, + // }, + // }).collect::>(); + // >::set_token_property_permissions(&collection, &owner, perms)?; + // let props = (0..b).map(|k| Property { + // key: property_key(k as usize), + // value: property_value(), + // }).collect::>(); + // let item = create_max_item(&collection, &owner, owner.clone())?; + + // let lazy_collection_info = pallet_common::BenchmarkPropertyWriter::::load_collection_info( + // &collection, + // &owner, + // ); + // }: { + // let mut property_writer = pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info); + + // property_writer.write_token_properties( + // item, + // props.into_iter(), + // crate::erc::ERC721TokenEvent::TokenChanged { + // token_id: item.into(), + // } + // .to_log(T::ContractAddress::get()), + // )? + // } #[benchmark] fn set_token_property_permissions( --- a/pallets/nonfungible/src/common.rs +++ b/pallets/nonfungible/src/common.rs @@ -18,8 +18,9 @@ use frame_support::{dispatch::DispatchResultWithPostInfo, ensure, fail, weights::Weight}; use pallet_common::{ - init_token_properties_delta, weights::WeightInfo as _, with_weight, CommonCollectionOperations, - CommonWeightInfo, RefungibleExtensions, SelfWeightOf as PalletCommonWeightOf, + weights::WeightInfo as _, with_weight, write_token_properties_total_weight, + CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, + SelfWeightOf as PalletCommonWeightOf, }; use pallet_structure::Pallet as PalletStructure; use sp_runtime::DispatchError; @@ -39,9 +40,9 @@ fn create_multiple_items_ex(data: &CreateItemExData) -> Weight { match data { CreateItemExData::NFT(t) => >::create_multiple_items_ex(t.len() as u32) - .saturating_add(init_token_properties_delta::( + .saturating_add(write_token_properties_total_weight::( t.iter().map(|t| t.properties.len() as u32), - >::init_token_properties, + >::write_token_properties, )), _ => Weight::zero(), } @@ -49,12 +50,12 @@ fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight { >::create_multiple_items(data.len() as u32).saturating_add( - init_token_properties_delta::( + write_token_properties_total_weight::( data.iter().map(|t| match t { up_data_structs::CreateItemData::NFT(n) => n.properties.len() as u32, _ => 0, }), - >::init_token_properties, + >::write_token_properties, ), ) } @@ -67,16 +68,15 @@ >::set_collection_properties(amount) } - fn delete_collection_properties(amount: u32) -> Weight { - >::delete_collection_properties(amount) - } - fn set_token_properties(amount: u32) -> Weight { - >::set_token_properties(amount) + write_token_properties_total_weight::([amount].into_iter(), |amount| { + >::load_token_properties() + .saturating_add(>::write_token_properties(amount)) + }) } fn delete_token_properties(amount: u32) -> Weight { - >::delete_token_properties(amount) + Self::set_token_properties(amount) } fn set_token_property_permissions(amount: u32) -> Weight { @@ -84,7 +84,8 @@ } fn transfer() -> Weight { - >::transfer_raw() + >::check_accesslist() * 2 + >::transfer_raw() + .saturating_add(>::check_accesslist().saturating_mul(2)) } fn approve() -> Weight { @@ -96,24 +97,11 @@ } fn transfer_from() -> Weight { - Self::transfer() + >::check_allowed_raw() + Self::transfer().saturating_add(>::check_allowed_raw()) } fn burn_from() -> Weight { >::burn_from() - } - - fn burn_recursively_self_raw() -> Weight { - >::burn_recursively_self_raw() - } - - fn burn_recursively_breadth_raw(amount: u32) -> Weight { - >::burn_recursively_breadth_plus_self_plus_self_per_each_raw(amount) - .saturating_sub(Self::burn_recursively_self_raw().saturating_mul(amount as u64 + 1)) - } - - fn token_owner() -> Weight { - >::token_owner() } fn set_allowance_for_all() -> Weight { @@ -306,16 +294,6 @@ >::check_token_immediate_ownership(self, token, &sender)?; Ok(().into()) } - } - - fn burn_item_recursively( - &self, - sender: T::CrossAccountId, - token: TokenId, - self_budget: &dyn Budget, - breadth_budget: &dyn Budget, - ) -> DispatchResultWithPostInfo { - >::burn_recursively(self, &sender, token, self_budget, breadth_budget) } fn transfer( --- a/pallets/nonfungible/src/erc.rs +++ b/pallets/nonfungible/src/erc.rs @@ -38,14 +38,14 @@ use pallet_evm_coder_substrate::{ call, dispatch_to_evm, execution::{Error, PreDispatch, Result}, - frontier_contract, + frontier_contract, SubstrateRecorder, }; use pallet_structure::{weights::WeightInfo as _, SelfWeightOf as StructureWeight}; use sp_core::{Get, U256}; use sp_std::{vec, vec::Vec}; use up_data_structs::{ - CollectionId, CollectionPropertiesVec, Property, PropertyKey, PropertyKeyPermission, - PropertyPermission, TokenId, + budget::Budget, CollectionId, CollectionPropertiesVec, Property, PropertyKey, + PropertyKeyPermission, PropertyPermission, TokenId, }; use crate::{ @@ -78,6 +78,10 @@ impl Contract for NonfungibleHandle {...} } +fn nesting_budget(recorder: &SubstrateRecorder) -> impl Budget + '_ { + recorder.weight_calls_budget(>::find_parent()) +} + /// @title A contract that allows to set and delete token properties and change token property permissions. #[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))] impl NonfungibleHandle { @@ -146,7 +150,7 @@ /// @param key Property key. /// @param value Property value. #[solidity(hide)] - #[weight(>::set_token_properties(1))] + #[weight(>::set_token_properties(1))] fn set_property( &mut self, caller: Caller, @@ -161,16 +165,12 @@ .map_err(|_| "key too long")?; let value = value.0.try_into().map_err(|_| "value too long")?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::set_token_property( self, &caller, TokenId(token_id), Property { key, value }, - &nesting_budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::) } @@ -179,7 +179,7 @@ /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param properties settable properties - #[weight(>::set_token_properties(properties.len() as u32))] + #[weight(>::set_token_properties(properties.len() as u32))] fn set_properties( &mut self, caller: Caller, @@ -189,10 +189,6 @@ let caller = T::CrossAccountId::from_eth(caller); let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - let properties = properties .into_iter() .map(eth::Property::try_into) @@ -203,7 +199,7 @@ &caller, TokenId(token_id), properties.into_iter(), - &nesting_budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::) } @@ -213,7 +209,7 @@ /// @param tokenId ID of the token. /// @param key Property key. #[solidity(hide)] - #[weight(>::delete_token_properties(1))] + #[weight(>::delete_token_properties(1))] fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> { let caller = T::CrossAccountId::from_eth(caller); let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; @@ -221,19 +217,21 @@ .try_into() .map_err(|_| "key too long")?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - - >::delete_token_property(self, &caller, TokenId(token_id), key, &nesting_budget) - .map_err(dispatch_to_evm::) + >::delete_token_property( + self, + &caller, + TokenId(token_id), + key, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::) } /// @notice Delete token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param keys Properties key. - #[weight(>::delete_token_properties(keys.len() as u32))] + #[weight(>::delete_token_properties(keys.len() as u32))] fn delete_properties( &mut self, token_id: U256, @@ -247,16 +245,12 @@ .map(|k| Ok(>::from(k).try_into().map_err(|_| "key too long")?)) .collect::>>()?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::delete_token_properties( self, &caller, TokenId(token_id), keys.into_iter(), - &nesting_budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::) } @@ -481,12 +475,16 @@ let from = T::CrossAccountId::from_eth(from); let to = T::CrossAccountId::from_eth(to); let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer_from(self, &caller, &from, &to, token, &budget) - .map_err(|e| dispatch_to_evm::(e.error))?; + >::transfer_from( + self, + &caller, + &from, + &to, + token, + &nesting_budget(&self.recorder), + ) + .map_err(|e| dispatch_to_evm::(e.error))?; Ok(()) } @@ -594,9 +592,6 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token_id: u32 = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); if >::get(self.id) .checked_add(1) @@ -613,7 +608,7 @@ properties: BoundedVec::default(), owner: to, }, - &budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::)?; @@ -664,9 +659,6 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); if >::get(self.id) .checked_add(1) @@ -694,7 +686,7 @@ properties, owner: to, }, - &budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::)?; Ok(true) @@ -840,11 +832,8 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer(self, &caller, &to, token, &budget) + >::transfer(self, &caller, &to, token, &nesting_budget(&self.recorder)) .map_err(|e| dispatch_to_evm::(e.error))?; Ok(()) } @@ -864,11 +853,8 @@ let caller = T::CrossAccountId::from_eth(caller); let to = to.into_sub_cross_account::()?; let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer(self, &caller, &to, token, &budget) + >::transfer(self, &caller, &to, token, &nesting_budget(&self.recorder)) .map_err(|e| dispatch_to_evm::(e.error))?; Ok(()) } @@ -891,11 +877,16 @@ let from = from.into_sub_cross_account::()?; let to = to.into_sub_cross_account::()?; let token_id = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - Pallet::::transfer_from(self, &caller, &from, &to, token_id, &budget) - .map_err(|e| dispatch_to_evm::(e.error))?; + + Pallet::::transfer_from( + self, + &caller, + &from, + &to, + token_id, + &nesting_budget(&self.recorder), + ) + .map_err(|e| dispatch_to_evm::(e.error))?; Ok(()) } @@ -911,11 +902,8 @@ let caller = T::CrossAccountId::from_eth(caller); let from = T::CrossAccountId::from_eth(from); let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::burn_from(self, &caller, &from, token, &budget) + >::burn_from(self, &caller, &from, token, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(()) } @@ -936,11 +924,8 @@ let caller = T::CrossAccountId::from_eth(caller); let from = from.into_sub_cross_account::()?; let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::burn_from(self, &caller, &from, token, &budget) + >::burn_from(self, &caller, &from, token, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(()) } @@ -966,9 +951,6 @@ let mut expected_index = >::get(self.id) .checked_add(1) .ok_or("item id overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let total_tokens = token_ids.len(); for id in token_ids.into_iter() { @@ -985,7 +967,7 @@ }) .collect(); - >::create_multiple_items(self, &caller, data, &budget) + >::create_multiple_items(self, &caller, data, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -995,9 +977,6 @@ #[weight(>::create_multiple_items(data.len() as u32) + >::set_token_properties(data.len() as u32))] fn mint_bulk_cross(&mut self, caller: Caller, data: Vec) -> Result { let caller = T::CrossAccountId::from_eth(caller); - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let mut create_nft_data = Vec::with_capacity(data.len()); for MintTokenData { owner, properties } in data { @@ -1013,8 +992,13 @@ }); } - >::create_multiple_items(self, &caller, create_nft_data, &budget) - .map_err(dispatch_to_evm::)?; + >::create_multiple_items( + self, + &caller, + create_nft_data, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -1037,9 +1021,6 @@ let mut expected_index = >::get(self.id) .checked_add(1) .ok_or("item id overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let mut data = Vec::with_capacity(tokens.len()); for TokenUri { id, uri } in tokens { @@ -1066,7 +1047,7 @@ }); } - >::create_multiple_items(self, &caller, data, &budget) + >::create_multiple_items(self, &caller, data, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -1096,10 +1077,6 @@ .map_err(|_| Error::Revert("too many properties".to_string()))?; let caller = T::CrossAccountId::from_eth(caller); - - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); >::create_item( self, @@ -1108,7 +1085,7 @@ properties, owner: to, }, - &budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::)?; --- a/pallets/nonfungible/src/lib.rs +++ b/pallets/nonfungible/src/lib.rs @@ -109,7 +109,7 @@ }; use pallet_evm::{account::CrossAccountId, Pallet as PalletEvm}; use pallet_evm_coder_substrate::{SubstrateRecorder, WithRecorder}; -use pallet_structure::{Error as StructureError, Pallet as PalletStructure}; +use pallet_structure::Pallet as PalletStructure; use parity_scale_codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; use sp_core::{Get, H160}; @@ -502,52 +502,7 @@ )); Ok(()) } - - /// Same as [`burn`] but burns all the tokens that are nested in the token first - /// - /// - `self_budget`: Limit for searching children in depth. - /// - `breadth_budget`: Limit of breadth of searching children. - /// - /// [`burn`]: struct.Pallet.html#method.burn - #[transactional] - pub fn burn_recursively( - collection: &NonfungibleHandle, - sender: &T::CrossAccountId, - token: TokenId, - self_budget: &dyn Budget, - breadth_budget: &dyn Budget, - ) -> DispatchResultWithPostInfo { - ensure!(self_budget.consume(), >::DepthLimit,); - let current_token_account = - T::CrossTokenAddressMapping::token_to_address(collection.id, token); - - let mut weight = Weight::zero(); - - // This method is transactional, if user in fact doesn't have permissions to remove token - - // tokens removed here will be restored after rejected transaction - for ((collection, token), _) in >::iter_prefix((collection.id, token)) { - ensure!(breadth_budget.consume(), >::BreadthLimit,); - let PostDispatchInfo { actual_weight, .. } = - >::burn_item_recursively( - current_token_account.clone(), - collection, - token, - self_budget, - breadth_budget, - )?; - if let Some(actual_weight) = actual_weight { - weight = weight.saturating_add(actual_weight); - } - } - - Self::burn(collection, sender, token)?; - DispatchResultWithPostInfo::Ok(PostDispatchInfo { - actual_weight: Some(weight + >::burn_item()), - pays_fee: Pays::Yes, - }) - } - /// A batch operation to add, edit or remove properties for a token. /// /// - `nesting_budget`: Limit for searching parents in-depth to check ownership. @@ -568,7 +523,7 @@ nesting_budget: &dyn Budget, ) -> DispatchResult { let mut property_writer = - pallet_common::property_writer_for_existing_token(collection, sender); + pallet_common::ExistingTokenPropertyWriter::new(collection, sender); property_writer.write_token_properties( sender, @@ -915,7 +870,7 @@ // ========= - let mut property_writer = pallet_common::property_writer_for_new_token(collection, sender); + let mut property_writer = pallet_common::NewTokenPropertyWriter::new(collection, sender); with_transaction(|| { for (i, data) in data.iter().enumerate() { --- a/pallets/nonfungible/src/weights.rs +++ b/pallets/nonfungible/src/weights.rs @@ -3,9 +3,9 @@ //! Autogenerated weights for pallet_nonfungible //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-30, STEPS: `50`, REPEAT: `400`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-05, STEPS: `50`, REPEAT: `80`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bench-host`, CPU: `Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz` +//! HOSTNAME: `hearthstone`, CPU: `AMD Ryzen 9 7950X3D 16-Core Processor` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -20,7 +20,7 @@ // * // --template=.maintain/frame-weight-template.hbs // --steps=50 -// --repeat=400 +// --repeat=80 // --heap-pages=4096 // --output=./pallets/nonfungible/src/weights.rs @@ -46,7 +46,8 @@ fn burn_from() -> Weight; fn set_token_property_permissions(b: u32, ) -> Weight; fn set_token_properties(b: u32, ) -> Weight; - fn init_token_properties(b: u32, ) -> Weight; + fn load_token_properties() -> Weight; + fn write_token_properties(b: u32, ) -> Weight; fn delete_token_properties(b: u32, ) -> Weight; fn token_owner() -> Weight; fn set_allowance_for_all() -> Weight; @@ -69,8 +70,8 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3530` - // Minimum execution time: 9_726_000 picoseconds. - Weight::from_parts(10_059_000, 3530) + // Minimum execution time: 4_990_000 picoseconds. + Weight::from_parts(5_170_000, 3530) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -87,10 +88,10 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3530` - // Minimum execution time: 3_270_000 picoseconds. - Weight::from_parts(3_693_659, 3530) - // Standard Error: 255 - .saturating_add(Weight::from_parts(3_024_284, 0).saturating_mul(b.into())) + // Minimum execution time: 1_680_000 picoseconds. + Weight::from_parts(1_720_000, 3530) + // Standard Error: 674 + .saturating_add(Weight::from_parts(2_406_591, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((2_u64).saturating_mul(b.into()))) @@ -108,10 +109,10 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3481 + b * (2540 ±0)` - // Minimum execution time: 3_188_000 picoseconds. - Weight::from_parts(3_307_000, 3481) - // Standard Error: 567 - .saturating_add(Weight::from_parts(4_320_449, 0).saturating_mul(b.into())) + // Minimum execution time: 1_680_000 picoseconds. + Weight::from_parts(1_720_000, 3481) + // Standard Error: 1_729 + .saturating_add(Weight::from_parts(3_418_983, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -136,8 +137,8 @@ // Proof Size summary in bytes: // Measured: `380` // Estimated: `3530` - // Minimum execution time: 18_062_000 picoseconds. - Weight::from_parts(18_433_000, 3530) + // Minimum execution time: 10_700_000 picoseconds. + Weight::from_parts(11_180_000, 3530) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -159,8 +160,8 @@ // Proof Size summary in bytes: // Measured: `380` // Estimated: `3530` - // Minimum execution time: 22_942_000 picoseconds. - Weight::from_parts(23_527_000, 3530) + // Minimum execution time: 13_650_000 picoseconds. + Weight::from_parts(13_910_000, 3530) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -185,10 +186,10 @@ // Proof Size summary in bytes: // Measured: `1500 + b * (58 ±0)` // Estimated: `5874 + b * (5032 ±0)` - // Minimum execution time: 22_709_000 picoseconds. - Weight::from_parts(23_287_000, 5874) - // Standard Error: 89_471 - .saturating_add(Weight::from_parts(63_285_201, 0).saturating_mul(b.into())) + // Minimum execution time: 13_500_000 picoseconds. + Weight::from_parts(13_830_000, 5874) + // Standard Error: 136_447 + .saturating_add(Weight::from_parts(43_149_279, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(7_u64)) .saturating_add(T::DbWeight::get().reads((4_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(6_u64)) @@ -207,8 +208,8 @@ // Proof Size summary in bytes: // Measured: `380` // Estimated: `6070` - // Minimum execution time: 13_652_000 picoseconds. - Weight::from_parts(13_981_000, 6070) + // Minimum execution time: 8_440_000 picoseconds. + Weight::from_parts(8_680_000, 6070) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -220,8 +221,8 @@ // Proof Size summary in bytes: // Measured: `326` // Estimated: `3522` - // Minimum execution time: 7_837_000 picoseconds. - Weight::from_parts(8_113_000, 3522) + // Minimum execution time: 4_580_000 picoseconds. + Weight::from_parts(4_850_000, 3522) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -233,8 +234,8 @@ // Proof Size summary in bytes: // Measured: `313` // Estimated: `3522` - // Minimum execution time: 7_769_000 picoseconds. - Weight::from_parts(7_979_000, 3522) + // Minimum execution time: 4_650_000 picoseconds. + Weight::from_parts(4_890_000, 3522) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -244,8 +245,8 @@ // Proof Size summary in bytes: // Measured: `362` // Estimated: `3522` - // Minimum execution time: 4_194_000 picoseconds. - Weight::from_parts(4_353_000, 3522) + // Minimum execution time: 2_630_000 picoseconds. + Weight::from_parts(2_760_000, 3522) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Nonfungible Allowance (r:1 w:1) @@ -266,8 +267,8 @@ // Proof Size summary in bytes: // Measured: `463` // Estimated: `3530` - // Minimum execution time: 21_978_000 picoseconds. - Weight::from_parts(22_519_000, 3530) + // Minimum execution time: 13_300_000 picoseconds. + Weight::from_parts(13_650_000, 3530) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -278,10 +279,10 @@ // Proof Size summary in bytes: // Measured: `314` // Estimated: `20191` - // Minimum execution time: 1_457_000 picoseconds. - Weight::from_parts(1_563_000, 20191) - // Standard Error: 14_041 - .saturating_add(Weight::from_parts(8_452_415, 0).saturating_mul(b.into())) + // Minimum execution time: 550_000 picoseconds. + Weight::from_parts(600_000, 20191) + // Standard Error: 23_117 + .saturating_add(Weight::from_parts(6_048_092, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -296,24 +297,34 @@ // Proof Size summary in bytes: // Measured: `640 + b * (261 ±0)` // Estimated: `36269` - // Minimum execution time: 963_000 picoseconds. - Weight::from_parts(1_126_511, 36269) - // Standard Error: 9_175 - .saturating_add(Weight::from_parts(5_096_011, 0).saturating_mul(b.into())) + // Minimum execution time: 340_000 picoseconds. + Weight::from_parts(7_359_078, 36269) + // Standard Error: 9_052 + .saturating_add(Weight::from_parts(2_763_267, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: Nonfungible TokenProperties (r:1 w:0) + /// Proof: Nonfungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) + fn load_token_properties() -> Weight { + // Proof Size summary in bytes: + // Measured: `279` + // Estimated: `36269` + // Minimum execution time: 1_610_000 picoseconds. + Weight::from_parts(1_690_000, 36269) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } /// Storage: Nonfungible TokenProperties (r:0 w:1) /// Proof: Nonfungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) /// The range of component `b` is `[0, 64]`. - fn init_token_properties(b: u32, ) -> Weight { + fn write_token_properties(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 194_000 picoseconds. - Weight::from_parts(222_000, 0) - // Standard Error: 7_295 - .saturating_add(Weight::from_parts(4_499_463, 0).saturating_mul(b.into())) + // Minimum execution time: 70_000 picoseconds. + Weight::from_parts(3_262_181, 0) + // Standard Error: 5_240 + .saturating_add(Weight::from_parts(2_426_582, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Common CollectionPropertyPermissions (r:1 w:0) @@ -327,10 +338,10 @@ // Proof Size summary in bytes: // Measured: `699 + b * (33291 ±0)` // Estimated: `36269` - // Minimum execution time: 992_000 picoseconds. - Weight::from_parts(1_043_000, 36269) - // Standard Error: 37_370 - .saturating_add(Weight::from_parts(23_672_870, 0).saturating_mul(b.into())) + // Minimum execution time: 350_000 picoseconds. + Weight::from_parts(370_000, 36269) + // Standard Error: 29_081 + .saturating_add(Weight::from_parts(9_667_268, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -340,8 +351,8 @@ // Proof Size summary in bytes: // Measured: `326` // Estimated: `3522` - // Minimum execution time: 3_743_000 picoseconds. - Weight::from_parts(3_908_000, 3522) + // Minimum execution time: 2_380_000 picoseconds. + Weight::from_parts(2_500_000, 3522) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Nonfungible CollectionAllowance (r:0 w:1) @@ -350,8 +361,8 @@ // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_106_000 picoseconds. - Weight::from_parts(4_293_000, 0) + // Minimum execution time: 2_060_000 picoseconds. + Weight::from_parts(2_150_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Nonfungible CollectionAllowance (r:1 w:0) @@ -360,8 +371,8 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3576` - // Minimum execution time: 2_775_000 picoseconds. - Weight::from_parts(2_923_000, 3576) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(1_730_000, 3576) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Nonfungible TokenProperties (r:1 w:1) @@ -370,8 +381,8 @@ // Proof Size summary in bytes: // Measured: `279` // Estimated: `36269` - // Minimum execution time: 3_033_000 picoseconds. - Weight::from_parts(3_174_000, 36269) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(1_780_000, 36269) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -391,8 +402,8 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3530` - // Minimum execution time: 9_726_000 picoseconds. - Weight::from_parts(10_059_000, 3530) + // Minimum execution time: 4_990_000 picoseconds. + Weight::from_parts(5_170_000, 3530) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -409,10 +420,10 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3530` - // Minimum execution time: 3_270_000 picoseconds. - Weight::from_parts(3_693_659, 3530) - // Standard Error: 255 - .saturating_add(Weight::from_parts(3_024_284, 0).saturating_mul(b.into())) + // Minimum execution time: 1_680_000 picoseconds. + Weight::from_parts(1_720_000, 3530) + // Standard Error: 674 + .saturating_add(Weight::from_parts(2_406_591, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((2_u64).saturating_mul(b.into()))) @@ -430,10 +441,10 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3481 + b * (2540 ±0)` - // Minimum execution time: 3_188_000 picoseconds. - Weight::from_parts(3_307_000, 3481) - // Standard Error: 567 - .saturating_add(Weight::from_parts(4_320_449, 0).saturating_mul(b.into())) + // Minimum execution time: 1_680_000 picoseconds. + Weight::from_parts(1_720_000, 3481) + // Standard Error: 1_729 + .saturating_add(Weight::from_parts(3_418_983, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -458,8 +469,8 @@ // Proof Size summary in bytes: // Measured: `380` // Estimated: `3530` - // Minimum execution time: 18_062_000 picoseconds. - Weight::from_parts(18_433_000, 3530) + // Minimum execution time: 10_700_000 picoseconds. + Weight::from_parts(11_180_000, 3530) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -481,8 +492,8 @@ // Proof Size summary in bytes: // Measured: `380` // Estimated: `3530` - // Minimum execution time: 22_942_000 picoseconds. - Weight::from_parts(23_527_000, 3530) + // Minimum execution time: 13_650_000 picoseconds. + Weight::from_parts(13_910_000, 3530) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -507,10 +518,10 @@ // Proof Size summary in bytes: // Measured: `1500 + b * (58 ±0)` // Estimated: `5874 + b * (5032 ±0)` - // Minimum execution time: 22_709_000 picoseconds. - Weight::from_parts(23_287_000, 5874) - // Standard Error: 89_471 - .saturating_add(Weight::from_parts(63_285_201, 0).saturating_mul(b.into())) + // Minimum execution time: 13_500_000 picoseconds. + Weight::from_parts(13_830_000, 5874) + // Standard Error: 136_447 + .saturating_add(Weight::from_parts(43_149_279, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(7_u64)) .saturating_add(RocksDbWeight::get().reads((4_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(6_u64)) @@ -529,8 +540,8 @@ // Proof Size summary in bytes: // Measured: `380` // Estimated: `6070` - // Minimum execution time: 13_652_000 picoseconds. - Weight::from_parts(13_981_000, 6070) + // Minimum execution time: 8_440_000 picoseconds. + Weight::from_parts(8_680_000, 6070) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -542,8 +553,8 @@ // Proof Size summary in bytes: // Measured: `326` // Estimated: `3522` - // Minimum execution time: 7_837_000 picoseconds. - Weight::from_parts(8_113_000, 3522) + // Minimum execution time: 4_580_000 picoseconds. + Weight::from_parts(4_850_000, 3522) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -555,8 +566,8 @@ // Proof Size summary in bytes: // Measured: `313` // Estimated: `3522` - // Minimum execution time: 7_769_000 picoseconds. - Weight::from_parts(7_979_000, 3522) + // Minimum execution time: 4_650_000 picoseconds. + Weight::from_parts(4_890_000, 3522) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -566,8 +577,8 @@ // Proof Size summary in bytes: // Measured: `362` // Estimated: `3522` - // Minimum execution time: 4_194_000 picoseconds. - Weight::from_parts(4_353_000, 3522) + // Minimum execution time: 2_630_000 picoseconds. + Weight::from_parts(2_760_000, 3522) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Nonfungible Allowance (r:1 w:1) @@ -588,8 +599,8 @@ // Proof Size summary in bytes: // Measured: `463` // Estimated: `3530` - // Minimum execution time: 21_978_000 picoseconds. - Weight::from_parts(22_519_000, 3530) + // Minimum execution time: 13_300_000 picoseconds. + Weight::from_parts(13_650_000, 3530) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -600,10 +611,10 @@ // Proof Size summary in bytes: // Measured: `314` // Estimated: `20191` - // Minimum execution time: 1_457_000 picoseconds. - Weight::from_parts(1_563_000, 20191) - // Standard Error: 14_041 - .saturating_add(Weight::from_parts(8_452_415, 0).saturating_mul(b.into())) + // Minimum execution time: 550_000 picoseconds. + Weight::from_parts(600_000, 20191) + // Standard Error: 23_117 + .saturating_add(Weight::from_parts(6_048_092, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -618,24 +629,34 @@ // Proof Size summary in bytes: // Measured: `640 + b * (261 ±0)` // Estimated: `36269` - // Minimum execution time: 963_000 picoseconds. - Weight::from_parts(1_126_511, 36269) - // Standard Error: 9_175 - .saturating_add(Weight::from_parts(5_096_011, 0).saturating_mul(b.into())) + // Minimum execution time: 340_000 picoseconds. + Weight::from_parts(7_359_078, 36269) + // Standard Error: 9_052 + .saturating_add(Weight::from_parts(2_763_267, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: Nonfungible TokenProperties (r:1 w:0) + /// Proof: Nonfungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) + fn load_token_properties() -> Weight { + // Proof Size summary in bytes: + // Measured: `279` + // Estimated: `36269` + // Minimum execution time: 1_610_000 picoseconds. + Weight::from_parts(1_690_000, 36269) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } /// Storage: Nonfungible TokenProperties (r:0 w:1) /// Proof: Nonfungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) /// The range of component `b` is `[0, 64]`. - fn init_token_properties(b: u32, ) -> Weight { + fn write_token_properties(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 194_000 picoseconds. - Weight::from_parts(222_000, 0) - // Standard Error: 7_295 - .saturating_add(Weight::from_parts(4_499_463, 0).saturating_mul(b.into())) + // Minimum execution time: 70_000 picoseconds. + Weight::from_parts(3_262_181, 0) + // Standard Error: 5_240 + .saturating_add(Weight::from_parts(2_426_582, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Common CollectionPropertyPermissions (r:1 w:0) @@ -649,10 +670,10 @@ // Proof Size summary in bytes: // Measured: `699 + b * (33291 ±0)` // Estimated: `36269` - // Minimum execution time: 992_000 picoseconds. - Weight::from_parts(1_043_000, 36269) - // Standard Error: 37_370 - .saturating_add(Weight::from_parts(23_672_870, 0).saturating_mul(b.into())) + // Minimum execution time: 350_000 picoseconds. + Weight::from_parts(370_000, 36269) + // Standard Error: 29_081 + .saturating_add(Weight::from_parts(9_667_268, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -662,8 +683,8 @@ // Proof Size summary in bytes: // Measured: `326` // Estimated: `3522` - // Minimum execution time: 3_743_000 picoseconds. - Weight::from_parts(3_908_000, 3522) + // Minimum execution time: 2_380_000 picoseconds. + Weight::from_parts(2_500_000, 3522) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Nonfungible CollectionAllowance (r:0 w:1) @@ -672,8 +693,8 @@ // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_106_000 picoseconds. - Weight::from_parts(4_293_000, 0) + // Minimum execution time: 2_060_000 picoseconds. + Weight::from_parts(2_150_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Nonfungible CollectionAllowance (r:1 w:0) @@ -682,8 +703,8 @@ // Proof Size summary in bytes: // Measured: `142` // Estimated: `3576` - // Minimum execution time: 2_775_000 picoseconds. - Weight::from_parts(2_923_000, 3576) + // Minimum execution time: 1_630_000 picoseconds. + Weight::from_parts(1_730_000, 3576) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Nonfungible TokenProperties (r:1 w:1) @@ -692,8 +713,8 @@ // Proof Size summary in bytes: // Measured: `279` // Estimated: `36269` - // Minimum execution time: 3_033_000 picoseconds. - Weight::from_parts(3_174_000, 36269) + // Minimum execution time: 1_700_000 picoseconds. + Weight::from_parts(1_780_000, 36269) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } --- a/pallets/refungible/src/benchmarking.rs +++ b/pallets/refungible/src/benchmarking.rs @@ -19,10 +19,7 @@ use frame_benchmarking::v2::*; use pallet_common::{ bench_init, - benchmarking::{ - create_collection_raw, /*load_is_admin_and_property_permissions,*/ property_key, - property_value, - }, + benchmarking::{create_collection_raw, property_key, property_value}, }; use sp_std::prelude::*; use up_data_structs::{ @@ -424,6 +421,81 @@ Ok(()) } + // set_token_properties { + // let b in 0..MAX_PROPERTIES_PER_ITEM; + // bench_init!{ + // owner: sub; collection: collection(owner); + // owner: cross_from_sub; + // }; + // let perms = (0..b).map(|k| PropertyKeyPermission { + // key: property_key(k as usize), + // permission: PropertyPermission { + // mutable: false, + // collection_admin: true, + // token_owner: true, + // }, + // }).collect::>(); + // >::set_token_property_permissions(&collection, &owner, perms)?; + // let props = (0..b).map(|k| Property { + // key: property_key(k as usize), + // value: property_value(), + // }).collect::>(); + // let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?; + // }: {>::set_token_properties(&collection, &owner, item, props.into_iter(), &Unlimited)?} + + // load_token_properties { + // bench_init!{ + // owner: sub; collection: collection(owner); + // owner: cross_from_sub; + // }; + + // let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?; + // }: { + // pallet_common::BenchmarkPropertyWriter::::load_token_properties( + // &collection, + // item, + // ) + // } + + // write_token_properties { + // let b in 0..MAX_PROPERTIES_PER_ITEM; + // bench_init!{ + // owner: sub; collection: collection(owner); + // owner: cross_from_sub; + // }; + + // let perms = (0..b).map(|k| PropertyKeyPermission { + // key: property_key(k as usize), + // permission: PropertyPermission { + // mutable: false, + // collection_admin: true, + // token_owner: true, + // }, + // }).collect::>(); + // >::set_token_property_permissions(&collection, &owner, perms)?; + // let props = (0..b).map(|k| Property { + // key: property_key(k as usize), + // value: property_value(), + // }).collect::>(); + // let item = create_max_item(&collection, &owner, [(owner.clone(), 200)])?; + + // let lazy_collection_info = pallet_common::BenchmarkPropertyWriter::::load_collection_info( + // &collection, + // &owner, + // ); + // }: { + // let mut property_writer = pallet_common::BenchmarkPropertyWriter::new(&collection, lazy_collection_info); + + // property_writer.write_token_properties( + // item, + // props.into_iter(), + // crate::erc::ERC721TokenEvent::TokenChanged { + // token_id: item.into(), + // } + // .to_log(T::ContractAddress::get()), + // )? + // } + #[benchmark] fn set_token_property_permissions( b: Linear<0, MAX_PROPERTIES_PER_ITEM>, --- a/pallets/refungible/src/common.rs +++ b/pallets/refungible/src/common.rs @@ -16,14 +16,12 @@ use core::marker::PhantomData; -use frame_support::{ - dispatch::DispatchResultWithPostInfo, ensure, fail, traits::Get, weights::Weight, -}; +use frame_support::{dispatch::DispatchResultWithPostInfo, fail, weights::Weight}; use pallet_common::{ - init_token_properties_delta, weights::WeightInfo as _, with_weight, CommonCollectionOperations, - CommonWeightInfo, RefungibleExtensions, + weights::WeightInfo as _, with_weight, write_token_properties_total_weight, + CommonCollectionOperations, CommonWeightInfo, RefungibleExtensions, }; -use pallet_structure::{Error as StructureError, Pallet as PalletStructure}; +use pallet_structure::Pallet as PalletStructure; use sp_runtime::DispatchError; use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; use up_data_structs::{ @@ -50,14 +48,14 @@ impl CommonWeightInfo for CommonWeights { fn create_multiple_items(data: &[up_data_structs::CreateItemData]) -> Weight { >::create_multiple_items(data.len() as u32).saturating_add( - init_token_properties_delta::( + write_token_properties_total_weight::( data.iter().map(|data| match data { up_data_structs::CreateItemData::ReFungible(rft_data) => { rft_data.properties.len() as u32 } _ => 0, }), - >::init_token_properties, + >::write_token_properties, ), ) } @@ -66,16 +64,16 @@ match call { CreateItemExData::RefungibleMultipleOwners(i) => { >::create_multiple_items_ex_multiple_owners(i.users.len() as u32) - .saturating_add(init_token_properties_delta::( + .saturating_add(write_token_properties_total_weight::( [i.properties.len() as u32].into_iter(), - >::init_token_properties, + >::write_token_properties, )) } CreateItemExData::RefungibleMultipleItems(i) => { >::create_multiple_items_ex_multiple_items(i.len() as u32) - .saturating_add(init_token_properties_delta::( + .saturating_add(write_token_properties_total_weight::( i.iter().map(|d| d.properties.len() as u32), - >::init_token_properties, + >::write_token_properties, )) } _ => Weight::zero(), @@ -88,18 +86,13 @@ fn set_collection_properties(amount: u32) -> Weight { >::set_collection_properties(amount) - } - - fn delete_collection_properties(amount: u32) -> Weight { - >::delete_collection_properties(amount) } fn set_token_properties(amount: u32) -> Weight { - >::set_token_properties(amount) - } - - fn delete_token_properties(amount: u32) -> Weight { - >::delete_token_properties(amount) + write_token_properties_total_weight::([amount].into_iter(), |amount| { + >::load_token_properties() + + >::write_token_properties(amount) + }) } fn set_token_property_permissions(amount: u32) -> Weight { @@ -136,19 +129,6 @@ >::burn_from() } - fn burn_recursively_self_raw() -> Weight { - // Read to get total balance - Self::burn_item() + T::DbWeight::get().reads(1) - } - fn burn_recursively_breadth_raw(_amount: u32) -> Weight { - // Refungible token can't have children - Weight::zero() - } - - fn token_owner() -> Weight { - >::token_owner() - } - fn set_allowance_for_all() -> Weight { >::set_allowance_for_all() } @@ -262,25 +242,6 @@ with_weight( >::burn(self, &sender, token, amount), >::burn_item(), - ) - } - - fn burn_item_recursively( - &self, - sender: T::CrossAccountId, - token: TokenId, - self_budget: &dyn Budget, - _breadth_budget: &dyn Budget, - ) -> DispatchResultWithPostInfo { - ensure!(self_budget.consume(), >::DepthLimit,); - with_weight( - >::burn( - self, - &sender, - token, - >::get((self.id, token, &sender)), - ), - >::burn_recursively_self_raw(), ) } --- a/pallets/refungible/src/erc.rs +++ b/pallets/refungible/src/erc.rs @@ -32,26 +32,26 @@ use pallet_common::{ erc::{static_property::key, CollectionCall, CommonEvmHandler}, eth::{self, TokenUri}, - CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations, + CollectionHandle, CollectionPropertyPermissions, CommonCollectionOperations, CommonWeightInfo, Error as CommonError, }; use pallet_evm::{account::CrossAccountId, PrecompileHandle}; use pallet_evm_coder_substrate::{ call, dispatch_to_evm, execution::{Error, PreDispatch, Result}, - frontier_contract, + frontier_contract, SubstrateRecorder, }; use pallet_structure::{weights::WeightInfo as _, SelfWeightOf as StructureWeight}; use sp_core::{Get, H160, U256}; use sp_std::{collections::btree_map::BTreeMap, vec, vec::Vec}; use up_data_structs::{ - mapping::TokenAddressMapping, CollectionId, CollectionPropertiesVec, Property, PropertyKey, - PropertyKeyPermission, PropertyPermission, TokenId, TokenOwnerError, + budget::Budget, mapping::TokenAddressMapping, CollectionId, CollectionPropertiesVec, Property, + PropertyKey, PropertyKeyPermission, PropertyPermission, TokenId, TokenOwnerError, }; use crate::{ - weights::WeightInfo, AccountBalance, Balance, Config, CreateItemData, Pallet, RefungibleHandle, - SelfWeightOf, TokenProperties, TokensMinted, TotalSupply, + common::CommonWeights, weights::WeightInfo, AccountBalance, Balance, Config, CreateItemData, + Pallet, RefungibleHandle, SelfWeightOf, TokenProperties, TokensMinted, TotalSupply, }; frontier_contract! { @@ -90,6 +90,10 @@ pub properties: Vec, } +pub fn nesting_budget(recorder: &SubstrateRecorder) -> impl Budget + '_ { + recorder.weight_calls_budget(>::find_parent()) +} + /// @title A contract that allows to set and delete token properties and change token property permissions. #[solidity_interface(name = TokenProperties, events(ERC721TokenEvent), enum(derive(PreDispatch)), enum_attr(weight))] impl RefungibleHandle { @@ -158,7 +162,7 @@ /// @param key Property key. /// @param value Property value. #[solidity(hide)] - #[weight(>::set_token_properties(1))] + #[weight(>::set_token_properties(1))] fn set_property( &mut self, caller: Caller, @@ -173,16 +177,12 @@ .map_err(|_| "key too long")?; let value = value.0.try_into().map_err(|_| "value too long")?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::set_token_property( self, &caller, TokenId(token_id), Property { key, value }, - &nesting_budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::) } @@ -191,7 +191,7 @@ /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param properties settable properties - #[weight(>::set_token_properties(properties.len() as u32))] + #[weight(>::set_token_properties(properties.len() as u32))] fn set_properties( &mut self, caller: Caller, @@ -201,10 +201,6 @@ let caller = T::CrossAccountId::from_eth(caller); let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - let properties = properties .into_iter() .map(eth::Property::try_into) @@ -215,7 +211,7 @@ &caller, TokenId(token_id), properties.into_iter(), - &nesting_budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::) } @@ -225,7 +221,7 @@ /// @param tokenId ID of the token. /// @param key Property key. #[solidity(hide)] - #[weight(>::delete_token_properties(1))] + #[weight(>::delete_token_properties(1))] fn delete_property(&mut self, token_id: U256, caller: Caller, key: String) -> Result<()> { let caller = T::CrossAccountId::from_eth(caller); let token_id: u32 = token_id.try_into().map_err(|_| "token id overflow")?; @@ -233,19 +229,21 @@ .try_into() .map_err(|_| "key too long")?; - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); - - >::delete_token_property(self, &caller, TokenId(token_id), key, &nesting_budget) - .map_err(dispatch_to_evm::) + >::delete_token_property( + self, + &caller, + TokenId(token_id), + key, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::) } /// @notice Delete token properties value. /// @dev Throws error if `msg.sender` has no permission to edit the property. /// @param tokenId ID of the token. /// @param keys Properties key. - #[weight(>::delete_token_properties(keys.len() as u32))] + #[weight(>::delete_token_properties(keys.len() as u32))] fn delete_properties( &mut self, token_id: U256, @@ -258,17 +256,13 @@ .into_iter() .map(|k| Ok(>::from(k).try_into().map_err(|_| "key too long")?)) .collect::>>()?; - - let nesting_budget = self - .recorder - .weight_calls_budget(>::find_parent()); >::delete_token_properties( self, &caller, TokenId(token_id), keys.into_iter(), - &nesting_budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::) } @@ -497,15 +491,20 @@ let from = T::CrossAccountId::from_eth(from); let to = T::CrossAccountId::from_eth(to); let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let balance = balance(self, token, &from)?; ensure_single_owner(self, token, balance)?; - >::transfer_from(self, &caller, &from, &to, token, balance, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer_from( + self, + &caller, + &from, + &to, + token, + balance, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(()) } @@ -629,9 +628,6 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token_id: u32 = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); if >::get(self.id) .checked_add(1) @@ -653,7 +649,7 @@ users, properties: CollectionPropertiesVec::default(), }, - &budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::)?; @@ -704,9 +700,6 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token_id: u32 = token_id.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); if >::get(self.id) .checked_add(1) @@ -736,7 +729,7 @@ self, &caller, CreateItemData:: { users, properties }, - &budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::)?; Ok(true) @@ -865,15 +858,19 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let balance = balance(self, token, &caller)?; ensure_single_owner(self, token, balance)?; - >::transfer(self, &caller, &to, token, balance, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer( + self, + &caller, + &to, + token, + balance, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(()) } @@ -893,15 +890,19 @@ let caller = T::CrossAccountId::from_eth(caller); let to = to.into_sub_cross_account::()?; let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let balance = balance(self, token, &caller)?; ensure_single_owner(self, token, balance)?; - >::transfer(self, &caller, &to, token, balance, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer( + self, + &caller, + &to, + token, + balance, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(()) } @@ -923,15 +924,20 @@ let from = from.into_sub_cross_account::()?; let to = to.into_sub_cross_account::()?; let token_id = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let balance = balance(self, token_id, &from)?; ensure_single_owner(self, token_id, balance)?; - Pallet::::transfer_from(self, &caller, &from, &to, token_id, balance, &budget) - .map_err(dispatch_to_evm::)?; + Pallet::::transfer_from( + self, + &caller, + &from, + &to, + token_id, + balance, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(()) } @@ -948,15 +954,19 @@ let caller = T::CrossAccountId::from_eth(caller); let from = T::CrossAccountId::from_eth(from); let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let balance = balance(self, token, &from)?; ensure_single_owner(self, token, balance)?; - >::burn_from(self, &caller, &from, token, balance, &budget) - .map_err(dispatch_to_evm::)?; + >::burn_from( + self, + &caller, + &from, + token, + balance, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(()) } @@ -977,15 +987,19 @@ let caller = T::CrossAccountId::from_eth(caller); let from = from.into_sub_cross_account::()?; let token = token_id.try_into()?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let balance = balance(self, token, &from)?; ensure_single_owner(self, token, balance)?; - >::burn_from(self, &caller, &from, token, balance, &budget) - .map_err(dispatch_to_evm::)?; + >::burn_from( + self, + &caller, + &from, + token, + balance, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(()) } @@ -1010,9 +1024,6 @@ let mut expected_index = >::get(self.id) .checked_add(1) .ok_or("item id overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let total_tokens = token_ids.len(); for id in token_ids.into_iter() { @@ -1035,7 +1046,7 @@ .map(|_| create_item_data.clone()) .collect(); - >::create_multiple_items(self, &caller, data, &budget) + >::create_multiple_items(self, &caller, data, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -1053,9 +1064,6 @@ token_properties: Vec, ) -> Result { let caller = T::CrossAccountId::from_eth(caller); - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let has_multiple_tokens = token_properties.len() > 1; let mut create_rft_data = Vec::with_capacity(token_properties.len()); @@ -1084,8 +1092,13 @@ }); } - >::create_multiple_items(self, &caller, create_rft_data, &budget) - .map_err(dispatch_to_evm::)?; + >::create_multiple_items( + self, + &caller, + create_rft_data, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -1108,9 +1121,6 @@ let mut expected_index = >::get(self.id) .checked_add(1) .ok_or("item id overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); let mut data = Vec::with_capacity(tokens.len()); let users: BoundedBTreeMap<_, _, _> = [(to, 1)] @@ -1143,7 +1153,7 @@ data.push(create_item_data); } - >::create_multiple_items(self, &caller, data, &budget) + >::create_multiple_items(self, &caller, data, &nesting_budget(&self.recorder)) .map_err(dispatch_to_evm::)?; Ok(true) } @@ -1174,10 +1184,6 @@ let caller = T::CrossAccountId::from_eth(caller); - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - let users = [(to, 1)] .into_iter() .collect::>() @@ -1187,7 +1193,7 @@ self, &caller, CreateItemData:: { users, properties }, - &budget, + &nesting_budget(&self.recorder), ) .map_err(dispatch_to_evm::)?; --- a/pallets/refungible/src/erc_token.rs +++ b/pallets/refungible/src/erc_token.rs @@ -37,14 +37,13 @@ execution::{PreDispatch, Result}, frontier_contract, WithRecorder, }; -use pallet_structure::{weights::WeightInfo as _, SelfWeightOf as StructureWeight}; use sp_core::U256; use sp_std::vec::Vec; use up_data_structs::TokenId; use crate::{ - common::CommonWeights, weights::WeightInfo, Allowance, Balance, Config, Pallet, - RefungibleHandle, SelfWeightOf, TotalSupply, + common::CommonWeights, erc::nesting_budget, weights::WeightInfo, Allowance, Balance, Config, + Pallet, RefungibleHandle, SelfWeightOf, TotalSupply, }; /// Refungible token handle contains information about token's collection and id @@ -140,12 +139,16 @@ let caller = T::CrossAccountId::from_eth(caller); let to = T::CrossAccountId::from_eth(to); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer(self, &caller, &to, self.1, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer( + self, + &caller, + &to, + self.1, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -165,12 +168,17 @@ let from = T::CrossAccountId::from_eth(from); let to = T::CrossAccountId::from_eth(to); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer_from(self, &caller, &from, &to, self.1, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer_from( + self, + &caller, + &from, + &to, + self.1, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -231,12 +239,16 @@ let caller = T::CrossAccountId::from_eth(caller); let from = T::CrossAccountId::from_eth(from); let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::burn_from(self, &caller, &from, self.1, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::burn_from( + self, + &caller, + &from, + self.1, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -254,12 +266,16 @@ let caller = T::CrossAccountId::from_eth(caller); let from = from.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::burn_from(self, &caller, &from, self.1, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::burn_from( + self, + &caller, + &from, + self.1, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -315,12 +331,16 @@ let caller = T::CrossAccountId::from_eth(caller); let to = to.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer(self, &caller, &to, self.1, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer( + self, + &caller, + &to, + self.1, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } @@ -340,12 +360,17 @@ let from = from.into_sub_cross_account::()?; let to = to.into_sub_cross_account::()?; let amount = amount.try_into().map_err(|_| "amount overflow")?; - let budget = self - .recorder - .weight_calls_budget(>::find_parent()); - >::transfer_from(self, &caller, &from, &to, self.1, amount, &budget) - .map_err(dispatch_to_evm::)?; + >::transfer_from( + self, + &caller, + &from, + &to, + self.1, + amount, + &nesting_budget(&self.recorder), + ) + .map_err(dispatch_to_evm::)?; Ok(true) } } --- a/pallets/refungible/src/lib.rs +++ b/pallets/refungible/src/lib.rs @@ -507,7 +507,7 @@ nesting_budget: &dyn Budget, ) -> DispatchResult { let mut property_writer = - pallet_common::property_writer_for_existing_token(collection, sender); + pallet_common::ExistingTokenPropertyWriter::new(collection, sender); property_writer.write_token_properties( sender, @@ -858,7 +858,7 @@ // ========= - let mut property_writer = pallet_common::property_writer_for_new_token(collection, sender); + let mut property_writer = pallet_common::NewTokenPropertyWriter::new(collection, sender); with_transaction(|| { for (i, data) in data.iter().enumerate() { --- a/pallets/refungible/src/weights.rs +++ b/pallets/refungible/src/weights.rs @@ -3,9 +3,9 @@ //! Autogenerated weights for pallet_refungible //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-30, STEPS: `50`, REPEAT: `400`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-10-05, STEPS: `50`, REPEAT: `80`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `bench-host`, CPU: `Intel(R) Core(TM) i7-8700 CPU @ 3.20GHz` +//! HOSTNAME: `hearthstone`, CPU: `AMD Ryzen 9 7950X3D 16-Core Processor` //! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024 // Executed Command: @@ -20,7 +20,7 @@ // * // --template=.maintain/frame-weight-template.hbs // --steps=50 -// --repeat=400 +// --repeat=80 // --heap-pages=4096 // --output=./pallets/refungible/src/weights.rs @@ -52,7 +52,8 @@ fn burn_from() -> Weight; fn set_token_property_permissions(b: u32, ) -> Weight; fn set_token_properties(b: u32, ) -> Weight; - fn init_token_properties(b: u32, ) -> Weight; + fn load_token_properties() -> Weight; + fn write_token_properties(b: u32, ) -> Weight; fn delete_token_properties(b: u32, ) -> Weight; fn repartition_item() -> Weight; fn token_owner() -> Weight; @@ -78,8 +79,8 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3530` - // Minimum execution time: 11_341_000 picoseconds. - Weight::from_parts(11_741_000, 3530) + // Minimum execution time: 5_710_000 picoseconds. + Weight::from_parts(5_980_000, 3530) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -98,10 +99,10 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3530` - // Minimum execution time: 2_665_000 picoseconds. - Weight::from_parts(2_791_000, 3530) - // Standard Error: 996 - .saturating_add(Weight::from_parts(4_343_736, 0).saturating_mul(b.into())) + // Minimum execution time: 1_300_000 picoseconds. + Weight::from_parts(1_360_000, 3530) + // Standard Error: 2_783 + .saturating_add(Weight::from_parts(3_456_531, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) .saturating_add(T::DbWeight::get().writes((3_u64).saturating_mul(b.into()))) @@ -121,10 +122,10 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3481 + b * (2540 ±0)` - // Minimum execution time: 2_616_000 picoseconds. - Weight::from_parts(2_726_000, 3481) - // Standard Error: 665 - .saturating_add(Weight::from_parts(5_554_066, 0).saturating_mul(b.into())) + // Minimum execution time: 1_290_000 picoseconds. + Weight::from_parts(1_370_000, 3481) + // Standard Error: 3_198 + .saturating_add(Weight::from_parts(4_435_305, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(1_u64)) @@ -146,10 +147,10 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3481 + b * (2540 ±0)` - // Minimum execution time: 3_697_000 picoseconds. - Weight::from_parts(2_136_481, 3481) - // Standard Error: 567 - .saturating_add(Weight::from_parts(4_390_621, 0).saturating_mul(b.into())) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(1_810_000, 3481) + // Standard Error: 1_923 + .saturating_add(Weight::from_parts(3_500_817, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(T::DbWeight::get().writes(2_u64)) @@ -168,8 +169,8 @@ // Proof Size summary in bytes: // Measured: `456` // Estimated: `8682` - // Minimum execution time: 22_859_000 picoseconds. - Weight::from_parts(23_295_000, 8682) + // Minimum execution time: 14_010_000 picoseconds. + Weight::from_parts(16_300_000, 8682) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -189,8 +190,8 @@ // Proof Size summary in bytes: // Measured: `341` // Estimated: `3554` - // Minimum execution time: 21_477_000 picoseconds. - Weight::from_parts(22_037_000, 3554) + // Minimum execution time: 13_700_000 picoseconds. + Weight::from_parts(14_180_000, 3554) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -202,8 +203,8 @@ // Proof Size summary in bytes: // Measured: `365` // Estimated: `6118` - // Minimum execution time: 13_714_000 picoseconds. - Weight::from_parts(14_050_000, 6118) + // Minimum execution time: 8_990_000 picoseconds. + Weight::from_parts(9_400_000, 6118) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -219,8 +220,8 @@ // Proof Size summary in bytes: // Measured: `341` // Estimated: `6118` - // Minimum execution time: 15_879_000 picoseconds. - Weight::from_parts(16_266_000, 6118) + // Minimum execution time: 10_240_000 picoseconds. + Weight::from_parts(10_610_000, 6118) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -236,8 +237,8 @@ // Proof Size summary in bytes: // Measured: `456` // Estimated: `6118` - // Minimum execution time: 18_186_000 picoseconds. - Weight::from_parts(18_682_000, 6118) + // Minimum execution time: 12_040_000 picoseconds. + Weight::from_parts(12_390_000, 6118) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(4_u64)) } @@ -253,8 +254,8 @@ // Proof Size summary in bytes: // Measured: `341` // Estimated: `6118` - // Minimum execution time: 17_943_000 picoseconds. - Weight::from_parts(18_333_000, 6118) + // Minimum execution time: 11_940_000 picoseconds. + Weight::from_parts(12_240_000, 6118) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(6_u64)) } @@ -266,8 +267,8 @@ // Proof Size summary in bytes: // Measured: `223` // Estimated: `3554` - // Minimum execution time: 8_391_000 picoseconds. - Weight::from_parts(8_637_000, 3554) + // Minimum execution time: 5_150_000 picoseconds. + Weight::from_parts(5_440_000, 3554) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -279,8 +280,8 @@ // Proof Size summary in bytes: // Measured: `211` // Estimated: `3554` - // Minimum execution time: 8_519_000 picoseconds. - Weight::from_parts(8_760_000, 3554) + // Minimum execution time: 5_170_000 picoseconds. + Weight::from_parts(5_400_000, 3554) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -294,8 +295,8 @@ // Proof Size summary in bytes: // Measured: `495` // Estimated: `6118` - // Minimum execution time: 19_554_000 picoseconds. - Weight::from_parts(20_031_000, 6118) + // Minimum execution time: 13_150_000 picoseconds. + Weight::from_parts(13_600_000, 6118) .saturating_add(T::DbWeight::get().reads(4_u64)) .saturating_add(T::DbWeight::get().writes(3_u64)) } @@ -313,8 +314,8 @@ // Proof Size summary in bytes: // Measured: `471` // Estimated: `6118` - // Minimum execution time: 21_338_000 picoseconds. - Weight::from_parts(21_803_000, 6118) + // Minimum execution time: 14_280_000 picoseconds. + Weight::from_parts(14_680_000, 6118) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -332,8 +333,8 @@ // Proof Size summary in bytes: // Measured: `586` // Estimated: `6118` - // Minimum execution time: 24_179_000 picoseconds. - Weight::from_parts(24_647_000, 6118) + // Minimum execution time: 16_110_000 picoseconds. + Weight::from_parts(16_710_000, 6118) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(5_u64)) } @@ -351,8 +352,8 @@ // Proof Size summary in bytes: // Measured: `471` // Estimated: `6118` - // Minimum execution time: 24_008_000 picoseconds. - Weight::from_parts(24_545_000, 6118) + // Minimum execution time: 16_130_000 picoseconds. + Weight::from_parts(16_680_000, 6118) .saturating_add(T::DbWeight::get().reads(6_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -374,8 +375,8 @@ // Proof Size summary in bytes: // Measured: `471` // Estimated: `3570` - // Minimum execution time: 27_907_000 picoseconds. - Weight::from_parts(28_489_000, 3570) + // Minimum execution time: 18_380_000 picoseconds. + Weight::from_parts(18_870_000, 3570) .saturating_add(T::DbWeight::get().reads(5_u64)) .saturating_add(T::DbWeight::get().writes(7_u64)) } @@ -386,10 +387,10 @@ // Proof Size summary in bytes: // Measured: `314` // Estimated: `20191` - // Minimum execution time: 1_460_000 picoseconds. - Weight::from_parts(1_564_000, 20191) - // Standard Error: 14_117 - .saturating_add(Weight::from_parts(8_196_214, 0).saturating_mul(b.into())) + // Minimum execution time: 580_000 picoseconds. + Weight::from_parts(660_000, 20191) + // Standard Error: 29_964 + .saturating_add(Weight::from_parts(6_251_766, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -404,24 +405,34 @@ // Proof Size summary in bytes: // Measured: `502 + b * (261 ±0)` // Estimated: `36269` - // Minimum execution time: 1_012_000 picoseconds. - Weight::from_parts(1_081_000, 36269) - // Standard Error: 6_838 - .saturating_add(Weight::from_parts(5_801_181, 0).saturating_mul(b.into())) + // Minimum execution time: 350_000 picoseconds. + Weight::from_parts(2_269_806, 36269) + // Standard Error: 7_751 + .saturating_add(Weight::from_parts(3_068_126, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } + /// Storage: Refungible TokenProperties (r:1 w:0) + /// Proof: Refungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) + fn load_token_properties() -> Weight { + // Proof Size summary in bytes: + // Measured: `120` + // Estimated: `36269` + // Minimum execution time: 1_010_000 picoseconds. + Weight::from_parts(1_080_000, 36269) + .saturating_add(T::DbWeight::get().reads(1_u64)) + } /// Storage: Refungible TokenProperties (r:0 w:1) /// Proof: Refungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) /// The range of component `b` is `[0, 64]`. - fn init_token_properties(b: u32, ) -> Weight { + fn write_token_properties(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 229_000 picoseconds. - Weight::from_parts(253_000, 0) - // Standard Error: 100_218 - .saturating_add(Weight::from_parts(12_632_221, 0).saturating_mul(b.into())) + // Minimum execution time: 70_000 picoseconds. + Weight::from_parts(1_363_449, 0) + // Standard Error: 8_964 + .saturating_add(Weight::from_parts(2_665_759, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Common CollectionPropertyPermissions (r:1 w:0) @@ -435,10 +446,10 @@ // Proof Size summary in bytes: // Measured: `561 + b * (33291 ±0)` // Estimated: `36269` - // Minimum execution time: 1_014_000 picoseconds. - Weight::from_parts(1_065_000, 36269) - // Standard Error: 39_536 - .saturating_add(Weight::from_parts(24_125_838, 0).saturating_mul(b.into())) + // Minimum execution time: 320_000 picoseconds. + Weight::from_parts(370_000, 36269) + // Standard Error: 28_541 + .saturating_add(Weight::from_parts(9_863_065, 0).saturating_mul(b.into())) .saturating_add(T::DbWeight::get().reads(3_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -450,8 +461,8 @@ // Proof Size summary in bytes: // Measured: `288` // Estimated: `3554` - // Minimum execution time: 10_315_000 picoseconds. - Weight::from_parts(10_601_000, 3554) + // Minimum execution time: 6_320_000 picoseconds. + Weight::from_parts(6_640_000, 3554) .saturating_add(T::DbWeight::get().reads(2_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } @@ -461,8 +472,8 @@ // Proof Size summary in bytes: // Measured: `288` // Estimated: `6118` - // Minimum execution time: 4_898_000 picoseconds. - Weight::from_parts(5_136_000, 6118) + // Minimum execution time: 2_520_000 picoseconds. + Weight::from_parts(2_680_000, 6118) .saturating_add(T::DbWeight::get().reads(2_u64)) } /// Storage: Refungible CollectionAllowance (r:0 w:1) @@ -471,8 +482,8 @@ // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_146_000 picoseconds. - Weight::from_parts(4_337_000, 0) + // Minimum execution time: 2_070_000 picoseconds. + Weight::from_parts(2_230_000, 0) .saturating_add(T::DbWeight::get().writes(1_u64)) } /// Storage: Refungible CollectionAllowance (r:1 w:0) @@ -481,8 +492,8 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3576` - // Minimum execution time: 2_170_000 picoseconds. - Weight::from_parts(2_301_000, 3576) + // Minimum execution time: 1_270_000 picoseconds. + Weight::from_parts(1_420_000, 3576) .saturating_add(T::DbWeight::get().reads(1_u64)) } /// Storage: Refungible TokenProperties (r:1 w:1) @@ -491,8 +502,8 @@ // Proof Size summary in bytes: // Measured: `120` // Estimated: `36269` - // Minimum execution time: 2_098_000 picoseconds. - Weight::from_parts(2_251_000, 36269) + // Minimum execution time: 1_010_000 picoseconds. + Weight::from_parts(1_160_000, 36269) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(1_u64)) } @@ -514,8 +525,8 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3530` - // Minimum execution time: 11_341_000 picoseconds. - Weight::from_parts(11_741_000, 3530) + // Minimum execution time: 5_710_000 picoseconds. + Weight::from_parts(5_980_000, 3530) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -534,10 +545,10 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3530` - // Minimum execution time: 2_665_000 picoseconds. - Weight::from_parts(2_791_000, 3530) - // Standard Error: 996 - .saturating_add(Weight::from_parts(4_343_736, 0).saturating_mul(b.into())) + // Minimum execution time: 1_300_000 picoseconds. + Weight::from_parts(1_360_000, 3530) + // Standard Error: 2_783 + .saturating_add(Weight::from_parts(3_456_531, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) .saturating_add(RocksDbWeight::get().writes((3_u64).saturating_mul(b.into()))) @@ -557,10 +568,10 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3481 + b * (2540 ±0)` - // Minimum execution time: 2_616_000 picoseconds. - Weight::from_parts(2_726_000, 3481) - // Standard Error: 665 - .saturating_add(Weight::from_parts(5_554_066, 0).saturating_mul(b.into())) + // Minimum execution time: 1_290_000 picoseconds. + Weight::from_parts(1_370_000, 3481) + // Standard Error: 3_198 + .saturating_add(Weight::from_parts(4_435_305, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(1_u64)) @@ -582,10 +593,10 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3481 + b * (2540 ±0)` - // Minimum execution time: 3_697_000 picoseconds. - Weight::from_parts(2_136_481, 3481) - // Standard Error: 567 - .saturating_add(Weight::from_parts(4_390_621, 0).saturating_mul(b.into())) + // Minimum execution time: 1_730_000 picoseconds. + Weight::from_parts(1_810_000, 3481) + // Standard Error: 1_923 + .saturating_add(Weight::from_parts(3_500_817, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().reads((1_u64).saturating_mul(b.into()))) .saturating_add(RocksDbWeight::get().writes(2_u64)) @@ -604,8 +615,8 @@ // Proof Size summary in bytes: // Measured: `456` // Estimated: `8682` - // Minimum execution time: 22_859_000 picoseconds. - Weight::from_parts(23_295_000, 8682) + // Minimum execution time: 14_010_000 picoseconds. + Weight::from_parts(16_300_000, 8682) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -625,8 +636,8 @@ // Proof Size summary in bytes: // Measured: `341` // Estimated: `3554` - // Minimum execution time: 21_477_000 picoseconds. - Weight::from_parts(22_037_000, 3554) + // Minimum execution time: 13_700_000 picoseconds. + Weight::from_parts(14_180_000, 3554) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -638,8 +649,8 @@ // Proof Size summary in bytes: // Measured: `365` // Estimated: `6118` - // Minimum execution time: 13_714_000 picoseconds. - Weight::from_parts(14_050_000, 6118) + // Minimum execution time: 8_990_000 picoseconds. + Weight::from_parts(9_400_000, 6118) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -655,8 +666,8 @@ // Proof Size summary in bytes: // Measured: `341` // Estimated: `6118` - // Minimum execution time: 15_879_000 picoseconds. - Weight::from_parts(16_266_000, 6118) + // Minimum execution time: 10_240_000 picoseconds. + Weight::from_parts(10_610_000, 6118) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -672,8 +683,8 @@ // Proof Size summary in bytes: // Measured: `456` // Estimated: `6118` - // Minimum execution time: 18_186_000 picoseconds. - Weight::from_parts(18_682_000, 6118) + // Minimum execution time: 12_040_000 picoseconds. + Weight::from_parts(12_390_000, 6118) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(4_u64)) } @@ -689,8 +700,8 @@ // Proof Size summary in bytes: // Measured: `341` // Estimated: `6118` - // Minimum execution time: 17_943_000 picoseconds. - Weight::from_parts(18_333_000, 6118) + // Minimum execution time: 11_940_000 picoseconds. + Weight::from_parts(12_240_000, 6118) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(6_u64)) } @@ -702,8 +713,8 @@ // Proof Size summary in bytes: // Measured: `223` // Estimated: `3554` - // Minimum execution time: 8_391_000 picoseconds. - Weight::from_parts(8_637_000, 3554) + // Minimum execution time: 5_150_000 picoseconds. + Weight::from_parts(5_440_000, 3554) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -715,8 +726,8 @@ // Proof Size summary in bytes: // Measured: `211` // Estimated: `3554` - // Minimum execution time: 8_519_000 picoseconds. - Weight::from_parts(8_760_000, 3554) + // Minimum execution time: 5_170_000 picoseconds. + Weight::from_parts(5_400_000, 3554) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -730,8 +741,8 @@ // Proof Size summary in bytes: // Measured: `495` // Estimated: `6118` - // Minimum execution time: 19_554_000 picoseconds. - Weight::from_parts(20_031_000, 6118) + // Minimum execution time: 13_150_000 picoseconds. + Weight::from_parts(13_600_000, 6118) .saturating_add(RocksDbWeight::get().reads(4_u64)) .saturating_add(RocksDbWeight::get().writes(3_u64)) } @@ -749,8 +760,8 @@ // Proof Size summary in bytes: // Measured: `471` // Estimated: `6118` - // Minimum execution time: 21_338_000 picoseconds. - Weight::from_parts(21_803_000, 6118) + // Minimum execution time: 14_280_000 picoseconds. + Weight::from_parts(14_680_000, 6118) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -768,8 +779,8 @@ // Proof Size summary in bytes: // Measured: `586` // Estimated: `6118` - // Minimum execution time: 24_179_000 picoseconds. - Weight::from_parts(24_647_000, 6118) + // Minimum execution time: 16_110_000 picoseconds. + Weight::from_parts(16_710_000, 6118) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(5_u64)) } @@ -787,8 +798,8 @@ // Proof Size summary in bytes: // Measured: `471` // Estimated: `6118` - // Minimum execution time: 24_008_000 picoseconds. - Weight::from_parts(24_545_000, 6118) + // Minimum execution time: 16_130_000 picoseconds. + Weight::from_parts(16_680_000, 6118) .saturating_add(RocksDbWeight::get().reads(6_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -810,8 +821,8 @@ // Proof Size summary in bytes: // Measured: `471` // Estimated: `3570` - // Minimum execution time: 27_907_000 picoseconds. - Weight::from_parts(28_489_000, 3570) + // Minimum execution time: 18_380_000 picoseconds. + Weight::from_parts(18_870_000, 3570) .saturating_add(RocksDbWeight::get().reads(5_u64)) .saturating_add(RocksDbWeight::get().writes(7_u64)) } @@ -822,10 +833,10 @@ // Proof Size summary in bytes: // Measured: `314` // Estimated: `20191` - // Minimum execution time: 1_460_000 picoseconds. - Weight::from_parts(1_564_000, 20191) - // Standard Error: 14_117 - .saturating_add(Weight::from_parts(8_196_214, 0).saturating_mul(b.into())) + // Minimum execution time: 580_000 picoseconds. + Weight::from_parts(660_000, 20191) + // Standard Error: 29_964 + .saturating_add(Weight::from_parts(6_251_766, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -840,24 +851,34 @@ // Proof Size summary in bytes: // Measured: `502 + b * (261 ±0)` // Estimated: `36269` - // Minimum execution time: 1_012_000 picoseconds. - Weight::from_parts(1_081_000, 36269) - // Standard Error: 6_838 - .saturating_add(Weight::from_parts(5_801_181, 0).saturating_mul(b.into())) + // Minimum execution time: 350_000 picoseconds. + Weight::from_parts(2_269_806, 36269) + // Standard Error: 7_751 + .saturating_add(Weight::from_parts(3_068_126, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } + /// Storage: Refungible TokenProperties (r:1 w:0) + /// Proof: Refungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) + fn load_token_properties() -> Weight { + // Proof Size summary in bytes: + // Measured: `120` + // Estimated: `36269` + // Minimum execution time: 1_010_000 picoseconds. + Weight::from_parts(1_080_000, 36269) + .saturating_add(RocksDbWeight::get().reads(1_u64)) + } /// Storage: Refungible TokenProperties (r:0 w:1) /// Proof: Refungible TokenProperties (max_values: None, max_size: Some(32804), added: 35279, mode: MaxEncodedLen) /// The range of component `b` is `[0, 64]`. - fn init_token_properties(b: u32, ) -> Weight { + fn write_token_properties(b: u32, ) -> Weight { // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 229_000 picoseconds. - Weight::from_parts(253_000, 0) - // Standard Error: 100_218 - .saturating_add(Weight::from_parts(12_632_221, 0).saturating_mul(b.into())) + // Minimum execution time: 70_000 picoseconds. + Weight::from_parts(1_363_449, 0) + // Standard Error: 8_964 + .saturating_add(Weight::from_parts(2_665_759, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Common CollectionPropertyPermissions (r:1 w:0) @@ -871,10 +892,10 @@ // Proof Size summary in bytes: // Measured: `561 + b * (33291 ±0)` // Estimated: `36269` - // Minimum execution time: 1_014_000 picoseconds. - Weight::from_parts(1_065_000, 36269) - // Standard Error: 39_536 - .saturating_add(Weight::from_parts(24_125_838, 0).saturating_mul(b.into())) + // Minimum execution time: 320_000 picoseconds. + Weight::from_parts(370_000, 36269) + // Standard Error: 28_541 + .saturating_add(Weight::from_parts(9_863_065, 0).saturating_mul(b.into())) .saturating_add(RocksDbWeight::get().reads(3_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } @@ -886,8 +907,8 @@ // Proof Size summary in bytes: // Measured: `288` // Estimated: `3554` - // Minimum execution time: 10_315_000 picoseconds. - Weight::from_parts(10_601_000, 3554) + // Minimum execution time: 6_320_000 picoseconds. + Weight::from_parts(6_640_000, 3554) .saturating_add(RocksDbWeight::get().reads(2_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } @@ -897,8 +918,8 @@ // Proof Size summary in bytes: // Measured: `288` // Estimated: `6118` - // Minimum execution time: 4_898_000 picoseconds. - Weight::from_parts(5_136_000, 6118) + // Minimum execution time: 2_520_000 picoseconds. + Weight::from_parts(2_680_000, 6118) .saturating_add(RocksDbWeight::get().reads(2_u64)) } /// Storage: Refungible CollectionAllowance (r:0 w:1) @@ -907,8 +928,8 @@ // Proof Size summary in bytes: // Measured: `0` // Estimated: `0` - // Minimum execution time: 4_146_000 picoseconds. - Weight::from_parts(4_337_000, 0) + // Minimum execution time: 2_070_000 picoseconds. + Weight::from_parts(2_230_000, 0) .saturating_add(RocksDbWeight::get().writes(1_u64)) } /// Storage: Refungible CollectionAllowance (r:1 w:0) @@ -917,8 +938,8 @@ // Proof Size summary in bytes: // Measured: `4` // Estimated: `3576` - // Minimum execution time: 2_170_000 picoseconds. - Weight::from_parts(2_301_000, 3576) + // Minimum execution time: 1_270_000 picoseconds. + Weight::from_parts(1_420_000, 3576) .saturating_add(RocksDbWeight::get().reads(1_u64)) } /// Storage: Refungible TokenProperties (r:1 w:1) @@ -927,8 +948,8 @@ // Proof Size summary in bytes: // Measured: `120` // Estimated: `36269` - // Minimum execution time: 2_098_000 picoseconds. - Weight::from_parts(2_251_000, 36269) + // Minimum execution time: 1_010_000 picoseconds. + Weight::from_parts(1_160_000, 36269) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(1_u64)) } --- a/pallets/structure/src/lib.rs +++ b/pallets/structure/src/lib.rs @@ -53,11 +53,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::{ - dispatch::{DispatchResult, DispatchResultWithPostInfo}, - fail, - pallet_prelude::*, -}; +use frame_support::{dispatch::DispatchResult, fail, pallet_prelude::*}; use pallet_common::{ dispatch::CollectionDispatch, erc::CrossAccountId, eth::is_collection, CommonCollectionOperations, @@ -267,22 +263,6 @@ } Err(>::DepthLimit.into()) - } - - /// Burn token and all of it's nested tokens - /// - /// - `self_budget`: Limit for searching children in depth. - /// - `breadth_budget`: Limit of breadth of searching children. - pub fn burn_item_recursively( - from: T::CrossAccountId, - collection: CollectionId, - token: TokenId, - self_budget: &dyn Budget, - breadth_budget: &dyn Budget, - ) -> DispatchResultWithPostInfo { - let dispatch = T::CollectionDispatch::dispatch(collection)?; - let dispatch = dispatch.as_dyn(); - dispatch.burn_item_recursively(from, token, self_budget, breadth_budget) } /// Check if `token` indirectly owned by `user` --- a/pallets/unique/Cargo.toml +++ b/pallets/unique/Cargo.toml @@ -31,7 +31,9 @@ 'parity-scale-codec/std', 'sp-runtime/std', 'sp-std/std', + 'up-common/std', 'up-data-structs/std', + 'pallet-structure/std', ] stubgen = ["evm-coder/stubgen", "pallet-common/stubgen"] try-runtime = ["frame-support/try-runtime"] @@ -53,9 +55,11 @@ pallet-evm-coder-substrate = { workspace = true } pallet-nonfungible = { workspace = true } pallet-refungible = { workspace = true } +pallet-structure = { workspace = true } scale-info = { workspace = true } sp-core = { workspace = true } sp-io = { workspace = true } sp-runtime = { workspace = true } sp-std = { workspace = true } +up-common = { workspace = true } up-data-structs = { workspace = true } --- a/pallets/unique/src/lib.rs +++ b/pallets/unique/src/lib.rs @@ -84,13 +84,20 @@ #[frame_support::pallet] pub mod pallet { - use frame_support::{dispatch::DispatchResult, ensure, fail, storage::Key, BoundedVec}; + use frame_support::{ + dispatch::{DispatchErrorWithPostInfo, DispatchResult, PostDispatchInfo}, + ensure, fail, + storage::Key, + BoundedVec, + }; use frame_system::{ensure_root, ensure_signed}; use pallet_common::{ dispatch::{dispatch_tx, CollectionDispatch}, - CollectionHandle, CommonWeightInfo, Pallet as PalletCommon, RefungibleExtensionsWeightInfo, + CollectionHandle, CommonCollectionOperations, CommonWeightInfo, Pallet as PalletCommon, + RefungibleExtensionsWeightInfo, }; use pallet_evm::account::CrossAccountId; + use pallet_structure::weights::WeightInfo as StructureWeightInfo; use scale_info::TypeInfo; use sp_std::{vec, vec::Vec}; use up_data_structs::{ @@ -104,9 +111,6 @@ use weights::WeightInfo; use super::*; - - /// A maximum number of levels of depth in the token nesting tree. - pub const NESTING_BUDGET: u32 = 5; /// Errors for the common Unique transactions. #[pallet::error] @@ -128,6 +132,8 @@ /// Weight information for common pallet operations. type CommonWeightInfo: CommonWeightInfo; + type StructureWeightInfo: StructureWeightInfo; + /// Weight info information for extra refungible pallet operations. type RefungibleExtensionsWeightInfo: RefungibleExtensionsWeightInfo; } @@ -264,7 +270,7 @@ impl Pallet { /// A maximum number of levels of depth in the token nesting tree. fn nesting_budget() -> u32 { - NESTING_BUDGET + 5 } /// Maximal length of a collection name. @@ -666,7 +672,7 @@ /// * `owner`: Address of the initial owner of the item. /// * `data`: Token data describing the item to store on chain. #[pallet::call_index(11)] - #[pallet::weight(T::CommonWeightInfo::create_item(data))] + #[pallet::weight(T::CommonWeightInfo::create_item(data) + >::nesting_budget_predispatch_weight())] pub fn create_item( origin: OriginFor, collection_id: CollectionId, @@ -674,9 +680,9 @@ data: CreateItemData, ) -> DispatchResultWithPostInfo { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.create_item(sender, owner, data, &budget) }) } @@ -700,7 +706,7 @@ /// * `owner`: Address of the initial owner of the tokens. /// * `items_data`: Vector of data describing each item to be created. #[pallet::call_index(12)] - #[pallet::weight(T::CommonWeightInfo::create_multiple_items(items_data))] + #[pallet::weight(T::CommonWeightInfo::create_multiple_items(items_data) + >::nesting_budget_predispatch_weight())] pub fn create_multiple_items( origin: OriginFor, collection_id: CollectionId, @@ -709,9 +715,9 @@ ) -> DispatchResultWithPostInfo { ensure!(!items_data.is_empty(), Error::::EmptyArgument); let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.create_multiple_items(sender, owner, items_data, &budget) }) } @@ -791,7 +797,7 @@ /// * `properties`: Vector of key-value pairs stored as the token's metadata. /// Keys support Latin letters, `-`, `_`, and `.` as symbols. #[pallet::call_index(15)] - #[pallet::weight(T::CommonWeightInfo::set_token_properties(properties.len() as u32))] + #[pallet::weight(T::CommonWeightInfo::set_token_properties(properties.len() as u32) + >::nesting_budget_predispatch_weight())] pub fn set_token_properties( origin: OriginFor, collection_id: CollectionId, @@ -801,9 +807,9 @@ ensure!(!properties.is_empty(), Error::::EmptyArgument); let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.set_token_properties(sender, token_id, properties, &budget) }) } @@ -824,7 +830,7 @@ /// * `property_keys`: Vector of keys of the properties to be deleted. /// Keys support Latin letters, `-`, `_`, and `.` as symbols. #[pallet::call_index(16)] - #[pallet::weight(T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32))] + #[pallet::weight(T::CommonWeightInfo::delete_token_properties(property_keys.len() as u32) + >::nesting_budget_predispatch_weight())] pub fn delete_token_properties( origin: OriginFor, collection_id: CollectionId, @@ -834,9 +840,9 @@ ensure!(!property_keys.is_empty(), Error::::EmptyArgument); let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.delete_token_properties(sender, token_id, property_keys, &budget) }) } @@ -888,16 +894,16 @@ /// * `collection_id`: ID of the collection to which the tokens would belong. /// * `data`: Explicit item creation data. #[pallet::call_index(18)] - #[pallet::weight(T::CommonWeightInfo::create_multiple_items_ex(data))] + #[pallet::weight(T::CommonWeightInfo::create_multiple_items_ex(data) + >::nesting_budget_predispatch_weight())] pub fn create_multiple_items_ex( origin: OriginFor, collection_id: CollectionId, data: CreateItemExData, ) -> DispatchResultWithPostInfo { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.create_multiple_items_ex(sender, data, &budget) }) } @@ -995,7 +1001,7 @@ /// * Fungible Mode: The desired number of pieces to burn. /// * Re-Fungible Mode: The desired number of pieces to burn. #[pallet::call_index(21)] - #[pallet::weight(T::CommonWeightInfo::burn_from())] + #[pallet::weight(T::CommonWeightInfo::burn_from() + >::nesting_budget_predispatch_weight())] pub fn burn_from( origin: OriginFor, collection_id: CollectionId, @@ -1004,9 +1010,9 @@ value: u128, ) -> DispatchResultWithPostInfo { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.burn_from(sender, from, item_id, value, &budget) }) } @@ -1033,7 +1039,7 @@ /// * Fungible Mode: The desired number of pieces to transfer. /// * Re-Fungible Mode: The desired number of pieces to transfer. #[pallet::call_index(22)] - #[pallet::weight(T::CommonWeightInfo::transfer())] + #[pallet::weight(T::CommonWeightInfo::transfer() + >::nesting_budget_predispatch_weight())] pub fn transfer( origin: OriginFor, recipient: T::CrossAccountId, @@ -1042,9 +1048,9 @@ value: u128, ) -> DispatchResultWithPostInfo { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.transfer(sender, recipient, item_id, value, &budget) }) } @@ -1138,7 +1144,7 @@ /// * Fungible Mode: The desired number of pieces to transfer. /// * Re-Fungible Mode: The desired number of pieces to transfer. #[pallet::call_index(25)] - #[pallet::weight(T::CommonWeightInfo::transfer_from())] + #[pallet::weight(T::CommonWeightInfo::transfer_from() + >::nesting_budget_predispatch_weight())] pub fn transfer_from( origin: OriginFor, from: T::CrossAccountId, @@ -1148,9 +1154,9 @@ value: u128, ) -> DispatchResultWithPostInfo { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); - let budget = budget::Value::new(NESTING_BUDGET); + let budget = Self::structure_nesting_budget(); - dispatch_tx::(collection_id, |d| { + Self::dispatch_tx_with_nesting_budget(collection_id, &budget, |d| { d.transfer_from(sender, from, recipient, item_id, value, &budget) }) } @@ -1348,5 +1354,44 @@ Ok(()) } + + fn structure_nesting_budget() -> budget::Value { + budget::Value::new(Self::nesting_budget()) + } + + fn nesting_budget_weight(value: &budget::Value) -> Weight { + T::StructureWeightInfo::find_parent().saturating_mul(value.remaining() as u64) + } + + fn nesting_budget_predispatch_weight() -> Weight { + Self::nesting_budget_weight(&Self::structure_nesting_budget()) + } + + pub fn dispatch_tx_with_nesting_budget< + C: FnOnce(&dyn CommonCollectionOperations) -> DispatchResultWithPostInfo, + >( + collection: CollectionId, + budget: &budget::Value, + call: C, + ) -> DispatchResultWithPostInfo { + let mut result = dispatch_tx::(collection, call); + + match &mut result { + Ok(PostDispatchInfo { + actual_weight: Some(weight), + .. + }) + | Err(DispatchErrorWithPostInfo { + post_info: PostDispatchInfo { + actual_weight: Some(weight), + .. + }, + .. + }) => *weight += Self::nesting_budget_weight(budget), + _ => {} + } + + result + } } } --- a/primitives/common/src/constants.rs +++ b/primitives/common/src/constants.rs @@ -45,6 +45,7 @@ /// Minimum balance required to create or keep an account open. pub const EXISTENTIAL_DEPOSIT: u128 = 0; + /// Amount of Balance reserved for candidate registration. pub const GENESIS_LICENSE_BOND: u128 = 1_000_000_000_000 * UNIQUE; /// Amount of maximum collators for Collator Selection. --- a/primitives/data-structs/src/budget.rs +++ b/primitives/data-structs/src/budget.rs @@ -1,4 +1,4 @@ -use core::cell::Cell; +use sp_std::cell::Cell; pub trait Budget { /// Returns true while not exceeded @@ -22,7 +22,7 @@ pub fn new(v: u32) -> Self { Self(Cell::new(v)) } - pub fn refund(self) -> u32 { + pub fn remaining(&self) -> u32 { self.0.get() } } --- a/runtime/common/config/pallets/mod.rs +++ b/runtime/common/config/pallets/mod.rs @@ -116,6 +116,7 @@ impl pallet_unique::Config for Runtime { type WeightInfo = pallet_unique::weights::SubstrateWeight; type CommonWeightInfo = CommonWeights; + type StructureWeightInfo = pallet_structure::weights::SubstrateWeight; type RefungibleExtensionsWeightInfo = CommonWeights; } --- a/runtime/common/runtime_apis.rs +++ b/runtime/common/runtime_apis.rs @@ -84,7 +84,7 @@ } fn topmost_token_owner(collection: CollectionId, token: TokenId) -> Result, DispatchError> { - let budget = up_data_structs::budget::Value::new(10); + let budget = budget::Value::new(10); >::find_topmost_owner(collection, token, &budget) } --- a/runtime/common/weights/mod.rs +++ b/runtime/common/weights/mod.rs @@ -98,10 +98,6 @@ dispatch_weight::() + max_weight_of!(set_token_properties(amount)) } - fn delete_token_properties(amount: u32) -> Weight { - dispatch_weight::() + max_weight_of!(delete_token_properties(amount)) - } - fn set_token_property_permissions(amount: u32) -> Weight { dispatch_weight::() + max_weight_of!(set_token_property_permissions(amount)) } @@ -124,26 +120,14 @@ fn burn_from() -> Weight { dispatch_weight::() + max_weight_of!(burn_from()) - } - - fn burn_recursively_self_raw() -> Weight { - max_weight_of!(burn_recursively_self_raw()) - } - - fn burn_recursively_breadth_raw(amount: u32) -> Weight { - max_weight_of!(burn_recursively_breadth_raw(amount)) - } - - fn token_owner() -> Weight { - max_weight_of!(token_owner()) } fn set_allowance_for_all() -> Weight { - max_weight_of!(set_allowance_for_all()) + dispatch_weight::() + max_weight_of!(set_allowance_for_all()) } fn force_repair_item() -> Weight { - max_weight_of!(force_repair_item()) + dispatch_weight::() + max_weight_of!(force_repair_item()) } } -- gitstuff