1pub 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 pub(crate) manager: Account,
54 deposit: Balance,
56 locked: Option<bool>,
59}
60
61impl<Account, Balance> ParaInfo<Account, Balance> {
62 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 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 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;
125
126 type RuntimeOrigin: From<<Self as frame_system::Config>::RuntimeOrigin>
131 + Into<result::Result<Origin, <Self as Config>::RuntimeOrigin>>;
132
133 type Currency: ReservableCurrency<Self::AccountId>;
135
136 type OnSwap: crate::traits::OnSwap;
138
139 #[pallet::constant]
142 type ParaDeposit: Get<BalanceOf<Self>>;
143
144 #[pallet::constant]
146 type DataDepositPerByte: Get<BalanceOf<Self>>;
147
148 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 NotRegistered,
165 AlreadyRegistered,
167 NotOwner,
169 CodeTooLarge,
171 HeadDataTooLarge,
173 NotParachain,
175 NotParathread,
177 CannotDeregister,
179 CannotDowngrade,
181 CannotUpgrade,
183 ParaLocked,
186 NotReserved,
188 InvalidCode,
190 CannotSwap,
193 }
194
195 #[pallet::storage]
197 pub(super) type PendingSwap<T> = StorageMap<_, Twox64Concat, ParaId, ParaId>;
198
199 #[pallet::storage]
204 pub type Paras<T: Config> =
205 StorageMap<_, Twox64Concat, ParaId, ParaInfo<T::AccountId, BalanceOf<T>>>;
206
207 #[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 #[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 #[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 #[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 #[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 == other {
320 PendingSwap::<T>::remove(id);
321 return Ok(())
322 }
323
324 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 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 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 #[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 #[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 #[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 #[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 #[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 fn manager_of(id: ParaId) -> Option<T::AccountId> {
462 Some(Paras::<T>::get(id)?.manager)
463 }
464
465 fn parachains() -> Vec<ParaId> {
468 paras::Parachains::<T>::get()
469 }
470
471 fn is_parathread(id: ParaId) -> bool {
473 paras::Pallet::<T>::is_parathread(id)
474 }
475
476 fn is_parachain(id: ParaId) -> bool {
478 paras::Pallet::<T>::is_parachain(id)
479 }
480
481 fn apply_lock(id: ParaId) {
483 Paras::<T>::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(true)));
484 }
485
486 fn remove_lock(id: ParaId) {
488 Paras::<T>::mutate(id, |x| x.as_mut().map(|info| info.locked = Some(false)));
489 }
490
491 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 fn deregister(id: ParaId) -> DispatchResult {
506 Self::do_deregister(id)
507 }
508
509 fn make_parachain(id: ParaId) -> DispatchResult {
511 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 fn make_parathread(id: ParaId) -> DispatchResult {
524 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 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 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 ensure!(caller_id == id, Error::<T>::NotOwner);
584 } else {
585 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 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 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 fn do_deregister(id: ParaId) -> DispatchResult {
648 match paras::Pallet::<T>::lifecycle(id) {
649 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 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 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 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, ..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 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 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 assert!(!Parachains::is_parathread(para_id));
974 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 assert!(Parachains::is_parathread(para_id));
988 assert!(!Parachains::is_parachain(para_id));
989 assert_ok!(Registrar::make_parachain(para_id));
991 run_to_session(START_SESSION_INDEX + 4);
992 assert!(!Parachains::is_parathread(para_id));
994 assert!(Parachains::is_parachain(para_id));
995 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 assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id,));
1002 run_to_session(START_SESSION_INDEX + 8);
1003 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 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 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 run_to_session(2);
1126
1127 assert_ok!(Registrar::deregister(RuntimeOrigin::root(), para_id));
1128
1129 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 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 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 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 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 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 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 assert_ok!(Registrar::make_parachain(para_1));
1263
1264 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 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 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 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 assert_eq!(SwapData::get().get(¶_1).unwrap(), &1337);
1297 assert_eq!(SwapData::get().get(¶_2).unwrap(), &69);
1298
1299 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 assert_eq!(SwapData::get().get(¶_1).unwrap(), &69);
1310 assert_eq!(SwapData::get().get(¶_2).unwrap(), &1337);
1311
1312 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 assert_ok!(Registrar::make_parachain(para_3));
1328
1329 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 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 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 assert_eq!(SwapData::get().get(¶_3).unwrap(), &69);
1353 assert_eq!(SwapData::get().get(¶_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 Registrar::on_new_head(para_id, &Default::default());
1375
1376 assert_noop!(
1378 Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id),
1379 BadOrigin
1380 );
1381 assert_noop!(Registrar::remove_lock(RuntimeOrigin::signed(1), para_id), BadOrigin);
1383 assert_ok!(Registrar::remove_lock(para_origin(para_id), para_id));
1385 assert_ok!(Registrar::ensure_root_para_or_owner(RuntimeOrigin::signed(1), para_id));
1387
1388 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 assert!(!Parachains::is_parathread(para_1));
1406 assert!(!Parachains::is_parathread(para_2));
1407
1408 assert_noop!(
1410 Registrar::swap(RuntimeOrigin::root(), para_1, para_2),
1411 Error::<Test>::NotRegistered
1412 );
1413
1414 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 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 assert!(Parachains::is_parathread(para_1));
1443 assert!(Parachains::is_parathread(para_2));
1444
1445 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 assert_ok!(Registrar::make_parachain(para_1));
1455
1456 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 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 assert!(Parachains::is_parachain(para_1));
1476 assert!(Parachains::is_parathread(para_2));
1477
1478 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 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 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 assert_ok!(Registrar::make_parathread(para_2));
1507
1508 run_to_session(START_SESSION_INDEX + 7);
1509
1510 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 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 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 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 next_scheduled_session::<T>();
1643
1644 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 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}