referrerpolicy=no-referrer-when-downgrade

pallet_broker/
benchmarking.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18#![cfg(feature = "runtime-benchmarks")]
19
20use super::*;
21
22use crate::{CoreAssignment::Task, Pallet as Broker};
23use alloc::{vec, vec::Vec};
24use frame_benchmarking::v2::*;
25use frame_support::{
26	storage::bounded_vec::BoundedVec,
27	traits::{
28		fungible::{Inspect, Mutate},
29		EnsureOrigin, Hooks,
30	},
31};
32use frame_system::{Pallet as System, RawOrigin};
33use sp_arithmetic::{FixedU64, Perbill};
34use sp_core::Get;
35use sp_runtime::{
36	traits::{BlockNumberProvider, MaybeConvert},
37	FixedPointNumber, Saturating,
38};
39
40const SEED: u32 = 0;
41const MAX_CORE_COUNT: u16 = 1_000;
42
43fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
44	frame_system::Pallet::<T>::assert_last_event(generic_event.into());
45}
46
47fn assert_has_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
48	frame_system::Pallet::<T>::assert_has_event(generic_event.into());
49}
50
51fn new_config_record<T: Config>() -> ConfigRecordOf<T> {
52	ConfigRecord {
53		advance_notice: 2u32.into(),
54		interlude_length: 1u32.into(),
55		leadin_length: 1u32.into(),
56		ideal_bulk_proportion: Default::default(),
57		limit_cores_offered: None,
58		region_length: 3,
59		renewal_bump: Perbill::from_percent(10),
60		contribution_timeout: 5,
61	}
62}
63
64fn new_schedule() -> Schedule {
65	// Max items for worst case
66	let mut items = Vec::new();
67	for i in 0..CORE_MASK_BITS {
68		items.push(ScheduleItem {
69			assignment: Task(i.try_into().unwrap()),
70			mask: CoreMask::complete(),
71		});
72	}
73	Schedule::truncate_from(items)
74}
75
76fn setup_reservations<T: Config>(n: u32) {
77	let schedule = new_schedule();
78
79	Reservations::<T>::put(BoundedVec::try_from(vec![schedule.clone(); n as usize]).unwrap());
80}
81
82fn setup_leases<T: Config>(n: u32, task: u32, until: u32) {
83	Leases::<T>::put(
84		BoundedVec::try_from(vec![LeaseRecordItem { task, until: until.into() }; n as usize])
85			.unwrap(),
86	);
87}
88
89fn advance_to<T: Config>(b: u32) {
90	while System::<T>::block_number() < b.into() {
91		System::<T>::set_block_number(System::<T>::block_number().saturating_add(1u32.into()));
92
93		let block_number: u32 = System::<T>::block_number().try_into().ok().unwrap();
94
95		RCBlockNumberProviderOf::<T::Coretime>::set_block_number(block_number.into());
96		Broker::<T>::on_initialize(System::<T>::block_number());
97	}
98}
99
100struct StartedSale<Balance> {
101	start_price: Balance,
102	end_price: Balance,
103	first_core: CoreIndex,
104}
105
106fn setup_and_start_sale<T: Config>() -> Result<StartedSale<BalanceOf<T>>, BenchmarkError> {
107	Configuration::<T>::put(new_config_record::<T>());
108
109	// Assume Reservations to be filled for worst case
110	setup_reservations::<T>(T::MaxReservedCores::get());
111
112	// Assume Leases to be filled for worst case
113	setup_leases::<T>(T::MaxLeasedCores::get(), 1, 10);
114
115	let initial_price = 10_000_000u32.into();
116	let (start_price, end_price) = get_start_end_price::<T>(initial_price);
117	Broker::<T>::do_start_sales(initial_price, MAX_CORE_COUNT.into())
118		.map_err(|_| BenchmarkError::Weightless)?;
119
120	let sale_data = StartedSale {
121		start_price,
122		end_price,
123		first_core: T::MaxReservedCores::get()
124			.saturating_add(T::MaxLeasedCores::get())
125			.try_into()
126			.unwrap(),
127	};
128
129	Ok(sale_data)
130}
131
132fn get_start_end_price<T: Config>(initial_price: BalanceOf<T>) -> (BalanceOf<T>, BalanceOf<T>) {
133	let end_price = <T as Config>::PriceAdapter::adapt_price(SalePerformance {
134		sellout_price: None,
135		end_price: initial_price,
136		ideal_cores_sold: 0,
137		cores_offered: 0,
138		cores_sold: 0,
139	})
140	.end_price;
141	let start_price = <T as Config>::PriceAdapter::leadin_factor_at(FixedU64::from(0))
142		.saturating_mul_int(end_price);
143	(start_price, end_price)
144}
145
146#[benchmarks]
147mod benches {
148	use super::*;
149	use crate::Finality::*;
150
151	#[benchmark]
152	fn configure() -> Result<(), BenchmarkError> {
153		let config = new_config_record::<T>();
154
155		let origin =
156			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
157
158		#[extrinsic_call]
159		_(origin as T::RuntimeOrigin, config.clone());
160
161		assert_eq!(Configuration::<T>::get(), Some(config));
162
163		Ok(())
164	}
165
166	#[benchmark]
167	fn reserve() -> Result<(), BenchmarkError> {
168		let schedule = new_schedule();
169
170		// Assume Reservations to be almost filled for worst case
171		setup_reservations::<T>(T::MaxReservedCores::get().saturating_sub(1));
172
173		let origin =
174			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
175
176		#[extrinsic_call]
177		_(origin as T::RuntimeOrigin, schedule);
178
179		assert_eq!(Reservations::<T>::get().len(), T::MaxReservedCores::get() as usize);
180
181		Ok(())
182	}
183
184	#[benchmark]
185	fn unreserve() -> Result<(), BenchmarkError> {
186		// Assume Reservations to be filled for worst case
187		setup_reservations::<T>(T::MaxReservedCores::get());
188
189		let origin =
190			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
191
192		#[extrinsic_call]
193		_(origin as T::RuntimeOrigin, 0);
194
195		assert_eq!(
196			Reservations::<T>::get().len(),
197			T::MaxReservedCores::get().saturating_sub(1) as usize
198		);
199
200		Ok(())
201	}
202
203	#[benchmark]
204	fn set_lease() -> Result<(), BenchmarkError> {
205		let task = 1u32;
206		let until = 10u32.into();
207
208		// Assume Leases to be almost filled for worst case
209		setup_leases::<T>(T::MaxLeasedCores::get().saturating_sub(1), task, until);
210
211		let origin =
212			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
213
214		#[extrinsic_call]
215		_(origin as T::RuntimeOrigin, task, until);
216
217		assert_eq!(Leases::<T>::get().len(), T::MaxLeasedCores::get() as usize);
218
219		Ok(())
220	}
221
222	#[benchmark]
223	fn remove_lease() -> Result<(), BenchmarkError> {
224		let task = 1u32;
225		let until = 10u32;
226
227		// Assume Leases to be almost filled for worst case
228		let mut leases = vec![
229			LeaseRecordItem { task, until };
230			T::MaxLeasedCores::get().saturating_sub(1) as usize
231		];
232		let task = 2u32;
233		leases.push(LeaseRecordItem { task, until });
234		Leases::<T>::put(BoundedVec::try_from(leases).unwrap());
235
236		let origin =
237			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
238
239		#[extrinsic_call]
240		_(origin as T::RuntimeOrigin, task);
241
242		assert_eq!(Leases::<T>::get().len(), T::MaxLeasedCores::get().saturating_sub(1) as usize);
243
244		Ok(())
245	}
246
247	#[benchmark]
248	fn start_sales(n: Linear<0, { MAX_CORE_COUNT.into() }>) -> Result<(), BenchmarkError> {
249		let config = new_config_record::<T>();
250		Configuration::<T>::put(config.clone());
251
252		let mut extra_cores = n;
253
254		// Assume Reservations to be filled for worst case
255		setup_reservations::<T>(extra_cores.min(T::MaxReservedCores::get()));
256		extra_cores = extra_cores.saturating_sub(T::MaxReservedCores::get());
257
258		// Assume Leases to be filled for worst case
259		setup_leases::<T>(extra_cores.min(T::MaxLeasedCores::get()), 1, 10);
260		extra_cores = extra_cores.saturating_sub(T::MaxLeasedCores::get());
261
262		let latest_region_begin = Broker::<T>::latest_timeslice_ready_to_commit(&config);
263
264		let initial_price = 10_000_000u32.into();
265		let (start_price, end_price) = get_start_end_price::<T>(initial_price);
266		let origin =
267			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
268
269		#[extrinsic_call]
270		_(origin as T::RuntimeOrigin, initial_price, extra_cores.try_into().unwrap());
271
272		assert!(SaleInfo::<T>::get().is_some());
273		let sale_start = RCBlockNumberProviderOf::<T::Coretime>::current_block_number() +
274			config.interlude_length;
275		assert_last_event::<T>(
276			Event::SaleInitialized {
277				sale_start,
278				leadin_length: 1u32.into(),
279				start_price,
280				end_price,
281				region_begin: latest_region_begin + config.region_length,
282				region_end: latest_region_begin + config.region_length * 2,
283				ideal_cores_sold: 0,
284				cores_offered: n
285					.saturating_sub(T::MaxReservedCores::get())
286					.saturating_sub(T::MaxLeasedCores::get())
287					.try_into()
288					.unwrap(),
289				sale_index: 1u32,
290			}
291			.into(),
292		);
293
294		Ok(())
295	}
296
297	#[benchmark]
298	fn purchase() -> Result<(), BenchmarkError> {
299		let sale_data = setup_and_start_sale::<T>()?;
300
301		advance_to::<T>(2);
302
303		let caller: T::AccountId = whitelisted_caller();
304		T::Currency::set_balance(
305			&caller.clone(),
306			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
307		);
308
309		#[extrinsic_call]
310		_(RawOrigin::Signed(caller.clone()), sale_data.start_price);
311
312		assert_eq!(SaleInfo::<T>::get().unwrap().sellout_price.unwrap(), sale_data.end_price);
313		assert_last_event::<T>(
314			Event::Purchased {
315				who: caller,
316				region_id: RegionId {
317					begin: SaleInfo::<T>::get().unwrap().region_begin,
318					core: sale_data.first_core,
319					mask: CoreMask::complete(),
320				},
321				price: sale_data.end_price,
322				duration: 3u32.into(),
323			}
324			.into(),
325		);
326
327		Ok(())
328	}
329
330	#[benchmark]
331	fn renew() -> Result<(), BenchmarkError> {
332		let sale_data = setup_and_start_sale::<T>()?;
333		let region_len = Configuration::<T>::get().unwrap().region_length;
334
335		advance_to::<T>(2);
336
337		let caller: T::AccountId = whitelisted_caller();
338		T::Currency::set_balance(
339			&caller.clone(),
340			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
341		);
342
343		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
344			.expect("Offer not high enough for configuration.");
345
346		Broker::<T>::do_assign(region, None, 1001, Final)
347			.map_err(|_| BenchmarkError::Weightless)?;
348
349		advance_to::<T>((T::TimeslicePeriod::get() * region_len.into()).try_into().ok().unwrap());
350
351		#[extrinsic_call]
352		_(RawOrigin::Signed(caller), region.core);
353
354		let id = PotentialRenewalId { core: region.core, when: region.begin + region_len * 2 };
355		assert!(PotentialRenewals::<T>::get(id).is_some());
356
357		Ok(())
358	}
359
360	#[benchmark]
361	fn transfer() -> Result<(), BenchmarkError> {
362		let sale_data = setup_and_start_sale::<T>()?;
363
364		advance_to::<T>(2);
365
366		let caller: T::AccountId = whitelisted_caller();
367		T::Currency::set_balance(
368			&caller.clone(),
369			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
370		);
371
372		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
373			.expect("Offer not high enough for configuration.");
374
375		let recipient: T::AccountId = account("recipient", 0, SEED);
376
377		#[extrinsic_call]
378		_(RawOrigin::Signed(caller.clone()), region, recipient.clone());
379
380		assert_last_event::<T>(
381			Event::Transferred {
382				region_id: region,
383				old_owner: Some(caller),
384				owner: Some(recipient),
385				duration: 3u32.into(),
386			}
387			.into(),
388		);
389
390		Ok(())
391	}
392
393	#[benchmark]
394	fn partition() -> Result<(), BenchmarkError> {
395		let sale_data = setup_and_start_sale::<T>()?;
396
397		advance_to::<T>(2);
398
399		let caller: T::AccountId = whitelisted_caller();
400		T::Currency::set_balance(
401			&caller.clone(),
402			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
403		);
404
405		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
406			.expect("Offer not high enough for configuration.");
407
408		// Worst case has an existing provisional pool assignment.
409		Broker::<T>::do_pool(region, None, caller.clone(), Finality::Provisional)
410			.map_err(|_| BenchmarkError::Weightless)?;
411
412		#[extrinsic_call]
413		_(RawOrigin::Signed(caller), region, 2);
414
415		assert_last_event::<T>(
416			Event::Partitioned {
417				old_region_id: RegionId {
418					begin: region.begin,
419					core: sale_data.first_core,
420					mask: CoreMask::complete(),
421				},
422				new_region_ids: (
423					RegionId {
424						begin: region.begin,
425						core: sale_data.first_core,
426						mask: CoreMask::complete(),
427					},
428					RegionId {
429						begin: region.begin + 2,
430						core: sale_data.first_core,
431						mask: CoreMask::complete(),
432					},
433				),
434			}
435			.into(),
436		);
437
438		Ok(())
439	}
440
441	#[benchmark]
442	fn interlace() -> Result<(), BenchmarkError> {
443		let sale_data = setup_and_start_sale::<T>()?;
444		let core = sale_data.first_core;
445
446		advance_to::<T>(2);
447
448		let caller: T::AccountId = whitelisted_caller();
449		T::Currency::set_balance(
450			&caller.clone(),
451			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
452		);
453
454		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
455			.expect("Offer not high enough for configuration.");
456
457		// Worst case has an existing provisional pool assignment.
458		Broker::<T>::do_pool(region, None, caller.clone(), Finality::Provisional)
459			.map_err(|_| BenchmarkError::Weightless)?;
460
461		#[extrinsic_call]
462		_(RawOrigin::Signed(caller), region, 0x00000_fffff_fffff_00000.into());
463
464		assert_last_event::<T>(
465			Event::Interlaced {
466				old_region_id: RegionId { begin: region.begin, core, mask: CoreMask::complete() },
467				new_region_ids: (
468					RegionId { begin: region.begin, core, mask: 0x00000_fffff_fffff_00000.into() },
469					RegionId {
470						begin: region.begin,
471						core,
472						mask: CoreMask::complete() ^ 0x00000_fffff_fffff_00000.into(),
473					},
474				),
475			}
476			.into(),
477		);
478
479		Ok(())
480	}
481
482	#[benchmark]
483	fn assign() -> Result<(), BenchmarkError> {
484		let sale_data = setup_and_start_sale::<T>()?;
485		let core = sale_data.first_core;
486
487		advance_to::<T>(2);
488
489		let caller: T::AccountId = whitelisted_caller();
490		T::Currency::set_balance(
491			&caller.clone(),
492			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
493		);
494
495		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
496			.expect("Offer not high enough for configuration.");
497
498		// Worst case has an existing provisional pool assignment.
499		Broker::<T>::do_pool(region, None, caller.clone(), Finality::Provisional)
500			.map_err(|_| BenchmarkError::Weightless)?;
501
502		#[extrinsic_call]
503		_(RawOrigin::Signed(caller), region, 1000, Provisional);
504
505		let workplan_key = (region.begin, region.core);
506		assert!(Workplan::<T>::get(workplan_key).is_some());
507
508		assert!(Regions::<T>::get(region).is_some());
509
510		assert_last_event::<T>(
511			Event::Assigned {
512				region_id: RegionId { begin: region.begin, core, mask: CoreMask::complete() },
513				task: 1000,
514				duration: 3u32.into(),
515			}
516			.into(),
517		);
518
519		Ok(())
520	}
521
522	#[benchmark]
523	fn pool() -> Result<(), BenchmarkError> {
524		let sale_data = setup_and_start_sale::<T>()?;
525		let core = sale_data.first_core;
526
527		advance_to::<T>(2);
528
529		let caller: T::AccountId = whitelisted_caller();
530		T::Currency::set_balance(
531			&caller.clone(),
532			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
533		);
534
535		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
536			.expect("Offer not high enough for configuration.");
537
538		let recipient: T::AccountId = account("recipient", 0, SEED);
539
540		#[extrinsic_call]
541		_(RawOrigin::Signed(caller), region, recipient, Final);
542
543		let workplan_key = (region.begin, region.core);
544		assert!(Workplan::<T>::get(workplan_key).is_some());
545
546		assert_last_event::<T>(
547			Event::Pooled {
548				region_id: RegionId { begin: region.begin, core, mask: CoreMask::complete() },
549				duration: 3u32.into(),
550			}
551			.into(),
552		);
553
554		Ok(())
555	}
556
557	#[benchmark]
558	fn claim_revenue(
559		m: Linear<1, { new_config_record::<T>().region_length }>,
560	) -> Result<(), BenchmarkError> {
561		let sale_data = setup_and_start_sale::<T>()?;
562		let core = sale_data.first_core;
563
564		advance_to::<T>(2);
565
566		let caller: T::AccountId = whitelisted_caller();
567		T::Currency::set_balance(
568			&caller.clone(),
569			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
570		);
571		T::Currency::set_balance(
572			&Broker::<T>::account_id(),
573			T::Currency::minimum_balance().saturating_add(200_000_000u32.into()),
574		);
575
576		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
577			.expect("Offer not high enough for configuration.");
578
579		let recipient: T::AccountId = account("recipient", 0, SEED);
580		T::Currency::set_balance(&recipient.clone(), T::Currency::minimum_balance());
581
582		Broker::<T>::do_pool(region, None, recipient.clone(), Final)
583			.map_err(|_| BenchmarkError::Weightless)?;
584
585		let revenue = 10_000_000u32.into();
586		InstaPoolHistory::<T>::insert(
587			region.begin,
588			InstaPoolHistoryRecord {
589				private_contributions: 4u32.into(),
590				system_contributions: 3u32.into(),
591				maybe_payout: Some(revenue),
592			},
593		);
594
595		#[extrinsic_call]
596		_(RawOrigin::Signed(caller), region, m);
597
598		assert!(InstaPoolHistory::<T>::get(region.begin).is_none());
599		assert_last_event::<T>(
600			Event::RevenueClaimPaid {
601				who: recipient,
602				amount: 200_000_000u32.into(),
603				next: if m < new_config_record::<T>().region_length {
604					Some(RegionId {
605						begin: region.begin.saturating_add(m),
606						core,
607						mask: CoreMask::complete(),
608					})
609				} else {
610					None
611				},
612			}
613			.into(),
614		);
615
616		Ok(())
617	}
618
619	#[benchmark]
620	fn purchase_credit() -> Result<(), BenchmarkError> {
621		setup_and_start_sale::<T>()?;
622
623		advance_to::<T>(2);
624
625		let caller: T::AccountId = whitelisted_caller();
626		T::Currency::set_balance(
627			&caller.clone(),
628			T::Currency::minimum_balance().saturating_add(T::MinimumCreditPurchase::get()),
629		);
630		T::Currency::set_balance(&Broker::<T>::account_id(), T::Currency::minimum_balance());
631
632		let beneficiary: RelayAccountIdOf<T> = account("beneficiary", 0, SEED);
633
634		#[extrinsic_call]
635		_(RawOrigin::Signed(caller.clone()), T::MinimumCreditPurchase::get(), beneficiary.clone());
636
637		assert_last_event::<T>(
638			Event::CreditPurchased {
639				who: caller,
640				beneficiary,
641				amount: T::MinimumCreditPurchase::get(),
642			}
643			.into(),
644		);
645
646		Ok(())
647	}
648
649	#[benchmark]
650	fn drop_region() -> Result<(), BenchmarkError> {
651		let sale_data = setup_and_start_sale::<T>()?;
652		let core = sale_data.first_core;
653		let region_len = Configuration::<T>::get().unwrap().region_length;
654
655		advance_to::<T>(2);
656
657		let caller: T::AccountId = whitelisted_caller();
658		T::Currency::set_balance(
659			&caller.clone(),
660			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
661		);
662
663		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
664			.expect("Offer not high enough for configuration.");
665
666		advance_to::<T>(
667			(T::TimeslicePeriod::get() * (region_len * 4).into()).try_into().ok().unwrap(),
668		);
669
670		#[extrinsic_call]
671		_(RawOrigin::Signed(caller), region);
672
673		assert_last_event::<T>(
674			Event::RegionDropped {
675				region_id: RegionId { begin: region.begin, core, mask: CoreMask::complete() },
676				duration: 3u32.into(),
677			}
678			.into(),
679		);
680
681		Ok(())
682	}
683
684	#[benchmark]
685	fn drop_contribution() -> Result<(), BenchmarkError> {
686		let sale_data = setup_and_start_sale::<T>()?;
687		let core = sale_data.first_core;
688		let region_len = Configuration::<T>::get().unwrap().region_length;
689
690		advance_to::<T>(2);
691
692		let caller: T::AccountId = whitelisted_caller();
693		T::Currency::set_balance(
694			&caller.clone(),
695			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
696		);
697
698		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
699			.expect("Offer not high enough for configuration.");
700
701		let recipient: T::AccountId = account("recipient", 0, SEED);
702
703		Broker::<T>::do_pool(region, None, recipient, Final)
704			.map_err(|_| BenchmarkError::Weightless)?;
705
706		advance_to::<T>(
707			(T::TimeslicePeriod::get() * (region_len * 8).into()).try_into().ok().unwrap(),
708		);
709
710		#[extrinsic_call]
711		_(RawOrigin::Signed(caller), region);
712
713		assert_last_event::<T>(
714			Event::ContributionDropped {
715				region_id: RegionId { begin: region.begin, core, mask: CoreMask::complete() },
716			}
717			.into(),
718		);
719
720		Ok(())
721	}
722
723	#[benchmark]
724	fn drop_history() -> Result<(), BenchmarkError> {
725		setup_and_start_sale::<T>()?;
726		let when = 5u32.into();
727		let revenue = 10_000_000u32.into();
728		let region_len = Configuration::<T>::get().unwrap().region_length;
729
730		advance_to::<T>(
731			(T::TimeslicePeriod::get() * (region_len * 8).into()).try_into().ok().unwrap(),
732		);
733
734		let caller: T::AccountId = whitelisted_caller();
735		InstaPoolHistory::<T>::insert(
736			when,
737			InstaPoolHistoryRecord {
738				private_contributions: 4u32.into(),
739				system_contributions: 3u32.into(),
740				maybe_payout: Some(revenue),
741			},
742		);
743
744		#[extrinsic_call]
745		_(RawOrigin::Signed(caller), when);
746
747		assert!(InstaPoolHistory::<T>::get(when).is_none());
748		assert_last_event::<T>(Event::HistoryDropped { when, revenue }.into());
749
750		Ok(())
751	}
752
753	#[benchmark]
754	fn drop_renewal() -> Result<(), BenchmarkError> {
755		let sale_data = setup_and_start_sale::<T>()?;
756		let core = sale_data.first_core;
757		let when = 5u32.into();
758		let region_len = Configuration::<T>::get().unwrap().region_length;
759
760		advance_to::<T>(
761			(T::TimeslicePeriod::get() * (region_len * 3).into()).try_into().ok().unwrap(),
762		);
763
764		let id = PotentialRenewalId { core, when };
765		let record = PotentialRenewalRecord {
766			price: 1_000_000u32.into(),
767			completion: CompletionStatus::Complete(new_schedule()),
768		};
769		PotentialRenewals::<T>::insert(id, record);
770
771		let caller: T::AccountId = whitelisted_caller();
772
773		#[extrinsic_call]
774		_(RawOrigin::Signed(caller), core, when);
775
776		assert!(PotentialRenewals::<T>::get(id).is_none());
777		assert_last_event::<T>(Event::PotentialRenewalDropped { core, when }.into());
778
779		Ok(())
780	}
781
782	#[benchmark]
783	fn request_core_count(n: Linear<0, { MAX_CORE_COUNT.into() }>) -> Result<(), BenchmarkError> {
784		let admin_origin =
785			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
786
787		#[extrinsic_call]
788		_(admin_origin as T::RuntimeOrigin, n.try_into().unwrap());
789
790		assert_last_event::<T>(
791			Event::CoreCountRequested { core_count: n.try_into().unwrap() }.into(),
792		);
793
794		Ok(())
795	}
796
797	#[benchmark]
798	fn process_core_count(n: Linear<0, { MAX_CORE_COUNT.into() }>) -> Result<(), BenchmarkError> {
799		setup_and_start_sale::<T>()?;
800
801		let core_count = n.try_into().unwrap();
802
803		CoreCountInbox::<T>::put(core_count);
804
805		let mut status = Status::<T>::get().ok_or(BenchmarkError::Weightless)?;
806
807		#[block]
808		{
809			Broker::<T>::process_core_count(&mut status);
810		}
811
812		assert_last_event::<T>(Event::CoreCountChanged { core_count }.into());
813
814		Ok(())
815	}
816
817	#[benchmark]
818	fn process_revenue() -> Result<(), BenchmarkError> {
819		setup_and_start_sale::<T>()?;
820
821		advance_to::<T>(2);
822
823		let caller: T::AccountId = whitelisted_caller();
824		T::Currency::set_balance(
825			&caller.clone(),
826			T::Currency::minimum_balance().saturating_add(30_000_000u32.into()),
827		);
828		T::Currency::set_balance(
829			&Broker::<T>::account_id(),
830			T::Currency::minimum_balance().saturating_add(90_000_000u32.into()),
831		);
832
833		let timeslice_period: u32 = T::TimeslicePeriod::get().try_into().ok().unwrap();
834		let multiplicator = 5;
835
836		RevenueInbox::<T>::put(OnDemandRevenueRecord {
837			until: (timeslice_period * multiplicator).into(),
838			amount: 10_000_000u32.into(),
839		});
840
841		let timeslice = multiplicator - 1;
842		InstaPoolHistory::<T>::insert(
843			timeslice,
844			InstaPoolHistoryRecord {
845				private_contributions: 4u32.into(),
846				system_contributions: 6u32.into(),
847				maybe_payout: None,
848			},
849		);
850
851		#[block]
852		{
853			Broker::<T>::process_revenue();
854		}
855
856		assert_last_event::<T>(
857			Event::ClaimsReady {
858				when: timeslice.into(),
859				system_payout: 6_000_000u32.into(),
860				private_payout: 4_000_000u32.into(),
861			}
862			.into(),
863		);
864
865		Ok(())
866	}
867
868	#[benchmark]
869	fn rotate_sale(n: Linear<0, { MAX_CORE_COUNT.into() }>) -> Result<(), BenchmarkError> {
870		let config = new_config_record::<T>();
871		Configuration::<T>::put(config.clone());
872
873		// Ensure there is one buyable core then use the rest to max out reservations and leases, if
874		// possible for worst case.
875
876		// First allocate up to MaxReservedCores for reservations
877		let n_reservations = T::MaxReservedCores::get().min(n.saturating_sub(1));
878		setup_reservations::<T>(n_reservations);
879		// Then allocate remaining cores to leases, up to MaxLeasedCores
880		let n_leases =
881			T::MaxLeasedCores::get().min(n.saturating_sub(1).saturating_sub(n_reservations));
882		setup_leases::<T>(n_leases, 1, 20);
883
884		// Start sales so we can test the auto-renewals.
885		let initial_price = 10_000_000u32.into();
886		let (start_price, _) = get_start_end_price::<T>(initial_price);
887		Broker::<T>::do_start_sales(
888			initial_price,
889			n.saturating_sub(n_reservations)
890				.saturating_sub(n_leases)
891				.try_into()
892				.expect("Upper limit of n is a u16."),
893		)
894		.expect("Configuration was initialized before; qed");
895
896		// Advance to the fixed price period.
897		advance_to::<T>(2);
898
899		// Assume max auto renewals for worst case. This is between 1 and the value of
900		// MaxAutoRenewals.
901		let n_renewable = T::MaxAutoRenewals::get()
902			.min(n.saturating_sub(n_leases).saturating_sub(n_reservations));
903
904		let timeslice_period: u32 = T::TimeslicePeriod::get().try_into().ok().unwrap();
905		let sale = SaleInfo::<T>::get().expect("Sale has started.");
906
907		let now = RCBlockNumberProviderOf::<T::Coretime>::current_block_number();
908		let price = Broker::<T>::sale_price(&sale, now);
909		(0..n_renewable.into()).try_for_each(|indx| -> Result<(), BenchmarkError> {
910			let task = 1000 + indx;
911			let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(task)
912				.expect("Failed to get sovereign account");
913			T::Currency::set_balance(
914				&caller.clone(),
915				T::Currency::minimum_balance()
916					.saturating_add(start_price)
917					.saturating_add(start_price),
918			);
919
920			let region = Broker::<T>::do_purchase(caller.clone(), start_price)
921				.expect("Offer not high enough for configuration.");
922
923			Broker::<T>::do_assign(region, None, task, Final)
924				.map_err(|_| BenchmarkError::Weightless)?;
925
926			Broker::<T>::do_enable_auto_renew(caller, region.core, task, Some(sale.region_end))?;
927
928			Ok(())
929		})?;
930
931		// Advance to the block before the rotate_sale in which the auto-renewals will take place.
932		let rotate_block = timeslice_period.saturating_mul(config.region_length) - 2;
933		advance_to::<T>(rotate_block - 1);
934
935		// Advance one block and manually tick so we can isolate the `rotate_sale` call.
936		System::<T>::set_block_number(rotate_block.into());
937		RCBlockNumberProviderOf::<T::Coretime>::set_block_number(rotate_block.into());
938		let mut status = Status::<T>::get().expect("Sale has started.");
939		let sale = SaleInfo::<T>::get().expect("Sale has started.");
940		Broker::<T>::process_core_count(&mut status);
941		Broker::<T>::process_revenue();
942		status.last_committed_timeslice = config.region_length;
943
944		#[block]
945		{
946			Broker::<T>::rotate_sale(sale.clone(), &config, &status);
947		}
948
949		// Get prices from the actual price adapter.
950		let new_prices = T::PriceAdapter::adapt_price(SalePerformance::from_sale(&sale));
951		let new_sale = SaleInfo::<T>::get().expect("Sale has started.");
952		let now = RCBlockNumberProviderOf::<T::Coretime>::current_block_number();
953		let sale_start = config.interlude_length.saturating_add(rotate_block.into());
954
955		assert_has_event::<T>(
956			Event::SaleInitialized {
957				sale_start,
958				leadin_length: 1u32.into(),
959				start_price: Broker::<T>::sale_price(&new_sale, now),
960				end_price: new_prices.end_price,
961				region_begin: sale.region_begin + config.region_length,
962				region_end: sale.region_end + config.region_length,
963				ideal_cores_sold: 0,
964				cores_offered: n
965					.saturating_sub(n_reservations)
966					.saturating_sub(n_leases)
967					.try_into()
968					.unwrap(),
969				sale_index: sale.sale_index.saturating_add(1),
970			}
971			.into(),
972		);
973
974		// Make sure all cores got renewed:
975		(0..n_renewable).for_each(|indx| {
976			let task = 1000 + indx;
977			let who = T::SovereignAccountOf::maybe_convert(task)
978				.expect("Failed to get sovereign account");
979			assert_has_event::<T>(
980				Event::Renewed {
981					who,
982					old_core: n_reservations as u16 + n_leases as u16 + indx as u16,
983					core: n_reservations as u16 + n_leases as u16 + indx as u16,
984					price,
985					begin: new_sale.region_begin,
986					duration: config.region_length,
987					workload: Schedule::truncate_from(vec![ScheduleItem {
988						assignment: Task(task),
989						mask: CoreMask::complete(),
990					}]),
991				}
992				.into(),
993			);
994		});
995
996		Ok(())
997	}
998
999	#[benchmark]
1000	fn process_pool() {
1001		let when = 10u32.into();
1002		let private_pool_size = 5u32.into();
1003		let system_pool_size = 4u32.into();
1004
1005		let config = new_config_record::<T>();
1006		let commit_timeslice = Broker::<T>::latest_timeslice_ready_to_commit(&config);
1007		let mut status = StatusRecord {
1008			core_count: 5u16.into(),
1009			private_pool_size,
1010			system_pool_size,
1011			last_committed_timeslice: commit_timeslice.saturating_sub(1),
1012			last_timeslice: Broker::<T>::current_timeslice(),
1013		};
1014
1015		#[block]
1016		{
1017			Broker::<T>::process_pool(when, &mut status);
1018		}
1019
1020		assert!(InstaPoolHistory::<T>::get(when).is_some());
1021		assert_last_event::<T>(
1022			Event::HistoryInitialized { when, private_pool_size, system_pool_size }.into(),
1023		);
1024	}
1025
1026	#[benchmark]
1027	fn process_core_schedule() {
1028		let timeslice = 10u32.into();
1029		let core = 5u16.into();
1030		let rc_begin = 1u32.into();
1031
1032		Workplan::<T>::insert((timeslice, core), new_schedule());
1033
1034		#[block]
1035		{
1036			Broker::<T>::process_core_schedule(timeslice, rc_begin, core);
1037		}
1038
1039		assert_eq!(Workload::<T>::get(core).len(), CORE_MASK_BITS);
1040
1041		let mut assignment: Vec<(CoreAssignment, PartsOf57600)> = vec![];
1042		for i in 0..CORE_MASK_BITS {
1043			assignment.push((CoreAssignment::Task(i.try_into().unwrap()), 57600));
1044		}
1045		assert_last_event::<T>(Event::CoreAssigned { core, when: rc_begin, assignment }.into());
1046	}
1047
1048	#[benchmark]
1049	fn request_revenue_info_at() {
1050		let current_timeslice = Broker::<T>::current_timeslice();
1051		let rc_block = T::TimeslicePeriod::get() * current_timeslice.into();
1052
1053		#[block]
1054		{
1055			T::Coretime::request_revenue_info_at(rc_block);
1056		}
1057	}
1058
1059	#[benchmark]
1060	fn notify_core_count() -> Result<(), BenchmarkError> {
1061		let admin_origin =
1062			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1063
1064		#[extrinsic_call]
1065		_(admin_origin as T::RuntimeOrigin, 100);
1066
1067		assert!(CoreCountInbox::<T>::take().is_some());
1068		Ok(())
1069	}
1070
1071	#[benchmark]
1072	fn notify_revenue() -> Result<(), BenchmarkError> {
1073		let admin_origin =
1074			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1075
1076		#[extrinsic_call]
1077		_(
1078			admin_origin as T::RuntimeOrigin,
1079			OnDemandRevenueRecord { until: 100u32.into(), amount: 100_000_000u32.into() },
1080		);
1081
1082		assert!(RevenueInbox::<T>::take().is_some());
1083		Ok(())
1084	}
1085
1086	#[benchmark]
1087	fn do_tick_base() -> Result<(), BenchmarkError> {
1088		setup_and_start_sale::<T>()?;
1089
1090		advance_to::<T>(5);
1091
1092		let mut status = Status::<T>::get().unwrap();
1093		status.last_committed_timeslice = 3;
1094		Status::<T>::put(&status);
1095
1096		#[block]
1097		{
1098			Broker::<T>::do_tick();
1099		}
1100
1101		let updated_status = Status::<T>::get().unwrap();
1102		assert_eq!(status, updated_status);
1103
1104		Ok(())
1105	}
1106
1107	#[benchmark]
1108	fn force_reserve() -> Result<(), BenchmarkError> {
1109		Configuration::<T>::put(new_config_record::<T>());
1110		// Assume Reservations to be almost filled for worst case.
1111		let reservation_count = T::MaxReservedCores::get().saturating_sub(1);
1112		setup_reservations::<T>(reservation_count);
1113
1114		// Assume leases to be filled for worst case
1115		setup_leases::<T>(T::MaxLeasedCores::get(), 1, 10);
1116
1117		let origin =
1118			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1119
1120		// Sales must be started.
1121		Broker::<T>::do_start_sales(100u32.into(), CoreIndex::try_from(reservation_count).unwrap())
1122			.map_err(|_| BenchmarkError::Weightless)?;
1123
1124		// Add a core.
1125		let core_count = Status::<T>::get().unwrap().core_count;
1126		Broker::<T>::do_request_core_count(core_count + 1).unwrap();
1127
1128		advance_to::<T>(T::TimeslicePeriod::get().try_into().ok().unwrap());
1129
1130		let schedule = new_schedule();
1131
1132		#[extrinsic_call]
1133		_(origin as T::RuntimeOrigin, schedule.clone(), core_count);
1134
1135		assert_eq!(Reservations::<T>::decode_len().unwrap(), T::MaxReservedCores::get() as usize);
1136		assert_eq!(ForceReservations::<T>::get(), vec![schedule]);
1137
1138		Ok(())
1139	}
1140
1141	#[benchmark]
1142	fn swap_leases() -> Result<(), BenchmarkError> {
1143		let admin_origin =
1144			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1145
1146		// Add two leases in `Leases`
1147		let n = (T::MaxLeasedCores::get() / 2) as usize;
1148		let mut leases = vec![LeaseRecordItem { task: 1, until: 10u32.into() }; n];
1149		leases.extend(vec![LeaseRecordItem { task: 2, until: 20u32.into() }; n]);
1150		Leases::<T>::put(BoundedVec::try_from(leases).unwrap());
1151
1152		#[extrinsic_call]
1153		_(admin_origin as T::RuntimeOrigin, 1, 2);
1154
1155		Ok(())
1156	}
1157
1158	#[benchmark]
1159	fn enable_auto_renew() -> Result<(), BenchmarkError> {
1160		let sale_data = setup_and_start_sale::<T>()?;
1161
1162		advance_to::<T>(2);
1163
1164		let sale = SaleInfo::<T>::get().expect("Sale has already started.");
1165		// We assume max auto renewals for worst case.
1166		(0..T::MaxAutoRenewals::get() - 1).try_for_each(|indx| -> Result<(), BenchmarkError> {
1167			let task = 1000 + indx;
1168			let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(task)
1169				.expect("Failed to get sovereign account");
1170			// Sovereign account needs sufficient funds to purchase and renew.
1171			T::Currency::set_balance(
1172				&caller.clone(),
1173				T::Currency::minimum_balance().saturating_add(sale_data.start_price),
1174			);
1175
1176			let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1177				.expect("Offer not high enough for configuration.");
1178
1179			Broker::<T>::do_assign(region, None, task, Final)
1180				.map_err(|_| BenchmarkError::Weightless)?;
1181
1182			Broker::<T>::do_enable_auto_renew(caller, region.core, task, Some(sale.region_end))?;
1183
1184			Ok(())
1185		})?;
1186
1187		let caller: T::AccountId =
1188			T::SovereignAccountOf::maybe_convert(2001).expect("Failed to get sovereign account");
1189		// Sovereign account needs sufficient funds to purchase and renew.
1190		T::Currency::set_balance(
1191			&caller.clone(),
1192			T::Currency::minimum_balance()
1193				.saturating_add(sale_data.start_price.saturating_add(sale_data.start_price)),
1194		);
1195
1196		// The region for which we benchmark enable auto renew.
1197		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1198			.expect("Offer not high enough for configuration.");
1199		Broker::<T>::do_assign(region, None, 2001, Final)
1200			.map_err(|_| BenchmarkError::Weightless)?;
1201
1202		// The most 'intensive' path is when we renew the core upon enabling auto-renewal.
1203		// Therefore, we advance to next bulk sale:
1204		let timeslice_period: u32 = T::TimeslicePeriod::get().try_into().ok().unwrap();
1205		let config = Configuration::<T>::get().expect("Already configured.");
1206		advance_to::<T>(config.region_length * timeslice_period);
1207
1208		#[extrinsic_call]
1209		_(RawOrigin::Signed(caller), region.core, 2001, None);
1210
1211		assert_last_event::<T>(Event::AutoRenewalEnabled { core: region.core, task: 2001 }.into());
1212		// Make sure we indeed renewed:
1213		let sale = SaleInfo::<T>::get().expect("Sales have started.");
1214		assert!(PotentialRenewals::<T>::get(PotentialRenewalId {
1215			core: region.core,
1216			when: sale.region_end,
1217		})
1218		.is_some());
1219
1220		Ok(())
1221	}
1222
1223	#[benchmark]
1224	fn disable_auto_renew() -> Result<(), BenchmarkError> {
1225		let sale_data = setup_and_start_sale::<T>()?;
1226		let core = sale_data.first_core;
1227
1228		advance_to::<T>(2);
1229
1230		let sale = SaleInfo::<T>::get().expect("Sale has already started.");
1231		// We assume max auto renewals for worst case.
1232		(0..T::MaxAutoRenewals::get()).try_for_each(|indx| -> Result<(), BenchmarkError> {
1233			let task = 1000 + indx;
1234			let caller: T::AccountId = T::SovereignAccountOf::maybe_convert(task)
1235				.expect("Failed to get sovereign account");
1236			T::Currency::set_balance(
1237				&caller.clone(),
1238				T::Currency::minimum_balance().saturating_add(sale_data.start_price),
1239			);
1240
1241			let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1242				.expect("Offer not high enough for configuration.");
1243
1244			Broker::<T>::do_assign(region, None, task, Final)
1245				.map_err(|_| BenchmarkError::Weightless)?;
1246
1247			Broker::<T>::do_enable_auto_renew(caller, region.core, task, Some(sale.region_end))?;
1248
1249			Ok(())
1250		})?;
1251
1252		let task = 1000;
1253
1254		let caller: T::AccountId =
1255			T::SovereignAccountOf::maybe_convert(task).expect("Failed to get sovereign account");
1256
1257		#[extrinsic_call]
1258		_(RawOrigin::Signed(caller), core, task);
1259
1260		assert_last_event::<T>(Event::AutoRenewalDisabled { core, task }.into());
1261
1262		Ok(())
1263	}
1264
1265	#[benchmark]
1266	fn on_new_timeslice() -> Result<(), BenchmarkError> {
1267		let sale_data = setup_and_start_sale::<T>()?;
1268
1269		advance_to::<T>(2);
1270
1271		let caller: T::AccountId = whitelisted_caller();
1272		T::Currency::set_balance(
1273			&caller.clone(),
1274			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
1275		);
1276
1277		let _region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1278			.expect("Offer not high enough for configuration.");
1279
1280		let timeslice = Broker::<T>::current_timeslice();
1281
1282		#[block]
1283		{
1284			T::Coretime::on_new_timeslice(timeslice);
1285		}
1286
1287		Ok(())
1288	}
1289
1290	#[benchmark]
1291	fn remove_assignment() -> Result<(), BenchmarkError> {
1292		let sale_data = setup_and_start_sale::<T>()?;
1293
1294		advance_to::<T>(2);
1295
1296		let caller: T::AccountId = whitelisted_caller();
1297		T::Currency::set_balance(
1298			&caller.clone(),
1299			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
1300		);
1301
1302		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1303			.expect("Offer not high enough for configuration.");
1304
1305		Broker::<T>::do_assign(region, None, 1000, Provisional)
1306			.map_err(|_| BenchmarkError::Weightless)?;
1307
1308		let origin =
1309			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1310
1311		#[extrinsic_call]
1312		_(origin as T::RuntimeOrigin, region);
1313
1314		Ok(())
1315	}
1316
1317	#[benchmark]
1318	fn remove_potential_renewal() -> Result<(), BenchmarkError> {
1319		let sale_data = setup_and_start_sale::<T>()?;
1320		advance_to::<T>(2);
1321
1322		let caller: T::AccountId = whitelisted_caller();
1323		T::Currency::set_balance(
1324			&caller.clone(),
1325			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
1326		);
1327
1328		let region_id = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1329			.expect("Offer not high enough for configuration.");
1330		let region = Regions::<T>::get(region_id).expect("Requested region not found");
1331
1332		Broker::<T>::do_assign(region_id, None, 1000, Final)
1333			.map_err(|_| BenchmarkError::Weightless)?;
1334
1335		let origin =
1336			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1337
1338		#[extrinsic_call]
1339		_(origin as T::RuntimeOrigin, region_id.core, region.end);
1340
1341		assert_last_event::<T>(
1342			Event::PotentialRenewalRemoved { core: region_id.core, timeslice: region.end }.into(),
1343		);
1344
1345		Ok(())
1346	}
1347
1348	#[benchmark]
1349	fn force_transfer() -> Result<(), BenchmarkError> {
1350		let sale_data = setup_and_start_sale::<T>()?;
1351		advance_to::<T>(2);
1352
1353		let caller: T::AccountId = whitelisted_caller();
1354		T::Currency::set_balance(
1355			&caller.clone(),
1356			T::Currency::minimum_balance().saturating_add(sale_data.start_price),
1357		);
1358
1359		let region = Broker::<T>::do_purchase(caller.clone(), sale_data.start_price)
1360			.expect("Offer not high enough for configuration.");
1361
1362		let recipient: T::AccountId = account("recipient", 0, SEED);
1363
1364		let origin =
1365			T::AdminOrigin::try_successful_origin().map_err(|_| BenchmarkError::Weightless)?;
1366
1367		#[extrinsic_call]
1368		_(origin, region, recipient.clone());
1369
1370		assert_last_event::<T>(
1371			Event::Transferred {
1372				region_id: region,
1373				old_owner: Some(caller),
1374				owner: Some(recipient),
1375				duration: 3u32.into(),
1376			}
1377			.into(),
1378		);
1379
1380		Ok(())
1381	}
1382
1383	// Implements a test for each benchmark. Execute with:
1384	// `cargo test -p pallet-broker --features runtime-benchmarks`.
1385	impl_benchmark_test_suite!(Pallet, crate::mock::new_test_ext(), crate::mock::Test);
1386}