From d0d0895188584228171cea9fdef1a214ae2bcab8 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 10:40:16 +0200 Subject: [PATCH 01/24] update with the latest code from substrate template node --- pallets/template/Cargo.toml | 14 +++++++------- pallets/template/README.md | 2 +- pallets/template/src/benchmarking.rs | 2 +- pallets/template/src/lib.rs | 2 +- pallets/template/src/mock.rs | 7 +++---- pallets/template/src/weights.rs | 3 +-- 6 files changed, 14 insertions(+), 16 deletions(-) diff --git a/pallets/template/Cargo.toml b/pallets/template/Cargo.toml index 2394866..bb20a1b 100644 --- a/pallets/template/Cargo.toml +++ b/pallets/template/Cargo.toml @@ -13,18 +13,18 @@ repository = "https://github.com/substrate-developer-hub/substrate-laos-evolutio targets = ["x86_64-unknown-linux-gnu"] [dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ "derive", ] } scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } [dev-dependencies] -sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-core = { version = "21.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-io = { version = "23.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-runtime = { version = "24.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } [features] default = ["std"] diff --git a/pallets/template/README.md b/pallets/template/README.md index 9e4dc55..d0d5953 100644 --- a/pallets/template/README.md +++ b/pallets/template/README.md @@ -1 +1 @@ -License: MIT-0 +License: MIT-0 \ No newline at end of file diff --git a/pallets/template/src/benchmarking.rs b/pallets/template/src/benchmarking.rs index d1a9554..5a26241 100644 --- a/pallets/template/src/benchmarking.rs +++ b/pallets/template/src/benchmarking.rs @@ -13,7 +13,7 @@ mod benchmarks { #[benchmark] fn do_something() { - let value = 100u32; + let value = 100u32.into(); let caller: T::AccountId = whitelisted_caller(); #[extrinsic_call] do_something(RawOrigin::Signed(caller), value); diff --git a/pallets/template/src/lib.rs b/pallets/template/src/lib.rs index edf7769..9550d3d 100644 --- a/pallets/template/src/lib.rs +++ b/pallets/template/src/lib.rs @@ -94,7 +94,7 @@ pub mod pallet { // Read a value from storage. match >::get() { // Return an error if the value has not been set. - None => Err(Error::::NoneValue.into()), + None => return Err(Error::::NoneValue.into()), Some(old) => { // Increment the value read from storage; will error in the event of overflow. let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; diff --git a/pallets/template/src/mock.rs b/pallets/template/src/mock.rs index 8b7236c..244ae1b 100644 --- a/pallets/template/src/mock.rs +++ b/pallets/template/src/mock.rs @@ -7,7 +7,6 @@ use sp_runtime::{ }; type Block = frame_system::mocking::MockBlock; -type Nonce = u32; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -25,12 +24,12 @@ impl frame_system::Config for Test { type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; + type Nonce = u64; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; - type Nonce = Nonce; - type Block = Block; type Lookup = IdentityLookup; + type Block = Block; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); @@ -51,5 +50,5 @@ impl pallet_template::Config for Test { // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - RuntimeGenesisConfig::default().build_storage().unwrap().into() + frame_system::GenesisConfig::::default().build_storage().unwrap().into() } diff --git a/pallets/template/src/weights.rs b/pallets/template/src/weights.rs index a497666..7c42936 100644 --- a/pallets/template/src/weights.rs +++ b/pallets/template/src/weights.rs @@ -8,7 +8,7 @@ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ../../target/release/laos-evolution +// ../../target/release/node-template // benchmark // pallet // --chain @@ -19,7 +19,6 @@ // * // --steps=50 // --repeat=20 -// --execution=wasm // --wasm-execution=compiled // --output // pallets/template/src/weights.rs From 21a58dc0f8e9fd5a5d39f20a2229524ad4abf905 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 11:04:33 +0200 Subject: [PATCH 02/24] pallet-living-assets-evolution --- Cargo.lock | 28 +++++++++---------- Cargo.toml | 2 +- README.md | 2 +- .../Cargo.toml | 7 ++--- .../README.md | 0 .../src/benchmarking.rs | 2 +- .../src/lib.rs | 0 .../src/mock.rs | 6 ++-- .../src/tests.rs | 0 .../src/weights.rs | 10 +++---- runtime/Cargo.toml | 8 +++--- runtime/src/lib.rs | 15 +++++----- 12 files changed, 38 insertions(+), 42 deletions(-) rename pallets/{template => living-assets-evolution}/Cargo.toml (83%) rename pallets/{template => living-assets-evolution}/README.md (100%) rename pallets/{template => living-assets-evolution}/src/benchmarking.rs (93%) rename pallets/{template => living-assets-evolution}/src/lib.rs (100%) rename pallets/{template => living-assets-evolution}/src/mock.rs (89%) rename pallets/{template => living-assets-evolution}/src/tests.rs (100%) rename pallets/{template => living-assets-evolution}/src/weights.rs (90%) diff --git a/Cargo.lock b/Cargo.lock index fad7b95..948eb87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3622,8 +3622,8 @@ dependencies = [ "pallet-balances", "pallet-bridge-grandpa", "pallet-grandpa", + "pallet-living-assets-evolution", "pallet-sudo", - "pallet-template", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -4997,53 +4997,53 @@ dependencies = [ ] [[package]] -name = "pallet-session" +name = "pallet-living-assets-evolution" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-timestamp", "parity-scale-codec", "scale-info", "sp-core", "sp-io", "sp-runtime", - "sp-session", - "sp-staking", - "sp-std", - "sp-trie", ] [[package]] -name = "pallet-sudo" +name = "pallet-session" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ - "frame-benchmarking", "frame-support", "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-timestamp", "parity-scale-codec", "scale-info", + "sp-core", "sp-io", "sp-runtime", + "sp-session", + "sp-staking", "sp-std", + "sp-trie", ] [[package]] -name = "pallet-template" +name = "pallet-sudo" version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "parity-scale-codec", "scale-info", - "sp-core", "sp-io", "sp-runtime", + "sp-std", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4e07323..e869ba3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ "node", - "pallets/template", + "pallets/living-assets-evolution", "runtime", "primitives" ] diff --git a/README.md b/README.md index 41c1f2b..b8bea00 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this ### Pallets -The runtime in this project is constructed using many FRAME pallets that ship with the [core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. +The runtime in this project is constructed using many FRAME pallets that ship with the [core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a template pallet that is [defined in the `pallets`](./pallets/living-assets-evolution/src/lib.rs) directory. A FRAME pallet is compromised of a number of blockchain primitives: diff --git a/pallets/template/Cargo.toml b/pallets/living-assets-evolution/Cargo.toml similarity index 83% rename from pallets/template/Cargo.toml rename to pallets/living-assets-evolution/Cargo.toml index bb20a1b..7e1bfc7 100644 --- a/pallets/template/Cargo.toml +++ b/pallets/living-assets-evolution/Cargo.toml @@ -1,13 +1,10 @@ [package] -name = "pallet-template" +name = "pallet-living-assets-evolution" version = "4.0.0-dev" -description = "FRAME pallet template for defining custom runtime logic." -authors = ["Substrate DevHub "] -homepage = "https://substrate.io" +homepage = "https://freeverse.io" edition = "2021" license = "MIT-0" publish = false -repository = "https://github.com/substrate-developer-hub/substrate-laos-evolution/" [package.metadata.docs.rs] targets = ["x86_64-unknown-linux-gnu"] diff --git a/pallets/template/README.md b/pallets/living-assets-evolution/README.md similarity index 100% rename from pallets/template/README.md rename to pallets/living-assets-evolution/README.md diff --git a/pallets/template/src/benchmarking.rs b/pallets/living-assets-evolution/src/benchmarking.rs similarity index 93% rename from pallets/template/src/benchmarking.rs rename to pallets/living-assets-evolution/src/benchmarking.rs index 5a26241..c4bdcaa 100644 --- a/pallets/template/src/benchmarking.rs +++ b/pallets/living-assets-evolution/src/benchmarking.rs @@ -1,4 +1,4 @@ -//! Benchmarking setup for pallet-template +//! Benchmarking setup for pallet-living-assets-evolution #![cfg(feature = "runtime-benchmarks")] use super::*; diff --git a/pallets/template/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs similarity index 100% rename from pallets/template/src/lib.rs rename to pallets/living-assets-evolution/src/lib.rs diff --git a/pallets/template/src/mock.rs b/pallets/living-assets-evolution/src/mock.rs similarity index 89% rename from pallets/template/src/mock.rs rename to pallets/living-assets-evolution/src/mock.rs index 244ae1b..9c928a1 100644 --- a/pallets/template/src/mock.rs +++ b/pallets/living-assets-evolution/src/mock.rs @@ -1,4 +1,4 @@ -use crate as pallet_template; +use crate as pallet_living_assets_evolution; use frame_support::traits::{ConstU16, ConstU64}; use sp_core::H256; use sp_runtime::{ @@ -13,7 +13,7 @@ frame_support::construct_runtime!( pub enum Test { System: frame_system, - TemplateModule: pallet_template, + TemplateModule: pallet_living_assets_evolution, } ); @@ -43,7 +43,7 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_template::Config for Test { +impl pallet_living_assets_evolution::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } diff --git a/pallets/template/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs similarity index 100% rename from pallets/template/src/tests.rs rename to pallets/living-assets-evolution/src/tests.rs diff --git a/pallets/template/src/weights.rs b/pallets/living-assets-evolution/src/weights.rs similarity index 90% rename from pallets/template/src/weights.rs rename to pallets/living-assets-evolution/src/weights.rs index 7c42936..2648b91 100644 --- a/pallets/template/src/weights.rs +++ b/pallets/living-assets-evolution/src/weights.rs @@ -1,5 +1,5 @@ -//! Autogenerated weights for pallet_template +//! Autogenerated weights for pallet_living_assets_evolution //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -14,14 +14,14 @@ // --chain // dev // --pallet -// pallet_template +// pallet_living_assets_evolution // --extrinsic // * // --steps=50 // --repeat=20 // --wasm-execution=compiled // --output -// pallets/template/src/weights.rs +// pallets/living-assets-evolution/src/weights.rs // --template // ../../.maintain/frame-weight-template.hbs @@ -32,13 +32,13 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_template. +/// Weight functions needed for pallet_living_assets_evolution. pub trait WeightInfo { fn do_something() -> Weight; fn cause_error() -> Weight; } -/// Weights for pallet_template using the Substrate node and recommended hardware. +/// Weights for pallet_living_assets_evolution using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: TemplateModule Something (r:0 w:1) diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 5d90cd2..8be7c0d 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -51,7 +51,7 @@ frame-benchmarking = { default-features = false, git = "https://github.com/parit frame-system-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", optional = true , branch = "polkadot-v1.0.0" } # Local Dependencies -pallet-template = { default-features = false, path = "../pallets/template" } +pallet-living-assets-evolution = { default-features = false, path = "../pallets/living-assets-evolution" } fp-account = { git = "https://github.com/paritytech/frontier.git", branch = "polkadot-v1.0.0", default-features = false, features = ["serde"] } # Bridge dependencies @@ -81,7 +81,7 @@ std = [ "pallet-balances/std", "pallet-grandpa/std", "pallet-sudo/std", - "pallet-template/std", + "pallet-living-assets-evolution/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -112,7 +112,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", - "pallet-template/runtime-benchmarks", + "pallet-living-assets-evolution/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] @@ -125,7 +125,7 @@ try-runtime = [ "pallet-balances/try-runtime", "pallet-grandpa/try-runtime", "pallet-sudo/try-runtime", - "pallet-template/try-runtime", + "pallet-living-assets-evolution/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "sp-runtime/try-runtime", diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 6cb1e1b..2e12bf9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -46,8 +46,7 @@ use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; -/// Import the template pallet. -pub use pallet_template; +pub use pallet_living_assets_evolution; /// An index to a block. pub type BlockNumber = evochain_primitives::BlockNumber; @@ -272,10 +271,10 @@ impl pallet_sudo::Config for Runtime { type WeightInfo = pallet_sudo::weights::SubstrateWeight; } -/// Configure the pallet-template in pallets/template. -impl pallet_template::Config for Runtime { +/// Configure the pallet-living-assets-evolution in pallets/living-assets-evolution. +impl pallet_living_assets_evolution::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_template::weights::SubstrateWeight; + type WeightInfo = pallet_living_assets_evolution::weights::SubstrateWeight; } impl pallet_bridge_grandpa::Config for Runtime { @@ -297,8 +296,8 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment, Sudo: pallet_sudo, - // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template, + // Include the custom logic from the pallet-living-assets-evolution in the runtime. + TemplateModule: pallet_living_assets_evolution, BridgeRococoGrandpa: pallet_bridge_grandpa, } @@ -347,7 +346,7 @@ mod benches { [frame_system, SystemBench::] [pallet_balances, Balances] [pallet_timestamp, Timestamp] - [pallet_template, TemplateModule] + [pallet_living_assets_evolution, TemplateModule] ); } From e50d8df78e557655ac21992152331d711018a35b Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 11:30:50 +0200 Subject: [PATCH 03/24] collection_owner --- pallets/living-assets-evolution/src/lib.rs | 9 +++++++++ pallets/living-assets-evolution/src/tests.rs | 10 +++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 9550d3d..2954b35 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -22,6 +22,9 @@ pub mod pallet { use frame_support::pallet_prelude::*; use frame_system::pallet_prelude::*; + /// Collection id type + pub type CollectionId = u64; + #[pallet::pallet] pub struct Pallet(_); @@ -42,6 +45,12 @@ pub mod pallet { // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items pub type Something = StorageValue<_, u32>; + // storage for the ownership of collections + #[pallet::storage] + #[pallet::getter(fn collection_owner)] + pub type CollectionOwner = + StorageMap<_, Blake2_128Concat, CollectionId, T::AccountId, OptionQuery>; + // Pallets use events to inform users when important changes are made. // https://docs.substrate.io/main-docs/build/events-errors/ #[pallet::event] diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs index 7c2b853..7f195d8 100644 --- a/pallets/living-assets-evolution/src/tests.rs +++ b/pallets/living-assets-evolution/src/tests.rs @@ -1,4 +1,4 @@ -use crate::{mock::*, Error, Event}; +use crate::{mock::*, CollectionId, Error, Event}; use frame_support::{assert_noop, assert_ok}; #[test] @@ -25,3 +25,11 @@ fn correct_error_for_none_value() { ); }); } + +#[test] +fn owner_of_unexistent_collection() { + new_test_ext().execute_with(|| { + let collection_id: CollectionId = 0; + assert_eq!(TemplateModule::collection_owner(collection_id), None); + }); +} From bb6486099cc1c2d904107cd5d8ce0d8077e77109 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 14:21:10 +0200 Subject: [PATCH 04/24] create collection implemented --- pallets/living-assets-evolution/src/lib.rs | 37 +++++++++++++++++++- pallets/living-assets-evolution/src/tests.rs | 35 ++++++++++++++++++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 2954b35..5a4fbf3 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -20,6 +20,7 @@ pub use weights::*; pub mod pallet { use super::*; use frame_support::pallet_prelude::*; + use frame_support::sp_runtime::traits::One; use frame_system::pallet_prelude::*; /// Collection id type @@ -45,6 +46,11 @@ pub mod pallet { // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items pub type Something = StorageValue<_, u32>; + /// Collection counter + #[pallet::storage] + #[pallet::getter(fn collection_counter)] + pub(super) type CollectionCounter = StorageValue<_, CollectionId, ValueQuery>; + // storage for the ownership of collections #[pallet::storage] #[pallet::getter(fn collection_owner)] @@ -59,6 +65,10 @@ pub mod pallet { /// Event documentation should end with an array that provides descriptive names for event /// parameters. [something, who] SomethingStored { something: u32, who: T::AccountId }, + + /// Collection created + /// parameters. [collection_id, who] + CollectionCreated { collection_id: CollectionId, who: T::AccountId }, } // Errors inform users that something went wrong. @@ -68,6 +78,8 @@ pub mod pallet { NoneValue, /// Errors should have helpful documentation associated with them. StorageOverflow, + /// The collection ID counter has overflowed + CollectionIdOverflow, } // Dispatchable functions allows users to interact with the pallet and invoke state changes. @@ -94,7 +106,6 @@ pub mod pallet { Ok(()) } - /// An example dispatchable that may throw a custom error. #[pallet::call_index(1)] #[pallet::weight(T::WeightInfo::cause_error())] pub fn cause_error(origin: OriginFor) -> DispatchResult { @@ -113,5 +124,29 @@ pub mod pallet { }, } } + + #[pallet::call_index(2)] + #[pallet::weight(T::WeightInfo::do_something())] + pub fn create_collection(origin: OriginFor) -> DispatchResult { + // Check that the extrinsic was signed and get the signer. + // This function will return an error if the extrinsic is not signed. + // https://docs.substrate.io/main-docs/build/origins/ + let who = ensure_signed(origin)?; + + let collection_id = Self::collection_counter(); + + CollectionOwner::::insert(collection_id, who.clone()); + + // Attempt to increment the collection counter by 1. If this operation + // would result in an overflow, return early with an error + let counter = + collection_id.checked_add(One::one()).ok_or(Error::::CollectionIdOverflow)?; + CollectionCounter::::put(counter); + + Self::deposit_event(Event::CollectionCreated { collection_id, who }); + + // Return a successful DispatchResultWithPostInfo + Ok(()) + } } } diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs index 7f195d8..6c21e7c 100644 --- a/pallets/living-assets-evolution/src/tests.rs +++ b/pallets/living-assets-evolution/src/tests.rs @@ -33,3 +33,38 @@ fn owner_of_unexistent_collection() { assert_eq!(TemplateModule::collection_owner(collection_id), None); }); } + +#[test] +fn create_collection() { + new_test_ext().execute_with(|| { + let collection_id: CollectionId = 0; + assert_eq!(TemplateModule::collection_owner(collection_id), None); + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + assert_eq!(TemplateModule::collection_owner(collection_id), Some(1)); + let collection_id: CollectionId = 1; + assert_eq!(TemplateModule::collection_owner(collection_id), None); + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(2))); + assert_eq!(TemplateModule::collection_owner(collection_id), Some(2)); + }); +} + +#[test] +fn counter_of_collection_increases() { + new_test_ext().execute_with(|| { + assert_eq!(TemplateModule::collection_counter(), 0); + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + assert_eq!(TemplateModule::collection_counter(), 1); + }) +} + +#[test] +fn crete_collection_emits_event() { + new_test_ext().execute_with(|| { + // Go past genesis block so events get deposited + System::set_block_number(1); + // Create a collection + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + // Assert that the correct event was deposited + System::assert_last_event(Event::CollectionCreated { collection_id: 0, who: 1 }.into()); + }); +} From 23df3538bc4ab3d5af36010d1df80fa651c0338f Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 14:23:18 +0200 Subject: [PATCH 05/24] add comment --- pallets/living-assets-evolution/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 5a4fbf3..4ecd424 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -143,6 +143,7 @@ pub mod pallet { collection_id.checked_add(One::one()).ok_or(Error::::CollectionIdOverflow)?; CollectionCounter::::put(counter); + // Emit an event. Self::deposit_event(Event::CollectionCreated { collection_id, who }); // Return a successful DispatchResultWithPostInfo From f648f11c82298e90f83bce007099f72344d7e705 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 14:26:52 +0200 Subject: [PATCH 06/24] removed template code --- pallets/living-assets-evolution/src/lib.rs | 52 -------------------- pallets/living-assets-evolution/src/tests.rs | 29 +---------- 2 files changed, 2 insertions(+), 79 deletions(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 4ecd424..e478ce6 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -38,14 +38,6 @@ pub mod pallet { type WeightInfo: WeightInfo; } - // The pallet's runtime storage items. - // https://docs.substrate.io/main-docs/build/runtime-storage/ - #[pallet::storage] - #[pallet::getter(fn something)] - // Learn more about declaring storage items: - // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items - pub type Something = StorageValue<_, u32>; - /// Collection counter #[pallet::storage] #[pallet::getter(fn collection_counter)] @@ -62,10 +54,6 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Event documentation should end with an array that provides descriptive names for event - /// parameters. [something, who] - SomethingStored { something: u32, who: T::AccountId }, - /// Collection created /// parameters. [collection_id, who] CollectionCreated { collection_id: CollectionId, who: T::AccountId }, @@ -74,10 +62,6 @@ pub mod pallet { // Errors inform users that something went wrong. #[pallet::error] pub enum Error { - /// Error names should be descriptive. - NoneValue, - /// Errors should have helpful documentation associated with them. - StorageOverflow, /// The collection ID counter has overflowed CollectionIdOverflow, } @@ -91,42 +75,6 @@ pub mod pallet { /// storage and emits an event. This function must be dispatched by a signed extrinsic. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::do_something())] - pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { - // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/main-docs/build/origins/ - let who = ensure_signed(origin)?; - - // Update storage. - >::put(something); - - // Emit an event. - Self::deposit_event(Event::SomethingStored { something, who }); - // Return a successful DispatchResultWithPostInfo - Ok(()) - } - - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::cause_error())] - pub fn cause_error(origin: OriginFor) -> DispatchResult { - let _who = ensure_signed(origin)?; - - // Read a value from storage. - match >::get() { - // Return an error if the value has not been set. - None => return Err(Error::::NoneValue.into()), - Some(old) => { - // Increment the value read from storage; will error in the event of overflow. - let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; - // Update the value in storage with the incremented result. - >::put(new); - Ok(()) - }, - } - } - - #[pallet::call_index(2)] - #[pallet::weight(T::WeightInfo::do_something())] pub fn create_collection(origin: OriginFor) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs index 6c21e7c..3189a85 100644 --- a/pallets/living-assets-evolution/src/tests.rs +++ b/pallets/living-assets-evolution/src/tests.rs @@ -1,30 +1,5 @@ -use crate::{mock::*, CollectionId, Error, Event}; -use frame_support::{assert_noop, assert_ok}; - -#[test] -fn it_works_for_default_value() { - new_test_ext().execute_with(|| { - // Go past genesis block so events get deposited - System::set_block_number(1); - // Dispatch a signed extrinsic. - assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); - // Read pallet storage and assert an expected result. - assert_eq!(TemplateModule::something(), Some(42)); - // Assert that the correct event was deposited - System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); - }); -} - -#[test] -fn correct_error_for_none_value() { - new_test_ext().execute_with(|| { - // Ensure the expected error is thrown when no value is present. - assert_noop!( - TemplateModule::cause_error(RuntimeOrigin::signed(1)), - Error::::NoneValue - ); - }); -} +use crate::{mock::*, CollectionId, Event}; +use frame_support::assert_ok; #[test] fn owner_of_unexistent_collection() { From c567e257f5a80708141d5ab70f87a7a89b175dcf Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 17:27:05 +0200 Subject: [PATCH 07/24] benchmark compiling --- .../living-assets-evolution/src/benchmarking.rs | 17 +++-------------- pallets/living-assets-evolution/src/lib.rs | 2 +- 2 files changed, 4 insertions(+), 15 deletions(-) diff --git a/pallets/living-assets-evolution/src/benchmarking.rs b/pallets/living-assets-evolution/src/benchmarking.rs index c4bdcaa..080703f 100644 --- a/pallets/living-assets-evolution/src/benchmarking.rs +++ b/pallets/living-assets-evolution/src/benchmarking.rs @@ -12,23 +12,12 @@ mod benchmarks { use super::*; #[benchmark] - fn do_something() { - let value = 100u32.into(); + fn create_collection() { let caller: T::AccountId = whitelisted_caller(); #[extrinsic_call] - do_something(RawOrigin::Signed(caller), value); + create_collection(RawOrigin::Signed(caller.clone())); - assert_eq!(Something::::get(), Some(value)); - } - - #[benchmark] - fn cause_error() { - Something::::put(100u32); - let caller: T::AccountId = whitelisted_caller(); - #[extrinsic_call] - cause_error(RawOrigin::Signed(caller)); - - assert_eq!(Something::::get(), Some(101u32)); + assert_eq!(CollectionOwner::::get(0), Some(caller)); } impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index e478ce6..ab5daec 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -74,7 +74,7 @@ pub mod pallet { /// An example dispatchable that takes a singles value as a parameter, writes the value to /// storage and emits an event. This function must be dispatched by a signed extrinsic. #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::do_something())] + #[pallet::weight(0)] pub fn create_collection(origin: OriginFor) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. From cb409364ebca14b4d4a3115009d506656ff46eab Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 19:09:04 +0200 Subject: [PATCH 08/24] compiling with benchmark --- node/src/command.rs | 73 +++++++++++++++++++++++++++++++++++++++++++-- node/src/lib.rs | 1 + node/src/main.rs | 1 + node/src/service.rs | 2 +- 4 files changed, 73 insertions(+), 4 deletions(-) diff --git a/node/src/command.rs b/node/src/command.rs index 71d2db7..e2dabe5 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -1,11 +1,14 @@ use crate::{ + benchmarking::{inherent_benchmark_data, RemarkBuilder, TransferKeepAliveBuilder}, chain_spec, cli::{Cli, Subcommand}, service, }; -use laos_evolution_runtime::Block; +use frame_benchmarking_cli::{BenchmarkCmd, ExtrinsicFactory, SUBSTRATE_REFERENCE_HARDWARE}; +use laos_evolution_runtime::{Block, ExistentialDeposit}; use sc_cli::SubstrateCli; use sc_service::PartialComponents; +use sp_keyring::Sr25519Keyring; impl SubstrateCli for Cli { fn impl_name() -> String { @@ -110,8 +113,72 @@ pub fn run() -> sc_cli::Result<()> { Ok((cmd.run(client, backend, Some(aux_revert)), task_manager)) }) }, - Some(Subcommand::Benchmark(_)) => { - todo!("Benchmarking is not supported in Evochain yet") + Some(Subcommand::Benchmark(cmd)) => { + let runner = cli.create_runner(cmd)?; + + runner.sync_run(|config| { + // This switch needs to be in the client, since the client decides + // which sub-commands it wants to support. + match cmd { + BenchmarkCmd::Pallet(cmd) => { + if !cfg!(feature = "runtime-benchmarks") { + return Err( + "Runtime benchmarking wasn't enabled when building the node. \ + You can enable it with `--features runtime-benchmarks`." + .into(), + ) + } + + cmd.run::(config) + }, + BenchmarkCmd::Block(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; + cmd.run(client) + }, + #[cfg(not(feature = "runtime-benchmarks"))] + BenchmarkCmd::Storage(_) => Err( + "Storage benchmarking can be enabled with `--features runtime-benchmarks`." + .into(), + ), + #[cfg(feature = "runtime-benchmarks")] + BenchmarkCmd::Storage(cmd) => { + let PartialComponents { client, backend, .. } = + service::new_partial(&config)?; + let db = backend.expose_db(); + let storage = backend.expose_storage(); + + cmd.run(config, client, db, storage) + }, + BenchmarkCmd::Overhead(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; + let ext_builder = RemarkBuilder::new(client.clone()); + + cmd.run( + config, + client, + inherent_benchmark_data()?, + Vec::new(), + &ext_builder, + ) + }, + BenchmarkCmd::Extrinsic(cmd) => { + let PartialComponents { client, .. } = service::new_partial(&config)?; + // Register the *Remark* and *TKA* builders. + let ext_factory = ExtrinsicFactory(vec![ + Box::new(RemarkBuilder::new(client.clone())), + Box::new(TransferKeepAliveBuilder::new( + client.clone(), + Sr25519Keyring::Alice.to_account_id(), + ExistentialDeposit::get(), + )), + ]); + + cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory) + }, + BenchmarkCmd::Machine(cmd) => + cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), + } + }) }, #[cfg(feature = "try-runtime")] Some(Subcommand::TryRuntime(_cmd)) => { diff --git a/node/src/lib.rs b/node/src/lib.rs index 0e1ab1d..2c70504 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -3,6 +3,7 @@ mod chain_spec; mod service; mod cli; mod command; +mod benchmarking; /// Node run result. pub type Result = sc_cli::Result<()>; diff --git a/node/src/main.rs b/node/src/main.rs index 369e693..1daa8f0 100644 --- a/node/src/main.rs +++ b/node/src/main.rs @@ -4,6 +4,7 @@ mod chain_spec; #[macro_use] mod service; +mod benchmarking; mod cli; mod command; diff --git a/node/src/service.rs b/node/src/service.rs index 7517543..ec76809 100644 --- a/node/src/service.rs +++ b/node/src/service.rs @@ -32,7 +32,7 @@ impl sc_executor::NativeExecutionDispatch for ExecutorDispatch { } } -type FullClient = +pub(crate) type FullClient = sc_service::TFullClient>; type FullBackend = sc_service::TFullBackend; type FullSelectChain = sc_consensus::LongestChain; From 4872c3f20bffea050c9a88eb3a3f003778335abe Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Fri, 15 Sep 2023 19:37:13 +0200 Subject: [PATCH 09/24] simplify --- node/src/lib.rs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/node/src/lib.rs b/node/src/lib.rs index 2c70504..38e4337 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -1,14 +1,2 @@ -mod chain_spec; -#[macro_use] -mod service; -mod cli; -mod command; -mod benchmarking; - -/// Node run result. -pub type Result = sc_cli::Result<()>; - -/// Run node. -pub fn run() -> Result { - command::run() -} +pub mod chain_spec; +pub mod service; From 2d7fca0b7d78a1ce821c2fc79893fb019d36b17b Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 09:56:18 +0200 Subject: [PATCH 10/24] add documentation --- pallets/living-assets-evolution/src/lib.rs | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index ab5daec..615691a 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -71,8 +71,24 @@ pub mod pallet { // Dispatchable functions must be annotated with a weight and must return a DispatchResult. #[pallet::call] impl Pallet { - /// An example dispatchable that takes a singles value as a parameter, writes the value to - /// storage and emits an event. This function must be dispatched by a signed extrinsic. + /// The `create_collection` extrinsic allows users to create a new collection. + /// + /// # Parameters + /// + /// - `origin`: The origin account sending the extrinsic, which will be set as the owner of the new collection. + /// + /// # Storage Changes + /// + /// - `CollectionOwner`: Inserts a new mapping from the generated `collection_id` to the `origin` account. + /// - `CollectionCounter`: Updates the counter for the next available `collection_id`. + /// + /// # Events + /// + /// Emits a `CollectionCreated` event upon successful execution. + /// + /// # Errors + /// + /// - Returns `CollectionIdOverflow` if incrementing the `collection_id` counter would result in an overflow. #[pallet::call_index(0)] #[pallet::weight(0)] pub fn create_collection(origin: OriginFor) -> DispatchResult { From e4e94ed2130267ecff7707a9bea89593da7762b0 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 10:11:11 +0200 Subject: [PATCH 11/24] fmt --- node/src/command.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/node/src/command.rs b/node/src/command.rs index e2dabe5..357b361 100644 --- a/node/src/command.rs +++ b/node/src/command.rs @@ -126,7 +126,7 @@ pub fn run() -> sc_cli::Result<()> { "Runtime benchmarking wasn't enabled when building the node. \ You can enable it with `--features runtime-benchmarks`." .into(), - ) + ); } cmd.run::(config) @@ -175,8 +175,9 @@ pub fn run() -> sc_cli::Result<()> { cmd.run(client, inherent_benchmark_data()?, Vec::new(), &ext_factory) }, - BenchmarkCmd::Machine(cmd) => - cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()), + BenchmarkCmd::Machine(cmd) => { + cmd.run(&config, SUBSTRATE_REFERENCE_HARDWARE.clone()) + }, } }) }, From e034e48e992f3d463c328aa335805651c64969e9 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 10:20:17 +0200 Subject: [PATCH 12/24] update the app database --- .github/actions/setup/action.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b474773..d1540a3 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -5,7 +5,9 @@ runs: steps: - uses: actions/checkout@v3 - name: Install linux dependencies - run: sudo apt-get install -y clang libssl-dev llvm libudev-dev protobuf-compiler + run: | + sudo apt update -yy + sudo apt-get install -y clang libssl-dev llvm libudev-dev protobuf-compiler shell: bash - name: Install Rust run: | From 0f9a43816885ea0d5a26eab20c05368fc602fa89 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 10:29:14 +0200 Subject: [PATCH 13/24] removed warning --- node/src/benchmarking.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/node/src/benchmarking.rs b/node/src/benchmarking.rs index a776e17..116fdba 100644 --- a/node/src/benchmarking.rs +++ b/node/src/benchmarking.rs @@ -84,7 +84,7 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { acc, BalancesCall::transfer_keep_alive { dest: self.dest.clone().into(), - value: self.value.into(), + value: self.value, } .into(), nonce, From 6fd2aa0af49aef7b3ac4e7fccefc739a097dd20d Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 10:32:25 +0200 Subject: [PATCH 14/24] fmt --- node/src/benchmarking.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/node/src/benchmarking.rs b/node/src/benchmarking.rs index 116fdba..0c56b96 100644 --- a/node/src/benchmarking.rs +++ b/node/src/benchmarking.rs @@ -82,11 +82,8 @@ impl frame_benchmarking_cli::ExtrinsicBuilder for TransferKeepAliveBuilder { let extrinsic: OpaqueExtrinsic = create_benchmark_extrinsic( self.client.as_ref(), acc, - BalancesCall::transfer_keep_alive { - dest: self.dest.clone().into(), - value: self.value, - } - .into(), + BalancesCall::transfer_keep_alive { dest: self.dest.clone().into(), value: self.value } + .into(), nonce, ) .into(); From c1eed1b4a55ca31cb436409112f414b479209817 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 15:52:52 +0200 Subject: [PATCH 15/24] create collection (#71) * update with the latest code from substrate template node * pallet-living-assets-evolution * collection_owner * create collection implemented * add comment * removed template code * benchmark compiling * add documentation * update the app database * Update pallets/living-assets-evolution/src/tests.rs Co-authored-by: dastan <137785454+dastanfv@users.noreply.github.com> * Update pallets/living-assets-evolution/src/tests.rs Co-authored-by: dastan <137785454+dastanfv@users.noreply.github.com> * removed part of the README * Update pallets/living-assets-evolution/src/lib.rs Co-authored-by: dastan <137785454+dastanfv@users.noreply.github.com> * fix compilation * fix compilation --------- Co-authored-by: dastan <137785454+dastanfv@users.noreply.github.com> --- .github/actions/setup/action.yml | 4 +- Cargo.lock | 28 +++--- Cargo.toml | 2 +- README.md | 12 --- pallets/living-assets-evolution/Cargo.toml | 36 ++++++++ pallets/living-assets-evolution/README.md | 1 + .../src/benchmarking.rs | 24 +++++ .../src/lib.rs | 89 ++++++++++--------- .../src/mock.rs | 13 ++- pallets/living-assets-evolution/src/tests.rs | 45 ++++++++++ .../src/weights.rs | 13 ++- pallets/template/Cargo.toml | 39 -------- pallets/template/README.md | 1 - pallets/template/src/benchmarking.rs | 35 -------- pallets/template/src/tests.rs | 27 ------ runtime/Cargo.toml | 8 +- runtime/src/lib.rs | 15 ++-- 17 files changed, 196 insertions(+), 196 deletions(-) create mode 100644 pallets/living-assets-evolution/Cargo.toml create mode 100644 pallets/living-assets-evolution/README.md create mode 100644 pallets/living-assets-evolution/src/benchmarking.rs rename pallets/{template => living-assets-evolution}/src/lib.rs (51%) rename pallets/{template => living-assets-evolution}/src/mock.rs (83%) create mode 100644 pallets/living-assets-evolution/src/tests.rs rename pallets/{template => living-assets-evolution}/src/weights.rs (89%) delete mode 100644 pallets/template/Cargo.toml delete mode 100644 pallets/template/README.md delete mode 100644 pallets/template/src/benchmarking.rs delete mode 100644 pallets/template/src/tests.rs diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index b474773..d1540a3 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -5,7 +5,9 @@ runs: steps: - uses: actions/checkout@v3 - name: Install linux dependencies - run: sudo apt-get install -y clang libssl-dev llvm libudev-dev protobuf-compiler + run: | + sudo apt update -yy + sudo apt-get install -y clang libssl-dev llvm libudev-dev protobuf-compiler shell: bash - name: Install Rust run: | diff --git a/Cargo.lock b/Cargo.lock index fad7b95..948eb87 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3622,8 +3622,8 @@ dependencies = [ "pallet-balances", "pallet-bridge-grandpa", "pallet-grandpa", + "pallet-living-assets-evolution", "pallet-sudo", - "pallet-template", "pallet-timestamp", "pallet-transaction-payment", "pallet-transaction-payment-rpc-runtime-api", @@ -4997,53 +4997,53 @@ dependencies = [ ] [[package]] -name = "pallet-session" +name = "pallet-living-assets-evolution" version = "4.0.0-dev" -source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ + "frame-benchmarking", "frame-support", "frame-system", - "impl-trait-for-tuples", - "log", - "pallet-timestamp", "parity-scale-codec", "scale-info", "sp-core", "sp-io", "sp-runtime", - "sp-session", - "sp-staking", - "sp-std", - "sp-trie", ] [[package]] -name = "pallet-sudo" +name = "pallet-session" version = "4.0.0-dev" source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ - "frame-benchmarking", "frame-support", "frame-system", + "impl-trait-for-tuples", + "log", + "pallet-timestamp", "parity-scale-codec", "scale-info", + "sp-core", "sp-io", "sp-runtime", + "sp-session", + "sp-staking", "sp-std", + "sp-trie", ] [[package]] -name = "pallet-template" +name = "pallet-sudo" version = "4.0.0-dev" +source = "git+https://github.com/paritytech/substrate.git?branch=polkadot-v1.0.0#948fbd2fd1233dc26dbb9f9bbc1d2cca2c03945d" dependencies = [ "frame-benchmarking", "frame-support", "frame-system", "parity-scale-codec", "scale-info", - "sp-core", "sp-io", "sp-runtime", + "sp-std", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4e07323..e869ba3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [workspace] members = [ "node", - "pallets/template", + "pallets/living-assets-evolution", "runtime", "primitives" ] diff --git a/README.md b/README.md index 41c1f2b..310aab3 100644 --- a/README.md +++ b/README.md @@ -129,18 +129,6 @@ Review the [FRAME runtime implementation](./runtime/src/lib.rs) included in this Each pallet configuration is defined by a code block that begins with `impl $PALLET_NAME::Config for Runtime`. - The pallets are composed into a single runtime by way of the [`construct_runtime!`](https://crates.parity.io/frame_support/macro.construct_runtime.html) macro, which is part of the core FRAME Support [system](https://docs.substrate.io/reference/frame-pallets/#system-pallets) library. -### Pallets - -The runtime in this project is constructed using many FRAME pallets that ship with the [core Substrate repository](https://github.com/paritytech/substrate/tree/master/frame) and a template pallet that is [defined in the `pallets`](./pallets/template/src/lib.rs) directory. - -A FRAME pallet is compromised of a number of blockchain primitives: - -- Storage: FRAME defines a rich set of powerful [storage abstractions](https://docs.substrate.io/build/runtime-storage/) that makes it easy to use Substrate's efficient key-value database to manage the evolving state of a blockchain. -- Dispatchables: FRAME pallets define special types of functions that can be invoked (dispatched) from outside of the runtime in order to update its state. -- Events: Substrate uses [events and errors](https://docs.substrate.io/build/events-and-errors/) to notify users of important changes in the runtime. -- Errors: When a dispatchable fails, it returns an error. -- Config: The `Config` configuration interface is used to define the types and parameters upon which a FRAME pallet depends. - ## Alternative Installations Instead of installing dependencies and building this source directly, consider the following alternatives. diff --git a/pallets/living-assets-evolution/Cargo.toml b/pallets/living-assets-evolution/Cargo.toml new file mode 100644 index 0000000..7e1bfc7 --- /dev/null +++ b/pallets/living-assets-evolution/Cargo.toml @@ -0,0 +1,36 @@ +[package] +name = "pallet-living-assets-evolution" +version = "4.0.0-dev" +homepage = "https://freeverse.io" +edition = "2021" +license = "MIT-0" +publish = false + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +codec = { package = "parity-scale-codec", version = "3.6.1", default-features = false, features = [ + "derive", +] } +scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } +frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } + +[dev-dependencies] +sp-core = { version = "21.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-io = { version = "23.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-runtime = { version = "24.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } + +[features] +default = ["std"] +std = [ + "codec/std", + "frame-benchmarking?/std", + "frame-support/std", + "frame-system/std", + "scale-info/std", +] +runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/living-assets-evolution/README.md b/pallets/living-assets-evolution/README.md new file mode 100644 index 0000000..d0d5953 --- /dev/null +++ b/pallets/living-assets-evolution/README.md @@ -0,0 +1 @@ +License: MIT-0 \ No newline at end of file diff --git a/pallets/living-assets-evolution/src/benchmarking.rs b/pallets/living-assets-evolution/src/benchmarking.rs new file mode 100644 index 0000000..080703f --- /dev/null +++ b/pallets/living-assets-evolution/src/benchmarking.rs @@ -0,0 +1,24 @@ +//! Benchmarking setup for pallet-living-assets-evolution +#![cfg(feature = "runtime-benchmarks")] +use super::*; + +#[allow(unused)] +use crate::Pallet as Template; +use frame_benchmarking::v2::*; +use frame_system::RawOrigin; + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn create_collection() { + let caller: T::AccountId = whitelisted_caller(); + #[extrinsic_call] + create_collection(RawOrigin::Signed(caller.clone())); + + assert_eq!(CollectionOwner::::get(0), Some(caller)); + } + + impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/pallets/template/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs similarity index 51% rename from pallets/template/src/lib.rs rename to pallets/living-assets-evolution/src/lib.rs index edf7769..de9d255 100644 --- a/pallets/template/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -20,8 +20,12 @@ pub use weights::*; pub mod pallet { use super::*; use frame_support::pallet_prelude::*; + use frame_support::sp_runtime::traits::One; use frame_system::pallet_prelude::*; + /// Collection id type + pub type CollectionId = u64; + #[pallet::pallet] pub struct Pallet(_); @@ -34,31 +38,32 @@ pub mod pallet { type WeightInfo: WeightInfo; } - // The pallet's runtime storage items. - // https://docs.substrate.io/main-docs/build/runtime-storage/ + /// Collection counter + #[pallet::storage] + #[pallet::getter(fn collection_counter)] + pub(super) type CollectionCounter = StorageValue<_, CollectionId, ValueQuery>; + + // storage for the ownership of collections #[pallet::storage] - #[pallet::getter(fn something)] - // Learn more about declaring storage items: - // https://docs.substrate.io/main-docs/build/runtime-storage/#declaring-storage-items - pub type Something = StorageValue<_, u32>; + #[pallet::getter(fn collection_owner)] + pub type CollectionOwner = + StorageMap<_, Blake2_128Concat, CollectionId, T::AccountId, OptionQuery>; // Pallets use events to inform users when important changes are made. // https://docs.substrate.io/main-docs/build/events-errors/ #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { - /// Event documentation should end with an array that provides descriptive names for event - /// parameters. [something, who] - SomethingStored { something: u32, who: T::AccountId }, + /// Collection created + /// parameters. [collection_id, who] + CollectionCreated { collection_id: CollectionId, owner: T::AccountId }, } // Errors inform users that something went wrong. #[pallet::error] pub enum Error { - /// Error names should be descriptive. - NoneValue, - /// Errors should have helpful documentation associated with them. - StorageOverflow, + /// The collection ID counter has overflowed + CollectionIdOverflow, } // Dispatchable functions allows users to interact with the pallet and invoke state changes. @@ -66,43 +71,47 @@ pub mod pallet { // Dispatchable functions must be annotated with a weight and must return a DispatchResult. #[pallet::call] impl Pallet { - /// An example dispatchable that takes a singles value as a parameter, writes the value to - /// storage and emits an event. This function must be dispatched by a signed extrinsic. + /// The `create_collection` extrinsic allows users to create a new collection. + /// + /// # Parameters + /// + /// - `origin`: The origin account sending the extrinsic, which will be set as the owner of the new collection. + /// + /// # Storage Changes + /// + /// - `CollectionOwner`: Inserts a new mapping from the generated `collection_id` to the `origin` account. + /// - `CollectionCounter`: Updates the counter for the next available `collection_id`. + /// + /// # Events + /// + /// Emits a `CollectionCreated` event upon successful execution. + /// + /// # Errors + /// + /// - Returns `CollectionIdOverflow` if incrementing the `collection_id` counter would result in an overflow. #[pallet::call_index(0)] - #[pallet::weight(T::WeightInfo::do_something())] - pub fn do_something(origin: OriginFor, something: u32) -> DispatchResult { + #[pallet::weight(0)] + pub fn create_collection(origin: OriginFor) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. // https://docs.substrate.io/main-docs/build/origins/ let who = ensure_signed(origin)?; - // Update storage. - >::put(something); + let collection_id = Self::collection_counter(); + + CollectionOwner::::insert(collection_id, who.clone()); + + // Attempt to increment the collection counter by 1. If this operation + // would result in an overflow, return early with an error + let counter = + collection_id.checked_add(One::one()).ok_or(Error::::CollectionIdOverflow)?; + CollectionCounter::::put(counter); // Emit an event. - Self::deposit_event(Event::SomethingStored { something, who }); + Self::deposit_event(Event::CollectionCreated { collection_id, owner: who }); + // Return a successful DispatchResultWithPostInfo Ok(()) } - - /// An example dispatchable that may throw a custom error. - #[pallet::call_index(1)] - #[pallet::weight(T::WeightInfo::cause_error())] - pub fn cause_error(origin: OriginFor) -> DispatchResult { - let _who = ensure_signed(origin)?; - - // Read a value from storage. - match >::get() { - // Return an error if the value has not been set. - None => Err(Error::::NoneValue.into()), - Some(old) => { - // Increment the value read from storage; will error in the event of overflow. - let new = old.checked_add(1).ok_or(Error::::StorageOverflow)?; - // Update the value in storage with the incremented result. - >::put(new); - Ok(()) - }, - } - } } } diff --git a/pallets/template/src/mock.rs b/pallets/living-assets-evolution/src/mock.rs similarity index 83% rename from pallets/template/src/mock.rs rename to pallets/living-assets-evolution/src/mock.rs index 8b7236c..9c928a1 100644 --- a/pallets/template/src/mock.rs +++ b/pallets/living-assets-evolution/src/mock.rs @@ -1,4 +1,4 @@ -use crate as pallet_template; +use crate as pallet_living_assets_evolution; use frame_support::traits::{ConstU16, ConstU64}; use sp_core::H256; use sp_runtime::{ @@ -7,14 +7,13 @@ use sp_runtime::{ }; type Block = frame_system::mocking::MockBlock; -type Nonce = u32; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( pub enum Test { System: frame_system, - TemplateModule: pallet_template, + TemplateModule: pallet_living_assets_evolution, } ); @@ -25,12 +24,12 @@ impl frame_system::Config for Test { type DbWeight = (); type RuntimeOrigin = RuntimeOrigin; type RuntimeCall = RuntimeCall; + type Nonce = u64; type Hash = H256; type Hashing = BlakeTwo256; type AccountId = u64; - type Nonce = Nonce; - type Block = Block; type Lookup = IdentityLookup; + type Block = Block; type RuntimeEvent = RuntimeEvent; type BlockHashCount = ConstU64<250>; type Version = (); @@ -44,12 +43,12 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } -impl pallet_template::Config for Test { +impl pallet_living_assets_evolution::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); } // Build genesis storage according to the mock runtime. pub fn new_test_ext() -> sp_io::TestExternalities { - RuntimeGenesisConfig::default().build_storage().unwrap().into() + frame_system::GenesisConfig::::default().build_storage().unwrap().into() } diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs new file mode 100644 index 0000000..6507840 --- /dev/null +++ b/pallets/living-assets-evolution/src/tests.rs @@ -0,0 +1,45 @@ +use crate::{mock::*, CollectionId, Event}; +use frame_support::assert_ok; + +#[test] +fn owner_of_inexistent_collection() { + new_test_ext().execute_with(|| { + let collection_id: CollectionId = 0; + assert_eq!(TemplateModule::collection_owner(collection_id), None); + }); +} + +#[test] +fn create_collection() { + new_test_ext().execute_with(|| { + let collection_id: CollectionId = 0; + assert_eq!(TemplateModule::collection_owner(collection_id), None); + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + assert_eq!(TemplateModule::collection_owner(collection_id), Some(1)); + let collection_id: CollectionId = 1; + assert_eq!(TemplateModule::collection_owner(collection_id), None); + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(2))); + assert_eq!(TemplateModule::collection_owner(collection_id), Some(2)); + }); +} + +#[test] +fn counter_of_collection_increases() { + new_test_ext().execute_with(|| { + assert_eq!(TemplateModule::collection_counter(), 0); + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + assert_eq!(TemplateModule::collection_counter(), 1); + }) +} + +#[test] +fn create_collection_emits_event() { + new_test_ext().execute_with(|| { + // Go past genesis block so events get deposited + System::set_block_number(1); + // Create a collection + assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + // Assert that the correct event was deposited + System::assert_last_event(Event::CollectionCreated { collection_id: 0, owner: 1 }.into()); + }); +} diff --git a/pallets/template/src/weights.rs b/pallets/living-assets-evolution/src/weights.rs similarity index 89% rename from pallets/template/src/weights.rs rename to pallets/living-assets-evolution/src/weights.rs index a497666..2648b91 100644 --- a/pallets/template/src/weights.rs +++ b/pallets/living-assets-evolution/src/weights.rs @@ -1,5 +1,5 @@ -//! Autogenerated weights for pallet_template +//! Autogenerated weights for pallet_living_assets_evolution //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev //! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` @@ -8,21 +8,20 @@ //! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 // Executed Command: -// ../../target/release/laos-evolution +// ../../target/release/node-template // benchmark // pallet // --chain // dev // --pallet -// pallet_template +// pallet_living_assets_evolution // --extrinsic // * // --steps=50 // --repeat=20 -// --execution=wasm // --wasm-execution=compiled // --output -// pallets/template/src/weights.rs +// pallets/living-assets-evolution/src/weights.rs // --template // ../../.maintain/frame-weight-template.hbs @@ -33,13 +32,13 @@ use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_template. +/// Weight functions needed for pallet_living_assets_evolution. pub trait WeightInfo { fn do_something() -> Weight; fn cause_error() -> Weight; } -/// Weights for pallet_template using the Substrate node and recommended hardware. +/// Weights for pallet_living_assets_evolution using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { /// Storage: TemplateModule Something (r:0 w:1) diff --git a/pallets/template/Cargo.toml b/pallets/template/Cargo.toml deleted file mode 100644 index 2394866..0000000 --- a/pallets/template/Cargo.toml +++ /dev/null @@ -1,39 +0,0 @@ -[package] -name = "pallet-template" -version = "4.0.0-dev" -description = "FRAME pallet template for defining custom runtime logic." -authors = ["Substrate DevHub "] -homepage = "https://substrate.io" -edition = "2021" -license = "MIT-0" -publish = false -repository = "https://github.com/substrate-developer-hub/substrate-laos-evolution/" - -[package.metadata.docs.rs] -targets = ["x86_64-unknown-linux-gnu"] - -[dependencies] -codec = { package = "parity-scale-codec", version = "3.2.2", default-features = false, features = [ - "derive", -] } -scale-info = { version = "2.5.0", default-features = false, features = ["derive"] } -frame-benchmarking = { default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -frame-support = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -frame-system = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } - -[dev-dependencies] -sp-core = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -sp-io = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } -sp-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } - -[features] -default = ["std"] -std = [ - "codec/std", - "frame-benchmarking?/std", - "frame-support/std", - "frame-system/std", - "scale-info/std", -] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] -try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/template/README.md b/pallets/template/README.md deleted file mode 100644 index 9e4dc55..0000000 --- a/pallets/template/README.md +++ /dev/null @@ -1 +0,0 @@ -License: MIT-0 diff --git a/pallets/template/src/benchmarking.rs b/pallets/template/src/benchmarking.rs deleted file mode 100644 index d1a9554..0000000 --- a/pallets/template/src/benchmarking.rs +++ /dev/null @@ -1,35 +0,0 @@ -//! Benchmarking setup for pallet-template -#![cfg(feature = "runtime-benchmarks")] -use super::*; - -#[allow(unused)] -use crate::Pallet as Template; -use frame_benchmarking::v2::*; -use frame_system::RawOrigin; - -#[benchmarks] -mod benchmarks { - use super::*; - - #[benchmark] - fn do_something() { - let value = 100u32; - let caller: T::AccountId = whitelisted_caller(); - #[extrinsic_call] - do_something(RawOrigin::Signed(caller), value); - - assert_eq!(Something::::get(), Some(value)); - } - - #[benchmark] - fn cause_error() { - Something::::put(100u32); - let caller: T::AccountId = whitelisted_caller(); - #[extrinsic_call] - cause_error(RawOrigin::Signed(caller)); - - assert_eq!(Something::::get(), Some(101u32)); - } - - impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); -} diff --git a/pallets/template/src/tests.rs b/pallets/template/src/tests.rs deleted file mode 100644 index 7c2b853..0000000 --- a/pallets/template/src/tests.rs +++ /dev/null @@ -1,27 +0,0 @@ -use crate::{mock::*, Error, Event}; -use frame_support::{assert_noop, assert_ok}; - -#[test] -fn it_works_for_default_value() { - new_test_ext().execute_with(|| { - // Go past genesis block so events get deposited - System::set_block_number(1); - // Dispatch a signed extrinsic. - assert_ok!(TemplateModule::do_something(RuntimeOrigin::signed(1), 42)); - // Read pallet storage and assert an expected result. - assert_eq!(TemplateModule::something(), Some(42)); - // Assert that the correct event was deposited - System::assert_last_event(Event::SomethingStored { something: 42, who: 1 }.into()); - }); -} - -#[test] -fn correct_error_for_none_value() { - new_test_ext().execute_with(|| { - // Ensure the expected error is thrown when no value is present. - assert_noop!( - TemplateModule::cause_error(RuntimeOrigin::signed(1)), - Error::::NoneValue - ); - }); -} diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 5d90cd2..8be7c0d 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -51,7 +51,7 @@ frame-benchmarking = { default-features = false, git = "https://github.com/parit frame-system-benchmarking = { default-features = false, git = "https://github.com/paritytech/substrate.git", optional = true , branch = "polkadot-v1.0.0" } # Local Dependencies -pallet-template = { default-features = false, path = "../pallets/template" } +pallet-living-assets-evolution = { default-features = false, path = "../pallets/living-assets-evolution" } fp-account = { git = "https://github.com/paritytech/frontier.git", branch = "polkadot-v1.0.0", default-features = false, features = ["serde"] } # Bridge dependencies @@ -81,7 +81,7 @@ std = [ "pallet-balances/std", "pallet-grandpa/std", "pallet-sudo/std", - "pallet-template/std", + "pallet-living-assets-evolution/std", "pallet-timestamp/std", "pallet-transaction-payment-rpc-runtime-api/std", "pallet-transaction-payment/std", @@ -112,7 +112,7 @@ runtime-benchmarks = [ "pallet-balances/runtime-benchmarks", "pallet-grandpa/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", - "pallet-template/runtime-benchmarks", + "pallet-living-assets-evolution/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", ] @@ -125,7 +125,7 @@ try-runtime = [ "pallet-balances/try-runtime", "pallet-grandpa/try-runtime", "pallet-sudo/try-runtime", - "pallet-template/try-runtime", + "pallet-living-assets-evolution/try-runtime", "pallet-timestamp/try-runtime", "pallet-transaction-payment/try-runtime", "sp-runtime/try-runtime", diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 6cb1e1b..2e12bf9 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -46,8 +46,7 @@ use pallet_transaction_payment::{ConstFeeMultiplier, CurrencyAdapter, Multiplier pub use sp_runtime::BuildStorage; pub use sp_runtime::{Perbill, Permill}; -/// Import the template pallet. -pub use pallet_template; +pub use pallet_living_assets_evolution; /// An index to a block. pub type BlockNumber = evochain_primitives::BlockNumber; @@ -272,10 +271,10 @@ impl pallet_sudo::Config for Runtime { type WeightInfo = pallet_sudo::weights::SubstrateWeight; } -/// Configure the pallet-template in pallets/template. -impl pallet_template::Config for Runtime { +/// Configure the pallet-living-assets-evolution in pallets/living-assets-evolution. +impl pallet_living_assets_evolution::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type WeightInfo = pallet_template::weights::SubstrateWeight; + type WeightInfo = pallet_living_assets_evolution::weights::SubstrateWeight; } impl pallet_bridge_grandpa::Config for Runtime { @@ -297,8 +296,8 @@ construct_runtime!( TransactionPayment: pallet_transaction_payment, Sudo: pallet_sudo, - // Include the custom logic from the pallet-template in the runtime. - TemplateModule: pallet_template, + // Include the custom logic from the pallet-living-assets-evolution in the runtime. + TemplateModule: pallet_living_assets_evolution, BridgeRococoGrandpa: pallet_bridge_grandpa, } @@ -347,7 +346,7 @@ mod benches { [frame_system, SystemBench::] [pallet_balances, Balances] [pallet_timestamp, Timestamp] - [pallet_template, TemplateModule] + [pallet_living_assets_evolution, TemplateModule] ); } From 849104b6201c3a9191773d99d1887b8a55ca3001 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Mon, 18 Sep 2023 15:53:56 +0200 Subject: [PATCH 16/24] create collection weight (#74) * set the weight for living assets pallet * running weight for all the pallet --- pallets/living-assets-evolution/src/lib.rs | 2 +- .../living-assets-evolution/src/weights.rs | 89 ++++++++----------- 2 files changed, 36 insertions(+), 55 deletions(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 615691a..afe535b 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -90,7 +90,7 @@ pub mod pallet { /// /// - Returns `CollectionIdOverflow` if incrementing the `collection_id` counter would result in an overflow. #[pallet::call_index(0)] - #[pallet::weight(0)] + #[pallet::weight(T::WeightInfo::create_collection())] pub fn create_collection(origin: OriginFor) -> DispatchResult { // Check that the extrinsic was signed and get the signer. // This function will return an error if the extrinsic is not signed. diff --git a/pallets/living-assets-evolution/src/weights.rs b/pallets/living-assets-evolution/src/weights.rs index 2648b91..25712d1 100644 --- a/pallets/living-assets-evolution/src/weights.rs +++ b/pallets/living-assets-evolution/src/weights.rs @@ -1,90 +1,71 @@ -//! Autogenerated weights for pallet_living_assets_evolution +//! Autogenerated weights for `pallet_living_assets_evolution` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-04-06, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `Alexs-MacBook-Pro-2.local`, CPU: `` -//! EXECUTION: Some(Wasm), WASM-EXECUTION: Compiled, CHAIN: Some("dev"), DB CACHE: 1024 +//! HOSTNAME: `titan`, CPU: `12th Gen Intel(R) Core(TM) i7-1260P` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: -// ../../target/release/node-template +// ./target/release/laos-evolution // benchmark // pallet -// --chain -// dev -// --pallet -// pallet_living_assets_evolution -// --extrinsic -// * +// --chain=dev +// --pallet=pallet_living_assets_evolution +// --extrinsic=* // --steps=50 // --repeat=20 // --wasm-execution=compiled // --output -// pallets/living-assets-evolution/src/weights.rs +// ./pallets/living-assets-evolution/src/weights.rs // --template -// ../../.maintain/frame-weight-template.hbs +// ../polkadot-sdk/substrate/.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] #![allow(unused_imports)] +#![allow(missing_docs)] use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; use core::marker::PhantomData; -/// Weight functions needed for pallet_living_assets_evolution. +/// Weight functions needed for `pallet_living_assets_evolution`. pub trait WeightInfo { - fn do_something() -> Weight; - fn cause_error() -> Weight; + fn create_collection() -> Weight; } -/// Weights for pallet_living_assets_evolution using the Substrate node and recommended hardware. +/// Weights for `pallet_living_assets_evolution` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: TemplateModule Something (r:0 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn do_something() -> Weight { + /// Storage: `TemplateModule::CollectionCounter` (r:1 w:1) + /// Proof: `TemplateModule::CollectionCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TemplateModule::CollectionOwner` (r:0 w:1) + /// Proof: `TemplateModule::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + fn create_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(T::DbWeight::get().writes(1_u64)) - } - /// Storage: TemplateModule Something (r:1 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn cause_error() -> Weight { - // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(6_000_000, 1489) + // Measured: `6` + // Estimated: `1493` + // Minimum execution time: 9_275_000 picoseconds. + Weight::from_parts(9_835_000, 1493) .saturating_add(T::DbWeight::get().reads(1_u64)) - .saturating_add(T::DbWeight::get().writes(1_u64)) + .saturating_add(T::DbWeight::get().writes(2_u64)) } } -// For backwards compatibility and tests +// For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: TemplateModule Something (r:0 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn do_something() -> Weight { - // Proof Size summary in bytes: - // Measured: `0` - // Estimated: `0` - // Minimum execution time: 8_000_000 picoseconds. - Weight::from_parts(9_000_000, 0) - .saturating_add(RocksDbWeight::get().writes(1_u64)) - } - /// Storage: TemplateModule Something (r:1 w:1) - /// Proof: TemplateModule Something (max_values: Some(1), max_size: Some(4), added: 499, mode: MaxEncodedLen) - fn cause_error() -> Weight { + /// Storage: `TemplateModule::CollectionCounter` (r:1 w:1) + /// Proof: `TemplateModule::CollectionCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `TemplateModule::CollectionOwner` (r:0 w:1) + /// Proof: `TemplateModule::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + fn create_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `32` - // Estimated: `1489` - // Minimum execution time: 6_000_000 picoseconds. - Weight::from_parts(6_000_000, 1489) + // Measured: `6` + // Estimated: `1493` + // Minimum execution time: 9_275_000 picoseconds. + Weight::from_parts(9_835_000, 1493) .saturating_add(RocksDbWeight::get().reads(1_u64)) - .saturating_add(RocksDbWeight::get().writes(1_u64)) + .saturating_add(RocksDbWeight::get().writes(2_u64)) } } From 068d966d702adeadb2c87c997be181c63e63b1ad Mon Sep 17 00:00:00 2001 From: dastan <137785454+dastanfv@users.noreply.github.com> Date: Tue, 26 Sep 2023 12:54:42 +0300 Subject: [PATCH 17/24] Mint assets in Evochain (#76) * Add code * Add weights * Add tests and events * Separate events * Some more renamings * Revert comments * Use doc strings * Add tests and asset id conversion * Use u128 for slot * Rename getter * Fix test * Add overflow check * Resolve comments * Remove asset owner, regenerate weights --- .maintain/frame-weight-template.hbs | 121 ++++++++++ Cargo.lock | 1 + Cargo.toml | 2 + node/src/lib.rs | 3 + pallets/living-assets-evolution/Cargo.toml | 20 +- .../src/benchmarking.rs | 27 ++- pallets/living-assets-evolution/src/lib.rs | 160 ++++++++++++-- pallets/living-assets-evolution/src/mock.rs | 35 ++- pallets/living-assets-evolution/src/tests.rs | 208 ++++++++++++++++-- pallets/living-assets-evolution/src/types.rs | 39 ++++ .../living-assets-evolution/src/weights.rs | 66 ++++-- runtime/Cargo.toml | 1 + runtime/src/lib.rs | 27 ++- 13 files changed, 635 insertions(+), 75 deletions(-) create mode 100644 .maintain/frame-weight-template.hbs create mode 100644 pallets/living-assets-evolution/src/types.rs diff --git a/.maintain/frame-weight-template.hbs b/.maintain/frame-weight-template.hbs new file mode 100644 index 0000000..ecd384a --- /dev/null +++ b/.maintain/frame-weight-template.hbs @@ -0,0 +1,121 @@ +{{header}} +//! Autogenerated weights for `{{pallet}}` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION {{version}} +//! DATE: {{date}}, STEPS: `{{cmd.steps}}`, REPEAT: `{{cmd.repeat}}`, LOW RANGE: `{{cmd.lowest_range_values}}`, HIGH RANGE: `{{cmd.highest_range_values}}` +//! WORST CASE MAP SIZE: `{{cmd.worst_case_map_values}}` +//! HOSTNAME: `{{hostname}}`, CPU: `{{cpuname}}` +//! WASM-EXECUTION: `{{cmd.wasm_execution}}`, CHAIN: `{{cmd.chain}}`, DB CACHE: `{{cmd.db_cache}}` + +// Executed Command: +{{#each args as |arg|}} +// {{arg}} +{{/each}} + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] +#![allow(missing_docs)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use core::marker::PhantomData; + +/// Weight functions needed for `{{pallet}}`. +pub trait WeightInfo { + {{#each benchmarks as |benchmark|}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{c.name}}: u32, {{/each~}} + ) -> Weight; + {{/each}} +} + +/// Weights for `{{pallet}}` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +{{#if (eq pallet "frame_system")}} +impl WeightInfo for SubstrateWeight { +{{else}} +impl WeightInfo for SubstrateWeight { +{{/if}} + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(T::DbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(T::DbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(T::DbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(T::DbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + {{#each benchmarks as |benchmark|}} + {{#each benchmark.comments as |comment|}} + /// {{comment}} + {{/each}} + {{#each benchmark.component_ranges as |range|}} + /// The range of component `{{range.name}}` is `[{{range.min}}, {{range.max}}]`. + {{/each}} + fn {{benchmark.name~}} + ( + {{~#each benchmark.components as |c| ~}} + {{~#if (not c.is_used)}}_{{/if}}{{c.name}}: u32, {{/each~}} + ) -> Weight { + // Proof Size summary in bytes: + // Measured: `{{benchmark.base_recorded_proof_size}}{{#each benchmark.component_recorded_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Estimated: `{{benchmark.base_calculated_proof_size}}{{#each benchmark.component_calculated_proof_size as |cp|}} + {{cp.name}} * ({{cp.slope}} ±{{underscore cp.error}}){{/each}}` + // Minimum execution time: {{underscore benchmark.min_execution_time}}_000 picoseconds. + Weight::from_parts({{underscore benchmark.base_weight}}, {{benchmark.base_calculated_proof_size}}) + {{#each benchmark.component_weight as |cw|}} + // Standard Error: {{underscore cw.error}} + .saturating_add(Weight::from_parts({{underscore cw.slope}}, 0).saturating_mul({{cw.name}}.into())) + {{/each}} + {{#if (ne benchmark.base_reads "0")}} + .saturating_add(RocksDbWeight::get().reads({{benchmark.base_reads}}_u64)) + {{/if}} + {{#each benchmark.component_reads as |cr|}} + .saturating_add(RocksDbWeight::get().reads(({{cr.slope}}_u64).saturating_mul({{cr.name}}.into()))) + {{/each}} + {{#if (ne benchmark.base_writes "0")}} + .saturating_add(RocksDbWeight::get().writes({{benchmark.base_writes}}_u64)) + {{/if}} + {{#each benchmark.component_writes as |cw|}} + .saturating_add(RocksDbWeight::get().writes(({{cw.slope}}_u64).saturating_mul({{cw.name}}.into()))) + {{/each}} + {{#each benchmark.component_calculated_proof_size as |cp|}} + .saturating_add(Weight::from_parts(0, {{cp.slope}}).saturating_mul({{cp.name}}.into())) + {{/each}} + } + {{/each}} +} diff --git a/Cargo.lock b/Cargo.lock index 948eb87..9deb36a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5008,6 +5008,7 @@ dependencies = [ "sp-core", "sp-io", "sp-runtime", + "sp-std", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index e869ba3..66c33a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,5 +5,7 @@ members = [ "runtime", "primitives" ] +resolver = "2" + [profile.release] panic = "unwind" diff --git a/node/src/lib.rs b/node/src/lib.rs index 38e4337..8ea98be 100644 --- a/node/src/lib.rs +++ b/node/src/lib.rs @@ -1,2 +1,5 @@ +pub mod benchmarking; pub mod chain_spec; +pub mod cli; +pub mod command; pub mod service; diff --git a/pallets/living-assets-evolution/Cargo.toml b/pallets/living-assets-evolution/Cargo.toml index 7e1bfc7..40eab04 100644 --- a/pallets/living-assets-evolution/Cargo.toml +++ b/pallets/living-assets-evolution/Cargo.toml @@ -17,9 +17,11 @@ scale-info = { version = "2.5.0", default-features = false, features = ["derive" frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } frame-support = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } frame-system = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-runtime = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-core = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } +sp-std = { default-features = false, git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } [dev-dependencies] -sp-core = { version = "21.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } sp-io = { version = "23.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } sp-runtime = { version = "24.0.0", git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v1.0.0" } @@ -31,6 +33,18 @@ std = [ "frame-support/std", "frame-system/std", "scale-info/std", + "sp-core/std", + "sp-runtime/std", + "sp-std/std", +] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "frame-support/runtime-benchmarks", + "frame-system/runtime-benchmarks", + "sp-runtime/runtime-benchmarks", +] +try-runtime = [ + "frame-support/try-runtime", + "frame-system/try-runtime", + "sp-runtime/try-runtime", ] -runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"] -try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/living-assets-evolution/src/benchmarking.rs b/pallets/living-assets-evolution/src/benchmarking.rs index 080703f..f447f27 100644 --- a/pallets/living-assets-evolution/src/benchmarking.rs +++ b/pallets/living-assets-evolution/src/benchmarking.rs @@ -3,8 +3,9 @@ use super::*; #[allow(unused)] -use crate::Pallet as Template; +use crate::Pallet as LivingAssetsEvo; use frame_benchmarking::v2::*; +use frame_support::traits::Get; use frame_system::RawOrigin; #[benchmarks] @@ -20,5 +21,27 @@ mod benchmarks { assert_eq!(CollectionOwner::::get(0), Some(caller)); } - impl_benchmark_test_suite!(Template, crate::mock::new_test_ext(), crate::mock::Test); + #[benchmark] + fn mint_with_external_uri() { + let caller: T::AccountId = whitelisted_caller(); + LivingAssetsEvo::::create_collection(RawOrigin::Signed(caller.clone()).into()).unwrap(); + + let token_uri: TokenUriOf = + vec![0; T::MaxTokenUriLength::get() as usize].try_into().unwrap(); + let slot = 0; + let token_id = LivingAssetsEvo::::slot_and_owner_to_token_id((slot, caller.clone())); + + #[extrinsic_call] + mint_with_external_uri( + RawOrigin::Signed(caller.clone()), + 0, + slot, + caller.clone(), + token_uri.clone(), + ); + + assert_eq!(TokenURI::::get(0, token_id), Some(token_uri)); + } + + impl_benchmark_test_suite!(LivingAssetsEvo, crate::mock::new_test_ext(), crate::mock::Test); } diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 54ef3fd..79f2af1 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -1,10 +1,6 @@ #![cfg_attr(not(feature = "std"), no_std)] -/// Edit this file to define custom logic or remove it if it is not needed. -/// Learn more about FRAME and the core library of Substrate FRAME pallets: -/// pub use pallet::*; - #[cfg(test)] mod mock; @@ -13,18 +9,22 @@ mod tests; #[cfg(feature = "runtime-benchmarks")] mod benchmarking; +mod types; pub mod weights; + +use types::*; pub use weights::*; +use sp_core::H160; +use sp_runtime::traits::Convert; + #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::pallet_prelude::*; use frame_support::sp_runtime::traits::One; use frame_system::pallet_prelude::*; - - /// Collection id type - pub type CollectionId = u64; + use sp_runtime::ArithmeticError; #[pallet::pallet] pub struct Pallet(_); @@ -34,8 +34,13 @@ pub mod pallet { pub trait Config: frame_system::Config { /// Because this pallet emits events, it depends on the runtime's definition of an event. type RuntimeEvent: From> + IsType<::RuntimeEvent>; + /// Limit for the length of `token_uri` + #[pallet::constant] + type MaxTokenUriLength: Get; /// Type representing the weight of this pallet type WeightInfo: WeightInfo; + /// Converts [`AccountId`] to [`H160`] + type AccountIdToH160: Convert, H160>; } /// Collection counter @@ -43,27 +48,53 @@ pub mod pallet { #[pallet::getter(fn collection_counter)] pub(super) type CollectionCounter = StorageValue<_, CollectionId, ValueQuery>; - // storage for the ownership of collections + /// Storage for the ownership of collections #[pallet::storage] #[pallet::getter(fn collection_owner)] pub type CollectionOwner = - StorageMap<_, Blake2_128Concat, CollectionId, T::AccountId, OptionQuery>; + StorageMap<_, Blake2_128Concat, CollectionId, AccountIdOf, OptionQuery>; - // Pallets use events to inform users when important changes are made. - // https://docs.substrate.io/main-docs/build/events-errors/ + /// Token URI which can override the default URI scheme and set explicitly + /// This will contain external URI in a raw form + #[pallet::storage] + #[pallet::getter(fn token_uri)] + pub type TokenURI = StorageDoubleMap< + _, + Blake2_128Concat, + CollectionId, + Blake2_128Concat, + TokenId, + TokenUriOf, + OptionQuery, + >; + + /// Events for this pallet. #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Collection created /// parameters. [collection_id, who] - CollectionCreated { collection_id: CollectionId, owner: T::AccountId }, + CollectionCreated { collection_id: CollectionId, owner: AccountIdOf }, + /// Asset minted + /// [collection_id, slot, to, token_uri] + MintedWithExternalTokenURI { + collection_id: CollectionId, + slot: Slot, + to: AccountIdOf, + token_uri: TokenUriOf, + token_id: TokenId, + }, } // Errors inform users that something went wrong. #[pallet::error] pub enum Error { - /// The collection ID counter has overflowed - CollectionIdOverflow, + /// Collection does not exist + CollectionDoesNotExist, + /// Not the owner of the collection + NoPermission, + /// [`Slot`] is already minted + AlreadyMinted, } // Dispatchable functions allows users to interact with the pallet and invoke state changes. @@ -79,22 +110,19 @@ pub mod pallet { /// /// # Storage Changes /// - /// - `CollectionOwner`: Inserts a new mapping from the generated `collection_id` to the `origin` account. - /// - `CollectionCounter`: Updates the counter for the next available `collection_id`. + /// - [`CollectionOwner`](`CollectionOwner`): Inserts a new mapping from the generated `collection_id` to the `origin` account. + /// - [`CollectionCounter`](`CollectionCounter`): Updates the counter for the next available `collection_id`. /// /// # Events /// - /// Emits a `CollectionCreated` event upon successful execution. + /// Emits a [`CollectionCreated`](`Event::::CollectionCreated`) event upon successful execution. /// /// # Errors /// - /// - Returns `CollectionIdOverflow` if incrementing the `collection_id` counter would result in an overflow. + /// - Returns [`Overflow`](`ArithmeticError::::Overflow`) if incrementing the `collection_id` counter would result in an overflow. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::create_collection())] pub fn create_collection(origin: OriginFor) -> DispatchResult { - // Check that the extrinsic was signed and get the signer. - // This function will return an error if the extrinsic is not signed. - // https://docs.substrate.io/main-docs/build/origins/ let who = ensure_signed(origin)?; let collection_id = Self::collection_counter(); @@ -103,15 +131,99 @@ pub mod pallet { // Attempt to increment the collection counter by 1. If this operation // would result in an overflow, return early with an error - let counter = - collection_id.checked_add(One::one()).ok_or(Error::::CollectionIdOverflow)?; + let counter = collection_id.checked_add(One::one()).ok_or(ArithmeticError::Overflow)?; CollectionCounter::::put(counter); // Emit an event. Self::deposit_event(Event::CollectionCreated { collection_id, owner: who }); - // Return a successful DispatchResultWithPostInfo + // Return a successful DispatchResult Ok(()) } + + /// Mint new asset with external URI + /// + /// This function performs the minting of a new asset with setting its external URI. + /// + /// NOTE: This function will panic if the `slot` has a value greater than `2^96 - 1` + /// This will be fixed in the future https://github.com/freeverseio/laos-evolution-node/issues/77 + /// + /// # Errors + /// + /// This function returns a dispatch error in the following cases: + /// + /// * [`NoPermission`](`Error::::NoPermission`) - if the caller is not the owner of the collection + /// * [`CollectionDoesNotExist`](`Error::::CollectionDoesNotExist`) - if the collection does not exist + /// * [`AlreadyMinted`](`Error::::AlreadyMinted`) - if the asset is already minted + /// * [`Overflow`](`ArithmeticError::::Overflow`) - if the `slot` is greater than `2^96 - 1` + #[pallet::call_index(1)] + #[pallet::weight(T::WeightInfo::mint_with_external_uri())] + pub fn mint_with_external_uri( + origin: OriginFor, + collection_id: CollectionId, + slot: Slot, + to: AccountIdOf, + token_uri: TokenUriOf, + ) -> DispatchResult { + let who = ensure_signed(origin)?; + + ensure!( + CollectionOwner::::contains_key(collection_id), + Error::::CollectionDoesNotExist + ); + + ensure!( + CollectionOwner::::get(collection_id) == Some(who), + Error::::NoPermission + ); + + // compose asset_id from slot and owner + let token_id = Self::slot_and_owner_to_token_id((slot, to.clone())); + + ensure!( + TokenURI::::get(collection_id, token_id).is_none(), + Error::::AlreadyMinted + ); + + // Slot must be 96 bits + // TODO: use a custom type for this https://github.com/freeverseio/laos-evolution-node/issues/77 + ensure!(slot <= MAX_U96, ArithmeticError::Overflow); + + TokenURI::::insert(collection_id, token_id, token_uri.clone()); + + Self::deposit_event(Event::MintedWithExternalTokenURI { + collection_id, + slot, + to, + token_id, + token_uri, + }); + + Ok(()) + } + } +} + +impl Pallet { + // Utility functions + /// A struct responsible for converting `Slot` and `AccountId` to `TokenId` + /// + /// Every slot is identified by a unique `token_id` where `token_id = concat(slot #, owner_address)` + fn slot_and_owner_to_token_id(slot_and_owner: (Slot, AccountIdOf)) -> TokenId { + let (slot, owner) = slot_and_owner; + + let mut bytes = [0u8; 32]; + + let slot_bytes = slot.to_be_bytes(); + + // NOTE: this will panic at runtime if two arrays overlap, we should see if there is a safer way to do this + // we also use the last 12 bytes of the slot, since the first 4 bytes are always 0 + bytes[..12].copy_from_slice(&slot_bytes[4..]); + + let h160 = T::AccountIdToH160::convert(owner); + let account_id_bytes = h160.as_fixed_bytes(); + + bytes[12..].copy_from_slice(account_id_bytes); + TokenId::from(bytes) } } diff --git a/pallets/living-assets-evolution/src/mock.rs b/pallets/living-assets-evolution/src/mock.rs index 9c928a1..6317812 100644 --- a/pallets/living-assets-evolution/src/mock.rs +++ b/pallets/living-assets-evolution/src/mock.rs @@ -1,8 +1,11 @@ use crate as pallet_living_assets_evolution; -use frame_support::traits::{ConstU16, ConstU64}; -use sp_core::H256; +use frame_support::{ + parameter_types, + traits::{ConstU16, ConstU64}, +}; +use sp_core::{H160, H256}; use sp_runtime::{ - traits::{BlakeTwo256, IdentityLookup}, + traits::{BlakeTwo256, Convert, IdentityLookup}, BuildStorage, }; @@ -13,10 +16,11 @@ frame_support::construct_runtime!( pub enum Test { System: frame_system, - TemplateModule: pallet_living_assets_evolution, + LivingAssets: pallet_living_assets_evolution, } ); +pub type AccountId = u64; impl frame_system::Config for Test { type BaseCallFilter = frame_support::traits::Everything; type BlockWeights = (); @@ -27,7 +31,7 @@ impl frame_system::Config for Test { type Nonce = u64; type Hash = H256; type Hashing = BlakeTwo256; - type AccountId = u64; + type AccountId = AccountId; type Lookup = IdentityLookup; type Block = Block; type RuntimeEvent = RuntimeEvent; @@ -43,9 +47,30 @@ impl frame_system::Config for Test { type MaxConsumers = frame_support::traits::ConstU32<16>; } +parameter_types! { + pub const MaxTokenUriLength: u32 = 512; +} + +/// A struct responsible for converting an `AccountId` to an `H160` address. +/// +/// The `AccountIdToH160` struct provides a conversion from `AccountId`, typically used +/// as a native identity in a blockchain, to an `H160` address, commonly used in Ethereum-like networks. +pub struct MockAccountIdToH160; +impl Convert for MockAccountIdToH160 { + fn convert(account_id: AccountId) -> H160 { + let mut bytes = [0u8; 20]; + let account_id_bytes = account_id.to_be_bytes(); + + bytes[0..8].copy_from_slice(&account_id_bytes); + H160::from(bytes) + } +} + impl pallet_living_assets_evolution::Config for Test { type RuntimeEvent = RuntimeEvent; type WeightInfo = (); + type AccountIdToH160 = MockAccountIdToH160; + type MaxTokenUriLength = MaxTokenUriLength; } // Build genesis storage according to the mock runtime. diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs index 13a899d..a4e4d1a 100644 --- a/pallets/living-assets-evolution/src/tests.rs +++ b/pallets/living-assets-evolution/src/tests.rs @@ -1,34 +1,46 @@ -use crate::{mock::*, CollectionId, Event}; -use frame_support::assert_ok; +use crate::{ + mock::*, + types::{TokenId, TokenUriOf, MAX_U96}, + CollectionId, Error, Event, +}; +use frame_support::{assert_noop, assert_ok}; +use sp_runtime::traits::Convert; + +/// Utility function to create a collection and return its ID +fn create_collection(owner: u64) -> CollectionId { + let collection_id = LivingAssets::collection_counter(); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(owner))); + collection_id +} #[test] -fn owner_of_unexistent_collection() { +fn owner_of_inexistent_collection() { new_test_ext().execute_with(|| { let collection_id: CollectionId = 0; - assert_eq!(TemplateModule::collection_owner(collection_id), None); + assert_eq!(LivingAssets::collection_owner(collection_id), None); }); } #[test] -fn create_collection() { +fn create_collection_works() { new_test_ext().execute_with(|| { let collection_id: CollectionId = 0; - assert_eq!(TemplateModule::collection_owner(collection_id), None); - assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); - assert_eq!(TemplateModule::collection_owner(collection_id), Some(1)); + assert_eq!(LivingAssets::collection_owner(collection_id), None); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1))); + assert_eq!(LivingAssets::collection_owner(collection_id), Some(1)); let collection_id: CollectionId = 1; - assert_eq!(TemplateModule::collection_owner(collection_id), None); - assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(2))); - assert_eq!(TemplateModule::collection_owner(collection_id), Some(2)); + assert_eq!(LivingAssets::collection_owner(collection_id), None); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(2))); + assert_eq!(LivingAssets::collection_owner(collection_id), Some(2)); }); } #[test] fn counter_of_collection_increases() { new_test_ext().execute_with(|| { - assert_eq!(TemplateModule::collection_counter(), 0); - assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); - assert_eq!(TemplateModule::collection_counter(), 1); + assert_eq!(LivingAssets::collection_counter(), 0); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1))); + assert_eq!(LivingAssets::collection_counter(), 1); }) } @@ -37,9 +49,171 @@ fn create_collection_emits_event() { new_test_ext().execute_with(|| { // Go past genesis block so events get deposited System::set_block_number(1); - // Create a collection - assert_ok!(TemplateModule::create_collection(RuntimeOrigin::signed(1))); + let collection_id = create_collection(1); + // Assert that the correct event was deposited - System::assert_last_event(Event::CollectionCreated { collection_id: 0, owner: 1 }.into()); + System::assert_last_event(Event::CollectionCreated { collection_id, owner: 1 }.into()); + }); +} + +#[test] +fn mint_with_external_uri_works() { + new_test_ext().execute_with(|| { + System::set_block_number(1); + + let collection_id = create_collection(1); + let token_uri: TokenUriOf = + vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); + let slot = 0; + let owner = 1; + + assert_ok!(LivingAssets::mint_with_external_uri( + RuntimeOrigin::signed(1), + collection_id, + slot, + owner, + token_uri.clone() + )); + + let expected_token_id = { + let mut buf = [0u8; 32]; + buf[..12].copy_from_slice(&slot.to_be_bytes()[4..]); + buf[12..].copy_from_slice( + ::AccountIdToH160::convert(owner).as_fixed_bytes(), + ); + + TokenId::from(buf) + }; + + let token_id = LivingAssets::slot_and_owner_to_token_id((slot, owner)); + + assert_eq!(token_id, expected_token_id); + assert_eq!(LivingAssets::token_uri(collection_id, token_id), Some(token_uri.clone())); + + System::assert_has_event( + Event::MintedWithExternalTokenURI { + collection_id, + slot, + to: owner, + token_id: expected_token_id, + token_uri, + } + .into(), + ); + }); +} + +#[test] +fn slot_and_owner_to_asset_id_works() { + let slot = 0; + let owner = 0; + + let expected_token_id = [0u8; 32].into(); + + assert_eq!(LivingAssets::slot_and_owner_to_token_id((slot, owner)), expected_token_id); + + let mut expected_token_id_bytes = [0; 32]; + + let slot = 1_u128; + let owner: AccountId = 1; + let mut owner_bytes = [0u8; 20]; + owner_bytes[0..8].copy_from_slice(&owner.to_be_bytes()); + expected_token_id_bytes[..12].copy_from_slice(&slot.to_be_bytes()[4..]); + expected_token_id_bytes[12..].copy_from_slice(&owner_bytes); + + assert_eq!( + LivingAssets::slot_and_owner_to_token_id((slot, owner)), + TokenId::from(expected_token_id_bytes) + ); +} + +#[test] +fn mint_with_external_uri_non_owner() { + new_test_ext().execute_with(|| { + let collection_id = create_collection(1); + let token_uri: TokenUriOf = + vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); + + assert_noop!( + LivingAssets::mint_with_external_uri( + RuntimeOrigin::signed(2), + collection_id, + 0, + 1, + token_uri.clone() + ), + Error::::NoPermission + ); + }); +} + +#[test] +fn mint_with_external_uri_collection_does_not_exist() { + new_test_ext().execute_with(|| { + // simply use the collection counter as collection id, do not create the collection + let collection_id = LivingAssets::collection_counter(); + + let token_uri: TokenUriOf = + vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); + + assert_noop!( + LivingAssets::mint_with_external_uri( + RuntimeOrigin::signed(1), + collection_id, + 0, + 1, + token_uri.clone() + ), + Error::::CollectionDoesNotExist + ); + }); +} + +#[test] +fn mint_with_external_uri_asset_already_minted() { + new_test_ext().execute_with(|| { + let collection_id = LivingAssets::collection_counter(); + let token_uri: TokenUriOf = + vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); + + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1))); + assert_ok!(LivingAssets::mint_with_external_uri( + RuntimeOrigin::signed(1), + collection_id, + 0, + 1, + token_uri.clone() + )); + + assert_noop!( + LivingAssets::mint_with_external_uri( + RuntimeOrigin::signed(1), + collection_id, + 0, + 1, + token_uri.clone() + ), + Error::::AlreadyMinted + ); + }); +} + +#[test] +fn slot_overflow() { + new_test_ext().execute_with(|| { + let collection_id = create_collection(1); + let token_uri: TokenUriOf = + vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); + + assert_noop!( + LivingAssets::mint_with_external_uri( + RuntimeOrigin::signed(1), + collection_id, + MAX_U96 + 1, // pass a value greater than 2^96 - 1 + 1, + token_uri.clone() + ), + sp_runtime::ArithmeticError::Overflow + ); }); } diff --git a/pallets/living-assets-evolution/src/types.rs b/pallets/living-assets-evolution/src/types.rs new file mode 100644 index 0000000..653b2a6 --- /dev/null +++ b/pallets/living-assets-evolution/src/types.rs @@ -0,0 +1,39 @@ +//! Types used in the pallet + +use codec::{Decode, Encode}; +use frame_support::traits::Get; +use scale_info::TypeInfo; +use sp_core::U256; +use sp_runtime::BoundedVec; + +/// Collection id type +pub type CollectionId = u64; + +/// Explicit `AccountId` +pub type AccountIdOf = ::AccountId; + +/// Wrapper around `BoundedVec` for `tokenUri` +pub type TokenUriOf = BoundedVec::MaxTokenUriLength>; + +/// TokenId type +/// every slot is identified by a unique `asset_id = concat(slot #, owner_address)` +pub type TokenId = U256; + +/// Slot type - 96-bit unsigned integer +/// +/// NOTE: `u128` is used since there is no native support for 96-bit integers in Rust and using `[u8;12]` is bad for UX +/// Maybe in the future we can use a custom type for this +pub type Slot = u128; + +/// Max value of `Slot`, used for validation +pub const MAX_U96: Slot = (1 << 96) - 1; + +/// Asset metadata +#[derive(Encode, Decode, Clone, PartialEq, Eq, sp_core::RuntimeDebug, TypeInfo)] +pub enum AssetMetadata> { + /// Explicit token URI + External { + /// Token URI + token_uri: BoundedVec, + }, +} diff --git a/pallets/living-assets-evolution/src/weights.rs b/pallets/living-assets-evolution/src/weights.rs index 5f1f456..09f3729 100644 --- a/pallets/living-assets-evolution/src/weights.rs +++ b/pallets/living-assets-evolution/src/weights.rs @@ -2,9 +2,9 @@ //! Autogenerated weights for `pallet_living_assets_evolution` //! //! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev -//! DATE: 2023-09-18, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! DATE: 2023-09-26, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]` //! WORST CASE MAP SIZE: `1000000` -//! HOSTNAME: `titan`, CPU: `12th Gen Intel(R) Core(TM) i7-1260P` +//! HOSTNAME: `MacBook-Pro.local`, CPU: `` //! WASM-EXECUTION: `Compiled`, CHAIN: `Some("dev")`, DB CACHE: `1024` // Executed Command: @@ -14,14 +14,11 @@ // --chain=dev // --pallet=pallet_living_assets_evolution // --extrinsic=* -// * // --steps=50 // --repeat=20 // --wasm-execution=compiled -// --output -// ./pallets/living-assets-evolution/src/weights.rs -// --template -// ../polkadot-sdk/substrate/.maintain/frame-weight-template.hbs +// --output=./pallets/living-assets-evolution/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs #![cfg_attr(rustfmt, rustfmt_skip)] #![allow(unused_parens)] @@ -34,39 +31,66 @@ use core::marker::PhantomData; /// Weight functions needed for `pallet_living_assets_evolution`. pub trait WeightInfo { fn create_collection() -> Weight; + fn mint_with_external_uri() -> Weight; } /// Weights for `pallet_living_assets_evolution` using the Substrate node and recommended hardware. pub struct SubstrateWeight(PhantomData); impl WeightInfo for SubstrateWeight { - /// Storage: `TemplateModule::CollectionCounter` (r:1 w:1) - /// Proof: `TemplateModule::CollectionCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `TemplateModule::CollectionOwner` (r:0 w:1) - /// Proof: `TemplateModule::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `LivingAssetsEvolution::CollectionCounter` (r:1 w:1) + /// Proof: `LivingAssetsEvolution::CollectionCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `LivingAssetsEvolution::CollectionOwner` (r:0 w:1) + /// Proof: `LivingAssetsEvolution::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) fn create_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `6` + // Measured: `42` // Estimated: `1493` - // Minimum execution time: 9_275_000 picoseconds. - Weight::from_parts(9_835_000, 1493) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 1493) .saturating_add(T::DbWeight::get().reads(1_u64)) .saturating_add(T::DbWeight::get().writes(2_u64)) } + /// Storage: `LivingAssetsEvolution::CollectionOwner` (r:1 w:0) + /// Proof: `LivingAssetsEvolution::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `LivingAssetsEvolution::TokenURI` (r:1 w:1) + /// Proof: `LivingAssetsEvolution::TokenURI` (`max_values`: None, `max_size`: Some(586), added: 3061, mode: `MaxEncodedLen`) + fn mint_with_external_uri() -> Weight { + // Proof Size summary in bytes: + // Measured: `152` + // Estimated: `4051` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 4051) + .saturating_add(T::DbWeight::get().reads(2_u64)) + .saturating_add(T::DbWeight::get().writes(1_u64)) + } } // For backwards compatibility and tests. impl WeightInfo for () { - /// Storage: `TemplateModule::CollectionCounter` (r:1 w:1) - /// Proof: `TemplateModule::CollectionCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) - /// Storage: `TemplateModule::CollectionOwner` (r:0 w:1) - /// Proof: `TemplateModule::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `LivingAssetsEvolution::CollectionCounter` (r:1 w:1) + /// Proof: `LivingAssetsEvolution::CollectionCounter` (`max_values`: Some(1), `max_size`: Some(8), added: 503, mode: `MaxEncodedLen`) + /// Storage: `LivingAssetsEvolution::CollectionOwner` (r:0 w:1) + /// Proof: `LivingAssetsEvolution::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) fn create_collection() -> Weight { // Proof Size summary in bytes: - // Measured: `6` + // Measured: `42` // Estimated: `1493` - // Minimum execution time: 9_275_000 picoseconds. - Weight::from_parts(9_835_000, 1493) + // Minimum execution time: 12_000_000 picoseconds. + Weight::from_parts(13_000_000, 1493) .saturating_add(RocksDbWeight::get().reads(1_u64)) .saturating_add(RocksDbWeight::get().writes(2_u64)) } + /// Storage: `LivingAssetsEvolution::CollectionOwner` (r:1 w:0) + /// Proof: `LivingAssetsEvolution::CollectionOwner` (`max_values`: None, `max_size`: Some(56), added: 2531, mode: `MaxEncodedLen`) + /// Storage: `LivingAssetsEvolution::TokenURI` (r:1 w:1) + /// Proof: `LivingAssetsEvolution::TokenURI` (`max_values`: None, `max_size`: Some(586), added: 3061, mode: `MaxEncodedLen`) + fn mint_with_external_uri() -> Weight { + // Proof Size summary in bytes: + // Measured: `152` + // Estimated: `4051` + // Minimum execution time: 20_000_000 picoseconds. + Weight::from_parts(21_000_000, 4051) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + .saturating_add(RocksDbWeight::get().writes(1_u64)) + } } diff --git a/runtime/Cargo.toml b/runtime/Cargo.toml index 8be7c0d..0f69310 100644 --- a/runtime/Cargo.toml +++ b/runtime/Cargo.toml @@ -115,6 +115,7 @@ runtime-benchmarks = [ "pallet-living-assets-evolution/runtime-benchmarks", "pallet-timestamp/runtime-benchmarks", "sp-runtime/runtime-benchmarks", + "pallet-bridge-grandpa/runtime-benchmarks", ] try-runtime = [ "frame-try-runtime/try-runtime", diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 2e12bf9..38e1abd 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -9,7 +9,7 @@ include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs")); use pallet_grandpa::AuthorityId as GrandpaId; use sp_api::impl_runtime_apis; use sp_consensus_aura::sr25519::AuthorityId as AuraId; -use sp_core::{crypto::KeyTypeId, OpaqueMetadata}; +use sp_core::{crypto::KeyTypeId, OpaqueMetadata, H160}; use sp_runtime::{ create_runtime_str, generic, impl_opaque_keys, traits::{Block as BlockT, NumberFor, One}, @@ -271,10 +271,31 @@ impl pallet_sudo::Config for Runtime { type WeightInfo = pallet_sudo::weights::SubstrateWeight; } +parameter_types! { + /// Max length of the `TokenUri` + pub const MaxTokenUriLength: u32 = 512; +} + +/// A struct responsible for converting an `AccountId` to an `H160` address. +/// +/// The `AccountIdToH160` struct provides a conversion from `AccountId`, typically used +/// as a native identity in a blockchain, to an `H160` address, commonly used in Ethereum-like networks. +pub struct AccountIdToH160; +impl sp_runtime::traits::Convert for AccountIdToH160 { + fn convert(account_id: AccountId) -> H160 { + let mut bytes = [0u8; 20]; + let account_id_bytes: [u8; 32] = account_id.into(); + bytes.copy_from_slice(&account_id_bytes[account_id_bytes.len() - 20..]); + H160::from(bytes) + } +} + /// Configure the pallet-living-assets-evolution in pallets/living-assets-evolution. impl pallet_living_assets_evolution::Config for Runtime { type RuntimeEvent = RuntimeEvent; type WeightInfo = pallet_living_assets_evolution::weights::SubstrateWeight; + type AccountIdToH160 = AccountIdToH160; + type MaxTokenUriLength = MaxTokenUriLength; } impl pallet_bridge_grandpa::Config for Runtime { @@ -297,7 +318,7 @@ construct_runtime!( Sudo: pallet_sudo, // Include the custom logic from the pallet-living-assets-evolution in the runtime. - TemplateModule: pallet_living_assets_evolution, + LivingAssetsEvolution: pallet_living_assets_evolution, BridgeRococoGrandpa: pallet_bridge_grandpa, } @@ -346,7 +367,7 @@ mod benches { [frame_system, SystemBench::] [pallet_balances, Balances] [pallet_timestamp, Timestamp] - [pallet_living_assets_evolution, TemplateModule] + [pallet_living_assets_evolution, LivingAssetsEvolution] ); } From d1cf6e9ec9081f047113c4024763d959a63ecd8f Mon Sep 17 00:00:00 2001 From: dastan <137785454+dastanfv@users.noreply.github.com> Date: Tue, 26 Sep 2023 13:13:28 +0300 Subject: [PATCH 18/24] Update lib.rs (#78) --- pallets/living-assets-evolution/src/lib.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index 79f2af1..b251246 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -216,7 +216,6 @@ impl Pallet { let slot_bytes = slot.to_be_bytes(); - // NOTE: this will panic at runtime if two arrays overlap, we should see if there is a safer way to do this // we also use the last 12 bytes of the slot, since the first 4 bytes are always 0 bytes[..12].copy_from_slice(&slot_bytes[4..]); From 806bf22a5438ddcbe294f256607992f82d33f625 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Tue, 26 Sep 2023 14:40:14 +0200 Subject: [PATCH 19/24] added owner param in the create_collection exstrinsic --- pallets/living-assets-evolution/src/lib.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/pallets/living-assets-evolution/src/lib.rs b/pallets/living-assets-evolution/src/lib.rs index b251246..5d2652a 100644 --- a/pallets/living-assets-evolution/src/lib.rs +++ b/pallets/living-assets-evolution/src/lib.rs @@ -106,11 +106,12 @@ pub mod pallet { /// /// # Parameters /// - /// - `origin`: The origin account sending the extrinsic, which will be set as the owner of the new collection. + /// - `origin`: The origin account sending the extrinsic. + /// - `owner`: The account that will be set as the owner of the new collection. /// /// # Storage Changes /// - /// - [`CollectionOwner`](`CollectionOwner`): Inserts a new mapping from the generated `collection_id` to the `origin` account. + /// - [`CollectionOwner`](`CollectionOwner`): Inserts a new mapping from the generated `collection_id` to the `owner` account. /// - [`CollectionCounter`](`CollectionCounter`): Updates the counter for the next available `collection_id`. /// /// # Events @@ -122,12 +123,12 @@ pub mod pallet { /// - Returns [`Overflow`](`ArithmeticError::::Overflow`) if incrementing the `collection_id` counter would result in an overflow. #[pallet::call_index(0)] #[pallet::weight(T::WeightInfo::create_collection())] - pub fn create_collection(origin: OriginFor) -> DispatchResult { - let who = ensure_signed(origin)?; + pub fn create_collection(origin: OriginFor, owner: T::AccountId) -> DispatchResult { + ensure_signed(origin)?; let collection_id = Self::collection_counter(); - CollectionOwner::::insert(collection_id, who.clone()); + CollectionOwner::::insert(collection_id, owner.clone()); // Attempt to increment the collection counter by 1. If this operation // would result in an overflow, return early with an error @@ -135,7 +136,7 @@ pub mod pallet { CollectionCounter::::put(counter); // Emit an event. - Self::deposit_event(Event::CollectionCreated { collection_id, owner: who }); + Self::deposit_event(Event::CollectionCreated { collection_id, owner }); // Return a successful DispatchResult Ok(()) From b9789b84e1737268ce563e39cc8e145ccd13337a Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Tue, 26 Sep 2023 15:02:29 +0200 Subject: [PATCH 20/24] fix tests --- pallets/living-assets-evolution/src/tests.rs | 22 ++++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs index a4e4d1a..146df81 100644 --- a/pallets/living-assets-evolution/src/tests.rs +++ b/pallets/living-assets-evolution/src/tests.rs @@ -6,10 +6,13 @@ use crate::{ use frame_support::{assert_noop, assert_ok}; use sp_runtime::traits::Convert; +const ALICE: AccountId = 5; +const BOB: AccountId = 6; + /// Utility function to create a collection and return its ID fn create_collection(owner: u64) -> CollectionId { let collection_id = LivingAssets::collection_counter(); - assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(owner))); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(owner), owner)); collection_id } @@ -26,12 +29,12 @@ fn create_collection_works() { new_test_ext().execute_with(|| { let collection_id: CollectionId = 0; assert_eq!(LivingAssets::collection_owner(collection_id), None); - assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1))); - assert_eq!(LivingAssets::collection_owner(collection_id), Some(1)); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1), ALICE)); + assert_eq!(LivingAssets::collection_owner(collection_id), Some(ALICE)); let collection_id: CollectionId = 1; assert_eq!(LivingAssets::collection_owner(collection_id), None); - assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(2))); - assert_eq!(LivingAssets::collection_owner(collection_id), Some(2)); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1), BOB)); + assert_eq!(LivingAssets::collection_owner(collection_id), Some(BOB)); }); } @@ -39,7 +42,7 @@ fn create_collection_works() { fn counter_of_collection_increases() { new_test_ext().execute_with(|| { assert_eq!(LivingAssets::collection_counter(), 0); - assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1))); + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1), ALICE)); assert_eq!(LivingAssets::collection_counter(), 1); }) } @@ -176,9 +179,10 @@ fn mint_with_external_uri_asset_already_minted() { let token_uri: TokenUriOf = vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); - assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1))); + + assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1), ALICE)); assert_ok!(LivingAssets::mint_with_external_uri( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(ALICE), collection_id, 0, 1, @@ -187,7 +191,7 @@ fn mint_with_external_uri_asset_already_minted() { assert_noop!( LivingAssets::mint_with_external_uri( - RuntimeOrigin::signed(1), + RuntimeOrigin::signed(ALICE), collection_id, 0, 1, From dd2871fbeb5773914fc1fba2af862896c38fa039 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Tue, 26 Sep 2023 15:24:15 +0200 Subject: [PATCH 21/24] fmt --- pallets/living-assets-evolution/src/tests.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/pallets/living-assets-evolution/src/tests.rs b/pallets/living-assets-evolution/src/tests.rs index 146df81..faa1253 100644 --- a/pallets/living-assets-evolution/src/tests.rs +++ b/pallets/living-assets-evolution/src/tests.rs @@ -179,7 +179,6 @@ fn mint_with_external_uri_asset_already_minted() { let token_uri: TokenUriOf = vec![1, MaxTokenUriLength::get() as u8].try_into().unwrap(); - assert_ok!(LivingAssets::create_collection(RuntimeOrigin::signed(1), ALICE)); assert_ok!(LivingAssets::mint_with_external_uri( RuntimeOrigin::signed(ALICE), From faee338e07eafbe24e63b76cb090441576bc2c25 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Tue, 26 Sep 2023 15:40:32 +0200 Subject: [PATCH 22/24] fix clippy --- pallets/living-assets-evolution/src/benchmarking.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pallets/living-assets-evolution/src/benchmarking.rs b/pallets/living-assets-evolution/src/benchmarking.rs index f447f27..c130245 100644 --- a/pallets/living-assets-evolution/src/benchmarking.rs +++ b/pallets/living-assets-evolution/src/benchmarking.rs @@ -15,8 +15,9 @@ mod benchmarks { #[benchmark] fn create_collection() { let caller: T::AccountId = whitelisted_caller(); + let owner = caller.clone(); #[extrinsic_call] - create_collection(RawOrigin::Signed(caller.clone())); + create_collection(RawOrigin::Signed(caller.clone()), owner); assert_eq!(CollectionOwner::::get(0), Some(caller)); } @@ -24,7 +25,8 @@ mod benchmarks { #[benchmark] fn mint_with_external_uri() { let caller: T::AccountId = whitelisted_caller(); - LivingAssetsEvo::::create_collection(RawOrigin::Signed(caller.clone()).into()).unwrap(); + let owner = caller.clone(); + LivingAssetsEvo::::create_collection(RawOrigin::Signed(caller.clone()).into(), owner).unwrap(); let token_uri: TokenUriOf = vec![0; T::MaxTokenUriLength::get() as usize].try_into().unwrap(); From 14b1b9554ab7f22c73ec77181aed4b37c1fb5030 Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Tue, 26 Sep 2023 15:58:02 +0200 Subject: [PATCH 23/24] fmt --- pallets/living-assets-evolution/src/benchmarking.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/pallets/living-assets-evolution/src/benchmarking.rs b/pallets/living-assets-evolution/src/benchmarking.rs index c130245..de465b5 100644 --- a/pallets/living-assets-evolution/src/benchmarking.rs +++ b/pallets/living-assets-evolution/src/benchmarking.rs @@ -26,7 +26,8 @@ mod benchmarks { fn mint_with_external_uri() { let caller: T::AccountId = whitelisted_caller(); let owner = caller.clone(); - LivingAssetsEvo::::create_collection(RawOrigin::Signed(caller.clone()).into(), owner).unwrap(); + LivingAssetsEvo::::create_collection(RawOrigin::Signed(caller.clone()).into(), owner) + .unwrap(); let token_uri: TokenUriOf = vec![0; T::MaxTokenUriLength::get() as usize].try_into().unwrap(); From 71f6f9c27fdb18f561a35838575916209ce0c59f Mon Sep 17 00:00:00 2001 From: Alessandro Siniscalchi Date: Tue, 26 Sep 2023 16:16:16 +0200 Subject: [PATCH 24/24] runtime spec_version 101->102 --- runtime/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/runtime/src/lib.rs b/runtime/src/lib.rs index 38e1abd..cc18df5 100644 --- a/runtime/src/lib.rs +++ b/runtime/src/lib.rs @@ -106,7 +106,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion { // `spec_version`, and `authoring_version` are the same between Wasm and native. // This value is set to 100 to notify Polkadot-JS App (https://polkadot.js.org/apps) to use // the compatible custom types. - spec_version: 101, + spec_version: 102, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1,