diff --git a/flow/Cargo.toml b/flow/Cargo.toml index 217893af8..9b122f315 100644 --- a/flow/Cargo.toml +++ b/flow/Cargo.toml @@ -23,7 +23,11 @@ frame-system = { git = "https://github.com/paritytech/substrate", branch = "polk frame-benchmarking = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13", default-features = false, optional = true } orml-traits = { path = "../../orml/traits", default-features = false } +orml-tokens = { path = "../../orml/tokens", optional = true } +orml-currencies = { path = "../../orml/currencies", optional = true } + gamedao-traits = { package = "gamedao-traits", path = "../traits", default-features = false } +gamedao-control = { package = "gamedao-control", path = "../control", optional = true } [dev-dependencies] sp-core = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } @@ -33,14 +37,14 @@ sp-io = { git = "https://github.com/paritytech/substrate", branch = "polkadot-v0 pallet-timestamp = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } pallet-balances = { default-features = false, git = "https://github.com/paritytech/substrate", branch = "polkadot-v0.9.13" } -orml-tokens = { path = "../../orml/tokens", default-features = false } -orml-currencies = { path = "../../orml/currencies", default-features = false } - gamedao-control = { package = "gamedao-control", path = "../control", default-features = true } [features] default = ["std"] -runtime-benchmarks = ["frame-benchmarking"] +runtime-benchmarks = [ + "frame-benchmarking", + "gamedao-traits/frame-benchmarking", +] std = [ "codec/std", "serde/std", @@ -53,10 +57,12 @@ std = [ "sp-core/std", "sp-std/std", "sp-runtime/std", + "orml-traits/std", "orml-tokens/std", "orml-currencies/std", + "gamedao-traits/std", - "gamedao-control/std", + "gamedao-control/std", ] try-runtime = ["frame-support/try-runtime"] diff --git a/flow/src/benchmarking.rs b/flow/src/benchmarking.rs index 65ca2fe24..24e3b0b4a 100644 --- a/flow/src/benchmarking.rs +++ b/flow/src/benchmarking.rs @@ -1,16 +1,119 @@ //! Benchmarking setup for gamedao-flow use super::*; -#[allow(unused)] use crate::Pallet as Flow; -use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite}; +use frame_benchmarking::{account, benchmarks, impl_benchmark_test_suite, whitelisted_caller}; use frame_system::RawOrigin; -use sp_std::vec; +use sp_runtime::{DispatchError, traits::{Saturating}}; +use sp_std::{vec}; + + +fn fund_account(account_id: &T::AccountId, multiplier: Option) -> Result<(), DispatchError> { + let amount = T::MinContribution::get().saturating_mul(multiplier.unwrap_or(10).into()); + T::Currency::deposit(T::ProtocolTokenId::get(), account_id, amount)?; + T::Currency::deposit(T::PaymentTokenId::get(), account_id, amount)?; + Ok(()) +} + +/// Fund accounts with tokens, needed for org interactions +fn fund_accounts(account_ids: &Vec, multiplier: Option) -> Result<(), DispatchError> { + for account_id in account_ids { + fund_account::(&account_id, multiplier)?; + } + Ok(()) +} + +fn create_campaign_call(caller: T::AccountId, org_id: T::Hash) -> Result { + let name: Vec = vec![0; T::MaxNameLength::get() as usize]; + let cid: Vec = vec![0; T::MaxNameLength::get() as usize]; + let token_symbol: Vec = vec![0; 5]; + let token_name: Vec = vec![0; 32]; + Flow::::create_campaign( + RawOrigin::Signed(caller.clone()).into(), + org_id, + caller.clone(), + name, + T::MinContribution::get(), + T::MinContribution::get(), + frame_system::Pallet::::block_number() + 200_u32.into(), + Default::default(), + Default::default(), + cid, + token_name, + token_symbol + )?; + let nonce = Nonce::::get() - 1u128; + Ok(T::Hashing::hash_of(&nonce)) +} + benchmarks! { - simple_benchmark {}: {} - // ::Currency::set_balance(GameCurrencyId, &creator, 1000); + create_campaign { + let b in 0 .. T::MaxCampaignsPerBlock::get()-1; // already created campaigns at current block + + let caller: T::AccountId = whitelisted_caller(); + fund_account::(&caller, None)?; + let org_id = T::Control::create_org(caller.clone().into())?; + let treasury_id = T::Control::org_treasury_account(&org_id); + fund_account::(&treasury_id, None)?; + for i in 0..b { + create_campaign_call::(caller.clone(), org_id.clone())?; + } + let count_before = CampaignsCount::::get(); + + }: _( + RawOrigin::Signed(caller.clone()), + org_id, + caller.clone(), + vec![0; T::MaxNameLength::get() as usize], + T::MinContribution::get(), + T::MinContribution::get(), + 200_u32.into(), + Default::default(), + Default::default(), + vec![0; T::MaxNameLength::get() as usize], + vec![0; 5], + vec![0; 32] + ) + verify { + assert!(CampaignsCount::::get() == count_before + 1); + } + + update_state { + let caller: T::AccountId = whitelisted_caller(); + fund_account::(&caller, None)?; + let org_id = T::Control::create_org(caller.clone().into())?; + let treasury_id = T::Control::org_treasury_account(&org_id); + fund_account::(&treasury_id, None)?; + let campaign_id = create_campaign_call::(caller.clone(), org_id.clone())?; + let new_state = FlowState::Paused; + }: _( + RawOrigin::Signed(caller.clone()), + campaign_id, + new_state.clone() + ) + verify { + assert!(CampaignState::::get(&campaign_id) == new_state); + } + + contribute { + let amount_to_contribute = T::MinContribution::get(); + let owner: T::AccountId = whitelisted_caller(); + let contributor: T::AccountId = account("contributor", 0, 0); + fund_accounts::(&vec![owner.clone(), contributor.clone()], None)?; + let org_id = T::Control::create_org(owner.clone().into())?; + let treasury_id = T::Control::org_treasury_account(&org_id); + fund_account::(&treasury_id, None)?; + let campaign_id = create_campaign_call::(owner, org_id)?; + }: _( + RawOrigin::Signed(contributor.clone()), + campaign_id.clone(), + amount_to_contribute + ) + verify { + assert!(CampaignContribution::::contains_key((&campaign_id, &contributor))); + } } diff --git a/flow/src/lib.rs b/flow/src/lib.rs index 7c939d107..28ce27893 100644 --- a/flow/src/lib.rs +++ b/flow/src/lib.rs @@ -1,7 +1,7 @@ -// _______ ________ ________ ________ ______ _______ _______ -// ╱╱ ╲╱ ╲╱ ╲╱ ╲_╱ ╲╲╱ ╲╲╱ ╲╲ -// ╱╱ __╱ ╱ ╱ ╱ ╱╱ ╱╱ ╱╱ -// ╱ ╱ ╱ ╱ ╱ _╱ ╱ ╱ ╱ +// _______ ________ ________ ________ ______ _______ _______ +// ╱╱ ╲╱ ╲╱ ╲╱ ╲_╱ ╲╲╱ ╲╲╱ ╲╲ +// ╱╱ __╱ ╱ ╱ ╱ ╱╱ ╱╱ ╱╱ +// ╱ ╱ ╱ ╱ ╱ _╱ ╱ ╱ ╱ // ╲________╱╲___╱____╱╲__╱__╱__╱╲________╱╲________╱╲___╱____╱╲________╱ // // This file is part of GameDAO Protocol. @@ -42,9 +42,9 @@ pub use types::*; mod mock; mod tests; - -// #[cfg(feature = "runtime-benchmarks")] -// mod benchmarking; +#[cfg(feature = "runtime-benchmarks")] +mod benchmarking; +pub mod weights; // TODO: weights // mod default_weights; @@ -53,8 +53,7 @@ mod tests; // mod errors; use frame_support::{ - codec::Encode, - dispatch::DispatchResult, + dispatch::{DispatchResult, DispatchResultWithPostInfo}, traits::{Get, UnixTime, BalanceStatus}, transactional, weights::Weight @@ -67,10 +66,11 @@ use sp_std::vec::Vec; use sp_std::convert::TryFrom; use codec::HasCompact; -use gamedao_traits::{ControlTrait, FlowTrait}; +use gamedao_traits::{ControlTrait, ControlBenchmarkingTrait, FlowTrait}; use orml_traits::{MultiCurrency, MultiReservableCurrency}; pub use pallet::*; +pub use weights::WeightInfo; // TODO: use associated type instead pub type Moment = u64; @@ -112,7 +112,7 @@ pub mod pallet { + TypeInfo; /// Weight information for extrinsics in this module. - type WeightInfo: frame_system::weights::WeightInfo; + type WeightInfo: WeightInfo; /// Multi-currency support for asset management. type Currency: MultiCurrency @@ -120,7 +120,8 @@ pub mod pallet { type UnixTime: UnixTime; - type Control: ControlTrait; + type Control: ControlTrait + + ControlBenchmarkingTrait; /// The GameDAO Treasury AccountId. #[pallet::constant] @@ -486,13 +487,13 @@ pub mod pallet { #[pallet::hooks] impl Hooks for Pallet { - fn on_initialize(block_number: T::BlockNumber) -> Weight { + fn on_initialize(block_number: T::BlockNumber) -> Weight { let mut processed: u32 = 0; Self::process_campaigns(&block_number, FlowState::Finalizing, &mut processed) .saturating_add( Self::process_campaigns(&block_number, FlowState::Reverting, &mut processed) ) - } + } fn on_finalize(block_number: T::BlockNumber) { Self::schedule_campaign_settlements(block_number) @@ -519,7 +520,9 @@ pub mod pallet { /// Emits `CampaignCreated` event when successful. /// /// Weight: `O(1)` - #[pallet::weight(5_000_000)] + #[pallet::weight(T::WeightInfo::create_campaign( + T::MaxCampaignsPerBlock::get() + ))] #[transactional] pub fn create_campaign( origin: OriginFor, @@ -534,9 +537,9 @@ pub mod pallet { cid: Vec, token_symbol: Vec, // up to 5 token_name: Vec, /* cleartext - * token_curve_a: u8, // preset - * token_curve_b: Vec, // custom */ - ) -> DispatchResult { + * token_curve_a: u8, // preset + * token_curve_b: Vec, // custom */ + ) -> DispatchResultWithPostInfo { let creator = ensure_signed(origin)?; let owner = T::Control::org_controller_account(&org_id); ensure!(creator == owner, Error::::AuthorizationError); @@ -572,9 +575,9 @@ pub mod pallet { // for collision // check contribution limit per block - let camapaigns = CampaignsByBlock::::get(expiry); + let campaigns = CampaignsByBlock::::get(expiry); ensure!( - (camapaigns.len() as u32) < T::MaxCampaignsPerBlock::get(), + (campaigns.len() as u32) < T::MaxCampaignsPerBlock::get(), Error::::CampaignsPerBlockExceeded ); @@ -612,7 +615,7 @@ pub mod pallet { expiry, name, }); - Ok(()) + Ok(Some(T::WeightInfo::create_campaign(campaigns.len() as u32)).into()) // No fees are paid here if we need to create this account; // that's why we don't just use the stock `transfer`. @@ -627,8 +630,8 @@ pub mod pallet { /// /// Emits `CampaignUpdated` event when successful. /// - /// Weight: - #[pallet::weight(1_000_000)] + /// Weight: O(1) + #[pallet::weight(T::WeightInfo::update_state())] pub fn update_state(origin: OriginFor, campaign_id: T::Hash, state: FlowState) -> DispatchResult { // access control let sender = ensure_signed(origin)?; @@ -665,8 +668,8 @@ pub mod pallet { /// /// Emits `CampaignContributed` event when successful. /// - /// Weight: - #[pallet::weight(5_000_000)] + /// Weight: O(1) + #[pallet::weight(T::WeightInfo::contribute())] pub fn contribute(origin: OriginFor, campaign_id: T::Hash, contribution: T::Balance) -> DispatchResult { // check @@ -859,7 +862,7 @@ impl Pallet { fn process_campaigns(block_number: &T::BlockNumber, state: FlowState, processed: &mut u32) -> Weight { let campaign_ids = CampaignsByState::::get(&state); - let total_weight: Weight = 0; + let mut total_weight: Weight = 0; for campaign_id in campaign_ids { let campaign = Campaigns::::get(campaign_id); let campaign_balance = CampaignBalance::::get(campaign_id); @@ -869,14 +872,14 @@ impl Pallet { if state == FlowState::Finalizing { if let Some(owner) = CampaignOwner::::get(campaign.id) { - total_weight.saturating_add( + total_weight = total_weight.saturating_add( Self::finalize_campaign(&block_number, processed, &campaign, &campaign_balance, &org, &org_treasury, &contributors, &owner) ); } else { // TODO: If no campaign owner: revert the campaign or leave it as is? } } else if state == FlowState::Reverting { - total_weight.saturating_add( + total_weight = total_weight.saturating_add( Self::revert_campaign(&block_number, processed, &campaign, &campaign_balance, &org, &org_treasury, &contributors) ); } diff --git a/flow/src/weights.rs b/flow/src/weights.rs new file mode 100644 index 000000000..391018cb3 --- /dev/null +++ b/flow/src/weights.rs @@ -0,0 +1,161 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Autogenerated weights for gamedao_flow +//! +//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 4.0.0-dev +//! DATE: 2022-06-16, STEPS: `20`, REPEAT: 10, LOW RANGE: `[]`, HIGH RANGE: `[]` +//! EXECUTION: None, WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 128 + +// Executed Command: +// ./target/release/subzero +// benchmark +// --pallet=gamedao_flow +// --extrinsic=* +// --steps=20 +// --repeat=10 +// --output=gamedao-protocol/flow/src/weights.rs +// --template=./.maintain/frame-weight-template.hbs + +#![cfg_attr(rustfmt, rustfmt_skip)] +#![allow(unused_parens)] +#![allow(unused_imports)] + +use frame_support::{traits::Get, weights::{Weight, constants::RocksDbWeight}}; +use sp_std::marker::PhantomData; + +/// Weight functions needed for gamedao_flow. +pub trait WeightInfo { + fn create_campaign(b: u32, ) -> Weight; + fn update_state() -> Weight; + fn contribute() -> Weight; +} + +/// Weights for gamedao_flow using the Substrate node and recommended hardware. +pub struct SubstrateWeight(PhantomData); +impl WeightInfo for SubstrateWeight { + // Storage: Control OrgController (r:1 w:0) + // Storage: Control OrgTreasury (r:1 w:0) + // Storage: Tokens Accounts (r:1 w:1) + // Storage: Flow Nonce (r:1 w:1) + // Storage: Flow CampaignsByBlock (r:1 w:1) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Flow CampaignsByOrg (r:1 w:1) + // Storage: Flow CampaignsCount (r:1 w:1) + // Storage: Flow CampaignsOwnedCount (r:1 w:1) + // Storage: Flow CampaignState (r:1 w:1) + // Storage: Flow CampaignsByState (r:2 w:1) + // Storage: Flow CampaignAdmin (r:0 w:1) + // Storage: Flow CampaignsOwnedIndex (r:0 w:1) + // Storage: Flow CampaignOwner (r:0 w:1) + // Storage: Flow CampaignsOwnedArray (r:0 w:1) + // Storage: Flow CampaignsArray (r:0 w:1) + // Storage: Flow Campaigns (r:0 w:1) + // Storage: Flow CampaignOrg (r:0 w:1) + // Storage: Flow CampaignsIndex (r:0 w:1) + fn create_campaign(b: u32, ) -> Weight { + (94_360_000 as Weight) + // Standard Error: 1_243_000 + .saturating_add((413_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(T::DbWeight::get().reads(12 as Weight)) + .saturating_add(T::DbWeight::get().writes(16 as Weight)) + } + // Storage: Flow CampaignOwner (r:1 w:0) + // Storage: Flow CampaignAdmin (r:1 w:0) + // Storage: Flow Campaigns (r:1 w:0) + // Storage: Flow CampaignState (r:1 w:1) + // Storage: Flow CampaignsByState (r:2 w:2) + fn update_state() -> Weight { + (36_791_000 as Weight) + .saturating_add(T::DbWeight::get().reads(6 as Weight)) + .saturating_add(T::DbWeight::get().writes(3 as Weight)) + } + // Storage: Tokens Accounts (r:1 w:1) + // Storage: Flow CampaignOwner (r:1 w:0) + // Storage: Flow Campaigns (r:1 w:0) + // Storage: Flow CampaignState (r:1 w:0) + // Storage: Flow CampaignContribution (r:1 w:1) + // Storage: Flow CampaignsContributedCount (r:1 w:1) + // Storage: Flow CampaignContributorsCount (r:1 w:1) + // Storage: Flow CampaignContributors (r:1 w:1) + // Storage: Flow CampaignsContributed (r:1 w:1) + // Storage: Flow CampaignBalance (r:1 w:1) + // Storage: Flow CampaignsContributedIndex (r:0 w:1) + // Storage: Flow CampaignsContributedArray (r:0 w:1) + fn contribute() -> Weight { + (57_117_000 as Weight) + .saturating_add(T::DbWeight::get().reads(10 as Weight)) + .saturating_add(T::DbWeight::get().writes(9 as Weight)) + } +} + +// For backwards compatibility and tests +impl WeightInfo for () { + // Storage: Control OrgController (r:1 w:0) + // Storage: Control OrgTreasury (r:1 w:0) + // Storage: Tokens Accounts (r:1 w:1) + // Storage: Flow Nonce (r:1 w:1) + // Storage: Flow CampaignsByBlock (r:1 w:1) + // Storage: Timestamp Now (r:1 w:0) + // Storage: Flow CampaignsByOrg (r:1 w:1) + // Storage: Flow CampaignsCount (r:1 w:1) + // Storage: Flow CampaignsOwnedCount (r:1 w:1) + // Storage: Flow CampaignState (r:1 w:1) + // Storage: Flow CampaignsByState (r:2 w:1) + // Storage: Flow CampaignAdmin (r:0 w:1) + // Storage: Flow CampaignsOwnedIndex (r:0 w:1) + // Storage: Flow CampaignOwner (r:0 w:1) + // Storage: Flow CampaignsOwnedArray (r:0 w:1) + // Storage: Flow CampaignsArray (r:0 w:1) + // Storage: Flow Campaigns (r:0 w:1) + // Storage: Flow CampaignOrg (r:0 w:1) + // Storage: Flow CampaignsIndex (r:0 w:1) + fn create_campaign(b: u32, ) -> Weight { + (94_360_000 as Weight) + // Standard Error: 1_243_000 + .saturating_add((413_000 as Weight).saturating_mul(b as Weight)) + .saturating_add(RocksDbWeight::get().reads(12 as Weight)) + .saturating_add(RocksDbWeight::get().writes(16 as Weight)) + } + // Storage: Flow CampaignOwner (r:1 w:0) + // Storage: Flow CampaignAdmin (r:1 w:0) + // Storage: Flow Campaigns (r:1 w:0) + // Storage: Flow CampaignState (r:1 w:1) + // Storage: Flow CampaignsByState (r:2 w:2) + fn update_state() -> Weight { + (36_791_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(6 as Weight)) + .saturating_add(RocksDbWeight::get().writes(3 as Weight)) + } + // Storage: Tokens Accounts (r:1 w:1) + // Storage: Flow CampaignOwner (r:1 w:0) + // Storage: Flow Campaigns (r:1 w:0) + // Storage: Flow CampaignState (r:1 w:0) + // Storage: Flow CampaignContribution (r:1 w:1) + // Storage: Flow CampaignsContributedCount (r:1 w:1) + // Storage: Flow CampaignContributorsCount (r:1 w:1) + // Storage: Flow CampaignContributors (r:1 w:1) + // Storage: Flow CampaignsContributed (r:1 w:1) + // Storage: Flow CampaignBalance (r:1 w:1) + // Storage: Flow CampaignsContributedIndex (r:0 w:1) + // Storage: Flow CampaignsContributedArray (r:0 w:1) + fn contribute() -> Weight { + (57_117_000 as Weight) + .saturating_add(RocksDbWeight::get().reads(10 as Weight)) + .saturating_add(RocksDbWeight::get().writes(9 as Weight)) + } +}