1use super::*;
18use frame_benchmarking::v2::*;
19use frame_support::{assert_ok, weights::Weight};
20use frame_system::RawOrigin;
21use xcm::{
22 latest::{prelude::*, MAX_ITEMS_IN_ASSETS},
23 MAX_INSTRUCTIONS_TO_DECODE,
24};
25use xcm_builder::EnsureDelivery;
26use xcm_executor::traits::{FeeReason, WeightBounds};
27
28type RuntimeOrigin<T> = <T as frame_system::Config>::RuntimeOrigin;
29
30const MAX_XCM_BLOB_BYTES: u32 = 128 * 1024;
35
36const MAX_WEIGHABLE_BLOB_BYTES: u32 = 8 * 1024;
38
39pub struct Pallet<T: Config>(crate::Pallet<T>);
41
42pub trait Config: crate::Config + pallet_balances::Config {
44 type DeliveryHelper: EnsureDelivery;
46
47 fn reachable_dest() -> Option<Location> {
51 None
52 }
53
54 fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
61 None
62 }
63
64 fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
71 None
72 }
73
74 fn set_up_complex_asset_transfer() -> Option<(Assets, u32, Location, Box<dyn FnOnce()>)> {
87 None
88 }
89
90 fn get_asset() -> Asset;
96
97 fn get_assets(_n: u32) -> Assets {
106 Self::get_asset().into()
107 }
108
109 fn batch_call(
116 _calls: Vec<<Self as crate::Config>::RuntimeCall>,
117 ) -> Option<<Self as crate::Config>::RuntimeCall> {
118 None
119 }
120}
121
122#[benchmarks(where <T as crate::Config>::RuntimeCall: From<crate::Call<T>>)]
125mod benchmarks {
126 use super::*;
127
128 #[benchmark]
129 fn send() -> Result<(), BenchmarkError> {
130 let send_origin =
131 T::SendXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
132 if T::SendXcmOrigin::try_origin(send_origin.clone()).is_err() {
133 return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
134 }
135 let msg = Xcm(vec![ClearOrigin]);
136 let versioned_dest: VersionedLocation = T::reachable_dest()
137 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?
138 .into();
139 let versioned_msg = VersionedXcm::from(msg);
140
141 T::DeliveryHelper::ensure_successful_delivery(
144 &Default::default(),
145 &versioned_dest.clone().try_into().unwrap(),
146 FeeReason::ChargeFees,
147 );
148
149 #[extrinsic_call]
150 _(send_origin as RuntimeOrigin<T>, Box::new(versioned_dest), Box::new(versioned_msg));
151
152 Ok(())
153 }
154
155 #[benchmark]
156 fn teleport_assets() -> Result<(), BenchmarkError> {
157 let (asset, destination) = T::teleportable_asset_and_dest()
158 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
159
160 let assets: Assets = asset.clone().into();
161
162 let caller: T::AccountId = whitelisted_caller();
163 let send_origin = RawOrigin::Signed(caller.clone());
164 let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into())
165 .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
166 if !T::XcmTeleportFilter::contains(&(origin_location.clone(), assets.clone().into_inner()))
167 {
168 return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
169 }
170
171 let (_, _) = T::DeliveryHelper::ensure_successful_delivery(
174 &origin_location,
175 &destination,
176 FeeReason::ChargeFees,
177 );
178
179 match &asset.fun {
180 Fungible(amount) => {
181 let context =
183 XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
184 let asset_to_mint = Asset { fun: Fungible(*amount), id: asset.id.clone() };
185 let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
186 &asset_to_mint,
187 &context,
188 )
189 .map_err(|error| {
190 tracing::error!("Fungible asset couldn't be minted, error: {:?}", error);
191 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
192 })?;
193 <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
194 holdings,
195 &origin_location,
196 Some(&context),
197 )
198 .map_err(|error| {
199 tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error.1);
200 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
201 })?;
202 },
203 NonFungible(_instance) => {
204 let context =
205 XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
206 let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
207 &asset, &context,
208 )
209 .map_err(|error| {
210 tracing::error!("Nonfungible asset couldn't be minted, error: {:?}", error);
211 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
212 })?;
213 <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
214 holdings,
215 &origin_location,
216 Some(&context),
217 )
218 .map_err(|error| {
219 tracing::error!(
220 "Nonfungible asset couldn't be deposited, error: {:?}",
221 error.1
222 );
223 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
224 })?;
225 },
226 };
227
228 let recipient = [0u8; 32];
229 let versioned_dest: VersionedLocation = destination.into();
230 let versioned_beneficiary: VersionedLocation =
231 AccountId32 { network: None, id: recipient.into() }.into();
232 let versioned_assets: VersionedAssets = assets.into();
233
234 #[extrinsic_call]
235 _(
236 send_origin,
237 Box::new(versioned_dest),
238 Box::new(versioned_beneficiary),
239 Box::new(versioned_assets),
240 0,
241 );
242
243 Ok(())
244 }
245
246 #[benchmark]
247 fn reserve_transfer_assets() -> Result<(), BenchmarkError> {
248 let (asset, destination) = T::reserve_transferable_asset_and_dest()
249 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
250
251 let assets: Assets = asset.clone().into();
252
253 let caller: T::AccountId = whitelisted_caller();
254 let send_origin = RawOrigin::Signed(caller.clone());
255 let origin_location = T::ExecuteXcmOrigin::try_origin(send_origin.clone().into())
256 .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
257 if !T::XcmReserveTransferFilter::contains(&(
258 origin_location.clone(),
259 assets.clone().into_inner(),
260 )) {
261 return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
262 }
263
264 let (_, _) = T::DeliveryHelper::ensure_successful_delivery(
267 &origin_location,
268 &destination,
269 FeeReason::ChargeFees,
270 );
271
272 match &asset.fun {
273 Fungible(amount) => {
274 let context =
276 XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
277 let asset_to_mint = Asset { fun: Fungible(*amount), id: asset.id.clone() };
278 let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
279 &asset_to_mint,
280 &context,
281 )
282 .map_err(|error| {
283 tracing::error!("Fungible asset couldn't be minted, error: {:?}", error);
284 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
285 })?;
286 <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
287 holdings,
288 &origin_location,
289 Some(&context),
290 )
291 .map_err(|error| {
292 tracing::error!("Fungible asset couldn't be deposited, error: {:?}", error.1);
293 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
294 })?;
295 },
296 NonFungible(_instance) => {
297 let context =
298 XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
299 let holdings = <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(
300 &asset, &context,
301 )
302 .map_err(|error| {
303 tracing::error!("Nonfungible asset couldn't be minted, error: {:?}", error);
304 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
305 })?;
306 <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::deposit_asset(
307 holdings,
308 &origin_location,
309 Some(&context),
310 )
311 .map_err(|error| {
312 tracing::error!(
313 "Nonfungible asset couldn't be deposited, error: {:?}",
314 error.1
315 );
316 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
317 })?;
318 },
319 };
320
321 let recipient = [0u8; 32];
322 let versioned_dest: VersionedLocation = destination.clone().into();
323 let versioned_beneficiary: VersionedLocation =
324 AccountId32 { network: None, id: recipient.into() }.into();
325 let versioned_assets: VersionedAssets = assets.into();
326
327 #[extrinsic_call]
328 _(
329 send_origin,
330 Box::new(versioned_dest),
331 Box::new(versioned_beneficiary),
332 Box::new(versioned_assets),
333 0,
334 );
335
336 match &asset.fun {
337 Fungible(amount) => {
338 assert_ok!(<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::withdraw_asset(
339 &Asset { fun: Fungible(*amount), id: asset.id },
340 &destination,
341 None,
342 ));
343 },
344 NonFungible(_instance) => {
345 assert_ok!(<T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::withdraw_asset(
346 &asset,
347 &destination,
348 None,
349 ));
350 },
351 };
352
353 Ok(())
354 }
355
356 #[benchmark]
357 fn transfer_assets() -> Result<(), BenchmarkError> {
358 let (assets, _fee_index, destination, verify_fn) = T::set_up_complex_asset_transfer()
359 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
360 let caller: T::AccountId = whitelisted_caller();
361 let send_origin = RawOrigin::Signed(caller.clone());
362 let recipient = [0u8; 32];
363 let versioned_dest: VersionedLocation = destination.into();
364 let versioned_beneficiary: VersionedLocation =
365 AccountId32 { network: None, id: recipient.into() }.into();
366 let versioned_assets: VersionedAssets = assets.into();
367
368 T::DeliveryHelper::ensure_successful_delivery(
371 &Default::default(),
372 &versioned_dest.clone().try_into().unwrap(),
373 FeeReason::ChargeFees,
374 );
375
376 #[extrinsic_call]
377 _(
378 send_origin,
379 Box::new(versioned_dest),
380 Box::new(versioned_beneficiary),
381 Box::new(versioned_assets),
382 0,
383 WeightLimit::Unlimited,
384 );
385
386 verify_fn();
388 Ok(())
389 }
390
391 #[benchmark]
392 fn execute() -> Result<(), BenchmarkError> {
393 let execute_origin =
394 T::ExecuteXcmOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
395 let origin_location = T::ExecuteXcmOrigin::try_origin(execute_origin.clone())
396 .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
397 let msg = Xcm(vec![ClearOrigin]);
398 if !T::XcmExecuteFilter::contains(&(origin_location, msg.clone())) {
399 return Err(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)));
400 }
401 let versioned_msg = VersionedXcm::from(msg);
402
403 #[extrinsic_call]
404 _(execute_origin as RuntimeOrigin<T>, Box::new(versioned_msg), Weight::MAX);
405
406 Ok(())
407 }
408
409 #[benchmark]
410 fn force_xcm_version() -> Result<(), BenchmarkError> {
411 let loc = T::reachable_dest()
412 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
413 let xcm_version = 2;
414
415 #[extrinsic_call]
416 _(RawOrigin::Root, Box::new(loc), xcm_version);
417
418 Ok(())
419 }
420
421 #[benchmark]
422 fn force_default_xcm_version() {
423 #[extrinsic_call]
424 _(RawOrigin::Root, Some(2))
425 }
426
427 #[benchmark]
428 fn force_subscribe_version_notify() -> Result<(), BenchmarkError> {
429 let versioned_loc: VersionedLocation = T::reachable_dest()
430 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?
431 .into();
432
433 T::DeliveryHelper::ensure_successful_delivery(
436 &Default::default(),
437 &versioned_loc.clone().try_into().unwrap(),
438 FeeReason::ChargeFees,
439 );
440
441 #[extrinsic_call]
442 _(RawOrigin::Root, Box::new(versioned_loc));
443
444 Ok(())
445 }
446
447 #[benchmark]
448 fn force_unsubscribe_version_notify() -> Result<(), BenchmarkError> {
449 let loc = T::reachable_dest()
450 .ok_or(BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
451 let versioned_loc: VersionedLocation = loc.clone().into();
452
453 T::DeliveryHelper::ensure_successful_delivery(
456 &Default::default(),
457 &versioned_loc.clone().try_into().unwrap(),
458 FeeReason::ChargeFees,
459 );
460
461 let _ = crate::Pallet::<T>::request_version_notify(loc);
462
463 #[extrinsic_call]
464 _(RawOrigin::Root, Box::new(versioned_loc));
465
466 Ok(())
467 }
468
469 #[benchmark]
470 fn force_suspension() {
471 #[extrinsic_call]
472 _(RawOrigin::Root, true)
473 }
474
475 #[benchmark]
476 fn migrate_supported_version() {
477 let old_version = XCM_VERSION - 1;
478 let loc = VersionedLocation::from(Location::from(Parent));
479 SupportedVersion::<T>::insert(old_version, loc, old_version);
480
481 #[block]
482 {
483 crate::Pallet::<T>::lazy_migration(
484 VersionMigrationStage::MigrateSupportedVersion,
485 Weight::zero(),
486 );
487 }
488 }
489
490 #[benchmark]
491 fn migrate_version_notifiers() {
492 let old_version = XCM_VERSION - 1;
493 let loc = VersionedLocation::from(Location::from(Parent));
494 VersionNotifiers::<T>::insert(old_version, loc, 0);
495
496 #[block]
497 {
498 crate::Pallet::<T>::lazy_migration(
499 VersionMigrationStage::MigrateVersionNotifiers,
500 Weight::zero(),
501 );
502 }
503 }
504
505 #[benchmark]
506 fn already_notified_target() -> Result<(), BenchmarkError> {
507 let loc = T::reachable_dest().ok_or(BenchmarkError::Override(
508 BenchmarkResult::from_weight(T::DbWeight::get().reads(1)),
509 ))?;
510 let loc = VersionedLocation::from(loc);
511 let current_version = T::AdvertisedXcmVersion::get();
512 VersionNotifyTargets::<T>::insert(
513 current_version,
514 loc,
515 (0, Weight::zero(), current_version),
516 );
517
518 #[block]
519 {
520 crate::Pallet::<T>::lazy_migration(
521 VersionMigrationStage::NotifyCurrentTargets(None),
522 Weight::zero(),
523 );
524 }
525
526 Ok(())
527 }
528
529 #[benchmark]
530 fn notify_current_targets() -> Result<(), BenchmarkError> {
531 let loc = T::reachable_dest().ok_or(BenchmarkError::Override(
532 BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3)),
533 ))?;
534 let loc = VersionedLocation::from(loc);
535 let current_version = T::AdvertisedXcmVersion::get();
536 let old_version = current_version - 1;
537 VersionNotifyTargets::<T>::insert(current_version, loc, (0, Weight::zero(), old_version));
538
539 #[block]
540 {
541 crate::Pallet::<T>::lazy_migration(
542 VersionMigrationStage::NotifyCurrentTargets(None),
543 Weight::zero(),
544 );
545 }
546
547 Ok(())
548 }
549
550 #[benchmark]
551 fn notify_target_migration_fail() {
552 let newer_xcm_version = xcm::prelude::XCM_VERSION;
553 let older_xcm_version = newer_xcm_version - 1;
554 let bad_location: Location = Plurality { id: BodyId::Unit, part: BodyPart::Voice }.into();
555 let bad_location = VersionedLocation::from(bad_location)
556 .into_version(older_xcm_version)
557 .expect("Version conversion should work");
558 let current_version = T::AdvertisedXcmVersion::get();
559 VersionNotifyTargets::<T>::insert(
560 current_version,
561 bad_location,
562 (0, Weight::zero(), current_version),
563 );
564
565 #[block]
566 {
567 crate::Pallet::<T>::lazy_migration(
568 VersionMigrationStage::MigrateAndNotifyOldTargets,
569 Weight::zero(),
570 );
571 }
572 }
573
574 #[benchmark]
575 fn migrate_version_notify_targets() {
576 let current_version = T::AdvertisedXcmVersion::get();
577 let old_version = current_version - 1;
578 let loc = VersionedLocation::from(Location::from(Parent));
579 VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), current_version));
580
581 #[block]
582 {
583 crate::Pallet::<T>::lazy_migration(
584 VersionMigrationStage::MigrateAndNotifyOldTargets,
585 Weight::zero(),
586 );
587 }
588 }
589
590 #[benchmark]
591 fn migrate_and_notify_old_targets() -> Result<(), BenchmarkError> {
592 let loc = T::reachable_dest().ok_or(BenchmarkError::Override(
593 BenchmarkResult::from_weight(T::DbWeight::get().reads_writes(1, 3)),
594 ))?;
595 let loc = VersionedLocation::from(loc);
596 let old_version = T::AdvertisedXcmVersion::get() - 1;
597 VersionNotifyTargets::<T>::insert(old_version, loc, (0, Weight::zero(), old_version));
598
599 #[block]
600 {
601 crate::Pallet::<T>::lazy_migration(
602 VersionMigrationStage::MigrateAndNotifyOldTargets,
603 Weight::zero(),
604 );
605 }
606
607 Ok(())
608 }
609
610 #[benchmark]
611 fn new_query() {
612 let responder = Location::from(Parent);
613 let timeout = 1u32.into();
614 let match_querier = Location::from(Here);
615
616 #[block]
617 {
618 crate::Pallet::<T>::new_query(responder, timeout, match_querier);
619 }
620 }
621
622 #[benchmark]
623 fn take_response() {
624 let responder = Location::from(Parent);
625 let timeout = 1u32.into();
626 let match_querier = Location::from(Here);
627 let query_id = crate::Pallet::<T>::new_query(responder, timeout, match_querier);
628 let infos = (0..xcm::v3::MaxPalletsInfo::get())
629 .map(|_| {
630 PalletInfo::new(
631 u32::MAX,
632 (0..xcm::v3::MaxPalletNameLen::get())
633 .map(|_| 97u8)
634 .collect::<Vec<_>>()
635 .try_into()
636 .unwrap(),
637 (0..xcm::v3::MaxPalletNameLen::get())
638 .map(|_| 97u8)
639 .collect::<Vec<_>>()
640 .try_into()
641 .unwrap(),
642 u32::MAX,
643 u32::MAX,
644 u32::MAX,
645 )
646 .unwrap()
647 })
648 .collect::<Vec<_>>();
649 crate::Pallet::<T>::expect_response(
650 query_id,
651 Response::PalletsInfo(infos.try_into().unwrap()),
652 );
653
654 #[block]
655 {
656 <crate::Pallet<T> as QueryHandler>::take_response(query_id);
657 }
658 }
659
660 #[benchmark]
661 fn claim_assets(n: Linear<1, { MAX_ITEMS_IN_ASSETS as u32 }>) -> Result<(), BenchmarkError> {
662 let claim_origin = RawOrigin::Signed(whitelisted_caller());
663 let claim_location = T::ExecuteXcmOrigin::try_origin(claim_origin.clone().into())
664 .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
665 let assets = T::get_assets(n);
666 if (assets.len() as u32) < n {
667 tracing::warn!(
668 target: "xcm::benchmarking::pallet_xcm::claim_assets",
669 requested = n,
670 distinct = assets.len(),
671 "`get_assets` returned fewer distinct assets than requested; the weight will \
672 have a ~zero per-asset slope. Chains that can deposit multiple distinct \
673 assets must override `benchmarking::Config::get_assets`.",
674 );
675 }
676 let context = XcmContext { origin: None, message_id: [0u8; 32], topic: None };
677 let mut holding = AssetsInHolding::new();
680 for asset in assets.inner() {
681 let minted =
682 <T::XcmExecutor as XcmAssetTransfers>::AssetTransactor::mint_asset(asset, &context)
683 .map_err(|_| {
684 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
685 })?;
686 holding.subsume_assets(minted);
687 }
688 crate::Pallet::<T>::drop_assets(&claim_location, holding, &context);
689 let versioned_assets = VersionedAssets::from(assets);
690
691 #[extrinsic_call]
692 _(
693 claim_origin,
694 Box::new(versioned_assets),
695 Box::new(VersionedLocation::from(claim_location)),
696 );
697
698 Ok(())
699 }
700
701 #[benchmark]
702 fn add_authorized_alias() -> Result<(), BenchmarkError> {
703 let who: T::AccountId = whitelisted_caller();
704 let origin = RawOrigin::Signed(who.clone());
705 let origin_location: VersionedLocation =
706 T::ExecuteXcmOrigin::try_origin(origin.clone().into())
707 .map_err(|_| {
708 tracing::error!(
709 target: "xcm::benchmarking::pallet_xcm::add_authorized_alias",
710 ?origin,
711 "try_origin failed",
712 );
713 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
714 })?
715 .into();
716
717 let balance = T::ExistentialDeposit::get() * 1000000u32.into();
719 let _ =
720 <pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
721
722 let mut existing_aliases = BoundedVec::<OriginAliaser, MaxAuthorizedAliases>::new();
723 for i in 1..MaxAuthorizedAliases::get() {
725 let alias =
726 Location::new(1, [Parachain(i), AccountId32 { network: None, id: [42_u8; 32] }])
727 .into();
728 let aliaser = OriginAliaser { location: alias, expiry: None };
729 existing_aliases.try_push(aliaser).unwrap()
730 }
731 let footprint = aliasers_footprint(existing_aliases.len());
732 let ticket = TicketOf::<T>::new(&who, footprint).map_err(|e| {
733 tracing::error!(
734 target: "xcm::benchmarking::pallet_xcm::add_authorized_alias",
735 ?who,
736 ?footprint,
737 error=?e,
738 "could not create ticket",
739 );
740 BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX))
741 })?;
742 let entry = AuthorizedAliasesEntry { aliasers: existing_aliases, ticket };
743 AuthorizedAliases::<T>::insert(&origin_location, entry);
744
745 let aliaser: VersionedLocation =
747 Location::new(1, [Parachain(1234), AccountId32 { network: None, id: [42_u8; 32] }])
748 .into();
749
750 #[extrinsic_call]
751 _(origin, Box::new(aliaser), None);
752
753 Ok(())
754 }
755
756 #[benchmark]
757 fn remove_authorized_alias() -> Result<(), BenchmarkError> {
758 let who: T::AccountId = whitelisted_caller();
759 let origin = RawOrigin::Signed(who.clone());
760 let error = BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX));
761 let origin_location =
762 T::ExecuteXcmOrigin::try_origin(origin.clone().into()).map_err(|_| {
763 tracing::error!(
764 target: "xcm::benchmarking::pallet_xcm::remove_authorized_alias",
765 ?origin,
766 "try_origin failed",
767 );
768 error.clone()
769 })?;
770 let origin_location: VersionedLocation = match origin_location.unpack() {
773 (0, [AccountId32 { network: _, id }]) => {
774 Location::new(0, [AccountId32 { network: None, id: *id }]).into()
775 },
776 _ => {
777 tracing::error!(
778 target: "xcm::benchmarking::pallet_xcm::remove_authorized_alias",
779 ?origin_location,
780 "unexpected origin failed",
781 );
782 return Err(error.clone());
783 },
784 };
785
786 let balance = T::ExistentialDeposit::get() * 1000000u32.into();
788 let _ =
789 <pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
790
791 let mut existing_aliases = BoundedVec::<OriginAliaser, MaxAuthorizedAliases>::new();
792 for i in 1..MaxAuthorizedAliases::get() + 1 {
794 let alias =
795 Location::new(1, [Parachain(i), AccountId32 { network: None, id: [42_u8; 32] }])
796 .into();
797 let aliaser = OriginAliaser { location: alias, expiry: None };
798 existing_aliases.try_push(aliaser).unwrap()
799 }
800 let footprint = aliasers_footprint(existing_aliases.len());
801 let ticket = TicketOf::<T>::new(&who, footprint).map_err(|e| {
802 tracing::error!(
803 target: "xcm::benchmarking::pallet_xcm::remove_authorized_alias",
804 ?who,
805 ?footprint,
806 error=?e,
807 "could not create ticket",
808 );
809 error
810 })?;
811 let entry = AuthorizedAliasesEntry { aliasers: existing_aliases, ticket };
812 AuthorizedAliases::<T>::insert(&origin_location, entry);
813
814 let aliaser_to_remove: VersionedLocation =
816 Location::new(1, [Parachain(1), AccountId32 { network: None, id: [42_u8; 32] }]).into();
817
818 #[extrinsic_call]
819 _(origin, Box::new(aliaser_to_remove));
820
821 Ok(())
822 }
823
824 #[benchmark]
831 fn weigh_message(n: Linear<0, MAX_WEIGHABLE_BLOB_BYTES>) -> Result<(), BenchmarkError> {
832 let bytes = helpers::worst_case_weighable_message::<T>(n);
833
834 #[block]
835 {
836 let decoded =
837 VersionedXcm::<<T as crate::Config>::RuntimeCall>::
838 decode_all_with_mem_and_depth_limit(&mut &bytes[..])
839 .expect("blob was just built by `worst_case_weighable_message`; qed");
840 let mut message: Xcm<<T as crate::Config>::RuntimeCall> =
841 decoded.try_into().expect("blob was built at the latest version; qed");
842 let _ = <T as crate::Config>::Weigher::weight(&mut message, Weight::MAX);
845 }
846
847 Ok(())
848 }
849
850 #[benchmark]
852 fn decode_xcm(n: Linear<0, MAX_XCM_BLOB_BYTES>) -> Result<(), BenchmarkError> {
853 let bytes = helpers::worst_case_decodable_blob(n);
854
855 #[block]
856 {
857 let _ = VersionedXcm::<()>::decode_all_with_mem_and_depth_limit(&mut &bytes[..]);
858 }
859
860 Ok(())
861 }
862
863 impl_benchmark_test_suite!(
864 Pallet,
865 crate::mock::new_test_ext_with_balances(Vec::new()),
866 crate::mock::Test
867 );
868}
869
870#[cfg(test)]
871mod tests {
872 use super::*;
873 use crate::mock::Test;
874
875 #[test]
878 fn worst_case_weighable_message_decodes() {
879 for target_bytes in [0, 1, 1024, MAX_WEIGHABLE_BLOB_BYTES] {
880 let bytes = helpers::worst_case_weighable_message::<Test>(target_bytes);
881 assert!(
882 bytes.len() >= target_bytes as usize,
883 "undershooting the target would under-charge",
884 );
885 VersionedXcm::<<Test as crate::Config>::RuntimeCall>::decode_all_with_mem_and_depth_limit(
886 &mut &bytes[..],
887 )
888 .expect("worst case must decode, otherwise the benchmark measures nothing");
889 }
890 }
891}
892
893pub mod helpers {
894 use super::*;
895
896 pub fn worst_case_weighable_message<T: Config>(target_bytes: u32) -> Vec<u8>
909 where
910 <T as crate::Config>::RuntimeCall: From<crate::Call<T>>,
911 {
912 let inner = Xcm::<<T as crate::Config>::RuntimeCall>(Vec::new());
913 let one: <T as crate::Config>::RuntimeCall = crate::Call::<T>::execute {
914 message: Box::new(VersionedXcm::from(inner)),
915 max_weight: Weight::zero(),
916 }
917 .into();
918 let count = (target_bytes as usize).div_ceil(one.encode().len());
919
920 let call = T::batch_call(vec![one.clone(); count]).unwrap_or_else(|| {
921 tracing::warn!(
922 target: "xcm::benchmarking::pallet_xcm::weigh_message",
923 "`batch_call` is not implemented, so the measured per-byte slope is far below \
924 the real worst case. Chains with a batching pallet must implement \
925 `benchmarking::Config::batch_call`.",
926 );
927 one
928 });
929
930 let message = Xcm::<<T as crate::Config>::RuntimeCall>(vec![Transact {
931 origin_kind: OriginKind::SovereignAccount,
932 fallback_max_weight: None,
933 call: call.encode().into(),
934 }]);
935 VersionedXcm::from(message).encode()
936 }
937
938 pub fn worst_case_decodable_blob(target_bytes: u32) -> Vec<u8> {
946 let dense_asset = |index: u32| -> Asset {
948 let mut data = [0u8; 32];
949 data[..4].copy_from_slice(&index.to_le_bytes());
950 Asset {
951 id: AssetId(Location::new(1, [GeneralKey { length: 32, data }; 8])),
952 fun: Fungible(u128::MAX),
953 }
954 };
955
956 let asset_len = dense_asset(0).encode().len();
958 let count = (target_bytes as usize).div_ceil(asset_len);
959 debug_assert!(
960 count <= MAX_INSTRUCTIONS_TO_DECODE as usize * MAX_ITEMS_IN_ASSETS,
961 "more assets than the instruction limit can carry; the blob would not decode",
962 );
963 let assets = (0..count).map(|index| dense_asset(index as u32)).collect::<Vec<_>>();
964
965 let instructions = assets
966 .chunks(MAX_ITEMS_IN_ASSETS)
967 .map(|chunk| ReserveAssetDeposited(chunk.to_vec().into()))
968 .collect::<Vec<Instruction<()>>>();
969 VersionedXcm::from(Xcm::<()>(instructions)).encode()
970 }
971
972 pub fn native_teleport_as_asset_transfer<T>(
973 native_asset_location: Location,
974 destination: Location,
975 ) -> Option<(Assets, u32, Location, Box<dyn FnOnce()>)>
976 where
977 T: Config + pallet_balances::Config,
978 u128: From<<T as pallet_balances::Config>::Balance>,
979 {
980 let amount = T::ExistentialDeposit::get() * 100u32.into();
982 let assets: Assets =
983 Asset { fun: Fungible(amount.into()), id: AssetId(native_asset_location) }.into();
984 let fee_index = 0u32;
985
986 let balance = amount * 10u32.into();
988 let who = whitelisted_caller();
989 let _ =
990 <pallet_balances::Pallet::<T> as frame_support::traits::Currency<_>>::make_free_balance_be(&who, balance);
991 assert_eq!(pallet_balances::Pallet::<T>::free_balance(&who), balance);
993
994 let verify = Box::new(move || {
996 assert!(pallet_balances::Pallet::<T>::free_balance(&who) <= balance - amount);
998 });
999 Some((assets, fee_index, destination, verify))
1000 }
1001}