Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Investments: benchmarks #1563

Merged
merged 12 commits into from
Sep 25, 2023
2 changes: 1 addition & 1 deletion libs/mocks/src/pools.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ pub mod pallet {
register_call!(f);
}

pub fn tranche_exists(f: impl Fn(T::PoolId, T::TrancheId) -> bool + 'static) {
pub fn mock_tranche_exists(f: impl Fn(T::PoolId, T::TrancheId) -> bool + 'static) {
register_call!(move |(a, b)| f(a, b));
}

Expand Down
21 changes: 21 additions & 0 deletions libs/test-utils/src/mocks/accountant.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,27 @@ macro_rules! impl_mock_accountant {
}
}

#[cfg(feature = "runtime-benchmarks")]
impl<Tokens> cfg_traits::benchmarking::PoolBenchmarkHelper for $name<Tokens> {
type AccountId = $account_id;
type Balance = $balance;
type PoolId = ();

fn bench_create_pool(_: Self::PoolId, _: &Self::AccountId) {}

fn bench_investor_setup(_: Self::PoolId, _: Self::AccountId, _: Self::Balance) {}
}
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(feature = "runtime-benchmarks")]
impl<Tokens> cfg_traits::benchmarking::InvestmentIdBenchmarkHelper for $name<Tokens> {
type InvestmentId = $investment_id;
type PoolId = ();

fn bench_default_investment_id(_: Self::PoolId) -> Self::InvestmentId {
Self::InvestmentId::default()
}
}

impl cfg_traits::investments::InvestmentProperties<$account_id> for InvestmentInfo {
type Currency = $currency_id;
type Id = $investment_id;
Expand Down
13 changes: 12 additions & 1 deletion libs/types/src/tokens.rs
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,18 @@ where
/// enables us to use the `TrancheCurrency` type separately where solely this
/// enum variant would be relevant. Most notably, in the `struct Tranche`.
#[derive(
Clone, Copy, PartialOrd, Ord, PartialEq, Eq, Debug, Encode, Decode, TypeInfo, MaxEncodedLen,
Clone,
Copy,
Default,
mustermeiszer marked this conversation as resolved.
Show resolved Hide resolved
PartialOrd,
Ord,
PartialEq,
Eq,
Debug,
Encode,
Decode,
TypeInfo,
MaxEncodedLen,
)]
#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
pub struct TrancheCurrency {
Expand Down
132 changes: 131 additions & 1 deletion pallets/investments/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2021 Centrifuge Foundation (centrifuge.io).
// Copyright 2023 Centrifuge Foundation (centrifuge.io).
// This file is part of Centrifuge chain project.

// Centrifuge is free software: you can redistribute it and/or modify
Expand All @@ -10,3 +10,133 @@
// 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.

use cfg_traits::{
benchmarking::{InvestmentIdBenchmarkHelper, PoolBenchmarkHelper},
investments::{Investment, InvestmentAccountant, InvestmentProperties, OrderManager},
};
use cfg_types::orders::FulfillmentWithPrice;
use frame_benchmarking::{account, impl_benchmark_test_suite, v2::*, whitelisted_caller};
use frame_support::traits::fungibles::Mutate;
use frame_system::RawOrigin;
use sp_runtime::{traits::One, Perquintill};

use crate::{Call, Config, CurrencyOf, Pallet};

struct Helper<T>(sp_std::marker::PhantomData<T>);
impl<T: Config> Helper<T>
where
<T::Accountant as InvestmentAccountant<T::AccountId>>::InvestmentInfo:
InvestmentProperties<T::AccountId, Currency = CurrencyOf<T>>,
T::InvestmentId: Default + Into<CurrencyOf<T>>,
T::Accountant: PoolBenchmarkHelper<AccountId = T::AccountId>
+ InvestmentIdBenchmarkHelper<
InvestmentId = T::InvestmentId,
PoolId = <T::Accountant as PoolBenchmarkHelper>::PoolId,
>,
<T::Accountant as PoolBenchmarkHelper>::PoolId: Default + Copy,
{
fn get_investment_id() -> T::InvestmentId {
let pool_id = Default::default();
let pool_admin = account("pool_admin", 0, 0);

T::Accountant::bench_create_pool(pool_id, &pool_admin);
T::Accountant::bench_default_investment_id(pool_id)
}
}

#[benchmarks(
where
<T::Accountant as InvestmentAccountant<T::AccountId>>::InvestmentInfo:
InvestmentProperties<T::AccountId, Currency = CurrencyOf<T>>,
T::InvestmentId: Default + Into<CurrencyOf<T>>,
T::Accountant: PoolBenchmarkHelper<AccountId = T::AccountId>
+ InvestmentIdBenchmarkHelper<
InvestmentId = T::InvestmentId,
PoolId = <T::Accountant as PoolBenchmarkHelper>::PoolId,
>,
<T::Accountant as PoolBenchmarkHelper>::PoolId: Default + Copy,
)]
mod benchmarks {
use super::*;

#[benchmark]
lemunozm marked this conversation as resolved.
Show resolved Hide resolved
fn update_invest_order() {
let caller: T::AccountId = whitelisted_caller();
let investment_id = Helper::<T>::get_investment_id();
let currency_id = T::Accountant::info(investment_id)?.payment_currency();

T::Tokens::mint_into(currency_id, &caller, 1u32.into())?;

#[extrinsic_call]
update_invest_order(RawOrigin::Signed(caller), investment_id, 1u32.into());
}

#[benchmark]
fn update_redeem_order() {
let caller: T::AccountId = whitelisted_caller();
let investment_id = Helper::<T>::get_investment_id();
let currency_id: CurrencyOf<T> = T::Accountant::info(investment_id)?.id().into();

T::Tokens::mint_into(currency_id, &caller, 1u32.into())?;

#[extrinsic_call]
update_redeem_order(RawOrigin::Signed(caller), investment_id, 1u32.into());
}

#[benchmark]
fn collect_investments(n: Linear<1, 10>) {
let caller: T::AccountId = whitelisted_caller();
let investment_id = Helper::<T>::get_investment_id();
let currency_id = T::Accountant::info(investment_id)
.unwrap()
.payment_currency();

T::Tokens::mint_into(currency_id, &caller, 1u32.into())?;

Pallet::<T>::update_investment(&caller, investment_id, 1u32.into())?;
for i in 0..n {
Pallet::<T>::process_invest_orders(investment_id)?;

let fulfillment = FulfillmentWithPrice {
of_amount: Perquintill::one(),
price: One::one(),
};

Pallet::<T>::invest_fulfillment(investment_id, fulfillment)?;
}

#[extrinsic_call]
collect_investments(RawOrigin::Signed(caller), investment_id);
}

#[benchmark]
fn collect_redemptions(n: Linear<1, 10>) {
Copy link
Contributor Author

@lemunozm lemunozm Sep 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
fn collect_redemptions(n: Linear<1, 10>) {
fn collect_redemptions(n: Linear<1, { T::MaxOutstandingCollects::get() }>) {

Tech debt once we upgrade to Polkadot v0.9.39

let caller: T::AccountId = whitelisted_caller();
let investment_id = Helper::<T>::get_investment_id();
let currency_id: CurrencyOf<T> = T::Accountant::info(investment_id)?.id().into();

T::Tokens::mint_into(currency_id, &caller, 1u32.into())?;

Pallet::<T>::update_redemption(&caller, investment_id, 1u32.into())?;
for i in 0..n {
Pallet::<T>::process_redeem_orders(investment_id)?;

let fulfillment = FulfillmentWithPrice {
of_amount: Perquintill::one(),
price: One::one(),
};

Pallet::<T>::redeem_fulfillment(investment_id, fulfillment)?;
}

#[extrinsic_call]
collect_redemptions(RawOrigin::Signed(caller), investment_id);
}

impl_benchmark_test_suite!(
Pallet,
crate::mock::TestExternalitiesBuilder::build(),
crate::mock::MockRuntime
);
}
20 changes: 11 additions & 9 deletions pallets/investments/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ use sp_std::{
vec::Vec,
};
pub mod weights;
pub use weights::WeightInfo;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;
Expand Down Expand Up @@ -162,7 +163,8 @@ pub mod pallet {

/// The bound on how many fulfilled orders we cache until
/// the user needs to collect them.
type MaxOutstandingCollects: Get<u64>;
#[pallet::constant]
type MaxOutstandingCollects: Get<u32>;

/// Something that can handle payments and transfers of
/// currencies
Expand Down Expand Up @@ -423,7 +425,7 @@ pub mod pallet {
/// amount is less than the current order, the balance
/// will be transferred from the pool to the calling
/// account.
#[pallet::weight(5_000_000_000)]
#[pallet::weight(T::WeightInfo::update_invest_order())]
#[pallet::call_index(0)]
pub fn update_invest_order(
origin: OriginFor<T>,
Expand All @@ -443,7 +445,7 @@ pub mod pallet {
/// amount is less than the current order, the balance
/// will be transferred from the pool to the calling
/// account.
#[pallet::weight(5_000_000_000)]
#[pallet::weight(T::WeightInfo::update_redeem_order())]
#[pallet::call_index(1)]
pub fn update_redeem_order(
origin: OriginFor<T>,
Expand All @@ -458,7 +460,7 @@ pub mod pallet {
/// Collect the results of a user's invest orders for the given
/// investment. If any amounts are not fulfilled they are directly
/// appended to the next active order for this investment.
#[pallet::weight(5_000_000_000)]
#[pallet::weight(T::WeightInfo::collect_investments(T::MaxOutstandingCollects::get()))]
#[pallet::call_index(2)]
pub fn collect_investments(
origin: OriginFor<T>,
Expand All @@ -472,7 +474,7 @@ pub mod pallet {
/// Collect the results of a user's redeem orders for the given
/// investment. If any amounts are not fulfilled they are directly
/// appended to the next active order for this investment.
#[pallet::weight(5_000_000_000)]
#[pallet::weight(T::WeightInfo::collect_redemptions(T::MaxOutstandingCollects::get()))]
#[pallet::call_index(3)]
pub fn collect_redemptions(
origin: OriginFor<T>,
Expand All @@ -486,7 +488,7 @@ pub mod pallet {
/// Collect the results of another users invest orders for the given
/// investment. If any amounts are not fulfilled they are directly
/// appended to the next active order for this investment.
#[pallet::weight(5_000_000_000)]
#[pallet::weight(T::WeightInfo::collect_investments(T::MaxOutstandingCollects::get()))]
#[pallet::call_index(4)]
pub fn collect_investments_for(
origin: OriginFor<T>,
Expand All @@ -501,7 +503,7 @@ pub mod pallet {
/// Collect the results of another users redeem orders for the given
/// investment. If any amounts are not fulfilled they are directly
/// appended to the next active order for this investment.
#[pallet::weight(5_000_000_000)]
#[pallet::weight(T::WeightInfo::collect_redemptions(T::MaxOutstandingCollects::get()))]
#[pallet::call_index(5)]
pub fn collect_redemptions_for(
origin: OriginFor<T>,
Expand Down Expand Up @@ -687,7 +689,7 @@ where
let last_processed_order_id = min(
order
.submitted_at()
.saturating_add(T::MaxOutstandingCollects::get()),
.saturating_add(T::MaxOutstandingCollects::get().into()),
cur_order_id,
);

Expand Down Expand Up @@ -814,7 +816,7 @@ where
let last_processed_order_id = min(
order
.submitted_at()
.saturating_add(T::MaxOutstandingCollects::get()),
.saturating_add(T::MaxOutstandingCollects::get().into()),
cur_order_id,
);

Expand Down
13 changes: 11 additions & 2 deletions pallets/investments/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,7 +152,7 @@ impl cfg_traits::StatusNotificationHook for NoopCollectHook {
}

parameter_types! {
pub const MaxOutstandingCollect: u64 = 10;
pub const MaxOutstandingCollect: u32 = 10;
}

impl pallet_investments::Config for MockRuntime {
Expand Down Expand Up @@ -203,6 +203,15 @@ pub enum InvestmentId {
},
}

impl Default for InvestmentId {
fn default() -> Self {
Self::PoolTranche {
pool_id: Default::default(),
tranche_id: Default::default(),
}
}
}

impl From<InvestmentId> for CurrencyId {
fn from(val: InvestmentId) -> Self {
match val {
Expand Down Expand Up @@ -366,7 +375,7 @@ pub(crate) fn invest_x_per_investor(amount: Balance) -> DispatchResult {
}

/// Redeem amount into INVESTMENT_0_0
///
///
/// User accounts are the default TrancheHolder{A,B,C}
pub(crate) fn redeem_x_per_investor(amount: Balance) -> DispatchResult {
Investments::update_redeem_order(
Expand Down
4 changes: 2 additions & 2 deletions pallets/investments/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2859,7 +2859,7 @@ fn collecting_over_max_works() {
InvestOrders::<MockRuntime>::get(InvestorA::get(), INVESTMENT_0_0),
Some(Order::new(
5368709120000000000,
MaxOutstandingCollect::get()
MaxOutstandingCollect::get().into()
)),
);
assert_ok!(collect_both(
Expand Down Expand Up @@ -2914,7 +2914,7 @@ fn collecting_over_max_works() {
RedeemOrders::<MockRuntime>::get(TrancheHolderA::get(), INVESTMENT_0_0),
Some(Order::new(
5368709120000000000,
MaxOutstandingCollect::get()
MaxOutstandingCollect::get().into()
)),
);
assert_ok!(collect_both(
Expand Down
27 changes: 25 additions & 2 deletions pallets/investments/src/weights.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,29 @@
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

pub trait WeightInfo {}
use frame_support::weights::Weight;

impl WeightInfo for () {}
pub trait WeightInfo {
fn update_invest_order() -> Weight;
fn update_redeem_order() -> Weight;
fn collect_investments(n: u32) -> Weight;
fn collect_redemptions(n: u32) -> Weight;
}

impl WeightInfo for () {
fn update_invest_order() -> Weight {
Weight::zero()
}

fn update_redeem_order() -> Weight {
Weight::zero()
}

fn collect_investments(_: u32) -> Weight {
Weight::zero()
}

fn collect_redemptions(_: u32) -> Weight {
Weight::zero()
}
}
Loading