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

Feat add benchmarks payments #325

Merged
merged 5 commits into from
Nov 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion pallets/payments/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,10 @@ pallet-scheduler= { workspace = true }

[features]
default = ["std"]
runtime-benchmarks = ["frame-benchmarking/runtime-benchmarks"]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"pallet-assets/runtime-benchmarks"
]
std = [
"parity-scale-codec/std",
"scale-info/std",
Expand Down
271 changes: 271 additions & 0 deletions pallets/payments/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,271 @@
use super::*;
#[allow(unused)]
use crate::{types::*, Pallet as Payments};
use frame_benchmarking::{account, v2::*};
use frame_support::{
traits::{
fungibles::{Inspect, Mutate},
Get,
},
BoundedVec,
};

use frame_system::RawOrigin;
use sp_runtime::Percent;

// Compare `generic_event` to the last emitted event.
fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
frame_system::Pallet::<T>::assert_last_event(generic_event.into());
}

fn create_accounts<T: Config>() -> (T::AccountId, T::AccountId, AccountIdLookupOf<T>, AccountIdLookupOf<T>) {
let sender: T::AccountId = account("Alice", 0, 10);
let beneficiary: T::AccountId = account("Bob", 0, 11);
let sender_lookup = T::Lookup::unlookup(sender.clone());
let beneficiary_lookup = T::Lookup::unlookup(beneficiary.clone());

(sender, beneficiary, sender_lookup, beneficiary_lookup)
}

fn create_and_mint_asset<T: Config>(
sender: &T::AccountId,
beneficiary: &T::AccountId,
asset: &AssetIdOf<T>,
amount: &BalanceOf<T>,
) -> Result<(), BenchmarkError> {
T::BenchmarkHelper::create_asset(asset.clone(), sender.clone(), true, <BalanceOf<T>>::from(1u32));
T::Assets::mint_into(asset.clone(), &sender, <BalanceOf<T>>::from(100000u32))?;
T::Assets::mint_into(asset.clone(), &beneficiary, <BalanceOf<T>>::from(100000u32))?;

Ok(())
}

fn create_payment<T: Config>(
amount: &BalanceOf<T>,
asset: &AssetIdOf<T>,
remark: Option<BoundedDataOf<T>>,
) -> Result<
(
T::PaymentId,
T::AccountId,
T::AccountId,
AccountIdLookupOf<T>,
AccountIdLookupOf<T>,
),
BenchmarkError,
> {
let (sender, beneficiary, sender_lookup, beneficiary_lookup) = create_accounts::<T>();
create_and_mint_asset::<T>(&sender, &beneficiary, &asset, &<BalanceOf<T>>::from(100000u32))?;

let payment_id: T::PaymentId = Payments::<T>::next_payment_id()?;

let payment_detail = Payments::<T>::create_payment(
&sender,
&beneficiary,
asset.clone(),
amount.clone(),
PaymentState::Created,
T::IncentivePercentage::get(),
remark.as_ref().map(|x| x.as_slice()),
)?;

// reserve funds for payment
Payments::<T>::reserve_payment_amount(&sender, &beneficiary, payment_detail)?;

// TODO: check storage items

Ok((payment_id, sender, beneficiary, sender_lookup, beneficiary_lookup))
}

#[benchmarks(
where
<<T as Config>::Assets as Inspect<<T as frame_system::Config>::AccountId>>::AssetId: Zero,
)]
mod benchmarks {
use super::*;

#[benchmark]
fn pay(q: Linear<1, { T::MaxRemarkLength::get() }>) -> Result<(), BenchmarkError> {
let (sender, beneficiary, _, beneficiary_lookup) = create_accounts::<T>();
let asset: AssetIdOf<T> = <AssetIdOf<T>>::zero();
create_and_mint_asset::<T>(&sender, &beneficiary, &asset, &<BalanceOf<T>>::from(100000u32))?;
let amount = <BalanceOf<T>>::from(50_u32);

let remark: Option<BoundedDataOf<T>> = if q == 0 {
None
} else {
Some(BoundedVec::try_from(vec![1 as u8; q as usize]).unwrap())
};

#[extrinsic_call]
_(
RawOrigin::Signed(sender.clone()),
beneficiary_lookup,
asset.clone(),
amount,
remark.clone(),
);

assert_last_event::<T>(
Event::PaymentCreated {
sender,
beneficiary,
asset,
amount,
remark,
}
.into(),
);
Ok(())
}

#[benchmark]
fn release() -> Result<(), BenchmarkError> {
let amount = <BalanceOf<T>>::from(50_u32);
let asset = <AssetIdOf<T>>::zero();
let (payment_id, sender, beneficiary, _, beneficiary_lookup) = create_payment::<T>(&amount, &asset, None)?;

#[extrinsic_call]
_(RawOrigin::Signed(sender.clone()), beneficiary_lookup, payment_id);

assert_last_event::<T>(Event::PaymentReleased { sender, beneficiary }.into());
Ok(())
}

#[benchmark]
fn cancel() -> Result<(), BenchmarkError> {
let amount = <BalanceOf<T>>::from(50_u32);
let asset = <AssetIdOf<T>>::zero();
let (payment_id, sender, beneficiary, sender_lookup, _beneficiary_lookup) =
create_payment::<T>(&amount, &asset, None)?;

#[extrinsic_call]
_(RawOrigin::Signed(beneficiary.clone()), sender_lookup, payment_id);

assert_last_event::<T>(Event::PaymentCancelled { sender, beneficiary }.into());
Ok(())
}

#[benchmark]
fn request_refund() -> Result<(), BenchmarkError> {
let amount = <BalanceOf<T>>::from(50_u32);
let asset = <AssetIdOf<T>>::zero();
let (payment_id, sender, beneficiary, _sender_lookup, beneficiary_lookup) =
create_payment::<T>(&amount, &asset, None)?;

#[extrinsic_call]
_(RawOrigin::Signed(sender.clone()), beneficiary_lookup, payment_id);

let current_block = frame_system::Pallet::<T>::block_number();
let expiry = current_block + T::CancelBufferBlockLength::get();

assert_last_event::<T>(
Event::PaymentCreatorRequestedRefund {
sender,
beneficiary,
expiry,
}
.into(),
);
Ok(())
}

#[benchmark]
fn dispute_refund() -> Result<(), BenchmarkError> {
let amount = <BalanceOf<T>>::from(50_u32);
let asset = <AssetIdOf<T>>::zero();
let (payment_id, sender, beneficiary, sender_lookup, beneficiary_lookup) =
create_payment::<T>(&amount, &asset, None)?;

assert!(Payments::<T>::request_refund(
RawOrigin::Signed(sender.clone()).into(),
beneficiary_lookup,
payment_id
)
.is_ok());

#[extrinsic_call]
_(RawOrigin::Signed(beneficiary.clone()), sender_lookup, payment_id);

assert_last_event::<T>(Event::PaymentRefundDisputed { sender, beneficiary }.into());
Ok(())
}

#[benchmark]
fn resolve_dispute() -> Result<(), BenchmarkError> {
let amount = <BalanceOf<T>>::from(50_u32);
let asset = <AssetIdOf<T>>::zero();
let (payment_id, sender, beneficiary, sender_lookup, beneficiary_lookup) =
create_payment::<T>(&amount, &asset, None)?;

assert!(Payments::<T>::request_refund(
RawOrigin::Signed(sender.clone()).into(),
beneficiary_lookup.clone(),
payment_id
)
.is_ok());

assert!(Payments::<T>::dispute_refund(
RawOrigin::Signed(beneficiary.clone()).into(),
sender_lookup.clone(),
payment_id
)
.is_ok());

let dispute_result = DisputeResult {
percent_beneficiary: Percent::from_percent(90),
in_favor_of: Role::Sender,
};

#[extrinsic_call]
_(
RawOrigin::Root,
sender_lookup,
beneficiary_lookup,
payment_id,
dispute_result,
);

assert_last_event::<T>(Event::PaymentDisputeResolved { sender, beneficiary }.into());
Ok(())
}

#[benchmark]
fn request_payment() -> Result<(), BenchmarkError> {
let (sender, beneficiary, sender_lookup, _beneficiary_lookup) = create_accounts::<T>();
let asset: AssetIdOf<T> = <AssetIdOf<T>>::zero();
create_and_mint_asset::<T>(&sender, &beneficiary, &asset, &<BalanceOf<T>>::from(100000u32))?;
let amount = <BalanceOf<T>>::from(50_u32);

#[extrinsic_call]
_(RawOrigin::Signed(beneficiary.clone()), sender_lookup, asset, amount);

assert_last_event::<T>(Event::PaymentRequestCreated { sender, beneficiary }.into());
Ok(())
}

#[benchmark]
fn accept_and_pay() -> Result<(), BenchmarkError> {
let (sender, beneficiary, sender_lookup, beneficiary_lookup) = create_accounts::<T>();
let asset: AssetIdOf<T> = <AssetIdOf<T>>::zero();
create_and_mint_asset::<T>(&sender, &beneficiary, &asset, &<BalanceOf<T>>::from(100000u32))?;
let amount = <BalanceOf<T>>::from(50_u32);
let payment_id: T::PaymentId = Payments::<T>::next_payment_id()?;

assert!(Payments::<T>::request_payment(
RawOrigin::Signed(beneficiary.clone()).into(),
sender_lookup,
asset,
amount
)
.is_ok());

#[extrinsic_call]
_(RawOrigin::Signed(sender.clone()), beneficiary_lookup, payment_id);

assert_last_event::<T>(Event::PaymentRequestCreated { sender, beneficiary }.into());
Ok(())
}

impl_benchmark_test_suite!(Payments, crate::mock::new_test_ext(), crate::mock::Test);
}
19 changes: 18 additions & 1 deletion pallets/payments/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ use frame_system::pallet_prelude::BlockNumberFor;
/// <https://docs.substrate.io/v3/runtime/frame>
pub use pallet::*;

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

#[cfg(test)]
mod mock;

Expand Down Expand Up @@ -52,6 +55,12 @@ pub mod pallet {
use frame_system::pallet_prelude::*;

use sp_runtime::{traits::Get, Percent};

#[cfg(feature = "runtime-benchmarks")]
pub trait BenchmarkHelper<AccountId, AssetId, Balance> {
fn create_asset(id: AssetId, admin: AccountId, is_sufficient: bool, min_balance: Balance);
}

#[pallet::config]
pub trait Config: frame_system::Config {
type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
Expand Down Expand Up @@ -127,6 +136,9 @@ pub mod pallet {
/// canceled payment
#[pallet::constant]
type CancelBufferBlockLength: Get<BlockNumberFor<Self>>;

#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper: BenchmarkHelper<AccountIdOf<Self>, AssetIdOf<Self>, BalanceOf<Self>>;
}

#[pallet::pallet]
Expand Down Expand Up @@ -208,6 +220,11 @@ pub mod pallet {
sender: T::AccountId,
beneficiary: T::AccountId,
},
/// Payment disputed resolved
PaymentDisputeResolved {
sender: T::AccountId,
beneficiary: T::AccountId,
},
}

#[pallet::error]
Expand Down Expand Up @@ -473,7 +490,7 @@ pub mod pallet {
let dispute = Some((dispute_result, dispute_resolver));
Self::settle_payment(&sender, &beneficiary, &payment_id, dispute)?;

Self::deposit_event(Event::PaymentRefundDisputed { sender, beneficiary });
Self::deposit_event(Event::PaymentDisputeResolved { sender, beneficiary });
Ok(().into())
}

Expand Down
21 changes: 20 additions & 1 deletion pallets/payments/src/mock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ use sp_runtime::{

type Block = frame_system::mocking::MockBlock<Test>;
type AccountId = u64;
#[allow(unused)]
type AssetId = u32;

pub const SENDER_ACCOUNT: AccountId = 10;
pub const PAYMENT_BENEFICIARY: AccountId = 11;
Expand Down Expand Up @@ -213,8 +215,23 @@ impl crate::types::FeeHandler<Test> for MockFeeHandler {
}
}

#[cfg(feature = "runtime-benchmarks")]
pub struct BenchmarkHelper;
#[cfg(feature = "runtime-benchmarks")]
impl super::BenchmarkHelper<AccountId, AssetId, Balance> for BenchmarkHelper {
fn create_asset(id: AssetId, admin: AccountId, is_sufficient: bool, min_balance: Balance) {
<Assets as frame_support::traits::tokens::fungibles::Create<AccountId>>::create(
id,
admin,
is_sufficient,
min_balance,
)
.unwrap();
}
}

parameter_types! {
pub const MaxRemarkLength: u32 = 50;
pub const MaxRemarkLength: u8 = 50;
pub const IncentivePercentage: Percent = Percent::from_percent(INCENTIVE_PERCENTAGE);
pub const PaymentPalletId: PalletId = PalletId(*b"payments");
}
Expand All @@ -237,6 +254,8 @@ impl pallet_payments::Config for Test {
type Preimages = ();
type CancelBufferBlockLength = ConstU64<10>;
type PalletsOrigin = OriginCaller;
#[cfg(feature = "runtime-benchmarks")]
type BenchmarkHelper = BenchmarkHelper;
}

// Build genesis storage according to the mock runtime.
Expand Down
1 change: 1 addition & 0 deletions runtime/kreivo/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ runtime-benchmarks = [
"pallet-burner/runtime-benchmarks",
"pallet-multisig/runtime-benchmarks",
"pallet-utility/runtime-benchmarks",
"pallet-payments/runtime-benchmarks",
"pallet-proxy/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
"xcm-builder/runtime-benchmarks",
Expand Down
Loading