1#![cfg(feature = "runtime-benchmarks")]
17
18use super::*;
19use crate::{account_and_location, new_executor, EnsureDelivery, XcmCallOf};
20use alloc::{vec, vec::Vec};
21use codec::Encode;
22use frame_benchmarking::v2::*;
23use frame_support::{traits::fungible::Inspect, BoundedVec};
24use xcm::{
25 latest::{prelude::*, MaxDispatchErrorLen, MaybeErrorCode, Weight, MAX_ITEMS_IN_ASSETS},
26 DoubleEncoded,
27};
28use xcm_executor::{
29 traits::{ConvertLocation, FeeReason, TransactAsset},
30 AssetsInHolding, ExecutorError, FeesMode,
31};
32
33fn assets_to_holding<T: crate::Config>(assets: &Assets) -> Result<AssetsInHolding, XcmError> {
36 let context = XcmContext { origin: None, message_id: XcmHash::default(), topic: None };
37 let mut holding = AssetsInHolding::new();
38 for asset in assets.inner() {
39 let transactor =
40 <T::XcmConfig as xcm_executor::Config>::AssetTransactor::mint_asset(asset, &context)?;
41 holding.subsume_assets(transactor);
42 }
43 Ok(holding)
44}
45
46#[benchmarks]
47mod benchmarks {
48 use super::*;
49
50 #[benchmark]
51 fn report_holding() -> Result<(), BenchmarkError> {
52 let (sender_account, sender_location) = account_and_location::<T>(1);
53 let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
54
55 let (expected_fees_mode, expected_assets_in_holding) =
56 T::DeliveryHelper::ensure_successful_delivery(
57 &sender_location,
58 &destination,
59 FeeReason::Report,
60 );
61 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
62
63 let holding = if let Some(expected_assets_in_holding) = expected_assets_in_holding {
65 let mut holding = T::worst_case_holding(expected_assets_in_holding.len() as u32);
66 let real_assets = assets_to_holding::<T>(&expected_assets_in_holding).unwrap();
68 holding.subsume_assets(real_assets);
69 holding
70 } else {
71 T::worst_case_holding(0)
72 };
73
74 let report_assets: Assets = {
77 let mut assets = Vec::new();
78 for (asset_id, imbalance) in holding.fungible.iter().take(MAX_ITEMS_IN_ASSETS) {
80 assets.push(Asset { id: asset_id.clone(), fun: Fungible(imbalance.amount()) });
81 }
82 let remaining = MAX_ITEMS_IN_ASSETS.saturating_sub(assets.len());
84 for (asset_id, instance) in holding.non_fungible.iter().take(remaining) {
85 assets.push(Asset { id: asset_id.clone(), fun: NonFungible(*instance) });
86 }
87 assets.into()
88 };
89
90 let mut executor = new_executor::<T>(sender_location);
91 executor.set_holding(holding);
92 if let Some(expected_fees_mode) = expected_fees_mode {
93 executor.set_fees_mode(expected_fees_mode);
94 }
95
96 let instruction = Instruction::<XcmCallOf<T>>::ReportHolding {
97 response_info: QueryResponseInfo {
98 destination,
99 query_id: Default::default(),
100 max_weight: Weight::MAX,
101 },
102 assets: Definite(report_assets),
105 };
106
107 let xcm = Xcm(vec![instruction]);
108 #[block]
109 {
110 executor.bench_process(xcm)?;
111 }
112 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
114
115 Ok(())
116 }
117
118 #[benchmark]
121 fn buy_execution() -> Result<(), BenchmarkError> {
122 let holding = T::worst_case_holding(0);
123
124 let mut executor = new_executor::<T>(Default::default());
125 executor.set_holding(holding);
126
127 let (fee_asset, weight_limit) = T::worst_case_for_trader()?;
130
131 let instruction = Instruction::<XcmCallOf<T>>::BuyExecution {
132 fees: fee_asset,
133 weight_limit: weight_limit.into(),
134 };
135
136 let xcm = Xcm(vec![instruction]);
137 #[block]
138 {
139 executor.bench_process(xcm)?;
140 }
141
142 Ok(())
143 }
144
145 #[benchmark]
146 fn pay_fees() -> Result<(), BenchmarkError> {
147 let holding = T::worst_case_holding(0);
148
149 let mut executor = new_executor::<T>(Default::default());
150 executor.set_holding(holding);
151 executor.set_message_weight(Weight::from_parts(100_000_000, 100_000));
153
154 let (fee_asset, _): (Asset, WeightLimit) = T::worst_case_for_trader().unwrap();
155
156 let instruction = Instruction::<XcmCallOf<T>>::PayFees { asset: fee_asset };
157
158 let xcm = Xcm(vec![instruction]);
159 #[block]
160 {
161 executor.bench_process(xcm)?;
162 }
163 Ok(())
164 }
165
166 #[benchmark]
167 fn asset_claimer() -> Result<(), BenchmarkError> {
168 let mut executor = new_executor::<T>(Default::default());
169 let (_, sender_location) = account_and_location::<T>(1);
170
171 let instruction = Instruction::SetHints {
172 hints: BoundedVec::<Hint, HintNumVariants>::truncate_from(vec![AssetClaimer {
173 location: sender_location.clone(),
174 }]),
175 };
176
177 let xcm = Xcm(vec![instruction]);
178 #[block]
179 {
180 executor.bench_process(xcm)?;
181 }
182 assert_eq!(executor.asset_claimer(), Some(sender_location.clone()));
183
184 Ok(())
185 }
186
187 #[benchmark]
188 fn query_response() -> Result<(), BenchmarkError> {
189 let mut executor = new_executor::<T>(Default::default());
190 let (query_id, response) = T::worst_case_response();
191 let max_weight = Weight::MAX;
192 let querier: Option<Location> = Some(Here.into());
193 let instruction = Instruction::QueryResponse { query_id, response, max_weight, querier };
194 let xcm = Xcm(vec![instruction]);
195
196 #[block]
197 {
198 executor.bench_process(xcm)?;
199 }
200 Ok(())
203 }
204
205 #[benchmark]
209 fn transact() -> Result<(), BenchmarkError> {
210 let (origin, noop_call) = T::transact_origin_and_runtime_call()?;
211 let mut executor = new_executor::<T>(origin);
212 let double_encoded_noop_call: DoubleEncoded<_> = noop_call.encode().into();
213
214 let instruction = Instruction::Transact {
215 origin_kind: OriginKind::SovereignAccount,
216 call: double_encoded_noop_call,
217 fallback_max_weight: None,
218 };
219 let xcm = Xcm(vec![instruction]);
220 #[block]
221 {
222 executor.bench_process(xcm)?;
223 }
224 Ok(())
227 }
228
229 #[benchmark]
230 fn refund_surplus() -> Result<(), BenchmarkError> {
231 let mut executor = new_executor::<T>(Default::default());
232 let holding_assets = T::worst_case_holding(1);
233 let (asset_for_fees, _): (Asset, WeightLimit) = T::worst_case_for_trader().unwrap();
235
236 let previous_xcm = Xcm(vec![BuyExecution {
237 fees: asset_for_fees,
238 weight_limit: Limited(Weight::from_parts(1337, 1337)),
239 }]);
240 executor.set_holding(holding_assets);
241 executor.set_total_surplus(Weight::from_parts(1337, 1337));
242 executor.set_total_refunded(Weight::zero());
243 executor
244 .bench_process(previous_xcm)
245 .expect("Holding has been loaded, so we can buy execution here");
246
247 let instruction = Instruction::<XcmCallOf<T>>::RefundSurplus;
248 let xcm = Xcm(vec![instruction]);
249 #[block]
250 {
251 let _result = executor.bench_process(xcm)?;
252 }
253 assert_eq!(executor.total_surplus(), &Weight::from_parts(1337, 1337));
254 assert_eq!(executor.total_refunded(), &Weight::from_parts(1337, 1337));
255
256 Ok(())
257 }
258
259 #[benchmark]
260 fn set_error_handler() -> Result<(), BenchmarkError> {
261 let mut executor = new_executor::<T>(Default::default());
262 let instruction = Instruction::<XcmCallOf<T>>::SetErrorHandler(Xcm(vec![]));
263 let xcm = Xcm(vec![instruction]);
264 #[block]
265 {
266 executor.bench_process(xcm)?;
267 }
268 assert_eq!(executor.error_handler(), &Xcm(vec![]));
269
270 Ok(())
271 }
272
273 #[benchmark]
274 fn set_appendix() -> Result<(), BenchmarkError> {
275 let mut executor = new_executor::<T>(Default::default());
276 let appendix = Xcm(vec![]);
277 let instruction = Instruction::<XcmCallOf<T>>::SetAppendix(appendix);
278 let xcm = Xcm(vec![instruction]);
279 #[block]
280 {
281 executor.bench_process(xcm)?;
282 }
283 assert_eq!(executor.appendix(), &Xcm(vec![]));
284 Ok(())
285 }
286
287 #[benchmark]
288 fn clear_error() -> Result<(), BenchmarkError> {
289 let mut executor = new_executor::<T>(Default::default());
290 executor.set_error(Some((5u32, XcmError::Overflow)));
291 let instruction = Instruction::<XcmCallOf<T>>::ClearError;
292 let xcm = Xcm(vec![instruction]);
293 #[block]
294 {
295 executor.bench_process(xcm)?;
296 }
297 assert!(executor.error().is_none());
298 Ok(())
299 }
300
301 #[benchmark]
302 fn descend_origin() -> Result<(), BenchmarkError> {
303 let mut executor = new_executor::<T>(Default::default());
304 let who = Junctions::from([OnlyChild, OnlyChild]);
305 let instruction = Instruction::DescendOrigin(who.clone());
306 let xcm = Xcm(vec![instruction]);
307 #[block]
308 {
309 executor.bench_process(xcm)?;
310 }
311 assert_eq!(executor.origin(), &Some(Location { parents: 0, interior: who }),);
312
313 Ok(())
314 }
315
316 #[benchmark]
317 fn execute_with_origin() -> Result<(), BenchmarkError> {
318 let mut executor = new_executor::<T>(Default::default());
319 let who: Junctions = Junctions::from([AccountId32 { id: [0u8; 32], network: None }]);
320 let instruction = Instruction::ExecuteWithOrigin {
321 descendant_origin: Some(who.clone()),
322 xcm: Xcm(vec![]),
323 };
324 let xcm = Xcm(vec![instruction]);
325 #[block]
326 {
327 executor
328 .bench_process(xcm)
329 .map_err(|_| BenchmarkError::Override(BenchmarkResult::from_weight(Weight::MAX)))?;
330 }
331 assert_eq!(executor.origin(), &Some(Location { parents: 0, interior: Here }),);
332
333 Ok(())
334 }
335
336 #[benchmark]
337 fn clear_origin() -> Result<(), BenchmarkError> {
338 let mut executor = new_executor::<T>(Default::default());
339 let instruction = Instruction::ClearOrigin;
340 let xcm = Xcm(vec![instruction]);
341 #[block]
342 {
343 executor.bench_process(xcm)?;
344 }
345 assert_eq!(executor.origin(), &None);
346 Ok(())
347 }
348
349 #[benchmark]
350 fn report_error() -> Result<(), BenchmarkError> {
351 let (sender_account, sender_location) = account_and_location::<T>(1);
352 let query_id = Default::default();
353 let max_weight = Default::default();
354 let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
355
356 let (expected_fees_mode, expected_assets_in_holding) =
357 T::DeliveryHelper::ensure_successful_delivery(
358 &sender_location,
359 &destination,
360 FeeReason::Report,
361 );
362 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
363
364 let mut executor = new_executor::<T>(sender_location);
365 if let Some(expected_fees_mode) = expected_fees_mode {
366 executor.set_fees_mode(expected_fees_mode);
367 }
368 if let Some(expected_assets_in_holding) = expected_assets_in_holding {
369 executor.set_holding(assets_to_holding::<T>(&expected_assets_in_holding).unwrap());
370 }
371 executor.set_error(Some((0u32, XcmError::Unimplemented)));
372
373 let instruction =
374 Instruction::ReportError(QueryResponseInfo { query_id, destination, max_weight });
375 let xcm = Xcm(vec![instruction]);
376 #[block]
377 {
378 executor.bench_process(xcm)?;
379 }
380 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
382
383 Ok(())
384 }
385
386 #[benchmark]
387 fn claim_asset() -> Result<(), BenchmarkError> {
388 use xcm_executor::traits::DropAssets;
389
390 let (origin, ticket, assets) = T::claimable_asset()?;
391
392 let context = XcmContext { origin: Some(origin.clone()), message_id: [0; 32], topic: None };
394 <T::XcmConfig as xcm_executor::Config>::AssetTrap::drop_assets(
395 &origin,
396 assets_to_holding::<T>(&assets).unwrap(),
397 &context,
398 );
399
400 let mut executor = new_executor::<T>(origin);
403 let instruction = Instruction::ClaimAsset { assets: assets.clone(), ticket };
404 let xcm = Xcm(vec![instruction]);
405 #[block]
406 {
407 executor.bench_process(xcm)?;
408 }
409 assert!(executor.holding().ensure_contains(&assets).is_ok());
410 Ok(())
411 }
412
413 #[benchmark]
414 fn trap() -> Result<(), BenchmarkError> {
415 let mut executor = new_executor::<T>(Default::default());
416 let instruction = Instruction::Trap(10);
417 let xcm = Xcm(vec![instruction]);
418 let result;
420 #[block]
421 {
422 result = executor.bench_process(xcm);
423 }
424 assert!(matches!(result, Err(ExecutorError { xcm_error: XcmError::Trap(10), .. })));
425
426 Ok(())
427 }
428
429 #[benchmark]
430 fn subscribe_version() -> Result<(), BenchmarkError> {
431 use xcm_executor::traits::VersionChangeNotifier;
432 let origin = T::subscribe_origin()?;
433 let query_id = Default::default();
434 let max_response_weight = Default::default();
435 let mut executor = new_executor::<T>(origin.clone());
436 let instruction = Instruction::SubscribeVersion { query_id, max_response_weight };
437 let xcm = Xcm(vec![instruction]);
438
439 T::DeliveryHelper::ensure_successful_delivery(&origin, &origin, FeeReason::QueryPallet);
440
441 #[block]
442 {
443 executor.bench_process(xcm)?;
444 }
445 assert!(<T::XcmConfig as xcm_executor::Config>::SubscriptionService::is_subscribed(
446 &origin
447 ));
448 Ok(())
449 }
450
451 #[benchmark]
452 fn unsubscribe_version() -> Result<(), BenchmarkError> {
453 use xcm_executor::traits::VersionChangeNotifier;
454 let (origin, _) = T::transact_origin_and_runtime_call()?;
456
457 T::DeliveryHelper::ensure_successful_delivery(&origin, &origin, FeeReason::QueryPallet);
458
459 let query_id = Default::default();
460 let max_response_weight = Default::default();
461 <T::XcmConfig as xcm_executor::Config>::SubscriptionService::start(
462 &origin,
463 query_id,
464 max_response_weight,
465 &XcmContext { origin: Some(origin.clone()), message_id: [0; 32], topic: None },
466 )
467 .map_err(|_| "Could not start subscription")?;
468 assert!(<T::XcmConfig as xcm_executor::Config>::SubscriptionService::is_subscribed(
469 &origin
470 ));
471
472 let mut executor = new_executor::<T>(origin.clone());
473 let instruction = Instruction::UnsubscribeVersion;
474 let xcm = Xcm(vec![instruction]);
475 #[block]
476 {
477 executor.bench_process(xcm)?;
478 }
479 assert!(!<T::XcmConfig as xcm_executor::Config>::SubscriptionService::is_subscribed(
480 &origin
481 ));
482 Ok(())
483 }
484
485 #[benchmark]
486 fn burn_asset() -> Result<(), BenchmarkError> {
487 let holding = T::worst_case_holding(0);
488
489 let assets: Assets = {
491 let mut assets = Vec::new();
492 for (asset_id, imbalance) in holding.fungible.iter() {
493 assets.push(Asset { id: asset_id.clone(), fun: Fungible(imbalance.amount()) });
494 }
495 for (asset_id, instance) in holding.non_fungible.iter() {
496 assets.push(Asset { id: asset_id.clone(), fun: NonFungible(*instance) });
497 }
498 assets.into()
499 };
500
501 let mut executor = new_executor::<T>(Default::default());
502 executor.set_holding(holding);
503
504 let instruction = Instruction::BurnAsset(assets);
505 let xcm = Xcm(vec![instruction]);
506 #[block]
507 {
508 executor.bench_process(xcm)?;
509 }
510 assert!(executor.holding().is_empty());
511 Ok(())
512 }
513
514 #[benchmark]
515 fn expect_asset() -> Result<(), BenchmarkError> {
516 let holding = T::worst_case_holding(0);
517
518 let assets: Assets = {
520 let mut assets = Vec::new();
521 for (asset_id, imbalance) in holding.fungible.iter() {
522 assets.push(Asset { id: asset_id.clone(), fun: Fungible(imbalance.amount()) });
523 }
524 for (asset_id, instance) in holding.non_fungible.iter() {
525 assets.push(Asset { id: asset_id.clone(), fun: NonFungible(*instance) });
526 }
527 assets.into()
528 };
529
530 let mut executor = new_executor::<T>(Default::default());
531 executor.set_holding(holding);
532
533 let instruction = Instruction::ExpectAsset(assets);
534 let xcm = Xcm(vec![instruction]);
535 #[block]
536 {
537 executor.bench_process(xcm)?;
538 }
539 Ok(())
542 }
543
544 #[benchmark]
545 fn expect_origin() -> Result<(), BenchmarkError> {
546 let expected_origin = Parent.into();
547 let mut executor = new_executor::<T>(Default::default());
548
549 let instruction = Instruction::ExpectOrigin(Some(expected_origin));
550 let xcm = Xcm(vec![instruction]);
551 let mut _result = Ok(());
552 #[block]
553 {
554 _result = executor.bench_process(xcm);
555 }
556 assert!(matches!(
557 _result,
558 Err(ExecutorError { xcm_error: XcmError::ExpectationFalse, .. })
559 ));
560
561 Ok(())
562 }
563
564 #[benchmark]
565 fn expect_error() -> Result<(), BenchmarkError> {
566 let mut executor = new_executor::<T>(Default::default());
567 executor.set_error(Some((3u32, XcmError::Overflow)));
568
569 let instruction = Instruction::ExpectError(None);
570 let xcm = Xcm(vec![instruction]);
571 let mut _result = Ok(());
572 #[block]
573 {
574 _result = executor.bench_process(xcm);
575 }
576 assert!(matches!(
577 _result,
578 Err(ExecutorError { xcm_error: XcmError::ExpectationFalse, .. })
579 ));
580
581 Ok(())
582 }
583
584 #[benchmark]
585 fn expect_transact_status() -> Result<(), BenchmarkError> {
586 let mut executor = new_executor::<T>(Default::default());
587 let worst_error =
588 || -> MaybeErrorCode { vec![0; MaxDispatchErrorLen::get() as usize].into() };
589 executor.set_transact_status(worst_error());
590
591 let instruction = Instruction::ExpectTransactStatus(worst_error());
592 let xcm = Xcm(vec![instruction]);
593 let mut _result = Ok(());
594 #[block]
595 {
596 _result = executor.bench_process(xcm);
597 }
598 assert!(matches!(_result, Ok(..)));
599 Ok(())
600 }
601
602 #[benchmark]
603 fn query_pallet() -> Result<(), BenchmarkError> {
604 let (sender_account, sender_location) = account_and_location::<T>(1);
605 let query_id = Default::default();
606 let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
607 let max_weight = Default::default();
608
609 let (expected_fees_mode, expected_assets_in_holding) =
610 T::DeliveryHelper::ensure_successful_delivery(
611 &sender_location,
612 &destination,
613 FeeReason::QueryPallet,
614 );
615 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
616 let mut executor = new_executor::<T>(sender_location);
617 if let Some(expected_fees_mode) = expected_fees_mode {
618 executor.set_fees_mode(expected_fees_mode);
619 }
620 if let Some(expected_assets_in_holding) = expected_assets_in_holding {
621 executor.set_holding(assets_to_holding::<T>(&expected_assets_in_holding).unwrap());
622 }
623
624 let valid_pallet = T::valid_pallet();
625 let instruction = Instruction::QueryPallet {
626 module_name: valid_pallet.module_name.as_bytes().to_vec(),
627 response_info: QueryResponseInfo { destination, query_id, max_weight },
628 };
629 let xcm = Xcm(vec![instruction]);
630 #[block]
631 {
632 executor.bench_process(xcm)?;
633 }
634 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
636 Ok(())
639 }
640
641 #[benchmark]
642 fn expect_pallet() -> Result<(), BenchmarkError> {
643 let mut executor = new_executor::<T>(Default::default());
644 let valid_pallet = T::valid_pallet();
645 let instruction = Instruction::ExpectPallet {
646 index: valid_pallet.index as u32,
647 name: valid_pallet.name.as_bytes().to_vec(),
648 module_name: valid_pallet.module_name.as_bytes().to_vec(),
649 crate_major: valid_pallet.crate_version.major.into(),
650 min_crate_minor: valid_pallet.crate_version.minor.into(),
651 };
652 let xcm = Xcm(vec![instruction]);
653 #[block]
654 {
655 executor.bench_process(xcm)?;
656 }
657 Ok(())
659 }
660
661 #[benchmark]
662 fn report_transact_status() -> Result<(), BenchmarkError> {
663 let (sender_account, sender_location) = account_and_location::<T>(1);
664 let query_id = Default::default();
665 let destination = T::valid_destination().map_err(|_| BenchmarkError::Skip)?;
666 let max_weight = Default::default();
667
668 let (expected_fees_mode, expected_assets_in_holding) =
669 T::DeliveryHelper::ensure_successful_delivery(
670 &sender_location,
671 &destination,
672 FeeReason::Report,
673 );
674 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
675
676 let mut executor = new_executor::<T>(sender_location);
677 if let Some(expected_fees_mode) = expected_fees_mode {
678 executor.set_fees_mode(expected_fees_mode);
679 }
680 if let Some(expected_assets_in_holding) = expected_assets_in_holding {
681 executor.set_holding(assets_to_holding::<T>(&expected_assets_in_holding).unwrap());
682 }
683 executor.set_transact_status(b"MyError".to_vec().into());
684
685 let instruction = Instruction::ReportTransactStatus(QueryResponseInfo {
686 query_id,
687 destination,
688 max_weight,
689 });
690 let xcm = Xcm(vec![instruction]);
691 #[block]
692 {
693 executor.bench_process(xcm)?;
694 }
695 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
697 Ok(())
699 }
700
701 #[benchmark]
702 fn clear_transact_status() -> Result<(), BenchmarkError> {
703 let mut executor = new_executor::<T>(Default::default());
704 executor.set_transact_status(b"MyError".to_vec().into());
705
706 let instruction = Instruction::ClearTransactStatus;
707 let xcm = Xcm(vec![instruction]);
708 #[block]
709 {
710 executor.bench_process(xcm)?;
711 }
712 assert_eq!(executor.transact_status(), &MaybeErrorCode::Success);
713 Ok(())
714 }
715
716 #[benchmark]
717 fn set_topic() -> Result<(), BenchmarkError> {
718 let mut executor = new_executor::<T>(Default::default());
719
720 let instruction = Instruction::SetTopic([1; 32]);
721 let xcm = Xcm(vec![instruction]);
722 #[block]
723 {
724 executor.bench_process(xcm)?;
725 }
726 assert_eq!(executor.topic(), &Some([1; 32]));
727 Ok(())
728 }
729
730 #[benchmark]
731 fn clear_topic() -> Result<(), BenchmarkError> {
732 let mut executor = new_executor::<T>(Default::default());
733 executor.set_topic(Some([2; 32]));
734
735 let instruction = Instruction::ClearTopic;
736 let xcm = Xcm(vec![instruction]);
737 #[block]
738 {
739 executor.bench_process(xcm)?;
740 }
741 assert_eq!(executor.topic(), &None);
742 Ok(())
743 }
744
745 #[benchmark]
746 fn exchange_asset() -> Result<(), BenchmarkError> {
747 let (give, want) = T::worst_case_asset_exchange().map_err(|_| BenchmarkError::Skip)?;
748 let assets = give.clone();
749
750 let mut executor = new_executor::<T>(Default::default());
751 executor.set_holding(assets_to_holding::<T>(&give).unwrap());
752 let instruction =
753 Instruction::ExchangeAsset { give: assets.into(), want: want.clone(), maximal: true };
754 let xcm = Xcm(vec![instruction]);
755 #[block]
756 {
757 executor.bench_process(xcm)?;
758 }
759 assert!(executor.holding().contains_assets(&want));
760 Ok(())
761 }
762
763 #[benchmark]
764 fn universal_origin() -> Result<(), BenchmarkError> {
765 let (origin, alias) = T::universal_alias().map_err(|_| BenchmarkError::Skip)?;
766
767 let mut executor = new_executor::<T>(origin);
768
769 let instruction = Instruction::UniversalOrigin(alias);
770 let xcm = Xcm(vec![instruction]);
771 #[block]
772 {
773 executor.bench_process(xcm)?;
774 }
775 use frame_support::traits::Get;
776 let universal_location = <T::XcmConfig as xcm_executor::Config>::UniversalLocation::get();
777 assert_eq!(
778 executor.origin(),
779 &Some(Junctions::from([alias]).relative_to(&universal_location))
780 );
781
782 Ok(())
783 }
784
785 #[benchmark]
786 fn export_message(x: Linear<1, 1000>) -> Result<(), BenchmarkError> {
787 let inner_xcm = Xcm(vec![ClearOrigin; x as usize]);
793 let (origin, network, destination) = T::export_message_origin_and_destination()?;
795
796 let (expected_fees_mode, expected_assets_in_holding) =
797 T::DeliveryHelper::ensure_successful_delivery(
798 &origin,
799 &destination.clone().into(),
800 FeeReason::Export { network, destination: destination.clone() },
801 );
802 let sender_account = T::AccountIdConverter::convert_location(&origin).unwrap();
803 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
804
805 let mut executor = new_executor::<T>(origin);
806 if let Some(expected_fees_mode) = expected_fees_mode {
807 executor.set_fees_mode(expected_fees_mode);
808 }
809 if let Some(expected_assets_in_holding) = expected_assets_in_holding {
810 executor.set_holding(assets_to_holding::<T>(&expected_assets_in_holding).unwrap());
811 }
812 let xcm =
813 Xcm(vec![ExportMessage { network, destination: destination.clone(), xcm: inner_xcm }]);
814 #[block]
815 {
816 executor.bench_process(xcm)?;
817 }
818 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
820 Ok(())
822 }
823
824 #[benchmark]
825 fn set_fees_mode() -> Result<(), BenchmarkError> {
826 let mut executor = new_executor::<T>(Default::default());
827 executor.set_fees_mode(FeesMode { jit_withdraw: false });
828
829 let instruction = Instruction::SetFeesMode { jit_withdraw: true };
830 let xcm = Xcm(vec![instruction]);
831 #[block]
832 {
833 executor.bench_process(xcm)?;
834 }
835 assert_eq!(executor.fees_mode(), &FeesMode { jit_withdraw: true });
836 Ok(())
837 }
838
839 #[benchmark]
840 fn lock_asset() -> Result<(), BenchmarkError> {
841 let (unlocker, owner, asset) = T::unlockable_asset()?;
842
843 let (expected_fees_mode, expected_assets_in_holding) =
844 T::DeliveryHelper::ensure_successful_delivery(&owner, &unlocker, FeeReason::LockAsset);
845 let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap();
846 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
847
848 let mut holding: Assets = asset.clone().into();
850 if let Some(expected_assets_in_holding) = expected_assets_in_holding {
851 for a in expected_assets_in_holding.into_inner() {
852 holding.push(a);
853 }
854 };
855
856 let mut executor = new_executor::<T>(owner);
857 executor.set_holding(assets_to_holding::<T>(&holding).unwrap());
858 if let Some(expected_fees_mode) = expected_fees_mode {
859 executor.set_fees_mode(expected_fees_mode);
860 }
861
862 let instruction = Instruction::LockAsset { asset, unlocker };
863 let xcm = Xcm(vec![instruction]);
864 #[block]
865 {
866 executor.bench_process(xcm)?;
867 }
868 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
870 Ok(())
872 }
873
874 #[benchmark]
875 fn unlock_asset() -> Result<(), BenchmarkError> {
876 use xcm_executor::traits::{AssetLock, Enact};
877
878 let (unlocker, owner, asset) = T::unlockable_asset()?;
879
880 let mut executor = new_executor::<T>(unlocker.clone());
881
882 <T::XcmConfig as xcm_executor::Config>::AssetLocker::prepare_lock(
884 unlocker,
885 asset.clone(),
886 owner.clone(),
887 )
888 .map_err(|_| BenchmarkError::Skip)?
889 .enact()
890 .map_err(|_| BenchmarkError::Skip)?;
891
892 let instruction = Instruction::UnlockAsset { asset, target: owner };
894 let xcm = Xcm(vec![instruction]);
895 #[block]
896 {
897 executor.bench_process(xcm)?;
898 }
899 Ok(())
900 }
901
902 #[benchmark]
903 fn note_unlockable() -> Result<(), BenchmarkError> {
904 use xcm_executor::traits::{AssetLock, Enact};
905
906 let (unlocker, owner, asset) = T::unlockable_asset()?;
907
908 let mut executor = new_executor::<T>(unlocker.clone());
909
910 <T::XcmConfig as xcm_executor::Config>::AssetLocker::prepare_lock(
912 unlocker,
913 asset.clone(),
914 owner.clone(),
915 )
916 .map_err(|_| BenchmarkError::Skip)?
917 .enact()
918 .map_err(|_| BenchmarkError::Skip)?;
919
920 let instruction = Instruction::NoteUnlockable { asset, owner };
922 let xcm = Xcm(vec![instruction]);
923 #[block]
924 {
925 executor.bench_process(xcm)?;
926 }
927 Ok(())
928 }
929
930 #[benchmark]
931 fn request_unlock() -> Result<(), BenchmarkError> {
932 use xcm_executor::traits::{AssetLock, Enact};
933
934 let (locker, owner, asset) = T::unlockable_asset()?;
935
936 <T::XcmConfig as xcm_executor::Config>::AssetLocker::prepare_lock(
938 locker.clone(),
939 asset.clone(),
940 owner.clone(),
941 )
942 .map_err(|_| BenchmarkError::Skip)?
943 .enact()
944 .map_err(|_| BenchmarkError::Skip)?;
945
946 let (expected_fees_mode, expected_assets_in_holding) =
947 T::DeliveryHelper::ensure_successful_delivery(
948 &owner,
949 &locker,
950 FeeReason::RequestUnlock,
951 );
952 let sender_account = T::AccountIdConverter::convert_location(&owner).unwrap();
953 let sender_account_balance_before = T::TransactAsset::balance(&sender_account);
954
955 let mut executor = new_executor::<T>(owner);
957 if let Some(expected_fees_mode) = expected_fees_mode {
958 executor.set_fees_mode(expected_fees_mode);
959 }
960 if let Some(expected_assets_in_holding) = expected_assets_in_holding {
961 executor.set_holding(assets_to_holding::<T>(&expected_assets_in_holding).unwrap());
962 }
963 let instruction = Instruction::RequestUnlock { asset, locker };
964 let xcm = Xcm(vec![instruction]);
965 #[block]
966 {
967 executor.bench_process(xcm)?;
968 }
969 assert!(T::TransactAsset::balance(&sender_account) <= sender_account_balance_before);
971 Ok(())
973 }
974
975 #[benchmark]
976 fn unpaid_execution() -> Result<(), BenchmarkError> {
977 let mut executor = new_executor::<T>(Default::default());
978 executor.set_origin(Some(Here.into()));
979
980 let instruction = Instruction::<XcmCallOf<T>>::UnpaidExecution {
981 weight_limit: WeightLimit::Unlimited,
982 check_origin: Some(Here.into()),
983 };
984
985 let xcm = Xcm(vec![instruction]);
986 #[block]
987 {
988 executor.bench_process(xcm)?;
989 }
990 Ok(())
991 }
992
993 #[benchmark]
994 fn alias_origin() -> Result<(), BenchmarkError> {
995 let (origin, target) = T::alias_origin().map_err(|_| BenchmarkError::Skip)?;
996
997 let mut executor = new_executor::<T>(origin);
998
999 let instruction = Instruction::AliasOrigin(target.clone());
1000 let xcm = Xcm(vec![instruction]);
1001 #[block]
1002 {
1003 executor.bench_process(xcm)?;
1004 }
1005 assert_eq!(executor.origin(), &Some(target));
1006 Ok(())
1007 }
1008
1009 impl_benchmark_test_suite!(
1010 Pallet,
1011 crate::generic::mock::new_test_ext(),
1012 crate::generic::mock::Test
1013 );
1014}