git.delta.rocks / unique-network / refs/commits / 6be1bb56d5e4

difftreelog

feat split large fields out of Collection

Yaroslav Bolyukin2022-04-07parent: #3db55eb.patch.diff
in: master

7 files changed

modifiedclient/rpc/src/lib.rsdiffbeforeafterboth
--- a/client/rpc/src/lib.rs
+++ b/client/rpc/src/lib.rs
@@ -19,7 +19,7 @@
 use codec::Decode;
 use jsonrpc_core::{Error as RpcError, ErrorCode, Result};
 use jsonrpc_derive::rpc;
-use up_data_structs::{Collection, CollectionId, CollectionStats, CollectionLimits, TokenId};
+use up_data_structs::{RpcCollection, Collection, CollectionId, CollectionStats, CollectionLimits, TokenId};
 use sp_api::{BlockId, BlockT, ProvideRuntimeApi, ApiExt};
 use sp_blockchain::HeaderBackend;
 use up_rpc::UniqueApi as UniqueRuntimeApi;
@@ -116,7 +116,7 @@
 		&self,
 		collection: CollectionId,
 		at: Option<BlockHash>,
-	) -> Result<Option<Collection<AccountId>>>;
+	) -> Result<Option<RpcCollection<AccountId>>>;
 	#[rpc(name = "unique_collectionStats")]
 	fn collection_stats(&self, at: Option<BlockHash>) -> Result<CollectionStats>;
 
@@ -235,7 +235,7 @@
 	pass_method!(allowlist(collection: CollectionId) -> Vec<CrossAccountId>);
 	pass_method!(allowed(collection: CollectionId, user: CrossAccountId) -> bool);
 	pass_method!(last_token_id(collection: CollectionId) -> TokenId);
-	pass_method!(collection_by_id(collection: CollectionId) -> Option<Collection<AccountId>>);
+	pass_method!(collection_by_id(collection: CollectionId) -> Option<RpcCollection<AccountId>>);
 	pass_method!(collection_stats() -> CollectionStats);
 	pass_method!(next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Option<u64>);
 	pass_method!(effective_collection_limits(collection_id: CollectionId) -> Option<CollectionLimits>);
modifiedpallets/common/src/lib.rsdiffbeforeafterboth
29};29};
30use pallet_evm::GasWeightMapping;30use pallet_evm::GasWeightMapping;
31use up_data_structs::{31use up_data_structs::{
32 COLLECTION_NUMBER_LIMIT, Collection, CollectionId, CreateItemData, MAX_TOKEN_PREFIX_LENGTH,32 COLLECTION_NUMBER_LIMIT, Collection, RpcCollection, CollectionId, CreateItemData, MAX_TOKEN_PREFIX_LENGTH,
33 COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId, CollectionStats, MAX_TOKEN_OWNERSHIP,33 COLLECTION_ADMINS_LIMIT, MetaUpdatePermission, TokenId, CollectionStats, MAX_TOKEN_OWNERSHIP,
34 CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,34 CollectionMode, NFT_SPONSOR_TRANSFER_TIMEOUT, FUNGIBLE_SPONSOR_TRANSFER_TIMEOUT,
35 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT, CUSTOM_DATA_LIMIT, CollectionLimits,35 REFUNGIBLE_SPONSOR_TRANSFER_TIMEOUT, MAX_SPONSOR_TIMEOUT, CUSTOM_DATA_LIMIT, CollectionLimits,
36 CustomDataLimit, CreateCollectionData, SponsorshipState, CreateItemExData, SponsoringRateLimit, budget::Budget,36 CustomDataLimit, CreateCollectionData, SponsorshipState, CreateItemExData, SponsoringRateLimit, budget::Budget, COLLECTION_FIELD_LIMIT, CollectionField,
37};37};
38pub use pallet::*;38pub use pallet::*;
39use sp_core::H160;39use sp_core::H160;
353 /// Only tokens from specific collections may nest tokens under this353 /// Only tokens from specific collections may nest tokens under this
354 SourceCollectionIsNotAllowedToNest,354 SourceCollectionIsNotAllowedToNest,
355
356 /// Tried to store more data than allowed in collection field
357 CollectionFieldSizeExceeded,
355 }358 }
356359
357 #[pallet::storage]360 #[pallet::storage]
369 QueryKind = OptionQuery,372 QueryKind = OptionQuery,
370 >;373 >;
374
375 /// Large variable-size collection fields are extracted here
376 #[pallet::storage]
377 pub type CollectionData<T> = StorageNMap<
378 Key = (
379 Key<Twox64Concat, CollectionId>,
380 Key<Twox64Concat, CollectionField>,
381 ),
382 Value = BoundedVec<u8, ConstU32<COLLECTION_FIELD_LIMIT>>,
383 QueryKind = ValueQuery,
384 >;
371385
372 #[pallet::storage]386 #[pallet::storage]
373 pub type AdminAmount<T> = StorageMap<387 pub type AdminAmount<T> = StorageMap<
409 fn on_runtime_upgrade() -> Weight {423 fn on_runtime_upgrade() -> Weight {
410 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {424 if StorageVersion::get::<Pallet<T>>() < StorageVersion::new(1) {
411 use up_data_structs::{CollectionVersion1, CollectionVersion2};425 use up_data_structs::{CollectionVersion1, CollectionVersion2};
412 <CollectionById<T>>::translate_values::<CollectionVersion1<T::AccountId>, _>(|v| {426 <CollectionById<T>>::translate::<CollectionVersion1<T::AccountId>, _>(|id, v| {
427 Self::set_field_raw(
428 id,
429 CollectionField::OffchainSchema,
430 v.offchain_schema.clone().into_inner(),
431 )
432 .expect("data has lower bounds than field");
433 Self::set_field_raw(
434 id,
435 CollectionField::VariableOnChainSchema,
436 v.variable_on_chain_schema.clone().into_inner(),
437 )
438 .expect("data has lower bounds than field");
439 Self::set_field_raw(
440 id,
441 CollectionField::ConstOnChainSchema,
442 v.const_on_chain_schema.clone().into_inner(),
443 )
444 .expect("data has lower bounds than field");
445
413 Some(CollectionVersion2::from(v))446 Some(CollectionVersion2::from(v))
414 });447 });
484 Some(effective_limits)517 Some(effective_limits)
485 }518 }
519
520 pub fn rpc_collection(collection: CollectionId) -> Option<RpcCollection<T::AccountId>> {
521 let Collection {
522 name,
523 description,
524 owner,
525 mode,
526 access,
527 token_prefix,
528 mint_mode,
529 schema_version,
530 sponsorship,
531 limits,
532 meta_update_permission,
533 } = <CollectionById<T>>::get(collection)?;
534 Some(RpcCollection {
535 name: name.into_inner(),
536 description: description.into_inner(),
537 owner,
538 mode,
539 access,
540 token_prefix: token_prefix.into_inner(),
541 mint_mode,
542 schema_version,
543 sponsorship,
544 limits,
545 meta_update_permission,
546 offchain_schema: <CollectionData<T>>::get((
547 collection,
548 CollectionField::OffchainSchema,
549 ))
550 .into_inner(),
551 const_on_chain_schema: <CollectionData<T>>::get((
552 collection,
553 CollectionField::ConstOnChainSchema,
554 ))
555 .into_inner(),
556 variable_on_chain_schema: <CollectionData<T>>::get((
557 collection,
558 CollectionField::VariableOnChainSchema,
559 ))
560 .into_inner(),
561 })
562 }
486}563}
487564
488impl<T: Config> Pallet<T> {565impl<T: Config> Pallet<T> {
520 access: data.access.unwrap_or_default(),597 access: data.access.unwrap_or_default(),
521 description: data.description,598 description: data.description,
522 token_prefix: data.token_prefix,599 token_prefix: data.token_prefix,
523 offchain_schema: data.offchain_schema,
524 schema_version: data.schema_version.unwrap_or_default(),600 schema_version: data.schema_version.unwrap_or_default(),
525 sponsorship: data601 sponsorship: data
526 .pending_sponsor602 .pending_sponsor
527 .map(SponsorshipState::Unconfirmed)603 .map(SponsorshipState::Unconfirmed)
528 .unwrap_or_default(),604 .unwrap_or_default(),
529 variable_on_chain_schema: data.variable_on_chain_schema,
530 const_on_chain_schema: data.const_on_chain_schema,
531 limits: data605 limits: data
532 .limits606 .limits
533 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))607 .map(|limits| Self::clamp_limits(data.mode.clone(), &Default::default(), limits))
557 <CreatedCollectionCount<T>>::put(created_count);631 <CreatedCollectionCount<T>>::put(created_count);
558 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));632 <Pallet<T>>::deposit_event(Event::CollectionCreated(id, data.mode.id(), owner.clone()));
559 <CollectionById<T>>::insert(id, collection);633 <CollectionById<T>>::insert(id, collection);
634 Self::set_field_raw(
635 id,
636 CollectionField::OffchainSchema,
637 data.offchain_schema.into_inner(),
638 )
639 .expect("data has lower bounds than field");
640 Self::set_field_raw(
641 id,
642 CollectionField::VariableOnChainSchema,
643 data.variable_on_chain_schema.into_inner(),
644 )
645 .expect("data has lower bounds than field");
646 Self::set_field_raw(
647 id,
648 CollectionField::ConstOnChainSchema,
649 data.const_on_chain_schema.into_inner(),
650 )
651 .expect("data has lower bounds than field");
560 Ok(id)652 Ok(id)
561 }653 }
562654
579671
580 <DestroyedCollectionCount<T>>::put(destroyed_collections);672 <DestroyedCollectionCount<T>>::put(destroyed_collections);
581 <CollectionById<T>>::remove(collection.id);673 <CollectionById<T>>::remove(collection.id);
674 <CollectionData<T>>::remove_prefix((collection.id,), None);
582 <AdminAmount<T>>::remove(collection.id);675 <AdminAmount<T>>::remove(collection.id);
583 <IsAdmin<T>>::remove_prefix((collection.id,), None);676 <IsAdmin<T>>::remove_prefix((collection.id,), None);
584 <Allowlist<T>>::remove_prefix((collection.id,), None);677 <Allowlist<T>>::remove_prefix((collection.id,), None);
587 Ok(())680 Ok(())
588 }681 }
682
683 fn set_field_raw(
684 collection_id: CollectionId,
685 field: CollectionField,
686 value: Vec<u8>,
687 ) -> DispatchResult {
688 if !value.is_empty() {
689 <CollectionData<T>>::insert(
690 (collection_id, field),
691 BoundedVec::try_from(value).map_err(|_| <Error<T>>::CollectionFieldSizeExceeded)?,
692 )
693 } else {
694 <CollectionData<T>>::remove((collection_id, field));
695 }
696 Ok(())
697 }
698
699 pub fn set_field(
700 collection: &CollectionHandle<T>,
701 sender: &T::CrossAccountId,
702 field: CollectionField,
703 value: Vec<u8>,
704 ) -> DispatchResult {
705 collection.check_is_owner_or_admin(sender)?;
706
707 // =========
708
709 Self::set_field_raw(collection.id, field, value)
710 }
589711
590 pub fn toggle_allowlist(712 pub fn toggle_allowlist(
591 collection: &CollectionHandle<T>,713 collection: &CollectionHandle<T>,
modifiedpallets/unique/src/lib.rsdiffbeforeafterboth
--- a/pallets/unique/src/lib.rs
+++ b/pallets/unique/src/lib.rs
@@ -43,7 +43,7 @@
 	MAX_COLLECTION_NAME_LENGTH, MAX_COLLECTION_DESCRIPTION_LENGTH, MAX_TOKEN_PREFIX_LENGTH,
 	AccessMode, CreateItemData, CollectionLimits, CollectionId, CollectionMode, TokenId,
 	SchemaVersion, SponsorshipState, MetaUpdatePermission, CreateCollectionData, CustomDataLimit,
-	CreateItemExData, budget,
+	CreateItemExData, budget, CollectionField,
 };
 use pallet_evm::account::CrossAccountId;
 use pallet_common::{
@@ -1004,16 +1004,16 @@
 			schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,
 		) -> DispatchResult {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
-			target_collection.check_is_owner_or_admin(&sender)?;
+			let collection = <CollectionHandle<T>>::try_get(collection_id)?;
+
+			// =========
 
-			target_collection.offchain_schema = schema;
+			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::OffchainSchema, schema.into_inner())?;
 
 			<Pallet<T>>::deposit_event(Event::<T>::OffchainSchemaSet(
 				collection_id
 			));
-
-			target_collection.save()
+			Ok(())
 		}
 
 		/// Set const on-chain data schema.
@@ -1036,16 +1036,16 @@
 			schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>
 		) -> DispatchResult {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
-			target_collection.check_is_owner_or_admin(&sender)?;
+			let collection = <CollectionHandle<T>>::try_get(collection_id)?;
+
+			// =========
 
-			target_collection.const_on_chain_schema = schema;
+			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::ConstOnChainSchema, schema.into_inner())?;
 
 			<Pallet<T>>::deposit_event(Event::<T>::ConstOnChainSchemaSet(
 				collection_id
 			));
-
-			target_collection.save()
+			Ok(())
 		}
 
 		/// Set variable on-chain data schema.
@@ -1068,16 +1068,16 @@
 			schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>
 		) -> DispatchResult {
 			let sender = T::CrossAccountId::from_sub(ensure_signed(origin)?);
-			let mut target_collection = <CollectionHandle<T>>::try_get(collection_id)?;
-			target_collection.check_is_owner_or_admin(&sender)?;
+			let collection = <CollectionHandle<T>>::try_get(collection_id)?;
+
+			// =========
 
-			target_collection.variable_on_chain_schema = schema;
+			<PalletCommon<T>>::set_field(&collection, &sender, CollectionField::VariableOnChainSchema, schema.into_inner())?;
 
 			<Pallet<T>>::deposit_event(Event::<T>::VariableOnChainSchemaSet(
 				collection_id
 			));
-
-			target_collection.save()
+			Ok(())
 		}
 
 		#[weight = <SelfWeightOf<T>>::set_collection_limits()]
modifiedprimitives/data-structs/src/lib.rsdiffbeforeafterboth
--- a/primitives/data-structs/src/lib.rs
+++ b/primitives/data-structs/src/lib.rs
@@ -78,6 +78,9 @@
 pub const VARIABLE_ON_CHAIN_SCHEMA_LIMIT: u32 = 8192;
 pub const CONST_ON_CHAIN_SCHEMA_LIMIT: u32 = 32768;
 
+pub const COLLECTION_FIELD_LIMIT: u32 = CONST_ON_CHAIN_SCHEMA_LIMIT;
+// u32::max is not const: OFFCHAIN_SCHEMA_LIMIT.max(VARIABLE_ON_CHAIN_SCHEMA_LIMIT).max(CONST_ON_CHAIN_SCHEMA_LIMIT);
+
 pub const MAX_COLLECTION_NAME_LENGTH: u32 = 64;
 pub const MAX_COLLECTION_DESCRIPTION_LENGTH: u32 = 256;
 pub const MAX_TOKEN_PREFIX_LENGTH: u32 = 16;
@@ -248,22 +251,21 @@
 	}
 }
 
+/// Used in storage
 #[struct_versioning::versioned(version = 2, upper)]
 #[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
-#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 pub struct Collection<AccountId> {
 	pub owner: AccountId,
 	pub mode: CollectionMode,
 	pub access: AccessMode,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	pub name: BoundedVec<u16, ConstU32<MAX_COLLECTION_NAME_LENGTH>>,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	pub description: BoundedVec<u16, ConstU32<MAX_COLLECTION_DESCRIPTION_LENGTH>>,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
 	pub token_prefix: BoundedVec<u8, ConstU32<MAX_TOKEN_PREFIX_LENGTH>>,
 	pub mint_mode: bool,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
+
+	#[version(..2)]
 	pub offchain_schema: BoundedVec<u8, ConstU32<OFFCHAIN_SCHEMA_LIMIT>>,
+
 	pub schema_version: SchemaVersion,
 	pub sponsorship: SponsorshipState<AccountId>,
 
@@ -272,13 +274,42 @@
 	#[version(2.., upper(limits.into()))]
 	pub limits: CollectionLimitsVersion2,
 
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
+	#[version(..2)]
 	pub variable_on_chain_schema: BoundedVec<u8, ConstU32<VARIABLE_ON_CHAIN_SCHEMA_LIMIT>>,
-	#[cfg_attr(feature = "serde1", serde(with = "bounded::vec_serde"))]
+	#[version(..2)]
 	pub const_on_chain_schema: BoundedVec<u8, ConstU32<CONST_ON_CHAIN_SCHEMA_LIMIT>>,
+
 	pub meta_update_permission: MetaUpdatePermission,
 }
 
+/// Used in RPC calls
+#[derive(Encode, Decode, Clone, PartialEq, TypeInfo)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub struct RpcCollection<AccountId> {
+	pub owner: AccountId,
+	pub mode: CollectionMode,
+	pub access: AccessMode,
+	pub name: Vec<u16>,
+	pub description: Vec<u16>,
+	pub token_prefix: Vec<u8>,
+	pub mint_mode: bool,
+	pub offchain_schema: Vec<u8>,
+	pub schema_version: SchemaVersion,
+	pub sponsorship: SponsorshipState<AccountId>,
+	pub limits: CollectionLimits,
+	pub variable_on_chain_schema: Vec<u8>,
+	pub const_on_chain_schema: Vec<u8>,
+	pub meta_update_permission: MetaUpdatePermission,
+}
+
+#[derive(Encode, Decode, Clone, PartialEq, TypeInfo, MaxEncodedLen)]
+#[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
+pub enum CollectionField {
+	VariableOnChainSchema,
+	ConstOnChainSchema,
+	OffchainSchema,
+}
+
 #[derive(Encode, Decode, Clone, PartialEq, TypeInfo, Debug, Derivative, MaxEncodedLen)]
 #[cfg_attr(feature = "serde1", derive(Serialize, Deserialize))]
 #[derivative(Default(bound = ""))]
modifiedprimitives/rpc/src/lib.rsdiffbeforeafterboth
--- a/primitives/rpc/src/lib.rs
+++ b/primitives/rpc/src/lib.rs
@@ -16,7 +16,7 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
-use up_data_structs::{CollectionId, TokenId, Collection, CollectionStats, CollectionLimits};
+use up_data_structs::{CollectionId, TokenId, RpcCollection, Collection, CollectionStats, CollectionLimits};
 use sp_std::vec::Vec;
 use codec::Decode;
 use sp_runtime::DispatchError;
@@ -53,7 +53,7 @@
 		fn allowlist(collection: CollectionId) -> Result<Vec<CrossAccountId>>;
 		fn allowed(collection: CollectionId, user: CrossAccountId) -> Result<bool>;
 		fn last_token_id(collection: CollectionId) -> Result<TokenId>;
-		fn collection_by_id(collection: CollectionId) -> Result<Option<Collection<AccountId>>>;
+		fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>>;
 		fn collection_stats() -> Result<CollectionStats>;
 		fn next_sponsored(collection: CollectionId, account: CrossAccountId, token: TokenId) -> Result<Option<u64>>;
 		fn effective_collection_limits(collection_id: CollectionId) -> Result<Option<CollectionLimits>>;
modifiedruntime/common/src/runtime_apis.rsdiffbeforeafterboth
--- a/runtime/common/src/runtime_apis.rs
+++ b/runtime/common/src/runtime_apis.rs
@@ -58,8 +58,8 @@
                 fn last_token_id(collection: CollectionId) -> Result<TokenId, DispatchError> {
                     dispatch_unique_runtime!(collection.last_token_id())
                 }
-                fn collection_by_id(collection: CollectionId) -> Result<Option<Collection<AccountId>>, DispatchError> {
-                    Ok(<pallet_common::CollectionById<Runtime>>::get(collection))
+                fn collection_by_id(collection: CollectionId) -> Result<Option<RpcCollection<AccountId>>, DispatchError> {
+                    Ok(<pallet_common::Pallet<Runtime>>::rpc_collection(collection))
                 }
                 fn collection_stats() -> Result<CollectionStats, DispatchError> {
                     Ok(<pallet_common::Pallet<Runtime>>::collection_stats())
modifiedruntime/opal/src/lib.rsdiffbeforeafterboth
--- a/runtime/opal/src/lib.rs
+++ b/runtime/opal/src/lib.rs
@@ -67,7 +67,7 @@
 	},
 };
 use up_data_structs::mapping::{EvmTokenAddressMapping, CrossTokenAddressMapping};
-use up_data_structs::{CollectionId, TokenId, CollectionStats, Collection};
+use up_data_structs::{CollectionId, TokenId, CollectionStats, Collection, RpcCollection};
 // use pallet_contracts::weights::WeightInfo;
 // #[cfg(any(feature = "std", test))]
 use frame_system::{