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