--- a/node/cli/src/chain_spec.rs +++ b/node/cli/src/chain_spec.rs @@ -202,18 +202,6 @@ nft_item_id: vec![], fungible_item_id: vec![], refungible_item_id: vec![], - chain_limit: ChainLimits { - collection_numbers_limit: 100000, - account_token_ownership_limit: 1000000, - collections_admins_limit: 5, - custom_data_limit: 2048, - nft_sponsor_transfer_timeout: 15, - fungible_sponsor_transfer_timeout: 15, - refungible_sponsor_transfer_timeout: 15, - offchain_schema_limit: 1024, - variable_on_chain_schema_limit: 1024, - const_on_chain_schema_limit: 1024, - }, }, parachain_info: nft_runtime::ParachainInfoConfig { parachain_id: id }, aura: nft_runtime::AuraConfig { --- a/pallets/nft/src/eth/sponsoring.rs +++ b/pallets/nft/src/eth/sponsoring.rs @@ -1,12 +1,13 @@ //! Implements EVM sponsoring logic via OnChargeEVMTransaction use crate::{ - ChainLimit, Collection, CollectionById, Config, FungibleTransferBasket, NftTransferBasket, - eth::{account::EvmBackwardsAddressMapping, map_eth_to_id}, + Collection, CollectionById, Config, FungibleTransferBasket, NftTransferBasket, + eth::{account::EvmBackwardsAddressMapping, map_eth_to_id}, limit, }; use evm_coder::{Call, abi::AbiReader}; use frame_support::{ - storage::{StorageMap, StorageDoubleMap, StorageValue}, + storage::{StorageMap, StorageDoubleMap}, + traits::Get, }; use sp_core::H160; use sp_std::prelude::*; @@ -43,7 +44,7 @@ let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 { collection_limits.sponsor_transfer_timeout } else { - ChainLimit::get().nft_sponsor_transfer_timeout + ::get() }; let mut sponsor = true; @@ -74,7 +75,7 @@ let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 { collection_limits.sponsor_transfer_timeout } else { - ChainLimit::get().fungible_sponsor_transfer_timeout + ::get() }; let block_number = >::block_number() as T::BlockNumber; --- a/pallets/nft/src/lib.rs +++ b/pallets/nft/src/lib.rs @@ -31,7 +31,7 @@ StorageValue, transactional, }; -use frame_system::{self as system, ensure_signed, ensure_root}; +use frame_system::{self as system, ensure_signed}; use sp_core::H160; use sp_std::vec; use sp_runtime::sp_std::prelude::Vec; @@ -243,6 +243,15 @@ <::Currency as Currency>::Balance, >; type TreasuryAccountId: Get; + type ChainLimits: ChainLimits; +} + +pub type ChainLimitsOf = ::ChainLimits; +#[macro_export] +macro_rules! limit { + ($config:ty, $limit:ident) => { + <$crate::ChainLimitsOf<$config> as nft_data_structs::ChainLimits>::$limit + } } // # Used definitions @@ -280,10 +289,6 @@ ItemListIndex: map hasher(blake2_128_concat) CollectionId => TokenId; //#endregion - //#region Chain limits struct - pub ChainLimit get(fn chain_limit) config(): ChainLimits; - //#endregion - //#region Bound counters /// Amount of collections destroyed, used for total amount tracking with /// CreatedCollectionCount @@ -485,14 +490,12 @@ CollectionMode::Fungible(points) => points, _ => 0 }; - - let chain_limit = ChainLimit::get(); let created_count = CreatedCollectionCount::get(); let destroyed_count = DestroyedCollectionCount::get(); // bound Total number of collections - ensure!(created_count - destroyed_count < chain_limit.collection_numbers_limit, Error::::TotalCollectionsLimitExceeded); + ensure!(created_count - destroyed_count < ::get(), Error::::TotalCollectionsLimitExceeded); // check params ensure!(decimal_points <= MAX_DECIMAL_POINTS, Error::::CollectionDecimalPointLimitExceeded); @@ -508,7 +511,7 @@ CreatedCollectionCount::put(next_id); let limits = CollectionLimits { - sponsored_data_size: chain_limit.custom_data_limit, + sponsored_data_size: ::get(), ..Default::default() }; @@ -737,8 +740,7 @@ match admin_arr.binary_search(&new_admin_id) { Ok(_) => {}, Err(idx) => { - let limits = ChainLimit::get(); - ensure!(admin_arr.len() < limits.collections_admins_limit as usize, Error::::CollectionAdminsLimitExceeded); + ensure!(admin_arr.len() < ::get() as usize, Error::::CollectionAdminsLimitExceeded); admin_arr.insert(idx, new_admin_id); >::insert(collection_id, admin_arr); } @@ -862,7 +864,7 @@ #[weight = ::WeightInfo::create_item(data.data_size())] #[transactional] - pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData) -> DispatchResult { + pub fn create_item(origin, collection_id: CollectionId, owner: T::CrossAccountId, data: CreateItemData>) -> DispatchResult { let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); let collection = Self::get_collection(collection_id)?; @@ -893,7 +895,7 @@ .map(|data| { data.data_size() }) .sum())] #[transactional] - pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec) -> DispatchResult { + pub fn create_multiple_items(origin, collection_id: CollectionId, owner: T::CrossAccountId, items_data: Vec>>) -> DispatchResult { ensure!(!items_data.is_empty(), Error::::EmptyArgument); let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?); @@ -1138,7 +1140,7 @@ Self::check_owner_or_admin_permissions(&target_collection, &sender)?; // check schema limit - ensure!(schema.len() as u32 <= ChainLimit::get().offchain_schema_limit, ""); + ensure!(schema.len() as u32 <= ::get(), ""); target_collection.offchain_schema = schema; target_collection.save() @@ -1168,7 +1170,7 @@ Self::check_owner_or_admin_permissions(&target_collection, &sender)?; // check schema limit - ensure!(schema.len() as u32 <= ChainLimit::get().const_on_chain_schema_limit, ""); + ensure!(schema.len() as u32 <= ::get(), ""); target_collection.const_on_chain_schema = schema; target_collection.save() @@ -1198,25 +1200,10 @@ Self::check_owner_or_admin_permissions(&target_collection, &sender)?; // check schema limit - ensure!(schema.len() as u32 <= ChainLimit::get().variable_on_chain_schema_limit, ""); + ensure!(schema.len() as u32 <= ::get(), ""); target_collection.variable_on_chain_schema = schema; target_collection.save() - } - - // Sudo permissions function - #[weight = ::WeightInfo::set_chain_limits()] - #[transactional] - pub fn set_chain_limits( - origin, - limits: ChainLimits - ) -> DispatchResult { - - #[cfg(not(feature = "runtime-benchmarks"))] - ensure_root(origin)?; - - ::put(limits); - Ok(()) } #[weight = ::WeightInfo::set_collection_limits()] @@ -1230,12 +1217,11 @@ let mut target_collection = Self::get_collection(collection_id)?; Self::check_owner_permissions(&target_collection, sender.as_sub())?; let old_limits = &target_collection.limits; - let chain_limits = ChainLimit::get(); // collection bounds ensure!(new_limits.sponsor_transfer_timeout <= MAX_SPONSOR_TIMEOUT && new_limits.account_token_ownership_limit <= MAX_TOKEN_OWNERSHIP && - new_limits.sponsored_data_size <= chain_limits.custom_data_limit, + new_limits.sponsored_data_size <= as ChainLimits>::CustomDataLimit::get(), Error::::CollectionLimitBoundsExceeded); // token_limit check prev @@ -1260,7 +1246,7 @@ sender: &T::CrossAccountId, collection: &CollectionHandle, owner: &T::CrossAccountId, - data: CreateItemData, + data: CreateItemData>, ) -> DispatchResult { Self::can_create_items_in_collection(collection, sender, owner, 1)?; Self::validate_create_item_args(collection, &data)?; @@ -1471,7 +1457,7 @@ Self::token_exists(collection, item_id)?; ensure!( - ChainLimit::get().custom_data_limit >= data.len() as u32, + ::get() >= data.len() as u32, Error::::TokenVariableDataLimitExceeded ); @@ -1498,7 +1484,7 @@ sender: &T::CrossAccountId, collection: &CollectionHandle, owner: &T::CrossAccountId, - items_data: Vec, + items_data: Vec>>, ) -> DispatchResult { Self::can_create_items_in_collection(collection, sender, owner, items_data.len() as u32)?; @@ -1612,18 +1598,18 @@ fn validate_create_item_args( target_collection: &CollectionHandle, - data: &CreateItemData, + data: &CreateItemData>, ) -> DispatchResult { match target_collection.mode { CollectionMode::NFT => { if let CreateItemData::NFT(data) = data { // check sizes ensure!( - ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, + ::get() >= data.const_data.len() as u32, Error::::TokenConstDataLimitExceeded ); ensure!( - ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, + ::get() >= data.variable_data.len() as u32, Error::::TokenVariableDataLimitExceeded ); } else { @@ -1640,11 +1626,11 @@ if let CreateItemData::ReFungible(data) = data { // check sizes ensure!( - ChainLimit::get().custom_data_limit >= data.const_data.len() as u32, + ::get() >= data.const_data.len() as u32, Error::::TokenConstDataLimitExceeded ); ensure!( - ChainLimit::get().custom_data_limit >= data.variable_data.len() as u32, + ::get() >= data.variable_data.len() as u32, Error::::TokenVariableDataLimitExceeded ); @@ -1669,7 +1655,7 @@ fn create_item_no_validation( collection: &CollectionHandle, owner: &T::CrossAccountId, - data: CreateItemData, + data: CreateItemData>, ) -> DispatchResult { match data { CreateItemData::NFT(data) => { @@ -2292,7 +2278,7 @@ // bound Owned tokens by a single address let count = >::get(owner.as_sub()); ensure!( - count < ChainLimit::get().account_token_ownership_limit, + count < ::get(), Error::::AddressOwnershipLimitExceeded ); --- a/pallets/nft/src/sponsorship.rs +++ b/pallets/nft/src/sponsorship.rs @@ -1,13 +1,13 @@ use crate::{ Config, Call, CollectionById, CreateItemBasket, VariableMetaDataBasket, - ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, ChainLimit, - CreateItemData, CollectionMode, + ReFungibleTransferBasket, FungibleTransferBasket, NftTransferBasket, + CreateItemData, CollectionMode, limit, }; use core::marker::PhantomData; use up_sponsorship::SponsorshipHandler; use frame_support::{ - traits::IsSubType, - storage::{StorageMap, StorageDoubleMap, StorageValue}, + traits::{IsSubType, Get}, + storage::{StorageMap, StorageDoubleMap}, }; use nft_data_structs::{TokenId, CollectionId}; @@ -16,7 +16,7 @@ pub fn withdraw_create_item( who: &T::AccountId, collection_id: &CollectionId, - _properties: &CreateItemData, + _properties: &CreateItemData, ) -> Option { let collection = CollectionById::::get(collection_id)?; @@ -47,7 +47,6 @@ item_id: &TokenId, ) -> Option { let collection = CollectionById::::get(collection_id)?; - let limits = ChainLimit::get(); let mut sponsor_transfer = false; if collection.sponsorship.confirmed() { @@ -62,7 +61,7 @@ let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 { collection_limits.sponsor_transfer_timeout } else { - limits.nft_sponsor_transfer_timeout + ::get() }; let mut sponsored = true; @@ -84,7 +83,7 @@ let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 { collection_limits.sponsor_transfer_timeout } else { - limits.fungible_sponsor_transfer_timeout + ::get() }; let block_number = >::block_number() as T::BlockNumber; @@ -107,7 +106,7 @@ let limit: u32 = if collection_limits.sponsor_transfer_timeout > 0 { collection_limits.sponsor_transfer_timeout } else { - limits.refungible_sponsor_transfer_timeout + ::get() }; let mut sponsored = true; --- a/primitives/nft/src/lib.rs +++ b/primitives/nft/src/lib.rs @@ -28,14 +28,6 @@ pub const MAX_SPONSOR_TIMEOUT: u32 = 10_368_000; pub const MAX_TOKEN_OWNERSHIP: u32 = 10_000_000; -// TODO: Somehow use ChainLimits for BoundedVec len calculation? -// Do we need ChainLimits anyway, if we can change them via forkless upgrades? -parameter_types! { -pub const MaxDataSize: u32 = 2048; -// TODO: This limit isn't checked for substrate create_multiple_items call -pub const MaxItemsPerBatch: u32 = 200; -} - pub type CollectionId = u32; pub type TokenId = u32; pub type DecimalPoints = u8; @@ -211,23 +203,25 @@ } } -#[derive(Encode, Decode, Default, Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -pub struct ChainLimits { - pub collection_numbers_limit: u32, - pub account_token_ownership_limit: u32, - pub collections_admins_limit: u64, - pub custom_data_limit: u32, +pub trait ChainLimits { + type CollectionNumberLimit: Get; + type AccountTokenOwnershipLimit: Get; + type CollectionAdminsLimit: Get; + type CustomDataLimit: Get; // Timeouts for item types in passed blocks - pub nft_sponsor_transfer_timeout: u32, - pub fungible_sponsor_transfer_timeout: u32, - pub refungible_sponsor_transfer_timeout: u32, + type NftSponsorTransferTimeout: Get; + type FungibleSponsorTransferTimeout: Get; + type ReFungibleSponsorTransferTimeout: Get; // Schema limits - pub offchain_schema_limit: u32, - pub variable_on_chain_schema_limit: u32, - pub const_on_chain_schema_limit: u32, + type OffchainSchemaLimit: Get; + type VariableOnChainSchemaLimit: Get; + type ConstOnChainSchemaLimit: Get; + + /// How much items can be created per single + /// create_many call + type MaxItemsPerBatch: Get; } /// BoundedVec doesn't supports serde @@ -263,16 +257,16 @@ } } -#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative, Clone, PartialEq)] +#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -#[derivative(Debug)] -pub struct CreateNftData { +#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))] +pub struct CreateNftData { #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] #[derivative(Debug = "ignore")] - pub const_data: BoundedVec, + pub const_data: BoundedVec, #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] #[derivative(Debug = "ignore")] - pub variable_data: BoundedVec, + pub variable_data: BoundedVec, } #[derive(Encode, Decode, MaxEncodedLen, Default, Debug, Clone, PartialEq)] @@ -281,28 +275,29 @@ pub value: u128, } -#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative, Clone, PartialEq)] +#[derive(Encode, Decode, MaxEncodedLen, Default, Derivative)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -#[derivative(Debug)] -pub struct CreateReFungibleData { +#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))] +pub struct CreateReFungibleData { #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] #[derivative(Debug = "ignore")] - pub const_data: BoundedVec, + pub const_data: BoundedVec, #[cfg_attr(feature = "serde1", serde(with = "bounded_serde"))] #[derivative(Debug = "ignore")] - pub variable_data: BoundedVec, + pub variable_data: BoundedVec, pub pieces: u128, } -#[derive(Encode, Decode, MaxEncodedLen, Debug, Clone, PartialEq)] +#[derive(Encode, Decode, MaxEncodedLen, Derivative)] #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))] -pub enum CreateItemData { - NFT(CreateNftData), +#[derivative(Debug(bound = ""), PartialEq(bound = ""), Clone(bound = ""))] +pub enum CreateItemData { + NFT(CreateNftData), Fungible(CreateFungibleData), - ReFungible(CreateReFungibleData), + ReFungible(CreateReFungibleData), } -impl CreateItemData { +impl CreateItemData { pub fn data_size(&self) -> usize { match self { CreateItemData::NFT(data) => data.variable_data.len() + data.const_data.len(), @@ -312,19 +307,19 @@ } } -impl From for CreateItemData { - fn from(item: CreateNftData) -> Self { +impl From> for CreateItemData { + fn from(item: CreateNftData) -> Self { CreateItemData::NFT(item) } } -impl From for CreateItemData { - fn from(item: CreateReFungibleData) -> Self { +impl From> for CreateItemData { + fn from(item: CreateReFungibleData) -> Self { CreateItemData::ReFungible(item) } } -impl From for CreateItemData { +impl From for CreateItemData { fn from(item: CreateFungibleData) -> Self { CreateItemData::Fungible(item) } --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -683,6 +683,35 @@ } parameter_types! { + pub const CollectionNumberLimit: u32 = 100000; + pub const AccountTokenOwnershipLimit: u32 = 1000000; + pub const CollectionAdminsLimit: u64 = 5; + pub const CustomDataLimit: u32 = 2048; + pub const NftSponsorTransferTimeout: u32 = 5; + pub const FungibleSponsorTransferTimeout: u32 = 5; + pub const ReFungibleSponsorTransferTimeout: u32 = 5; + pub const OffchainSchemaLimit: u32 = 1024; + pub const VariableOnChainSchemaLimit: u32 = 1024; + pub const ConstOnChainSchemaLimit: u32 = 1024; + pub const MaxItemsPerBatch: u32 = 200; +} + +pub struct ChainLimits; +impl nft_data_structs::ChainLimits for ChainLimits { + type CollectionNumberLimit = CollectionNumberLimit; + type AccountTokenOwnershipLimit = AccountTokenOwnershipLimit; + type CollectionAdminsLimit = CollectionAdminsLimit; + type CustomDataLimit = CustomDataLimit; + type NftSponsorTransferTimeout = NftSponsorTransferTimeout; + type FungibleSponsorTransferTimeout = FungibleSponsorTransferTimeout; + type ReFungibleSponsorTransferTimeout = ReFungibleSponsorTransferTimeout; + type OffchainSchemaLimit = OffchainSchemaLimit; + type VariableOnChainSchemaLimit = VariableOnChainSchemaLimit; + type ConstOnChainSchemaLimit = ConstOnChainSchemaLimit; + type MaxItemsPerBatch = MaxItemsPerBatch; +} + +parameter_types! { pub TreasuryAccountId: AccountId = TreasuryModuleId::get().into_account(); pub const CollectionCreationPrice: Balance = 100 * UNIQUE; } @@ -699,6 +728,7 @@ type Currency = Balances; type CollectionCreationPrice = CollectionCreationPrice; type TreasuryAccountId = TreasuryAccountId; + type ChainLimits = ChainLimits; } parameter_types! {