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
	use frame_support::{
265
		traits::{OnInitialize, OnFinalize},
266
		assert_ok, assert_noop, parameter_types,
267
	};
268
	use frame_support_test::TestRandomness;
269
	use keyring::Sr25519Keyring;
270
271
272
273
	use runtime_parachains::{
		initializer, configuration, inclusion, session_info, scheduler, dmp, ump, hrmp, shared,
		ParaLifecycle,
	};
274
	use frame_support::traits::OneSessionHandler;
275
276
277
278
279
280
281
282
283
284
285
286
287
288
	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>},
289
			Shared: shared::{Module, Call, Storage},
290
291
292
293
294
			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},
295
			Hrmp: hrmp::{Module, Call, Storage, Event},
296
		}
297
	);
298
299
300
301
302
303
304
305
306
307
308
309

	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,
		);
	}

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

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

	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;
	}

355
	impl pallet_balances::Config for Test {
356
357
		type Balance = u128;
		type DustRemoval = ();
358
		type Event = Event;
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
		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! {
375
		pub const Period: BlockNumber = 3;
376
377
378
379
380
		pub const Offset: BlockNumber = 0;
		pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
		pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
	}

381
	impl pallet_session::Config for Test {
382
383
384
385
386
		type SessionManager = ();
		type Keys = UintAuthorityId;
		type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
		type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
		type SessionHandler = pallet_session::TestSessionHandler;
387
		type Event = Event;
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
		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;
	}

405
406
407
408
409
410
411
	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>;
	}

412
	impl pallet_staking::Config for Test {
413
		type RewardRemainder = ();
414
		type CurrencyToVote = frame_support::traits::SaturatingCurrencyToVote;
415
		type Event = Event;
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
		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 = ();
433
		type OffchainSolutionWeightLimit = ();
434
		type ElectionProvider = sp_election_providers::onchain::OnChainSequentialPhragmen<Self>;
435
436
437
		type WeightInfo = ();
	}

438
	impl pallet_timestamp::Config for Test {
439
440
441
442
443
444
		type Moment = u64;
		type OnTimestampSet = ();
		type MinimumPeriod = MinimumPeriod;
		type WeightInfo = ();
	}

445
446
	impl shared::Config for Test {}

447
	impl dmp::Config for Test {}
448

449
	impl ump::Config for Test {
450
		type UmpSink = ();
451
452
	}

453
	impl hrmp::Config for Test {
454
		type Event = Event;
Sergey Pepyakin's avatar
Sergey Pepyakin committed
455
		type Origin = Origin;
456
		type Currency = pallet_balances::Module<Test>;
457
	}
458

459
	impl pallet_session::historical::Config for Test {
460
461
462
463
464
465
466
467
468
469
470
		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 {
471
			use super::super::Shared;
472
473
474
475
476
477
478
479
480
			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();
481
					Shared::active_validator_keys().iter().position(|b| *b == id).unwrap() as u64
482
483
484
485
486
487
488
				}
			}
		}

		pub type ReporterId = app::Public;
	}

489
	impl paras::Config for Test {
490
491
492
		type Origin = Origin;
	}

493
	impl configuration::Config for Test { }
494

495
496
497
498
499
500
501
	pub struct TestRewardValidators;

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

502
	impl inclusion::Config for Test {
503
		type Event = Event;
504
		type RewardValidators = TestRewardValidators;
505
506
	}

507
	impl session_info::AuthorityDiscoveryConfig for Test {
508
509
510
511
512
		fn authorities() -> Vec<AuthorityDiscoveryId> {
			Vec::new()
		}
	}

513
	impl session_info::Config for Test { }
514

515
	impl initializer::Config for Test {
516
		type Randomness = TestRandomness<Self>;
517
518
	}

519
	impl scheduler::Config for Test { }
520
521
522
523
524
525
526
527
528

	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,
529
530
			_account: <Test as frame_system::Config>::AccountId,
			nonce: <Test as frame_system::Config>::Index,
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
		) -> 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;
	}

547
	impl Config for Test {
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
		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,
		];

567
568
569
570
571
572
		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();

573
574
575
576
577
578
579
580
581
582
583
584
585
		// 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) {
586
587
		// NOTE that this function only simulates modules of interest. Depending on new module may
		// require adding it here.
588
589
590
591
592
593
594
		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());
595
				Initializer::on_finalize(System::block_number());
596
597
			}
			// Session change every 3 blocks.
598
			if (b + 1) % Period::get() == 0 {
599
				println!("New session at {}", System::block_number());
600
601
602
603
604
605
606
				Initializer::on_new_session(
					false,
					Vec::new().into_iter(),
					Vec::new().into_iter(),
				);
			}
			System::set_block_number(b + 1);
607
608
			println!("Initializing {}", System::block_number());
			System::on_initialize(System::block_number());
609
			Session::on_initialize(System::block_number());
610
			Initializer::on_initialize(System::block_number());
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
		}
	}

	#[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(),
635
				WASM_MAGIC.to_vec().into(),
636
637
638
639
640
641
642
643
644
			));

			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(),
645
				WASM_MAGIC.to_vec().into(),
646
647
648
649
650
651
			));

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

652
			run_to_block(10);
653
654
655
656
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

			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(),
684
				WASM_MAGIC.to_vec().into(),
685
686
687
688
689
			));

			assert_ok!(Registrar::register_parachain(
				2u32.into(),
				vec![1; 3].into(),
690
				WASM_MAGIC.to_vec().into(),
691
692
693
694
695
696
697
698
			));

			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()));

699
700
			run_to_block(15);

701
702
703
			// Deregister a parathread that was originally a parachain
			assert_ok!(Registrar::deregister_parathread(runtime_parachains::Origin::Parachain(2u32.into()).into()));

704
			run_to_block(21);
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719

			// 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(),
720
				WASM_MAGIC.to_vec().into(),
721
722
			));

723
724
725
726
			// 2 session changes to fully onboard.
			run_to_block(12);

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

			assert_ok!(Registrar::deregister_parachain(1u32.into()));
729
730
731
			run_to_block(13);

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

733
			assert_noop!(Registrar::register_parachain(
734
735
				1u32.into(),
				vec![1; 3].into(),
736
				WASM_MAGIC.to_vec().into(),
737
738
739
740
			), Error::<Test>::ParaAlreadyExists);

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

742
			assert!(Parachains::lifecycle(1u32.into()).is_none());
743
744
745
			assert_ok!(Registrar::register_parachain(
				1u32.into(),
				vec![1; 3].into(),
746
				WASM_MAGIC.to_vec().into(),
747
748
749
750
			));
		});
	}
}