Skip to content

Commit

Permalink
feat: add xcm benchmarks (#1129)
Browse files Browse the repository at this point in the history
* feat: add generic xcm benchmarks wrapper

* feat: add fungible xcm benchmarks wrapper

* feat: add xcm benchmarks to shibuya

* feat: add missing benchmark

* feat: use `WeightInfoBounds` in shibuya

* fix: use max assets properly

* feat: update weights from benchmarks

* feat: merge mocks

* feat: refactor code

* fix: make clippy happy

* fix: buy execution benchmarks

* chore: remove file

* fix: benchmakrs

* feat: update weights from benchmarks

* feat: apply suggestions
  • Loading branch information
ashutoshvarma authored Jan 15, 2024
1 parent 5c6d6f0 commit ffe8628
Show file tree
Hide file tree
Showing 19 changed files with 2,104 additions and 13 deletions.
27 changes: 27 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,7 @@ polkadot-runtime-parachains = { git = "https://github.com/paritytech/polkadot",
cumulus-pallet-xcm = { git = "https://github.com/paritytech/cumulus", branch = "polkadot-v0.9.43", default-features = false }
xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false }
pallet-xcm = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false }
pallet-xcm-benchmarks = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false }
xcm-builder = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false }
xcm-executor = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false }
xcm-simulator = { git = "https://github.com/paritytech/polkadot", branch = "release-v0.9.43", default-features = false }
Expand Down Expand Up @@ -282,6 +283,7 @@ pallet-ethereum-checked = { path = "./pallets/ethereum-checked", default-feature
pallet-inflation = { path = "./pallets/inflation", default-features = false }
pallet-dynamic-evm-base-fee = { path = "./pallets/dynamic-evm-base-fee", default-features = false }
pallet-unified-accounts = { path = "./pallets/unified-accounts", default-features = false }
astar-xcm-benchmarks = { path = "./pallets/astar-xcm-benchmarks", default-features = false }
pallet-static-price-provider = { path = "./pallets/static-price-provider", default-features = false }

dapp-staking-v3-runtime-api = { path = "./pallets/dapp-staking-v3/rpc/runtime-api", default-features = false }
Expand Down
65 changes: 65 additions & 0 deletions pallets/astar-xcm-benchmarks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
[package]
name = "astar-xcm-benchmarks"
version = "0.1.0"
description = "Pallet for providing benchmarks for xcm instructions"
authors.workspace = true
edition.workspace = true
homepage.workspace = true
repository.workspace = true

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
log = { workspace = true }
serde = { workspace = true, optional = true }

# Substrate
frame-support = { workspace = true }
frame-system = { workspace = true }
parity-scale-codec = { workspace = true, optional = true, features = ["derive"] }
scale-info = { workspace = true }
sp-std = { workspace = true }

# Polkadot / XCM
pallet-xcm-benchmarks = { workspace = true }
xcm = { workspace = true }
xcm-executor = { workspace = true }

# Benchmarks
frame-benchmarking = { workspace = true, optional = true }

# Astar
astar-primitives = { workspace = true }

[dev-dependencies]
pallet-assets = { workspace = true, features = ["std"] }
pallet-balances = { workspace = true, features = ["std"] }
sp-core = { workspace = true, features = ["std"] }
sp-io = { workspace = true, features = ["std"] }
sp-runtime = { workspace = true, features = ["std"] }
xcm-builder = { workspace = true, features = ["std"] }

[features]
default = ["std"]
std = [
"astar-primitives/std",
"frame-benchmarking/std",
"frame-support/std",
"frame-system/std",
"pallet-xcm-benchmarks/std",
"parity-scale-codec/std",
"serde",
"sp-std/std",
"xcm/std",
]

try-runtime = ["frame-support/try-runtime"]

runtime-benchmarks = [
"frame-benchmarking",
"frame-system/runtime-benchmarks",
"pallet-assets/runtime-benchmarks",
"pallet-xcm-benchmarks/runtime-benchmarks",
"parity-scale-codec",
"xcm-executor/runtime-benchmarks",
]
204 changes: 204 additions & 0 deletions pallets/astar-xcm-benchmarks/src/fungible/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar 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.

// Astar 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 Astar. If not, see <http://www.gnu.org/licenses/>.

use super::{Pallet as AstarBenchmarks, *};
use crate::WrappedBenchmark;
use frame_benchmarking::v2::*;
use frame_support::{
dispatch::Weight,
traits::{fungible::Inspect, Get},
};
use pallet_xcm_benchmarks::{
account_and_location, fungible::Pallet as PalletXcmBenchmarks, new_executor, AssetTransactorOf,
};
use sp_std::vec;
use xcm::latest::prelude::*;
use xcm_executor::traits::{Convert, TransactAsset};

#[benchmarks(
where
<
<
T::TransactAsset
as
Inspect<T::AccountId>
>::Balance
as
TryInto<u128>
>::Error: sp_std::fmt::Debug,
)]
mod benchmarks {
use super::*;

/// Re-write for fungibles assets (like pallet_assets's assets) as
/// upstream benchmark does not take ED (assets's min_balance) into consideration
#[benchmark]
fn transfer_asset() -> Result<(), BenchmarkError> {
let (sender_account, sender_location) = account_and_location::<T>(1);
let asset_to_deposit = T::get_multi_asset();
// take out ED from given asset
let (asset_to_send, min_balance) =
take_minimum_balance::<T>(asset_to_deposit.clone()).unwrap();
let assets: MultiAssets = vec![asset_to_send.clone()].into();
// this xcm doesn't use holding

let dest_location = T::valid_destination()?;
let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap();

<AssetTransactorOf<T>>::deposit_asset(
&asset_to_deposit,
&sender_location,
&XcmContext {
origin: Some(sender_location.clone()),
message_hash: [0; 32],
topic: None,
},
)
.unwrap();

let mut executor = new_executor::<T>(sender_location);
let instruction = Instruction::TransferAsset {
assets,
beneficiary: dest_location,
};
let xcm = Xcm(vec![instruction]);

#[block]
{
executor.bench_process(xcm)?;
}

assert_eq!(T::TransactAsset::balance(&sender_account), min_balance);
assert!(!T::TransactAsset::balance(&dest_account).is_zero());
Ok(())
}

/// Re-write for fungibles assets (like pallet_assets's assets) as
/// upstream benchmark does not take ED (assets's min_balance) into consideration
#[benchmark]
fn transfer_reserve_asset() -> Result<(), BenchmarkError> {
let (sender_account, sender_location) = account_and_location::<T>(1);
let dest_location = T::valid_destination()?;
let dest_account = T::AccountIdConverter::convert(dest_location.clone()).unwrap();

let asset_to_deposit = T::get_multi_asset();
// take out ED from given asset
let (asset_to_send, min_balance) =
take_minimum_balance::<T>(asset_to_deposit.clone()).unwrap();
let assets: MultiAssets = vec![asset_to_send].into();

<AssetTransactorOf<T>>::deposit_asset(
&asset_to_deposit,
&sender_location,
&XcmContext {
origin: Some(sender_location.clone()),
message_hash: [0; 32],
topic: None,
},
)
.unwrap();
assert!(T::TransactAsset::balance(&dest_account).is_zero());

let mut executor = new_executor::<T>(sender_location);
let instruction = Instruction::TransferReserveAsset {
assets,
dest: dest_location,
xcm: Xcm::new(),
};
let xcm = Xcm(vec![instruction]);

#[block]
{
executor.bench_process(xcm)?;
}

assert_eq!(T::TransactAsset::balance(&sender_account), min_balance);
assert!(!T::TransactAsset::balance(&dest_account).is_zero());
Ok(())
}

/// The benchmarks for `reserve_asset_deposited` was added in later versions of
/// `pallet-xcm-benchmarks` (in v1.x.x versions).
/// TODO: remove this once we uplift to new polkadot release
#[benchmark]
fn reserve_asset_deposited() -> Result<(), BenchmarkError> {
let (trusted_reserve, transferable_reserve_asset) = T::TrustedReserve::get().ok_or(
BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)),
)?;

let assets: MultiAssets = vec![transferable_reserve_asset].into();

let mut executor = new_executor::<T>(trusted_reserve);
let instruction = Instruction::ReserveAssetDeposited(assets.clone());
let xcm = Xcm(vec![instruction]);

#[block]
{
executor.bench_process(xcm)?;
}

assert!(executor.holding().ensure_contains(&assets).is_ok());
Ok(())
}

#[benchmark]
fn receive_teleported_asset() -> Result<(), BenchmarkError> {
#[block]
{}
Err(BenchmarkError::Override(BenchmarkResult::from_weight(
Weight::MAX,
)))
}

#[benchmark]
fn initiate_teleport() -> Result<(), BenchmarkError> {
#[block]
{}
Err(BenchmarkError::Override(BenchmarkResult::from_weight(
Weight::MAX,
)))
}

impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
}

// wrapper benchmarks
pub type XcmFungibleBenchmarks<T> = WrappedBenchmark<AstarBenchmarks<T>, PalletXcmBenchmarks<T>>;

/// Take out the ED from given MultiAsset (if fungible)
fn take_minimum_balance<T: Config>(
mut asset: MultiAsset,
) -> Result<
(
MultiAsset,
<T::TransactAsset as Inspect<T::AccountId>>::Balance,
),
(),
>
where
<<T::TransactAsset as Inspect<T::AccountId>>::Balance as TryInto<u128>>::Error:
sp_std::fmt::Debug,
{
let minimum_balance = T::TransactAsset::minimum_balance();

if let Fungible(fun) = asset.fun {
asset.fun = Fungible(fun.saturating_sub(minimum_balance.try_into().map_err(|_| ())?));
}

Ok((asset, minimum_balance))
}
39 changes: 39 additions & 0 deletions pallets/astar-xcm-benchmarks/src/fungible/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// This file is part of Astar.

// Copyright (C) 2019-2023 Stake Technologies Pte.Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later

// Astar 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.

// Astar 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 Astar. If not, see <http://www.gnu.org/licenses/>.

pub use pallet::*;

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

#[frame_support::pallet]
pub mod pallet {
#[pallet::config]
pub trait Config<I: 'static = ()>:
frame_system::Config + crate::Config + pallet_xcm_benchmarks::fungible::Config
{
/// A trusted location where reserve assets are stored, and the asset we allow to be
/// reserves.
type TrustedReserve: frame_support::traits::Get<
Option<(xcm::latest::MultiLocation, xcm::latest::MultiAsset)>,
>;
}

#[pallet::pallet]
pub struct Pallet<T, I = ()>(_);
}
Loading

0 comments on commit ffe8628

Please sign in to comment.