From aa60b88b71d20f3eb89c16e45ff0ef44262baab4 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 6 Jul 2024 16:51:04 +0200 Subject: [PATCH 01/34] outline --- Cargo.lock | 36 ++++++++++++++ Cargo.toml | 2 + pallets/orders/Cargo.toml | 4 ++ pallets/orders/src/lib.rs | 7 +++ pallets/orders/src/types.rs | 30 ------------ pallets/processor/Cargo.toml | 59 ++++++++++++++++++++++ pallets/processor/src/lib.rs | 94 ++++++++++++++++++++++++++++++++++++ 7 files changed, 202 insertions(+), 30 deletions(-) create mode 100644 pallets/processor/Cargo.toml create mode 100644 pallets/processor/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index c92c35b2..9eda63b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6036,6 +6036,19 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "order-primitives" +version = "0.1.0" +dependencies = [ + "cumulus-primitives-core", + "frame-support", + "log", + "pallet-broker", + "parity-scale-codec", + "scale-info", + "sp-core", +] + [[package]] name = "ordered-float" version = "1.1.1" @@ -6967,6 +6980,7 @@ dependencies = [ "frame-support", "frame-system", "log", + "order-primitives", "pallet-balances", "pallet-broker", "parity-scale-codec", @@ -6998,6 +7012,28 @@ dependencies = [ "sp-std", ] +[[package]] +name = "pallet-processor" +version = "0.1.0" +dependencies = [ + "frame-benchmarking", + "frame-support", + "frame-system", + "log", + "order-primitives", + "pallet-balances", + "pallet-broker", + "parity-scale-codec", + "scale-info", + "serde", + "sp-core", + "sp-io", + "sp-runtime", + "staging-xcm", + "staging-xcm-builder", + "staging-xcm-executor", +] + [[package]] name = "pallet-proxy" version = "28.0.0" diff --git a/Cargo.toml b/Cargo.toml index bd517704..72841de6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -158,8 +158,10 @@ ismp-testsuite = { git = "https://github.com/polytope-labs/hyperbridge.git", bra # Local region-primitives = { path = "./primitives/region", default-features = false } nonfungible-primitives = { path = "./primitives/nonfungible", default-features = false } +order-primitives = { path = "./primitives/order", default-features = false } regionx-runtime-common = { path = "./runtime/common", default-features = false } cocos-runtime = { path = "./runtime/cocos", default-features = false } pallet-market = { path = "./pallets/market", default-features = false } pallet-orders = { path = "./pallets/orders", default-features = false } +pallet-processor = { path = "./pallets/processor", default-features = false } pallet-regions = { path = "./pallets/regions", default-features = false } diff --git a/pallets/orders/Cargo.toml b/pallets/orders/Cargo.toml index 37ec0536..a5ee22da 100644 --- a/pallets/orders/Cargo.toml +++ b/pallets/orders/Cargo.toml @@ -25,6 +25,9 @@ sp-runtime = { workspace = true, default-features = false } pallet-broker = { workspace = true, default-features = false } xcm-executor = { workspace = true, default-features = false } +# Local +order-primitives = { workspace = true, default-features = false } + [dev-dependencies] serde = { workspace = true } pallet-balances = { workspace = true, default-features = false } @@ -50,6 +53,7 @@ std = [ "frame-system/std", "pallet-broker/std", "pallet-balances/std", + "order-primitives/std", "xcm/std", "xcm-executor/std", "xcm-builder/std", diff --git a/pallets/orders/src/lib.rs b/pallets/orders/src/lib.rs index 9411ef11..7a805653 100644 --- a/pallets/orders/src/lib.rs +++ b/pallets/orders/src/lib.rs @@ -16,6 +16,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::traits::Currency; +use order_primitives::{Order, OrderId, OrderInspect, Requirements}; pub use pallet::*; use pallet_broker::Timeslice; use sp_runtime::{traits::BlockNumberProvider, SaturatedConversion}; @@ -287,4 +288,10 @@ pub mod pallet { (latest_rc_block / timeslice_period).saturated_into() } } + + impl OrderInspect for Pallet { + fn order(order_id: &OrderId) -> Option> { + Orders::::get(order_id) + } + } } diff --git a/pallets/orders/src/types.rs b/pallets/orders/src/types.rs index b133b524..48e6a6cb 100644 --- a/pallets/orders/src/types.rs +++ b/pallets/orders/src/types.rs @@ -13,42 +13,12 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . use crate::BalanceOf; -use codec::{Decode, Encode, MaxEncodedLen}; pub use cumulus_primitives_core::ParaId; -use pallet_broker::{PartsOf57600, Timeslice}; -use scale_info::TypeInfo; use sp_runtime::DispatchResult; pub type RegionRecordOf = pallet_broker::RegionRecord<::AccountId, BalanceOf>; -/// Order identifier. -pub type OrderId = u32; - -/// The region requirements of an order. -#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct Requirements { - /// The timeslice at which the Region begins. - pub begin: Timeslice, - /// The timeslice at which the Region ends. - pub end: Timeslice, - /// The minimum fraction of the core that the region should occupy. - pub core_occupancy: PartsOf57600, -} - -/// The information we store about a Coretime order. -#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] -pub struct Order { - /// The `AccountId` that created the order. - /// - /// In most cases this will probably be the sovereign account of the parachain. - pub creator: AccountId, - /// The para id to which Coretime will be allocated. - pub para_id: ParaId, - /// Region requirements of the order. - pub requirements: Requirements, -} - pub trait FeeHandler { /// Function responsible for handling how we deal with fees. fn handle(who: &AccountId, fee: Balance) -> DispatchResult; diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml new file mode 100644 index 00000000..4acff66a --- /dev/null +++ b/pallets/processor/Cargo.toml @@ -0,0 +1,59 @@ +[package] +name = "pallet-processor" +authors = ["Anonymous"] +description = "Pallet for processing coretime orders" +version = "0.1.0" +license = "GPLv3" +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +log = { workspace = true } +codec = { workspace = true, default-features = false, features = ["derive"] } +scale-info = { workspace = true, default-features = false, features = ["derive"] } + +# Substrate +frame-benchmarking = { workspace = true, default-features = false, optional = true } +frame-support = { workspace = true, default-features = false } +frame-system = { workspace = true, default-features = false } +sp-io = { workspace = true, default-features = false } +sp-core = { workspace = true, default-features = false } +sp-runtime = { workspace = true, default-features = false } +pallet-broker = { workspace = true, default-features = false } +xcm-executor = { workspace = true, default-features = false } + +# Local +order-primitives = { workspace = true, default-features = false } + +[dev-dependencies] +serde = { workspace = true } +pallet-balances = { workspace = true, default-features = false } +xcm = { workspace = true, default-features = false } +xcm-builder = { workspace = true, default-features = false } + +[features] +default = ["std"] +runtime-benchmarks = [ + "frame-benchmarking/runtime-benchmarks", + "xcm-builder/runtime-benchmarks", +] +std = [ + "log/std", + "codec/std", + "scale-info/std", + "sp-io/std", + "sp-core/std", + "sp-runtime/std", + "frame-benchmarking/std", + "frame-support/std", + "frame-system/std", + "pallet-broker/std", + "pallet-balances/std", + "order-primitives/std", + "xcm/std", + "xcm-executor/std", + "xcm-builder/std", +] +try-runtime = ["frame-support/try-runtime"] diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs new file mode 100644 index 00000000..ff7ad929 --- /dev/null +++ b/pallets/processor/src/lib.rs @@ -0,0 +1,94 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . + +#![cfg_attr(not(feature = "std"), no_std)] + +use frame_support::traits::Currency; +use frame_system::WeightInfo; +use order_primitives::{OrderId, OrderInspect}; +pub use pallet::*; +use pallet_broker::RegionId; + +pub type BalanceOf = + <::Currency as Currency<::AccountId>>::Balance; + +#[frame_support::pallet] +pub mod pallet { + use super::*; + use frame_support::{ + pallet_prelude::*, + traits::{fungible::Mutate, Get, ReservableCurrency}, + }; + use frame_system::pallet_prelude::*; + + /// The module configuration trait. + #[pallet::config] + pub trait Config: frame_system::Config { + /// The overarching event type. + type RuntimeEvent: From> + IsType<::RuntimeEvent>; + + /// Currency used for purchasing coretime. + type Currency: Mutate + ReservableCurrency; + + /// Type over which we can access order data. + type Orders: OrderInspect; + + /// Weight Info + type WeightInfo: WeightInfo; + } + + #[pallet::pallet] + pub struct Pallet(_); + + #[pallet::event] + #[pallet::generate_deposit(pub(super) fn deposit_event)] + pub enum Event {} + + #[pallet::error] + #[derive(PartialEq)] + pub enum Error { + /// Invalid order id. + InvalidOrderId, + } + + #[pallet::hooks] + impl Hooks> for Pallet { + fn on_initialize(_: BlockNumberFor) -> Weight { + + Weight::zero() + } + } + + #[pallet::call] + impl Pallet { + #[pallet::call_index(0)] + #[pallet::weight(10_000)] + pub fn fulfill_order( + origin: OriginFor, + order_id: OrderId, + region_id: RegionId, + ) -> DispatchResult { + // TODO + + // Maybe move this to the orders pallet? + + // PROS: simpler + + // CONS: Adds opinionation. + + Ok(()) + } + } +} From e3a1853facb326c94947d577ba075380ff5ee2c7 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 6 Jul 2024 16:56:04 +0200 Subject: [PATCH 02/34] add primitives --- primitives/order/Cargo.toml | 34 +++++++++++++++++++++++ primitives/order/src/lib.rs | 53 ++++++++++++++++++++++++++++++++++++ primitives/region/Cargo.toml | 2 +- 3 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 primitives/order/Cargo.toml create mode 100644 primitives/order/src/lib.rs diff --git a/primitives/order/Cargo.toml b/primitives/order/Cargo.toml new file mode 100644 index 00000000..d643a985 --- /dev/null +++ b/primitives/order/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "order-primitives" +authors = ["Anonymous"] +description = "Traits and types coretime orders" +version = "0.1.0" +license = "GPLv3" +homepage = "https://substrate.io" +repository = "https://github.com/paritytech/substrate/" +edition = "2021" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +cumulus-primitives-core = { workspace = true, default-features = false } +log = { workspace = true } +codec = { workspace = true, default-features = false, features = ["derive"] } +scale-info = { workspace = true, default-features = false, features = ["derive"] } +sp-core = { workspace = true, default-features = false } +pallet-broker = { workspace = true, default-features = false } + +frame-support = { workspace = true, default-features = false } + +[features] +default = ["std"] +std = [ + "cumulus-primitives-core/std", + "log/std", + "codec/std", + "scale-info/std", + "sp-core/std", + "pallet-broker/std", + "frame-support/std", +] diff --git a/primitives/order/src/lib.rs b/primitives/order/src/lib.rs new file mode 100644 index 00000000..ddb03689 --- /dev/null +++ b/primitives/order/src/lib.rs @@ -0,0 +1,53 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . +#![cfg_attr(not(feature = "std"), no_std)] +use codec::{Decode, Encode, MaxEncodedLen}; +pub use cumulus_primitives_core::ParaId; +use pallet_broker::{PartsOf57600, Timeslice}; +use scale_info::TypeInfo; + +/// Order identifier. +pub type OrderId = u32; + +/// The information we store about a Coretime order. +#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] +pub struct Order { + /// The `AccountId` that created the order. + /// + /// In most cases this will probably be the sovereign account of the parachain. + pub creator: AccountId, + /// The para id to which Coretime will be allocated. + pub para_id: ParaId, + /// Region requirements of the order. + pub requirements: Requirements, +} + +/// The region requirements of an order. +#[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] +pub struct Requirements { + /// The timeslice at which the Region begins. + pub begin: Timeslice, + /// The timeslice at which the Region ends. + pub end: Timeslice, + /// The minimum fraction of the core that the region should occupy. + pub core_occupancy: PartsOf57600, +} + +pub trait OrderInspect { + /// Get the order with the associated id. + /// + /// If `None` the order was not found. + fn order(order_id: &OrderId) -> Option>; +} diff --git a/primitives/region/Cargo.toml b/primitives/region/Cargo.toml index eae1e4f0..b7234e01 100644 --- a/primitives/region/Cargo.toml +++ b/primitives/region/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "region-primitives" authors = ["Anonymous"] -description = "Traits and types related to nonfungible assets" +description = "Traits and types related to regions" version = "0.1.0" license = "GPLv3" homepage = "https://substrate.io" From 4b7049198740fa40cfac8c99c1d38f5af1e0bc59 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Mon, 8 Jul 2024 09:59:52 +0200 Subject: [PATCH 03/34] progress --- Cargo.lock | 2 + pallets/market/src/lib.rs | 9 ++- pallets/market/src/tests.rs | 2 +- pallets/processor/Cargo.toml | 4 ++ pallets/processor/src/lib.rs | 82 ++++++++++++++++++------ pallets/regions/src/lib.rs | 8 +-- pallets/regions/src/nonfungible_impls.rs | 5 ++ pallets/regions/src/types.rs | 3 + primitives/region/src/lib.rs | 5 ++ 9 files changed, 90 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9eda63b2..06351141 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7020,10 +7020,12 @@ dependencies = [ "frame-support", "frame-system", "log", + "nonfungible-primitives", "order-primitives", "pallet-balances", "pallet-broker", "parity-scale-codec", + "region-primitives", "scale-info", "serde", "sp-core", diff --git a/pallets/market/src/lib.rs b/pallets/market/src/lib.rs index 2c68c019..3b74eaa5 100644 --- a/pallets/market/src/lib.rs +++ b/pallets/market/src/lib.rs @@ -143,6 +143,10 @@ pub mod pallet { NotAllowed, /// The price of the region is higher than what the buyer is willing to pay. PriceTooHigh, + /// The region record is not available. + RecordUnavailable, + /// Locked regions cannot be listed on sale. + RegionLocked, } #[pallet::call] @@ -165,7 +169,10 @@ pub mod pallet { let who = ensure_signed(origin)?; ensure!(Listings::::get(region_id).is_none(), Error::::AlreadyListed); - let record = T::Regions::record(®ion_id.into()).ok_or(Error::::UnknownRegion)?; + + let region = T::Regions::region(®ion_id.into()).ok_or(Error::::UnknownRegion)?; + ensure!(!region.locked, Error::::RegionLocked); + let record = region.record.get().ok_or(Error::::RecordUnavailable)?; // It doesn't make sense to list a region that expired. let current_timeslice = Self::current_timeslice(); diff --git a/pallets/market/src/tests.rs b/pallets/market/src/tests.rs index d376de9a..5391fbfc 100644 --- a/pallets/market/src/tests.rs +++ b/pallets/market/src/tests.rs @@ -88,7 +88,7 @@ fn list_region_works() { assert_noop!( Market::list_region(signer.clone(), region_id, price, None), - Error::::UnknownRegion + Error::::RecordUnavailable ); assert_ok!(Regions::set_record(region_id, record.clone())); diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml index 4acff66a..c12d595b 100644 --- a/pallets/processor/Cargo.toml +++ b/pallets/processor/Cargo.toml @@ -25,7 +25,9 @@ pallet-broker = { workspace = true, default-features = false } xcm-executor = { workspace = true, default-features = false } # Local +nonfungible-primitives = { workspace = true, default-features = false } order-primitives = { workspace = true, default-features = false } +region-primitives = { workspace = true, default-features = false } [dev-dependencies] serde = { workspace = true } @@ -51,7 +53,9 @@ std = [ "frame-system/std", "pallet-broker/std", "pallet-balances/std", + "nonfungible-primitives/std", "order-primitives/std", + "region-primitives/std", "xcm/std", "xcm-executor/std", "xcm-builder/std", diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index ff7ad929..fdbf4d85 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -15,21 +15,25 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::Currency; +use frame_support::traits::{nonfungible::Transfer, Currency}; use frame_system::WeightInfo; -use order_primitives::{OrderId, OrderInspect}; +use nonfungible_primitives::LockableNonFungible; +use order_primitives::{OrderId, OrderInspect, Requirements}; pub use pallet::*; -use pallet_broker::RegionId; +use pallet_broker::{RegionId, RegionRecord}; +use region_primitives::RegionInspect; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; +pub type RegionRecordOf = RegionRecord<::AccountId, BalanceOf>; + #[frame_support::pallet] pub mod pallet { use super::*; use frame_support::{ pallet_prelude::*, - traits::{fungible::Mutate, Get, ReservableCurrency}, + traits::{fungible::Mutate, ReservableCurrency}, }; use frame_system::pallet_prelude::*; @@ -42,8 +46,15 @@ pub mod pallet { /// Currency used for purchasing coretime. type Currency: Mutate + ReservableCurrency; - /// Type over which we can access order data. - type Orders: OrderInspect; + /// Type over which we can access order data. + type Orders: OrderInspect; + + /// Type providing a way of reading, transferring and locking regions. + // + // The item id is `u128` encoded RegionId. + type Regions: Transfer + + LockableNonFungible + + RegionInspect, ItemId = u128>; /// Weight Info type WeightInfo: WeightInfo; @@ -59,16 +70,20 @@ pub mod pallet { #[pallet::error] #[derive(PartialEq)] pub enum Error { - /// Invalid order id. - InvalidOrderId, - } - - #[pallet::hooks] - impl Hooks> for Pallet { - fn on_initialize(_: BlockNumberFor) -> Weight { - - Weight::zero() - } + /// Region not found. + UnknownRegion, + /// Order not found. + UnknownOrder, + /// The region doesn't start when it should based on the requirements. + RegionStartsTooLate, + /// The region doesn't end when it should based on the requirements. + RegionEndsTooSoon, + /// Regions core mask doesn't match the requirements. + RegionCoreOccupancyInsufficient, + /// The region record is not available. + RecordUnavailable, + /// Locked regions cannot be listed on sale. + RegionLocked, } #[pallet::call] @@ -80,13 +95,38 @@ pub mod pallet { order_id: OrderId, region_id: RegionId, ) -> DispatchResult { - // TODO + let who = ensure_signed(origin)?; + + let region = T::Regions::region(®ion_id.into()).ok_or(Error::::UnknownRegion)?; + ensure!(!region.locked, Error::::RegionLocked); + + let record = region.record.get().ok_or(Error::::RecordUnavailable)?; + let order = T::Orders::order(&order_id).ok_or(Error::::UnknownOrder)?; + + Self::ensure_matching_requirements(region_id, record, order.requirements)?; - // Maybe move this to the orders pallet? - - // PROS: simpler + // TODO: process fulfilling. - // CONS: Adds opinionation. + // TODO: event + + Ok(()) + } + } + + impl Pallet { + pub(crate) fn ensure_matching_requirements( + region_id: RegionId, + record: RegionRecordOf, + requirements: Requirements, + ) -> DispatchResult { + ensure!(region_id.begin <= requirements.begin, Error::::RegionStartsTooLate); + ensure!(record.end >= requirements.end, Error::::RegionEndsTooSoon); + + let mask_as_nominator = region_id.mask.count_ones() * (57600 / 80); + ensure!( + mask_as_nominator >= requirements.core_occupancy.into(), + Error::::RegionCoreOccupancyInsufficient + ); Ok(()) } diff --git a/pallets/regions/src/lib.rs b/pallets/regions/src/lib.rs index b2902cab..651e7edb 100644 --- a/pallets/regions/src/lib.rs +++ b/pallets/regions/src/lib.rs @@ -103,13 +103,7 @@ pub mod pallet { /// Regions that got cross-chain transferred to the RegionX parachain. #[pallet::storage] #[pallet::getter(fn regions)] - pub type Regions = StorageMap< - _, - Blake2_128Concat, - RegionId, - Region<::AccountId, BalanceOf>, - OptionQuery, - >; + pub type Regions = StorageMap<_, Blake2_128Concat, RegionId, RegionOf, OptionQuery>; #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] diff --git a/pallets/regions/src/nonfungible_impls.rs b/pallets/regions/src/nonfungible_impls.rs index 1ae0a389..02d2fbf6 100644 --- a/pallets/regions/src/nonfungible_impls.rs +++ b/pallets/regions/src/nonfungible_impls.rs @@ -101,6 +101,11 @@ impl RegionInspect> for Pallet { let region = Regions::::get(region_id)?; region.record.get() } + + fn region(item: &Self::ItemId) -> Option> { + let region_id: RegionId = (*item).into(); + Regions::::get(region_id) + } } impl LockableNonFungible for Pallet { diff --git a/pallets/regions/src/types.rs b/pallets/regions/src/types.rs index 2c724f8c..458a492b 100644 --- a/pallets/regions/src/types.rs +++ b/pallets/regions/src/types.rs @@ -24,6 +24,9 @@ pub type BalanceOf = pub type RegionRecordOf = pallet_broker::RegionRecord<::AccountId, BalanceOf>; +pub type RegionOf = + region_primitives::Region<::AccountId, BalanceOf>; + /// ISMP errors specific to the RegionX project. #[derive(Encode, Decode, Debug, Clone, PartialEq, Eq, TypeInfo, MaxEncodedLen)] pub enum IsmpCustomError { diff --git a/primitives/region/src/lib.rs b/primitives/region/src/lib.rs index 84483875..7df9b7ad 100644 --- a/primitives/region/src/lib.rs +++ b/primitives/region/src/lib.rs @@ -79,4 +79,9 @@ pub trait RegionInspect { /// /// If `None` the region record was not found. fn record(region_id: &Self::ItemId) -> Option>; + + /// Get the region data. + /// + /// If `None` the region was not found. + fn region(region_id: &Self::ItemId) -> Option>; } From af73b15cec85ea691d8126d4c56a51847a65dcb2 Mon Sep 17 00:00:00 2001 From: cuteolaf Date: Wed, 10 Jul 2024 16:35:51 +0000 Subject: [PATCH 04/34] fulfill order --- pallets/orders/src/lib.rs | 4 ++++ pallets/processor/src/lib.rs | 19 ++++++++++++++++--- primitives/order/src/lib.rs | 3 +++ 3 files changed, 23 insertions(+), 3 deletions(-) diff --git a/pallets/orders/src/lib.rs b/pallets/orders/src/lib.rs index 7a805653..3b2208d3 100644 --- a/pallets/orders/src/lib.rs +++ b/pallets/orders/src/lib.rs @@ -293,5 +293,9 @@ pub mod pallet { fn order(order_id: &OrderId) -> Option> { Orders::::get(order_id) } + + fn remove_order(order_id: &OrderId) { + Orders::::remove(order_id) + } } } diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index fdbf4d85..b21e718a 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -65,7 +65,9 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] - pub enum Event {} + pub enum Event { + OrderFulfilled { order_id: OrderId, region_id: RegionId, seller: T::AccountId }, + } #[pallet::error] #[derive(PartialEq)] @@ -84,6 +86,8 @@ pub mod pallet { RecordUnavailable, /// Locked regions cannot be listed on sale. RegionLocked, + /// The caller is not the owner of the region. + NotOwner, } #[pallet::call] @@ -100,14 +104,23 @@ pub mod pallet { let region = T::Regions::region(®ion_id.into()).ok_or(Error::::UnknownRegion)?; ensure!(!region.locked, Error::::RegionLocked); + ensure!(region.owner == who, Error::::NotOwner); + let record = region.record.get().ok_or(Error::::RecordUnavailable)?; let order = T::Orders::order(&order_id).ok_or(Error::::UnknownOrder)?; Self::ensure_matching_requirements(region_id, record, order.requirements)?; - // TODO: process fulfilling. + // Transfer the region to the order creator + T::Regions::transfer(®ion_id.into(), &order.creator)?; + // Transfer the tokens collected by the order to the caller(ie the seller) + // FIXME: Price ??? + // T::Currency::transfer(&order.creator, ®ion.owner) + + // remove the order + T::Orders::remove_order(&order_id); - // TODO: event + Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); Ok(()) } diff --git a/primitives/order/src/lib.rs b/primitives/order/src/lib.rs index ddb03689..ff5b350b 100644 --- a/primitives/order/src/lib.rs +++ b/primitives/order/src/lib.rs @@ -50,4 +50,7 @@ pub trait OrderInspect { /// /// If `None` the order was not found. fn order(order_id: &OrderId) -> Option>; + + /// Remove an order with the associated id. + fn remove_order(order_id: &OrderId); } From 6ebc859ffab086164e817c81471adaf57fd4eb4c Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 13 Jul 2024 20:26:17 +0200 Subject: [PATCH 05/34] implement payment --- Cargo.lock | 1 + pallets/processor/src/lib.rs | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 06351141..c092efe5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1288,6 +1288,7 @@ dependencies = [ "sp-core", "sp-genesis-builder", "sp-inherents", + "sp-io", "sp-mmr-primitives", "sp-offchain", "sp-runtime", diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index b21e718a..609fd09d 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -15,13 +15,14 @@ #![cfg_attr(not(feature = "std"), no_std)] -use frame_support::traits::{nonfungible::Transfer, Currency}; +use frame_support::traits::{nonfungible::Transfer, Currency, ExistenceRequirement}; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; use order_primitives::{OrderId, OrderInspect, Requirements}; pub use pallet::*; use pallet_broker::{RegionId, RegionRecord}; use region_primitives::RegionInspect; +use sp_runtime::traits::Convert; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -49,6 +50,9 @@ pub mod pallet { /// Type over which we can access order data. type Orders: OrderInspect; + /// A way for getting the associated account of an order. + type OrderToAccountId: Convert; + /// Type providing a way of reading, transferring and locking regions. // // The item id is `u128` encoded RegionId. @@ -113,9 +117,16 @@ pub mod pallet { // Transfer the region to the order creator T::Regions::transfer(®ion_id.into(), &order.creator)?; - // Transfer the tokens collected by the order to the caller(ie the seller) - // FIXME: Price ??? - // T::Currency::transfer(&order.creator, ®ion.owner) + + let order_account = T::OrderToAccountId::convert(order_id); + let amount = T::Currency::free_balance(&order_account); + + <::Currency as Currency>::transfer( + &order_account, + &who, + amount, + ExistenceRequirement::AllowDeath, + )?; // remove the order T::Orders::remove_order(&order_id); From c36f45b0ce52a9a90018b7f8e979d56520e1ca94 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Wed, 17 Jul 2024 18:32:45 +0200 Subject: [PATCH 06/34] progress --- pallets/processor/Cargo.toml | 3 + pallets/processor/src/lib.rs | 2 + pallets/processor/src/mock.rs | 160 ++++++++++++++++++++++++++++++++++ 3 files changed, 165 insertions(+) create mode 100644 pallets/processor/src/mock.rs diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml index c12d595b..7d1291c9 100644 --- a/pallets/processor/Cargo.toml +++ b/pallets/processor/Cargo.toml @@ -35,6 +35,8 @@ pallet-balances = { workspace = true, default-features = false } xcm = { workspace = true, default-features = false } xcm-builder = { workspace = true, default-features = false } +pallet-orders = { workspace = true, default-features = false } + [features] default = ["std"] runtime-benchmarks = [ @@ -53,6 +55,7 @@ std = [ "frame-system/std", "pallet-broker/std", "pallet-balances/std", + "pallet-orders/std", "nonfungible-primitives/std", "order-primitives/std", "region-primitives/std", diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 609fd09d..9a6b7edd 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -131,6 +131,8 @@ pub mod pallet { // remove the order T::Orders::remove_order(&order_id); + // TODO: make assignment + Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); Ok(()) diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs new file mode 100644 index 00000000..01d52372 --- /dev/null +++ b/pallets/processor/src/mock.rs @@ -0,0 +1,160 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . + +use crate::{FeeHandler, OrderId, ParaId}; +use frame_support::{ + pallet_prelude::*, + parameter_types, + traits::{fungible::Mutate, tokens::Preservation, Everything}, +}; +use sp_core::{ConstU64, H256}; +use sp_io::hashing::blake2_256; +use sp_runtime::{ + traits::{BlakeTwo256, BlockNumberProvider, Convert, IdentityLookup}, + AccountId32, BuildStorage, +}; +use xcm::opaque::lts::NetworkId; + +use xcm_builder::{ + AccountId32Aliases, ChildParachainConvertsVia, DescribeAllTerminal, HashedDescription, +}; + +type AccountId = AccountId32; +type Block = frame_system::mocking::MockBlock; + +pub const ALICE: AccountId = AccountId::new([0u8; 32]); +pub const BOB: AccountId = AccountId::new([1u8; 32]); +pub const CHARLIE: AccountId = AccountId::new([2u8; 32]); +pub const TREASURY: AccountId = AccountId::new([3u8; 32]); + +// Configure a mock runtime to test the pallet. +frame_support::construct_runtime!( + pub enum Test + { + System: frame_system::{Pallet, Call, Config, Storage, Event}, + Balances: pallet_balances, + Orders: crate::{Pallet, Call, Storage, Event}, + } +); + +parameter_types! { + pub const AnyNetwork: Option = None; +} + +pub type SovereignAccountOf = ( + ChildParachainConvertsVia, + AccountId32Aliases, + HashedDescription, +); + +parameter_types! { + pub const BlockHashCount: u64 = 250; + pub const SS58Prefix: u8 = 42; +} + +impl frame_system::Config for Test { + type BaseCallFilter = Everything; + type BlockWeights = (); + type BlockLength = (); + type DbWeight = (); + type RuntimeOrigin = RuntimeOrigin; + type RuntimeCall = RuntimeCall; + type Nonce = u64; + type Hash = H256; + type Hashing = BlakeTwo256; + type AccountId = AccountId; + type Lookup = IdentityLookup; + type Block = Block; + type RuntimeEvent = RuntimeEvent; + type RuntimeTask = RuntimeTask; + type BlockHashCount = BlockHashCount; + type Version = (); + type PalletInfo = PalletInfo; + type AccountData = pallet_balances::AccountData; + type OnNewAccount = (); + type OnKilledAccount = (); + type SystemWeightInfo = (); + type SS58Prefix = SS58Prefix; + type OnSetCode = (); + type MaxConsumers = frame_support::traits::ConstU32<16>; +} + +impl pallet_balances::Config for Test { + type Balance = u64; + type DustRemoval = (); + type RuntimeEvent = RuntimeEvent; + type ExistentialDeposit = ConstU64<1>; + type AccountStore = System; + type WeightInfo = (); + type MaxLocks = (); + type MaxHolds = (); + type MaxReserves = ConstU32<50>; + type ReserveIdentifier = [u8; 8]; + type RuntimeHoldReason = RuntimeHoldReason; + type RuntimeFreezeReason = RuntimeFreezeReason; + type FreezeIdentifier = (); + type MaxFreezes = (); +} + +pub struct OrderCreationFeeHandler; +impl FeeHandler for OrderCreationFeeHandler { + fn handle(who: &AccountId, fee: u64) -> DispatchResult { + ::Currency::transfer(who, &TREASURY, fee, Preservation::Preserve)?; + Ok(()) + } +} + +parameter_types! { + pub static RelayBlockNumber: u64 = 0; +} + +pub struct RelayBlockNumberProvider; +impl BlockNumberProvider for RelayBlockNumberProvider { + type BlockNumber = u64; + fn current_block_number() -> Self::BlockNumber { + RelayBlockNumber::get() + } +} + +pub struct OrderToAccountId; +impl Convert for OrderToAccountId { + fn convert(order: OrderId) -> AccountId { + ("order", order).using_encoded(blake2_256).into() + } +} + +impl pallet_orders::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type SovereignAccountOf = SovereignAccountOf; + type OrderCreationCost = ConstU64<100>; + type MinimumContribution = ConstU64<50>; + type RCBlockNumberProvider = RelayBlockNumberProvider; + type OrderToAccountId = OrderToAccountId; + type TimeslicePeriod = ConstU64<80>; + type OrderCreationFeeHandler = OrderCreationFeeHandler; + type WeightInfo = (); +} + +// Build genesis storage according to the mock runtime. +pub fn new_test_ext(endowed_accounts: Vec<(AccountId32, u64)>) -> sp_io::TestExternalities { + let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); + pallet_balances::GenesisConfig:: { balances: endowed_accounts } + .assimilate_storage(&mut t) + .unwrap(); + let mut ext = sp_io::TestExternalities::new(t); + ext.execute_with(|| System::set_block_number(1)); + ext +} From 839631de285e8711042e5ddf61737b401b20bd1f Mon Sep 17 00:00:00 2001 From: Szegoo Date: Thu, 18 Jul 2024 08:46:11 +0200 Subject: [PATCH 07/34] Cargo.lock --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index c092efe5..f22152cb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7025,6 +7025,7 @@ dependencies = [ "order-primitives", "pallet-balances", "pallet-broker", + "pallet-orders", "parity-scale-codec", "region-primitives", "scale-info", From c31cfe710e76ea5135108de92bd3733332f42789 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Fri, 19 Jul 2024 17:14:23 +0200 Subject: [PATCH 08/34] progress --- Cargo.lock | 3 ++ pallets/processor/Cargo.toml | 6 +++ pallets/processor/src/lib.rs | 6 +++ pallets/processor/src/mock.rs | 96 +++++++++++++++++++++++++++------- pallets/processor/src/tests.rs | 14 +++++ 5 files changed, 105 insertions(+), 20 deletions(-) create mode 100644 pallets/processor/src/tests.rs diff --git a/Cargo.lock b/Cargo.lock index a224a9f2..474783fb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7017,12 +7017,15 @@ dependencies = [ "frame-benchmarking", "frame-support", "frame-system", + "ismp 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "ismp-testsuite", "log", "nonfungible-primitives", "order-primitives", "pallet-balances", "pallet-broker", "pallet-orders", + "pallet-regions", "parity-scale-codec", "region-primitives", "scale-info", diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml index 7d1291c9..18e310b5 100644 --- a/pallets/processor/Cargo.toml +++ b/pallets/processor/Cargo.toml @@ -35,8 +35,12 @@ pallet-balances = { workspace = true, default-features = false } xcm = { workspace = true, default-features = false } xcm-builder = { workspace = true, default-features = false } +pallet-regions = { workspace = true, default-features = false } pallet-orders = { workspace = true, default-features = false } +ismp = { workspace = true, default-features = false } +ismp-testsuite = { workspace = true } + [features] default = ["std"] runtime-benchmarks = [ @@ -55,10 +59,12 @@ std = [ "frame-system/std", "pallet-broker/std", "pallet-balances/std", + "pallet-regions/std", "pallet-orders/std", "nonfungible-primitives/std", "order-primitives/std", "region-primitives/std", + "ismp/std", "xcm/std", "xcm-executor/std", "xcm-builder/std", diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 9a6b7edd..c3c56954 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -15,6 +15,12 @@ #![cfg_attr(not(feature = "std"), no_std)] +#[cfg(test)] +mod mock; + +#[cfg(test)] +mod tests; + use frame_support::traits::{nonfungible::Transfer, Currency, ExistenceRequirement}; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 01d52372..344f08dc 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -13,23 +13,27 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::{FeeHandler, OrderId, ParaId}; use frame_support::{ pallet_prelude::*, parameter_types, traits::{fungible::Mutate, tokens::Preservation, Everything}, }; +use ismp::{ + consensus::StateMachineId, + dispatcher::{FeeMetadata, IsmpDispatcher}, + host::StateMachine, +}; +use ismp_testsuite::mocks::Host; +use order_primitives::OrderId; +use pallet_orders::FeeHandler; +use pallet_regions::primitives::StateMachineHeightProvider; use sp_core::{ConstU64, H256}; use sp_io::hashing::blake2_256; use sp_runtime::{ traits::{BlakeTwo256, BlockNumberProvider, Convert, IdentityLookup}, - AccountId32, BuildStorage, -}; -use xcm::opaque::lts::NetworkId; - -use xcm_builder::{ - AccountId32Aliases, ChildParachainConvertsVia, DescribeAllTerminal, HashedDescription, + AccountId32, BuildStorage, DispatchResult, }; +use std::sync::Arc; type AccountId = AccountId32; type Block = frame_system::mocking::MockBlock; @@ -45,20 +49,11 @@ frame_support::construct_runtime!( { System: frame_system::{Pallet, Call, Config, Storage, Event}, Balances: pallet_balances, - Orders: crate::{Pallet, Call, Storage, Event}, + Orders: pallet_orders::{Pallet, Call, Storage, Event}, + Regions: pallet_regions::{Pallet, Call, Storage, Event}, } ); -parameter_types! { - pub const AnyNetwork: Option = None; -} - -pub type SovereignAccountOf = ( - ChildParachainConvertsVia, - AccountId32Aliases, - HashedDescription, -); - parameter_types! { pub const BlockHashCount: u64 = 250; pub const SS58Prefix: u8 = 42; @@ -108,10 +103,63 @@ impl pallet_balances::Config for Test { type MaxFreezes = (); } +pub struct MockStateMachineHeightProvider; +impl StateMachineHeightProvider for MockStateMachineHeightProvider { + fn latest_state_machine_height(_id: StateMachineId) -> Option { + Some(0) + } +} + +pub struct MockDispatcher(pub Arc, PhantomData); +impl Default for MockDispatcher { + fn default() -> Self { + MockDispatcher(Default::default(), PhantomData::::default()) + } +} +impl IsmpDispatcher for MockDispatcher { + type Account = u64; + type Balance = u64; + + fn dispatch_request( + &self, + _request: DispatchRequest, + _fee: FeeMetadata, + ) -> Result { + Ok(Default::default()) + } + + fn dispatch_response( + &self, + _response: PostResponse, + _fee: FeeMetadata, + ) -> Result { + Ok(Default::default()) + } +} + +parameter_types! { + pub const CoretimeChain: StateMachine = StateMachine::Kusama(1005); // coretime-kusama +} + +impl pallet_regions::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type CoretimeChain = CoretimeChain; + type IsmpDispatcher = MockDispatcher; + type StateMachineHeightProvider = MockStateMachineHeightProvider; + type Timeout = ConstU64<1000>; + type WeightInfo = (); +} + pub struct OrderCreationFeeHandler; impl FeeHandler for OrderCreationFeeHandler { fn handle(who: &AccountId, fee: u64) -> DispatchResult { - ::Currency::transfer(who, &TREASURY, fee, Preservation::Preserve)?; + ::Currency::transfer( + who, + &TREASURY, + fee, + Preservation::Preserve, + )?; Ok(()) } } @@ -138,7 +186,6 @@ impl Convert for OrderToAccountId { impl pallet_orders::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type SovereignAccountOf = SovereignAccountOf; type OrderCreationCost = ConstU64<100>; type MinimumContribution = ConstU64<50>; type RCBlockNumberProvider = RelayBlockNumberProvider; @@ -148,6 +195,15 @@ impl pallet_orders::Config for Test { type WeightInfo = (); } +impl crate::Config for Test { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Orders = Orders; + type OrderToAccountId = OrderToAccountId; + type Regions = Regions; + type WeightInfo = (); +} + // Build genesis storage according to the mock runtime. pub fn new_test_ext(endowed_accounts: Vec<(AccountId32, u64)>) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs new file mode 100644 index 00000000..a49118c4 --- /dev/null +++ b/pallets/processor/src/tests.rs @@ -0,0 +1,14 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . From a474ce4612c207eaabeb79fac385aa7d9c710ffa Mon Sep 17 00:00:00 2001 From: Szegoo Date: Fri, 19 Jul 2024 19:35:39 +0200 Subject: [PATCH 09/34] mock.rs compiling --- pallets/processor/src/mock.rs | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 344f08dc..659bdb77 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -20,28 +20,26 @@ use frame_support::{ }; use ismp::{ consensus::StateMachineId, - dispatcher::{FeeMetadata, IsmpDispatcher}, + dispatcher::{DispatchRequest, FeeMetadata, IsmpDispatcher}, + error::Error, host::StateMachine, + router::PostResponse, }; use ismp_testsuite::mocks::Host; use order_primitives::OrderId; use pallet_orders::FeeHandler; use pallet_regions::primitives::StateMachineHeightProvider; use sp_core::{ConstU64, H256}; -use sp_io::hashing::blake2_256; use sp_runtime::{ traits::{BlakeTwo256, BlockNumberProvider, Convert, IdentityLookup}, - AccountId32, BuildStorage, DispatchResult, + BuildStorage, DispatchResult, }; use std::sync::Arc; -type AccountId = AccountId32; +type AccountId = u64; type Block = frame_system::mocking::MockBlock; -pub const ALICE: AccountId = AccountId::new([0u8; 32]); -pub const BOB: AccountId = AccountId::new([1u8; 32]); -pub const CHARLIE: AccountId = AccountId::new([2u8; 32]); -pub const TREASURY: AccountId = AccountId::new([3u8; 32]); +pub const TREASURY: AccountId = 42; // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( @@ -51,6 +49,7 @@ frame_support::construct_runtime!( Balances: pallet_balances, Orders: pallet_orders::{Pallet, Call, Storage, Event}, Regions: pallet_regions::{Pallet, Call, Storage, Event}, + Processor: crate::{Pallet, Call, Storage, Event}, } ); @@ -179,7 +178,7 @@ impl BlockNumberProvider for RelayBlockNumberProvider { pub struct OrderToAccountId; impl Convert for OrderToAccountId { fn convert(order: OrderId) -> AccountId { - ("order", order).using_encoded(blake2_256).into() + 1000u64 + order as u64 } } @@ -205,7 +204,7 @@ impl crate::Config for Test { } // Build genesis storage according to the mock runtime. -pub fn new_test_ext(endowed_accounts: Vec<(AccountId32, u64)>) -> sp_io::TestExternalities { +pub fn new_test_ext(endowed_accounts: Vec<(u64, u64)>) -> sp_io::TestExternalities { let mut t = frame_system::GenesisConfig::::default().build_storage().unwrap(); pallet_balances::GenesisConfig:: { balances: endowed_accounts } .assimilate_storage(&mut t) From a3ac7a145b95f63bdf30af0ee9cfd74972614a68 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Fri, 19 Jul 2024 20:25:10 +0200 Subject: [PATCH 10/34] outline login for the fulfill extrinsic --- pallets/processor/src/lib.rs | 12 +++++++++++- pallets/processor/src/tests.rs | 7 +++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index c3c56954..9be5f768 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -122,6 +122,14 @@ pub mod pallet { Self::ensure_matching_requirements(region_id, record, order.requirements)?; // Transfer the region to the order creator + // + // NOTE: Since we are assigning the region in this extrinsic, we will transfer it to + // the order creator and in case the extrinsic fails we creator will keep the region and + // can assign it himelf. + // + // ADDITONAL NOTE: Instead of transferring to the creator we should maybe indicate + // somehow that the order was fulfilled, the region is reserved and anyone can call a + // separate extrinsic to assign it to the task. T::Regions::transfer(®ion_id.into(), &order.creator)?; let order_account = T::OrderToAccountId::convert(order_id); @@ -137,7 +145,9 @@ pub mod pallet { // remove the order T::Orders::remove_order(&order_id); - // TODO: make assignment + // TODO: make assignment - NOTE: if an error occurs don't return error, return ok and + // emit appropriate event so the transaction doesn't get reverted in case the assignment + // fails. Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index a49118c4..50be0268 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -12,3 +12,10 @@ // // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . + +use crate::mock::new_test_ext; + +#[test] +fn fulfill_order_works() { + new_test_ext(vec![(1, 1000)]).execute_with(|| {}); +} From 88e3784de76c2d3529011a0ae10cadb4378697d4 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Fri, 19 Jul 2024 20:34:50 +0200 Subject: [PATCH 11/34] test progress --- pallets/processor/src/tests.rs | 43 ++++++++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index 50be0268..2768c372 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -13,9 +13,48 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::mock::new_test_ext; +use crate::mock::{new_test_ext, Orders, Regions, RuntimeOrigin, Test}; +use frame_support::{ + assert_ok, + traits::{nonfungible::Mutate, Currency}, +}; +use order_primitives::{Order, Requirements}; +use pallet_broker::{CoreMask, RegionId}; #[test] fn fulfill_order_works() { - new_test_ext(vec![(1, 1000)]).execute_with(|| {}); + new_test_ext(vec![(1, 1000)]).execute_with(|| { + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + let region_owner = 1; + + let order_creator = 2000; + ::Currency::make_free_balance_be(&order_creator, 1000u32.into()); + let requirements = Requirements { + begin: 0, + end: 8, + core_occupancy: 28800, // Half of a core. + }; + + // 1. create a region + + assert!(Regions::regions(®ion_id).is_none()); + assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); + + // 2. create an order. + + assert_ok!(Orders::create_order( + RuntimeOrigin::signed(order_creator.clone()), + 2000.into(), + requirements.clone() + )); + // Check storage items + assert_eq!( + Orders::orders(0), + Some(Order { para_id: 2000.into(), creator: order_creator, requirements }) + ); + + // 3. make contributions to an order + // 4. call the fulfill extrinsic + // 5. ensure correct storage items. + }); } From 1d8d91b3969e6193a261fd38219279d98da8f8eb Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 20 Jul 2024 11:01:43 +0200 Subject: [PATCH 12/34] fulfill_order_works almost complete --- pallets/processor/src/tests.rs | 89 ++++++++++++++++++++-------------- 1 file changed, 53 insertions(+), 36 deletions(-) diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index 2768c372..308163a1 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -13,48 +13,65 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::mock::{new_test_ext, Orders, Regions, RuntimeOrigin, Test}; +use crate::mock::{new_test_ext, Orders, Processor, Regions, RuntimeOrigin, Test}; use frame_support::{ assert_ok, traits::{nonfungible::Mutate, Currency}, }; use order_primitives::{Order, Requirements}; -use pallet_broker::{CoreMask, RegionId}; +use pallet_broker::{CoreMask, RegionId, RegionRecord}; #[test] fn fulfill_order_works() { - new_test_ext(vec![(1, 1000)]).execute_with(|| { - let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; - let region_owner = 1; - - let order_creator = 2000; - ::Currency::make_free_balance_be(&order_creator, 1000u32.into()); - let requirements = Requirements { - begin: 0, - end: 8, - core_occupancy: 28800, // Half of a core. - }; - - // 1. create a region - - assert!(Regions::regions(®ion_id).is_none()); - assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); - - // 2. create an order. - - assert_ok!(Orders::create_order( - RuntimeOrigin::signed(order_creator.clone()), - 2000.into(), - requirements.clone() - )); - // Check storage items - assert_eq!( - Orders::orders(0), - Some(Order { para_id: 2000.into(), creator: order_creator, requirements }) - ); - - // 3. make contributions to an order - // 4. call the fulfill extrinsic - // 5. ensure correct storage items. - }); + new_test_ext(vec![(1, 1000), (2000, 1000), (10, 1000), (11, 1000), (12, 1000)]).execute_with( + || { + let region_owner = 1; + let order_creator = 2000; + let requirements = Requirements { + begin: 0, + end: 8, + core_occupancy: 28800, // Half of a core. + }; + + // 2. create an order + ::Currency::make_free_balance_be(&order_creator, 1000u32.into()); + assert_ok!(Orders::create_order( + RuntimeOrigin::signed(order_creator.clone()), + 2000.into(), + requirements.clone() + )); + assert_eq!( + Orders::orders(0), + Some(Order { para_id: 2000.into(), creator: order_creator, requirements }) + ); + + // 3. make contributions to an order + assert_ok!(Orders::contribute(RuntimeOrigin::signed(10), 0, 500)); + assert_ok!(Orders::contribute(RuntimeOrigin::signed(11), 0, 800)); + assert_ok!(Orders::contribute(RuntimeOrigin::signed(12), 0, 700)); + + // Fulfill order fails with a region that doesn't meet the requirements: + + // Create a region which doesn't the requirements: + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 10) }; + assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); + assert_ok!(Regions::set_record( + region_id, + RegionRecord { end: 123600, owner: 1, paid: None } + )); + + // Create a region which meets the requirements: + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); + assert_ok!(Regions::set_record( + region_id, + RegionRecord { end: 123600, owner: 1, paid: None } + )); + + // Works with a region that meets the requirements: + assert_ok!(Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id)); + + // 5. ensure correct storage items. + }, + ); } From 8b654dc16e1950f94e520af509bfeff989d696bc Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 20 Jul 2024 12:58:57 +0200 Subject: [PATCH 13/34] complete test --- pallets/processor/src/tests.rs | 94 +++++++++++++++++----------------- 1 file changed, 48 insertions(+), 46 deletions(-) diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index 308163a1..01e6aac4 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -13,65 +13,67 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::mock::{new_test_ext, Orders, Processor, Regions, RuntimeOrigin, Test}; +use crate::mock::{new_test_ext, Balances, Orders, Processor, Regions, RuntimeOrigin, Test}; use frame_support::{ assert_ok, traits::{nonfungible::Mutate, Currency}, }; use order_primitives::{Order, Requirements}; use pallet_broker::{CoreMask, RegionId, RegionRecord}; +use region_primitives::RegionInspect; #[test] fn fulfill_order_works() { - new_test_ext(vec![(1, 1000), (2000, 1000), (10, 1000), (11, 1000), (12, 1000)]).execute_with( - || { - let region_owner = 1; - let order_creator = 2000; - let requirements = Requirements { - begin: 0, - end: 8, - core_occupancy: 28800, // Half of a core. - }; + new_test_ext(vec![(2000, 1000), (10, 1000), (11, 1000), (12, 1000)]).execute_with(|| { + let region_owner = 1; + let order_creator = 2000; + let requirements = Requirements { + begin: 0, + end: 8, + core_occupancy: 28800, // Half of a core. + }; - // 2. create an order - ::Currency::make_free_balance_be(&order_creator, 1000u32.into()); - assert_ok!(Orders::create_order( - RuntimeOrigin::signed(order_creator.clone()), - 2000.into(), - requirements.clone() - )); - assert_eq!( - Orders::orders(0), - Some(Order { para_id: 2000.into(), creator: order_creator, requirements }) - ); + // 2. create an order + ::Currency::make_free_balance_be(&order_creator, 1000u32.into()); + assert_ok!(Orders::create_order( + RuntimeOrigin::signed(order_creator.clone()), + 2000.into(), + requirements.clone() + )); + assert_eq!( + Orders::orders(0), + Some(Order { para_id: 2000.into(), creator: order_creator, requirements }) + ); - // 3. make contributions to an order - assert_ok!(Orders::contribute(RuntimeOrigin::signed(10), 0, 500)); - assert_ok!(Orders::contribute(RuntimeOrigin::signed(11), 0, 800)); - assert_ok!(Orders::contribute(RuntimeOrigin::signed(12), 0, 700)); + // 3. make contributions to an order + assert_ok!(Orders::contribute(RuntimeOrigin::signed(10), 0, 500)); + assert_ok!(Orders::contribute(RuntimeOrigin::signed(11), 0, 800)); + assert_ok!(Orders::contribute(RuntimeOrigin::signed(12), 0, 200)); - // Fulfill order fails with a region that doesn't meet the requirements: + // Fulfill order fails with a region that doesn't meet the requirements: - // Create a region which doesn't the requirements: - let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 10) }; - assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); - assert_ok!(Regions::set_record( - region_id, - RegionRecord { end: 123600, owner: 1, paid: None } - )); + // Create a region which doesn't the requirements: + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 10) }; + assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); + assert_ok!(Regions::set_record( + region_id, + RegionRecord { end: 123600, owner: 1, paid: None } + )); - // Create a region which meets the requirements: - let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; - assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); - assert_ok!(Regions::set_record( - region_id, - RegionRecord { end: 123600, owner: 1, paid: None } - )); + // Create a region which meets the requirements: + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); + assert_ok!(Regions::set_record( + region_id, + RegionRecord { end: 123600, owner: 1, paid: None } + )); - // Works with a region that meets the requirements: - assert_ok!(Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id)); - - // 5. ensure correct storage items. - }, - ); + // Works with a region that meets the requirements: + assert_ok!(Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id)); + // Ensure order is removed: + assert!(Orders::orders(0).is_none()); + // Region owner receives as the contributions for fulfilling the order: + assert_eq!(Balances::free_balance(region_owner), 1500); + assert_eq!(Regions::regions(region_id).unwrap().owner, 2000); + }); } From bf7aa119d39d0e25021f94822cc603b60b1cb101 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Sat, 20 Jul 2024 14:43:34 +0200 Subject: [PATCH 14/34] region assignment --- pallets/processor/src/dispatcher.rs | 23 +++++++++++++++++++++++ pallets/processor/src/lib.rs | 18 +++++++++++++++--- 2 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 pallets/processor/src/dispatcher.rs diff --git a/pallets/processor/src/dispatcher.rs b/pallets/processor/src/dispatcher.rs new file mode 100644 index 00000000..65a1e55b --- /dev/null +++ b/pallets/processor/src/dispatcher.rs @@ -0,0 +1,23 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . +use order_primitives::ParaId; +use pallet_broker::RegionId; +use sp_runtime::DispatchResult; + +/// Type assigning the region to the specified task. +pub trait RegionAssigner { + // Assigns the region to the specified task. + fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult; +} diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 9be5f768..98362834 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -17,10 +17,12 @@ #[cfg(test)] mod mock; - #[cfg(test)] mod tests; +mod dispatcher; + +use crate::dispatcher::RegionAssigner; use frame_support::traits::{nonfungible::Transfer, Currency, ExistenceRequirement}; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; @@ -66,6 +68,9 @@ pub mod pallet { + LockableNonFungible + RegionInspect, ItemId = u128>; + /// Type assigning the region to the specified task. + type RegionAssigner: RegionAssigner; + /// Weight Info type WeightInfo: WeightInfo; } @@ -76,7 +81,10 @@ pub mod pallet { #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { + /// Order got fulfilled with a region which is matching the requirements. OrderFulfilled { order_id: OrderId, region_id: RegionId, seller: T::AccountId }, + /// Region assignment failed. + AssignmentFailed(DispatchError), } #[pallet::error] @@ -145,9 +153,13 @@ pub mod pallet { // remove the order T::Orders::remove_order(&order_id); - // TODO: make assignment - NOTE: if an error occurs don't return error, return ok and - // emit appropriate event so the transaction doesn't get reverted in case the assignment + // NOTE: if an error occurs we don't return error, we instead return ok and emit + // appropriate event so the transaction doesn't get reverted in case the assignment // fails. + if let Err(err) = T::RegionAssigner::assign(region_id, order.para_id) { + Self::deposit_event(Event::AssignmentFailed(err)); + return Ok(()) + } Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); From fd770a93dcd63e55b53f610f284e5b0976c0f0d6 Mon Sep 17 00:00:00 2001 From: Sergej Date: Mon, 22 Jul 2024 16:16:04 +0200 Subject: [PATCH 15/34] outline xcm region assigner --- Cargo.lock | 1 + pallets/processor/Cargo.toml | 7 ++-- .../src/{dispatcher.rs => assigner.rs} | 32 ++++++++++++++++++- pallets/processor/src/lib.rs | 22 ++++++++----- 4 files changed, 51 insertions(+), 11 deletions(-) rename pallets/processor/src/{dispatcher.rs => assigner.rs} (51%) diff --git a/Cargo.lock b/Cargo.lock index 474783fb..ebfb3803 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7026,6 +7026,7 @@ dependencies = [ "pallet-broker", "pallet-orders", "pallet-regions", + "pallet-xcm", "parity-scale-codec", "region-primitives", "scale-info", diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml index 18e310b5..aee9f816 100644 --- a/pallets/processor/Cargo.toml +++ b/pallets/processor/Cargo.toml @@ -22,7 +22,11 @@ sp-io = { workspace = true, default-features = false } sp-core = { workspace = true, default-features = false } sp-runtime = { workspace = true, default-features = false } pallet-broker = { workspace = true, default-features = false } +pallet-xcm = { workspace = true, default-features = false } + +xcm = { workspace = true, default-features = false } xcm-executor = { workspace = true, default-features = false } +xcm-builder = { workspace = true, default-features = false } # Local nonfungible-primitives = { workspace = true, default-features = false } @@ -32,8 +36,6 @@ region-primitives = { workspace = true, default-features = false } [dev-dependencies] serde = { workspace = true } pallet-balances = { workspace = true, default-features = false } -xcm = { workspace = true, default-features = false } -xcm-builder = { workspace = true, default-features = false } pallet-regions = { workspace = true, default-features = false } pallet-orders = { workspace = true, default-features = false } @@ -61,6 +63,7 @@ std = [ "pallet-balances/std", "pallet-regions/std", "pallet-orders/std", + "pallet-xcm/std", "nonfungible-primitives/std", "order-primitives/std", "region-primitives/std", diff --git a/pallets/processor/src/dispatcher.rs b/pallets/processor/src/assigner.rs similarity index 51% rename from pallets/processor/src/dispatcher.rs rename to pallets/processor/src/assigner.rs index 65a1e55b..7afba806 100644 --- a/pallets/processor/src/dispatcher.rs +++ b/pallets/processor/src/assigner.rs @@ -12,12 +12,42 @@ // // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . +use crate::LOG_TARGET; +use core::marker::PhantomData; use order_primitives::ParaId; use pallet_broker::RegionId; -use sp_runtime::DispatchResult; +use sp_runtime::{traits::Get, DispatchResult}; +use xcm::latest::prelude::*; /// Type assigning the region to the specified task. pub trait RegionAssigner { // Assigns the region to the specified task. fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult; } + +/// A type that implements the RegionAssigner trait and assigns a region to a task by sending the +/// appropriate XCM message to the Coretime chain. +pub struct XcmRegionAssigner(PhantomData); +impl RegionAssigner for XcmRegionAssigner { + fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult { + let message = Xcm(vec![]); + + match pallet_xcm::Pallet::::send_xcm( + Here, + ::CoretimeChain::get(), + message, + ) { + Ok(_) => log::info!( + target: LOG_TARGET, + "Region assignment sent successfully" + ), + Err(e) => log::error!( + target: LOG_TARGET, + "Failed to send region assignment: {:?}", + e + ), + } + + Ok(()) + } +} diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 98362834..943aa44c 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -15,14 +15,7 @@ #![cfg_attr(not(feature = "std"), no_std)] -#[cfg(test)] -mod mock; -#[cfg(test)] -mod tests; - -mod dispatcher; - -use crate::dispatcher::RegionAssigner; +use crate::assigner::RegionAssigner; use frame_support::traits::{nonfungible::Transfer, Currency, ExistenceRequirement}; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; @@ -31,6 +24,16 @@ pub use pallet::*; use pallet_broker::{RegionId, RegionRecord}; use region_primitives::RegionInspect; use sp_runtime::traits::Convert; +use xcm::opaque::lts::MultiLocation; + +#[cfg(test)] +mod mock; +#[cfg(test)] +mod tests; + +pub mod assigner; + +const LOG_TARGET: &str = "runtime::order-creator"; pub type BalanceOf = <::Currency as Currency<::AccountId>>::Balance; @@ -71,6 +74,9 @@ pub mod pallet { /// Type assigning the region to the specified task. type RegionAssigner: RegionAssigner; + /// The Coretime chain from which we read region state. + type CoretimeChain: Get; + /// Weight Info type WeightInfo: WeightInfo; } From 9337a56569c2f703f7910b32bab64b0b842b1727 Mon Sep 17 00:00:00 2001 From: Sergej Date: Mon, 22 Jul 2024 18:35:59 +0200 Subject: [PATCH 16/34] assignment call --- pallets/processor/src/assigner.rs | 33 ++++++++++++++++++++++++++++++- pallets/processor/src/lib.rs | 24 +++++++++++++++++++--- 2 files changed, 53 insertions(+), 4 deletions(-) diff --git a/pallets/processor/src/assigner.rs b/pallets/processor/src/assigner.rs index 7afba806..baeb1f6e 100644 --- a/pallets/processor/src/assigner.rs +++ b/pallets/processor/src/assigner.rs @@ -12,13 +12,20 @@ // // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . + use crate::LOG_TARGET; use core::marker::PhantomData; +use frame_support::weights::WeightToFee; use order_primitives::ParaId; use pallet_broker::RegionId; use sp_runtime::{traits::Get, DispatchResult}; use xcm::latest::prelude::*; +/// Type which encodes the region assignment call. +pub trait AssignmentCallEncoder { + fn encode_assignment_call(region_id: RegionId, para_id: ParaId) -> Vec; +} + /// Type assigning the region to the specified task. pub trait RegionAssigner { // Assigns the region to the specified task. @@ -30,7 +37,31 @@ pub trait RegionAssigner { pub struct XcmRegionAssigner(PhantomData); impl RegionAssigner for XcmRegionAssigner { fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult { - let message = Xcm(vec![]); + let assignment_call = T::AssignmentCallEncoder::encode_assignment_call(region_id, para_id); + + // `ref_time` = TODO, we will round up to: TODO. + // `proof_size` = TODO, we will round up to: TODO. + let call_weight = Weight::from_parts(100_000_000, 10_000); + let fee = T::WeightToFee::weight_to_fee(&call_weight); + + let message = Xcm(vec![ + Instruction::WithdrawAsset( + MultiAsset { id: Concrete(MultiLocation::parent()), fun: Fungible(fee.into()) } + .into(), + ), + Instruction::BuyExecution { + fees: MultiAsset { + id: Concrete(MultiLocation::parent()), + fun: Fungible(fee.into()), + }, + weight_limit: Unlimited, + }, + Instruction::Transact { + origin_kind: OriginKind::SovereignAccount, + require_weight_at_most: call_weight, + call: assignment_call.into(), + }, + ]); match pallet_xcm::Pallet::::send_xcm( Here, diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 943aa44c..4038f05a 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -15,8 +15,11 @@ #![cfg_attr(not(feature = "std"), no_std)] -use crate::assigner::RegionAssigner; -use frame_support::traits::{nonfungible::Transfer, Currency, ExistenceRequirement}; +use crate::assigner::{AssignmentCallEncoder, RegionAssigner}; +use frame_support::{ + traits::{nonfungible::Transfer, Currency, ExistenceRequirement}, + weights::WeightToFee, +}; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; use order_primitives::{OrderId, OrderInspect, Requirements}; @@ -45,7 +48,11 @@ pub mod pallet { use super::*; use frame_support::{ pallet_prelude::*, - traits::{fungible::Mutate, ReservableCurrency}, + traits::{ + fungible::{Inspect, Mutate}, + tokens::Balance, + ReservableCurrency, + }, }; use frame_system::pallet_prelude::*; @@ -58,6 +65,11 @@ pub mod pallet { /// Currency used for purchasing coretime. type Currency: Mutate + ReservableCurrency; + /// Relay chain balance type + type Balance: Balance + + Into<>::Balance> + + Into; + /// Type over which we can access order data. type Orders: OrderInspect; @@ -74,6 +86,12 @@ pub mod pallet { /// Type assigning the region to the specified task. type RegionAssigner: RegionAssigner; + /// Type whcih encodes the region assignment call. + type AssignmentCallEncoder: AssignmentCallEncoder; + + /// Type for weight to fee conversion on the ReigonX parachain. + type WeightToFee: WeightToFee; + /// The Coretime chain from which we read region state. type CoretimeChain: Get; From ba5a61d7677bfd900fbd5051560aacc89115cc78 Mon Sep 17 00:00:00 2001 From: Sergej Date: Tue, 23 Jul 2024 14:17:39 +0200 Subject: [PATCH 17/34] mock.rs compiles --- pallets/processor/Cargo.toml | 1 + pallets/processor/src/mock.rs | 72 +++++++++++++++++++++++++++++++++-- 2 files changed, 69 insertions(+), 4 deletions(-) diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml index aee9f816..e5c50d0b 100644 --- a/pallets/processor/Cargo.toml +++ b/pallets/processor/Cargo.toml @@ -35,6 +35,7 @@ region-primitives = { workspace = true, default-features = false } [dev-dependencies] serde = { workspace = true } +smallvec = { workspace = true } pallet-balances = { workspace = true, default-features = false } pallet-regions = { workspace = true, default-features = false } diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 659bdb77..e247e07f 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -17,6 +17,10 @@ use frame_support::{ pallet_prelude::*, parameter_types, traits::{fungible::Mutate, tokens::Preservation, Everything}, + weights::{ + constants::ExtrinsicBaseWeight, WeightToFeeCoefficient, WeightToFeeCoefficients, + WeightToFeePolynomial, + }, }; use ismp::{ consensus::StateMachineId, @@ -26,21 +30,42 @@ use ismp::{ router::PostResponse, }; use ismp_testsuite::mocks::Host; -use order_primitives::OrderId; +use order_primitives::{OrderId, ParaId}; +use pallet_broker::RegionId; use pallet_orders::FeeHandler; use pallet_regions::primitives::StateMachineHeightProvider; +use smallvec::smallvec; use sp_core::{ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, BlockNumberProvider, Convert, IdentityLookup}, - BuildStorage, DispatchResult, + BuildStorage, DispatchResult, Perbill, }; use std::sync::Arc; +use xcm::latest::prelude::*; type AccountId = u64; type Block = frame_system::mocking::MockBlock; pub const TREASURY: AccountId = 42; +pub const MILLIUNIT: u64 = 1_000_000_000; +pub struct WeightToFee; +impl WeightToFeePolynomial for WeightToFee { + type Balance = u64; + fn polynomial() -> WeightToFeeCoefficients { + // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT: + // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT + let p = MILLIUNIT / 10; + let q = 100 * u64::from(ExtrinsicBaseWeight::get().ref_time()); + smallvec![WeightToFeeCoefficient { + degree: 1, + negative: false, + coeff_frac: Perbill::from_rational(p % q, q), + coeff_integer: p / q, + }] + } +} + // Configure a mock runtime to test the pallet. frame_support::construct_runtime!( pub enum Test @@ -137,13 +162,13 @@ impl IsmpDispatcher for MockDispatcher { } parameter_types! { - pub const CoretimeChain: StateMachine = StateMachine::Kusama(1005); // coretime-kusama + pub const CoretimeChainStateMachine: StateMachine = StateMachine::Kusama(1005); // coretime-kusama } impl pallet_regions::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; - type CoretimeChain = CoretimeChain; + type CoretimeChain = CoretimeChainStateMachine; type IsmpDispatcher = MockDispatcher; type StateMachineHeightProvider = MockStateMachineHeightProvider; type Timeout = ConstU64<1000>; @@ -194,12 +219,51 @@ impl pallet_orders::Config for Test { type WeightInfo = (); } +parameter_types! { + // The location of the Coretime parachain. + pub const CoretimeChain: MultiLocation = MultiLocation { parents: 1, interior: X1(Parachain(1005)) }; +} + +#[derive(Encode, Decode)] +enum CoretimeRuntimeCalls { + #[codec(index = 92)] + Broker(BrokerPalletCalls), +} + +/// Broker pallet calls. +// +// NOTE: We only use the `CreateOrder` call. +#[derive(Encode, Decode)] +enum BrokerPalletCalls { + #[codec(index = 0)] + Assign(RegionId, ParaId), +} + +pub struct AssignmentCallEncoder; +impl crate::AssignmentCallEncoder for AssignmentCallEncoder { + fn encode_assignment_call(region_id: RegionId, para_id: ParaId) -> Vec { + CoretimeRuntimeCalls::Broker(BrokerPalletCalls::Assign(region_id, para_id)).encode() + } +} + +pub struct DummyRegionAssigner; +impl crate::RegionAssigner for DummyRegionAssigner { + fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult { + Ok(()) + } +} + impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; + type Balance = u64; type Orders = Orders; type OrderToAccountId = OrderToAccountId; type Regions = Regions; + type AssignmentCallEncoder = AssignmentCallEncoder; + type RegionAssigner = DummyRegionAssigner; + type CoretimeChain = CoretimeChain; + type WeightToFee = WeightToFee; type WeightInfo = (); } From 519f68ecea3750f3cea87a98a64488dcad8de868 Mon Sep 17 00:00:00 2001 From: Sergej Date: Tue, 23 Jul 2024 16:28:35 +0200 Subject: [PATCH 18/34] add some docs --- Cargo.lock | 1 + pallets/processor/src/lib.rs | 19 ++++++++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index ebfb3803..8bd49de5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -7031,6 +7031,7 @@ dependencies = [ "region-primitives", "scale-info", "serde", + "smallvec", "sp-core", "sp-io", "sp-runtime", diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 4038f05a..50b17d0b 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -134,6 +134,16 @@ pub mod pallet { #[pallet::call] impl Pallet { + /// Extrinsic for fulfilling an order. + /// + /// This extrinsic will also attempt to assign the region to the `para_id` specified by the + /// order. In case this fails, the region will be TODO + /// + /// ## Arguments: + /// - `origin`: Signed origin; the region owner. + /// - `order_id`: The order which the caller intends to fulfill. + /// - `region_id`: The region that the caller intends to sell to the coretime order. The + /// region must match the order requierements otherwise the extrinsic will fail #[pallet::call_index(0)] #[pallet::weight(10_000)] pub fn fulfill_order( @@ -177,6 +187,8 @@ pub mod pallet { // remove the order T::Orders::remove_order(&order_id); + Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); + // NOTE: if an error occurs we don't return error, we instead return ok and emit // appropriate event so the transaction doesn't get reverted in case the assignment // fails. @@ -185,8 +197,13 @@ pub mod pallet { return Ok(()) } - Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); + Ok(()) + } + /// TODO + #[pallet::call_index(1)] + #[pallet::weight(10_000)] + pub fn assign(origin: OriginFor) -> DispatchResult { Ok(()) } } From cb29be8e86b5207f5828e570e1b6a5c15202aafc Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 12:17:59 +0200 Subject: [PATCH 19/34] region assignment --- pallets/processor/src/lib.rs | 50 ++++++++++++++++++++++++++-------- pallets/processor/src/mock.rs | 9 ++++++ pallets/processor/src/tests.rs | 2 ++ 3 files changed, 50 insertions(+), 11 deletions(-) diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 50b17d0b..42d5ec7f 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -22,7 +22,7 @@ use frame_support::{ }; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; -use order_primitives::{OrderId, OrderInspect, Requirements}; +use order_primitives::{OrderId, OrderInspect, ParaId, Requirements}; pub use pallet::*; use pallet_broker::{RegionId, RegionRecord}; use region_primitives::RegionInspect; @@ -102,11 +102,19 @@ pub mod pallet { #[pallet::pallet] pub struct Pallet(_); + /// Specifies the assignment for each region. + #[pallet::storage] + #[pallet::getter(fn listings)] + pub type RegionAssignments = + StorageMap<_, Blake2_128Concat, RegionId, ParaId, OptionQuery>; + #[pallet::event] #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Order got fulfilled with a region which is matching the requirements. OrderFulfilled { order_id: OrderId, region_id: RegionId, seller: T::AccountId }, + /// Region got successfully assigned to a parachain. + RegionAssigned { region_id: RegionId, para_id: ParaId }, /// Region assignment failed. AssignmentFailed(DispatchError), } @@ -130,6 +138,8 @@ pub mod pallet { RegionLocked, /// The caller is not the owner of the region. NotOwner, + /// We didn't find the task to which the region is supposed to be assigned. + RegionAssignmentNotFound, } #[pallet::call] @@ -137,7 +147,11 @@ pub mod pallet { /// Extrinsic for fulfilling an order. /// /// This extrinsic will also attempt to assign the region to the `para_id` specified by the - /// order. In case this fails, the region will be TODO + /// order. + /// + /// In case this fails, the region will be tranferred to the order creator and anyone can + /// call the `assign` extrinsic to assign it to specific para. The region will be locked, + /// and only assignment is allowed. /// /// ## Arguments: /// - `origin`: Signed origin; the region owner. @@ -165,14 +179,15 @@ pub mod pallet { // Transfer the region to the order creator // - // NOTE: Since we are assigning the region in this extrinsic, we will transfer it to - // the order creator and in case the extrinsic fails we creator will keep the region and - // can assign it himelf. - // - // ADDITONAL NOTE: Instead of transferring to the creator we should maybe indicate - // somehow that the order was fulfilled, the region is reserved and anyone can call a - // separate extrinsic to assign it to the task. + // We will try to assign the region to the task, however before we do that we will + // transfer it to the order creator. This way in case the assignment fails the region + // will still be owned by the creator. T::Regions::transfer(®ion_id.into(), &order.creator)?; + // Lock the region so the owner creator cannot transfer it. + T::Regions::lock(®ion_id.into(), None)?; + // Even though the region will be owned by the creator, anyone can assign it to the task + // by calling the `assign` extrinsic. + RegionAssignments::::insert(®ion_id, order.para_id); let order_account = T::OrderToAccountId::convert(order_id); let amount = T::Currency::free_balance(&order_account); @@ -197,13 +212,26 @@ pub mod pallet { return Ok(()) } + Self::deposit_event(Event::RegionAssigned { region_id, para_id: order.para_id }); Ok(()) } - /// TODO + /// Assign a region to the specific `para_id`. + /// + /// ## Arguments: + /// - `origin`: Signed origin; can be anyone. + /// - `region_id`: The region that the caller intends assign. Must be found in the + /// `RegionAssignments` mapping. #[pallet::call_index(1)] #[pallet::weight(10_000)] - pub fn assign(origin: OriginFor) -> DispatchResult { + pub fn assign(origin: OriginFor, region_id: RegionId) -> DispatchResult { + let _who = ensure_signed(origin)?; + let para_id = RegionAssignments::::get(region_id) + .ok_or(Error::::RegionAssignmentNotFound)?; + + T::RegionAssigner::assign(region_id, para_id)?; + + Self::deposit_event(Event::RegionAssigned { region_id, para_id }); Ok(()) } } diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index e247e07f..8c3d58f1 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . +use core::cell::RefCell; use frame_support::{ pallet_prelude::*, parameter_types, @@ -246,9 +247,17 @@ impl crate::AssignmentCallEncoder for AssignmentCallEncoder { } } +thread_local! { + pub static ASSIGNMENTS: RefCell> = Default::default(); +} + pub struct DummyRegionAssigner; impl crate::RegionAssigner for DummyRegionAssigner { fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult { + ASSIGNMENTS.with(|assignments| { + let mut assignments = assignments.borrow_mut(); + assignments.push((region_id, para_id)); + }); Ok(()) } } diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index 01e6aac4..f7d8ffea 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -77,3 +77,5 @@ fn fulfill_order_works() { assert_eq!(Regions::regions(region_id).unwrap().owner, 2000); }); } + +// TODO test: can't fulfill with a locked region. From 649058f70fcf3e403bbe99cf9a4394b69d292c60 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 14:51:35 +0200 Subject: [PATCH 20/34] check assignments & lock --- pallets/processor/src/mock.rs | 4 ++++ pallets/processor/src/tests.rs | 37 +++++++++++++++++++++++++--------- 2 files changed, 31 insertions(+), 10 deletions(-) diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 8c3d58f1..58f8834d 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -251,6 +251,10 @@ thread_local! { pub static ASSIGNMENTS: RefCell> = Default::default(); } +pub fn assignments() -> Vec<(RegionId, ParaId)> { + ASSIGNMENTS.with(|assignments| assignments.borrow().clone()) +} + pub struct DummyRegionAssigner; impl crate::RegionAssigner for DummyRegionAssigner { fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult { diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index f7d8ffea..d38b6411 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -13,14 +13,17 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::mock::{new_test_ext, Balances, Orders, Processor, Regions, RuntimeOrigin, Test}; +use crate::{ + mock::{assignments, new_test_ext, Balances, Orders, Processor, Regions, RuntimeOrigin, Test}, + Error, +}; use frame_support::{ - assert_ok, + assert_noop, assert_ok, traits::{nonfungible::Mutate, Currency}, }; +use nonfungible_primitives::LockableNonFungible; use order_primitives::{Order, Requirements}; use pallet_broker::{CoreMask, RegionId, RegionRecord}; -use region_primitives::RegionInspect; #[test] fn fulfill_order_works() { @@ -33,7 +36,7 @@ fn fulfill_order_works() { core_occupancy: 28800, // Half of a core. }; - // 2. create an order + // 1. create an order ::Currency::make_free_balance_be(&order_creator, 1000u32.into()); assert_ok!(Orders::create_order( RuntimeOrigin::signed(order_creator.clone()), @@ -45,20 +48,22 @@ fn fulfill_order_works() { Some(Order { para_id: 2000.into(), creator: order_creator, requirements }) ); - // 3. make contributions to an order + // 2. make contributions to an order assert_ok!(Orders::contribute(RuntimeOrigin::signed(10), 0, 500)); assert_ok!(Orders::contribute(RuntimeOrigin::signed(11), 0, 800)); assert_ok!(Orders::contribute(RuntimeOrigin::signed(12), 0, 200)); // Fulfill order fails with a region that doesn't meet the requirements: - - // Create a region which doesn't the requirements: let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 10) }; assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); assert_ok!(Regions::set_record( region_id, RegionRecord { end: 123600, owner: 1, paid: None } )); + assert_noop!( + Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id), + Error::::RegionCoreOccupancyInsufficient + ); // Create a region which meets the requirements: let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; @@ -68,14 +73,26 @@ fn fulfill_order_works() { RegionRecord { end: 123600, owner: 1, paid: None } )); - // Works with a region that meets the requirements: + // Fails if the region is locked: + Regions::lock(®ion_id.into(), None).unwrap(); + assert_noop!( + Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id), + Error::::RegionLocked + ); + + // Works with a region that meets the requirements and is unlocked: + + Regions::unlock(®ion_id.into(), None).unwrap(); assert_ok!(Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id)); + // Ensure order is removed: assert!(Orders::orders(0).is_none()); + // Region owner receives as the contributions for fulfilling the order: assert_eq!(Balances::free_balance(region_owner), 1500); assert_eq!(Regions::regions(region_id).unwrap().owner, 2000); + + // Assignment request is emmited: + assert_eq!(assignments(), vec![(region_id, 2000.into())]); }); } - -// TODO test: can't fulfill with a locked region. From 3be428e30e4556e094a72d37844301b4fd72248d Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 15:00:29 +0200 Subject: [PATCH 21/34] ensure_matching_requirements_works --- pallets/processor/src/tests.rs | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index d38b6411..eb2b3afc 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -96,3 +96,51 @@ fn fulfill_order_works() { assert_eq!(assignments(), vec![(region_id, 2000.into())]); }); } + +#[test] +fn ensure_matching_requirements_works() { + new_test_ext(vec![]).execute_with(|| { + let requirements = Requirements { + begin: 0, + end: 8, + core_occupancy: 28800, // Half of a core. + }; + + // Region starts too late: + assert_noop!( + Processor::ensure_matching_requirements( + RegionId { begin: 2, core: 0, mask: CoreMask::complete() }, + RegionRecord { end: 10, owner: 1, paid: None }, + requirements.clone() + ), + Error::::RegionStartsTooLate + ); + + // Region ends too soon: + assert_noop!( + Processor::ensure_matching_requirements( + RegionId { begin: 0, core: 0, mask: CoreMask::complete() }, + RegionRecord { end: 4, owner: 1, paid: None }, + requirements.clone() + ), + Error::::RegionEndsTooSoon + ); + + // Region core occupancy insufficient: + assert_noop!( + Processor::ensure_matching_requirements( + RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 39) }, + RegionRecord { end: 8, owner: 1, paid: None }, + requirements.clone() + ), + Error::::RegionCoreOccupancyInsufficient + ); + + // Works when all requirements are met: + assert_ok!(Processor::ensure_matching_requirements( + RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 40) }, + RegionRecord { end: 8, owner: 1, paid: None }, + requirements.clone() + ),); + }) +} From 41326273bed0fcd9167566e729d0552a561796d5 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 15:25:01 +0200 Subject: [PATCH 22/34] check events & assign works --- pallets/processor/src/lib.rs | 4 ++-- pallets/processor/src/tests.rs | 32 +++++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 42d5ec7f..33d4f518 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -112,7 +112,7 @@ pub mod pallet { #[pallet::generate_deposit(pub(super) fn deposit_event)] pub enum Event { /// Order got fulfilled with a region which is matching the requirements. - OrderFulfilled { order_id: OrderId, region_id: RegionId, seller: T::AccountId }, + OrderProcessed { order_id: OrderId, region_id: RegionId, seller: T::AccountId }, /// Region got successfully assigned to a parachain. RegionAssigned { region_id: RegionId, para_id: ParaId }, /// Region assignment failed. @@ -202,7 +202,7 @@ pub mod pallet { // remove the order T::Orders::remove_order(&order_id); - Self::deposit_event(Event::OrderFulfilled { order_id, region_id, seller: who }); + Self::deposit_event(Event::OrderProcessed { order_id, region_id, seller: who }); // NOTE: if an error occurs we don't return error, we instead return ok and emit // appropriate event so the transaction doesn't get reverted in case the assignment diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index eb2b3afc..287668b3 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -14,15 +14,18 @@ // along with RegionX. If not, see . use crate::{ - mock::{assignments, new_test_ext, Balances, Orders, Processor, Regions, RuntimeOrigin, Test}, - Error, + mock::{ + assignments, new_test_ext, Balances, Orders, Processor, Regions, RuntimeOrigin, System, + Test, + }, + Error, Event, }; use frame_support::{ assert_noop, assert_ok, traits::{nonfungible::Mutate, Currency}, }; use nonfungible_primitives::LockableNonFungible; -use order_primitives::{Order, Requirements}; +use order_primitives::{Order, ParaId, Requirements}; use pallet_broker::{CoreMask, RegionId, RegionRecord}; #[test] @@ -84,6 +87,11 @@ fn fulfill_order_works() { Regions::unlock(®ion_id.into(), None).unwrap(); assert_ok!(Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id)); + // Check events + System::assert_has_event(Event::RegionAssigned { region_id, para_id: 2000.into() }.into()); + System::assert_has_event( + Event::OrderProcessed { order_id: 0, region_id, seller: region_owner }.into(), + ); // Ensure order is removed: assert!(Orders::orders(0).is_none()); @@ -97,6 +105,24 @@ fn fulfill_order_works() { }); } +#[test] +fn assign_works() { + new_test_ext(vec![]).execute_with(|| { + let para_id: ParaId = 2000.into(); + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + + // Fails if the record cannot be found in `RegionAssignments` + assert_noop!( + Processor::assign(RuntimeOrigin::signed(1), region_id), + Error::::RegionAssignmentNotFound + ); + + crate::RegionAssignments::::insert(®ion_id, para_id); + assert_ok!(Processor::assign(RuntimeOrigin::signed(1), region_id)); + System::assert_last_event(Event::RegionAssigned { region_id, para_id: 2000.into() }.into()); + }); +} + #[test] fn ensure_matching_requirements_works() { new_test_ext(vec![]).execute_with(|| { From 0e8b419036edfc3a11d70bae0642ffa57d2b5c05 Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 17:00:17 +0200 Subject: [PATCH 23/34] benchmark progress | not working --- pallets/orders/src/lib.rs | 27 +++++++--- pallets/processor/Cargo.toml | 1 + pallets/processor/src/benchmarking.rs | 74 +++++++++++++++++++++++++++ pallets/processor/src/lib.rs | 11 ++++ pallets/processor/src/mock.rs | 26 +++++++++- pallets/processor/src/tests.rs | 10 +--- pallets/processor/src/types.rs | 26 ++++++++++ 7 files changed, 157 insertions(+), 18 deletions(-) create mode 100644 pallets/processor/src/benchmarking.rs create mode 100644 pallets/processor/src/types.rs diff --git a/pallets/orders/src/lib.rs b/pallets/orders/src/lib.rs index bc691f5a..b7a7ee0e 100644 --- a/pallets/orders/src/lib.rs +++ b/pallets/orders/src/lib.rs @@ -168,14 +168,7 @@ pub mod pallet { ) -> DispatchResult { let who = ensure_signed(origin)?; - T::OrderCreationFeeHandler::handle(&who, T::OrderCreationCost::get())?; - - let order_id = NextOrderId::::get(); - Orders::::insert(order_id, Order { creator: who.clone(), para_id, requirements }); - NextOrderId::::put(order_id.saturating_add(1)); - - Self::deposit_event(Event::OrderCreated { order_id, by: who }); - Ok(()) + Self::do_create_order(who, para_id, requirements) } /// Extrinsic for cancelling an order. @@ -264,6 +257,24 @@ pub mod pallet { } impl Pallet { + pub fn do_create_order( + creator: T::AccountId, + para_id: ParaId, + requirements: Requirements, + ) -> DispatchResult { + T::OrderCreationFeeHandler::handle(&creator, T::OrderCreationCost::get())?; + + let order_id = NextOrderId::::get(); + Orders::::insert( + order_id, + Order { creator: creator.clone(), para_id, requirements }, + ); + NextOrderId::::put(order_id.saturating_add(1)); + + Self::deposit_event(Event::OrderCreated { order_id, by: creator }); + Ok(()) + } + pub(crate) fn do_cancel_order( order_id: OrderId, current_timeslice: Timeslice, diff --git a/pallets/processor/Cargo.toml b/pallets/processor/Cargo.toml index e5c50d0b..bf5e9cf6 100644 --- a/pallets/processor/Cargo.toml +++ b/pallets/processor/Cargo.toml @@ -49,6 +49,7 @@ default = ["std"] runtime-benchmarks = [ "frame-benchmarking/runtime-benchmarks", "xcm-builder/runtime-benchmarks", + "pallet-xcm/runtime-benchmarks", ] std = [ "log/std", diff --git a/pallets/processor/src/benchmarking.rs b/pallets/processor/src/benchmarking.rs new file mode 100644 index 00000000..476c9300 --- /dev/null +++ b/pallets/processor/src/benchmarking.rs @@ -0,0 +1,74 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . + +//! Benchmarks for pallet-market + +#![cfg(feature = "runtime-benchmarks")] + +use super::*; + +use frame_benchmarking::v2::*; +use frame_support::{assert_ok, traits::fungible::Mutate}; +use frame_system::RawOrigin; +use pallet_broker::{CoreMask, RegionId, RegionRecord}; + +const SEED: u32 = 0; + +fn assert_last_event(generic_event: ::RuntimeEvent) { + frame_system::Pallet::::assert_last_event(generic_event.into()); +} + +#[benchmarks] +mod benchmarks { + use super::*; + + #[benchmark] + fn fulfill_order() -> Result<(), BenchmarkError> { + let caller: T::AccountId = whitelisted_caller(); + let requirements = Requirements { + begin: 0, + end: 8, + core_occupancy: 57600, // Full core. + }; + + assert_ok!(Orders::create_order( + T::RuntimeOrigin::signed(caller.clone()), + 2000.into(), + requirements.clone() + )); + // Create a region which meets the requirements: + // let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + // assert_ok!(Regions::mint_into(®ion_id.into(), &caller)); + // assert_ok!(Regions::set_record(region_id, RegionRecord { end: 10, owner: 1, paid: None + // })); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), 0, region_id); + + // assert_last_event::( + // Event::Listed { + // region_id, + // timeslice_price, + // seller: caller.clone(), + // sale_recipient: caller, + // } + // .into(), + // ); + + Ok(()) + } + + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); +} diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 33d4f518..3b396a55 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -29,11 +29,19 @@ use region_primitives::RegionInspect; use sp_runtime::traits::Convert; use xcm::opaque::lts::MultiLocation; +mod types; + +#[cfg(feature = "runtime-benchmarks")] +use crate::types::OrderFactory; + #[cfg(test)] mod mock; #[cfg(test)] mod tests; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; + pub mod assigner; const LOG_TARGET: &str = "runtime::order-creator"; @@ -97,6 +105,9 @@ pub mod pallet { /// Weight Info type WeightInfo: WeightInfo; + + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper: RegionFactory + OrderFactory; } #[pallet::pallet] diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 58f8834d..2c871231 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -13,6 +13,7 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . +use crate::types::OrderFactory; use core::cell::RefCell; use frame_support::{ pallet_prelude::*, @@ -31,8 +32,8 @@ use ismp::{ router::PostResponse, }; use ismp_testsuite::mocks::Host; -use order_primitives::{OrderId, ParaId}; -use pallet_broker::RegionId; +use order_primitives::{OrderId, ParaId, Requirements}; +use pallet_broker::{RegionId, RegionRecordOf}; use pallet_orders::FeeHandler; use pallet_regions::primitives::StateMachineHeightProvider; use smallvec::smallvec; @@ -266,6 +267,25 @@ impl crate::RegionAssigner for DummyRegionAssigner { } } +pub struct BenchmarkHelper; +impl RegionFactory for BenchmarkHelper { + fn create_region( + region_id: RegionId, + record: RegionRecordOf, + owner: ::AccountId, + ) -> DispatchResult { + Regions::mint_into(®ion_id.into(), &owner)?; + Regions::set_record(region_id, record.clone())?; + Ok(()) + } +} + +impl crate::OrderFactory for BenchmarkHelper { + fn create_region(para_id: ParaId, requirements: Requirements) -> DispatchResult { + Orders::do_create_order(para_id, requirements) + } +} + impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -277,6 +297,8 @@ impl crate::Config for Test { type RegionAssigner = DummyRegionAssigner; type CoretimeChain = CoretimeChain; type WeightToFee = WeightToFee; + #[cfg(feature = "runtime-benchmarks")] + type BenchmarkHelper = BenchmarkHelper; type WeightInfo = (); } diff --git a/pallets/processor/src/tests.rs b/pallets/processor/src/tests.rs index 287668b3..49a658b5 100644 --- a/pallets/processor/src/tests.rs +++ b/pallets/processor/src/tests.rs @@ -59,10 +59,7 @@ fn fulfill_order_works() { // Fulfill order fails with a region that doesn't meet the requirements: let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::from_chunk(0, 10) }; assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); - assert_ok!(Regions::set_record( - region_id, - RegionRecord { end: 123600, owner: 1, paid: None } - )); + assert_ok!(Regions::set_record(region_id, RegionRecord { end: 8, owner: 1, paid: None })); assert_noop!( Processor::fulfill_order(RuntimeOrigin::signed(region_owner), 0, region_id), Error::::RegionCoreOccupancyInsufficient @@ -71,10 +68,7 @@ fn fulfill_order_works() { // Create a region which meets the requirements: let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; assert_ok!(Regions::mint_into(®ion_id.into(), ®ion_owner)); - assert_ok!(Regions::set_record( - region_id, - RegionRecord { end: 123600, owner: 1, paid: None } - )); + assert_ok!(Regions::set_record(region_id, RegionRecord { end: 8, owner: 1, paid: None })); // Fails if the region is locked: Regions::lock(®ion_id.into(), None).unwrap(); diff --git a/pallets/processor/src/types.rs b/pallets/processor/src/types.rs new file mode 100644 index 00000000..219b84ae --- /dev/null +++ b/pallets/processor/src/types.rs @@ -0,0 +1,26 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . + +use crate::{BalanceOf, RegionId}; +use order_primitives::{ParaId, Requirements}; +use sp_runtime::DispatchResult; + +pub type RegionRecordOf = + pallet_broker::RegionRecord<::AccountId, BalanceOf>; + +/// Trait for creating regions. Used for benchmarking. +pub trait OrderFactory { + fn create_order(para_id: ParaId, requierements: Requirements) -> DispatchResult; +} From 6b046bdecffe16ca87d307704f06a05837a30e4d Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 19:56:12 +0200 Subject: [PATCH 24/34] remove benchmark helper --- pallets/market/src/benchmarking.rs | 8 ++++---- pallets/market/src/lib.rs | 8 +++----- pallets/market/src/mock.rs | 24 ++---------------------- pallets/market/src/types.rs | 12 +----------- pallets/regions/src/lib.rs | 16 ++++++++++++++-- primitives/region/src/lib.rs | 10 ++++++++-- 6 files changed, 32 insertions(+), 46 deletions(-) diff --git a/pallets/market/src/benchmarking.rs b/pallets/market/src/benchmarking.rs index c406a198..72d5f568 100644 --- a/pallets/market/src/benchmarking.rs +++ b/pallets/market/src/benchmarking.rs @@ -40,7 +40,7 @@ mod benchmarks { let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; let record: RegionRecordOf = RegionRecord { end: 8, owner: caller.clone(), paid: None }; - T::BenchmarkHelper::create_region(region_id, record, caller.clone())?; + T::Regions::create_region(region_id, record, caller.clone())?; let timeslice_price: BalanceOf = 1_000u32.into(); #[extrinsic_call] @@ -65,7 +65,7 @@ mod benchmarks { let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; let record: RegionRecordOf = RegionRecord { end: 8, owner: caller.clone(), paid: None }; - T::BenchmarkHelper::create_region(region_id, record, caller.clone())?; + T::Regions::create_region(region_id, record, caller.clone())?; let timeslice_price: BalanceOf = 1_000u32.into(); crate::Pallet::::list_region( @@ -89,7 +89,7 @@ mod benchmarks { let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; let record: RegionRecordOf = RegionRecord { end: 8, owner: caller.clone(), paid: None }; - T::BenchmarkHelper::create_region(region_id, record, caller.clone())?; + T::Regions::create_region(region_id, record, caller.clone())?; crate::Pallet::::list_region( RawOrigin::Signed(caller.clone()).into(), @@ -116,7 +116,7 @@ mod benchmarks { let record: RegionRecordOf = RegionRecord { end: 8, owner: alice.clone(), paid: None }; ::Currency::set_balance(&alice.clone(), u32::MAX.into()); - T::BenchmarkHelper::create_region(region_id, record, alice.clone())?; + T::Regions::create_region(region_id, record, alice.clone())?; crate::Pallet::::list_region( RawOrigin::Signed(alice).into(), region_id, diff --git a/pallets/market/src/lib.rs b/pallets/market/src/lib.rs index 3b74eaa5..78e47549 100644 --- a/pallets/market/src/lib.rs +++ b/pallets/market/src/lib.rs @@ -19,7 +19,7 @@ use frame_support::traits::{fungible::Inspect, tokens::Preservation}; use nonfungible_primitives::LockableNonFungible; pub use pallet::*; use pallet_broker::{RegionId, Timeslice}; -use region_primitives::RegionInspect; +use region_primitives::{RegionFactory, RegionInspect}; use sp_runtime::{traits::BlockNumberProvider, SaturatedConversion, Saturating}; mod types; @@ -67,7 +67,8 @@ pub mod pallet { // The item id is `u128` encoded RegionId. type Regions: Transfer + LockableNonFungible - + RegionInspect, ItemId = u128>; + + RegionInspect, ItemId = u128> + + RegionFactory>; /// Type for getting the current relay chain block. /// @@ -80,9 +81,6 @@ pub mod pallet { /// Weight Info type WeightInfo: WeightInfo; - - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper: RegionFactory; } #[pallet::pallet] diff --git a/pallets/market/src/mock.rs b/pallets/market/src/mock.rs index 5e40ef0c..2e9c359e 100644 --- a/pallets/market/src/mock.rs +++ b/pallets/market/src/mock.rs @@ -13,12 +13,7 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::{RegionId, RegionRecordOf}; -use frame_support::{ - pallet_prelude::*, - parameter_types, - traits::{nonfungible::Mutate, Everything}, -}; +use frame_support::{pallet_prelude::*, parameter_types, traits::Everything}; use ismp::{ consensus::StateMachineId, dispatcher::{DispatchRequest, FeeMetadata, IsmpDispatcher}, @@ -31,7 +26,7 @@ use pallet_regions::primitives::StateMachineHeightProvider; use sp_core::{ConstU64, H256}; use sp_runtime::{ traits::{BlakeTwo256, BlockNumberProvider, IdentityLookup}, - BuildStorage, DispatchResult, + BuildStorage, }; use std::sync::Arc; @@ -158,19 +153,6 @@ impl BlockNumberProvider for RelayBlockNumberProvider { } } -pub struct RegionFactory; -impl crate::RegionFactory for RegionFactory { - fn create_region( - region_id: RegionId, - record: RegionRecordOf, - owner: ::AccountId, - ) -> DispatchResult { - Regions::mint_into(®ion_id.into(), &owner)?; - Regions::set_record(region_id, record.clone())?; - Ok(()) - } -} - impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -178,8 +160,6 @@ impl crate::Config for Test { type RCBlockNumberProvider = RelayBlockNumberProvider; type TimeslicePeriod = ConstU64<80>; type WeightInfo = (); - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = RegionFactory; } // Build genesis storage according to the mock runtime. diff --git a/pallets/market/src/types.rs b/pallets/market/src/types.rs index 00920b2e..cf59e942 100644 --- a/pallets/market/src/types.rs +++ b/pallets/market/src/types.rs @@ -12,10 +12,9 @@ // // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::{BalanceOf, RegionId}; +use crate::BalanceOf; use codec::{Decode, Encode, MaxEncodedLen}; use scale_info::TypeInfo; -use sp_runtime::DispatchResult; pub type RegionRecordOf = pallet_broker::RegionRecord<::AccountId, BalanceOf>; @@ -32,12 +31,3 @@ pub struct Listing { /// This will usually be the seller account. pub sale_recipient: AccountId, } - -/// Trait for creating regions. Used for benchmarking. -pub trait RegionFactory { - fn create_region( - region_id: RegionId, - record: RegionRecordOf, - owner: T::AccountId, - ) -> DispatchResult; -} diff --git a/pallets/regions/src/lib.rs b/pallets/regions/src/lib.rs index 651e7edb..bf6a6804 100644 --- a/pallets/regions/src/lib.rs +++ b/pallets/regions/src/lib.rs @@ -17,7 +17,7 @@ use codec::{alloc::collections::BTreeMap, Decode}; use core::{cmp::max, marker::PhantomData}; -use frame_support::{pallet_prelude::Weight, PalletId}; +use frame_support::{pallet_prelude::Weight, traits::nonfungible::Mutate as NftMutate, PalletId}; use ismp::{ consensus::StateMachineId, dispatcher::{DispatchGet, DispatchRequest, FeeMetadata, IsmpDispatcher}, @@ -30,7 +30,7 @@ use ismp_parachain::PARACHAIN_CONSENSUS_ID; pub use pallet::*; use pallet_broker::RegionId; use pallet_ismp::{weights::IsmpModuleWeight, ModuleId}; -use region_primitives::{Record, Region}; +use region_primitives::{Record, Region, RegionFactory}; use scale_info::prelude::{format, vec, vec::Vec}; use sp_core::H256; use sp_runtime::traits::Zero; @@ -374,6 +374,18 @@ impl Default for IsmpRegionsModuleWeight { } } +impl RegionFactory> for Pallet { + fn create_region( + region_id: RegionId, + record: RegionRecordOf, + owner: ::AccountId, + ) -> sp_runtime::DispatchResult { + crate::Pallet::::mint_into(®ion_id.into(), &owner)?; + crate::Pallet::::set_record(region_id, record.clone())?; + Ok(()) + } +} + mod utils { use super::{BTreeMap, IsmpCustomError, IsmpError}; #[cfg(not(feature = "std"))] diff --git a/primitives/region/src/lib.rs b/primitives/region/src/lib.rs index 7df9b7ad..c7fcc084 100644 --- a/primitives/region/src/lib.rs +++ b/primitives/region/src/lib.rs @@ -15,8 +15,8 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode, MaxEncodedLen}; -use frame_support::Parameter; -use pallet_broker::RegionRecord; +use frame_support::{pallet_prelude::DispatchResult, Parameter}; +use pallet_broker::{RegionId, RegionRecord}; use scale_info::TypeInfo; use sp_core::H256; @@ -85,3 +85,9 @@ pub trait RegionInspect { /// If `None` the region was not found. fn region(region_id: &Self::ItemId) -> Option>; } + +/// Trait for creating regions. Mostly used for benchmarking. +pub trait RegionFactory { + fn create_region(region_id: RegionId, record: RegionRecord, owner: AccountId) + -> DispatchResult; +} From eb5abdc177f9d78f6f55dca662f9d1ac665b1dfd Mon Sep 17 00:00:00 2001 From: Sergej Date: Wed, 24 Jul 2024 20:19:21 +0200 Subject: [PATCH 25/34] order creator --- pallets/orders/src/lib.rs | 15 +++++++++++++-- pallets/processor/src/benchmarking.rs | 4 ++-- pallets/processor/src/lib.rs | 12 ++---------- pallets/processor/src/mock.rs | 26 ++------------------------ pallets/processor/src/types.rs | 26 -------------------------- primitives/order/src/lib.rs | 10 ++++++++++ 6 files changed, 29 insertions(+), 64 deletions(-) delete mode 100644 pallets/processor/src/types.rs diff --git a/pallets/orders/src/lib.rs b/pallets/orders/src/lib.rs index b7a7ee0e..f7d5902a 100644 --- a/pallets/orders/src/lib.rs +++ b/pallets/orders/src/lib.rs @@ -16,7 +16,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use frame_support::traits::{Currency, ExistenceRequirement}; -use order_primitives::{Order, OrderId, OrderInspect, Requirements}; +use order_primitives::{Order, OrderFactory, OrderId, OrderInspect, Requirements}; pub use pallet::*; use pallet_broker::Timeslice; use sp_runtime::{ @@ -257,7 +257,7 @@ pub mod pallet { } impl Pallet { - pub fn do_create_order( + pub(crate) fn do_create_order( creator: T::AccountId, para_id: ParaId, requirements: Requirements, @@ -309,3 +309,14 @@ pub mod pallet { } } } + +impl OrderFactory for Pallet { + fn create_order( + creator: T::AccountId, + para_id: ParaId, + requirements: Requirements, + ) -> sp_runtime::DispatchResult { + crate::Pallet::::do_create_order(creator, para_id, requirements)?; + Ok(()) + } +} diff --git a/pallets/processor/src/benchmarking.rs b/pallets/processor/src/benchmarking.rs index 476c9300..c62abbb0 100644 --- a/pallets/processor/src/benchmarking.rs +++ b/pallets/processor/src/benchmarking.rs @@ -43,13 +43,13 @@ mod benchmarks { core_occupancy: 57600, // Full core. }; - assert_ok!(Orders::create_order( + assert_ok!(T::Orders::create_order( T::RuntimeOrigin::signed(caller.clone()), 2000.into(), requirements.clone() )); // Create a region which meets the requirements: - // let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; // assert_ok!(Regions::mint_into(®ion_id.into(), &caller)); // assert_ok!(Regions::set_record(region_id, RegionRecord { end: 10, owner: 1, paid: None // })); diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 3b396a55..5eaf6b4a 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -22,18 +22,13 @@ use frame_support::{ }; use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; -use order_primitives::{OrderId, OrderInspect, ParaId, Requirements}; +use order_primitives::{OrderFactory, OrderId, OrderInspect, ParaId, Requirements}; pub use pallet::*; use pallet_broker::{RegionId, RegionRecord}; use region_primitives::RegionInspect; use sp_runtime::traits::Convert; use xcm::opaque::lts::MultiLocation; -mod types; - -#[cfg(feature = "runtime-benchmarks")] -use crate::types::OrderFactory; - #[cfg(test)] mod mock; #[cfg(test)] @@ -79,7 +74,7 @@ pub mod pallet { + Into; /// Type over which we can access order data. - type Orders: OrderInspect; + type Orders: OrderInspect + OrderFactory; /// A way for getting the associated account of an order. type OrderToAccountId: Convert; @@ -105,9 +100,6 @@ pub mod pallet { /// Weight Info type WeightInfo: WeightInfo; - - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper: RegionFactory + OrderFactory; } #[pallet::pallet] diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 2c871231..58f8834d 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -13,7 +13,6 @@ // You should have received a copy of the GNU General Public License // along with RegionX. If not, see . -use crate::types::OrderFactory; use core::cell::RefCell; use frame_support::{ pallet_prelude::*, @@ -32,8 +31,8 @@ use ismp::{ router::PostResponse, }; use ismp_testsuite::mocks::Host; -use order_primitives::{OrderId, ParaId, Requirements}; -use pallet_broker::{RegionId, RegionRecordOf}; +use order_primitives::{OrderId, ParaId}; +use pallet_broker::RegionId; use pallet_orders::FeeHandler; use pallet_regions::primitives::StateMachineHeightProvider; use smallvec::smallvec; @@ -267,25 +266,6 @@ impl crate::RegionAssigner for DummyRegionAssigner { } } -pub struct BenchmarkHelper; -impl RegionFactory for BenchmarkHelper { - fn create_region( - region_id: RegionId, - record: RegionRecordOf, - owner: ::AccountId, - ) -> DispatchResult { - Regions::mint_into(®ion_id.into(), &owner)?; - Regions::set_record(region_id, record.clone())?; - Ok(()) - } -} - -impl crate::OrderFactory for BenchmarkHelper { - fn create_region(para_id: ParaId, requirements: Requirements) -> DispatchResult { - Orders::do_create_order(para_id, requirements) - } -} - impl crate::Config for Test { type RuntimeEvent = RuntimeEvent; type Currency = Balances; @@ -297,8 +277,6 @@ impl crate::Config for Test { type RegionAssigner = DummyRegionAssigner; type CoretimeChain = CoretimeChain; type WeightToFee = WeightToFee; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = BenchmarkHelper; type WeightInfo = (); } diff --git a/pallets/processor/src/types.rs b/pallets/processor/src/types.rs deleted file mode 100644 index 219b84ae..00000000 --- a/pallets/processor/src/types.rs +++ /dev/null @@ -1,26 +0,0 @@ -// This file is part of RegionX. -// -// RegionX is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// RegionX is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with RegionX. If not, see . - -use crate::{BalanceOf, RegionId}; -use order_primitives::{ParaId, Requirements}; -use sp_runtime::DispatchResult; - -pub type RegionRecordOf = - pallet_broker::RegionRecord<::AccountId, BalanceOf>; - -/// Trait for creating regions. Used for benchmarking. -pub trait OrderFactory { - fn create_order(para_id: ParaId, requierements: Requirements) -> DispatchResult; -} diff --git a/primitives/order/src/lib.rs b/primitives/order/src/lib.rs index ff5b350b..3fba74f5 100644 --- a/primitives/order/src/lib.rs +++ b/primitives/order/src/lib.rs @@ -15,6 +15,7 @@ #![cfg_attr(not(feature = "std"), no_std)] use codec::{Decode, Encode, MaxEncodedLen}; pub use cumulus_primitives_core::ParaId; +use frame_support::pallet_prelude::DispatchResult; use pallet_broker::{PartsOf57600, Timeslice}; use scale_info::TypeInfo; @@ -54,3 +55,12 @@ pub trait OrderInspect { /// Remove an order with the associated id. fn remove_order(order_id: &OrderId); } + +/// Trait for creating orders. Mostly used for benchmarking. +pub trait OrderFactory { + fn create_order( + creator: AccountId, + para_id: ParaId, + requirements: Requirements, + ) -> DispatchResult; +} From 452cb9b4317d0c03d4146591a87fcbbce92d0d9e Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 25 Jul 2024 09:54:30 +0200 Subject: [PATCH 26/34] benchmarking --- pallets/processor/src/benchmarking.rs | 43 ++++++++++++++------------- pallets/processor/src/lib.rs | 5 ++-- 2 files changed, 26 insertions(+), 22 deletions(-) diff --git a/pallets/processor/src/benchmarking.rs b/pallets/processor/src/benchmarking.rs index c62abbb0..55d041bd 100644 --- a/pallets/processor/src/benchmarking.rs +++ b/pallets/processor/src/benchmarking.rs @@ -24,8 +24,6 @@ use frame_support::{assert_ok, traits::fungible::Mutate}; use frame_system::RawOrigin; use pallet_broker::{CoreMask, RegionId, RegionRecord}; -const SEED: u32 = 0; - fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); } @@ -43,32 +41,37 @@ mod benchmarks { core_occupancy: 57600, // Full core. }; - assert_ok!(T::Orders::create_order( - T::RuntimeOrigin::signed(caller.clone()), - 2000.into(), - requirements.clone() - )); + ::Currency::set_balance(&caller.clone(), u32::MAX.into()); + assert_ok!(T::Orders::create_order(caller.clone(), 2000.into(), requirements.clone())); + // Create a region which meets the requirements: let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; - // assert_ok!(Regions::mint_into(®ion_id.into(), &caller)); - // assert_ok!(Regions::set_record(region_id, RegionRecord { end: 10, owner: 1, paid: None - // })); + let record: RegionRecordOf = RegionRecord { end: 8, owner: caller.clone(), paid: None }; + T::Regions::create_region(region_id, record, caller.clone())?; #[extrinsic_call] _(RawOrigin::Signed(caller.clone()), 0, region_id); - // assert_last_event::( - // Event::Listed { - // region_id, - // timeslice_price, - // seller: caller.clone(), - // sale_recipient: caller, - // } - // .into(), - // ); + assert_last_event::(Event::RegionAssigned { region_id, para_id: 2000.into() }.into()); + + Ok(()) + } + + #[benchmark] + fn assign() -> Result<(), BenchmarkError> { + let caller: T::AccountId = whitelisted_caller(); + let para_id: ParaId = 2000.into(); + + let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; + crate::RegionAssignments::::insert(®ion_id, para_id); + + #[extrinsic_call] + _(RawOrigin::Signed(caller.clone()), region_id); + + assert_last_event::(Event::RegionAssigned { region_id, para_id }.into()); Ok(()) } - impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test); + impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(vec![]), crate::mock::Test); } diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 5eaf6b4a..c327422c 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -25,7 +25,7 @@ use nonfungible_primitives::LockableNonFungible; use order_primitives::{OrderFactory, OrderId, OrderInspect, ParaId, Requirements}; pub use pallet::*; use pallet_broker::{RegionId, RegionRecord}; -use region_primitives::RegionInspect; +use region_primitives::{RegionFactory, RegionInspect}; use sp_runtime::traits::Convert; use xcm::opaque::lts::MultiLocation; @@ -84,7 +84,8 @@ pub mod pallet { // The item id is `u128` encoded RegionId. type Regions: Transfer + LockableNonFungible - + RegionInspect, ItemId = u128>; + + RegionInspect, ItemId = u128> + + RegionFactory>; /// Type assigning the region to the specified task. type RegionAssigner: RegionAssigner; From 62fcf1b31eeb0b624e9f24927cbee4fcf1f5dcbf Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 25 Jul 2024 12:20:44 +0200 Subject: [PATCH 27/34] nit fixes --- pallets/processor/src/assigner.rs | 7 +++++-- pallets/processor/src/lib.rs | 2 +- primitives/order/Cargo.toml | 6 +++--- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/pallets/processor/src/assigner.rs b/pallets/processor/src/assigner.rs index baeb1f6e..19a896c3 100644 --- a/pallets/processor/src/assigner.rs +++ b/pallets/processor/src/assigner.rs @@ -39,8 +39,11 @@ impl RegionAssigner for XcmRegionAssigner fn assign(region_id: RegionId, para_id: ParaId) -> DispatchResult { let assignment_call = T::AssignmentCallEncoder::encode_assignment_call(region_id, para_id); - // `ref_time` = TODO, we will round up to: TODO. - // `proof_size` = TODO, we will round up to: TODO. + // NOTE: the weight is runtime dependant, however we are rounding up a lot so it should + // always be sufficient. + // + // `ref_time` = `31_500`, we will round up to: `100_000_000`. + // `proof_size` = `4700`, we will round up to: `10_000`. let call_weight = Weight::from_parts(100_000_000, 10_000); let fee = T::WeightToFee::weight_to_fee(&call_weight); diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index c327422c..de4a3594 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -187,7 +187,7 @@ pub mod pallet { // transfer it to the order creator. This way in case the assignment fails the region // will still be owned by the creator. T::Regions::transfer(®ion_id.into(), &order.creator)?; - // Lock the region so the owner creator cannot transfer it. + // Lock the region so the order creator cannot transfer it. T::Regions::lock(®ion_id.into(), None)?; // Even though the region will be owned by the creator, anyone can assign it to the task // by calling the `assign` extrinsic. diff --git a/primitives/order/Cargo.toml b/primitives/order/Cargo.toml index d643a985..b84a4e8b 100644 --- a/primitives/order/Cargo.toml +++ b/primitives/order/Cargo.toml @@ -25,9 +25,9 @@ frame-support = { workspace = true, default-features = false } default = ["std"] std = [ "cumulus-primitives-core/std", - "log/std", - "codec/std", - "scale-info/std", + "log/std", + "codec/std", + "scale-info/std", "sp-core/std", "pallet-broker/std", "frame-support/std", From 678f66b105a291a7da3c5dc4a67dc20cd4df43c7 Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 25 Jul 2024 12:37:00 +0200 Subject: [PATCH 28/34] runtime implementation --- pallets/processor/src/assigner.rs | 2 ++ pallets/processor/src/mock.rs | 8 +++----- runtime/cocos/Cargo.toml | 6 ++++++ runtime/cocos/src/impls.rs | 23 +++++++++++++++++++++++ runtime/cocos/src/lib.rs | 20 +++++++++++++++++++- 5 files changed, 53 insertions(+), 6 deletions(-) diff --git a/pallets/processor/src/assigner.rs b/pallets/processor/src/assigner.rs index 19a896c3..5ca9b3a9 100644 --- a/pallets/processor/src/assigner.rs +++ b/pallets/processor/src/assigner.rs @@ -18,6 +18,8 @@ use core::marker::PhantomData; use frame_support::weights::WeightToFee; use order_primitives::ParaId; use pallet_broker::RegionId; +#[cfg(not(feature = "std"))] +use scale_info::prelude::{vec, vec::Vec}; use sp_runtime::{traits::Get, DispatchResult}; use xcm::latest::prelude::*; diff --git a/pallets/processor/src/mock.rs b/pallets/processor/src/mock.rs index 58f8834d..9d70207d 100644 --- a/pallets/processor/src/mock.rs +++ b/pallets/processor/src/mock.rs @@ -227,16 +227,14 @@ parameter_types! { #[derive(Encode, Decode)] enum CoretimeRuntimeCalls { - #[codec(index = 92)] + #[codec(index = 50)] Broker(BrokerPalletCalls), } -/// Broker pallet calls. -// -// NOTE: We only use the `CreateOrder` call. +/// Broker pallet calls. We don't define all of them, only the ones we use. #[derive(Encode, Decode)] enum BrokerPalletCalls { - #[codec(index = 0)] + #[codec(index = 10)] Assign(RegionId, ParaId), } diff --git a/runtime/cocos/Cargo.toml b/runtime/cocos/Cargo.toml index f1c76fbe..61c8b169 100644 --- a/runtime/cocos/Cargo.toml +++ b/runtime/cocos/Cargo.toml @@ -22,7 +22,9 @@ smallvec = { workspace = true } regionx-runtime-common = { workspace = true, default-features = false } pallet-market = { workspace = true, default-features = false } pallet-orders = { workspace = true, default-features = false } +pallet-processor = { workspace = true, default-features = false } pallet-regions = { workspace = true, default-features = false } +order-primitives = { workspace = true, default-features = false } # Polytope Labs ismp = { workspace = true } @@ -141,6 +143,7 @@ std = [ "orml-traits/std", "orml-unknown-tokens/std", "orml-xcm-support/std", + "order-primitives/std", "pallet-aura/std", "pallet-authorship/std", "pallet-asset-rate/std", @@ -151,6 +154,7 @@ std = [ "pallet-conviction-voting/std", "pallet-collator-selection/std", "pallet-referenda/std", + "pallet-processor/std", "pallet-regions/std", "regionx-runtime-common/std", "pallet-market/std", @@ -222,6 +226,7 @@ runtime-benchmarks = [ "pallet-orders/runtime-benchmarks", "pallet-proxy/runtime-benchmarks", "pallet-preimage/runtime-benchmarks", + "pallet-processor/runtime-benchmarks", "pallet-regions/runtime-benchmarks", "pallet-referenda/runtime-benchmarks", "pallet-sudo/runtime-benchmarks", @@ -270,6 +275,7 @@ try-runtime = [ "pallet-orders/try-runtime", "pallet-proxy/try-runtime", "pallet-preimage/try-runtime", + "pallet-processor/try-runtime", "pallet-regions/try-runtime", "pallet-referenda/try-runtime", "pallet-session/try-runtime", diff --git a/runtime/cocos/src/impls.rs b/runtime/cocos/src/impls.rs index 7e202100..a078e331 100644 --- a/runtime/cocos/src/impls.rs +++ b/runtime/cocos/src/impls.rs @@ -22,9 +22,12 @@ use frame_support::traits::{ fungibles, tokens::ConversionToAssetBalance, Defensive, ExistenceRequirement, Imbalance, InstanceFilter, OnUnbalanced, }; +use order_primitives::ParaId; use orml_asset_registry::DefaultAssetMetadata; use orml_traits::{asset_registry::AssetProcessor, GetByKey}; use pallet_asset_tx_payment::HandleCredit; +use pallet_broker::RegionId; +use pallet_processor::assigner::AssignmentCallEncoder as AssignmentCallEncoderT; use scale_info::TypeInfo; use sp_runtime::{ traits::{AccountIdConversion, CheckedDiv}, @@ -193,6 +196,26 @@ impl pallet_orders::FeeHandler for OrderCreationFeeHandler { } } +#[derive(Encode, Decode)] +enum CoretimeRuntimeCalls { + #[codec(index = 50)] + Broker(BrokerPalletCalls), +} + +/// Broker pallet calls. We don't define all of them, only the ones we use. +#[derive(Encode, Decode)] +enum BrokerPalletCalls { + #[codec(index = 10)] + Assign(RegionId, ParaId), +} + +pub struct AssignmentCallEncoder; +impl AssignmentCallEncoderT for AssignmentCallEncoder { + fn encode_assignment_call(region_id: RegionId, para_id: ParaId) -> Vec { + CoretimeRuntimeCalls::Broker(BrokerPalletCalls::Assign(region_id, para_id)).encode() + } +} + #[cfg(feature = "runtime-benchmarks")] pub mod benchmarks { use crate::*; diff --git a/runtime/cocos/src/lib.rs b/runtime/cocos/src/lib.rs index 737f920b..ae60c4f4 100644 --- a/runtime/cocos/src/lib.rs +++ b/runtime/cocos/src/lib.rs @@ -38,6 +38,7 @@ mod ismp; use impls::*; +use crate::xcm_config::CoretimeChainLocation; use codec::Encode; use cumulus_pallet_parachain_system::{ RelayChainState, RelayNumberMonotonicallyIncreases, RelaychainDataProvider, @@ -48,7 +49,8 @@ use frame_support::traits::{ tokens::{PayFromAccount, UnityAssetBalanceConversion}, Currency as PalletCurrency, EqualPrivilegeOnly, LinearStoragePrice, TransformOrigin, }; -use pallet_orders::OrderId; +use order_primitives::OrderId; +use pallet_processor::assigner::XcmRegionAssigner; use pallet_regions::primitives::StateMachineHeightProvider as StateMachineHeightProviderT; use parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling}; use polkadot_runtime_common::xcm_sender::NoPriceForMessageDelivery; @@ -785,6 +787,20 @@ impl pallet_orders::Config for Runtime { type WeightInfo = weights::pallet_orders::WeightInfo; } +impl pallet_processor::Config for Runtime { + type RuntimeEvent = RuntimeEvent; + type Currency = Balances; + type Balance = Balance; + type Orders = Orders; + type OrderToAccountId = OrderToAccountId; + type Regions = Regions; + type AssignmentCallEncoder = AssignmentCallEncoder; + type RegionAssigner = XcmRegionAssigner; + type CoretimeChain = CoretimeChainLocation; + type WeightToFee = WeightToFee; + type WeightInfo = (); +} + // Create the runtime by composing the FRAME pallets that were previously configured. construct_runtime!( pub enum Runtime @@ -849,6 +865,7 @@ construct_runtime!( Regions: pallet_regions = 90, Market: pallet_market = 91, Orders: pallet_orders = 92, + Processor: pallet_processor = 93, } ); @@ -875,6 +892,7 @@ mod benches { [pallet_message_queue, MessageQueue] [pallet_orders, Orders] [pallet_preimage, Preimage] + [pallet_processor, Processor] [pallet_referenda, NativeReferenda] [pallet_referenda, DelegatedReferenda] [pallet_scheduler, Scheduler] From bb56d58a32c5fad578b8249e12808aae83c6817a Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 25 Jul 2024 12:39:15 +0200 Subject: [PATCH 29/34] fix bench build --- Cargo.lock | 2 ++ runtime/cocos/src/impls.rs | 22 ---------------------- runtime/cocos/src/lib.rs | 2 -- 3 files changed, 2 insertions(+), 24 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8bd49de5..90c768cf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1239,6 +1239,7 @@ dependencies = [ "ismp-parachain", "ismp-parachain-runtime-api", "log", + "order-primitives", "orml-asset-registry", "orml-currencies", "orml-tokens", @@ -1262,6 +1263,7 @@ dependencies = [ "pallet-multisig", "pallet-orders", "pallet-preimage", + "pallet-processor", "pallet-proxy", "pallet-referenda", "pallet-regions", diff --git a/runtime/cocos/src/impls.rs b/runtime/cocos/src/impls.rs index a078e331..6c1be3f5 100644 --- a/runtime/cocos/src/impls.rs +++ b/runtime/cocos/src/impls.rs @@ -215,25 +215,3 @@ impl AssignmentCallEncoderT for AssignmentCallEncoder { CoretimeRuntimeCalls::Broker(BrokerPalletCalls::Assign(region_id, para_id)).encode() } } - -#[cfg(feature = "runtime-benchmarks")] -pub mod benchmarks { - use crate::*; - use frame_support::traits::nonfungible::Mutate; - use pallet_broker::RegionId; - use pallet_market::RegionRecordOf; - use sp_runtime::DispatchResult; - - pub struct RegionFactory; - impl pallet_market::RegionFactory for RegionFactory { - fn create_region( - region_id: RegionId, - record: RegionRecordOf, - owner: ::AccountId, - ) -> DispatchResult { - Regions::mint_into(®ion_id.into(), &owner)?; - Regions::set_record(region_id, record.clone())?; - Ok(()) - } - } -} diff --git a/runtime/cocos/src/lib.rs b/runtime/cocos/src/lib.rs index ae60c4f4..a0bd15bd 100644 --- a/runtime/cocos/src/lib.rs +++ b/runtime/cocos/src/lib.rs @@ -759,8 +759,6 @@ impl pallet_market::Config for Runtime { type RCBlockNumberProvider = RelaychainDataProvider; type TimeslicePeriod = ConstU32<80>; type WeightInfo = weights::pallet_market::WeightInfo; - #[cfg(feature = "runtime-benchmarks")] - type BenchmarkHelper = impls::benchmarks::RegionFactory; } parameter_types! { From 6d3d08080ed7183004032bda59f594f2837deed8 Mon Sep 17 00:00:00 2001 From: Sergej Date: Thu, 25 Jul 2024 12:54:38 +0200 Subject: [PATCH 30/34] fixes --- runtime/cocos/src/impls.rs | 2 +- runtime/cocos/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/runtime/cocos/src/impls.rs b/runtime/cocos/src/impls.rs index 6c1be3f5..b009630d 100644 --- a/runtime/cocos/src/impls.rs +++ b/runtime/cocos/src/impls.rs @@ -211,7 +211,7 @@ enum BrokerPalletCalls { pub struct AssignmentCallEncoder; impl AssignmentCallEncoderT for AssignmentCallEncoder { - fn encode_assignment_call(region_id: RegionId, para_id: ParaId) -> Vec { + fn encode_assignment_call(region_id: RegionId, para_id: ParaId) -> sp_std::vec::Vec { CoretimeRuntimeCalls::Broker(BrokerPalletCalls::Assign(region_id, para_id)).encode() } } diff --git a/runtime/cocos/src/lib.rs b/runtime/cocos/src/lib.rs index a0bd15bd..86b0206c 100644 --- a/runtime/cocos/src/lib.rs +++ b/runtime/cocos/src/lib.rs @@ -787,7 +787,7 @@ impl pallet_orders::Config for Runtime { impl pallet_processor::Config for Runtime { type RuntimeEvent = RuntimeEvent; - type Currency = Balances; + type Currency = RelaychainCurrency; type Balance = Balance; type Orders = Orders; type OrderToAccountId = OrderToAccountId; From 6d2497a80f1c988f0665b185e842a8bbddf40f46 Mon Sep 17 00:00:00 2001 From: Sergej Date: Fri, 26 Jul 2024 11:29:13 +0200 Subject: [PATCH 31/34] add weight --- pallets/processor/src/benchmarking.rs | 12 ++- pallets/processor/src/weights.rs | 131 ++++++++++++++++++++++++++ 2 files changed, 141 insertions(+), 2 deletions(-) create mode 100644 pallets/processor/src/weights.rs diff --git a/pallets/processor/src/benchmarking.rs b/pallets/processor/src/benchmarking.rs index 55d041bd..2bbc353c 100644 --- a/pallets/processor/src/benchmarking.rs +++ b/pallets/processor/src/benchmarking.rs @@ -23,6 +23,9 @@ use frame_benchmarking::v2::*; use frame_support::{assert_ok, traits::fungible::Mutate}; use frame_system::RawOrigin; use pallet_broker::{CoreMask, RegionId, RegionRecord}; +use sp_runtime::SaturatedConversion; + +const SEED: u32 = 0; fn assert_last_event(generic_event: ::RuntimeEvent) { frame_system::Pallet::::assert_last_event(generic_event.into()); @@ -35,14 +38,19 @@ mod benchmarks { #[benchmark] fn fulfill_order() -> Result<(), BenchmarkError> { let caller: T::AccountId = whitelisted_caller(); + let alice: T::AccountId = account("alice", 0, SEED); + let requirements = Requirements { begin: 0, end: 8, core_occupancy: 57600, // Full core. }; - ::Currency::set_balance(&caller.clone(), u32::MAX.into()); - assert_ok!(T::Orders::create_order(caller.clone(), 2000.into(), requirements.clone())); + ::Currency::make_free_balance_be( + &alice.clone(), + u64::MAX.saturated_into(), + ); + assert_ok!(T::Orders::create_order(alice.clone(), 2000.into(), requirements.clone())); // Create a region which meets the requirements: let region_id = RegionId { begin: 0, core: 0, mask: CoreMask::complete() }; diff --git a/pallets/processor/src/weights.rs b/pallets/processor/src/weights.rs new file mode 100644 index 00000000..542ed31f --- /dev/null +++ b/pallets/processor/src/weights.rs @@ -0,0 +1,131 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . + +//! Autogenerated weights for `pallet_processor` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-26, STEPS: `20`, REPEAT: `50`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `sergej-B650-AORUS-ELITE-AX`, CPU: `AMD Ryzen 9 7900X3D 12-Core Processor` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("cocos")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/regionx-node +// benchmark +// pallet +// --pallet +// pallet-processor +// --extrinsic=* +// --template +// ./config/frame-weight-template.hbs +// --output +// ./pallets/processor/src/weights.rs +// --steps +// 20 +// --repeat +// 50 +// --header +// ./config/HEADER-GPL3 +// --chain +// cocos +// --wasm-execution +// compiled +// --heap-pages +// 4096 + +#![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_processor`. +pub trait WeightInfo { + fn fulfill_order() -> Weight; + fn assign() -> Weight; +} + +/// Weights for `pallet_processor` using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + /// Storage: `Regions::Regions` (r:1 w:1) + /// Proof: `Regions::Regions` (`max_values`: None, `max_size`: Some(119), added: 2594, mode: `MaxEncodedLen`) + /// Storage: `Orders::Orders` (r:1 w:1) + /// Proof: `Orders::Orders` (`max_values`: None, `max_size`: Some(66), added: 2541, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:1 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Processor::RegionAssignments` (r:0 w:1) + /// Proof: `Processor::RegionAssignments` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + fn fulfill_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `572` + // Estimated: `3584` + // Minimum execution time: 43_483_000 picoseconds. + Weight::from_parts(45_266_000, 3584) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Processor::RegionAssignments` (r:1 w:0) + /// Proof: `Processor::RegionAssignments` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn assign() -> Weight { + // Proof Size summary in bytes: + // Measured: `141` + // Estimated: `3501` + // Minimum execution time: 21_691_000 picoseconds. + Weight::from_parts(22_143_000, 3501) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } +} + +// For backwards compatibility and tests. +impl WeightInfo for () { + /// Storage: `Regions::Regions` (r:1 w:1) + /// Proof: `Regions::Regions` (`max_values`: None, `max_size`: Some(119), added: 2594, mode: `MaxEncodedLen`) + /// Storage: `Orders::Orders` (r:1 w:1) + /// Proof: `Orders::Orders` (`max_values`: None, `max_size`: Some(66), added: 2541, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:1 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Processor::RegionAssignments` (r:0 w:1) + /// Proof: `Processor::RegionAssignments` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + fn fulfill_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `572` + // Estimated: `3584` + // Minimum execution time: 43_483_000 picoseconds. + Weight::from_parts(45_266_000, 3584) + .saturating_add(RocksDbWeight::get().reads(4_u64)) + .saturating_add(RocksDbWeight::get().writes(3_u64)) + } + /// Storage: `Processor::RegionAssignments` (r:1 w:0) + /// Proof: `Processor::RegionAssignments` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn assign() -> Weight { + // Proof Size summary in bytes: + // Measured: `141` + // Estimated: `3501` + // Minimum execution time: 21_691_000 picoseconds. + Weight::from_parts(22_143_000, 3501) + .saturating_add(RocksDbWeight::get().reads(2_u64)) + } +} From 3660242410177b6cce7b3e439490fdc5b30a2207 Mon Sep 17 00:00:00 2001 From: Szegoo Date: Fri, 26 Jul 2024 10:40:00 +0000 Subject: [PATCH 32/34] weight from gcloud instance --- runtime/cocos/src/weights/pallet_processor.rs | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 runtime/cocos/src/weights/pallet_processor.rs diff --git a/runtime/cocos/src/weights/pallet_processor.rs b/runtime/cocos/src/weights/pallet_processor.rs new file mode 100644 index 00000000..5be14421 --- /dev/null +++ b/runtime/cocos/src/weights/pallet_processor.rs @@ -0,0 +1,88 @@ +// This file is part of RegionX. +// +// RegionX is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// RegionX is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with RegionX. If not, see . + +//! Autogenerated weights for `pallet_processor` +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 32.0.0 +//! DATE: 2024-07-26, STEPS: `20`, REPEAT: `50`, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! WORST CASE MAP SIZE: `1000000` +//! HOSTNAME: `cocos-instance-1`, CPU: `Intel(R) Xeon(R) CPU @ 2.80GHz` +//! WASM-EXECUTION: `Compiled`, CHAIN: `Some("cocos")`, DB CACHE: `1024` + +// Executed Command: +// ./target/release/regionx-node +// benchmark +// pallet +// --chain +// cocos +// --pallet +// pallet_processor +// --steps +// 20 +// --repeat +// 50 +// --output +// ./runtime/cocos/src/weights/ +// --header +// ./config/HEADER-GPL3 +// --template +// ./config/runtime-weight-template.hbs +// --extrinsic=* +// --wasm-execution=compiled +// --heap-pages=4096 + +#![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; + +/// Weights for `pallet_processor` using the Substrate node and recommended hardware. +pub struct WeightInfo(PhantomData); +impl pallet_processor::WeightInfo for WeightInfo { + /// Storage: `Regions::Regions` (r:1 w:1) + /// Proof: `Regions::Regions` (`max_values`: None, `max_size`: Some(119), added: 2594, mode: `MaxEncodedLen`) + /// Storage: `Orders::Orders` (r:1 w:1) + /// Proof: `Orders::Orders` (`max_values`: None, `max_size`: Some(66), added: 2541, mode: `MaxEncodedLen`) + /// Storage: `Tokens::Accounts` (r:1 w:0) + /// Proof: `Tokens::Accounts` (`max_values`: None, `max_size`: Some(108), added: 2583, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + /// Storage: `Processor::RegionAssignments` (r:0 w:1) + /// Proof: `Processor::RegionAssignments` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + fn fulfill_order() -> Weight { + // Proof Size summary in bytes: + // Measured: `572` + // Estimated: `3584` + // Minimum execution time: 75_897_000 picoseconds. + Weight::from_parts(84_457_000, 3584) + .saturating_add(T::DbWeight::get().reads(4_u64)) + .saturating_add(T::DbWeight::get().writes(3_u64)) + } + /// Storage: `Processor::RegionAssignments` (r:1 w:0) + /// Proof: `Processor::RegionAssignments` (`max_values`: None, `max_size`: Some(36), added: 2511, mode: `MaxEncodedLen`) + /// Storage: `ParachainSystem::RelevantMessagingState` (r:1 w:0) + /// Proof: `ParachainSystem::RelevantMessagingState` (`max_values`: Some(1), `max_size`: None, mode: `Measured`) + fn assign() -> Weight { + // Proof Size summary in bytes: + // Measured: `141` + // Estimated: `3501` + // Minimum execution time: 48_346_000 picoseconds. + Weight::from_parts(49_659_000, 3501) + .saturating_add(T::DbWeight::get().reads(2_u64)) + } +} From d85dbbe0027892fec8a538a45d64be7b08ab6a48 Mon Sep 17 00:00:00 2001 From: Sergej Date: Fri, 26 Jul 2024 13:16:56 +0200 Subject: [PATCH 33/34] use weight --- pallets/processor/src/lib.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index de4a3594..58226b05 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -20,7 +20,6 @@ use frame_support::{ traits::{nonfungible::Transfer, Currency, ExistenceRequirement}, weights::WeightToFee, }; -use frame_system::WeightInfo; use nonfungible_primitives::LockableNonFungible; use order_primitives::{OrderFactory, OrderId, OrderInspect, ParaId, Requirements}; pub use pallet::*; @@ -39,6 +38,9 @@ mod benchmarking; pub mod assigner; +mod weights; +pub use weights::WeightInfo; + const LOG_TARGET: &str = "runtime::order-creator"; pub type BalanceOf = @@ -163,7 +165,7 @@ pub mod pallet { /// - `region_id`: The region that the caller intends to sell to the coretime order. The /// region must match the order requierements otherwise the extrinsic will fail #[pallet::call_index(0)] - #[pallet::weight(10_000)] + #[pallet::weight(T::WeightInfo::fulfill_order())] pub fn fulfill_order( origin: OriginFor, order_id: OrderId, @@ -227,7 +229,7 @@ pub mod pallet { /// - `region_id`: The region that the caller intends assign. Must be found in the /// `RegionAssignments` mapping. #[pallet::call_index(1)] - #[pallet::weight(10_000)] + #[pallet::weight(T::WeightInfo::assign())] pub fn assign(origin: OriginFor, region_id: RegionId) -> DispatchResult { let _who = ensure_signed(origin)?; let para_id = RegionAssignments::::get(region_id) From add628e039a7f3c2086658b153c6b09fb689bee4 Mon Sep 17 00:00:00 2001 From: Sergej Date: Fri, 26 Jul 2024 13:19:54 +0200 Subject: [PATCH 34/34] make clippy happy --- pallets/processor/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pallets/processor/src/lib.rs b/pallets/processor/src/lib.rs index 58226b05..357a25a1 100644 --- a/pallets/processor/src/lib.rs +++ b/pallets/processor/src/lib.rs @@ -193,7 +193,7 @@ pub mod pallet { T::Regions::lock(®ion_id.into(), None)?; // Even though the region will be owned by the creator, anyone can assign it to the task // by calling the `assign` extrinsic. - RegionAssignments::::insert(®ion_id, order.para_id); + RegionAssignments::::insert(region_id, order.para_id); let order_account = T::OrderToAccountId::convert(order_id); let amount = T::Currency::free_balance(&order_account);