Skip to content

Commit

Permalink
Added BoundedVec and MaxEncodedLen (open-web3-stack#496)
Browse files Browse the repository at this point in the history
* Derived MaxEncodedLen

* Changed Vec to Bounded Vec and derived MaxEncodedLen

* Added test for max metadata

* Separated class and token max metadata

* Added doc comments
  • Loading branch information
brettkolodny authored May 18, 2021
1 parent 4921569 commit cfe1913
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 15 deletions.
50 changes: 37 additions & 13 deletions nft/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,21 +22,26 @@
#![allow(clippy::unused_unit)]

use codec::{Decode, Encode};
use frame_support::{ensure, pallet_prelude::*, Parameter};
use frame_support::{
ensure,
pallet_prelude::*,
traits::{Get, MaxEncodedLen},
BoundedVec, Parameter,
};
use sp_runtime::{
traits::{AtLeast32BitUnsigned, CheckedAdd, CheckedSub, MaybeSerializeDeserialize, Member, One, Zero},
ArithmeticError, DispatchError, DispatchResult, RuntimeDebug,
};
use sp_std::vec::Vec;
use sp_std::{convert::TryInto, vec::Vec};

mod mock;
mod tests;

/// Class info
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)]
pub struct ClassInfo<TokenId, AccountId, Data> {
#[derive(Encode, Decode, Clone, Eq, PartialEq, MaxEncodedLen, RuntimeDebug)]
pub struct ClassInfo<TokenId, AccountId, Data, ClassMetadataOf> {
/// Class metadata
pub metadata: Vec<u8>,
pub metadata: ClassMetadataOf,
/// Total issuance for the class
pub total_issuance: TokenId,
/// Class owner
Expand All @@ -46,10 +51,10 @@ pub struct ClassInfo<TokenId, AccountId, Data> {
}

/// Token info
#[derive(Encode, Decode, Clone, Eq, PartialEq, RuntimeDebug)]
pub struct TokenInfo<AccountId, Data> {
#[derive(Encode, Decode, Clone, Eq, PartialEq, MaxEncodedLen, RuntimeDebug)]
pub struct TokenInfo<AccountId, Data, TokenMetadataOf> {
/// Token metadata
pub metadata: Vec<u8>,
pub metadata: TokenMetadataOf,
/// Token owner
pub owner: AccountId,
/// Token Properties
Expand All @@ -72,11 +77,22 @@ pub mod module {
type ClassData: Parameter + Member + MaybeSerializeDeserialize;
/// The token properties type
type TokenData: Parameter + Member + MaybeSerializeDeserialize;
/// The maximum size of a class's metadata
type MaxClassMetadata: Get<u32>;
/// The maximum size of a token's metadata
type MaxTokenMetadata: Get<u32>;
}

pub type ClassInfoOf<T> =
ClassInfo<<T as Config>::TokenId, <T as frame_system::Config>::AccountId, <T as Config>::ClassData>;
pub type TokenInfoOf<T> = TokenInfo<<T as frame_system::Config>::AccountId, <T as Config>::TokenData>;
pub type ClassMetadataOf<T> = BoundedVec<u8, <T as Config>::MaxClassMetadata>;
pub type TokenMetadataOf<T> = BoundedVec<u8, <T as Config>::MaxTokenMetadata>;
pub type ClassInfoOf<T> = ClassInfo<
<T as Config>::TokenId,
<T as frame_system::Config>::AccountId,
<T as Config>::ClassData,
ClassMetadataOf<T>,
>;
pub type TokenInfoOf<T> =
TokenInfo<<T as frame_system::Config>::AccountId, <T as Config>::TokenData, TokenMetadataOf<T>>;

pub type GenesisTokenData<T> = (
<T as frame_system::Config>::AccountId, // Token owner
Expand Down Expand Up @@ -106,6 +122,8 @@ pub mod module {
/// Can not destroy class
/// Total issuance is not 0
CannotDestroyClass,
/// Failed because the Maximum amount of metadata was exceeded
MaxMetadataExceeded,
}

/// Next available class ID.
Expand Down Expand Up @@ -182,14 +200,17 @@ impl<T: Config> Pallet<T> {
metadata: Vec<u8>,
data: T::ClassData,
) -> Result<T::ClassId, DispatchError> {
let bounded_metadata: BoundedVec<u8, T::MaxClassMetadata> =
metadata.try_into().map_err(|_| Error::<T>::MaxMetadataExceeded)?;

let class_id = NextClassId::<T>::try_mutate(|id| -> Result<T::ClassId, DispatchError> {
let current_id = *id;
*id = id.checked_add(&One::one()).ok_or(Error::<T>::NoAvailableClassId)?;
Ok(current_id)
})?;

let info = ClassInfo {
metadata,
metadata: bounded_metadata,
total_issuance: Default::default(),
owner: owner.clone(),
data,
Expand Down Expand Up @@ -226,6 +247,9 @@ impl<T: Config> Pallet<T> {
data: T::TokenData,
) -> Result<T::TokenId, DispatchError> {
NextTokenId::<T>::try_mutate(class_id, |id| -> Result<T::TokenId, DispatchError> {
let bounded_metadata: BoundedVec<u8, T::MaxTokenMetadata> =
metadata.try_into().map_err(|_| Error::<T>::MaxMetadataExceeded)?;

let token_id = *id;
*id = id.checked_add(&One::one()).ok_or(Error::<T>::NoAvailableTokenId)?;

Expand All @@ -239,7 +263,7 @@ impl<T: Config> Pallet<T> {
})?;

let token_info = TokenInfo {
metadata,
metadata: bounded_metadata,
owner: owner.clone(),
data,
};
Expand Down
7 changes: 7 additions & 0 deletions nft/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,11 +43,18 @@ impl frame_system::Config for Runtime {
type OnSetCode = ();
}

parameter_types! {
pub const MaxClassMetadata: u32 = 1;
pub const MaxTokenMetadata: u32 = 1;
}

impl Config for Runtime {
type ClassId = u64;
type TokenId = u64;
type ClassData = ();
type TokenData = ();
type MaxClassMetadata = MaxClassMetadata;
type MaxTokenMetadata = MaxTokenMetadata;
}

type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Runtime>;
Expand Down
15 changes: 15 additions & 0 deletions nft/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,18 @@ fn destroy_class_should_fail() {
assert_eq!(Classes::<Runtime>::contains_key(CLASS_ID), false);
});
}

#[test]
fn exceeding_max_metadata_should_fail() {
ExtBuilder::default().build().execute_with(|| {
assert_noop!(
NonFungibleTokenModule::create_class(&ALICE, vec![1, 2], ()),
Error::<Runtime>::MaxMetadataExceeded
);
assert_ok!(NonFungibleTokenModule::create_class(&ALICE, vec![1], ()));
assert_noop!(
NonFungibleTokenModule::mint(&BOB, CLASS_ID, vec![1, 2], ()),
Error::<Runtime>::MaxMetadataExceeded
);
});
}
4 changes: 2 additions & 2 deletions rewards/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ mod mock;
mod tests;

use codec::{FullCodec, HasCompact};
use frame_support::pallet_prelude::*;
use frame_support::{pallet_prelude::*, traits::MaxEncodedLen};
use orml_traits::RewardHandler;
use sp_runtime::{
traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Member, Saturating, Zero},
Expand All @@ -17,7 +17,7 @@ use sp_std::{
};

/// The Reward Pool Info.
#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, Default)]
#[derive(Clone, Encode, Decode, PartialEq, Eq, RuntimeDebug, Default, MaxEncodedLen)]
pub struct PoolInfo<Share: HasCompact, Balance: HasCompact> {
/// Total shares amount
#[codec(compact)]
Expand Down

0 comments on commit cfe1913

Please sign in to comment.