Skip to content

Commit

Permalink
Feat add benchmarks payments (#325)
Browse files Browse the repository at this point in the history
* WIP

* WIP

* adding release

* Benchmarks completed

* Removing unused code
  • Loading branch information
darkforest0202 authored Nov 24, 2023
1 parent 7b8f771 commit 3b2c09a
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 3 deletions.
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

0 comments on commit 3b2c09a

Please sign in to comment.