referrerpolicy=no-referrer-when-downgrade

polkadot_runtime_common/assigned_slots/
mod.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! This pallet allows to assign permanent (long-lived) or temporary
18//! (short-lived) parachain slots to paras, leveraging the existing
19//! parachain slot lease mechanism. Temporary slots are given turns
20//! in a fair (though best-effort) manner.
21//! The dispatchables must be called from the configured origin
22//! (typically `Sudo` or a governance origin).
23//! This pallet should not be used on a production relay chain,
24//! only on a test relay chain (e.g. Rococo).
25
26pub mod benchmarking;
27pub mod migration;
28
29use crate::{
30	slots::{self, Pallet as Slots, WeightInfo as SlotsWeightInfo},
31	traits::{LeaseError, Leaser, Registrar},
32};
33use alloc::vec::Vec;
34use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
35use frame_support::{pallet_prelude::*, traits::Currency};
36use frame_system::pallet_prelude::*;
37pub use pallet::*;
38use polkadot_primitives::Id as ParaId;
39use polkadot_runtime_parachains::{
40	configuration,
41	paras::{self},
42};
43use scale_info::TypeInfo;
44use sp_runtime::traits::{One, Saturating, Zero};
45
46const LOG_TARGET: &str = "runtime::assigned_slots";
47
48/// Lease period an assigned slot should start from (current, or next one).
49#[derive(
50	Encode, Decode, DecodeWithMemTracking, Clone, Copy, Eq, PartialEq, RuntimeDebug, TypeInfo,
51)]
52pub enum SlotLeasePeriodStart {
53	Current,
54	Next,
55}
56
57/// Information about a temporary parachain slot.
58#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, MaxEncodedLen, RuntimeDebug, TypeInfo)]
59pub struct ParachainTemporarySlot<AccountId, LeasePeriod> {
60	/// Manager account of the para.
61	pub manager: AccountId,
62	/// Lease period the parachain slot should ideally start from,
63	/// As slot are allocated in a best-effort manner, this could be later,
64	/// but not earlier than the specified period.
65	pub period_begin: LeasePeriod,
66	/// Number of lease period the slot lease will last.
67	/// This is set to the value configured in `TemporarySlotLeasePeriodLength`.
68	pub period_count: LeasePeriod,
69	/// Last lease period this slot had a turn in (incl. current).
70	/// This is set to the beginning period of a slot.
71	pub last_lease: Option<LeasePeriod>,
72	/// Number of leases this temporary slot had (incl. current).
73	pub lease_count: u32,
74}
75
76pub trait WeightInfo {
77	fn assign_perm_parachain_slot() -> Weight;
78	fn assign_temp_parachain_slot() -> Weight;
79	fn unassign_parachain_slot() -> Weight;
80	fn set_max_permanent_slots() -> Weight;
81	fn set_max_temporary_slots() -> Weight;
82}
83
84pub struct TestWeightInfo;
85impl WeightInfo for TestWeightInfo {
86	fn assign_perm_parachain_slot() -> Weight {
87		Weight::zero()
88	}
89	fn assign_temp_parachain_slot() -> Weight {
90		Weight::zero()
91	}
92	fn unassign_parachain_slot() -> Weight {
93		Weight::zero()
94	}
95	fn set_max_permanent_slots() -> Weight {
96		Weight::zero()
97	}
98	fn set_max_temporary_slots() -> Weight {
99		Weight::zero()
100	}
101}
102
103type BalanceOf<T> = <<<T as Config>::Leaser as Leaser<BlockNumberFor<T>>>::Currency as Currency<
104	<T as frame_system::Config>::AccountId,
105>>::Balance;
106type LeasePeriodOf<T> = <<T as Config>::Leaser as Leaser<BlockNumberFor<T>>>::LeasePeriod;
107
108#[frame_support::pallet]
109pub mod pallet {
110	use super::*;
111
112	/// The in-code storage version.
113	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
114
115	#[pallet::pallet]
116	#[pallet::storage_version(STORAGE_VERSION)]
117	pub struct Pallet<T>(_);
118
119	#[pallet::config]
120	#[pallet::disable_frame_system_supertrait_check]
121	pub trait Config: configuration::Config + paras::Config + slots::Config {
122		/// The overarching event type.
123		#[allow(deprecated)]
124		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
125
126		/// Origin for assigning slots.
127		type AssignSlotOrigin: EnsureOrigin<<Self as frame_system::Config>::RuntimeOrigin>;
128
129		/// The type representing the leasing system.
130		type Leaser: Leaser<
131			BlockNumberFor<Self>,
132			AccountId = Self::AccountId,
133			LeasePeriod = BlockNumberFor<Self>,
134		>;
135
136		/// The number of lease periods a permanent parachain slot lasts.
137		#[pallet::constant]
138		type PermanentSlotLeasePeriodLength: Get<u32>;
139
140		/// The number of lease periods a temporary parachain slot lasts.
141		#[pallet::constant]
142		type TemporarySlotLeasePeriodLength: Get<u32>;
143
144		/// The max number of temporary slots to be scheduled per lease periods.
145		#[pallet::constant]
146		type MaxTemporarySlotPerLeasePeriod: Get<u32>;
147
148		/// Weight Information for the Extrinsics in the Pallet
149		type WeightInfo: WeightInfo;
150	}
151
152	/// Assigned permanent slots, with their start lease period, and duration.
153	#[pallet::storage]
154	pub type PermanentSlots<T: Config> =
155		StorageMap<_, Twox64Concat, ParaId, (LeasePeriodOf<T>, LeasePeriodOf<T>), OptionQuery>;
156
157	/// Number of assigned (and active) permanent slots.
158	#[pallet::storage]
159	pub type PermanentSlotCount<T: Config> = StorageValue<_, u32, ValueQuery>;
160
161	/// Assigned temporary slots.
162	#[pallet::storage]
163	pub type TemporarySlots<T: Config> = StorageMap<
164		_,
165		Twox64Concat,
166		ParaId,
167		ParachainTemporarySlot<T::AccountId, LeasePeriodOf<T>>,
168		OptionQuery,
169	>;
170
171	/// Number of assigned temporary slots.
172	#[pallet::storage]
173	pub type TemporarySlotCount<T: Config> = StorageValue<_, u32, ValueQuery>;
174
175	/// Number of active temporary slots in current slot lease period.
176	#[pallet::storage]
177	pub type ActiveTemporarySlotCount<T: Config> = StorageValue<_, u32, ValueQuery>;
178
179	///  The max number of temporary slots that can be assigned.
180	#[pallet::storage]
181	pub type MaxTemporarySlots<T: Config> = StorageValue<_, u32, ValueQuery>;
182
183	/// The max number of permanent slots that can be assigned.
184	#[pallet::storage]
185	pub type MaxPermanentSlots<T: Config> = StorageValue<_, u32, ValueQuery>;
186
187	#[pallet::genesis_config]
188	#[derive(frame_support::DefaultNoBound)]
189	pub struct GenesisConfig<T: Config> {
190		pub max_temporary_slots: u32,
191		pub max_permanent_slots: u32,
192		#[serde(skip)]
193		pub _config: PhantomData<T>,
194	}
195
196	#[pallet::genesis_build]
197	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
198		fn build(&self) {
199			MaxPermanentSlots::<T>::put(&self.max_permanent_slots);
200			MaxTemporarySlots::<T>::put(&self.max_temporary_slots);
201		}
202	}
203
204	#[pallet::event]
205	#[pallet::generate_deposit(pub(super) fn deposit_event)]
206	pub enum Event<T: Config> {
207		/// A parachain was assigned a permanent parachain slot
208		PermanentSlotAssigned(ParaId),
209		/// A parachain was assigned a temporary parachain slot
210		TemporarySlotAssigned(ParaId),
211		/// The maximum number of permanent slots has been changed
212		MaxPermanentSlotsChanged { slots: u32 },
213		/// The maximum number of temporary slots has been changed
214		MaxTemporarySlotsChanged { slots: u32 },
215	}
216
217	#[pallet::error]
218	pub enum Error<T> {
219		/// The specified parachain is not registered.
220		ParaDoesntExist,
221		/// Not a parathread (on-demand parachain).
222		NotParathread,
223		/// Cannot upgrade on-demand parachain to lease holding
224		/// parachain.
225		CannotUpgrade,
226		/// Cannot downgrade lease holding parachain to
227		/// on-demand.
228		CannotDowngrade,
229		/// Permanent or Temporary slot already assigned.
230		SlotAlreadyAssigned,
231		/// Permanent or Temporary slot has not been assigned.
232		SlotNotAssigned,
233		/// An ongoing lease already exists.
234		OngoingLeaseExists,
235		// The maximum number of permanent slots exceeded
236		MaxPermanentSlotsExceeded,
237		// The maximum number of temporary slots exceeded
238		MaxTemporarySlotsExceeded,
239	}
240
241	#[pallet::hooks]
242	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
243		fn on_initialize(n: BlockNumberFor<T>) -> Weight {
244			if let Some((lease_period, first_block)) = Self::lease_period_index(n) {
245				// If we're beginning a new lease period then handle that.
246				if first_block {
247					return Self::manage_lease_period_start(lease_period)
248				}
249			}
250
251			// We didn't return early above, so we didn't do anything.
252			Weight::zero()
253		}
254	}
255
256	#[pallet::call]
257	impl<T: Config> Pallet<T> {
258		/// Assign a permanent parachain slot and immediately create a lease for it.
259		#[pallet::call_index(0)]
260		#[pallet::weight((<T as Config>::WeightInfo::assign_perm_parachain_slot(), DispatchClass::Operational))]
261		pub fn assign_perm_parachain_slot(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
262			T::AssignSlotOrigin::ensure_origin(origin)?;
263
264			let manager = T::Registrar::manager_of(id).ok_or(Error::<T>::ParaDoesntExist)?;
265
266			ensure!(T::Registrar::is_parathread(id), Error::<T>::NotParathread);
267
268			ensure!(
269				!Self::has_permanent_slot(id) && !Self::has_temporary_slot(id),
270				Error::<T>::SlotAlreadyAssigned
271			);
272
273			let current_lease_period: BlockNumberFor<T> = Self::current_lease_period_index();
274			ensure!(
275				!T::Leaser::already_leased(
276					id,
277					current_lease_period,
278					// Check current lease & next one
279					current_lease_period.saturating_add(
280						BlockNumberFor::<T>::from(2u32)
281							.saturating_mul(T::PermanentSlotLeasePeriodLength::get().into())
282					)
283				),
284				Error::<T>::OngoingLeaseExists
285			);
286
287			ensure!(
288				PermanentSlotCount::<T>::get() < MaxPermanentSlots::<T>::get(),
289				Error::<T>::MaxPermanentSlotsExceeded
290			);
291
292			// Permanent slot assignment fails if a lease cannot be created
293			Self::configure_slot_lease(
294				id,
295				manager,
296				current_lease_period,
297				T::PermanentSlotLeasePeriodLength::get().into(),
298			)
299			.map_err(|_| Error::<T>::CannotUpgrade)?;
300
301			PermanentSlots::<T>::insert(
302				id,
303				(
304					current_lease_period,
305					LeasePeriodOf::<T>::from(T::PermanentSlotLeasePeriodLength::get()),
306				),
307			);
308			PermanentSlotCount::<T>::mutate(|count| count.saturating_inc());
309
310			Self::deposit_event(Event::<T>::PermanentSlotAssigned(id));
311			Ok(())
312		}
313
314		/// Assign a temporary parachain slot. The function tries to create a lease for it
315		/// immediately if `SlotLeasePeriodStart::Current` is specified, and if the number
316		/// of currently active temporary slots is below `MaxTemporarySlotPerLeasePeriod`.
317		#[pallet::call_index(1)]
318		#[pallet::weight((<T as Config>::WeightInfo::assign_temp_parachain_slot(), DispatchClass::Operational))]
319		pub fn assign_temp_parachain_slot(
320			origin: OriginFor<T>,
321			id: ParaId,
322			lease_period_start: SlotLeasePeriodStart,
323		) -> DispatchResult {
324			T::AssignSlotOrigin::ensure_origin(origin)?;
325
326			let manager = T::Registrar::manager_of(id).ok_or(Error::<T>::ParaDoesntExist)?;
327
328			ensure!(T::Registrar::is_parathread(id), Error::<T>::NotParathread);
329
330			ensure!(
331				!Self::has_permanent_slot(id) && !Self::has_temporary_slot(id),
332				Error::<T>::SlotAlreadyAssigned
333			);
334
335			let current_lease_period: BlockNumberFor<T> = Self::current_lease_period_index();
336			ensure!(
337				!T::Leaser::already_leased(
338					id,
339					current_lease_period,
340					// Check current lease & next one
341					current_lease_period.saturating_add(
342						BlockNumberFor::<T>::from(2u32)
343							.saturating_mul(T::TemporarySlotLeasePeriodLength::get().into())
344					)
345				),
346				Error::<T>::OngoingLeaseExists
347			);
348
349			ensure!(
350				TemporarySlotCount::<T>::get() < MaxTemporarySlots::<T>::get(),
351				Error::<T>::MaxTemporarySlotsExceeded
352			);
353
354			let mut temp_slot = ParachainTemporarySlot {
355				manager: manager.clone(),
356				period_begin: match lease_period_start {
357					SlotLeasePeriodStart::Current => current_lease_period,
358					SlotLeasePeriodStart::Next => current_lease_period + One::one(),
359				},
360				period_count: T::TemporarySlotLeasePeriodLength::get().into(),
361				last_lease: None,
362				lease_count: 0,
363			};
364
365			if lease_period_start == SlotLeasePeriodStart::Current &&
366				ActiveTemporarySlotCount::<T>::get() < T::MaxTemporarySlotPerLeasePeriod::get()
367			{
368				// Try to allocate slot directly
369				match Self::configure_slot_lease(
370					id,
371					manager,
372					temp_slot.period_begin,
373					temp_slot.period_count,
374				) {
375					Ok(_) => {
376						ActiveTemporarySlotCount::<T>::mutate(|count| count.saturating_inc());
377						temp_slot.last_lease = Some(temp_slot.period_begin);
378						temp_slot.lease_count += 1;
379					},
380					Err(err) => {
381						// Treat failed lease creation as warning .. slot will be allocated a lease
382						// in a subsequent lease period by the `allocate_temporary_slot_leases`
383						// function.
384						log::warn!(
385							target: LOG_TARGET,
386							"Failed to allocate a temp slot for para {:?} at period {:?}: {:?}",
387							id,
388							current_lease_period,
389							err
390						);
391					},
392				}
393			}
394
395			TemporarySlots::<T>::insert(id, temp_slot);
396			TemporarySlotCount::<T>::mutate(|count| count.saturating_inc());
397
398			Self::deposit_event(Event::<T>::TemporarySlotAssigned(id));
399
400			Ok(())
401		}
402
403		/// Unassign a permanent or temporary parachain slot
404		#[pallet::call_index(2)]
405		#[pallet::weight((<T as Config>::WeightInfo::unassign_parachain_slot(), DispatchClass::Operational))]
406		pub fn unassign_parachain_slot(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
407			T::AssignSlotOrigin::ensure_origin(origin.clone())?;
408
409			ensure!(
410				Self::has_permanent_slot(id) || Self::has_temporary_slot(id),
411				Error::<T>::SlotNotAssigned
412			);
413
414			// Check & cache para status before we clear the lease
415			let is_parachain = Self::is_parachain(id);
416
417			// Remove perm or temp slot
418			Self::clear_slot_leases(origin.clone(), id)?;
419
420			if PermanentSlots::<T>::contains_key(id) {
421				PermanentSlots::<T>::remove(id);
422				PermanentSlotCount::<T>::mutate(|count| *count = count.saturating_sub(One::one()));
423			} else if TemporarySlots::<T>::contains_key(id) {
424				TemporarySlots::<T>::remove(id);
425				TemporarySlotCount::<T>::mutate(|count| *count = count.saturating_sub(One::one()));
426				if is_parachain {
427					ActiveTemporarySlotCount::<T>::mutate(|active_count| {
428						*active_count = active_count.saturating_sub(One::one())
429					});
430				}
431			}
432
433			// Force downgrade to on-demand parachain (if needed) before end of lease period
434			if is_parachain {
435				if let Err(err) = polkadot_runtime_parachains::schedule_parachain_downgrade::<T>(id)
436				{
437					// Treat failed downgrade as warning .. slot lease has been cleared,
438					// so the parachain will be downgraded anyway by the slots pallet
439					// at the end of the lease period .
440					log::warn!(
441						target: LOG_TARGET,
442						"Failed to downgrade parachain {:?} at period {:?}: {:?}",
443						id,
444						Self::current_lease_period_index(),
445						err
446					);
447				}
448			}
449
450			Ok(())
451		}
452
453		/// Sets the storage value [`MaxPermanentSlots`].
454		#[pallet::call_index(3)]
455		#[pallet::weight((<T as Config>::WeightInfo::set_max_permanent_slots(), DispatchClass::Operational))]
456		pub fn set_max_permanent_slots(origin: OriginFor<T>, slots: u32) -> DispatchResult {
457			ensure_root(origin)?;
458
459			MaxPermanentSlots::<T>::put(slots);
460
461			Self::deposit_event(Event::<T>::MaxPermanentSlotsChanged { slots });
462			Ok(())
463		}
464
465		/// Sets the storage value [`MaxTemporarySlots`].
466		#[pallet::call_index(4)]
467		#[pallet::weight((<T as Config>::WeightInfo::set_max_temporary_slots(), DispatchClass::Operational))]
468		pub fn set_max_temporary_slots(origin: OriginFor<T>, slots: u32) -> DispatchResult {
469			ensure_root(origin)?;
470
471			MaxTemporarySlots::<T>::put(slots);
472
473			Self::deposit_event(Event::<T>::MaxTemporarySlotsChanged { slots });
474			Ok(())
475		}
476	}
477}
478
479impl<T: Config> Pallet<T> {
480	/// Allocate temporary slot leases up to `MaxTemporarySlotPerLeasePeriod` per lease period.
481	/// Beyond the already active temporary slot leases, this function will activate more leases
482	/// in the following order of preference:
483	/// - Assigned slots that didn't have a turn yet, though their `period_begin` has passed.
484	/// - Assigned slots that already had one (or more) turn(s): they will be considered for the
485	/// current slot lease if they weren't active in the preceding one, and will be ranked by
486	/// total number of lease (lower first), and then when they last a turn (older ones first).
487	/// If any remaining ex-aequo, we just take the para ID in ascending order as discriminator.
488	///
489	/// Assigned slots with a `period_begin` bigger than current lease period are not considered
490	/// (yet).
491	///
492	/// The function will call out to `Leaser::lease_out` to create the appropriate slot leases.
493	fn allocate_temporary_slot_leases(lease_period_index: LeasePeriodOf<T>) -> DispatchResult {
494		let mut active_temp_slots = 0u32;
495		let mut pending_temp_slots = Vec::new();
496		TemporarySlots::<T>::iter().for_each(|(para, slot)| {
497				match slot.last_lease {
498					Some(last_lease)
499						if last_lease <= lease_period_index &&
500							lease_period_index <
501								(last_lease.saturating_add(slot.period_count)) =>
502					{
503						// Active slot lease
504						active_temp_slots += 1;
505					}
506					Some(last_lease)
507						// Slot w/ past lease, only consider it every other slot lease period (times period_count)
508						if last_lease.saturating_add(slot.period_count.saturating_mul(2u32.into())) <= lease_period_index => {
509							pending_temp_slots.push((para, slot));
510					},
511					None if slot.period_begin <= lease_period_index => {
512						// Slot hasn't had a lease yet
513						pending_temp_slots.insert(0, (para, slot));
514					},
515					_ => {
516						// Slot not being considered for this lease period (will be for a subsequent one)
517					},
518				}
519		});
520
521		let mut newly_created_lease = 0u32;
522		if active_temp_slots < T::MaxTemporarySlotPerLeasePeriod::get() &&
523			!pending_temp_slots.is_empty()
524		{
525			// Sort by lease_count, favoring slots that had no or less turns first
526			// (then by last_lease index, and then Para ID)
527			pending_temp_slots.sort_by(|a, b| {
528				a.1.lease_count
529					.cmp(&b.1.lease_count)
530					.then_with(|| a.1.last_lease.cmp(&b.1.last_lease))
531					.then_with(|| a.0.cmp(&b.0))
532			});
533
534			let slots_to_be_upgraded = pending_temp_slots.iter().take(
535				(T::MaxTemporarySlotPerLeasePeriod::get().saturating_sub(active_temp_slots))
536					as usize,
537			);
538
539			for (id, temp_slot) in slots_to_be_upgraded {
540				TemporarySlots::<T>::try_mutate::<_, _, Error<T>, _>(id, |s| {
541					// Configure temp slot lease
542					Self::configure_slot_lease(
543						*id,
544						temp_slot.manager.clone(),
545						lease_period_index,
546						temp_slot.period_count,
547					)
548					.map_err(|_| Error::<T>::CannotUpgrade)?;
549
550					// Update temp slot lease info in storage
551					*s = Some(ParachainTemporarySlot {
552						manager: temp_slot.manager.clone(),
553						period_begin: temp_slot.period_begin,
554						period_count: temp_slot.period_count,
555						last_lease: Some(lease_period_index),
556						lease_count: temp_slot.lease_count + 1,
557					});
558
559					newly_created_lease += 1;
560
561					Ok(())
562				})?;
563			}
564		}
565
566		ActiveTemporarySlotCount::<T>::set(active_temp_slots + newly_created_lease);
567
568		Ok(())
569	}
570
571	/// Clear out all slot leases for both permanent & temporary slots.
572	/// The function merely calls out to `Slots::clear_all_leases`.
573	fn clear_slot_leases(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
574		Slots::<T>::clear_all_leases(origin, id)
575	}
576
577	/// Create a parachain slot lease based on given params.
578	/// The function merely calls out to `Leaser::lease_out`.
579	fn configure_slot_lease(
580		para: ParaId,
581		manager: T::AccountId,
582		lease_period: LeasePeriodOf<T>,
583		lease_duration: LeasePeriodOf<T>,
584	) -> Result<(), LeaseError> {
585		T::Leaser::lease_out(para, &manager, BalanceOf::<T>::zero(), lease_period, lease_duration)
586	}
587
588	/// Returns whether a para has been assigned a permanent slot.
589	fn has_permanent_slot(id: ParaId) -> bool {
590		PermanentSlots::<T>::contains_key(id)
591	}
592
593	/// Returns whether a para has been assigned temporary slot.
594	fn has_temporary_slot(id: ParaId) -> bool {
595		TemporarySlots::<T>::contains_key(id)
596	}
597
598	/// Returns whether a para is currently a lease holding parachain.
599	fn is_parachain(id: ParaId) -> bool {
600		T::Registrar::is_parachain(id)
601	}
602
603	/// Returns current lease period index.
604	fn current_lease_period_index() -> LeasePeriodOf<T> {
605		T::Leaser::lease_period_index(frame_system::Pallet::<T>::block_number())
606			.and_then(|x| Some(x.0))
607			.unwrap()
608	}
609
610	/// Returns lease period index for block
611	fn lease_period_index(block: BlockNumberFor<T>) -> Option<(LeasePeriodOf<T>, bool)> {
612		T::Leaser::lease_period_index(block)
613	}
614
615	/// Handles start of a lease period.
616	fn manage_lease_period_start(lease_period_index: LeasePeriodOf<T>) -> Weight {
617		// Note: leases that have ended in previous lease period, should have been cleaned in slots
618		// pallet.
619		if let Err(err) = Self::allocate_temporary_slot_leases(lease_period_index) {
620			log::error!(
621				target: LOG_TARGET,
622				"Allocating slots failed for lease period {:?}, with: {:?}",
623				lease_period_index,
624				err
625			);
626		}
627		<T as slots::Config>::WeightInfo::force_lease() *
628			(T::MaxTemporarySlotPerLeasePeriod::get() as u64)
629	}
630}
631
632/// tests for this pallet
633#[cfg(test)]
634mod tests {
635	use super::*;
636
637	use crate::{assigned_slots, mock::TestRegistrar, slots};
638	use frame_support::{assert_noop, assert_ok, derive_impl, parameter_types};
639	use frame_system::EnsureRoot;
640	use pallet_balances;
641	use polkadot_primitives::BlockNumber;
642	use polkadot_primitives_test_helpers::{dummy_head_data, dummy_validation_code};
643	use polkadot_runtime_parachains::{
644		configuration as parachains_configuration, paras as parachains_paras,
645		shared as parachains_shared,
646	};
647	use sp_core::H256;
648	use sp_runtime::{
649		traits::{BlakeTwo256, IdentityLookup},
650		transaction_validity::TransactionPriority,
651		BuildStorage,
652		DispatchError::BadOrigin,
653	};
654
655	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
656	type Block = frame_system::mocking::MockBlockU32<Test>;
657
658	frame_support::construct_runtime!(
659		pub enum Test
660		{
661			System: frame_system,
662			Balances: pallet_balances,
663			Configuration: parachains_configuration,
664			ParasShared: parachains_shared,
665			Parachains: parachains_paras,
666			Slots: slots,
667			AssignedSlots: assigned_slots,
668		}
669	);
670
671	impl<C> frame_system::offchain::CreateTransactionBase<C> for Test
672	where
673		RuntimeCall: From<C>,
674	{
675		type Extrinsic = UncheckedExtrinsic;
676		type RuntimeCall = RuntimeCall;
677	}
678
679	impl<C> frame_system::offchain::CreateBare<C> for Test
680	where
681		RuntimeCall: From<C>,
682	{
683		fn create_bare(call: Self::RuntimeCall) -> Self::Extrinsic {
684			UncheckedExtrinsic::new_bare(call)
685		}
686	}
687
688	#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
689	impl frame_system::Config for Test {
690		type BaseCallFilter = frame_support::traits::Everything;
691		type BlockWeights = ();
692		type BlockLength = ();
693		type RuntimeOrigin = RuntimeOrigin;
694		type RuntimeCall = RuntimeCall;
695		type Nonce = u64;
696		type Hash = H256;
697		type Hashing = BlakeTwo256;
698		type AccountId = u64;
699		type Lookup = IdentityLookup<Self::AccountId>;
700		type Block = Block;
701		type RuntimeEvent = RuntimeEvent;
702		type DbWeight = ();
703		type Version = ();
704		type PalletInfo = PalletInfo;
705		type AccountData = pallet_balances::AccountData<u64>;
706		type OnNewAccount = ();
707		type OnKilledAccount = ();
708		type SystemWeightInfo = ();
709		type SS58Prefix = ();
710		type OnSetCode = ();
711		type MaxConsumers = frame_support::traits::ConstU32<16>;
712	}
713
714	#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
715	impl pallet_balances::Config for Test {
716		type AccountStore = System;
717	}
718
719	impl parachains_configuration::Config for Test {
720		type WeightInfo = parachains_configuration::TestWeightInfo;
721	}
722
723	parameter_types! {
724		pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
725	}
726
727	impl parachains_paras::Config for Test {
728		type RuntimeEvent = RuntimeEvent;
729		type WeightInfo = parachains_paras::TestWeightInfo;
730		type UnsignedPriority = ParasUnsignedPriority;
731		type QueueFootprinter = ();
732		type NextSessionRotation = crate::mock::TestNextSessionRotation;
733		type OnNewHead = ();
734		type AssignCoretime = ();
735		type Fungible = Balances;
736		type CooldownRemovalMultiplier = ConstUint<1>;
737		type AuthorizeCurrentCodeOrigin = EnsureRoot<Self::AccountId>;
738	}
739
740	impl parachains_shared::Config for Test {
741		type DisabledValidators = ();
742	}
743
744	parameter_types! {
745		pub const LeasePeriod: BlockNumber = 3;
746		pub static LeaseOffset: BlockNumber = 0;
747		pub const ParaDeposit: u64 = 1;
748	}
749
750	impl slots::Config for Test {
751		type RuntimeEvent = RuntimeEvent;
752		type Currency = Balances;
753		type Registrar = TestRegistrar<Test>;
754		type LeasePeriod = LeasePeriod;
755		type LeaseOffset = LeaseOffset;
756		type ForceOrigin = EnsureRoot<Self::AccountId>;
757		type WeightInfo = crate::slots::TestWeightInfo;
758	}
759
760	parameter_types! {
761		pub const PermanentSlotLeasePeriodLength: u32 = 3;
762		pub const TemporarySlotLeasePeriodLength: u32 = 2;
763		pub const MaxTemporarySlotPerLeasePeriod: u32 = 2;
764	}
765
766	impl assigned_slots::Config for Test {
767		type RuntimeEvent = RuntimeEvent;
768		type AssignSlotOrigin = EnsureRoot<Self::AccountId>;
769		type Leaser = Slots;
770		type PermanentSlotLeasePeriodLength = PermanentSlotLeasePeriodLength;
771		type TemporarySlotLeasePeriodLength = TemporarySlotLeasePeriodLength;
772		type MaxTemporarySlotPerLeasePeriod = MaxTemporarySlotPerLeasePeriod;
773		type WeightInfo = crate::assigned_slots::TestWeightInfo;
774	}
775
776	// This function basically just builds a genesis storage key/value store according to
777	// our desired mock up.
778	pub fn new_test_ext() -> sp_io::TestExternalities {
779		let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
780		pallet_balances::GenesisConfig::<Test> {
781			balances: vec![(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)],
782			..Default::default()
783		}
784		.assimilate_storage(&mut t)
785		.unwrap();
786
787		crate::assigned_slots::GenesisConfig::<Test> {
788			max_temporary_slots: 6,
789			max_permanent_slots: 2,
790			_config: Default::default(),
791		}
792		.assimilate_storage(&mut t)
793		.unwrap();
794
795		t.into()
796	}
797
798	#[test]
799	fn basic_setup_works() {
800		new_test_ext().execute_with(|| {
801			System::run_to_block::<AllPalletsWithSystem>(1);
802			assert_eq!(AssignedSlots::current_lease_period_index(), 0);
803			assert_eq!(Slots::deposit_held(1.into(), &1), 0);
804
805			System::run_to_block::<AllPalletsWithSystem>(3);
806			assert_eq!(AssignedSlots::current_lease_period_index(), 1);
807		});
808	}
809
810	#[test]
811	fn assign_perm_slot_fails_for_unknown_para() {
812		new_test_ext().execute_with(|| {
813			System::run_to_block::<AllPalletsWithSystem>(1);
814
815			assert_noop!(
816				AssignedSlots::assign_perm_parachain_slot(
817					RuntimeOrigin::root(),
818					ParaId::from(1_u32),
819				),
820				Error::<Test>::ParaDoesntExist
821			);
822		});
823	}
824
825	#[test]
826	fn assign_perm_slot_fails_for_invalid_origin() {
827		new_test_ext().execute_with(|| {
828			System::run_to_block::<AllPalletsWithSystem>(1);
829
830			assert_noop!(
831				AssignedSlots::assign_perm_parachain_slot(
832					RuntimeOrigin::signed(1),
833					ParaId::from(1_u32),
834				),
835				BadOrigin
836			);
837		});
838	}
839
840	#[test]
841	fn assign_perm_slot_fails_when_not_parathread() {
842		new_test_ext().execute_with(|| {
843			System::run_to_block::<AllPalletsWithSystem>(1);
844
845			assert_ok!(TestRegistrar::<Test>::register(
846				1,
847				ParaId::from(1_u32),
848				dummy_head_data(),
849				dummy_validation_code(),
850			));
851			assert_ok!(TestRegistrar::<Test>::make_parachain(ParaId::from(1_u32)));
852
853			assert_noop!(
854				AssignedSlots::assign_perm_parachain_slot(
855					RuntimeOrigin::root(),
856					ParaId::from(1_u32),
857				),
858				Error::<Test>::NotParathread
859			);
860		});
861	}
862
863	#[test]
864	fn assign_perm_slot_fails_when_existing_lease() {
865		new_test_ext().execute_with(|| {
866			System::run_to_block::<AllPalletsWithSystem>(1);
867
868			assert_ok!(TestRegistrar::<Test>::register(
869				1,
870				ParaId::from(1_u32),
871				dummy_head_data(),
872				dummy_validation_code(),
873			));
874
875			// Register lease in current lease period
876			assert_ok!(Slots::lease_out(ParaId::from(1_u32), &1, 1, 1, 1));
877			// Try to assign a perm slot in current period fails
878			assert_noop!(
879				AssignedSlots::assign_perm_parachain_slot(
880					RuntimeOrigin::root(),
881					ParaId::from(1_u32),
882				),
883				Error::<Test>::OngoingLeaseExists
884			);
885
886			// Cleanup
887			assert_ok!(Slots::clear_all_leases(RuntimeOrigin::root(), 1.into()));
888
889			// Register lease for next lease period
890			assert_ok!(Slots::lease_out(ParaId::from(1_u32), &1, 1, 2, 1));
891			// Should be detected and also fail
892			assert_noop!(
893				AssignedSlots::assign_perm_parachain_slot(
894					RuntimeOrigin::root(),
895					ParaId::from(1_u32),
896				),
897				Error::<Test>::OngoingLeaseExists
898			);
899		});
900	}
901
902	#[test]
903	fn assign_perm_slot_fails_when_max_perm_slots_exceeded() {
904		new_test_ext().execute_with(|| {
905			System::run_to_block::<AllPalletsWithSystem>(1);
906
907			assert_ok!(TestRegistrar::<Test>::register(
908				1,
909				ParaId::from(1_u32),
910				dummy_head_data(),
911				dummy_validation_code(),
912			));
913
914			assert_ok!(TestRegistrar::<Test>::register(
915				2,
916				ParaId::from(2_u32),
917				dummy_head_data(),
918				dummy_validation_code(),
919			));
920
921			assert_ok!(TestRegistrar::<Test>::register(
922				3,
923				ParaId::from(3_u32),
924				dummy_head_data(),
925				dummy_validation_code(),
926			));
927
928			assert_ok!(AssignedSlots::assign_perm_parachain_slot(
929				RuntimeOrigin::root(),
930				ParaId::from(1_u32),
931			));
932			assert_ok!(AssignedSlots::assign_perm_parachain_slot(
933				RuntimeOrigin::root(),
934				ParaId::from(2_u32),
935			));
936			assert_eq!(assigned_slots::PermanentSlotCount::<Test>::get(), 2);
937
938			assert_noop!(
939				AssignedSlots::assign_perm_parachain_slot(
940					RuntimeOrigin::root(),
941					ParaId::from(3_u32),
942				),
943				Error::<Test>::MaxPermanentSlotsExceeded
944			);
945		});
946	}
947
948	#[test]
949	fn assign_perm_slot_succeeds_for_parathread() {
950		new_test_ext().execute_with(|| {
951			let mut block = 1;
952			System::run_to_block::<AllPalletsWithSystem>(block);
953			assert_ok!(TestRegistrar::<Test>::register(
954				1,
955				ParaId::from(1_u32),
956				dummy_head_data(),
957				dummy_validation_code(),
958			));
959
960			assert_eq!(assigned_slots::PermanentSlotCount::<Test>::get(), 0);
961			assert_eq!(assigned_slots::PermanentSlots::<Test>::get(ParaId::from(1_u32)), None);
962
963			assert_ok!(AssignedSlots::assign_perm_parachain_slot(
964				RuntimeOrigin::root(),
965				ParaId::from(1_u32),
966			));
967
968			// Para is a lease holding parachain for PermanentSlotLeasePeriodLength * LeasePeriod
969			// blocks
970			while block < 9 {
971				println!("block #{}", block);
972
973				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
974
975				assert_eq!(assigned_slots::PermanentSlotCount::<Test>::get(), 1);
976				assert_eq!(AssignedSlots::has_permanent_slot(ParaId::from(1_u32)), true);
977				assert_eq!(
978					assigned_slots::PermanentSlots::<Test>::get(ParaId::from(1_u32)),
979					Some((0, 3))
980				);
981
982				assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 2), true);
983
984				block += 1;
985				System::run_to_block::<AllPalletsWithSystem>(block);
986			}
987
988			// Para lease ended, downgraded back to parathread (on-demand parachain)
989			assert_eq!(TestRegistrar::<Test>::is_parathread(ParaId::from(1_u32)), true);
990			assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 5), false);
991		});
992	}
993
994	#[test]
995	fn assign_temp_slot_fails_for_unknown_para() {
996		new_test_ext().execute_with(|| {
997			System::run_to_block::<AllPalletsWithSystem>(1);
998
999			assert_noop!(
1000				AssignedSlots::assign_temp_parachain_slot(
1001					RuntimeOrigin::root(),
1002					ParaId::from(1_u32),
1003					SlotLeasePeriodStart::Current
1004				),
1005				Error::<Test>::ParaDoesntExist
1006			);
1007		});
1008	}
1009
1010	#[test]
1011	fn assign_temp_slot_fails_for_invalid_origin() {
1012		new_test_ext().execute_with(|| {
1013			System::run_to_block::<AllPalletsWithSystem>(1);
1014
1015			assert_noop!(
1016				AssignedSlots::assign_temp_parachain_slot(
1017					RuntimeOrigin::signed(1),
1018					ParaId::from(1_u32),
1019					SlotLeasePeriodStart::Current
1020				),
1021				BadOrigin
1022			);
1023		});
1024	}
1025
1026	#[test]
1027	fn assign_temp_slot_fails_when_not_parathread() {
1028		new_test_ext().execute_with(|| {
1029			System::run_to_block::<AllPalletsWithSystem>(1);
1030
1031			assert_ok!(TestRegistrar::<Test>::register(
1032				1,
1033				ParaId::from(1_u32),
1034				dummy_head_data(),
1035				dummy_validation_code(),
1036			));
1037			assert_ok!(TestRegistrar::<Test>::make_parachain(ParaId::from(1_u32)));
1038
1039			assert_noop!(
1040				AssignedSlots::assign_temp_parachain_slot(
1041					RuntimeOrigin::root(),
1042					ParaId::from(1_u32),
1043					SlotLeasePeriodStart::Current
1044				),
1045				Error::<Test>::NotParathread
1046			);
1047		});
1048	}
1049
1050	#[test]
1051	fn assign_temp_slot_fails_when_existing_lease() {
1052		new_test_ext().execute_with(|| {
1053			System::run_to_block::<AllPalletsWithSystem>(1);
1054
1055			assert_ok!(TestRegistrar::<Test>::register(
1056				1,
1057				ParaId::from(1_u32),
1058				dummy_head_data(),
1059				dummy_validation_code(),
1060			));
1061
1062			// Register lease in current lease period
1063			assert_ok!(Slots::lease_out(ParaId::from(1_u32), &1, 1, 1, 1));
1064			// Try to assign a perm slot in current period fails
1065			assert_noop!(
1066				AssignedSlots::assign_temp_parachain_slot(
1067					RuntimeOrigin::root(),
1068					ParaId::from(1_u32),
1069					SlotLeasePeriodStart::Current
1070				),
1071				Error::<Test>::OngoingLeaseExists
1072			);
1073
1074			// Cleanup
1075			assert_ok!(Slots::clear_all_leases(RuntimeOrigin::root(), 1.into()));
1076
1077			// Register lease for next lease period
1078			assert_ok!(Slots::lease_out(ParaId::from(1_u32), &1, 1, 2, 1));
1079			// Should be detected and also fail
1080			assert_noop!(
1081				AssignedSlots::assign_temp_parachain_slot(
1082					RuntimeOrigin::root(),
1083					ParaId::from(1_u32),
1084					SlotLeasePeriodStart::Current
1085				),
1086				Error::<Test>::OngoingLeaseExists
1087			);
1088		});
1089	}
1090
1091	#[test]
1092	fn assign_temp_slot_fails_when_max_temp_slots_exceeded() {
1093		new_test_ext().execute_with(|| {
1094			System::run_to_block::<AllPalletsWithSystem>(1);
1095
1096			// Register 6 paras & a temp slot for each
1097			for n in 0..=5 {
1098				assert_ok!(TestRegistrar::<Test>::register(
1099					n,
1100					ParaId::from(n as u32),
1101					dummy_head_data(),
1102					dummy_validation_code()
1103				));
1104
1105				assert_ok!(AssignedSlots::assign_temp_parachain_slot(
1106					RuntimeOrigin::root(),
1107					ParaId::from(n as u32),
1108					SlotLeasePeriodStart::Current
1109				));
1110			}
1111
1112			assert_eq!(assigned_slots::TemporarySlotCount::<Test>::get(), 6);
1113
1114			// Attempt to assign one more temp slot
1115			assert_ok!(TestRegistrar::<Test>::register(
1116				7,
1117				ParaId::from(7_u32),
1118				dummy_head_data(),
1119				dummy_validation_code(),
1120			));
1121			assert_noop!(
1122				AssignedSlots::assign_temp_parachain_slot(
1123					RuntimeOrigin::root(),
1124					ParaId::from(7_u32),
1125					SlotLeasePeriodStart::Current
1126				),
1127				Error::<Test>::MaxTemporarySlotsExceeded
1128			);
1129		});
1130	}
1131
1132	#[test]
1133	fn assign_temp_slot_succeeds_for_single_parathread() {
1134		new_test_ext().execute_with(|| {
1135			let mut block = 1;
1136			System::run_to_block::<AllPalletsWithSystem>(block);
1137			assert_ok!(TestRegistrar::<Test>::register(
1138				1,
1139				ParaId::from(1_u32),
1140				dummy_head_data(),
1141				dummy_validation_code(),
1142			));
1143
1144			assert_eq!(assigned_slots::TemporarySlots::<Test>::get(ParaId::from(1_u32)), None);
1145
1146			assert_ok!(AssignedSlots::assign_temp_parachain_slot(
1147				RuntimeOrigin::root(),
1148				ParaId::from(1_u32),
1149				SlotLeasePeriodStart::Current
1150			));
1151			assert_eq!(assigned_slots::TemporarySlotCount::<Test>::get(), 1);
1152			assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 1);
1153
1154			// Block 1-5
1155			// Para is a lease holding parachain for TemporarySlotLeasePeriodLength * LeasePeriod
1156			// blocks
1157			while block < 6 {
1158				println!("block #{}", block);
1159				println!("lease period #{}", AssignedSlots::current_lease_period_index());
1160				println!("lease {:?}", slots::Leases::<Test>::get(ParaId::from(1_u32)));
1161
1162				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
1163
1164				assert_eq!(AssignedSlots::has_temporary_slot(ParaId::from(1_u32)), true);
1165				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 1);
1166				assert_eq!(
1167					assigned_slots::TemporarySlots::<Test>::get(ParaId::from(1_u32)),
1168					Some(ParachainTemporarySlot {
1169						manager: 1,
1170						period_begin: 0,
1171						period_count: 2, // TemporarySlotLeasePeriodLength
1172						last_lease: Some(0),
1173						lease_count: 1
1174					})
1175				);
1176
1177				assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 1), true);
1178
1179				block += 1;
1180				System::run_to_block::<AllPalletsWithSystem>(block);
1181			}
1182
1183			// Block 6
1184			println!("block #{}", block);
1185			println!("lease period #{}", AssignedSlots::current_lease_period_index());
1186			println!("lease {:?}", slots::Leases::<Test>::get(ParaId::from(1_u32)));
1187
1188			// Para lease ended, downgraded back to on-demand parachain
1189			assert_eq!(TestRegistrar::<Test>::is_parathread(ParaId::from(1_u32)), true);
1190			assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 3), false);
1191			assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 0);
1192
1193			// Block 12
1194			// Para should get a turn after TemporarySlotLeasePeriodLength * LeasePeriod blocks
1195			System::run_to_block::<AllPalletsWithSystem>(12);
1196			println!("block #{}", block);
1197			println!("lease period #{}", AssignedSlots::current_lease_period_index());
1198			println!("lease {:?}", slots::Leases::<Test>::get(ParaId::from(1_u32)));
1199
1200			assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
1201			assert_eq!(Slots::already_leased(ParaId::from(1_u32), 4, 5), true);
1202			assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 1);
1203		});
1204	}
1205
1206	#[test]
1207	fn assign_temp_slot_succeeds_for_multiple_parathreads() {
1208		new_test_ext().execute_with(|| {
1209			// Block 1, Period 0
1210			System::run_to_block::<AllPalletsWithSystem>(1);
1211
1212			// Register 6 paras & a temp slot for each
1213			// (3 slots in current lease period, 3 in the next one)
1214			for n in 0..=5 {
1215				assert_ok!(TestRegistrar::<Test>::register(
1216					n,
1217					ParaId::from(n as u32),
1218					dummy_head_data(),
1219					dummy_validation_code()
1220				));
1221
1222				assert_ok!(AssignedSlots::assign_temp_parachain_slot(
1223					RuntimeOrigin::root(),
1224					ParaId::from(n as u32),
1225					if (n % 2).is_zero() {
1226						SlotLeasePeriodStart::Current
1227					} else {
1228						SlotLeasePeriodStart::Next
1229					}
1230				));
1231			}
1232
1233			// Block 1-5, Period 0-1
1234			for n in 1..=5 {
1235				if n > 1 {
1236					System::run_to_block::<AllPalletsWithSystem>(n);
1237				}
1238				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(0)), true);
1239				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), false);
1240				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(2_u32)), true);
1241				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(3_u32)), false);
1242				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(4_u32)), false);
1243				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(5_u32)), false);
1244				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 2);
1245			}
1246
1247			// Block 6-11, Period 2-3
1248			for n in 6..=11 {
1249				System::run_to_block::<AllPalletsWithSystem>(n);
1250				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(0)), false);
1251				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
1252				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(2_u32)), false);
1253				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(3_u32)), true);
1254				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(4_u32)), false);
1255				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(5_u32)), false);
1256				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 2);
1257			}
1258
1259			// Block 12-17, Period 4-5
1260			for n in 12..=17 {
1261				System::run_to_block::<AllPalletsWithSystem>(n);
1262				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(0)), false);
1263				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), false);
1264				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(2_u32)), false);
1265				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(3_u32)), false);
1266				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(4_u32)), true);
1267				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(5_u32)), true);
1268				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 2);
1269			}
1270
1271			// Block 18-23, Period 6-7
1272			for n in 18..=23 {
1273				System::run_to_block::<AllPalletsWithSystem>(n);
1274				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(0)), true);
1275				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), false);
1276				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(2_u32)), true);
1277				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(3_u32)), false);
1278				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(4_u32)), false);
1279				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(5_u32)), false);
1280				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 2);
1281			}
1282
1283			// Block 24-29, Period 8-9
1284			for n in 24..=29 {
1285				System::run_to_block::<AllPalletsWithSystem>(n);
1286				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(0)), false);
1287				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
1288				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(2_u32)), false);
1289				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(3_u32)), true);
1290				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(4_u32)), false);
1291				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(5_u32)), false);
1292				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 2);
1293			}
1294
1295			// Block 30-35, Period 10-11
1296			for n in 30..=35 {
1297				System::run_to_block::<AllPalletsWithSystem>(n);
1298				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(0)), false);
1299				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), false);
1300				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(2_u32)), false);
1301				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(3_u32)), false);
1302				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(4_u32)), true);
1303				assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(5_u32)), true);
1304				assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 2);
1305			}
1306		});
1307	}
1308
1309	#[test]
1310	fn unassign_slot_fails_for_unknown_para() {
1311		new_test_ext().execute_with(|| {
1312			System::run_to_block::<AllPalletsWithSystem>(1);
1313
1314			assert_noop!(
1315				AssignedSlots::unassign_parachain_slot(RuntimeOrigin::root(), ParaId::from(1_u32),),
1316				Error::<Test>::SlotNotAssigned
1317			);
1318		});
1319	}
1320
1321	#[test]
1322	fn unassign_slot_fails_for_invalid_origin() {
1323		new_test_ext().execute_with(|| {
1324			System::run_to_block::<AllPalletsWithSystem>(1);
1325
1326			assert_noop!(
1327				AssignedSlots::assign_perm_parachain_slot(
1328					RuntimeOrigin::signed(1),
1329					ParaId::from(1_u32),
1330				),
1331				BadOrigin
1332			);
1333		});
1334	}
1335
1336	#[test]
1337	fn unassign_perm_slot_succeeds() {
1338		new_test_ext().execute_with(|| {
1339			System::run_to_block::<AllPalletsWithSystem>(1);
1340
1341			assert_ok!(TestRegistrar::<Test>::register(
1342				1,
1343				ParaId::from(1_u32),
1344				dummy_head_data(),
1345				dummy_validation_code(),
1346			));
1347
1348			assert_ok!(AssignedSlots::assign_perm_parachain_slot(
1349				RuntimeOrigin::root(),
1350				ParaId::from(1_u32),
1351			));
1352
1353			assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
1354
1355			assert_ok!(AssignedSlots::unassign_parachain_slot(
1356				RuntimeOrigin::root(),
1357				ParaId::from(1_u32),
1358			));
1359
1360			assert_eq!(assigned_slots::PermanentSlotCount::<Test>::get(), 0);
1361			assert_eq!(AssignedSlots::has_permanent_slot(ParaId::from(1_u32)), false);
1362			assert_eq!(assigned_slots::PermanentSlots::<Test>::get(ParaId::from(1_u32)), None);
1363
1364			assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 2), false);
1365		});
1366	}
1367
1368	#[test]
1369	fn unassign_temp_slot_succeeds() {
1370		new_test_ext().execute_with(|| {
1371			System::run_to_block::<AllPalletsWithSystem>(1);
1372
1373			assert_ok!(TestRegistrar::<Test>::register(
1374				1,
1375				ParaId::from(1_u32),
1376				dummy_head_data(),
1377				dummy_validation_code(),
1378			));
1379
1380			assert_ok!(AssignedSlots::assign_temp_parachain_slot(
1381				RuntimeOrigin::root(),
1382				ParaId::from(1_u32),
1383				SlotLeasePeriodStart::Current
1384			));
1385
1386			assert_eq!(TestRegistrar::<Test>::is_parachain(ParaId::from(1_u32)), true);
1387
1388			assert_ok!(AssignedSlots::unassign_parachain_slot(
1389				RuntimeOrigin::root(),
1390				ParaId::from(1_u32),
1391			));
1392
1393			assert_eq!(assigned_slots::TemporarySlotCount::<Test>::get(), 0);
1394			assert_eq!(assigned_slots::ActiveTemporarySlotCount::<Test>::get(), 0);
1395			assert_eq!(AssignedSlots::has_temporary_slot(ParaId::from(1_u32)), false);
1396			assert_eq!(assigned_slots::TemporarySlots::<Test>::get(ParaId::from(1_u32)), None);
1397
1398			assert_eq!(Slots::already_leased(ParaId::from(1_u32), 0, 1), false);
1399		});
1400	}
1401	#[test]
1402	fn set_max_permanent_slots_fails_for_no_root_origin() {
1403		new_test_ext().execute_with(|| {
1404			System::run_to_block::<AllPalletsWithSystem>(1);
1405
1406			assert_noop!(
1407				AssignedSlots::set_max_permanent_slots(RuntimeOrigin::signed(1), 5),
1408				BadOrigin
1409			);
1410		});
1411	}
1412	#[test]
1413	fn set_max_permanent_slots_succeeds() {
1414		new_test_ext().execute_with(|| {
1415			System::run_to_block::<AllPalletsWithSystem>(1);
1416
1417			assert_eq!(MaxPermanentSlots::<Test>::get(), 2);
1418			assert_ok!(AssignedSlots::set_max_permanent_slots(RuntimeOrigin::root(), 10),);
1419			assert_eq!(MaxPermanentSlots::<Test>::get(), 10);
1420		});
1421	}
1422
1423	#[test]
1424	fn set_max_temporary_slots_fails_for_no_root_origin() {
1425		new_test_ext().execute_with(|| {
1426			System::run_to_block::<AllPalletsWithSystem>(1);
1427
1428			assert_noop!(
1429				AssignedSlots::set_max_temporary_slots(RuntimeOrigin::signed(1), 5),
1430				BadOrigin
1431			);
1432		});
1433	}
1434	#[test]
1435	fn set_max_temporary_slots_succeeds() {
1436		new_test_ext().execute_with(|| {
1437			System::run_to_block::<AllPalletsWithSystem>(1);
1438
1439			assert_eq!(MaxTemporarySlots::<Test>::get(), 6);
1440			assert_ok!(AssignedSlots::set_max_temporary_slots(RuntimeOrigin::root(), 12),);
1441			assert_eq!(MaxTemporarySlots::<Test>::get(), 12);
1442		});
1443	}
1444}