referrerpolicy=no-referrer-when-downgrade

pallet_xcm_benchmarks/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! Pallet that serves no other purpose than benchmarking raw messages [`Xcm`].
18
19#![cfg_attr(not(feature = "std"), no_std)]
20
21extern crate alloc;
22
23use codec::Encode;
24use frame_benchmarking::{account, BenchmarkError};
25use xcm::latest::prelude::*;
26use xcm_builder::EnsureDelivery;
27use xcm_executor::{traits::ConvertLocation, AssetsInHolding, Config as XcmConfig};
28
29pub mod fungible;
30pub mod generic;
31
32#[cfg(test)]
33mod mock;
34
35/// A base trait for all individual pallets
36pub trait Config: frame_system::Config {
37	/// The XCM configurations.
38	///
39	/// These might affect the execution of XCM messages, such as defining how the
40	/// `TransactAsset` is implemented.
41	type XcmConfig: XcmConfig;
42
43	/// A converter between a location to a sovereign account.
44	type AccountIdConverter: ConvertLocation<Self::AccountId>;
45
46	/// Helper that ensures successful delivery for XCM instructions which need `SendXcm`.
47	type DeliveryHelper: EnsureDelivery;
48
49	/// Does any necessary setup to create a valid destination for XCM messages.
50	/// Returns that destination's location to be used in benchmarks.
51	fn valid_destination() -> Result<Location, BenchmarkError>;
52
53	/// Worst case scenario for a holding account in this runtime.
54	/// - `depositable_count` specifies the count of assets we plan to add to the holding on top of
55	///   those generated by the `worst_case_holding` implementation.
56	///
57	/// Returns prebuilt `AssetsInHolding` with dummy assets using `MockCredit` for benchmarking.
58	/// These don't need to be real, mintable assets - they're just for worst-case scenario testing.
59	fn worst_case_holding(depositable_count: u32) -> AssetsInHolding;
60}
61
62const SEED: u32 = 0;
63
64/// Re-export MockCredit for benchmarking.
65/// Used to create dummy `AssetsInHolding` without needing real asset transactors.
66#[cfg(any(test, feature = "runtime-benchmarks"))]
67pub use xcm_executor::test_helpers::MockCredit;
68
69/// The XCM executor to use for doing stuff.
70pub type ExecutorOf<T> = xcm_executor::XcmExecutor<<T as Config>::XcmConfig>;
71/// The overarching call type.
72pub type RuntimeCallOf<T> = <T as frame_system::Config>::RuntimeCall;
73/// The asset transactor of our executor
74pub type AssetTransactorOf<T> = <<T as Config>::XcmConfig as XcmConfig>::AssetTransactor;
75/// The call type of executor's config. Should eventually resolve to the same overarching call type.
76pub type XcmCallOf<T> = <<T as Config>::XcmConfig as XcmConfig>::RuntimeCall;
77
78#[cfg(any(test, feature = "runtime-benchmarks"))]
79pub fn generate_holding_assets(max_assets: u32) -> AssetsInHolding {
80	use xcm_executor::AssetsInHolding;
81	let fungibles_amount: u128 = 100;
82	let holding_fungibles = max_assets / 2;
83	let holding_non_fungibles = max_assets - holding_fungibles - 1; // -1 because of adding `Here` asset
84
85	let mut holding = AssetsInHolding::new();
86
87	// Add fungible assets with MockCredit
88	for i in 0..holding_fungibles {
89		let asset_id = AssetId(GeneralIndex(i as u128).into());
90		let amount = fungibles_amount * (i + 1) as u128;
91		holding.fungible.insert(asset_id, alloc::boxed::Box::new(MockCredit(amount)));
92	}
93
94	// Add one more `Here` asset
95	holding
96		.fungible
97		.insert(AssetId(Here.into()), alloc::boxed::Box::new(MockCredit(u128::MAX)));
98
99	// Add non-fungible assets
100	for i in 0..holding_non_fungibles {
101		let asset_id = AssetId(GeneralIndex(i as u128).into());
102		let instance = asset_instance_from(i);
103		holding.non_fungible.insert((asset_id, instance));
104	}
105
106	holding
107}
108
109#[cfg(any(test, feature = "runtime-benchmarks"))]
110pub fn asset_instance_from(x: u32) -> AssetInstance {
111	let bytes = x.encode();
112	let mut instance = [0u8; 4];
113	instance.copy_from_slice(&bytes);
114	AssetInstance::Array4(instance)
115}
116
117pub fn new_executor<T: Config>(origin: Location) -> ExecutorOf<T> {
118	ExecutorOf::<T>::new(origin, [0; 32])
119}
120
121/// Build a location from an account id.
122fn account_id_junction<T: frame_system::Config>(index: u32) -> Junction {
123	let account: T::AccountId = account("account", index, SEED);
124	let mut encoded = account.encode();
125	encoded.resize(32, 0u8);
126	let mut id = [0u8; 32];
127	id.copy_from_slice(&encoded);
128	Junction::AccountId32 { network: None, id }
129}
130
131pub fn account_and_location<T: Config>(index: u32) -> (T::AccountId, Location) {
132	let location: Location = account_id_junction::<T>(index).into();
133	let account = T::AccountIdConverter::convert_location(&location).unwrap();
134
135	(account, location)
136}