polkadot_runtime_common/paras_registrar/
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//! Pallet to handle parachain registration and related fund management.
18//! In essence this is a simple wrapper around `paras`.
19
20pub mod migration;
21
22use alloc::{vec, vec::Vec};
23use core::result;
24use frame_support::{
25	dispatch::DispatchResult,
26	ensure,
27	pallet_prelude::Weight,
28	traits::{Currency, Get, ReservableCurrency},
29};
30use frame_system::{self, ensure_root, ensure_signed};
31use polkadot_primitives::{
32	HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, MIN_CODE_SIZE,
33};
34use polkadot_runtime_parachains::{
35	configuration, ensure_parachain,
36	paras::{self, ParaGenesisArgs, UpgradeStrategy},
37	Origin, ParaLifecycle,
38};
39
40use crate::traits::{OnSwap, Registrar};
41use codec::{Decode, Encode};
42pub use pallet::*;
43use polkadot_runtime_parachains::paras::{OnNewHead, ParaKind};
44use scale_info::TypeInfo;
45use sp_runtime::{
46	traits::{CheckedSub, Saturating},
47	RuntimeDebug,
48};
49
50#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug, TypeInfo)]
51pub struct ParaInfo<Account, Balance> {
52	/// The account that has placed a deposit for registering this para.
53	pub(crate) manager: Account,
54	/// The amount reserved by the `manager` account for the registration.
55	deposit: Balance,
56	/// Whether the para registration should be locked from being controlled by the manager.
57	/// None means the lock had not been explicitly set, and should be treated as false.
58	locked: Option<bool>,
59}
60
61impl<Account, Balance> ParaInfo<Account, Balance> {
62	/// Returns if the para is locked.
63	pub fn is_locked(&self) -> bool {
64		self.locked.unwrap_or(false)
65	}
66}
67
68type BalanceOf<T> =
69	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
70
71pub trait WeightInfo {
72	fn reserve() -> Weight;
73	fn register() -> Weight;
74	fn force_register() -> Weight;
75	fn deregister() -> Weight;
76	fn swap() -> Weight;
77	fn schedule_code_upgrade(b: u32) -> Weight;
78	fn set_current_head(b: u32) -> Weight;
79}
80
81pub struct TestWeightInfo;
82impl WeightInfo for TestWeightInfo {
83	fn reserve() -> Weight {
84		Weight::zero()
85	}
86	fn register() -> Weight {
87		Weight::zero()
88	}
89	fn force_register() -> Weight {
90		Weight::zero()
91	}
92	fn deregister() -> Weight {
93		Weight::zero()
94	}
95	fn swap() -> Weight {
96		Weight::zero()
97	}
98	fn schedule_code_upgrade(_b: u32) -> Weight {
99		Weight::zero()
100	}
101	fn set_current_head(_b: u32) -> Weight {
102		Weight::zero()
103	}
104}
105
106#[frame_support::pallet]
107pub mod pallet {
108	use super::*;
109	use frame_support::pallet_prelude::*;
110	use frame_system::pallet_prelude::*;
111
112	/// The in-code storage version.
113	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
114
115	#[pallet::pallet]
116	#[pallet::without_storage_info]
117	#[pallet::storage_version(STORAGE_VERSION)]
118	pub struct Pallet<T>(_);
119
120	#[pallet::config]
121	#[pallet::disable_frame_system_supertrait_check]
122	pub trait Config: configuration::Config + paras::Config {
123		/// The overarching event type.
124		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
125
126		/// The aggregated origin type must support the `parachains` origin. We require that we can
127		/// infallibly convert between this origin and the system origin, but in reality, they're
128		/// the same type, we just can't express that to the Rust type system without writing a
129		/// `where` clause everywhere.
130		type RuntimeOrigin: From<<Self as frame_system::Config>::RuntimeOrigin>
131			+ Into<result::Result<Origin, <Self as Config>::RuntimeOrigin>>;
132
133		/// The system's currency for on-demand parachain payment.
134		type Currency: ReservableCurrency<Self::AccountId>;
135
136		/// Runtime hook for when a lease holding parachain and on-demand parachain swap.
137		type OnSwap: crate::traits::OnSwap;
138
139		/// The deposit to be paid to run a on-demand parachain.
140		/// This should include the cost for storing the genesis head and validation code.
141		#[pallet::constant]
142		type ParaDeposit: Get<BalanceOf<Self>>;
143
144		/// The deposit to be paid per byte stored on chain.
145		#[pallet::constant]
146		type DataDepositPerByte: Get<BalanceOf<Self>>;
147
148		/// Weight Information for the Extrinsics in the Pallet
149		type WeightInfo: WeightInfo;
150	}
151
152	#[pallet::event]
153	#[pallet::generate_deposit(pub(super) fn deposit_event)]
154	pub enum Event<T: Config> {
155		Registered { para_id: ParaId, manager: T::AccountId },
156		Deregistered { para_id: ParaId },
157		Reserved { para_id: ParaId, who: T::AccountId },
158		Swapped { para_id: ParaId, other_id: ParaId },
159	}
160
161	#[pallet::error]
162	pub enum Error<T> {
163		/// The ID is not registered.
164		NotRegistered,
165		/// The ID is already registered.
166		AlreadyRegistered,
167		/// The caller is not the owner of this Id.
168		NotOwner,
169		/// Invalid para code size.
170		CodeTooLarge,
171		/// Invalid para head data size.
172		HeadDataTooLarge,
173		/// Para is not a Parachain.
174		NotParachain,
175		/// Para is not a Parathread (on-demand parachain).
176		NotParathread,
177		/// Cannot deregister para
178		CannotDeregister,
179		/// Cannot schedule downgrade of lease holding parachain to on-demand parachain
180		CannotDowngrade,
181		/// Cannot schedule upgrade of on-demand parachain to lease holding parachain
182		CannotUpgrade,
183		/// Para is locked from manipulation by the manager. Must use parachain or relay chain
184		/// governance.
185		ParaLocked,
186		/// The ID given for registration has not been reserved.
187		NotReserved,
188		/// The validation code is invalid.
189		InvalidCode,
190		/// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras
191		/// are correct for the swap to work.
192		CannotSwap,
193	}
194
195	/// Pending swap operations.
196	#[pallet::storage]
197	pub(super) type PendingSwap<T> = StorageMap<_, Twox64Concat, ParaId, ParaId>;
198
199	/// Amount held on deposit for each para and the original depositor.
200	///
201	/// The given account ID is responsible for registering the code and initial head data, but may
202	/// only do so if it isn't yet registered. (After that, it's up to governance to do so.)
203	#[pallet::storage]
204	pub type Paras<T: Config> =
205		StorageMap<_, Twox64Concat, ParaId, ParaInfo<T::AccountId, BalanceOf<T>>>;
206
207	/// The next free `ParaId`.
208	#[pallet::storage]
209	pub type NextFreeParaId<T> = StorageValue<_, ParaId, ValueQuery>;
210
211	#[pallet::genesis_config]
212	pub struct GenesisConfig<T: Config> {
213		#[serde(skip)]
214		pub _config: core::marker::PhantomData<T>,
215		pub next_free_para_id: ParaId,
216	}
217
218	impl<T: Config> Default for GenesisConfig<T> {
219		fn default() -> Self {
220			GenesisConfig { next_free_para_id: LOWEST_PUBLIC_ID, _config: Default::default() }
221		}
222	}
223
224	#[pallet::genesis_build]
225	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
226		fn build(&self) {
227			NextFreeParaId::<T>::put(self.next_free_para_id);
228		}
229	}
230
231	#[pallet::hooks]
232	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
233
234	#[pallet::call]
235	impl<T: Config> Pallet<T> {
236		/// Register head data and validation code for a reserved Para Id.
237		///
238		/// ## Arguments
239		/// - `origin`: Must be called by a `Signed` origin.
240		/// - `id`: The para ID. Must be owned/managed by the `origin` signing account.
241		/// - `genesis_head`: The genesis head data of the parachain/thread.
242		/// - `validation_code`: The initial validation code of the parachain/thread.
243		///
244		/// ## Deposits/Fees
245		/// The account with the originating signature must reserve a deposit.
246		///
247		/// The deposit is required to cover the costs associated with storing the genesis head
248		/// data and the validation code.
249		/// This accounts for the potential to store validation code of a size up to the
250		/// `max_code_size`, as defined in the configuration pallet
251		///
252		/// Anything already reserved previously for this para ID is accounted for.
253		///
254		/// ## Events
255		/// The `Registered` event is emitted in case of success.
256		#[pallet::call_index(0)]
257		#[pallet::weight(<T as Config>::WeightInfo::register())]
258		pub fn register(
259			origin: OriginFor<T>,
260			id: ParaId,
261			genesis_head: HeadData,
262			validation_code: ValidationCode,
263		) -> DispatchResult {
264			let who = ensure_signed(origin)?;
265			Self::do_register(who, None, id, genesis_head, validation_code, true)?;
266			Ok(())
267		}
268
269		/// Force the registration of a Para Id on the relay chain.
270		///
271		/// This function must be called by a Root origin.
272		///
273		/// The deposit taken can be specified for this registration. Any `ParaId`
274		/// can be registered, including sub-1000 IDs which are System Parachains.
275		#[pallet::call_index(1)]
276		#[pallet::weight(<T as Config>::WeightInfo::force_register())]
277		pub fn force_register(
278			origin: OriginFor<T>,
279			who: T::AccountId,
280			deposit: BalanceOf<T>,
281			id: ParaId,
282			genesis_head: HeadData,
283			validation_code: ValidationCode,
284		) -> DispatchResult {
285			ensure_root(origin)?;
286			Self::do_register(who, Some(deposit), id, genesis_head, validation_code, false)
287		}
288
289		/// Deregister a Para Id, freeing all data and returning any deposit.
290		///
291		/// The caller must be Root, the `para` owner, or the `para` itself. The para must be an
292		/// on-demand parachain.
293		#[pallet::call_index(2)]
294		#[pallet::weight(<T as Config>::WeightInfo::deregister())]
295		pub fn deregister(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
296			Self::ensure_root_para_or_owner(origin, id)?;
297			Self::do_deregister(id)
298		}
299
300		/// Swap a lease holding parachain with another parachain, either on-demand or lease
301		/// holding.
302		///
303		/// The origin must be Root, the `para` owner, or the `para` itself.
304		///
305		/// The swap will happen only if there is already an opposite swap pending. If there is not,
306		/// the swap will be stored in the pending swaps map, ready for a later confirmatory swap.
307		///
308		/// The `ParaId`s remain mapped to the same head data and code so external code can rely on
309		/// `ParaId` to be a long-term identifier of a notional "parachain". However, their
310		/// scheduling info (i.e. whether they're an on-demand parachain or lease holding
311		/// parachain), auction information and the auction deposit are switched.
312		#[pallet::call_index(3)]
313		#[pallet::weight(<T as Config>::WeightInfo::swap())]
314		pub fn swap(origin: OriginFor<T>, id: ParaId, other: ParaId) -> DispatchResult {
315			Self::ensure_root_para_or_owner(origin, id)?;
316
317			// If `id` and `other` is the same id, we treat this as a "clear" function, and exit
318			// early, since swapping the same id would otherwise be a noop.
319			if id == other {
320				PendingSwap::<T>::remove(id);
321				return Ok(())
322			}
323
324			// Sanity check that `id` is even a para.
325			let id_lifecycle =
326				paras::Pallet::<T>::lifecycle(id).ok_or(Error::<T>::NotRegistered)?;
327
328			if PendingSwap::<T>::get(other) == Some(id) {
329				let other_lifecycle =
330					paras::Pallet::<T>::lifecycle(other).ok_or(Error::<T>::NotRegistered)?;
331				// identify which is a lease holding parachain and which is a parathread (on-demand
332				// parachain)
333				if id_lifecycle == ParaLifecycle::Parachain &&
334					other_lifecycle == ParaLifecycle::Parathread
335				{
336					Self::do_thread_and_chain_swap(id, other);
337				} else if id_lifecycle == ParaLifecycle::Parathread &&
338					other_lifecycle == ParaLifecycle::Parachain
339				{
340					Self::do_thread_and_chain_swap(other, id);
341				} else if id_lifecycle == ParaLifecycle::Parachain &&
342					other_lifecycle == ParaLifecycle::Parachain
343				{
344					// If both chains are currently parachains, there is nothing funny we
345					// need to do for their lifecycle management, just swap the underlying
346					// data.
347					T::OnSwap::on_swap(id, other);
348				} else {
349					return Err(Error::<T>::CannotSwap.into())
350				}
351				Self::deposit_event(Event::<T>::Swapped { para_id: id, other_id: other });
352				PendingSwap::<T>::remove(other);
353			} else {
354				PendingSwap::<T>::insert(id, other);
355			}
356
357			Ok(())
358		}
359
360		/// Remove a manager lock from a para. This will allow the manager of a
361		/// previously locked para to deregister or swap a para without using governance.
362		///
363		/// Can only be called by the Root origin or the parachain.
364		#[pallet::call_index(4)]
365		#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
366		pub fn remove_lock(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
367			Self::ensure_root_or_para(origin, para)?;
368			<Self as Registrar>::remove_lock(para);
369			Ok(())
370		}
371
372		/// Reserve a Para Id on the relay chain.
373		///
374		/// This function will reserve a new Para Id to be owned/managed by the origin account.
375		/// The origin account is able to register head data and validation code using `register` to
376		/// create an on-demand parachain. Using the Slots pallet, an on-demand parachain can then
377		/// be upgraded to a lease holding parachain.
378		///
379		/// ## Arguments
380		/// - `origin`: Must be called by a `Signed` origin. Becomes the manager/owner of the new
381		///   para ID.
382		///
383		/// ## Deposits/Fees
384		/// The origin must reserve a deposit of `ParaDeposit` for the registration.
385		///
386		/// ## Events
387		/// The `Reserved` event is emitted in case of success, which provides the ID reserved for
388		/// use.
389		#[pallet::call_index(5)]
390		#[pallet::weight(<T as Config>::WeightInfo::reserve())]
391		pub fn reserve(origin: OriginFor<T>) -> DispatchResult {
392			let who = ensure_signed(origin)?;
393			let id = NextFreeParaId::<T>::get().max(LOWEST_PUBLIC_ID);
394			Self::do_reserve(who, None, id)?;
395			NextFreeParaId::<T>::set(id + 1);
396			Ok(())
397		}
398
399		/// Add a manager lock from a para. This will prevent the manager of a
400		/// para to deregister or swap a para.
401		///
402		/// Can be called by Root, the parachain, or the parachain manager if the parachain is
403		/// unlocked.
404		#[pallet::call_index(6)]
405		#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
406		pub fn add_lock(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
407			Self::ensure_root_para_or_owner(origin, para)?;
408			<Self as Registrar>::apply_lock(para);
409			Ok(())
410		}
411
412		/// Schedule a parachain upgrade.
413		///
414		/// This will kick off a check of `new_code` by all validators. After the majority of the
415		/// validators have reported on the validity of the code, the code will either be enacted
416		/// or the upgrade will be rejected. If the code will be enacted, the current code of the
417		/// parachain will be overwritten directly. This means that any PoV will be checked by this
418		/// new code. The parachain itself will not be informed explicitly that the validation code
419		/// has changed.
420		///
421		/// Can be called by Root, the parachain, or the parachain manager if the parachain is
422		/// unlocked.
423		#[pallet::call_index(7)]
424		#[pallet::weight(<T as Config>::WeightInfo::schedule_code_upgrade(new_code.0.len() as u32))]
425		pub fn schedule_code_upgrade(
426			origin: OriginFor<T>,
427			para: ParaId,
428			new_code: ValidationCode,
429		) -> DispatchResult {
430			Self::ensure_root_para_or_owner(origin, para)?;
431			polkadot_runtime_parachains::schedule_code_upgrade::<T>(
432				para,
433				new_code,
434				UpgradeStrategy::ApplyAtExpectedBlock,
435			)?;
436			Ok(())
437		}
438
439		/// Set the parachain's current head.
440		///
441		/// Can be called by Root, the parachain, or the parachain manager if the parachain is
442		/// unlocked.
443		#[pallet::call_index(8)]
444		#[pallet::weight(<T as Config>::WeightInfo::set_current_head(new_head.0.len() as u32))]
445		pub fn set_current_head(
446			origin: OriginFor<T>,
447			para: ParaId,
448			new_head: HeadData,
449		) -> DispatchResult {
450			Self::ensure_root_para_or_owner(origin, para)?;
451			polkadot_runtime_parachains::set_current_head::<T>(para, new_head);
452			Ok(())
453		}
454	}
455}
456
457impl<T: Config> Registrar for Pallet<T> {
458	type AccountId = T::AccountId;
459
460	/// Return the manager `AccountId` of a para if one exists.
461	fn manager_of(id: ParaId) -> Option<T::AccountId> {
462		Some(Paras::<T>::get(id)?.manager)
463	}
464
465	// All lease holding parachains. Ordered ascending by ParaId. On-demand parachains are not
466	// included.
467	fn parachains() -> Vec<ParaId> {
468		paras::Parachains::<T>::get()
469	}
470
471	// Return if a para is a parathread (on-demand parachain)
472	fn is_parathread(id: ParaId) -> bool {
473		paras::Pallet::<T>::is_parathread(id)
474	}
475
476	// Return if a para is a lease holding parachain
477	fn is_parachain(id: ParaId) -> bool {
478		paras::Pallet::<T>::is_parachain(id)
479	}
480
481	// Apply a lock to the parachain.
482	fn apply_lock(id: ParaId) {
483		Paras::<T>::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(true)));
484	}
485
486	// Remove a lock from the parachain.
487	fn remove_lock(id: ParaId) {
488		Paras::<T>::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(false)));
489	}
490
491	// Register a Para ID under control of `manager`.
492	//
493	// Note this is a backend registration API, so verification of ParaId
494	// is not done here to prevent.
495	fn register(
496		manager: T::AccountId,
497		id: ParaId,
498		genesis_head: HeadData,
499		validation_code: ValidationCode,
500	) -> DispatchResult {
501		Self::do_register(manager, None, id, genesis_head, validation_code, false)
502	}
503
504	// Deregister a Para ID, free any data, and return any deposits.
505	fn deregister(id: ParaId) -> DispatchResult {
506		Self::do_deregister(id)
507	}
508
509	// Upgrade a registered on-demand parachain into a lease holding parachain.
510	fn make_parachain(id: ParaId) -> DispatchResult {
511		// Para backend should think this is an on-demand parachain...
512		ensure!(
513			paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parathread),
514			Error::<T>::NotParathread
515		);
516		polkadot_runtime_parachains::schedule_parathread_upgrade::<T>(id)
517			.map_err(|_| Error::<T>::CannotUpgrade)?;
518
519		Ok(())
520	}
521
522	// Downgrade a registered para into a parathread (on-demand parachain).
523	fn make_parathread(id: ParaId) -> DispatchResult {
524		// Para backend should think this is a parachain...
525		ensure!(
526			paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parachain),
527			Error::<T>::NotParachain
528		);
529		polkadot_runtime_parachains::schedule_parachain_downgrade::<T>(id)
530			.map_err(|_| Error::<T>::CannotDowngrade)?;
531		Ok(())
532	}
533
534	#[cfg(any(feature = "runtime-benchmarks", test))]
535	fn worst_head_data() -> HeadData {
536		let max_head_size = configuration::ActiveConfig::<T>::get().max_head_data_size;
537		assert!(max_head_size > 0, "max_head_data can't be zero for generating worst head data.");
538		vec![0u8; max_head_size as usize].into()
539	}
540
541	#[cfg(any(feature = "runtime-benchmarks", test))]
542	fn worst_validation_code() -> ValidationCode {
543		let max_code_size = configuration::ActiveConfig::<T>::get().max_code_size;
544		assert!(max_code_size > 0, "max_code_size can't be zero for generating worst code data.");
545		let validation_code = vec![0u8; max_code_size as usize];
546		validation_code.into()
547	}
548
549	#[cfg(any(feature = "runtime-benchmarks", test))]
550	fn execute_pending_transitions() {
551		use polkadot_runtime_parachains::shared;
552		shared::Pallet::<T>::set_session_index(shared::Pallet::<T>::scheduled_session());
553		paras::Pallet::<T>::test_on_new_session();
554	}
555}
556
557impl<T: Config> Pallet<T> {
558	/// Ensure the origin is one of Root, the `para` owner, or the `para` itself.
559	/// If the origin is the `para` owner, the `para` must be unlocked.
560	fn ensure_root_para_or_owner(
561		origin: <T as frame_system::Config>::RuntimeOrigin,
562		id: ParaId,
563	) -> DispatchResult {
564		ensure_signed(origin.clone())
565			.map_err(|e| e.into())
566			.and_then(|who| -> DispatchResult {
567				let para_info = Paras::<T>::get(id).ok_or(Error::<T>::NotRegistered)?;
568				ensure!(!para_info.is_locked(), Error::<T>::ParaLocked);
569				ensure!(para_info.manager == who, Error::<T>::NotOwner);
570				Ok(())
571			})
572			.or_else(|_| -> DispatchResult { Self::ensure_root_or_para(origin, id) })
573	}
574
575	/// Ensure the origin is one of Root or the `para` itself.
576	fn ensure_root_or_para(
577		origin: <T as frame_system::Config>::RuntimeOrigin,
578		id: ParaId,
579	) -> DispatchResult {
580		if let Ok(caller_id) = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin.clone()))
581		{
582			// Check if matching para id...
583			ensure!(caller_id == id, Error::<T>::NotOwner);
584		} else {
585			// Check if root...
586			ensure_root(origin.clone())?;
587		}
588		Ok(())
589	}
590
591	fn do_reserve(
592		who: T::AccountId,
593		deposit_override: Option<BalanceOf<T>>,
594		id: ParaId,
595	) -> DispatchResult {
596		ensure!(!Paras::<T>::contains_key(id), Error::<T>::AlreadyRegistered);
597		ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
598
599		let deposit = deposit_override.unwrap_or_else(T::ParaDeposit::get);
600		<T as Config>::Currency::reserve(&who, deposit)?;
601		let info = ParaInfo { manager: who.clone(), deposit, locked: None };
602
603		Paras::<T>::insert(id, info);
604		Self::deposit_event(Event::<T>::Reserved { para_id: id, who });
605		Ok(())
606	}
607
608	/// Attempt to register a new Para Id under management of `who` in the
609	/// system with the given information.
610	fn do_register(
611		who: T::AccountId,
612		deposit_override: Option<BalanceOf<T>>,
613		id: ParaId,
614		genesis_head: HeadData,
615		validation_code: ValidationCode,
616		ensure_reserved: bool,
617	) -> DispatchResult {
618		let deposited = if let Some(para_data) = Paras::<T>::get(id) {
619			ensure!(para_data.manager == who, Error::<T>::NotOwner);
620			ensure!(!para_data.is_locked(), Error::<T>::ParaLocked);
621			para_data.deposit
622		} else {
623			ensure!(!ensure_reserved, Error::<T>::NotReserved);
624			Default::default()
625		};
626		ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
627		let (genesis, deposit) =
628			Self::validate_onboarding_data(genesis_head, validation_code, ParaKind::Parathread)?;
629		let deposit = deposit_override.unwrap_or(deposit);
630
631		if let Some(additional) = deposit.checked_sub(&deposited) {
632			<T as Config>::Currency::reserve(&who, additional)?;
633		} else if let Some(rebate) = deposited.checked_sub(&deposit) {
634			<T as Config>::Currency::unreserve(&who, rebate);
635		};
636		let info = ParaInfo { manager: who.clone(), deposit, locked: None };
637
638		Paras::<T>::insert(id, info);
639		// We check above that para has no lifecycle, so this should not fail.
640		let res = polkadot_runtime_parachains::schedule_para_initialize::<T>(id, genesis);
641		debug_assert!(res.is_ok());
642		Self::deposit_event(Event::<T>::Registered { para_id: id, manager: who });
643		Ok(())
644	}
645
646	/// Deregister a Para Id, freeing all data returning any deposit.
647	fn do_deregister(id: ParaId) -> DispatchResult {
648		match paras::Pallet::<T>::lifecycle(id) {
649			// Para must be a parathread (on-demand parachain), or not exist at all.
650			Some(ParaLifecycle::Parathread) | None => {},
651			_ => return Err(Error::<T>::NotParathread.into()),
652		}
653		polkadot_runtime_parachains::schedule_para_cleanup::<T>(id)
654			.map_err(|_| Error::<T>::CannotDeregister)?;
655
656		if let Some(info) = Paras::<T>::take(&id) {
657			<T as Config>::Currency::unreserve(&info.manager, info.deposit);
658		}
659
660		PendingSwap::<T>::remove(id);
661		Self::deposit_event(Event::<T>::Deregistered { para_id: id });
662		Ok(())
663	}
664
665	/// Verifies the onboarding data is valid for a para.
666	///
667	/// Returns `ParaGenesisArgs` and the deposit needed for the data.
668	fn validate_onboarding_data(
669		genesis_head: HeadData,
670		validation_code: ValidationCode,
671		para_kind: ParaKind,
672	) -> Result<(ParaGenesisArgs, BalanceOf<T>), sp_runtime::DispatchError> {
673		let config = configuration::ActiveConfig::<T>::get();
674		ensure!(validation_code.0.len() >= MIN_CODE_SIZE as usize, Error::<T>::InvalidCode);
675		ensure!(validation_code.0.len() <= config.max_code_size as usize, Error::<T>::CodeTooLarge);
676		ensure!(
677			genesis_head.0.len() <= config.max_head_data_size as usize,
678			Error::<T>::HeadDataTooLarge
679		);
680
681		let per_byte_fee = T::DataDepositPerByte::get();
682		let deposit = T::ParaDeposit::get()
683			.saturating_add(per_byte_fee.saturating_mul((genesis_head.0.len() as u32).into()))
684			.saturating_add(per_byte_fee.saturating_mul(config.max_code_size.into()));
685
686		Ok((ParaGenesisArgs { genesis_head, validation_code, para_kind }, deposit))
687	}
688
689	/// Swap a lease holding parachain and parathread (on-demand parachain), which involves
690	/// scheduling an appropriate lifecycle update.
691	fn do_thread_and_chain_swap(to_downgrade: ParaId, to_upgrade: ParaId) {
692		let res1 = polkadot_runtime_parachains::schedule_parachain_downgrade::<T>(to_downgrade);
693		debug_assert!(res1.is_ok());
694		let res2 = polkadot_runtime_parachains::schedule_parathread_upgrade::<T>(to_upgrade);
695		debug_assert!(res2.is_ok());
696		T::OnSwap::on_swap(to_upgrade, to_downgrade);
697	}
698}
699
700impl<T: Config> OnNewHead for Pallet<T> {
701	fn on_new_head(id: ParaId, _head: &HeadData) -> Weight {
702		// mark the parachain locked if the locked value is not already set
703		let mut writes = 0;
704		if let Some(mut info) = Paras::<T>::get(id) {
705			if info.locked.is_none() {
706				info.locked = Some(true);
707				Paras::<T>::insert(id, info);
708				writes += 1;
709			}
710		}
711		T::DbWeight::get().reads_writes(1, writes)
712	}
713}
714
715#[cfg(test)]
716mod tests {
717	use super::*;
718	use crate::{
719		mock::conclude_pvf_checking, paras_registrar, traits::Registrar as RegistrarTrait,
720	};
721	use alloc::collections::btree_map::BTreeMap;
722	use frame_support::{
723		assert_noop, assert_ok, derive_impl, parameter_types,
724		traits::{OnFinalize, OnInitialize},
725	};
726	use frame_system::limits;
727	use pallet_balances::Error as BalancesError;
728	use polkadot_primitives::{Balance, BlockNumber, SessionIndex, MAX_CODE_SIZE};
729	use polkadot_runtime_parachains::{configuration, origin, shared};
730	use sp_core::H256;
731	use sp_io::TestExternalities;
732	use sp_keyring::Sr25519Keyring;
733	use sp_runtime::{
734		traits::{BadOrigin, BlakeTwo256, IdentityLookup},
735		transaction_validity::TransactionPriority,
736		BuildStorage, Perbill,
737	};
738
739	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
740	type Block = frame_system::mocking::MockBlockU32<Test>;
741
742	frame_support::construct_runtime!(
743		pub enum Test
744		{
745			System: frame_system,
746			Balances: pallet_balances,
747			Configuration: configuration,
748			Parachains: paras,
749			ParasShared: shared,
750			Registrar: paras_registrar,
751			ParachainsOrigin: origin,
752		}
753	);
754
755	impl<C> frame_system::offchain::CreateTransactionBase<C> for Test
756	where
757		RuntimeCall: From<C>,
758	{
759		type Extrinsic = UncheckedExtrinsic;
760		type RuntimeCall = RuntimeCall;
761	}
762
763	impl<C> frame_system::offchain::CreateInherent<C> for Test
764	where
765		RuntimeCall: From<C>,
766	{
767		fn create_inherent(call: Self::RuntimeCall) -> Self::Extrinsic {
768			UncheckedExtrinsic::new_bare(call)
769		}
770	}
771
772	const NORMAL_RATIO: Perbill = Perbill::from_percent(75);
773	parameter_types! {
774		pub BlockWeights: limits::BlockWeights =
775			frame_system::limits::BlockWeights::simple_max(Weight::from_parts(1024, u64::MAX));
776		pub BlockLength: limits::BlockLength =
777			limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO);
778	}
779
780	#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
781	impl frame_system::Config for Test {
782		type BaseCallFilter = frame_support::traits::Everything;
783		type RuntimeOrigin = RuntimeOrigin;
784		type RuntimeCall = RuntimeCall;
785		type Nonce = u64;
786		type Hash = H256;
787		type Hashing = BlakeTwo256;
788		type AccountId = u64;
789		type Lookup = IdentityLookup<u64>;
790		type Block = Block;
791		type RuntimeEvent = RuntimeEvent;
792		type DbWeight = ();
793		type BlockWeights = BlockWeights;
794		type BlockLength = BlockLength;
795		type Version = ();
796		type PalletInfo = PalletInfo;
797		type AccountData = pallet_balances::AccountData<u128>;
798		type OnNewAccount = ();
799		type OnKilledAccount = ();
800		type SystemWeightInfo = ();
801		type SS58Prefix = ();
802		type OnSetCode = ();
803		type MaxConsumers = frame_support::traits::ConstU32<16>;
804	}
805
806	parameter_types! {
807		pub const ExistentialDeposit: Balance = 1;
808	}
809
810	#[derive_impl(pallet_balances::config_preludes::TestDefaultConfig)]
811	impl pallet_balances::Config for Test {
812		type Balance = Balance;
813		type ExistentialDeposit = ExistentialDeposit;
814		type AccountStore = System;
815	}
816
817	impl shared::Config for Test {
818		type DisabledValidators = ();
819	}
820
821	impl origin::Config for Test {}
822
823	parameter_types! {
824		pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
825	}
826
827	impl paras::Config for Test {
828		type RuntimeEvent = RuntimeEvent;
829		type WeightInfo = paras::TestWeightInfo;
830		type UnsignedPriority = ParasUnsignedPriority;
831		type QueueFootprinter = ();
832		type NextSessionRotation = crate::mock::TestNextSessionRotation;
833		type OnNewHead = ();
834		type AssignCoretime = ();
835	}
836
837	impl configuration::Config for Test {
838		type WeightInfo = configuration::TestWeightInfo;
839	}
840
841	parameter_types! {
842		pub const ParaDeposit: Balance = 10;
843		pub const DataDepositPerByte: Balance = 1;
844		pub const MaxRetries: u32 = 3;
845	}
846
847	impl Config for Test {
848		type RuntimeOrigin = RuntimeOrigin;
849		type RuntimeEvent = RuntimeEvent;
850		type Currency = Balances;
851		type OnSwap = MockSwap;
852		type ParaDeposit = ParaDeposit;
853		type DataDepositPerByte = DataDepositPerByte;
854		type WeightInfo = TestWeightInfo;
855	}
856
857	pub fn new_test_ext() -> TestExternalities {
858		let mut t = frame_system::GenesisConfig::<Test>::default().build_storage().unwrap();
859
860		configuration::GenesisConfig::<Test> {
861			config: configuration::HostConfiguration {
862				max_code_size: MAX_CODE_SIZE,
863				max_head_data_size: 1 * 1024 * 1024, // 1 MB
864				..Default::default()
865			},
866		}
867		.assimilate_storage(&mut t)
868		.unwrap();
869
870		pallet_balances::GenesisConfig::<Test> {
871			balances: vec![(1, 10_000_000), (2, 10_000_000), (3, 10_000_000)],
872		}
873		.assimilate_storage(&mut t)
874		.unwrap();
875
876		t.into()
877	}
878
879	parameter_types! {
880		pub static SwapData: BTreeMap<ParaId, u64> = BTreeMap::new();
881	}
882
883	pub struct MockSwap;
884	impl OnSwap for MockSwap {
885		fn on_swap(one: ParaId, other: ParaId) {
886			let mut swap_data = SwapData::get();
887			let one_data = swap_data.remove(&one).unwrap_or_default();
888			let other_data = swap_data.remove(&other).unwrap_or_default();
889			swap_data.insert(one, other_data);
890			swap_data.insert(other, one_data);
891			SwapData::set(swap_data);
892		}
893	}
894
895	const BLOCKS_PER_SESSION: u32 = 3;
896
897	const VALIDATORS: &[Sr25519Keyring] = &[
898		Sr25519Keyring::Alice,
899		Sr25519Keyring::Bob,
900		Sr25519Keyring::Charlie,
901		Sr25519Keyring::Dave,
902		Sr25519Keyring::Ferdie,
903	];
904
905	fn run_to_block(n: BlockNumber) {
906		// NOTE that this function only simulates modules of interest. Depending on new pallet may
907		// require adding it here.
908		assert!(System::block_number() < n);
909		while System::block_number() < n {
910			let b = System::block_number();
911
912			if System::block_number() > 1 {
913				System::on_finalize(System::block_number());
914			}
915			// Session change every 3 blocks.
916			if (b + 1) % BLOCKS_PER_SESSION == 0 {
917				let session_index = shared::CurrentSessionIndex::<Test>::get() + 1;
918				let validators_pub_keys = VALIDATORS.iter().map(|v| v.public().into()).collect();
919
920				shared::Pallet::<Test>::set_session_index(session_index);
921				shared::Pallet::<Test>::set_active_validators_ascending(validators_pub_keys);
922
923				Parachains::test_on_new_session();
924			}
925			System::set_block_number(b + 1);
926			System::on_initialize(System::block_number());
927		}
928	}
929
930	fn run_to_session(n: BlockNumber) {
931		let block_number = n * BLOCKS_PER_SESSION;
932		run_to_block(block_number);
933	}
934
935	fn test_genesis_head(size: usize) -> HeadData {
936		HeadData(vec![0u8; size])
937	}
938
939	fn test_validation_code(size: usize) -> ValidationCode {
940		let validation_code = vec![0u8; size as usize];
941		ValidationCode(validation_code)
942	}
943
944	fn para_origin(id: ParaId) -> RuntimeOrigin {
945		polkadot_runtime_parachains::Origin::Parachain(id).into()
946	}
947
948	fn max_code_size() -> u32 {
949		configuration::ActiveConfig::<Test>::get().max_code_size
950	}
951
952	fn max_head_size() -> u32 {
953		configuration::ActiveConfig::<Test>::get().max_head_data_size
954	}
955
956	#[test]
957	fn basic_setup_works() {
958		new_test_ext().execute_with(|| {
959			assert_eq!(PendingSwap::<Test>::get(&ParaId::from(0u32)), None);
960			assert_eq!(Paras::<Test>::get(&ParaId::from(0u32)), None);
961		});
962	}
963
964	#[test]
965	fn end_to_end_scenario_works() {
966		new_test_ext().execute_with(|| {
967			let para_id = LOWEST_PUBLIC_ID;
968
969			const START_SESSION_INDEX: SessionIndex = 1;
970			run_to_session(START_SESSION_INDEX);
971
972			// first para is not yet registered
973			assert!(!Parachains::is_parathread(para_id));
974			// We register the Para ID
975			let validation_code = test_validation_code(32);
976			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
977			assert_ok!(Registrar::register(
978				RuntimeOrigin::signed(1),
979				para_id,
980				test_genesis_head(32),
981				validation_code.clone(),
982			));
983			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
984
985			run_to_session(START_SESSION_INDEX + 2);
986			// It is now a parathread (on-demand parachain).
987			assert!(Parachains::is_parathread(para_id));
988			assert!(!Parachains::is_parachain(para_id));
989			// Some other external process will elevate on-demand to lease holding parachain
990			assert_ok!(Registrar::make_parachain(para_id));
991			run_to_session(START_SESSION_INDEX + 4);
992			// It is now a lease holding parachain.
993			assert!(!Parachains::is_parathread(para_id));
994			assert!(Parachains::is_parachain(para_id));
995			// Turn it back into a parathread (on-demand parachain)
996			assert_ok!(Registrar::make_parathread(para_id));
997			run_to_session(START_SESSION_INDEX + 6);
998			assert!(Parachains::is_parathread(para_id));
999			assert!(!Parachains::is_parachain(para_id));
1000			// Deregister it
1001			assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,));
1002			run_to_session(START_SESSION_INDEX + 8);
1003			// It is nothing
1004			assert!(!Parachains::is_parathread(para_id));
1005			assert!(!Parachains::is_parachain(para_id));
1006		});
1007	}
1008
1009	#[test]
1010	fn register_works() {
1011		new_test_ext().execute_with(|| {
1012			const START_SESSION_INDEX: SessionIndex = 1;
1013			run_to_session(START_SESSION_INDEX);
1014
1015			let para_id = LOWEST_PUBLIC_ID;
1016			assert!(!Parachains::is_parathread(para_id));
1017
1018			let validation_code = test_validation_code(32);
1019			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1020			assert_eq!(Balances::reserved_balance(&1), <Test as Config>::ParaDeposit::get());
1021			assert_ok!(Registrar::register(
1022				RuntimeOrigin::signed(1),
1023				para_id,
1024				test_genesis_head(32),
1025				validation_code.clone(),
1026			));
1027			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
1028
1029			run_to_session(START_SESSION_INDEX + 2);
1030			assert!(Parachains::is_parathread(para_id));
1031			// Even though the registered validation code has a smaller size than the maximum the
1032			// para manager's deposit is reserved as though they registered the maximum-sized code.
1033			// Consequently, they can upgrade their code to the maximum size at any point without
1034			// additional cost.
1035			let validation_code_deposit =
1036				max_code_size() as BalanceOf<Test> * <Test as Config>::DataDepositPerByte::get();
1037			let head_deposit = 32 * <Test as Config>::DataDepositPerByte::get();
1038			assert_eq!(
1039				Balances::reserved_balance(&1),
1040				<Test as Config>::ParaDeposit::get() + head_deposit + validation_code_deposit
1041			);
1042		});
1043	}
1044
1045	#[test]
1046	fn schedule_code_upgrade_validates_code() {
1047		new_test_ext().execute_with(|| {
1048			const START_SESSION_INDEX: SessionIndex = 1;
1049			run_to_session(START_SESSION_INDEX);
1050
1051			let para_id = LOWEST_PUBLIC_ID;
1052			assert!(!Parachains::is_parathread(para_id));
1053
1054			let validation_code = test_validation_code(32);
1055			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1056			assert_eq!(Balances::reserved_balance(&1), <Test as Config>::ParaDeposit::get());
1057			assert_ok!(Registrar::register(
1058				RuntimeOrigin::signed(1),
1059				para_id,
1060				test_genesis_head(32),
1061				validation_code.clone(),
1062			));
1063			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
1064
1065			run_to_session(START_SESSION_INDEX + 2);
1066			assert!(Parachains::is_parathread(para_id));
1067
1068			let new_code = test_validation_code(0);
1069			assert_noop!(
1070				Registrar::schedule_code_upgrade(
1071					RuntimeOrigin::signed(1),
1072					para_id,
1073					new_code.clone(),
1074				),
1075				paras::Error::<Test>::InvalidCode
1076			);
1077
1078			let new_code = test_validation_code(max_code_size() as usize + 1);
1079			assert_noop!(
1080				Registrar::schedule_code_upgrade(
1081					RuntimeOrigin::signed(1),
1082					para_id,
1083					new_code.clone(),
1084				),
1085				paras::Error::<Test>::InvalidCode
1086			);
1087		});
1088	}
1089
1090	#[test]
1091	fn register_handles_basic_errors() {
1092		new_test_ext().execute_with(|| {
1093			let para_id = LOWEST_PUBLIC_ID;
1094
1095			assert_noop!(
1096				Registrar::register(
1097					RuntimeOrigin::signed(1),
1098					para_id,
1099					test_genesis_head(max_head_size() as usize),
1100					test_validation_code(max_code_size() as usize),
1101				),
1102				Error::<Test>::NotReserved
1103			);
1104
1105			// Successfully register para
1106			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1107
1108			assert_noop!(
1109				Registrar::register(
1110					RuntimeOrigin::signed(2),
1111					para_id,
1112					test_genesis_head(max_head_size() as usize),
1113					test_validation_code(max_code_size() as usize),
1114				),
1115				Error::<Test>::NotOwner
1116			);
1117
1118			assert_ok!(Registrar::register(
1119				RuntimeOrigin::signed(1),
1120				para_id,
1121				test_genesis_head(max_head_size() as usize),
1122				test_validation_code(max_code_size() as usize),
1123			));
1124			// Can skip pre-check and deregister para which's still onboarding.
1125			run_to_session(2);
1126
1127			assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id));
1128
1129			// Can't do it again
1130			assert_noop!(
1131				Registrar::register(
1132					RuntimeOrigin::signed(1),
1133					para_id,
1134					test_genesis_head(max_head_size() as usize),
1135					test_validation_code(max_code_size() as usize),
1136				),
1137				Error::<Test>::NotReserved
1138			);
1139
1140			// Head Size Check
1141			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2)));
1142			assert_noop!(
1143				Registrar::register(
1144					RuntimeOrigin::signed(2),
1145					para_id + 1,
1146					test_genesis_head((max_head_size() + 1) as usize),
1147					test_validation_code(max_code_size() as usize),
1148				),
1149				Error::<Test>::HeadDataTooLarge
1150			);
1151
1152			// Code Size Check
1153			assert_noop!(
1154				Registrar::register(
1155					RuntimeOrigin::signed(2),
1156					para_id + 1,
1157					test_genesis_head(max_head_size() as usize),
1158					test_validation_code((max_code_size() + 1) as usize),
1159				),
1160				Error::<Test>::CodeTooLarge
1161			);
1162
1163			// Needs enough funds for deposit
1164			assert_noop!(
1165				Registrar::reserve(RuntimeOrigin::signed(1337)),
1166				BalancesError::<Test, _>::InsufficientBalance
1167			);
1168		});
1169	}
1170
1171	#[test]
1172	fn deregister_works() {
1173		new_test_ext().execute_with(|| {
1174			const START_SESSION_INDEX: SessionIndex = 1;
1175			run_to_session(START_SESSION_INDEX);
1176
1177			let para_id = LOWEST_PUBLIC_ID;
1178			assert!(!Parachains::is_parathread(para_id));
1179
1180			let validation_code = test_validation_code(32);
1181			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1182			assert_ok!(Registrar::register(
1183				RuntimeOrigin::signed(1),
1184				para_id,
1185				test_genesis_head(32),
1186				validation_code.clone(),
1187			));
1188			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
1189
1190			run_to_session(START_SESSION_INDEX + 2);
1191			assert!(Parachains::is_parathread(para_id));
1192			assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,));
1193			run_to_session(START_SESSION_INDEX + 4);
1194			assert!(paras::Pallet::<Test>::lifecycle(para_id).is_none());
1195			assert_eq!(Balances::reserved_balance(&1), 0);
1196		});
1197	}
1198
1199	#[test]
1200	fn deregister_handles_basic_errors() {
1201		new_test_ext().execute_with(|| {
1202			const START_SESSION_INDEX: SessionIndex = 1;
1203			run_to_session(START_SESSION_INDEX);
1204
1205			let para_id = LOWEST_PUBLIC_ID;
1206			assert!(!Parachains::is_parathread(para_id));
1207
1208			let validation_code = test_validation_code(32);
1209			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1210			assert_ok!(Registrar::register(
1211				RuntimeOrigin::signed(1),
1212				para_id,
1213				test_genesis_head(32),
1214				validation_code.clone(),
1215			));
1216			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
1217
1218			run_to_session(START_SESSION_INDEX + 2);
1219			assert!(Parachains::is_parathread(para_id));
1220			// Owner check
1221			assert_noop!(Registrar::deregister(RuntimeOrigin::signed(2), para_id,), BadOrigin);
1222			assert_ok!(Registrar::make_parachain(para_id));
1223			run_to_session(START_SESSION_INDEX + 4);
1224			// Cant directly deregister parachain
1225			assert_noop!(
1226				Registrar::deregister(RuntimeOrigin::root(), para_id,),
1227				Error::<Test>::NotParathread
1228			);
1229		});
1230	}
1231
1232	#[test]
1233	fn swap_works() {
1234		new_test_ext().execute_with(|| {
1235			const START_SESSION_INDEX: SessionIndex = 1;
1236			run_to_session(START_SESSION_INDEX);
1237
1238			// Successfully register first two parachains
1239			let para_1 = LOWEST_PUBLIC_ID;
1240			let para_2 = LOWEST_PUBLIC_ID + 1;
1241
1242			let validation_code = test_validation_code(max_code_size() as usize);
1243			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1244			assert_ok!(Registrar::register(
1245				RuntimeOrigin::signed(1),
1246				para_1,
1247				test_genesis_head(max_head_size() as usize),
1248				validation_code.clone(),
1249			));
1250			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2)));
1251			assert_ok!(Registrar::register(
1252				RuntimeOrigin::signed(2),
1253				para_2,
1254				test_genesis_head(max_head_size() as usize),
1255				validation_code.clone(),
1256			));
1257			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
1258
1259			run_to_session(START_SESSION_INDEX + 2);
1260
1261			// Upgrade para 1 into a parachain
1262			assert_ok!(Registrar::make_parachain(para_1));
1263
1264			// Set some mock swap data.
1265			let mut swap_data = SwapData::get();
1266			swap_data.insert(para_1, 69);
1267			swap_data.insert(para_2, 1337);
1268			SwapData::set(swap_data);
1269
1270			run_to_session(START_SESSION_INDEX + 4);
1271
1272			// Roles are as we expect
1273			assert!(Parachains::is_parachain(para_1));
1274			assert!(!Parachains::is_parathread(para_1));
1275			assert!(!Parachains::is_parachain(para_2));
1276			assert!(Parachains::is_parathread(para_2));
1277
1278			// Both paras initiate a swap
1279			// Swap between parachain and parathread
1280			assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,));
1281			assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,));
1282			System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped {
1283				para_id: para_2,
1284				other_id: para_1,
1285			}));
1286
1287			run_to_session(START_SESSION_INDEX + 6);
1288
1289			// Roles are swapped
1290			assert!(!Parachains::is_parachain(para_1));
1291			assert!(Parachains::is_parathread(para_1));
1292			assert!(Parachains::is_parachain(para_2));
1293			assert!(!Parachains::is_parathread(para_2));
1294
1295			// Data is swapped
1296			assert_eq!(SwapData::get().get(&para_1).unwrap(), &1337);
1297			assert_eq!(SwapData::get().get(&para_2).unwrap(), &69);
1298
1299			// Both paras initiate a swap
1300			// Swap between parathread and parachain
1301			assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_2,));
1302			assert_ok!(Registrar::swap(para_origin(para_2), para_2, para_1,));
1303			System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped {
1304				para_id: para_2,
1305				other_id: para_1,
1306			}));
1307
1308			// Data is swapped
1309			assert_eq!(SwapData::get().get(&para_1).unwrap(), &69);
1310			assert_eq!(SwapData::get().get(&para_2).unwrap(), &1337);
1311
1312			// Parachain to parachain swap
1313			let para_3 = LOWEST_PUBLIC_ID + 2;
1314			let validation_code = test_validation_code(max_code_size() as usize);
1315			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(3)));
1316			assert_ok!(Registrar::register(
1317				RuntimeOrigin::signed(3),
1318				para_3,
1319				test_genesis_head(max_head_size() as usize),
1320				validation_code.clone(),
1321			));
1322			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX + 6);
1323
1324			run_to_session(START_SESSION_INDEX + 8);
1325
1326			// Upgrade para 3 into a parachain
1327			assert_ok!(Registrar::make_parachain(para_3));
1328
1329			// Set some mock swap data.
1330			let mut swap_data = SwapData::get();
1331			swap_data.insert(para_3, 777);
1332			SwapData::set(swap_data);
1333
1334			run_to_session(START_SESSION_INDEX + 10);
1335
1336			// Both are parachains
1337			assert!(Parachains::is_parachain(para_3));
1338			assert!(!Parachains::is_parathread(para_3));
1339			assert!(Parachains::is_parachain(para_1));
1340			assert!(!Parachains::is_parathread(para_1));
1341
1342			// Both paras initiate a swap
1343			// Swap between parachain and parachain
1344			assert_ok!(Registrar::swap(para_origin(para_1), para_1, para_3,));
1345			assert_ok!(Registrar::swap(para_origin(para_3), para_3, para_1,));
1346			System::assert_last_event(RuntimeEvent::Registrar(paras_registrar::Event::Swapped {
1347				para_id: para_3,
1348				other_id: para_1,
1349			}));
1350
1351			// Data is swapped
1352			assert_eq!(SwapData::get().get(&para_3).unwrap(), &69);
1353			assert_eq!(SwapData::get().get(&para_1).unwrap(), &777);
1354		});
1355	}
1356
1357	#[test]
1358	fn para_lock_works() {
1359		new_test_ext().execute_with(|| {
1360			run_to_block(1);
1361
1362			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1363			let para_id = LOWEST_PUBLIC_ID;
1364			assert_ok!(Registrar::register(
1365				RuntimeOrigin::signed(1),
1366				para_id,
1367				vec![1; 3].into(),
1368				test_validation_code(32)
1369			));
1370
1371			assert_noop!(Registrar::add_lock(RuntimeOrigin::signed(2), para_id), BadOrigin);
1372
1373			// Once they produces new block, we lock them in.
1374			Registrar::on_new_head(para_id, &Default::default());
1375
1376			// Owner cannot pass origin check when checking lock
1377			assert_noop!(
1378				Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id),
1379				BadOrigin
1380			);
1381			// Owner cannot remove lock.
1382			assert_noop!(Registrar::remove_lock(RuntimeOrigin::signed(1), para_id), BadOrigin);
1383			// Para can.
1384			assert_ok!(Registrar::remove_lock(para_origin(para_id), para_id));
1385			// Owner can pass origin check again
1386			assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id));
1387
1388			// Won't lock again after it is unlocked
1389			Registrar::on_new_head(para_id, &Default::default());
1390
1391			assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id));
1392		});
1393	}
1394
1395	#[test]
1396	fn swap_handles_bad_states() {
1397		new_test_ext().execute_with(|| {
1398			const START_SESSION_INDEX: SessionIndex = 1;
1399			run_to_session(START_SESSION_INDEX);
1400
1401			let para_1 = LOWEST_PUBLIC_ID;
1402			let para_2 = LOWEST_PUBLIC_ID + 1;
1403
1404			// paras are not yet registered
1405			assert!(!Parachains::is_parathread(para_1));
1406			assert!(!Parachains::is_parathread(para_2));
1407
1408			// Cannot even start a swap
1409			assert_noop!(
1410				Registrar::swap(RuntimeOrigin::root(), para_1, para_2),
1411				Error::<Test>::NotRegistered
1412			);
1413
1414			// We register Paras 1 and 2
1415			let validation_code = test_validation_code(32);
1416			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(1)));
1417			assert_ok!(Registrar::reserve(RuntimeOrigin::signed(2)));
1418			assert_ok!(Registrar::register(
1419				RuntimeOrigin::signed(1),
1420				para_1,
1421				test_genesis_head(32),
1422				validation_code.clone(),
1423			));
1424			assert_ok!(Registrar::register(
1425				RuntimeOrigin::signed(2),
1426				para_2,
1427				test_genesis_head(32),
1428				validation_code.clone(),
1429			));
1430			conclude_pvf_checking::<Test>(&validation_code, VALIDATORS, START_SESSION_INDEX);
1431
1432			// Cannot swap
1433			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1434			assert_noop!(
1435				Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
1436				Error::<Test>::CannotSwap
1437			);
1438
1439			run_to_session(START_SESSION_INDEX + 2);
1440
1441			// They are now parathreads (on-demand parachains).
1442			assert!(Parachains::is_parathread(para_1));
1443			assert!(Parachains::is_parathread(para_2));
1444
1445			// Cannot swap
1446			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1447			assert_noop!(
1448				Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
1449				Error::<Test>::CannotSwap
1450			);
1451
1452			// Some other external process will elevate one on-demand
1453			// parachain to a lease holding parachain
1454			assert_ok!(Registrar::make_parachain(para_1));
1455
1456			// Cannot swap
1457			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1458			assert_noop!(
1459				Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
1460				Error::<Test>::CannotSwap
1461			);
1462
1463			run_to_session(START_SESSION_INDEX + 3);
1464
1465			// Cannot swap
1466			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1467			assert_noop!(
1468				Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
1469				Error::<Test>::CannotSwap
1470			);
1471
1472			run_to_session(START_SESSION_INDEX + 4);
1473
1474			// It is now a lease holding parachain.
1475			assert!(Parachains::is_parachain(para_1));
1476			assert!(Parachains::is_parathread(para_2));
1477
1478			// Swap works here.
1479			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1480			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_2, para_1));
1481			assert!(System::events().iter().any(|r| matches!(
1482				r.event,
1483				RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. })
1484			)));
1485
1486			run_to_session(START_SESSION_INDEX + 5);
1487
1488			// Cannot swap
1489			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1490			assert_noop!(
1491				Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
1492				Error::<Test>::CannotSwap
1493			);
1494
1495			run_to_session(START_SESSION_INDEX + 6);
1496
1497			// Swap worked!
1498			assert!(Parachains::is_parachain(para_2));
1499			assert!(Parachains::is_parathread(para_1));
1500			assert!(System::events().iter().any(|r| matches!(
1501				r.event,
1502				RuntimeEvent::Registrar(paras_registrar::Event::Swapped { .. })
1503			)));
1504
1505			// Something starts to downgrade a para
1506			assert_ok!(Registrar::make_parathread(para_2));
1507
1508			run_to_session(START_SESSION_INDEX + 7);
1509
1510			// Cannot swap
1511			assert_ok!(Registrar::swap(RuntimeOrigin::root(), para_1, para_2));
1512			assert_noop!(
1513				Registrar::swap(RuntimeOrigin::root(), para_2, para_1),
1514				Error::<Test>::CannotSwap
1515			);
1516
1517			run_to_session(START_SESSION_INDEX + 8);
1518
1519			assert!(Parachains::is_parathread(para_1));
1520			assert!(Parachains::is_parathread(para_2));
1521		});
1522	}
1523}
1524
1525#[cfg(feature = "runtime-benchmarks")]
1526mod benchmarking {
1527	use super::{Pallet as Registrar, *};
1528	use crate::traits::Registrar as RegistrarT;
1529	use frame_support::assert_ok;
1530	use frame_system::RawOrigin;
1531	use polkadot_primitives::{MAX_CODE_SIZE, MAX_HEAD_DATA_SIZE, MIN_CODE_SIZE};
1532	use polkadot_runtime_parachains::{paras, shared, Origin as ParaOrigin};
1533	use sp_runtime::traits::Bounded;
1534
1535	use frame_benchmarking::{account, benchmarks, whitelisted_caller};
1536
1537	fn assert_last_event<T: Config>(generic_event: <T as Config>::RuntimeEvent) {
1538		let events = frame_system::Pallet::<T>::events();
1539		let system_event: <T as frame_system::Config>::RuntimeEvent = generic_event.into();
1540		// compare to the last event record
1541		let frame_system::EventRecord { event, .. } = &events[events.len() - 1];
1542		assert_eq!(event, &system_event);
1543	}
1544
1545	fn register_para<T: Config>(id: u32) -> ParaId {
1546		let para = ParaId::from(id);
1547		let genesis_head = Registrar::<T>::worst_head_data();
1548		let validation_code = Registrar::<T>::worst_validation_code();
1549		let caller: T::AccountId = whitelisted_caller();
1550		T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
1551		assert_ok!(Registrar::<T>::reserve(RawOrigin::Signed(caller.clone()).into()));
1552		assert_ok!(Registrar::<T>::register(
1553			RawOrigin::Signed(caller).into(),
1554			para,
1555			genesis_head,
1556			validation_code.clone()
1557		));
1558		assert_ok!(polkadot_runtime_parachains::paras::Pallet::<T>::add_trusted_validation_code(
1559			frame_system::Origin::<T>::Root.into(),
1560			validation_code,
1561		));
1562		return para
1563	}
1564
1565	fn para_origin(id: u32) -> ParaOrigin {
1566		ParaOrigin::Parachain(id.into())
1567	}
1568
1569	// This function moves forward to the next scheduled session for parachain lifecycle upgrades.
1570	fn next_scheduled_session<T: Config>() {
1571		shared::Pallet::<T>::set_session_index(shared::Pallet::<T>::scheduled_session());
1572		paras::Pallet::<T>::test_on_new_session();
1573	}
1574
1575	benchmarks! {
1576		where_clause { where ParaOrigin: Into<<T as frame_system::Config>::RuntimeOrigin> }
1577
1578		reserve {
1579			let caller: T::AccountId = whitelisted_caller();
1580			T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
1581		}: _(RawOrigin::Signed(caller.clone()))
1582		verify {
1583			assert_last_event::<T>(Event::<T>::Reserved { para_id: LOWEST_PUBLIC_ID, who: caller }.into());
1584			assert!(Paras::<T>::get(LOWEST_PUBLIC_ID).is_some());
1585			assert_eq!(paras::Pallet::<T>::lifecycle(LOWEST_PUBLIC_ID), None);
1586		}
1587
1588		register {
1589			let para = LOWEST_PUBLIC_ID;
1590			let genesis_head = Registrar::<T>::worst_head_data();
1591			let validation_code = Registrar::<T>::worst_validation_code();
1592			let caller: T::AccountId = whitelisted_caller();
1593			T::Currency::make_free_balance_be(&caller, BalanceOf::<T>::max_value());
1594			assert_ok!(Registrar::<T>::reserve(RawOrigin::Signed(caller.clone()).into()));
1595		}: _(RawOrigin::Signed(caller.clone()), para, genesis_head, validation_code.clone())
1596		verify {
1597			assert_last_event::<T>(Event::<T>::Registered{ para_id: para, manager: caller }.into());
1598			assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Onboarding));
1599			assert_ok!(polkadot_runtime_parachains::paras::Pallet::<T>::add_trusted_validation_code(
1600				frame_system::Origin::<T>::Root.into(),
1601				validation_code,
1602			));
1603			next_scheduled_session::<T>();
1604			assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Parathread));
1605		}
1606
1607		force_register {
1608			let manager: T::AccountId = account("manager", 0, 0);
1609			let deposit = 0u32.into();
1610			let para = ParaId::from(69);
1611			let genesis_head = Registrar::<T>::worst_head_data();
1612			let validation_code = Registrar::<T>::worst_validation_code();
1613		}: _(RawOrigin::Root, manager.clone(), deposit, para, genesis_head, validation_code.clone())
1614		verify {
1615			assert_last_event::<T>(Event::<T>::Registered { para_id: para, manager }.into());
1616			assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Onboarding));
1617			assert_ok!(polkadot_runtime_parachains::paras::Pallet::<T>::add_trusted_validation_code(
1618				frame_system::Origin::<T>::Root.into(),
1619				validation_code,
1620			));
1621			next_scheduled_session::<T>();
1622			assert_eq!(paras::Pallet::<T>::lifecycle(para), Some(ParaLifecycle::Parathread));
1623		}
1624
1625		deregister {
1626			let para = register_para::<T>(LOWEST_PUBLIC_ID.into());
1627			next_scheduled_session::<T>();
1628			let caller: T::AccountId = whitelisted_caller();
1629		}: _(RawOrigin::Signed(caller), para)
1630		verify {
1631			assert_last_event::<T>(Event::<T>::Deregistered { para_id: para }.into());
1632		}
1633
1634		swap {
1635			// On demand parachain
1636			let parathread = register_para::<T>(LOWEST_PUBLIC_ID.into());
1637			let parachain = register_para::<T>((LOWEST_PUBLIC_ID + 1).into());
1638
1639			let parachain_origin = para_origin(parachain.into());
1640
1641			// Actually finish registration process
1642			next_scheduled_session::<T>();
1643
1644			// Upgrade the parachain
1645			Registrar::<T>::make_parachain(parachain)?;
1646			next_scheduled_session::<T>();
1647
1648			assert_eq!(paras::Pallet::<T>::lifecycle(parachain), Some(ParaLifecycle::Parachain));
1649			assert_eq!(paras::Pallet::<T>::lifecycle(parathread), Some(ParaLifecycle::Parathread));
1650
1651			let caller: T::AccountId = whitelisted_caller();
1652			Registrar::<T>::swap(parachain_origin.into(), parachain, parathread)?;
1653		}: _(RawOrigin::Signed(caller.clone()), parathread, parachain)
1654		verify {
1655			next_scheduled_session::<T>();
1656			// Swapped!
1657			assert_eq!(paras::Pallet::<T>::lifecycle(parachain), Some(ParaLifecycle::Parathread));
1658			assert_eq!(paras::Pallet::<T>::lifecycle(parathread), Some(ParaLifecycle::Parachain));
1659		}
1660
1661		schedule_code_upgrade {
1662			let b in MIN_CODE_SIZE .. MAX_CODE_SIZE;
1663			let new_code = ValidationCode(vec![0; b as usize]);
1664			let para_id = ParaId::from(1000);
1665		}: _(RawOrigin::Root, para_id, new_code)
1666
1667		set_current_head {
1668			let b in 1 .. MAX_HEAD_DATA_SIZE;
1669			let new_head = HeadData(vec![0; b as usize]);
1670			let para_id = ParaId::from(1000);
1671		}: _(RawOrigin::Root, para_id, new_head)
1672
1673		impl_benchmark_test_suite!(
1674			Registrar,
1675			crate::integration_tests::new_test_ext(),
1676			crate::integration_tests::Test,
1677		);
1678	}
1679}