referrerpolicy=no-referrer-when-downgrade

pallet_xcm/
benchmarking.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
17use super::*;
18use frame_benchmarking::v2::*;
19use frame_support::{assert_ok, weights::Weight};
20use frame_system::RawOrigin;
21use xcm::{latest::prelude::*, MAX_INSTRUCTIONS_TO_DECODE};
22use xcm_builder::EnsureDelivery;
23use xcm_executor::traits::FeeReason;
24
25type RuntimeOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;
26
27/// Pallet we're benchmarking here.
28pub struct Pallet<T: Config>(crate::Pallet<T>);
29
30/// Trait that must be implemented by runtime to be able to benchmark pallet properly.
31pub trait Config: crate::Config + pallet_balances::Config {
32	/// Helper that ensures successful delivery for extrinsics/benchmarks which need `SendXcm`.
33	type DeliveryHelper: EnsureDelivery;
34
35	/// A `Location` that can be reached via `XcmRouter`. Used only in benchmarks.
36	///
37	/// If `None`, the benchmarks that depend on a reachable destination will be skipped.
38	fn reachable_dest() -> Option<Location> {
39		None
40	}
41
42	/// A `(Asset, Location)` pair representing asset and the destination it can be
43	/// teleported to. Used only in benchmarks.
44	///
45	/// Implementation should also make sure `dest` is reachable/connected.
46	///
47	/// If `None`, the benchmarks that depend on this will default to `Weight::MAX`.
48	fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
49		None
50	}
51
52	/// A `(Asset, Location)` pair representing asset and the destination it can be
53	/// reserve-transferred to. Used only in benchmarks.
54	///
55	/// Implementation should also make sure `dest` is reachable/connected.
56	///
57	/// If `None`, the benchmarks that depend on this will default to `Weight::MAX`.
58	fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
59		None
60	}
61
62	/// Sets up a complex transfer (usually consisting of a teleport and reserve-based transfer), so
63	/// that runtime can properly benchmark `transfer_assets()` extrinsic. Should return a tuple
64	/// `(Asset, u32, Location, dyn FnOnce())` representing the assets to transfer, the
65	/// `u32` index of the asset to be used for fees, the destination chain for the transfer, and a
66	/// `verify()` closure to verify the intended transfer side-effects.
67	///
68	/// Implementation should make sure the provided assets can be transacted by the runtime, there
69	/// are enough balances in the involved accounts, and that `dest` is reachable/connected.
70	///
71	/// Used only in benchmarks.
72	///
73	/// If `None`, the benchmarks that depend on this will default to `Weight::MAX`.
74	fn set_up_complex_asset_transfer() -> Option<(Assets, u32, Location, Box<dyn FnOnce()>)> {
75		None
76	}
77
78	/// Gets an asset that can be handled by the AssetTransactor.
79	///
80	/// Used only in benchmarks.
81	///
82	/// Used, for example, in the benchmark for `claim_assets`.
83	fn get_asset() -> Asset;
84}
85
86#[benchmarks]
87mod benchmarks {
88	use super::*;
89
90	#[benchmark]
91	fn send() -> Result<(), BenchmarkError> {
92		let send_origin =
93			T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
94		if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() {
95			return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
96		}
97		let msg = Xcm(vec![ClearOrigin]);
98		let versioned_dest: VersionedLocation = T::reachable_dest()
99			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?
100			.into();
101		let versioned_msg = VersionedXcm::from(msg);
102
103		// Ensure that origin can send to destination
104		// (e.g. setup delivery fees, ensure router setup, ...)
105		T::DeliveryHelper::ensure_successful_delivery(
106			&Default::default(),
107			&versioned_dest.clone().try_into().unwrap(),
108			FeeReason::ChargeFees,
109		);
110
111		#[extrinsic_call]
112		_(send_origin as RuntimeOrigin<T>, Box::new(versioned_dest), Box::new(versioned_msg));
113
114		Ok(())
115	}
116
117	#[benchmark]
118	fn teleport_assets() -> Result<(), BenchmarkError> {
119		let (asset, destination) = T::teleportable_asset_and_dest()
120			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
121
122		let assets: Assets = asset.clone().into();
123
124		let caller: T::AccountId = whitelisted_caller();
125		let send_origin = RawOrigin::Signed(caller.clone());
126		let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into())
127			.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
128		if !T::XcmTeleportFilter::contains(&(origin_location.clone(), assets.clone().into_inner()))
129		{
130			return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
131		}
132
133		// Ensure that origin can send to destination
134		// (e.g. setup delivery fees, ensure router setup, ...)
135		let (_, _) = T::DeliveryHelper::ensure_successful_delivery(
136			&origin_location,
137			&destination,
138			FeeReason::ChargeFees,
139		);
140
141		match &asset.fun {
142			Fungible(amount) => {
143				// Add transferred_amount to origin
144				let context =
145					XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
146				let asset_to_mint = Asset { fun: Fungible(*amount), id: asset.id.clone() };
147				let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
148					&asset_to_mint,
149					&context,
150				)
151				.map_err(|error| {
152					tracing::error!("Fungible asset couldn't be minted, error: {:?}", error);
153					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
154				})?;
155				<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
156					holdings,
157					&origin_location,
158					Some(&context),
159				)
160				.map_err(|error| {
161					tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error.1);
162					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
163				})?;
164			},
165			NonFungible(_instance) => {
166				let context =
167					XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
168				let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
169					&asset, &context,
170				)
171				.map_err(|error| {
172					tracing::error!("Nonfungible asset couldn't be minted, error: {:?}", error);
173					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
174				})?;
175				<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
176					holdings,
177					&origin_location,
178					Some(&context),
179				)
180				.map_err(|error| {
181					tracing::error!(
182						"Nonfungible asset couldn't be deposited, error: {:?}",
183						error.1
184					);
185					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
186				})?;
187			},
188		};
189
190		let recipient = [0u8; 32];
191		let versioned_dest: VersionedLocation = destination.into();
192		let versioned_beneficiary: VersionedLocation =
193			AccountId32 { network: None, id: recipient.into() }.into();
194		let versioned_assets: VersionedAssets = assets.into();
195
196		#[extrinsic_call]
197		_(
198			send_origin,
199			Box::new(versioned_dest),
200			Box::new(versioned_beneficiary),
201			Box::new(versioned_assets),
202			0,
203		);
204
205		Ok(())
206	}
207
208	#[benchmark]
209	fn reserve_transfer_assets() -> Result<(), BenchmarkError> {
210		let (asset, destination) = T::reserve_transferable_asset_and_dest()
211			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
212
213		let assets: Assets = asset.clone().into();
214
215		let caller: T::AccountId = whitelisted_caller();
216		let send_origin = RawOrigin::Signed(caller.clone());
217		let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into())
218			.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
219		if !T::XcmReserveTransferFilter::contains(&(
220			origin_location.clone(),
221			assets.clone().into_inner(),
222		)) {
223			return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
224		}
225
226		// Ensure that origin can send to destination
227		// (e.g. setup delivery fees, ensure router setup, ...)
228		let (_, _) = T::DeliveryHelper::ensure_successful_delivery(
229			&origin_location,
230			&destination,
231			FeeReason::ChargeFees,
232		);
233
234		match &asset.fun {
235			Fungible(amount) => {
236				// Add transferred_amount to origin
237				let context =
238					XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
239				let asset_to_mint = Asset { fun: Fungible(*amount), id: asset.id.clone() };
240				let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
241					&asset_to_mint,
242					&context,
243				)
244				.map_err(|error| {
245					tracing::error!("Fungible asset couldn't be minted, error: {:?}", error);
246					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
247				})?;
248				<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
249					holdings,
250					&origin_location,
251					Some(&context),
252				)
253				.map_err(|error| {
254					tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error.1);
255					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
256				})?;
257			},
258			NonFungible(_instance) => {
259				let context =
260					XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
261				let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
262					&asset, &context,
263				)
264				.map_err(|error| {
265					tracing::error!("Nonfungible asset couldn't be minted, error: {:?}", error);
266					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
267				})?;
268				<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
269					holdings,
270					&origin_location,
271					Some(&context),
272				)
273				.map_err(|error| {
274					tracing::error!(
275						"Nonfungible asset couldn't be deposited, error: {:?}",
276						error.1
277					);
278					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
279				})?;
280			},
281		};
282
283		let recipient = [0u8; 32];
284		let versioned_dest: VersionedLocation = destination.clone().into();
285		let versioned_beneficiary: VersionedLocation =
286			AccountId32 { network: None, id: recipient.into() }.into();
287		let versioned_assets: VersionedAssets = assets.into();
288
289		#[extrinsic_call]
290		_(
291			send_origin,
292			Box::new(versioned_dest),
293			Box::new(versioned_beneficiary),
294			Box::new(versioned_assets),
295			0,
296		);
297
298		match &asset.fun {
299			Fungible(amount) => {
300				assert_ok!(<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::withdraw_asset(
301					&Asset { fun: Fungible(*amount), id: asset.id },
302					&destination,
303					None,
304				));
305			},
306			NonFungible(_instance) => {
307				assert_ok!(<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::withdraw_asset(
308					&asset,
309					&destination,
310					None,
311				));
312			},
313		};
314
315		Ok(())
316	}
317
318	#[benchmark]
319	fn transfer_assets() -> Result<(), BenchmarkError> {
320		let (assets, _fee_index, destination, verify_fn) = T::set_up_complex_asset_transfer()
321			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
322		let caller: T::AccountId = whitelisted_caller();
323		let send_origin = RawOrigin::Signed(caller.clone());
324		let recipient = [0u8; 32];
325		let versioned_dest: VersionedLocation = destination.into();
326		let versioned_beneficiary: VersionedLocation =
327			AccountId32 { network: None, id: recipient.into() }.into();
328		let versioned_assets: VersionedAssets = assets.into();
329
330		// Ensure that origin can send to destination
331		// (e.g. setup delivery fees, ensure router setup, ...)
332		T::DeliveryHelper::ensure_successful_delivery(
333			&Default::default(),
334			&versioned_dest.clone().try_into().unwrap(),
335			FeeReason::ChargeFees,
336		);
337
338		#[extrinsic_call]
339		_(
340			send_origin,
341			Box::new(versioned_dest),
342			Box::new(versioned_beneficiary),
343			Box::new(versioned_assets),
344			0,
345			WeightLimit::Unlimited,
346		);
347
348		// run provided verification function
349		verify_fn();
350		Ok(())
351	}
352
353	#[benchmark]
354	fn execute() -> Result<(), BenchmarkError> {
355		let execute_origin =
356			T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
357		let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone())
358			.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
359		let msg = Xcm(vec![ClearOrigin]);
360		if !T::XcmExecuteFilter::contains(&(origin_location, msg.clone())) {
361			return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
362		}
363		let versioned_msg = VersionedXcm::from(msg);
364
365		#[extrinsic_call]
366		_(execute_origin as RuntimeOrigin<T>, Box::new(versioned_msg), Weight::MAX);
367
368		Ok(())
369	}
370
371	#[benchmark]
372	fn force_xcm_version() -> Result<(), BenchmarkError> {
373		let loc = T::reachable_dest()
374			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
375		let xcm_version = 2;
376
377		#[extrinsic_call]
378		_(RawOrigin::Root, Box::new(loc), xcm_version);
379
380		Ok(())
381	}
382
383	#[benchmark]
384	fn force_default_xcm_version() {
385		#[extrinsic_call]
386		_(RawOrigin::Root, Some(2))
387	}
388
389	#[benchmark]
390	fn force_subscribe_version_notify() -> Result<(), BenchmarkError> {
391		let versioned_loc: VersionedLocation = T::reachable_dest()
392			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?
393			.into();
394
395		// Ensure that origin can send to destination
396		// (e.g. setup delivery fees, ensure router setup, ...)
397		T::DeliveryHelper::ensure_successful_delivery(
398			&Default::default(),
399			&versioned_loc.clone().try_into().unwrap(),
400			FeeReason::ChargeFees,
401		);
402
403		#[extrinsic_call]
404		_(RawOrigin::Root, Box::new(versioned_loc));
405
406		Ok(())
407	}
408
409	#[benchmark]
410	fn force_unsubscribe_version_notify() -> Result<(), BenchmarkError> {
411		let loc = T::reachable_dest()
412			.ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
413		let versioned_loc: VersionedLocation = loc.clone().into();
414
415		// Ensure that origin can send to destination
416		// (e.g. setup delivery fees, ensure router setup, ...)
417		T::DeliveryHelper::ensure_successful_delivery(
418			&Default::default(),
419			&versioned_loc.clone().try_into().unwrap(),
420			FeeReason::ChargeFees,
421		);
422
423		let _ = crate::Pallet::<T>::request_version_notify(loc);
424
425		#[extrinsic_call]
426		_(RawOrigin::Root, Box::new(versioned_loc));
427
428		Ok(())
429	}
430
431	#[benchmark]
432	fn force_suspension() {
433		#[extrinsic_call]
434		_(RawOrigin::Root, true)
435	}
436
437	#[benchmark]
438	fn migrate_supported_version() {
439		let old_version = XCM_VERSION - 1;
440		let loc = VersionedLocation::from(Location::from(Parent));
441		SupportedVersion::<T>::insert(old_version, loc, old_version);
442
443		#[block]
444		{
445			crate::Pallet::<T>::lazy_migration(
446				VersionMigrationStage::MigrateSupportedVersion,
447				Weight::zero(),
448			);
449		}
450	}
451
452	#[benchmark]
453	fn migrate_version_notifiers() {
454		let old_version = XCM_VERSION - 1;
455		let loc = VersionedLocation::from(Location::from(Parent));
456		VersionNotifiers::<T>::insert(old_version, loc, 0);
457
458		#[block]
459		{
460			crate::Pallet::<T>::lazy_migration(
461				VersionMigrationStage::MigrateVersionNotifiers,
462				Weight::zero(),
463			);
464		}
465	}
466
467	#[benchmark]
468	fn already_notified_target() -> Result<(), BenchmarkError> {
469		let loc = T::reachable_dest().ok_or(BenchmarkError::Override(
470			BenchmarkResult::from_weight(T::DbWeight::get().reads(1)),
471		))?;
472		let loc = VersionedLocation::from(loc);
473		let current_version = T::AdvertisedXcmVersion::get();
474		VersionNotifyTargets::<T>::insert(
475			current_version,
476			loc,
477			(0, Weight::zero(), current_version),
478		);
479
480		#[block]
481		{
482			crate::Pallet::<T>::lazy_migration(
483				VersionMigrationStage::NotifyCurrentTargets(None),
484				Weight::zero(),
485			);
486		}
487
488		Ok(())
489	}
490
491	#[benchmark]
492	fn notify_current_targets() -> Result<(), BenchmarkError> {
493		let loc = T::reachable_dest().ok_or(BenchmarkError::Override(
494			BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3)),
495		))?;
496		let loc = VersionedLocation::from(loc);
497		let current_version = T::AdvertisedXcmVersion::get();
498		let old_version = current_version - 1;
499		VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), old_version));
500
501		#[block]
502		{
503			crate::Pallet::<T>::lazy_migration(
504				VersionMigrationStage::NotifyCurrentTargets(None),
505				Weight::zero(),
506			);
507		}
508
509		Ok(())
510	}
511
512	#[benchmark]
513	fn notify_target_migration_fail() {
514		let newer_xcm_version = xcm::prelude::XCM_VERSION;
515		let older_xcm_version = newer_xcm_version - 1;
516		let bad_location: Location = Plurality { id: BodyId::Unit, part: BodyPart::Voice }.into();
517		let bad_location = VersionedLocation::from(bad_location)
518			.into_version(older_xcm_version)
519			.expect("Version conversion should work");
520		let current_version = T::AdvertisedXcmVersion::get();
521		VersionNotifyTargets::<T>::insert(
522			current_version,
523			bad_location,
524			(0, Weight::zero(), current_version),
525		);
526
527		#[block]
528		{
529			crate::Pallet::<T>::lazy_migration(
530				VersionMigrationStage::MigrateAndNotifyOldTargets,
531				Weight::zero(),
532			);
533		}
534	}
535
536	#[benchmark]
537	fn migrate_version_notify_targets() {
538		let current_version = T::AdvertisedXcmVersion::get();
539		let old_version = current_version - 1;
540		let loc = VersionedLocation::from(Location::from(Parent));
541		VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), current_version));
542
543		#[block]
544		{
545			crate::Pallet::<T>::lazy_migration(
546				VersionMigrationStage::MigrateAndNotifyOldTargets,
547				Weight::zero(),
548			);
549		}
550	}
551
552	#[benchmark]
553	fn migrate_and_notify_old_targets() -> Result<(), BenchmarkError> {
554		let loc = T::reachable_dest().ok_or(BenchmarkError::Override(
555			BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3)),
556		))?;
557		let loc = VersionedLocation::from(loc);
558		let old_version = T::AdvertisedXcmVersion::get() - 1;
559		VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), old_version));
560
561		#[block]
562		{
563			crate::Pallet::<T>::lazy_migration(
564				VersionMigrationStage::MigrateAndNotifyOldTargets,
565				Weight::zero(),
566			);
567		}
568
569		Ok(())
570	}
571
572	#[benchmark]
573	fn new_query() {
574		let responder = Location::from(Parent);
575		let timeout = 1u32.into();
576		let match_querier = Location::from(Here);
577
578		#[block]
579		{
580			crate::Pallet::<T>::new_query(responder, timeout, match_querier);
581		}
582	}
583
584	#[benchmark]
585	fn take_response() {
586		let responder = Location::from(Parent);
587		let timeout = 1u32.into();
588		let match_querier = Location::from(Here);
589		let query_id = crate::Pallet::<T>::new_query(responder, timeout, match_querier);
590		let infos = (0..xcm::v3::MaxPalletsInfo::get())
591			.map(|_| {
592				PalletInfo::new(
593					u32::MAX,
594					(0..xcm::v3::MaxPalletNameLen::get())
595						.map(|_| 97u8)
596						.collect::<Vec<_>>()
597						.try_into()
598						.unwrap(),
599					(0..xcm::v3::MaxPalletNameLen::get())
600						.map(|_| 97u8)
601						.collect::<Vec<_>>()
602						.try_into()
603						.unwrap(),
604					u32::MAX,
605					u32::MAX,
606					u32::MAX,
607				)
608				.unwrap()
609			})
610			.collect::<Vec<_>>();
611		crate::Pallet::<T>::expect_response(
612			query_id,
613			Response::PalletsInfo(infos.try_into().unwrap()),
614		);
615
616		#[block]
617		{
618			<crate::Pallet<T> as QueryHandler>::take_response(query_id);
619		}
620	}
621
622	#[benchmark]
623	fn claim_assets() -> Result<(), BenchmarkError> {
624		let claim_origin = RawOrigin::Signed(whitelisted_caller());
625		let claim_location = T::ExecuteXcmOrigin::try_origin(claim_origin.clone().into())
626			.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
627		let asset: Asset = T::get_asset();
628		let context = XcmContext { origin: None, message_id: [0u8; 32], topic: None };
629		// Trap assets for claiming later
630		let holdings =
631			<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(&asset, &context)
632				.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
633		crate::Pallet::<T>::drop_assets(&claim_location, holdings, &context);
634		let versioned_assets = VersionedAssets::from(Assets::from(asset));
635
636		#[extrinsic_call]
637		_(
638			claim_origin,
639			Box::new(versioned_assets),
640			Box::new(VersionedLocation::from(claim_location)),
641		);
642
643		Ok(())
644	}
645
646	#[benchmark]
647	fn add_authorized_alias() -> Result<(), BenchmarkError> {
648		let who: T::AccountId = whitelisted_caller();
649		let origin = RawOrigin::Signed(who.clone());
650		let origin_location: VersionedLocation =
651			T::ExecuteXcmOrigin::try_origin(origin.clone().into())
652				.map_err(|_| {
653					tracing::error!(
654						target: "xcm::benchmarking::pallet_xcm::add_authorized_alias",
655						?origin,
656						"try_origin failed",
657					);
658					BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
659				})?
660				.into();
661
662		// Give some multiple of ED
663		let balance = T::ExistentialDeposit::get() * 1000000u32.into();
664		let _ =
665			<pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
666
667		let mut existing_aliases = BoundedVec::<OriginAliaser, MaxAuthorizedAliases>::new();
668		// prepopulate list with `max-1` aliases to benchmark worst case
669		for i in 1..MaxAuthorizedAliases::get() {
670			let alias =
671				Location::new(1, [Parachain(i), AccountId32 { network: None, id: [42_u8; 32] }])
672					.into();
673			let aliaser = OriginAliaser { location: alias, expiry: None };
674			existing_aliases.try_push(aliaser).unwrap()
675		}
676		let footprint = aliasers_footprint(existing_aliases.len());
677		let ticket = TicketOf::<T>::new(&who, footprint).map_err(|e| {
678			tracing::error!(
679				target: "xcm::benchmarking::pallet_xcm::add_authorized_alias",
680				?who,
681				?footprint,
682				error=?e,
683				"could not create ticket",
684			);
685			BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
686		})?;
687		let entry = AuthorizedAliasesEntry { aliasers: existing_aliases, ticket };
688		AuthorizedAliases::<T>::insert(&origin_location, entry);
689
690		// now benchmark adding new alias
691		let aliaser: VersionedLocation =
692			Location::new(1, [Parachain(1234), AccountId32 { network: None, id: [42_u8; 32] }])
693				.into();
694
695		#[extrinsic_call]
696		_(origin, Box::new(aliaser), None);
697
698		Ok(())
699	}
700
701	#[benchmark]
702	fn remove_authorized_alias() -> Result<(), BenchmarkError> {
703		let who: T::AccountId = whitelisted_caller();
704		let origin = RawOrigin::Signed(who.clone());
705		let error = BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX));
706		let origin_location =
707			T::ExecuteXcmOrigin::try_origin(origin.clone().into()).map_err(|_| {
708				tracing::error!(
709					target: "xcm::benchmarking::pallet_xcm::remove_authorized_alias",
710					?origin,
711					"try_origin failed",
712				);
713				error.clone()
714			})?;
715		// remove `network` from inner `AccountId32` for easier matching of automatic AccountId ->
716		// Location conversions.
717		let origin_location: VersionedLocation = match origin_location.unpack() {
718			(0, [AccountId32 { network: _, id }]) => {
719				Location::new(0, [AccountId32 { network: None, id: *id }]).into()
720			},
721			_ => {
722				tracing::error!(
723					target: "xcm::benchmarking::pallet_xcm::remove_authorized_alias",
724					?origin_location,
725					"unexpected origin failed",
726				);
727				return Err(error.clone());
728			},
729		};
730
731		// Give some multiple of ED
732		let balance = T::ExistentialDeposit::get() * 1000000u32.into();
733		let _ =
734			<pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
735
736		let mut existing_aliases = BoundedVec::<OriginAliaser, MaxAuthorizedAliases>::new();
737		// prepopulate list with `max` aliases to benchmark worst case
738		for i in 1..MaxAuthorizedAliases::get() + 1 {
739			let alias =
740				Location::new(1, [Parachain(i), AccountId32 { network: None, id: [42_u8; 32] }])
741					.into();
742			let aliaser = OriginAliaser { location: alias, expiry: None };
743			existing_aliases.try_push(aliaser).unwrap()
744		}
745		let footprint = aliasers_footprint(existing_aliases.len());
746		let ticket = TicketOf::<T>::new(&who, footprint).map_err(|e| {
747			tracing::error!(
748				target: "xcm::benchmarking::pallet_xcm::remove_authorized_alias",
749				?who,
750				?footprint,
751				error=?e,
752				"could not create ticket",
753			);
754			error
755		})?;
756		let entry = AuthorizedAliasesEntry { aliasers: existing_aliases, ticket };
757		AuthorizedAliases::<T>::insert(&origin_location, entry);
758
759		// now benchmark removing an alias
760		let aliaser_to_remove: VersionedLocation =
761			Location::new(1, [Parachain(1), AccountId32 { network: None, id: [42_u8; 32] }]).into();
762
763		#[extrinsic_call]
764		_(origin, Box::new(aliaser_to_remove));
765
766		Ok(())
767	}
768
769	#[benchmark]
770	fn weigh_message() -> Result<(), BenchmarkError> {
771		let msg = Xcm(vec![ClearOrigin; MAX_INSTRUCTIONS_TO_DECODE.into()]);
772		let versioned_msg = VersionedXcm::from(msg);
773
774		#[block]
775		{
776			crate::Pallet::<T>::query_xcm_weight(versioned_msg)
777				.map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
778		}
779
780		Ok(())
781	}
782
783	impl_benchmark_test_suite!(
784		Pallet,
785		crate::mock::new_test_ext_with_balances(Vec::new()),
786		crate::mock::Test
787	);
788}
789
790pub mod helpers {
791	use super::*;
792	pub fn native_teleport_as_asset_transfer<T>(
793		native_asset_location: Location,
794		destination: Location,
795	) -> Option<(Assets, u32, Location, Box<dyn FnOnce()>)>
796	where
797		T: Config + pallet_balances::Config,
798		u128: From<<T as pallet_balances::Config>::Balance>,
799	{
800		// Relay/native token can be teleported to/from AH.
801		let amount = T::ExistentialDeposit::get() * 100u32.into();
802		let assets: Assets =
803			Asset { fun: Fungible(amount.into()), id: AssetId(native_asset_location) }.into();
804		let fee_index = 0u32;
805
806		// Give some multiple of transferred amount
807		let balance = amount * 10u32.into();
808		let who = whitelisted_caller();
809		let _ =
810			<pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
811		// verify initial balance
812		assert_eq!(pallet_balances::Pallet::<T>::free_balance(&who), balance);
813
814		// verify transferred successfully
815		let verify = Box::new(move || {
816			// verify balance after transfer, decreased by transferred amount (and delivery fees)
817			assert!(pallet_balances::Pallet::<T>::free_balance(&who) <= balance - amount);
818		});
819		Some((assets, fee_index, destination, verify))
820	}
821}