paras_registrar.rs 22 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 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/>.

//! Module to handle parathread/parachain registration and related fund management.
//! In essence this is a simple wrapper around `paras`.

20
use crate::WASM_MAGIC;
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
use sp_std::{prelude::*, result};
use frame_support::{
	decl_storage, decl_module, decl_error, ensure,
	dispatch::DispatchResult,
	traits::{Get, Currency, ReservableCurrency},
};
use frame_system::{self, ensure_root, ensure_signed};
use primitives::v1::{
	Id as ParaId, ValidationCode, HeadData,
};
use runtime_parachains::{
	paras::{
		self,
		ParaGenesisArgs,
	},
36
	dmp, ump, hrmp,
37
38
39
40
41
	ensure_parachain,
	Origin,
};

type BalanceOf<T> =
42
	<<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
43

44
pub trait Config: paras::Config + dmp::Config + ump::Config + hrmp::Config {
45
46
47
48
	/// 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.
49
50
	type Origin: From<<Self as frame_system::Config>::Origin>
		+ Into<result::Result<Origin, <Self as Config>::Origin>>;
51
52
53
54
55
56
57
58
59

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

	/// The deposit to be paid to run a parathread.
	type ParathreadDeposit: Get<BalanceOf<Self>>;
}

decl_storage! {
60
	trait Store for Module<T: Config> as Registrar {
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
		/// Whether parathreads are enabled or not.
		ParathreadsRegistrationEnabled: bool;

		/// Pending swap operations.
		PendingSwap: map hasher(twox_64_concat) ParaId => Option<ParaId>;

		/// Map of all registered parathreads/chains.
		Paras get(fn paras): map hasher(twox_64_concat) ParaId => Option<bool>;

		/// Users who have paid a parathread's deposit.
		Debtors: map hasher(twox_64_concat) ParaId => T::AccountId;
	}
}

decl_error! {
76
	pub enum Error for Module<T: Config> {
77
78
79
80
81
82
83
84
85
86
87
88
		/// Parachain already exists.
		ParaAlreadyExists,
		/// Invalid parachain ID.
		InvalidChainId,
		/// Invalid parathread ID.
		InvalidThreadId,
		/// Invalid para code size.
		CodeTooLarge,
		/// Invalid para head data size.
		HeadDataTooLarge,
		/// Parathreads registration is disabled.
		ParathreadsRegistrationDisabled,
89
90
		/// The validation code provided doesn't start with the Wasm file magic string.
		DefinitelyNotWasm,
91
92
		/// Cannot deregister para
		CannotDeregister,
93
94
95
96
	}
}

decl_module! {
97
	pub struct Module<T: Config> for enum Call where origin: <T as frame_system::Config>::Origin {
98
99
100
101
102
		type Error = Error<T>;

		/// Register a parathread with given code for immediate use.
		///
		/// Must be sent from a Signed origin that is able to have `ParathreadDeposit` reserved.
103
		/// `genesis_head` and `validation_code` are used to initalize the parathread's state.
104
105
106
107
108
109
110
111
112
113
		#[weight = 0]
		fn register_parathread(
			origin,
			id: ParaId,
			genesis_head: HeadData,
			validation_code: ValidationCode,
		) -> DispatchResult {
			let who = ensure_signed(origin)?;

			ensure!(ParathreadsRegistrationEnabled::get(), Error::<T>::ParathreadsRegistrationDisabled);
114
			ensure!(validation_code.0.starts_with(WASM_MAGIC), Error::<T>::DefinitelyNotWasm);
115
116
117
118
119
120
121
122

			ensure!(!Paras::contains_key(id), Error::<T>::ParaAlreadyExists);

			let genesis = ParaGenesisArgs {
				genesis_head,
				validation_code,
				parachain: false,
			};
123
124
			ensure!(paras::Module::<T>::can_schedule_para_initialize(&id, &genesis), Error::<T>::ParaAlreadyExists);
			<T as Config>::Currency::reserve(&who, T::ParathreadDeposit::get())?;
125

126
127
128
129
			<Debtors<T>>::insert(id, who);
			Paras::insert(id, false);
			// Checked this shouldn't fail above.
			let _ = runtime_parachains::schedule_para_initialize::<T>(id, genesis);
130
131
132
133
134
135
136
137
138
139
140
141
142

			Ok(())
		}

		/// Deregister a parathread and retreive the deposit.
		///
		/// Must be sent from a `Parachain` origin which is currently a parathread.
		///
		/// Ensure that before calling this that any funds you want emptied from the parathread's
		/// account is moved out; after this it will be impossible to retreive them (without
		/// governance intervention).
		#[weight = 0]
		fn deregister_parathread(origin) -> DispatchResult {
143
			let id = ensure_parachain(<T as Config>::Origin::from(origin))?;
144
145
146

			ensure!(ParathreadsRegistrationEnabled::get(), Error::<T>::ParathreadsRegistrationDisabled);

147
			let is_parachain = Paras::get(id).ok_or(Error::<T>::InvalidChainId)?;
148
149
150

			ensure!(!is_parachain, Error::<T>::InvalidThreadId);

151
152
			runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CannotDeregister)?;

153
			let debtor = <Debtors<T>>::take(id);
154
			let _ = <T as Config>::Currency::unreserve(&debtor, T::ParathreadDeposit::get());
155
156
			Paras::remove(&id);
			PendingSwap::remove(&id);
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188

			Ok(())
		}

		#[weight = 0]
		fn enable_parathread_registration(origin) -> DispatchResult {
			ensure_root(origin)?;

			ParathreadsRegistrationEnabled::put(true);

			Ok(())
		}

		#[weight = 0]
		fn disable_parathread_registration(origin) -> DispatchResult {
			ensure_root(origin)?;

			ParathreadsRegistrationEnabled::put(false);

			Ok(())
		}

		/// Swap a parachain with another parachain or parathread. The origin must be a `Parachain`.
		/// 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.
		#[weight = 0]
		fn swap(origin, other: ParaId) {
189
			let id = ensure_parachain(<T as Config>::Origin::from(origin))?;
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212

			if PendingSwap::get(other) == Some(id) {
				// Remove intention to swap.
				PendingSwap::remove(other);

				Paras::mutate(id, |i|
					Paras::mutate(other, |j|
						sp_std::mem::swap(i, j)
					)
				);

				<Debtors<T>>::mutate(id, |i|
					<Debtors<T>>::mutate(other, |j|
						sp_std::mem::swap(i, j)
					)
				);
			} else {
				PendingSwap::insert(id, other);
			}
		}
	}
}

213
impl<T: Config> Module<T> {
214
215
216
217
218
219
220
221
	/// Register a parachain with given code. Must be called by root.
	/// Fails if given ID is already used.
	pub fn register_parachain(
		id: ParaId,
		genesis_head: HeadData,
		validation_code: ValidationCode,
	) -> DispatchResult {
		ensure!(!Paras::contains_key(id), Error::<T>::ParaAlreadyExists);
222
		ensure!(validation_code.0.starts_with(WASM_MAGIC), Error::<T>::DefinitelyNotWasm);
223
224
225
226
227
228
229

		let genesis = ParaGenesisArgs {
			genesis_head,
			validation_code,
			parachain: true,
		};

230
		runtime_parachains::schedule_para_initialize::<T>(id, genesis).map_err(|_| Error::<T>::ParaAlreadyExists)?;
231

232
		Paras::insert(id, true);
233
234
235
236
237
		Ok(())
	}

	/// Deregister a parachain with the given ID. Must be called by root.
	pub fn deregister_parachain(id: ParaId) -> DispatchResult {
238
		let is_parachain = Paras::get(id).ok_or(Error::<T>::InvalidChainId)?;
239
240
241

		ensure!(is_parachain, Error::<T>::InvalidChainId);

242
243
244
		runtime_parachains::schedule_para_cleanup::<T>(id).map_err(|_| Error::<T>::CannotDeregister)?;
		Paras::remove(&id);
		PendingSwap::remove(&id);
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260

		Ok(())
	}
}

#[cfg(test)]
mod tests {
	use super::*;
	use sp_io::TestExternalities;
	use sp_core::H256;
	use sp_runtime::{
		traits::{
			BlakeTwo256, IdentityLookup, Extrinsic as ExtrinsicT,
		}, testing::{UintAuthorityId, TestXt}, Perbill, curve::PiecewiseLinear,
	};
	use primitives::v1::{
261
		Balance, BlockNumber, Header, Signature, AuthorityDiscoveryId, ValidatorIndex,
262
	};
263
	use frame_system::limits;
264
265
	use frame_support::{
		traits::{Randomness, OnInitialize, OnFinalize},
266
		assert_ok, assert_noop, parameter_types,
267
268
	};
	use keyring::Sr25519Keyring;
269
270
271
272
	use runtime_parachains::{
		initializer, configuration, inclusion, session_info, scheduler, dmp, ump, hrmp, shared,
		ParaLifecycle,
	};
273
	use frame_support::traits::OneSessionHandler;
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
	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,
		{
			System: frame_system::{Module, Call, Config, Storage, Event<T>},
			Balances: pallet_balances::{Module, Call, Storage, Config<T>, Event<T>},
			Parachains: paras::{Module, Origin, Call, Storage, Config<T>},
			Inclusion: inclusion::{Module, Call, Storage, Event<T>},
			Registrar: paras_registrar::{Module, Call, Storage},
	 		Staking: pallet_staking::{Module, Call, Config<T>, Storage, Event<T>, ValidateUnsigned},
			Session: pallet_session::{Module, Call, Storage, Event, Config<T>},
			Initializer: initializer::{Module, Call, Storage},
293
		}
294
	);
295
296
297
298
299
300
301
302
303
304
305
306

	pallet_staking_reward_curve::build! {
		const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
			min_inflation: 0_025_000,
			max_inflation: 0_100_000,
			ideal_stake: 0_500_000,
			falloff: 0_050_000,
			max_piece_count: 40,
			test_precision: 0_005_000,
		);
	}

307
	const NORMAL_RATIO: Perbill = Perbill::from_percent(75);
308
309
	parameter_types! {
		pub const BlockHashCount: u32 = 250;
310
		pub BlockWeights: limits::BlockWeights =
311
			frame_system::limits::BlockWeights::simple_max(1024);
312
313
		pub BlockLength: limits::BlockLength =
			limits::BlockLength::max_with_normal_ratio(4 * 1024 * 1024, NORMAL_RATIO);
314
315
	}

316
	impl frame_system::Config for Test {
317
318
319
320
321
322
323
324
325
326
		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;
327
		type Event = Event;
328
329
		type BlockHashCount = BlockHashCount;
		type DbWeight = ();
330
331
		type BlockWeights = BlockWeights;
		type BlockLength = BlockLength;
332
		type Version = ();
333
		type PalletInfo = PalletInfo;
334
335
		type AccountData = pallet_balances::AccountData<u128>;
		type OnNewAccount = ();
336
		type OnKilledAccount = ();
337
		type SystemWeightInfo = ();
338
		type SS58Prefix = ();
339
340
341
342
343
344
345
346
347
348
349
350
351
	}

	impl<C> frame_system::offchain::SendTransactionTypes<C> for Test where
		Call: From<C>,
	{
		type OverarchingCall = Call;
		type Extrinsic = TestXt<Call, ()>;
	}

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

352
	impl pallet_balances::Config for Test {
353
354
		type Balance = u128;
		type DustRemoval = ();
355
		type Event = Event;
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
		type ExistentialDeposit = ExistentialDeposit;
		type AccountStore = System;
		type MaxLocks = ();
		type WeightInfo = ();
	}

	parameter_types!{
		pub const SlashDeferDuration: pallet_staking::EraIndex = 7;
		pub const AttestationPeriod: BlockNumber = 100;
		pub const MinimumPeriod: u64 = 3;
		pub const SessionsPerEra: sp_staking::SessionIndex = 6;
		pub const BondingDuration: pallet_staking::EraIndex = 28;
		pub const MaxNominatorRewardedPerValidator: u32 = 64;
	}

	parameter_types! {
372
		pub const Period: BlockNumber = 3;
373
374
375
376
377
		pub const Offset: BlockNumber = 0;
		pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
		pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
	}

378
	impl pallet_session::Config for Test {
379
380
381
382
383
		type SessionManager = ();
		type Keys = UintAuthorityId;
		type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
		type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
		type SessionHandler = pallet_session::TestSessionHandler;
384
		type Event = Event;
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
		type ValidatorId = u64;
		type ValidatorIdOf = ();
		type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
		type WeightInfo = ();
	}

	parameter_types! {
		pub const MaxHeadDataSize: u32 = 100;
		pub const MaxCodeSize: u32 = 100;

		pub const ValidationUpgradeFrequency: BlockNumber = 10;
		pub const ValidationUpgradeDelay: BlockNumber = 2;
		pub const SlashPeriod: BlockNumber = 50;
		pub const ElectionLookahead: BlockNumber = 0;
		pub const StakingUnsignedPriority: u64 = u64::max_value() / 2;
	}

402
403
404
405
406
407
408
	impl sp_election_providers::onchain::Config for Test {
		type AccountId = <Self as frame_system::Config>::AccountId;
		type BlockNumber = <Self as frame_system::Config>::BlockNumber;
		type Accuracy = sp_runtime::Perbill;
		type DataProvider = pallet_staking::Module<Test>;
	}

409
	impl pallet_staking::Config for Test {
410
		type RewardRemainder = ();
411
		type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
412
		type Event = Event;
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
		type Currency = pallet_balances::Module<Test>;
		type Slash = ();
		type Reward = ();
		type SessionsPerEra = SessionsPerEra;
		type BondingDuration = BondingDuration;
		type SlashDeferDuration = SlashDeferDuration;
		type SlashCancelOrigin = frame_system::EnsureRoot<Self::AccountId>;
		type SessionInterface = Self;
		type UnixTime = pallet_timestamp::Module<Test>;
		type RewardCurve = RewardCurve;
		type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
		type NextNewSession = Session;
		type ElectionLookahead = ElectionLookahead;
		type Call = Call;
		type UnsignedPriority = StakingUnsignedPriority;
		type MaxIterations = ();
		type MinSolutionScoreBump = ();
430
		type OffchainSolutionWeightLimit = ();
431
		type ElectionProvider = sp_election_providers::onchain::OnChainSequentialPhragmen<Self>;
432
433
434
		type WeightInfo = ();
	}

435
	impl pallet_timestamp::Config for Test {
436
437
438
439
440
441
		type Moment = u64;
		type OnTimestampSet = ();
		type MinimumPeriod = MinimumPeriod;
		type WeightInfo = ();
	}

442
443
	impl shared::Config for Test {}

444
	impl dmp::Config for Test {}
445

446
	impl ump::Config for Test {
447
		type UmpSink = ();
448
449
	}

450
	impl hrmp::Config for Test {
Sergey Pepyakin's avatar
Sergey Pepyakin committed
451
		type Origin = Origin;
452
		type Currency = pallet_balances::Module<Test>;
453
	}
454

455
	impl pallet_session::historical::Config for Test {
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
		type FullIdentification = pallet_staking::Exposure<u64, Balance>;
		type FullIdentificationOf = pallet_staking::ExposureOf<Self>;
	}

	// This is needed for a custom `AccountId` type which is `u64` in testing here.
	pub mod test_keys {
		use sp_core::crypto::KeyTypeId;

		pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");

		mod app {
			use super::super::Inclusion;
			use sp_application_crypto::{app_crypto, sr25519};

			app_crypto!(sr25519, super::KEY_TYPE);

			impl sp_runtime::traits::IdentifyAccount for Public {
				type AccountId = u64;

				fn into_account(self) -> Self::AccountId {
					let id = self.0.clone().into();
					Inclusion::validators().iter().position(|b| *b == id).unwrap() as u64
				}
			}
		}

		pub type ReporterId = app::Public;
	}

485
	impl paras::Config for Test {
486
487
488
		type Origin = Origin;
	}

489
	impl configuration::Config for Test { }
490

491
492
493
494
495
496
497
	pub struct TestRewardValidators;

	impl inclusion::RewardValidators for TestRewardValidators {
		fn reward_backing(_: impl IntoIterator<Item = ValidatorIndex>) { }
		fn reward_bitfields(_: impl IntoIterator<Item = ValidatorIndex>) { }
	}

498
	impl inclusion::Config for Test {
499
		type Event = Event;
500
		type RewardValidators = TestRewardValidators;
501
502
	}

503
	impl session_info::AuthorityDiscoveryConfig for Test {
504
505
506
507
508
		fn authorities() -> Vec<AuthorityDiscoveryId> {
			Vec::new()
		}
	}

509
	impl session_info::Config for Test { }
510

511
512
513
514
515
516
517
518
	pub struct TestRandomness;

	impl Randomness<H256> for TestRandomness {
		fn random(_subject: &[u8]) -> H256 {
			Default::default()
		}
	}

519
	impl initializer::Config for Test {
520
521
522
		type Randomness = TestRandomness;
	}

523
	impl scheduler::Config for Test { }
524
525
526
527
528
529
530
531
532

	type Extrinsic = TestXt<Call, ()>;

	impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Test where
		Call: From<LocalCall>,
	{
		fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
			call: Call,
			_public: test_keys::ReporterId,
533
534
			_account: <Test as frame_system::Config>::AccountId,
			nonce: <Test as frame_system::Config>::Index,
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
		) -> Option<(Call, <Extrinsic as ExtrinsicT>::SignaturePayload)> {
			Some((call, (nonce, ())))
		}
	}

	impl frame_system::offchain::SigningTypes for Test {
		type Public = test_keys::ReporterId;
		type Signature = Signature;
	}

	parameter_types! {
		pub const ParathreadDeposit: Balance = 10;
		pub const QueueSize: usize = 2;
		pub const MaxRetries: u32 = 3;
	}

551
	impl Config for Test {
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
		type Origin = Origin;
		type Currency = pallet_balances::Module<Test>;
		type ParathreadDeposit = ParathreadDeposit;
	}

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

		let authority_keys = [
			Sr25519Keyring::Alice,
			Sr25519Keyring::Bob,
			Sr25519Keyring::Charlie,
			Sr25519Keyring::Dave,
			Sr25519Keyring::Eve,
			Sr25519Keyring::Ferdie,
			Sr25519Keyring::One,
			Sr25519Keyring::Two,
		];

571
572
573
574
575
576
		let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();

		pallet_balances::GenesisConfig::<Test> {
			balances,
		}.assimilate_storage(&mut t).unwrap();

577
578
579
580
581
582
583
584
585
586
587
588
589
		// stashes are the index.
		let session_keys: Vec<_> = authority_keys.iter().enumerate()
			.map(|(i, _k)| (i as u64, i as u64, UintAuthorityId(i as u64)))
			.collect();

		pallet_session::GenesisConfig::<Test> {
			keys: session_keys,
		}.assimilate_storage(&mut t).unwrap();

		t.into()
	}

	fn run_to_block(n: BlockNumber) {
590
591
		// NOTE that this function only simulates modules of interest. Depending on new module may
		// require adding it here.
592
593
594
595
596
597
598
		println!("Running until block {}", n);
		while System::block_number() < n {
			let b = System::block_number();

			if System::block_number() > 1 {
				println!("Finalizing {}", System::block_number());
				System::on_finalize(System::block_number());
599
				Initializer::on_finalize(System::block_number());
600
601
			}
			// Session change every 3 blocks.
602
			if (b + 1) % Period::get() == 0 {
603
				println!("New session at {}", System::block_number());
604
605
606
607
608
609
610
				Initializer::on_new_session(
					false,
					Vec::new().into_iter(),
					Vec::new().into_iter(),
				);
			}
			System::set_block_number(b + 1);
611
612
			println!("Initializing {}", System::block_number());
			System::on_initialize(System::block_number());
613
			Session::on_initialize(System::block_number());
614
			Initializer::on_initialize(System::block_number());
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
		}
	}

	#[test]
	fn basic_setup_works() {
		new_test_ext().execute_with(|| {
			assert_eq!(PendingSwap::get(&ParaId::from(0u32)), None);
			assert_eq!(Paras::get(&ParaId::from(0u32)), None);
		});
	}

	#[test]
	fn register_deregister_chain_works() {
		new_test_ext().execute_with(|| {
			run_to_block(1);

			assert_ok!(Registrar::enable_parathread_registration(
				Origin::root(),
			));
			run_to_block(2);

			assert_ok!(Registrar::register_parachain(
				2u32.into(),
				vec![3; 3].into(),
639
				WASM_MAGIC.to_vec().into(),
640
641
642
643
644
645
646
647
648
			));

			let orig_bal = Balances::free_balance(&3u64);

			// Register a new parathread
			assert_ok!(Registrar::register_parathread(
				Origin::signed(3u64),
				8u32.into(),
				vec![3; 3].into(),
649
				WASM_MAGIC.to_vec().into(),
650
651
652
653
654
655
			));

			// deposit should be taken (reserved)
			assert_eq!(Balances::free_balance(3u64) + ParathreadDeposit::get(), orig_bal);
			assert_eq!(Balances::reserved_balance(3u64), ParathreadDeposit::get());

656
			run_to_block(10);
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687

			assert_ok!(Registrar::deregister_parachain(2u32.into()));

			assert_ok!(Registrar::deregister_parathread(
				runtime_parachains::Origin::Parachain(8u32.into()).into()
			));

			// reserved balance should be returned.
			assert_eq!(Balances::free_balance(3u64), orig_bal);
			assert_eq!(Balances::reserved_balance(3u64), 0);
		});
	}

	#[test]
	fn swap_handles_funds_correctly() {
		new_test_ext().execute_with(|| {
			run_to_block(1);

			assert_ok!(Registrar::enable_parathread_registration(
				Origin::root(),
			));
			run_to_block(2);

			let initial_1_balance = Balances::free_balance(1);
			let initial_2_balance = Balances::free_balance(2);

			// User 1 register a new parathread
			assert_ok!(Registrar::register_parathread(
				Origin::signed(1),
				8u32.into(),
				vec![1; 3].into(),
688
				WASM_MAGIC.to_vec().into(),
689
690
691
692
693
			));

			assert_ok!(Registrar::register_parachain(
				2u32.into(),
				vec![1; 3].into(),
694
				WASM_MAGIC.to_vec().into(),
695
696
697
698
699
700
701
702
			));

			run_to_block(9);

			// Swap the parachain and parathread
			assert_ok!(Registrar::swap(runtime_parachains::Origin::Parachain(2u32.into()).into(), 8u32.into()));
			assert_ok!(Registrar::swap(runtime_parachains::Origin::Parachain(8u32.into()).into(), 2u32.into()));

703
704
			run_to_block(15);

705
706
707
			// Deregister a parathread that was originally a parachain
			assert_ok!(Registrar::deregister_parathread(runtime_parachains::Origin::Parachain(2u32.into()).into()));

708
			run_to_block(21);
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723

			// Funds are correctly returned
			assert_eq!(Balances::free_balance(1), initial_1_balance);
			assert_eq!(Balances::free_balance(2), initial_2_balance);
		});
	}

	#[test]
	fn cannot_register_until_para_is_cleaned_up() {
		new_test_ext().execute_with(|| {
			run_to_block(2);

			assert_ok!(Registrar::register_parachain(
				1u32.into(),
				vec![1; 3].into(),
724
				WASM_MAGIC.to_vec().into(),
725
726
			));

727
728
729
730
			// 2 session changes to fully onboard.
			run_to_block(12);

			assert_eq!(Parachains::lifecycle(1u32.into()), Some(ParaLifecycle::Parachain));
731
732

			assert_ok!(Registrar::deregister_parachain(1u32.into()));
733
734
735
			run_to_block(13);

			assert_eq!(Parachains::lifecycle(1u32.into()), Some(ParaLifecycle::OffboardingParachain));
736

737
			assert_noop!(Registrar::register_parachain(
738
739
				1u32.into(),
				vec![1; 3].into(),
740
				WASM_MAGIC.to_vec().into(),
741
742
743
744
			), Error::<Test>::ParaAlreadyExists);

			// Need 2 session changes to see the effect, which takes place by block 13.
			run_to_block(18);
745

746
			assert!(Parachains::lifecycle(1u32.into()).is_none());
747
748
749
			assert_ok!(Registrar::register_parachain(
				1u32.into(),
				vec![1; 3].into(),
750
				WASM_MAGIC.to_vec().into(),
751
752
753
754
			));
		});
	}
}