referrerpolicy=no-referrer-when-downgrade

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//!
20//! Registration is either local, with the deposit reserved here, or driven by a remote control
21//! plane that holds the deposit itself โ€” see the [`registrar_primitives::ParachainRegistrar`]
22//! impl.
23
24pub mod migration;
25
26use alloc::vec::Vec;
27use core::result;
28use frame_support::{
29	dispatch::DispatchResult,
30	ensure,
31	pallet_prelude::Weight,
32	traits::{Currency, Get, ReservableCurrency},
33};
34use frame_system::{self, ensure_root, ensure_signed, pallet_prelude::BlockNumberFor};
35use polkadot_primitives::{
36	HeadData, Id as ParaId, ValidationCode, LOWEST_PUBLIC_ID, MIN_CODE_SIZE,
37};
38use polkadot_runtime_parachains::{
39	configuration, ensure_parachain,
40	paras::{self, ParaGenesisArgs, UpgradeStrategy},
41	Origin, ParaLifecycle,
42};
43
44use crate::traits::{OnSwap, Registrar};
45use codec::{Decode, DecodeWithMemTracking, Encode, MaxEncodedLen};
46pub use pallet::*;
47use polkadot_runtime_parachains::paras::{OnNewHead, ParaKind};
48use scale_info::TypeInfo;
49use sp_runtime::{
50	traits::{CheckedSub, Saturating, Zero},
51	Debug,
52};
53
54#[derive(
55	Encode,
56	Decode,
57	Clone,
58	PartialEq,
59	Eq,
60	Default,
61	Debug,
62	TypeInfo,
63	MaxEncodedLen,
64	DecodeWithMemTracking,
65)]
66pub struct ParaInfo<Account, Balance> {
67	/// The account that has placed a deposit for registering this para.
68	pub manager: Account,
69	/// The amount reserved by the `manager` account for the registration.
70	pub deposit: Balance,
71	/// Whether the para registration should be locked from being controlled by the manager.
72	/// None means the lock had not been explicitly set, and should be treated as false.
73	pub locked: Option<bool>,
74}
75
76impl<Account, Balance> ParaInfo<Account, Balance> {
77	/// Returns if the para is locked.
78	pub fn is_locked(&self) -> bool {
79		self.locked.unwrap_or(false)
80	}
81}
82
83type BalanceOf<T> =
84	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
85
86pub trait WeightInfo {
87	fn reserve() -> Weight;
88	fn register() -> Weight;
89	fn force_register() -> Weight;
90	fn deregister() -> Weight;
91	fn swap() -> Weight;
92	fn schedule_code_upgrade(b: u32) -> Weight;
93	fn set_current_head(b: u32) -> Weight;
94}
95
96pub struct TestWeightInfo;
97impl WeightInfo for TestWeightInfo {
98	fn reserve() -> Weight {
99		Weight::zero()
100	}
101	fn register() -> Weight {
102		Weight::zero()
103	}
104	fn force_register() -> Weight {
105		Weight::zero()
106	}
107	fn deregister() -> Weight {
108		Weight::zero()
109	}
110	fn swap() -> Weight {
111		Weight::zero()
112	}
113	fn schedule_code_upgrade(_b: u32) -> Weight {
114		Weight::zero()
115	}
116	fn set_current_head(_b: u32) -> Weight {
117		Weight::zero()
118	}
119}
120
121#[frame_support::pallet]
122pub mod pallet {
123	use super::*;
124	use frame_support::pallet_prelude::*;
125	use frame_system::pallet_prelude::*;
126
127	/// The in-code storage version.
128	const STORAGE_VERSION: StorageVersion = StorageVersion::new(1);
129
130	#[pallet::pallet]
131	#[pallet::without_storage_info]
132	#[pallet::storage_version(STORAGE_VERSION)]
133	pub struct Pallet<T>(_);
134
135	#[pallet::config]
136	#[pallet::disable_frame_system_supertrait_check]
137	pub trait Config: configuration::Config + paras::Config {
138		/// The overarching event type.
139		#[allow(deprecated)]
140		type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
141
142		/// The aggregated origin type must support the `parachains` origin. We require that we can
143		/// infallibly convert between this origin and the system origin, but in reality, they're
144		/// the same type, we just can't express that to the Rust type system without writing a
145		/// `where` clause everywhere.
146		type RuntimeOrigin: From<<Self as frame_system::Config>::RuntimeOrigin>
147			+ Into<result::Result<Origin, <Self as Config>::RuntimeOrigin>>;
148
149		/// The system's currency for on-demand parachain payment.
150		type Currency: ReservableCurrency<Self::AccountId>;
151
152		/// Runtime hook for when a lease holding parachain and on-demand parachain swap.
153		type OnSwap: crate::traits::OnSwap;
154
155		/// The deposit to be paid to run a on-demand parachain.
156		/// This should include the cost for storing the genesis head and validation code.
157		#[pallet::constant]
158		type ParaDeposit: Get<BalanceOf<Self>>;
159
160		/// The deposit to be paid per byte stored on chain.
161		#[pallet::constant]
162		type DataDepositPerByte: Get<BalanceOf<Self>>;
163
164		/// Weight Information for the Extrinsics in the Pallet
165		type WeightInfo: WeightInfo;
166	}
167
168	#[pallet::event]
169	#[pallet::generate_deposit(pub(super) fn deposit_event)]
170	pub enum Event<T: Config> {
171		Registered { para_id: ParaId, manager: T::AccountId },
172		Deregistered { para_id: ParaId },
173		Reserved { para_id: ParaId, who: T::AccountId },
174		Swapped { para_id: ParaId, other_id: ParaId },
175	}
176
177	#[pallet::error]
178	pub enum Error<T> {
179		/// The ID is not registered.
180		NotRegistered,
181		/// The ID is already registered.
182		AlreadyRegistered,
183		/// The caller is not the owner of this Id.
184		NotOwner,
185		/// Invalid para code size.
186		CodeTooLarge,
187		/// Invalid para head data size.
188		HeadDataTooLarge,
189		/// Para is not a Parachain.
190		NotParachain,
191		/// Para is not a Parathread (on-demand parachain).
192		NotParathread,
193		/// Cannot deregister para
194		CannotDeregister,
195		/// Cannot schedule downgrade of lease holding parachain to on-demand parachain
196		CannotDowngrade,
197		/// Cannot schedule upgrade of on-demand parachain to lease holding parachain
198		CannotUpgrade,
199		/// Para is locked from manipulation by the manager. Must use parachain or relay chain
200		/// governance.
201		ParaLocked,
202		/// The ID given for registration has not been reserved.
203		NotReserved,
204		/// The validation code is invalid.
205		InvalidCode,
206		/// Cannot perform a parachain slot / lifecycle swap. Check that the state of both paras
207		/// are correct for the swap to work.
208		CannotSwap,
209		/// The operation is scaffolded but not implemented yet.
210		NotImplemented,
211	}
212
213	/// Pending swap operations.
214	#[pallet::storage]
215	pub(super) type PendingSwap<T> = StorageMap<_, Twox64Concat, ParaId, ParaId>;
216
217	/// Amount held on deposit for each para and the original depositor.
218	///
219	/// The given account ID is responsible for registering the code and initial head data, but may
220	/// only do so if it isn't yet registered. (After that, it's up to governance to do so.)
221	#[pallet::storage]
222	pub type Paras<T: Config> =
223		StorageMap<_, Twox64Concat, ParaId, ParaInfo<T::AccountId, BalanceOf<T>>>;
224
225	/// The next free `ParaId`.
226	#[pallet::storage]
227	pub type NextFreeParaId<T> = StorageValue<_, ParaId, ValueQuery>;
228
229	#[pallet::genesis_config]
230	pub struct GenesisConfig<T: Config> {
231		#[serde(skip)]
232		pub _config: core::marker::PhantomData<T>,
233		pub next_free_para_id: ParaId,
234	}
235
236	impl<T: Config> Default for GenesisConfig<T> {
237		fn default() -> Self {
238			GenesisConfig { next_free_para_id: LOWEST_PUBLIC_ID, _config: Default::default() }
239		}
240	}
241
242	#[pallet::genesis_build]
243	impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
244		fn build(&self) {
245			NextFreeParaId::<T>::put(self.next_free_para_id);
246		}
247	}
248
249	#[pallet::hooks]
250	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
251
252	#[pallet::call]
253	impl<T: Config> Pallet<T> {
254		/// Register head data and validation code for a reserved Para Id.
255		///
256		/// ## Arguments
257		/// - `origin`: Must be called by a `Signed` origin.
258		/// - `id`: The para ID. Must be owned/managed by the `origin` signing account.
259		/// - `genesis_head`: The genesis head data of the parachain/thread.
260		/// - `validation_code`: The initial validation code of the parachain/thread.
261		///
262		/// ## Deposits/Fees
263		/// The account with the originating signature must reserve a deposit.
264		///
265		/// The deposit is required to cover the costs associated with storing the genesis head
266		/// data and the validation code.
267		/// This accounts for the potential to store validation code of a size up to the
268		/// `max_code_size`, as defined in the configuration pallet
269		///
270		/// Anything already reserved previously for this para ID is accounted for.
271		///
272		/// ## Events
273		/// The `Registered` event is emitted in case of success.
274		#[pallet::call_index(0)]
275		#[pallet::weight(<T as Config>::WeightInfo::register())]
276		pub fn register(
277			origin: OriginFor<T>,
278			id: ParaId,
279			genesis_head: HeadData,
280			validation_code: ValidationCode,
281		) -> DispatchResult {
282			let who = ensure_signed(origin)?;
283			Self::do_register(who, None, id, genesis_head, validation_code, true)?;
284			Ok(())
285		}
286
287		/// Force the registration of a Para Id on the relay chain.
288		///
289		/// This function must be called by a Root origin.
290		///
291		/// The deposit taken can be specified for this registration. Any `ParaId`
292		/// can be registered, including sub-1000 IDs which are System Parachains.
293		#[pallet::call_index(1)]
294		#[pallet::weight(<T as Config>::WeightInfo::force_register())]
295		pub fn force_register(
296			origin: OriginFor<T>,
297			who: T::AccountId,
298			deposit: BalanceOf<T>,
299			id: ParaId,
300			genesis_head: HeadData,
301			validation_code: ValidationCode,
302		) -> DispatchResult {
303			ensure_root(origin)?;
304			Self::do_register(who, Some(deposit), id, genesis_head, validation_code, false)
305		}
306
307		/// Deregister a Para Id, freeing all data and returning any deposit.
308		///
309		/// The caller must be Root, the `para` owner, or the `para` itself. The para must be an
310		/// on-demand parachain.
311		#[pallet::call_index(2)]
312		#[pallet::weight(<T as Config>::WeightInfo::deregister())]
313		pub fn deregister(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
314			Self::ensure_root_para_or_owner(origin, id)?;
315			Self::do_deregister(id)
316		}
317
318		/// Swap a lease holding parachain with another parachain, either on-demand or lease
319		/// holding.
320		///
321		/// The origin must be Root, the `para` owner, or the `para` itself.
322		///
323		/// The swap will happen only if there is already an opposite swap pending. If there is not,
324		/// the swap will be stored in the pending swaps map, ready for a later confirmatory swap.
325		///
326		/// The `ParaId`s remain mapped to the same head data and code so external code can rely on
327		/// `ParaId` to be a long-term identifier of a notional "parachain". However, their
328		/// scheduling info (i.e. whether they're an on-demand parachain or lease holding
329		/// parachain), auction information and the auction deposit are switched.
330		#[pallet::call_index(3)]
331		#[pallet::weight(<T as Config>::WeightInfo::swap())]
332		pub fn swap(origin: OriginFor<T>, id: ParaId, other: ParaId) -> DispatchResult {
333			Self::ensure_root_para_or_owner(origin, id)?;
334
335			// If `id` and `other` is the same id, we treat this as a "clear" function, and exit
336			// early, since swapping the same id would otherwise be a noop.
337			if id == other {
338				PendingSwap::<T>::remove(id);
339				return Ok(());
340			}
341
342			// Sanity check that `id` is even a para.
343			let id_lifecycle =
344				paras::Pallet::<T>::lifecycle(id).ok_or(Error::<T>::NotRegistered)?;
345
346			if PendingSwap::<T>::get(other) == Some(id) {
347				let other_lifecycle =
348					paras::Pallet::<T>::lifecycle(other).ok_or(Error::<T>::NotRegistered)?;
349				// identify which is a lease holding parachain and which is a parathread (on-demand
350				// parachain)
351				if id_lifecycle == ParaLifecycle::Parachain &&
352					other_lifecycle == ParaLifecycle::Parathread
353				{
354					Self::do_thread_and_chain_swap(id, other);
355				} else if id_lifecycle == ParaLifecycle::Parathread &&
356					other_lifecycle == ParaLifecycle::Parachain
357				{
358					Self::do_thread_and_chain_swap(other, id);
359				} else if id_lifecycle == ParaLifecycle::Parachain &&
360					other_lifecycle == ParaLifecycle::Parachain
361				{
362					// If both chains are currently parachains, there is nothing funny we
363					// need to do for their lifecycle management, just swap the underlying
364					// data.
365					T::OnSwap::on_swap(id, other);
366				} else {
367					return Err(Error::<T>::CannotSwap.into());
368				}
369				Self::deposit_event(Event::<T>::Swapped { para_id: id, other_id: other });
370				PendingSwap::<T>::remove(other);
371			} else {
372				PendingSwap::<T>::insert(id, other);
373			}
374
375			Ok(())
376		}
377
378		/// Remove a manager lock from a para. This will allow the manager of a
379		/// previously locked para to deregister or swap a para without using governance.
380		///
381		/// Can only be called by the Root origin or the parachain.
382		#[pallet::call_index(4)]
383		#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
384		pub fn remove_lock(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
385			Self::ensure_root_or_para(origin, para)?;
386			<Self as Registrar>::remove_lock(para);
387			Ok(())
388		}
389
390		/// Reserve a Para Id on the relay chain.
391		///
392		/// This function will reserve a new Para Id to be owned/managed by the origin account.
393		/// The origin account is able to register head data and validation code using `register` to
394		/// create an on-demand parachain. Using the Slots pallet, an on-demand parachain can then
395		/// be upgraded to a lease holding parachain.
396		///
397		/// ## Arguments
398		/// - `origin`: Must be called by a `Signed` origin. Becomes the manager/owner of the new
399		///   para ID.
400		///
401		/// ## Deposits/Fees
402		/// The origin must reserve a deposit of `ParaDeposit` for the registration.
403		///
404		/// ## Events
405		/// The `Reserved` event is emitted in case of success, which provides the ID reserved for
406		/// use.
407		#[pallet::call_index(5)]
408		#[pallet::weight(<T as Config>::WeightInfo::reserve())]
409		pub fn reserve(origin: OriginFor<T>) -> DispatchResult {
410			let who = ensure_signed(origin)?;
411			let id = NextFreeParaId::<T>::get().max(LOWEST_PUBLIC_ID);
412			Self::do_reserve(who, None, id)?;
413			NextFreeParaId::<T>::set(id + 1);
414			Ok(())
415		}
416
417		/// Add a manager lock from a para. This will prevent the manager of a
418		/// para to deregister or swap a para.
419		///
420		/// Can be called by Root, the parachain, or the parachain manager if the parachain is
421		/// unlocked.
422		#[pallet::call_index(6)]
423		#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
424		pub fn add_lock(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
425			Self::ensure_root_para_or_owner(origin, para)?;
426			<Self as Registrar>::apply_lock(para);
427			Ok(())
428		}
429
430		/// Schedule a parachain upgrade.
431		///
432		/// This will kick off a check of `new_code` by all validators. After the majority of the
433		/// validators have reported on the validity of the code, the code will either be enacted
434		/// or the upgrade will be rejected. If the code will be enacted, the current code of the
435		/// parachain will be overwritten directly. This means that any PoV will be checked by this
436		/// new code. The parachain itself will not be informed explicitly that the validation code
437		/// has changed.
438		///
439		/// Can be called by Root, the parachain, or the parachain manager if the parachain is
440		/// unlocked.
441		#[pallet::call_index(7)]
442		#[pallet::weight(<T as Config>::WeightInfo::schedule_code_upgrade(new_code.0.len() as u32))]
443		pub fn schedule_code_upgrade(
444			origin: OriginFor<T>,
445			para: ParaId,
446			new_code: ValidationCode,
447		) -> DispatchResult {
448			Self::ensure_root_para_or_owner(origin, para)?;
449			polkadot_runtime_parachains::schedule_code_upgrade::<T>(
450				para,
451				new_code,
452				UpgradeStrategy::ApplyAtExpectedBlock,
453			)?;
454			Ok(())
455		}
456
457		/// Set the parachain's current head.
458		///
459		/// Can be called by Root, the parachain, or the parachain manager if the parachain is
460		/// unlocked.
461		#[pallet::call_index(8)]
462		#[pallet::weight(<T as Config>::WeightInfo::set_current_head(new_head.0.len() as u32))]
463		pub fn set_current_head(
464			origin: OriginFor<T>,
465			para: ParaId,
466			new_head: HeadData,
467		) -> DispatchResult {
468			Self::ensure_root_para_or_owner(origin, para)?;
469			polkadot_runtime_parachains::set_current_head::<T>(para, new_head);
470			Ok(())
471		}
472	}
473}
474
475impl<T: Config> Registrar for Pallet<T> {
476	type AccountId = T::AccountId;
477
478	/// Return the manager `AccountId` of a para if one exists.
479	fn manager_of(id: ParaId) -> Option<T::AccountId> {
480		Some(Paras::<T>::get(id)?.manager)
481	}
482
483	// All lease holding parachains. Ordered ascending by ParaId. On-demand parachains are not
484	// included.
485	fn parachains() -> Vec<ParaId> {
486		paras::Parachains::<T>::get()
487	}
488
489	// Return if a para is a parathread (on-demand parachain)
490	fn is_parathread(id: ParaId) -> bool {
491		paras::Pallet::<T>::is_parathread(id)
492	}
493
494	// Return if a para is a lease holding parachain
495	fn is_parachain(id: ParaId) -> bool {
496		paras::Pallet::<T>::is_parachain(id)
497	}
498
499	// Apply a lock to the parachain.
500	fn apply_lock(id: ParaId) {
501		Paras::<T>::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(true)));
502	}
503
504	// Remove a lock from the parachain.
505	fn remove_lock(id: ParaId) {
506		Paras::<T>::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(false)));
507	}
508
509	// Register a Para ID under control of `manager`.
510	//
511	// Note this is a backend registration API, so verification of ParaId
512	// is not done here to prevent.
513	fn register(
514		manager: T::AccountId,
515		id: ParaId,
516		genesis_head: HeadData,
517		validation_code: ValidationCode,
518	) -> DispatchResult {
519		Self::do_register(manager, None, id, genesis_head, validation_code, false)
520	}
521
522	// Deregister a Para ID, free any data, and return any deposits.
523	fn deregister(id: ParaId) -> DispatchResult {
524		Self::do_deregister(id)
525	}
526
527	// Upgrade a registered on-demand parachain into a lease holding parachain.
528	fn make_parachain(id: ParaId) -> DispatchResult {
529		// Para backend should think this is an on-demand parachain...
530		ensure!(
531			paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parathread),
532			Error::<T>::NotParathread
533		);
534		polkadot_runtime_parachains::schedule_parathread_upgrade::<T>(id)
535			.map_err(|_| Error::<T>::CannotUpgrade)?;
536
537		Ok(())
538	}
539
540	// Downgrade a registered para into a parathread (on-demand parachain).
541	fn make_parathread(id: ParaId) -> DispatchResult {
542		// Para backend should think this is a parachain...
543		ensure!(
544			paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parachain),
545			Error::<T>::NotParachain
546		);
547		polkadot_runtime_parachains::schedule_parachain_downgrade::<T>(id)
548			.map_err(|_| Error::<T>::CannotDowngrade)?;
549		Ok(())
550	}
551
552	#[cfg(any(feature = "runtime-benchmarks", test))]
553	fn worst_head_data() -> HeadData {
554		let max_head_size = configuration::ActiveConfig::<T>::get().max_head_data_size;
555		assert!(max_head_size > 0, "max_head_data can't be zero for generating worst head data.");
556		alloc::vec![0u8; max_head_size as usize].into()
557	}
558
559	#[cfg(any(feature = "runtime-benchmarks", test))]
560	fn worst_validation_code() -> ValidationCode {
561		let max_code_size = configuration::ActiveConfig::<T>::get().max_code_size;
562		assert!(max_code_size > 0, "max_code_size can't be zero for generating worst code data.");
563		let validation_code = alloc::vec![0u8; max_code_size as usize];
564		validation_code.into()
565	}
566
567	#[cfg(any(feature = "runtime-benchmarks", test))]
568	fn execute_pending_transitions() {
569		use polkadot_runtime_parachains::shared;
570		shared::Pallet::<T>::set_session_index(shared::Pallet::<T>::scheduled_session());
571		paras::Pallet::<T>::test_on_new_session();
572	}
573}
574
575/// Exposes this pallet's registry to a remote registration control plane.
576///
577/// Registration can be driven by another pallet โ€” typically on another trusted chain โ€” that
578/// owns the manager relationship and holds the deposit. This impl is the seam: it does the
579/// registry work and nothing else, so where the deposit lives and how the request arrived
580/// are outside this pallet's concern.
581///
582/// The trait is stated in plain `u32`/`Vec<u8>` so its definition carries no dependency on
583/// Polkadot's parachain primitives; conversion to [`ParaId`], [`HeadData`] and [`ValidationCode`]
584/// happens here.
585impl<T: Config> registrar_primitives::ParachainRegistrar for Pallet<T> {
586	type AccountId = T::AccountId;
587
588	fn check_onboarding(head_len: u32, code_len: u32) -> Result<(), ()> {
589		let config = configuration::ActiveConfig::<T>::get();
590		Self::validate_onboarding_sizes(&config, head_len as usize, code_len as usize)
591			.map_err(|_| ())
592	}
593
594	fn is_registered(para_id: u32) -> bool {
595		let id = ParaId::from(para_id);
596		Paras::<T>::contains_key(id) || paras::Pallet::<T>::lifecycle(id).is_some()
597	}
598
599	fn register(
600		manager: T::AccountId,
601		para_id: u32,
602		genesis_head: Vec<u8>,
603		validation_code: Vec<u8>,
604	) -> DispatchResult {
605		Self::do_register(
606			manager,
607			Some(BalanceOf::<T>::zero()),
608			ParaId::from(para_id),
609			HeadData(genesis_head),
610			ValidationCode(validation_code),
611			false,
612		)
613	}
614
615	fn deregister(_para_id: u32) -> DispatchResult {
616		// TODO(ahm-v2): deregister the para and clear its registry entry.
617		Err(Error::<T>::NotImplemented.into())
618	}
619
620	fn check_head_data(_head_len: u32) -> Result<(), ()> {
621		// TODO(ahm-v2): validate the head data length against the active configuration.
622		Err(())
623	}
624
625	fn set_current_head(_para_id: u32, _head: Vec<u8>) {
626		// TODO(ahm-v2): set the para's current head.
627	}
628
629	fn check_code_upgrade(_para_id: u32, _code_len: u32) -> Result<(), ()> {
630		// TODO(ahm-v2): validate the code length and that an upgrade may be scheduled now.
631		Err(())
632	}
633
634	fn schedule_code_upgrade(_para_id: u32, _validation_code: Vec<u8>) -> DispatchResult {
635		// TODO(ahm-v2): schedule the validation code upgrade.
636		Err(Error::<T>::NotImplemented.into())
637	}
638}
639
640impl<T: Config> Pallet<T> {
641	/// Ensure the origin is one of Root, the `para` owner, or the `para` itself.
642	/// If the origin is the `para` owner, the `para` must be unlocked.
643	fn ensure_root_para_or_owner(
644		origin: <T as frame_system::Config>::RuntimeOrigin,
645		id: ParaId,
646	) -> DispatchResult {
647		if let Ok(who) = ensure_signed(origin.clone()) {
648			let para_info = Paras::<T>::get(id).ok_or(Error::<T>::NotRegistered)?;
649
650			if para_info.manager == who {
651				ensure!(!para_info.is_locked(), Error::<T>::ParaLocked);
652				return Ok(());
653			}
654		}
655
656		Self::ensure_root_or_para(origin, id)
657	}
658
659	/// Ensure the origin is one of Root or the `para` itself.
660	fn ensure_root_or_para(
661		origin: <T as frame_system::Config>::RuntimeOrigin,
662		id: ParaId,
663	) -> DispatchResult {
664		if ensure_root(origin.clone()).is_ok() {
665			return Ok(());
666		}
667
668		let caller_id = ensure_parachain(<T as Config>::RuntimeOrigin::from(origin))?;
669		// Check if matching para id...
670		ensure!(caller_id == id, Error::<T>::NotOwner);
671
672		Ok(())
673	}
674
675	fn do_reserve(
676		who: T::AccountId,
677		deposit_override: Option<BalanceOf<T>>,
678		id: ParaId,
679	) -> DispatchResult {
680		ensure!(!Paras::<T>::contains_key(id), Error::<T>::AlreadyRegistered);
681		ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
682
683		let deposit = deposit_override.unwrap_or_else(T::ParaDeposit::get);
684		<T as Config>::Currency::reserve(&who, deposit)?;
685		let info = ParaInfo { manager: who.clone(), deposit, locked: None };
686
687		Paras::<T>::insert(id, info);
688		Self::deposit_event(Event::<T>::Reserved { para_id: id, who });
689		Ok(())
690	}
691
692	/// Attempt to register a new Para Id under management of `who` in the
693	/// system with the given information.
694	fn do_register(
695		who: T::AccountId,
696		deposit_override: Option<BalanceOf<T>>,
697		id: ParaId,
698		genesis_head: HeadData,
699		validation_code: ValidationCode,
700		ensure_reserved: bool,
701	) -> DispatchResult {
702		let deposited = if let Some(para_data) = Paras::<T>::get(id) {
703			ensure!(para_data.manager == who, Error::<T>::NotOwner);
704			ensure!(!para_data.is_locked(), Error::<T>::ParaLocked);
705			para_data.deposit
706		} else {
707			ensure!(!ensure_reserved, Error::<T>::NotReserved);
708			Default::default()
709		};
710		ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
711		let (genesis, deposit) =
712			Self::validate_onboarding_data(genesis_head, validation_code, ParaKind::Parathread)?;
713		let deposit = deposit_override.unwrap_or(deposit);
714
715		if let Some(additional) = deposit.checked_sub(&deposited) {
716			<T as Config>::Currency::reserve(&who, additional)?;
717		} else if let Some(rebate) = deposited.checked_sub(&deposit) {
718			<T as Config>::Currency::unreserve(&who, rebate);
719		};
720		let info = ParaInfo { manager: who.clone(), deposit, locked: None };
721
722		Paras::<T>::insert(id, info);
723		// We check above that para has no lifecycle, so this should not fail.
724		let res = polkadot_runtime_parachains::schedule_para_initialize::<T>(id, genesis);
725		debug_assert!(res.is_ok());
726		Self::deposit_event(Event::<T>::Registered { para_id: id, manager: who });
727		Ok(())
728	}
729
730	/// Deregister a Para Id, freeing all data returning any deposit.
731	fn do_deregister(id: ParaId) -> DispatchResult {
732		match paras::Pallet::<T>::lifecycle(id) {
733			// Para must be a parathread (on-demand parachain), or not exist at all.
734			Some(ParaLifecycle::Parathread) | None => {},
735			_ => return Err(Error::<T>::NotParathread.into()),
736		}
737		polkadot_runtime_parachains::schedule_para_cleanup::<T>(id)
738			.map_err(|_| Error::<T>::CannotDeregister)?;
739
740		if let Some(info) = Paras::<T>::take(&id) {
741			<T as Config>::Currency::unreserve(&info.manager, info.deposit);
742		}
743
744		PendingSwap::<T>::remove(id);
745		Self::deposit_event(Event::<T>::Deregistered { para_id: id });
746		Ok(())
747	}
748
749	/// Verifies the onboarding data is valid for a para.
750	///
751	/// Returns `ParaGenesisArgs` and the deposit needed for the data.
752	fn validate_onboarding_data(
753		genesis_head: HeadData,
754		validation_code: ValidationCode,
755		para_kind: ParaKind,
756	) -> Result<(ParaGenesisArgs, BalanceOf<T>), sp_runtime::DispatchError> {
757		let config = configuration::ActiveConfig::<T>::get();
758		Self::validate_onboarding_sizes(&config, genesis_head.0.len(), validation_code.0.len())?;
759
760		let per_byte_fee = T::DataDepositPerByte::get();
761		let deposit = T::ParaDeposit::get()
762			.saturating_add(per_byte_fee.saturating_mul((genesis_head.0.len() as u32).into()))
763			.saturating_add(per_byte_fee.saturating_mul(config.max_code_size.into()));
764
765		Ok((ParaGenesisArgs { genesis_head, validation_code, para_kind }, deposit))
766	}
767
768	/// Check onboarding head and code sizes against the given configuration.
769	fn validate_onboarding_sizes(
770		config: &configuration::HostConfiguration<BlockNumberFor<T>>,
771		head_len: usize,
772		code_len: usize,
773	) -> DispatchResult {
774		ensure!(code_len >= MIN_CODE_SIZE as usize, Error::<T>::InvalidCode);
775		ensure!(code_len <= config.max_code_size as usize, Error::<T>::CodeTooLarge);
776		ensure!(head_len <= config.max_head_data_size as usize, Error::<T>::HeadDataTooLarge);
777		Ok(())
778	}
779
780	/// Swap a lease holding parachain and parathread (on-demand parachain), which involves
781	/// scheduling an appropriate lifecycle update.
782	fn do_thread_and_chain_swap(to_downgrade: ParaId, to_upgrade: ParaId) {
783		let res1 = polkadot_runtime_parachains::schedule_parachain_downgrade::<T>(to_downgrade);
784		debug_assert!(res1.is_ok());
785		let res2 = polkadot_runtime_parachains::schedule_parathread_upgrade::<T>(to_upgrade);
786		debug_assert!(res2.is_ok());
787		T::OnSwap::on_swap(to_upgrade, to_downgrade);
788	}
789}
790
791impl<T: Config> OnNewHead for Pallet<T> {
792	fn on_new_head(id: ParaId, _head: &HeadData) -> Weight {
793		// mark the parachain locked if the locked value is not already set
794		let mut writes = 0;
795		if let Some(mut info) = Paras::<T>::get(id) {
796			if info.locked.is_none() {
797				info.locked = Some(true);
798				Paras::<T>::insert(id, info);
799				writes += 1;
800			}
801		}
802		T::DbWeight::get().reads_writes(1, writes)
803	}
804}
805
806#[cfg(test)]
807mod mock;
808
809#[cfg(test)]
810mod tests;
811
812#[cfg(feature = "runtime-benchmarks")]
813mod benchmarking;