paras_registrar.rs 36.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.

17
//! Pallet to handle parathread/parachain registration and related fund management.
18
19
20
21
//! In essence this is a simple wrapper around `paras`.

use sp_std::{prelude::*, result};
use frame_support::{
22
	ensure,
23
24
	dispatch::DispatchResult,
	traits::{Get, Currency, ReservableCurrency},
25
	pallet_prelude::Weight,
26
27
28
};
use frame_system::{self, ensure_root, ensure_signed};
use primitives::v1::{
29
	Id as ParaId, ValidationCode, HeadData, LOWEST_PUBLIC_ID,
30
31
32
33
34
35
};
use runtime_parachains::{
	paras::{
		self,
		ParaGenesisArgs,
	},
36
	configuration,
37
	ensure_parachain,
38
	Origin, ParaLifecycle,
39
40
};

41
42
use crate::traits::{Registrar, OnSwap};
use parity_scale_codec::{Encode, Decode};
43
use sp_runtime::{RuntimeDebug, traits::{Saturating, CheckedSub}};
44
pub use pallet::*;
45
46
47

#[derive(Encode, Decode, Clone, PartialEq, Eq, Default, RuntimeDebug)]
pub struct ParaInfo<Account, Balance> {
48
	/// The account that has placed a deposit for registering this para.
49
	pub(crate) manager: Account,
50
	/// The amount reserved by the `manager` account for the registration.
51
	deposit: Balance,
52
53
	/// Whether the para registration should be locked from being controlled by the manager.
	locked: bool,
54
55
}

56
type BalanceOf<T> =
57
	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
58

59
pub trait WeightInfo {
60
	fn reserve() -> Weight;
61
	fn register() -> Weight;
62
	fn force_register() -> Weight;
63
64
65
66
67
68
	fn deregister() -> Weight;
	fn swap() -> Weight;
}

pub struct TestWeightInfo;
impl WeightInfo for TestWeightInfo {
69
	fn reserve() -> Weight { 0 }
70
	fn register() -> Weight { 0 }
71
	fn force_register() -> Weight { 0 }
72
73
74
75
	fn deregister() -> Weight { 0 }
	fn swap() -> Weight { 0 }
}

76
77
78
79
80
#[frame_support::pallet]
pub mod pallet {
	use frame_support::pallet_prelude::*;
	use frame_system::pallet_prelude::*;
	use super::*;
81

82
83
84
	#[pallet::pallet]
	#[pallet::generate_store(pub(super) trait Store)]
	pub struct Pallet<T>(_);
85

86
87
	#[pallet::config]
	#[pallet::disable_frame_system_supertrait_check]
88
	pub trait Config: configuration::Config + paras::Config {
89
90
		/// The overarching event type.
		type Event: From<Event<Self>> + IsType<<Self as frame_system::Config>::Event>;
91

92
93
94
95
96
97
		/// The aggregated origin type must support the `parachains` origin. We require that we can
		/// infallibly convert between this origin and the system origin, but in reality, they're the
		/// same type, we just can't express that to the Rust type system without writing a `where`
		/// clause everywhere.
		type Origin: From<<Self as frame_system::Config>::Origin>
			+ Into<result::Result<Origin, <Self as Config>::Origin>>;
98

99
100
		/// The system's currency for parathread payment.
		type Currency: ReservableCurrency<Self::AccountId>;
101

102
103
		/// Runtime hook for when a parachain and parathread swap.
		type OnSwap: crate::traits::OnSwap;
104

105
106
107
108
		/// The deposit to be paid to run a parathread.
		/// This should include the cost for storing the genesis head and validation code.
		#[pallet::constant]
		type ParaDeposit: Get<BalanceOf<Self>>;
109

110
111
112
		/// The deposit to be paid per byte stored on chain.
		#[pallet::constant]
		type DataDepositPerByte: Get<BalanceOf<Self>>;
113

114
115
		/// Weight Information for the Extrinsics in the Pallet
		type WeightInfo: WeightInfo;
116
	}
117

118
119
120
121
122
	#[pallet::event]
	#[pallet::generate_deposit(pub(super) fn deposit_event)]
	#[pallet::metadata(T::AccountId = "AccountId")]
	pub enum Event<T: Config> {
		Registered(ParaId, T::AccountId),
123
		Deregistered(ParaId),
124
		Reserved(ParaId, T::AccountId),
125
126
	}

127
128
	#[pallet::error]
	pub enum Error<T> {
129
130
131
132
133
134
		/// The ID is not registered.
		NotRegistered,
		/// The ID is already registered.
		AlreadyRegistered,
		/// The caller is not the owner of this Id.
		NotOwner,
135
136
137
138
		/// Invalid para code size.
		CodeTooLarge,
		/// Invalid para head data size.
		HeadDataTooLarge,
139
140
141
142
		/// Para is not a Parachain.
		NotParachain,
		/// Para is not a Parathread.
		NotParathread,
143
144
		/// Cannot deregister para
		CannotDeregister,
145
146
147
148
		/// Cannot schedule downgrade of parachain to parathread
		CannotDowngrade,
		/// Cannot schedule upgrade of parathread to parachain
		CannotUpgrade,
149
150
		/// Para is locked from manipulation by the manager. Must use parachain or relay chain governance.
		ParaLocked,
151
152
		/// The ID given for registration has not been reserved.
		NotReserved,
153
154
	}

155
156
157
158
159
160
161
162
163
164
	/// Pending swap operations.
	#[pallet::storage]
	pub(super) type PendingSwap<T> = StorageMap<_, Twox64Concat, ParaId, ParaId>;

	/// Amount held on deposit for each para and the original depositor.
	///
	/// The given account ID is responsible for registering the code and initial head data, but may only do
	/// so if it isn't yet registered. (After that, it's up to governance to do so.)
	#[pallet::storage]
	pub type Paras<T: Config> = StorageMap<_, Twox64Concat, ParaId, ParaInfo<T::AccountId, BalanceOf<T>>>;
165

166
167
168
	/// The next free `ParaId`.
	#[pallet::storage]
	pub type NextFreeParaId<T> = StorageValue<_, ParaId, ValueQuery>;
169

170
171
	#[pallet::hooks]
	impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {}
172

173
174
	#[pallet::call]
	impl<T: Config> Pallet<T> {
175
		/// Register head data and validation code for a reserved Para Id.
176
		///
177
178
179
180
181
		/// ## Arguments
		/// - `origin`: Must be called by a `Signed` origin.
		/// - `id`: The para ID. Must be owned/managed by the `origin` signing account.
		/// - `genesis_head`: The genesis head data of the parachain/thread.
		/// - `validation_code`: The initial validation code of the parachain/thread.
182
		///
183
184
185
		/// ## Deposits/Fees
		/// The origin signed account must reserve a corresponding deposit for the registration. Anything already
		/// reserved previously for this para ID is accounted for.
186
		///
187
188
		/// ## Events
		/// The `Registered` event is emitted in case of success.
189
		#[pallet::weight(T::WeightInfo::register())]
190
		pub fn register(
191
			origin: OriginFor<T>,
192
193
194
195
196
			id: ParaId,
			genesis_head: HeadData,
			validation_code: ValidationCode,
		) -> DispatchResult {
			let who = ensure_signed(origin)?;
197
			Self::do_register(who, None, id, genesis_head, validation_code, true)?;
198
			Ok(())
199
200
201
202
203
204
205
206
		}

		/// Force the registration of a Para Id on the relay chain.
		///
		/// This function must be called by a Root origin.
		///
		/// The deposit taken can be specified for this registration. Any ParaId
		/// can be registered, including sub-1000 IDs which are System Parachains.
207
		#[pallet::weight(T::WeightInfo::force_register())]
208
		pub fn force_register(
209
			origin: OriginFor<T>,
210
211
212
213
214
215
216
			who: T::AccountId,
			deposit: BalanceOf<T>,
			id: ParaId,
			genesis_head: HeadData,
			validation_code: ValidationCode,
		) -> DispatchResult {
			ensure_root(origin)?;
217
			Self::do_register(who, Some(deposit), id, genesis_head, validation_code, false)
218
219
		}

220
		/// Deregister a Para Id, freeing all data and returning any deposit.
221
		///
222
		/// The caller must be Root, the `para` owner, or the `para` itself. The para must be a parathread.
223
224
		#[pallet::weight(T::WeightInfo::deregister())]
		pub fn deregister(origin: OriginFor<T>, id: ParaId) -> DispatchResult {
225
			Self::ensure_root_para_or_owner(origin, id)?;
226
			Self::do_deregister(id)
227
228
		}

229
230
231
232
		/// Swap a parachain with another parachain or parathread.
		///
		/// The origin must be Root, the `para` owner, or the `para` itself.
		///
233
234
235
236
237
238
239
		/// The swap will happen only if there is already an opposite swap pending. If there is not,
		/// the swap will be stored in the pending swaps map, ready for a later confirmatory swap.
		///
		/// The `ParaId`s remain mapped to the same head data and code so external code can rely on
		/// `ParaId` to be a long-term identifier of a notional "parachain". However, their
		/// scheduling info (i.e. whether they're a parathread or parachain), auction information
		/// and the auction deposit are switched.
240
241
		#[pallet::weight(T::WeightInfo::swap())]
		pub fn swap(origin: OriginFor<T>, id: ParaId, other: ParaId) -> DispatchResult {
242
243
			Self::ensure_root_para_or_owner(origin, id)?;

244
245
246
			if PendingSwap::<T>::get(other) == Some(id) {
				if let Some(other_lifecycle) = paras::Pallet::<T>::lifecycle(other) {
					if let Some(id_lifecycle) = paras::Pallet::<T>::lifecycle(id) {
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
						// identify which is a parachain and which is a parathread
						if id_lifecycle.is_parachain() && other_lifecycle.is_parathread() {
							// We check that both paras are in an appropriate lifecycle for a swap,
							// so these should never fail.
							let res1 = runtime_parachains::schedule_parachain_downgrade::<T>(id);
							debug_assert!(res1.is_ok());
							let res2 = runtime_parachains::schedule_parathread_upgrade::<T>(other);
							debug_assert!(res2.is_ok());
							T::OnSwap::on_swap(id, other);
						} else if id_lifecycle.is_parathread() && other_lifecycle.is_parachain() {
							// We check that both paras are in an appropriate lifecycle for a swap,
							// so these should never fail.
							let res1 = runtime_parachains::schedule_parachain_downgrade::<T>(other);
							debug_assert!(res1.is_ok());
							let res2 = runtime_parachains::schedule_parathread_upgrade::<T>(id);
							debug_assert!(res2.is_ok());
							T::OnSwap::on_swap(id, other);
						}

266
						PendingSwap::<T>::remove(other);
267
268
					}
				}
269
			} else {
270
				PendingSwap::<T>::insert(id, other);
271
			}
272
273

			Ok(())
274
		}
275
276
277
278
279

		/// Remove a manager lock from a para. This will allow the manager of a
		/// previously locked para to deregister or swap a para without using governance.
		///
		/// Can only be called by the Root origin.
280
		#[pallet::weight(T::DbWeight::get().reads_writes(1, 1))]
281
		pub fn force_remove_lock(origin: OriginFor<T>, para: ParaId) -> DispatchResult {
282
283
			ensure_root(origin)?;
			Self::remove_lock(para);
284
			Ok(())
285
		}
286

287
		/// Reserve a Para Id on the relay chain.
288
		///
289
290
291
		/// This function will reserve a new Para Id to be owned/managed by the origin account.
		/// The origin account is able to register head data and validation code using `register` to create
		/// a parathread. Using the Slots pallet, a parathread can then be upgraded to get a parachain slot.
292
		///
293
294
		/// ## Arguments
		/// - `origin`: Must be called by a `Signed` origin. Becomes the manager/owner of the new para ID.
295
		///
296
297
298
299
300
		/// ## Deposits/Fees
		/// The origin must reserve a deposit of `ParaDeposit` for the registration.
		///
		/// ## Events
		/// The `Reserved` event is emitted in case of success, which provides the ID reserved for use.
301
302
		#[pallet::weight(T::WeightInfo::reserve())]
		pub fn reserve(origin: OriginFor<T>) -> DispatchResult {
303
			let who = ensure_signed(origin)?;
304
			let id = NextFreeParaId::<T>::get().max(LOWEST_PUBLIC_ID);
305
			Self::do_reserve(who, None, id)?;
306
			NextFreeParaId::<T>::set(id + 1);
307
308
			Ok(())
		}
309
310
311
	}
}

312
impl<T: Config> Registrar for Pallet<T> {
313
314
315
316
317
318
319
320
321
	type AccountId = T::AccountId;

	/// Return the manager `AccountId` of a para if one exists.
	fn manager_of(id: ParaId) -> Option<T::AccountId> {
		Some(Paras::<T>::get(id)?.manager)
	}

	// All parachains. Ordered ascending by ParaId. Parathreads are not included.
	fn parachains() -> Vec<ParaId> {
322
		paras::Pallet::<T>::parachains()
323
324
325
326
	}

	// Return if a para is a parathread
	fn is_parathread(id: ParaId) -> bool {
327
		paras::Pallet::<T>::is_parathread(id)
328
329
330
331
	}

	// Return if a para is a parachain
	fn is_parachain(id: ParaId) -> bool {
332
		paras::Pallet::<T>::is_parachain(id)
333
334
	}

335
336
337
338
339
340
341
342
343
344
	// Apply a lock to the parachain.
	fn apply_lock(id: ParaId) {
		Paras::<T>::mutate(id, |x| x.as_mut().map(|mut info| info.locked = true));
	}

	// Apply a lock to the parachain.
	fn remove_lock(id: ParaId) {
		Paras::<T>::mutate(id, |x| x.as_mut().map(|mut info| info.locked = false));
	}

345
	// Register a Para ID under control of `manager`.
346
347
348
	//
	// Note this is a backend registration api, so verification of ParaId
	// is not done here to prevent.
349
350
	fn register(
		manager: T::AccountId,
351
352
353
354
		id: ParaId,
		genesis_head: HeadData,
		validation_code: ValidationCode,
	) -> DispatchResult {
355
		Self::do_register(manager, None, id, genesis_head, validation_code, false)
356
	}
357

358
359
360
361
	// Deregister a Para ID, free any data, and return any deposits.
	fn deregister(id: ParaId) -> DispatchResult {
		Self::do_deregister(id)
	}
362

363
364
365
	// Upgrade a registered parathread into a parachain.
	fn make_parachain(id: ParaId) -> DispatchResult {
		// Para backend should think this is a parathread...
366
		ensure!(paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parathread), Error::<T>::NotParathread);
367
		runtime_parachains::schedule_parathread_upgrade::<T>(id).map_err(|_| Error::<T>::CannotUpgrade)?;
368
369
370
		// Once a para has upgraded to a parachain, it can no longer be managed by the owner.
		// Intentionally, the flag stays with the para even after downgrade.
		Self::apply_lock(id);
371
372
		Ok(())
	}
373

374
375
376
	// Downgrade a registered para into a parathread.
	fn make_parathread(id: ParaId) -> DispatchResult {
		// Para backend should think this is a parachain...
377
		ensure!(paras::Pallet::<T>::lifecycle(id) == Some(ParaLifecycle::Parachain), Error::<T>::NotParachain);
378
		runtime_parachains::schedule_parachain_downgrade::<T>(id).map_err(|_| Error::<T>::CannotDowngrade)?;
379
380
381
		Ok(())
	}

382
383
	#[cfg(any(feature = "runtime-benchmarks", test))]
	fn worst_head_data() -> HeadData {
384
385
		let max_head_size = configuration::Pallet::<T>::config().max_head_data_size;
		assert!(max_head_size > 0, "max_head_data can't be zero for generating worst head data.");
386
387
		vec![0u8; max_head_size as usize].into()
	}
388

389
390
	#[cfg(any(feature = "runtime-benchmarks", test))]
	fn worst_validation_code() -> ValidationCode {
391
392
		let max_code_size = configuration::Pallet::<T>::config().max_code_size;
		assert!(max_code_size > 0, "max_code_size can't be zero for generating worst code data.");
asynchronous rob's avatar
asynchronous rob committed
393
		let validation_code = vec![0u8; max_code_size as usize];
394
395
		validation_code.into()
	}
396

397
398
399
	#[cfg(any(feature = "runtime-benchmarks", test))]
	fn execute_pending_transitions() {
		use runtime_parachains::shared;
400
401
		shared::Pallet::<T>::set_session_index(
			shared::Pallet::<T>::scheduled_session()
402
		);
403
		paras::Pallet::<T>::test_on_new_session();
404
405
406
	}
}

407
impl<T: Config> Pallet<T> {
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
	/// Ensure the origin is one of Root, the `para` owner, or the `para` itself.
	/// If the origin is the `para` owner, the `para` must be unlocked.
	fn ensure_root_para_or_owner(origin: <T as frame_system::Config>::Origin, id: ParaId) -> DispatchResult {
		ensure_signed(origin.clone()).map_err(|e| e.into())
		.and_then(|who| -> DispatchResult {
			let para_info = Paras::<T>::get(id).ok_or(Error::<T>::NotRegistered)?;
			ensure!(!para_info.locked, Error::<T>::ParaLocked);
			ensure!(para_info.manager == who, Error::<T>::NotOwner);
			Ok(())
		})
		.or_else(|_| -> DispatchResult {
			// Else check if para origin...
			let caller_id = ensure_parachain(<T as Config>::Origin::from(origin.clone()))?;
			ensure!(caller_id == id, Error::<T>::NotOwner);
			Ok(())
		}).or_else(|_| -> DispatchResult {
			// Check if root...
			ensure_root(origin.clone()).map_err(|e| e.into())
		})
	}

429
430
431
432
433
434
	fn do_reserve(
		who: T::AccountId,
		deposit_override: Option<BalanceOf<T>>,
		id: ParaId,
	) -> DispatchResult {
		ensure!(!Paras::<T>::contains_key(id), Error::<T>::AlreadyRegistered);
435
		ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
436
437
438
439
440
441
442
443
444
445

		let deposit = deposit_override.unwrap_or_else(T::ParaDeposit::get);
		<T as Config>::Currency::reserve(&who, deposit)?;
		let info = ParaInfo {
			manager: who.clone(),
			deposit,
			locked: false,
		};

		Paras::<T>::insert(id, info);
446
		Self::deposit_event(Event::<T>::Reserved(id, who));
447
448
449
		Ok(())
	}

450
451
452
453
	/// Attempt to register a new Para Id under management of `who` in the
	/// system with the given information.
	fn do_register(
		who: T::AccountId,
454
		deposit_override: Option<BalanceOf<T>>,
455
456
457
		id: ParaId,
		genesis_head: HeadData,
		validation_code: ValidationCode,
458
		ensure_reserved: bool,
459
	) -> DispatchResult {
460
461
462
463
464
465
466
467
		let deposited = if let Some(para_data) = Paras::<T>::get(id) {
			ensure!(para_data.manager == who, Error::<T>::NotOwner);
			ensure!(!para_data.locked, Error::<T>::ParaLocked);
			para_data.deposit
		} else {
			ensure!(!ensure_reserved, Error::<T>::NotReserved);
			Default::default()
		};
468
		ensure!(paras::Pallet::<T>::lifecycle(id).is_none(), Error::<T>::AlreadyRegistered);
469
470
471
472
473
		let (genesis, deposit) = Self::validate_onboarding_data(
			genesis_head,
			validation_code,
			false
		)?;
474
		let deposit = deposit_override.unwrap_or(deposit);
475
476
477
478
479
480

		if let Some(additional) = deposit.checked_sub(&deposited) {
			<T as Config>::Currency::reserve(&who, additional)?;
		} else if let Some(rebate) = deposited.checked_sub(&deposit) {
			<T as Config>::Currency::unreserve(&who, rebate);
		};
481
482
		let info = ParaInfo {
			manager: who.clone(),
483
			deposit,
484
			locked: false,
485
486
487
488
489
490
		};

		Paras::<T>::insert(id, info);
		// We check above that para has no lifecycle, so this should not fail.
		let res = runtime_parachains::schedule_para_initialize::<T>(id, genesis);
		debug_assert!(res.is_ok());
491
		Self::deposit_event(Event::<T>::Registered(id, who));
492
493
494
495
496
		Ok(())
	}

	/// Deregister a Para Id, freeing all data returning any deposit.
	fn do_deregister(id: ParaId) -> DispatchResult {
497
		match paras::Pallet::<T>::lifecycle(id) {
498
499
500
501
			// Para must be a parathread, or not exist at all.
			Some(ParaLifecycle::Parathread) | None => {},
			_ => return Err(Error::<T>::NotParathread.into())
		}
502
		runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CannotDeregister)?;
503

504
505
506
507
		if let Some(info) = Paras::<T>::take(&id) {
			<T as Config>::Currency::unreserve(&info.manager, info.deposit);
		}

508
509
		PendingSwap::<T>::remove(id);
		Self::deposit_event(Event::<T>::Deregistered(id));
510
511
		Ok(())
	}
512
513
514
515
516
517
518
519
520

	/// Verifies the onboarding data is valid for a para.
	///
	/// Returns `ParaGenesisArgs` and the deposit needed for the data.
	fn validate_onboarding_data(
		genesis_head: HeadData,
		validation_code: ValidationCode,
		parachain: bool,
	) -> Result<(ParaGenesisArgs, BalanceOf<T>), sp_runtime::DispatchError> {
521
522
523
		let config = configuration::Pallet::<T>::config();
		ensure!(validation_code.0.len() <= config.max_code_size as usize, Error::<T>::CodeTooLarge);
		ensure!(genesis_head.0.len() <= config.max_head_data_size as usize, Error::<T>::HeadDataTooLarge);
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538

		let per_byte_fee = T::DataDepositPerByte::get();
		let deposit = T::ParaDeposit::get()
			.saturating_add(
				per_byte_fee.saturating_mul((genesis_head.0.len() as u32).into())
			).saturating_add(
				per_byte_fee.saturating_mul((validation_code.0.len() as u32).into())
			);

		Ok((ParaGenesisArgs {
			genesis_head,
			validation_code,
			parachain,
		}, deposit))
	}
539
540
541
542
543
544
545
546
547
}

#[cfg(test)]
mod tests {
	use super::*;
	use sp_io::TestExternalities;
	use sp_core::H256;
	use sp_runtime::{
		traits::{
548
549
			BlakeTwo256, IdentityLookup,
		}, Perbill,
550
	};
551
	use primitives::v1::{Balance, BlockNumber, Header};
552
	use frame_system::limits;
553
	use frame_support::{
554
		traits::{OnInitialize, OnFinalize},
555
		assert_ok, assert_noop, parameter_types,
556
		error::BadOrigin,
557
	};
558
559
560
	use runtime_parachains::{configuration, shared};
	use pallet_balances::Error as BalancesError;
	use crate::traits::Registrar as RegistrarTrait;
561
562
563
564
565
566
567
568
569
570
571
	use crate::paras_registrar;

	type UncheckedExtrinsic = frame_system::mocking::MockUncheckedExtrinsic<Test>;
	type Block = frame_system::mocking::MockBlock<Test>;

	frame_support::construct_runtime!(
		pub enum Test where
			Block = Block,
			NodeBlock = Block,
			UncheckedExtrinsic = UncheckedExtrinsic,
		{
572
573
			System: frame_system::{Pallet, Call, Config, Storage, Event<T>},
			Balances: pallet_balances::{Pallet, Call, Storage, Config<T>, Event<T>},
574
			ParachainsConfiguration: configuration::{Pallet, Call, Storage, Config<T>},
575
			Parachains: paras::{Pallet, Origin, Call, Storage, Config<T>, Event},
576
			Registrar: paras_registrar::{Pallet, Call, Storage, Event<T>},
577
		}
578
	);
579

580
	const NORMAL_RATIO: Perbill = Perbill::from_percent(75);
581
582
	parameter_types! {
		pub const BlockHashCount: u32 = 250;
583
		pub BlockWeights: limits::BlockWeights =
584
			frame_system::limits::BlockWeights::simple_max(1024);
585
586
		pub BlockLength: limits::BlockLength =
			limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO);
587
588
	}

589
	impl frame_system::Config for Test {
590
591
592
593
594
595
596
597
598
599
		type BaseCallFilter = ();
		type Origin = Origin;
		type Call = Call;
		type Index = u64;
		type BlockNumber = BlockNumber;
		type Hash = H256;
		type Hashing = BlakeTwo256;
		type AccountId = u64;
		type Lookup = IdentityLookup<u64>;
		type Header = Header;
600
		type Event = Event;
601
602
		type BlockHashCount = BlockHashCount;
		type DbWeight = ();
603
604
		type BlockWeights = BlockWeights;
		type BlockLength = BlockLength;
605
		type Version = ();
606
		type PalletInfo = PalletInfo;
607
608
		type AccountData = pallet_balances::AccountData<u128>;
		type OnNewAccount = ();
609
		type OnKilledAccount = ();
610
		type SystemWeightInfo = ();
611
		type SS58Prefix = ();
612
		type OnSetCode = ();
613
614
615
616
617
618
	}

	parameter_types! {
		pub const ExistentialDeposit: Balance = 1;
	}

619
	impl pallet_balances::Config for Test {
620
621
		type Balance = u128;
		type DustRemoval = ();
622
		type Event = Event;
623
624
625
		type ExistentialDeposit = ExistentialDeposit;
		type AccountStore = System;
		type MaxLocks = ();
Gavin Wood's avatar
Gavin Wood committed
626
627
		type MaxReserves = ();
		type ReserveIdentifier = [u8; 8];
628
629
630
		type WeightInfo = ();
	}

631
632
	impl shared::Config for Test {}

633
	impl paras::Config for Test {
634
		type Origin = Origin;
635
		type Event = Event;
636
637
	}

638
	impl configuration::Config for Test { }
639
640

	parameter_types! {
641
642
		pub const ParaDeposit: Balance = 10;
		pub const DataDepositPerByte: Balance = 1;
643
644
645
646
		pub const QueueSize: usize = 2;
		pub const MaxRetries: u32 = 3;
	}

647
	impl Config for Test {
648
		type Event = Event;
649
		type Origin = Origin;
650
651
652
653
654
		type Currency = Balances;
		type OnSwap = ();
		type ParaDeposit = ParaDeposit;
		type DataDepositPerByte = DataDepositPerByte;
		type WeightInfo = TestWeightInfo;
655
656
	}

657
	pub fn new_test_ext() -> TestExternalities {
658
659
		let mut t = frame_system::GenesisConfig::default().build_storage::<Test>().unwrap();

660
661
662
663
664
665
666
667
		configuration::GenesisConfig::<Test> {
			config: configuration::HostConfiguration {
				max_code_size: 2 * 1024 * 1024, // 2 MB
				max_head_data_size: 1 * 1024 * 1024, // 1 MB
				..Default::default()
			},
		}.assimilate_storage(&mut t).unwrap();

668
		pallet_balances::GenesisConfig::<Test> {
669
			balances: vec![(1, 10_000_000), (2, 10_000_000)],
670
671
672
673
674
		}.assimilate_storage(&mut t).unwrap();

		t.into()
	}

675
676
	const BLOCKS_PER_SESSION: u32 = 3;

677
	fn run_to_block(n: BlockNumber) {
678
		// NOTE that this function only simulates modules of interest. Depending on new pallet may
679
		// require adding it here.
680
		assert!(System::block_number() < n);
681
682
683
684
685
686
687
		while System::block_number() < n {
			let b = System::block_number();

			if System::block_number() > 1 {
				System::on_finalize(System::block_number());
			}
			// Session change every 3 blocks.
688
			if (b + 1) % BLOCKS_PER_SESSION == 0 {
689
690
				shared::Pallet::<Test>::set_session_index(
					shared::Pallet::<Test>::session_index() + 1
691
				);
692
				Parachains::test_on_new_session();
693
694
			}
			System::set_block_number(b + 1);
695
			System::on_initialize(System::block_number());
696
697
698
		}
	}

699
700
701
702
703
704
705
706
707
708
	fn run_to_session(n: BlockNumber) {
		let block_number = n * BLOCKS_PER_SESSION;
		run_to_block(block_number);
	}

	fn test_genesis_head(size: usize) -> HeadData {
		HeadData(vec![0u8; size])
	}

	fn test_validation_code(size: usize) -> ValidationCode {
asynchronous rob's avatar
asynchronous rob committed
709
		let validation_code = vec![0u8; size as usize];
710
711
712
713
714
715
716
		ValidationCode(validation_code)
	}

	fn para_origin(id: ParaId) -> Origin {
		runtime_parachains::Origin::Parachain(id).into()
	}

717
718
719
720
721
722
723
724
	fn max_code_size() -> u32 {
		ParachainsConfiguration::config().max_code_size
	}

	fn max_head_size() -> u32 {
		ParachainsConfiguration::config().max_head_data_size
	}

725
726
727
	#[test]
	fn basic_setup_works() {
		new_test_ext().execute_with(|| {
728
			assert_eq!(PendingSwap::<Test>::get(&ParaId::from(0u32)), None);
729
			assert_eq!(Paras::<Test>::get(&ParaId::from(0u32)), None);
730
731
732
733
		});
	}

	#[test]
734
	fn end_to_end_scenario_works() {
735
		new_test_ext().execute_with(|| {
736
			let para_id = LOWEST_PUBLIC_ID;
737
			run_to_block(1);
738
739
			// first para is not yet registered
			assert!(!Parachains::is_parathread(para_id));
740
			// We register the Para ID
741
			assert_ok!(Registrar::reserve(Origin::signed(1)));
742
743
			assert_ok!(Registrar::register(
				Origin::signed(1),
744
				para_id,
745
746
747
748
749
				test_genesis_head(32),
				test_validation_code(32),
			));
			run_to_session(2);
			// It is now a parathread.
750
751
			assert!(Parachains::is_parathread(para_id));
			assert!(!Parachains::is_parachain(para_id));
752
			// Some other external process will elevate parathread to parachain
753
			assert_ok!(Registrar::make_parachain(para_id));
754
755
			run_to_session(4);
			// It is now a parachain.
756
757
			assert!(!Parachains::is_parathread(para_id));
			assert!(Parachains::is_parachain(para_id));
758
			// Turn it back into a parathread
759
			assert_ok!(Registrar::make_parathread(para_id));
760
			run_to_session(6);
761
762
			assert!(Parachains::is_parathread(para_id));
			assert!(!Parachains::is_parachain(para_id));
763
764
			// Deregister it
			assert_ok!(Registrar::deregister(
765
				Origin::root(),
766
				para_id,
767
			));
768
769
			run_to_session(8);
			// It is nothing
770
771
			assert!(!Parachains::is_parathread(para_id));
			assert!(!Parachains::is_parachain(para_id));
772
773
		});
	}
774

775
776
777
778
	#[test]
	fn register_works() {
		new_test_ext().execute_with(|| {
			run_to_block(1);
779
780
			let para_id = LOWEST_PUBLIC_ID;
			assert!(!Parachains::is_parathread(para_id));
781
782
			assert_ok!(Registrar::reserve(Origin::signed(1)));
			assert_eq!(Balances::reserved_balance(&1), <Test as Config>::ParaDeposit::get());
783
784
			assert_ok!(Registrar::register(
				Origin::signed(1),
785
				para_id,
786
787
				test_genesis_head(32),
				test_validation_code(32),
788
			));
789
			run_to_session(2);
790
			assert!(Parachains::is_parathread(para_id));
791
792
793
794
795
796
			assert_eq!(
				Balances::reserved_balance(&1),
				<Test as Config>::ParaDeposit::get() + 64 * <Test as Config>::DataDepositPerByte::get()
			);
		});
	}
797

798
799
800
	#[test]
	fn register_handles_basic_errors() {
		new_test_ext().execute_with(|| {
801
802
			let para_id = LOWEST_PUBLIC_ID;

803
			assert_noop!(Registrar::register(
804
				Origin::signed(1),
805
				para_id,
806
807
				test_genesis_head(max_head_size() as usize),
				test_validation_code(max_code_size() as usize),
808
			), Error::<Test>::NotReserved);
809

810
			// Successfully register para
811
812
813
814
815
			assert_ok!(Registrar::reserve(Origin::signed(1)));

			assert_noop!(Registrar::register(
				Origin::signed(2),
				para_id,
816
817
				test_genesis_head(max_head_size() as usize),
				test_validation_code(max_code_size() as usize),
818
819
			), Error::<Test>::NotOwner);

820
821
			assert_ok!(Registrar::register(
				Origin::signed(1),
822
				para_id,
823
824
				test_genesis_head(max_head_size() as usize),
				test_validation_code(max_code_size() as usize),
825
826
			));

827
			run_to_session(2);
828

829
			assert_ok!(Registrar::deregister(Origin::root(), para_id));
830

831
			// Can't do it again
832
833
			assert_noop!(Registrar::register(
				Origin::signed(1),
834
				para_id,
835
836
				test_genesis_head(max_head_size() as usize),
				test_validation_code(max_code_size() as usize),
837
			), Error::<Test>::NotReserved);
838
839

			// Head Size Check
840
			assert_ok!(Registrar::reserve(Origin::signed(2)));
841
842
			assert_noop!(Registrar::register(
				Origin::signed(2),
843
				para_id + 1,
844
845
				test_genesis_head((max_head_size() + 1) as usize),
				test_validation_code(max_code_size() as usize),
846
847
848
849
850
			), Error::<Test>::HeadDataTooLarge);

			// Code Size Check
			assert_noop!(Registrar::register(
				Origin::signed(2),
851
				para_id + 1,
852
853
				test_genesis_head(max_head_size() as usize),
				test_validation_code((max_code_size() + 1) as usize),
854
855
856
			), Error::<Test>::CodeTooLarge);

			// Needs enough funds for deposit
857
			assert_noop!(Registrar::reserve(Origin::signed(1337)), BalancesError::<Test, _>::InsufficientBalance);
858
859
860
861
		});
	}

	#[test]
862
	fn deregister_works() {
863
864
		new_test_ext().execute_with(|| {
			run_to_block(1);
865
866
			let para_id = LOWEST_PUBLIC_ID;
			assert!(!Parachains::is_parathread(para_id));
867
			assert_ok!(Registrar::reserve(Origin::signed(1)));
868
869
			assert_ok!(Registrar::register(
				Origin::signed(1),
870
				para_id,
871
872
873
874
				test_genesis_head(32),
				test_validation_code(32),
			));
			run_to_session(2);
875
			assert!(Parachains::is_parathread(para_id));
876
			assert_ok!(Registrar::deregister(
877
				Origin::root(),
878
				para_id,
879
			));
880
			run_to_session(4);
881
			assert!(paras::Pallet::<Test>::lifecycle(para_id).is_none());
882
883
884
			assert_eq!(Balances::reserved_balance(&1), 0);
		});
	}
885

886
887
888
889
	#[test]
	fn deregister_handles_basic_errors() {
		new_test_ext().execute_with(|| {
			run_to_block(1);
890
891
			let para_id = LOWEST_PUBLIC_ID;
			assert!(!Parachains::is_parathread(para_id));
892
			assert_ok!(Registrar::reserve(Origin::signed(1)));
893
			assert_ok!(Registrar::register(
894
				Origin::signed(1),
895
				para_id,
896
897
				test_genesis_head(32),
				test_validation_code(32),
898
			));
899
			run_to_session(2);
900
			assert!(Parachains::is_parathread(para_id));
901
			// Owner check
902
			assert_noop!(Registrar::deregister(
903
				Origin::signed(2),
904
				para_id,
905
			), BadOrigin);
906
			assert_ok!(Registrar::make_parachain(para_id));
907
908
909
910
			run_to_session(4);
			// Cant directly deregister parachain
			assert_noop!(Registrar::deregister(
				Origin::root(),
911
				para_id,
912
913
914
			), Error::<Test>::NotParathread);
		});
	}
915

916
917
918
	#[test]
	fn swap_works() {
		new_test_ext().execute_with(|| {
919
920
921
			// Successfully register first two parachains
			let para_1 = LOWEST_PUBLIC_ID;
			let para_2 = LOWEST_PUBLIC_ID + 1;
922
			assert_ok!(Registrar::reserve(Origin::signed(1)));
923
924
			assert_ok!(Registrar::register(
				Origin::signed(1),
925
				para_1,
926
927
				test_genesis_head(max_head_size() as usize),
				test_validation_code(max_code_size() as usize),
928
			));
929
			assert_ok!(Registrar::reserve(Origin::signed(2)));
930
931
			assert_ok!(Registrar::register(
				Origin::signed(2),
932
				para_2,
933
934
				test_genesis_head(max_head_size() as usize),
				test_validation_code(max_code_size() as usize),
935
936
937
			));
			run_to_session(2);

938
			// Upgrade 1023 into a parachain
939
			assert_ok!(Registrar::make_parachain(para_1));
940

941
			run_to_session(4);
942

943
			// Roles are as we expect
944
945
946
947
			assert!(Parachains::is_parachain(para_1));
			assert!(!Parachains::is_parathread(para_1));
			assert!(!Parachains::is_parachain(para_2));
			assert!(Parachains::is_parathread(para_2));
948

949
950
			// Both paras initiate a swap
			assert_ok!(Registrar::swap(
951
952
953
				para_origin(para_1),
				para_1,
				para_2,
954
955
			));
			assert_ok!(Registrar::swap(
956
957
958
				para_origin(para_2),
				para_2,
				para_1,
959
960
961
			));

			run_to_session(6);
962

963
			// Deregister a parathread that was originally a parachain
964
965
			assert_eq!(Parachains::lifecycle(para_1), Some(ParaLifecycle::Parathread));
			assert_ok!(Registrar::deregister(runtime_parachains::Origin::Parachain(para_1).into(), para_1));
966