From b1558157cbaa6580d7bf21e02179425f1ab5cc67 Mon Sep 17 00:00:00 2001
From: Gavin Wood <gavin@parity.io>
Date: Fri, 11 Oct 2019 08:27:30 +0200
Subject: [PATCH] Introduce Parathreads (runtime) (#341)

* Rest of parathread draft implementation, parachain permissioning.

* Update Substrate

* Update Substrate again

* Integrate weight/fee stuff.

* Council

* Build fixes

* More fixes

* Minor additions

* fix some small errors

* Revert "fix some small errors"

This reverts commit 4fb52c82adfdaf3af98edfe36b280133bcd4f9d3.

* Merge fix.

* do_swap -> on_swap

* Update depdendency to polkadot-master

* Fix more merge problems

* Some patching of errors

* Fix storage closure

* Actually fix storage. It builds!

* Tests run... but not successfully.

* Add `run_to_block` to get parachains active to start

* More `run_to_block`

* Fix build

* Queue up changes to threads

* Move registration test

* Fix regsiter/deregister test

* Retry queue.

* Minor refactor

* Refactor to avoid heavy storage items

* Make tests pass

* remove para on deregister, add events

* Remove println

* Fix register/deregister parathread test

* fix merge

* Parathread can be activated test

* Test auction

* Add `Debtors` storage item

I considered putting the debtor information in `ParaInfo`, but it did not make sense to me since this information only applies to parathreads, not `paras` in general.

* remove comment code

* Some new tests

* Fixes for removing threads when scheduled. Tests.

* Test progression of threads.

* Test that reschedule queuing works properly.

* Make test slightly more interesting

* whitespace

* Swap works properly.

* Update locks

* Build

* Rename can_swap

* Add test for funds to be correctly returned after a swap

Swap does not seem to have logic which correctly swaps the debtor account to the new parathread.

* Make tests consistant

* Add check that `PendingSwap` is cleaned up

* Update runtime/src/parachains.rs

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Update runtime/src/registrar.rs

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Some fixes/suggestions from review

* Docs

* Apply suggestions from code review

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>
Co-Authored-By: Shawn Tabrizi <shawntabrizi@gmail.com>

* Update network/src/gossip.rs

Co-Authored-By: Robert Habermeier <rphmeier@gmail.com>

* Rename OnSwap

* Add missing `]`

* Rejig ordering semantics, making everything a bit slower but correct.

* Some Fixes to Parathread Compile (#470)

* Some Fixes

* Fix queue_upward_messages

* Change back to const

* Build fixes

* Fix tests
---
 polkadot/Cargo.lock                           |    2 +
 polkadot/network/src/gossip.rs                |    3 +-
 polkadot/network/src/tests/validation.rs      |    6 +-
 polkadot/parachain/Cargo.toml                 |    2 +
 polkadot/parachain/src/lib.rs                 |   22 +
 polkadot/primitives/src/parachain.rs          |   65 +-
 polkadot/runtime/Cargo.toml                   |    2 +
 polkadot/runtime/src/crowdfund.rs             |   32 +-
 polkadot/runtime/src/lib.rs                   |   42 +-
 polkadot/runtime/src/parachains.rs            |  509 +++---
 polkadot/runtime/src/registrar.rs             | 1368 +++++++++++++++++
 polkadot/runtime/src/slots.rs                 |  113 +-
 polkadot/runtime/src/testing.rs               |    0
 polkadot/service/src/chain_spec.rs            |    6 +-
 .../test-parachains/adder/wasm/Cargo.toml     |    0
 polkadot/validation/src/evaluation.rs         |    4 +-
 polkadot/validation/src/lib.rs                |    2 +-
 17 files changed, 1886 insertions(+), 292 deletions(-)
 create mode 100644 polkadot/runtime/src/registrar.rs
 create mode 100644 polkadot/runtime/src/testing.rs
 create mode 100644 polkadot/test-parachains/adder/wasm/Cargo.toml

diff --git a/polkadot/Cargo.lock b/polkadot/Cargo.lock
index 38617b5277f..d70335d03af 100644
--- a/polkadot/Cargo.lock
+++ b/polkadot/Cargo.lock
@@ -2773,6 +2773,7 @@ dependencies = [
  "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
  "shared_memory 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "sr-std 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
+ "substrate-primitives 2.0.0 (git+https://github.com/paritytech/substrate?branch=polkadot-master)",
  "tiny-keccak 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "wasmi 0.4.5 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
@@ -2805,6 +2806,7 @@ dependencies = [
  "libsecp256k1 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
  "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
  "parity-scale-codec 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
+ "polkadot-parachain 0.6.0",
  "polkadot-primitives 0.6.0",
  "rustc-hex 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "safe-mix 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/polkadot/network/src/gossip.rs b/polkadot/network/src/gossip.rs
index 1f6c5382c55..873596a7fce 100644
--- a/polkadot/network/src/gossip.rs
+++ b/polkadot/network/src/gossip.rs
@@ -265,7 +265,8 @@ impl<F, P> ChainContext for (F, P) where
 		let leaf_id = BlockId::Hash(leaf);
 		let active_parachains = api.active_parachains(&leaf_id)?;
 
-		for para_id in active_parachains {
+		// TODO: https://github.com/paritytech/polkadot/issues/467
+		for (para_id, _) in active_parachains {
 			if let Some(ingress) = api.ingress(&leaf_id, para_id, None)? {
 				for (_height, _from, queue_root) in ingress.iter() {
 					with_queue_root(queue_root);
diff --git a/polkadot/network/src/tests/validation.rs b/polkadot/network/src/tests/validation.rs
index cc08d5eda8d..36e98b9bb90 100644
--- a/polkadot/network/src/tests/validation.rs
+++ b/polkadot/network/src/tests/validation.rs
@@ -30,7 +30,7 @@ use polkadot_primitives::{Block, BlockNumber, Hash, Header, BlockId};
 use polkadot_primitives::parachain::{
 	Id as ParaId, Chain, DutyRoster, ParachainHost, TargetedMessage,
 	ValidatorId, StructuredUnroutedIngress, BlockIngressRoots, Status,
-	FeeSchedule, HeadData,
+	FeeSchedule, HeadData, Retriable, CollatorId
 };
 use parking_lot::Mutex;
 use substrate_client::error::Result as ClientResult;
@@ -177,7 +177,7 @@ impl NetworkService for TestNetwork {
 struct ApiData {
 	validators: Vec<ValidatorId>,
 	duties: Vec<Chain>,
-	active_parachains: Vec<ParaId>,
+	active_parachains: Vec<(ParaId, Option<(CollatorId, Retriable)>)>,
 	ingress: HashMap<ParaId, StructuredUnroutedIngress>,
 }
 
@@ -279,7 +279,7 @@ impl ParachainHost<Block> for RuntimeApi {
 		_: ExecutionContext,
 		_: Option<()>,
 		_: Vec<u8>,
-	) -> ClientResult<NativeOrEncoded<Vec<ParaId>>> {
+	) -> ClientResult<NativeOrEncoded<Vec<(ParaId, Option<(CollatorId, Retriable)>)>>> {
 		Ok(NativeOrEncoded::Native(self.data.lock().active_parachains.clone()))
 	}
 
diff --git a/polkadot/parachain/Cargo.toml b/polkadot/parachain/Cargo.toml
index c916486a9e6..0087d97c9c3 100644
--- a/polkadot/parachain/Cargo.toml
+++ b/polkadot/parachain/Cargo.toml
@@ -11,6 +11,7 @@ wasmi = { version = "0.4.3", optional = true }
 derive_more = { version = "0.14", optional = true }
 serde = { version = "1.0", default-features = false, features = [ "derive" ] }
 rstd = { package = "sr-std", git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
+substrate-primitives = { git = "https://github.com/paritytech/substrate", branch = "polkadot-master", default-features = false }
 lazy_static = { version = "1.3.0", optional = true }
 parking_lot = { version = "0.7.1", optional = true }
 log = { version = "0.4.6", optional = true }
@@ -33,6 +34,7 @@ std = [
 	"serde/std",
 	"rstd/std",
 	"shared_memory",
+	"substrate-primitives/std",
 	"lazy_static",
 	"parking_lot",
 	"log"
diff --git a/polkadot/parachain/src/lib.rs b/polkadot/parachain/src/lib.rs
index 8964743beeb..07c5b4166c3 100644
--- a/polkadot/parachain/src/lib.rs
+++ b/polkadot/parachain/src/lib.rs
@@ -54,6 +54,7 @@ pub mod wasm_api;
 use rstd::vec::Vec;
 
 use codec::{Encode, Decode};
+use substrate_primitives::TypeId;
 
 /// Validation parameters for evaluating the parachain validity function.
 // TODO: balance downloads (https://github.com/paritytech/polkadot/issues/220)
@@ -82,6 +83,16 @@ pub struct ValidationResult {
 #[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize, Debug))]
 pub struct Id(u32);
 
+impl TypeId for Id {
+	const TYPE_ID: [u8; 4] = *b"para";
+}
+
+/// Type for determining the active set of parachains.
+pub trait ActiveThreads {
+	/// Return the current ordered set of `Id`s of active parathreads.
+	fn active_threads() -> Vec<Id>;
+}
+
 impl codec::CompactAs for Id {
 	type As = u32;
 	fn encode_as(&self) -> &u32 {
@@ -105,11 +116,19 @@ impl From<u32> for Id {
 	fn from(x: u32) -> Self { Id(x) }
 }
 
+const USER_INDEX_START: u32 = 1000;
+
+/// The ID of the first user (non-system) parachain.
+pub const LOWEST_USER_ID: Id = Id(USER_INDEX_START);
+
 impl Id {
 	/// Convert this Id into its inner representation.
 	pub fn into_inner(self) -> u32 {
 		self.0
 	}
+
+	/// Returns `true` if this parachain runs with system-level privileges.
+	pub fn is_system(&self) -> bool { self.0 < USER_INDEX_START }
 }
 
 // TODO: Remove all of this, move sr-primitives::AccountIdConversion to own crate and and use that.
@@ -191,6 +210,9 @@ pub enum ParachainDispatchOrigin {
 	/// As the special `Origin::Parachain(ParaId)`. This is good when interacting with parachain-
 	/// aware modules which need to succinctly verify that the origin is a parachain.
 	Parachain,
+	/// As the simple, superuser `Origin::Root`. This can only be done on specially permissioned
+	/// parachains.
+	Root,
 }
 
 impl rstd::convert::TryFrom<u8> for ParachainDispatchOrigin {
diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/parachain.rs
index 24bcf990816..bfe4f8ca33c 100644
--- a/polkadot/primitives/src/parachain.rs
+++ b/polkadot/primitives/src/parachain.rs
@@ -30,7 +30,7 @@ use primitives::bytes;
 use application_crypto::KeyTypeId;
 
 pub use polkadot_parachain::{
-	Id, AccountIdConversion, ParachainDispatchOrigin, UpwardMessage,
+	Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage,
 };
 
 /// The key type ID for a collator key.
@@ -78,6 +78,67 @@ pub type ValidatorPair = validator_app::Pair;
 /// so we define it to be the same type as `SessionKey`. In the future it may have different crypto.
 pub type ValidatorSignature = validator_app::Signature;
 
+/// Retriability for a given active para.
+#[derive(Clone, Eq, PartialEq, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub enum Retriable {
+	/// Ineligible for retry. This means it's either a parachain which is always scheduled anyway or
+	/// has been removed/swapped.
+	Never,
+	/// Eligible for retry; the associated value is the number of retries that the para already had.
+	WithRetries(u32),
+}
+
+/// Type determining the active set of parachains in current block.
+pub trait ActiveParas {
+	/// Return the active set of parachains in current block. This attempts to keep any IDs in the
+	/// same place between sequential blocks. It is therefore unordered. The second item in the
+	/// tuple is the required collator ID, if any. If `Some`, then it is invalid to include any
+	/// other collator's block.
+	///
+	/// NOTE: The initial implementation simply concatenates the (ordered) set of (permanent)
+	/// parachain IDs with the (unordered) set of parathread IDs selected for this block.
+	fn active_paras() -> Vec<(Id, Option<(CollatorId, Retriable)>)>;
+}
+
+/// Description of how often/when this parachain is scheduled for progression.
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub enum Scheduling {
+	/// Scheduled every block.
+	Always,
+	/// Scheduled dynamically (i.e. a parathread).
+	Dynamic,
+}
+
+/// Information regarding a deployed parachain/thread.
+#[derive(Encode, Decode, Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct Info {
+	/// Scheduling info.
+	pub scheduling: Scheduling,
+}
+
+/// An `Info` value for a standard leased parachain.
+pub const PARACHAIN_INFO: Info = Info {
+	scheduling: Scheduling::Always,
+};
+
+/// Auxilliary for when there's an attempt to swapped two parachains/parathreads.
+pub trait SwapAux {
+	/// Result describing whether it is possible to swap two parachains. Doesn't mutate state.
+	fn ensure_can_swap(one: Id, other: Id) -> Result<(), &'static str>;
+
+	/// Updates any needed state/references to enact a logical swap of two parachains. Identity,
+	/// code and head_data remain equivalent for all parachains/threads, however other properties
+	/// such as leases, deposits held and thread/chain nature are swapped.
+	///
+	/// May only be called on a state that `ensure_can_swap` has previously returned `Ok` for: if this is
+	/// not the case, the result is undefined. May only return an error if `ensure_can_swap` also returns
+	/// an error.
+	fn on_swap(one: Id, other: Id) -> Result<(), &'static str>;
+}
+
 /// Identifier for a chain, either one of a number of parachains or the relay chain.
 #[derive(Copy, Clone, PartialEq, Encode, Decode)]
 #[cfg_attr(feature = "std", derive(Debug))]
@@ -432,7 +493,7 @@ substrate_client::decl_runtime_apis! {
 		/// Get the current duty roster.
 		fn duty_roster() -> DutyRoster;
 		/// Get the currently active parachains.
-		fn active_parachains() -> Vec<Id>;
+		fn active_parachains() -> Vec<(Id, Option<(CollatorId, Retriable)>)>;
 		/// Get the given parachain's status.
 		fn parachain_status(id: Id) -> Option<Status>;
 		/// Get the given parachain's head code blob.
diff --git a/polkadot/runtime/Cargo.toml b/polkadot/runtime/Cargo.toml
index 24a773cea77..b290bd42731 100644
--- a/polkadot/runtime/Cargo.toml
+++ b/polkadot/runtime/Cargo.toml
@@ -53,6 +53,7 @@ timestamp = { package = "srml-timestamp", git = "https://github.com/paritytech/s
 treasury = { package = "srml-treasury", git = "https://github.com/paritytech/substrate", default-features = false, branch = "polkadot-master" }
 
 primitives = { package = "polkadot-primitives", path = "../primitives", default-features = false }
+polkadot-parachain = { path = "../parachain", default-features = false }
 
 [dev-dependencies]
 hex-literal = "0.2.0"
@@ -79,6 +80,7 @@ std = [
 	"codec/std",
 	"inherents/std",
 	"substrate-primitives/std",
+	"polkadot-parachain/std",
 	"client/std",
 	"offchain-primitives/std",
 	"rstd/std",
diff --git a/polkadot/runtime/src/crowdfund.rs b/polkadot/runtime/src/crowdfund.rs
index 881dee0222c..f9132f73de1 100644
--- a/polkadot/runtime/src/crowdfund.rs
+++ b/polkadot/runtime/src/crowdfund.rs
@@ -77,14 +77,16 @@ use sr_primitives::{ModuleId, weights::SimpleDispatchInfo,
 use crate::slots;
 use codec::{Encode, Decode};
 use rstd::vec::Vec;
-use crate::parachains::ParachainRegistrar;
 use substrate_primitives::storage::well_known_keys::CHILD_STORAGE_KEY_PREFIX;
+use primitives::parachain::Id as ParaId;
 
 const MODULE_ID: ModuleId = ModuleId(*b"py/cfund");
 
-pub type BalanceOf<T> = <<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
-pub type NegativeImbalanceOf<T> = <<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
-pub type ParaIdOf<T> = <<T as slots::Trait>::Parachains as ParachainRegistrar<<T as system::Trait>::AccountId>>::ParaId;
+pub type BalanceOf<T> =
+	<<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
+#[allow(dead_code)]
+pub type NegativeImbalanceOf<T> =
+	<<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::NegativeImbalance;
 
 pub trait Trait: slots::Trait {
 	type Event: From<Event<Self>> + Into<<Self as system::Trait>::Event>;
@@ -117,7 +119,7 @@ pub enum LastContribution<BlockNumber> {
 
 #[derive(Encode, Decode, Clone, PartialEq, Eq)]
 #[cfg_attr(feature = "std", derive(Debug))]
-pub struct FundInfo<AccountId, Balance, Hash, BlockNumber, ParaId> {
+pub struct FundInfo<AccountId, Balance, Hash, BlockNumber> {
 	/// The parachain that this fund has funded, if there is one. As long as this is `Some`, then
 	/// the funds may not be withdrawn and the fund cannot be dissolved.
 	parachain: Option<ParaId>,
@@ -154,7 +156,7 @@ decl_storage! {
 	trait Store for Module<T: Trait> as Example {
 		/// Info on all of the funds.
 		Funds get(funds):
-			map FundIndex => Option<FundInfo<T::AccountId, BalanceOf<T>, T::Hash, T::BlockNumber, ParaIdOf<T>>>;
+			map FundIndex => Option<FundInfo<T::AccountId, BalanceOf<T>, T::Hash, T::BlockNumber>>;
 
 		/// The total number of funds that have so far been allocated.
 		FundCount get(fund_count): FundIndex;
@@ -172,7 +174,6 @@ decl_event! {
 	pub enum Event<T> where
 		<T as system::Trait>::AccountId,
 		Balance = BalanceOf<T>,
-		ParaId = ParaIdOf<T>,
 	{
 		Created(FundIndex),
 		Contributed(AccountId, FundIndex, Balance),
@@ -321,7 +322,7 @@ decl_module! {
 		/// - `para_id` is the parachain index that this fund won.
 		fn onboard(origin,
 			#[compact] index: FundIndex,
-			#[compact] para_id: ParaIdOf<T>
+			#[compact] para_id: ParaId
 		) {
 			let _ = ensure_signed(origin)?;
 
@@ -503,13 +504,14 @@ mod tests {
 	use srml_support::{impl_outer_origin, assert_ok, assert_noop, parameter_types};
 	use sr_io::with_externalities;
 	use substrate_primitives::{H256, Blake2Hasher};
-	use primitives::parachain::Id as ParaId;
+	use primitives::parachain::Info as ParaInfo;
 	// The testing primitives are very useful for avoiding having to work with signatures
 	// or public keys. `u64` is used as the `AccountId` and no `Signature`s are requried.
 	use sr_primitives::{
 		Perbill, Permill, testing::Header,
 		traits::{BlakeTwo256, OnInitialize, OnFinalize, IdentityLookup, ConvertInto},
 	};
+	use crate::registrar::Registrar;
 
 	impl_outer_origin! {
 		pub enum Origin for Test {}
@@ -595,16 +597,16 @@ mod tests {
 	}
 
 	pub struct TestParachains;
-	impl ParachainRegistrar<u64> for TestParachains {
-		type ParaId = ParaId;
-		fn new_id() -> Self::ParaId {
+	impl Registrar<u64> for TestParachains {
+		fn new_id() -> ParaId {
 			PARACHAIN_COUNT.with(|p| {
 				*p.borrow_mut() += 1;
 				(*p.borrow() - 1).into()
 			})
 		}
-		fn register_parachain(
-			id: Self::ParaId,
+		fn register_para(
+			id: ParaId,
+			_info: ParaInfo,
 			code: Vec<u8>,
 			initial_head_data: Vec<u8>
 		) -> Result<(), &'static str> {
@@ -616,7 +618,7 @@ mod tests {
 				Ok(())
 			})
 		}
-		fn deregister_parachain(id: Self::ParaId) -> Result<(), &'static str> {
+		fn deregister_para(id: ParaId) -> Result<(), &'static str> {
 			PARACHAINS.with(|p| {
 				if !p.borrow().contains_key(&id.into_inner()) {
 					panic!("ID doesn't exist")
diff --git a/polkadot/runtime/src/lib.rs b/polkadot/runtime/src/lib.rs
index 69224ae5311..5b9f11fd6f1 100644
--- a/polkadot/runtime/src/lib.rs
+++ b/polkadot/runtime/src/lib.rs
@@ -24,15 +24,16 @@ mod attestations;
 mod claims;
 mod parachains;
 mod slot_range;
+mod registrar;
 mod slots;
 mod crowdfund;
 
 use rstd::prelude::*;
-use codec::{Encode, Decode};
 use substrate_primitives::u32_trait::{_1, _2, _3, _4};
+use codec::{Encode, Decode};
 use primitives::{
 	AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
-	parachain, ValidityError,
+	parachain::{self, ActiveParas}, ValidityError,
 };
 use client::{
 	block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
@@ -187,7 +188,7 @@ impl indices::Trait for Runtime {
 }
 
 parameter_types! {
-	pub const ExistentialDeposit: Balance = 10 * CENTS;
+	pub const ExistentialDeposit: Balance = 100 * CENTS;
 	pub const TransferFee: Balance = 1 * CENTS;
 	pub const CreationFee: Balance = 1 * CENTS;
 	pub const TransactionBaseFee: Balance = 1 * CENTS;
@@ -221,7 +222,6 @@ impl balances::Trait for Runtime {
 parameter_types! {
 	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
 }
-
 impl timestamp::Trait for Runtime {
 	type Moment = u64;
 	type OnTimestampSet = Babe;
@@ -275,15 +275,15 @@ impl session::Trait for Runtime {
 	type ShouldEndSession = Babe;
 	type Event = Event;
 	type Keys = SessionKeys;
-	type SelectInitialValidators = Staking;
 	type ValidatorId = AccountId;
 	type ValidatorIdOf = staking::StashOf<Self>;
+	type SelectInitialValidators = Staking;
 	type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
 }
 
 impl session::historical::Trait for Runtime {
 	type FullIdentification = staking::Exposure<AccountId, Balance>;
-	type FullIdentificationOf = staking::ExposureOf<Self>;
+	type FullIdentificationOf = staking::ExposureOf<Runtime>;
 }
 
 srml_staking_reward_curve::build! {
@@ -480,6 +480,24 @@ impl parachains::Trait for Runtime {
 	type Origin = Origin;
 	type Call = Call;
 	type ParachainCurrency = Balances;
+	type ActiveParachains = Registrar;
+	type Registrar = Registrar;
+}
+
+parameter_types! {
+	pub const ParathreadDeposit: Balance = 500 * DOLLARS;
+	pub const QueueSize: usize = 2;
+	pub const MaxRetries: u32 = 3;
+}
+
+impl registrar::Trait for Runtime {
+	type Event = Event;
+	type Origin = Origin;
+	type Currency = Balances;
+	type ParathreadDeposit = ParathreadDeposit;
+	type SwapAux = Slots;
+	type QueueSize = QueueSize;
+	type MaxRetries = MaxRetries;
 }
 
 parameter_types!{
@@ -489,8 +507,8 @@ parameter_types!{
 
 impl slots::Trait for Runtime {
 	type Event = Event;
-	type Currency = balances::Module<Self>;
-	type Parachains = parachains::Module<Self>;
+	type Currency = Balances;
+	type Parachains = Registrar;
 	type LeasePeriod = LeasePeriod;
 	type EndingPeriod = EndingPeriod;
 }
@@ -553,9 +571,10 @@ construct_runtime!(
 
 		// Parachains stuff; slots are disabled (no auctions initially). The rest are safe as they
 		// have no public dispatchables.
-		Parachains: parachains::{Module, Call, Storage, Config<T>, Inherent, Origin},
+		Parachains: parachains::{Module, Call, Storage, Config, Inherent, Origin},
 		Attestations: attestations::{Module, Call, Storage},
 		Slots: slots::{Module, Call, Storage, Event<T>},
+		Registrar: registrar::{Module, Call, Storage, Event, Config<T>},
 
 		// Sudo. Usable initially.
 		// RELEASE: remove this for release build.
@@ -583,6 +602,7 @@ pub type SignedExtra = (
 	system::CheckNonce<Runtime>,
 	system::CheckWeight<Runtime>,
 	balances::TakeFees<Runtime>,
+	registrar::LimitParathreadCommits<Runtime>
 );
 /// Unchecked extrinsic type as expected by this runtime.
 pub type UncheckedExtrinsic = generic::UncheckedExtrinsic<Address, Call, Signature, SignedExtra>;
@@ -653,8 +673,8 @@ impl_runtime_apis! {
 		fn duty_roster() -> parachain::DutyRoster {
 			Parachains::calculate_duty_roster().0
 		}
-		fn active_parachains() -> Vec<parachain::Id> {
-			Parachains::active_parachains()
+		fn active_parachains() -> Vec<(parachain::Id, Option<(parachain::CollatorId, parachain::Retriable)>)> {
+			Registrar::active_paras()
 		}
 		fn parachain_status(id: parachain::Id) -> Option<parachain::Status> {
 			Parachains::parachain_status(&id)
diff --git a/polkadot/runtime/src/parachains.rs b/polkadot/runtime/src/parachains.rs
index a31b9e6ea93..b45021e24af 100644
--- a/polkadot/runtime/src/parachains.rs
+++ b/polkadot/runtime/src/parachains.rs
@@ -17,17 +17,20 @@
 //! Main parachains logic. For now this is just the determination of which validators do what.
 
 use rstd::prelude::*;
+use rstd::result;
 use rstd::collections::btree_map::BTreeMap;
-use codec::{Encode, Decode, HasCompact};
-use srml_support::{decl_storage, decl_module, fail, ensure};
+use codec::{Encode, Decode};
+use srml_support::{decl_storage, decl_module, ensure};
 
 use sr_primitives::traits::{
-	Hash as HashT, BlakeTwo256, Member, CheckedConversion, Saturating, One, Zero, Dispatchable,
+	Hash as HashT, BlakeTwo256, Saturating, One, Zero, Dispatchable,
+	AccountIdConversion,
 };
 use sr_primitives::weights::SimpleDispatchInfo;
 use primitives::{Hash, Balance, parachain::{
-	self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, AccountIdConversion,
-	ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots, ValidatorId
+	self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement,
+	ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots, ValidatorId, ActiveParas, CollatorId,
+	Retriable
 }};
 use {system, session};
 use srml_support::{
@@ -36,11 +39,9 @@ use srml_support::{
 
 use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};
 
-#[cfg(any(feature = "std", test))]
-use rstd::marker::PhantomData;
-
-use system::{ensure_none, ensure_root};
+use system::ensure_none;
 use crate::attestations::{self, IncludedBlocks};
+use crate::registrar::Registrar;
 
 // ranges for iteration of general block number don't work, so this
 // is a utility to get around that.
@@ -68,75 +69,6 @@ fn number_range<N>(low: N, high: N) -> BlockNumberRange<N> {
 	BlockNumberRange { low, high }
 }
 
-/// Parachain registration API.
-pub trait ParachainRegistrar<AccountId> {
-	/// An identifier for a parachain.
-	type ParaId: Member + Parameter + Default + AccountIdConversion<AccountId> + Copy + HasCompact;
-
-	/// Create a new unique parachain identity for later registration.
-	fn new_id() -> Self::ParaId;
-
-	/// Register a parachain with given `code` and `initial_head_data`. `id` must not yet be registered or it will
-	/// result in a error.
-	fn register_parachain(id: Self::ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result;
-
-	/// Deregister a parachain with given `id`. If `id` is not currently registered, an error is returned.
-	fn deregister_parachain(id: Self::ParaId) -> Result;
-}
-
-impl<T: Trait> ParachainRegistrar<T::AccountId> for Module<T> {
-	type ParaId = ParaId;
-	fn new_id() -> ParaId {
-		<NextFreeId>::mutate(|n| { let r = *n; *n = ParaId::from(u32::from(*n) + 1); r })
-	}
-	fn register_parachain(id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
-		let mut parachains = Self::active_parachains();
-		match parachains.binary_search(&id) {
-			Ok(_) => fail!("Parachain already exists"),
-			Err(idx) => parachains.insert(idx, id),
-		}
-
-		<Code>::insert(id, code);
-		<Parachains>::put(parachains);
-		<Heads>::insert(id, initial_head_data);
-
-		// Because there are no ordering guarantees that inherents
-		// are applied before regular transactions, a parachain candidate could
-		// be registered before the `UpdateHeads` inherent is processed. If so, messages
-		// could be sent to a parachain in the block it is registered.
-		<Watermarks<T>>::insert(id, <system::Module<T>>::block_number().saturating_sub(One::one()));
-
-		Ok(())
-	}
-	fn deregister_parachain(id: ParaId) -> Result {
-		let mut parachains = Self::active_parachains();
-		match parachains.binary_search(&id) {
-			Ok(idx) => { parachains.remove(idx); }
-			Err(_) => return Ok(()),
-		}
-
-		<Code>::remove(id);
-		<Heads>::remove(id);
-
-		let watermark = <Watermarks<T>>::take(id);
-
-		// clear all routing entries _to_. But not those _from_.
-		if let Some(watermark) = watermark {
-			let now = <system::Module<T>>::block_number();
-
-			// iterate over all blocks between watermark and now + 1 (since messages might
-			// have already been sent to `id` in this block.
-			for unrouted_block in number_range(watermark, now).map(|n| n.saturating_add(One::one())) {
-				<UnroutedIngress<T>>::remove(&(unrouted_block, id));
-			}
-		}
-
-		<Parachains>::put(parachains);
-
-		Ok(())
-	}
-}
-
 // wrapper trait because an associated type of `Currency<Self::AccountId,Balance=Balance>`
 // doesn't work.`
 pub trait ParachainCurrency<AccountId> {
@@ -186,6 +118,12 @@ pub trait Trait: attestations::Trait {
 
 	/// Some way of interacting with balances for fees.
 	type ParachainCurrency: ParachainCurrency<Self::AccountId>;
+
+	/// Means to determine what the current set of active parachains are.
+	type ActiveParachains: ActiveParas;
+
+	/// The way that we are able to register parachains.
+	type Registrar: Registrar<Self::AccountId>;
 }
 
 /// Origin for the parachains module.
@@ -213,8 +151,6 @@ decl_storage! {
 	trait Store for Module<T: Trait> as Parachains {
 		/// All authorities' keys at the moment.
 		pub Authorities get(authorities) config(authorities): Vec<ValidatorId>;
-		/// Vector of all parachain IDs.
-		pub Parachains get(active_parachains): Vec<ParaId>;
 		/// The parachains registered at present.
 		pub Code get(parachain_code): map ParaId => Option<Vec<u8>>;
 		/// The heads of the parachains registered at present.
@@ -237,35 +173,14 @@ decl_storage! {
 		/// decoding when checking receipt validity. First item in tuple is the count of messages
 		///	second if the total length (in bytes) of the message payloads.
 		pub RelayDispatchQueueSize: map ParaId => (u32, u32);
+		/// The ordered list of ParaIds that have a `RelayDispatchQueue` entry.
+		NeedsDispatch: Vec<ParaId>;
 
-		/// Did the parachain heads get updated in this block?
-		DidUpdate: bool;
-
-		/// The next unused ParaId value.
-		NextFreeId: ParaId;
-	}
-	add_extra_genesis {
-		config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
-		config(_phdata): PhantomData<T>;
-		build(build::<T>);
-	}
-}
-
-#[cfg(feature = "std")]
-fn build<T: Trait>(config: &GenesisConfig<T>) {
-	let mut p = config.parachains.clone();
-	p.sort_unstable_by_key(|&(ref id, _, _)| *id);
-	p.dedup_by_key(|&mut (ref id, _, _)| *id);
-
-	let only_ids: Vec<ParaId> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
-
-	Parachains::put(&only_ids);
-
-	for (id, code, genesis) in p {
-		// no ingress -- a chain cannot be routed to until it is live.
-		Code::insert(&id, &code);
-		Heads::insert(&id, &genesis);
-		<Watermarks<T>>::insert(&id, &T::BlockNumber::zero());
+		/// Some if the parachain heads get updated in this block, along with the parachain IDs that
+		/// did update. Ordered in the same way as `registrar::Active` (i.e. by ParaId).
+		///
+		/// None if not yet updated.
+		pub DidUpdate: Option<Vec<ParaId>>;
 	}
 }
 
@@ -274,32 +189,38 @@ decl_module! {
 	pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
 		/// Provide candidate receipts for parachains, in ascending order by id.
 		#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
-		fn set_heads(origin, heads: Vec<AttestedCandidate>) -> Result {
+		pub fn set_heads(origin, heads: Vec<AttestedCandidate>) -> Result {
 			ensure_none(origin)?;
 			ensure!(!<DidUpdate>::exists(), "Parachain heads must be updated only once in the block");
 
 			let active_parachains = Self::active_parachains();
+
 			let parachain_count = active_parachains.len();
 			ensure!(heads.len() <= parachain_count, "Too many parachain candidates");
 
+			let mut proceeded = Vec::with_capacity(heads.len());
+
 			if !active_parachains.is_empty() {
 				// perform integrity checks before writing to storage.
 				{
 					let mut last_id = None;
+
 					let mut iter = active_parachains.iter();
 					for head in &heads {
 						let id = head.parachain_index();
 						// proposed heads must be ascending order by parachain ID without duplicate.
 						ensure!(
 							last_id.as_ref().map_or(true, |x| x < &id),
-							"Parachain candidates out of order by ID"
+							"candidate out of order"
 						);
 
 						// must be unknown since active parachains are always sorted.
-						ensure!(
-							iter.find(|x| x == &&id).is_some(),
-							"Submitted candidate for unregistered or out-of-order parachain {}"
-						);
+						let (_, maybe_required_collator) = iter.find(|para| para.0 == id)
+							.ok_or("candidate for unregistered parachain {}")?;
+
+						if let Some((required_collator, _)) = maybe_required_collator {
+							ensure!(required_collator == &head.candidate.collator, "invalid collator");
+						}
 
 						Self::check_upward_messages(
 							id,
@@ -309,7 +230,9 @@ decl_module! {
 						)?;
 						Self::check_egress_queue_roots(&head, &active_parachains)?;
 
-						last_id = Some(head.parachain_index());
+						let id = head.parachain_index();
+						proceeded.push(id);
+						last_id = Some(id);
 					}
 				}
 
@@ -324,36 +247,23 @@ decl_module! {
 				);
 
 				Self::dispatch_upward_messages(
-					current_number,
-					&active_parachains,
 					MAX_QUEUE_COUNT,
 					WATERMARK_QUEUE_SIZE,
 					Self::dispatch_message,
 				);
 			}
 
-			<DidUpdate>::put(true);
+			DidUpdate::put(proceeded);
 
 			Ok(())
 		}
 
-		/// Register a parachain with given code.
-		/// Fails if given ID is already used.
-		#[weight = SimpleDispatchInfo::FixedOperational(5_000_000)]
-		pub fn register_parachain(origin, id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
-			ensure_root(origin)?;
-			<Self as ParachainRegistrar<T::AccountId>>::register_parachain(id, code, initial_head_data)
+		fn on_initialize() {
+			<Self as Store>::DidUpdate::kill();
 		}
 
-		/// Deregister a parachain with given id
-		#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
-		pub fn deregister_parachain(origin, id: ParaId) -> Result {
-			ensure_root(origin)?;
-			<Self as ParachainRegistrar<T::AccountId>>::deregister_parachain(id)
-		}
-
-		fn on_finalize(_n: T::BlockNumber) {
-			assert!(<Self as Store>::DidUpdate::take(), "Parachain heads must be updated once in the block");
+		fn on_finalize() {
+			assert!(<Self as Store>::DidUpdate::exists(), "Parachain heads must be updated once in the block");
 		}
 	}
 }
@@ -369,6 +279,42 @@ fn localized_payload(statement: Statement, parent_hash: ::primitives::Hash) -> V
 }
 
 impl<T: Trait> Module<T> {
+	/// Initialize the state of a new parachain/parathread.
+	pub fn initialize_para(
+		id: ParaId,
+		code: Vec<u8>,
+		initial_head_data: Vec<u8>,
+	) {
+		<Code>::insert(id, code);
+		<Heads>::insert(id, initial_head_data);
+
+		// Because there are no ordering guarantees that inherents
+		// are applied before regular transactions, a parachain candidate could
+		// be registered before the `UpdateHeads` inherent is processed. If so, messages
+		// could be sent to a parachain in the block it is registered.
+		<Watermarks<T>>::insert(id, <system::Module<T>>::block_number().saturating_sub(One::one()));
+	}
+
+	pub fn cleanup_para(
+		id: ParaId,
+	) {
+		<Code>::remove(id);
+		<Heads>::remove(id);
+
+		let watermark = <Watermarks<T>>::take(id);
+
+		// clear all routing entries _to_. But not those _from_.
+		if let Some(watermark) = watermark {
+			let now = <system::Module<T>>::block_number();
+
+			// iterate over all blocks between watermark and now + 1 (since messages might
+			// have already been sent to `id` in this block.
+			for unrouted_block in number_range(watermark, now).map(|n| n.saturating_add(One::one())) {
+				<UnroutedIngress<T>>::remove(&(unrouted_block, id));
+			}
+		}
+	}
+
 	/// Dispatch some messages from a parachain.
 	fn dispatch_message(
 		id: ParaId,
@@ -381,6 +327,8 @@ impl<T: Trait> Module<T> {
 					system::RawOrigin::Signed(id.into_account()).into(),
 				ParachainDispatchOrigin::Parachain =>
 					Origin::Parachain(id).into(),
+				ParachainDispatchOrigin::Root =>
+					system::RawOrigin::Root.into(),
 			};
 			let _ok = message_call.dispatch(origin).is_ok();
 			// Not much to do with the result as it is. It's up to the parachain to ensure that the
@@ -415,6 +363,11 @@ impl<T: Trait> Module<T> {
 				),
 				"Messages added when queue full"
 			);
+			if !id.is_system() {
+				for m in upward_messages.iter() {
+					ensure!(m.origin != ParachainDispatchOrigin::Root, "bad message origin");
+				}
+			}
 		}
 		Ok(())
 	}
@@ -431,6 +384,10 @@ impl<T: Trait> Module<T> {
 
 		let mut ingress_update = BTreeMap::new();
 
+		// we sort them in order to provide a fast lookup to ensure we can avoid duplicates in the
+		// needs_dispatch queue.
+		let mut ordered_needs_dispatch = NeedsDispatch::get();
+
 		for head in heads.iter() {
 			let id = head.parachain_index();
 			<Heads>::insert(id, &head.candidate.head_data.0);
@@ -452,9 +409,15 @@ impl<T: Trait> Module<T> {
 			}
 
 			// Queue up upwards messages (from parachains to relay chain).
-			Self::queue_upward_messages(id, &head.candidate.upward_messages);
+			Self::queue_upward_messages(
+				id,
+				&head.candidate.upward_messages,
+				&mut ordered_needs_dispatch,
+			);
 		}
 
+		NeedsDispatch::put(ordered_needs_dispatch);
+
 		// apply the ingress update.
 		for (to, ingress_roots) in ingress_update {
 			<UnroutedIngress<T>>::insert((now, to), ingress_roots);
@@ -462,36 +425,46 @@ impl<T: Trait> Module<T> {
 	}
 
 	/// Place any new upward messages into our queue for later dispatch.
-	fn queue_upward_messages(id: ParaId, upward_messages: &[UpwardMessage]) {
+	///
+	/// `ordered_needs_dispatch` is mutated to ensure it reflects the new value of
+	/// `RelayDispatchQueueSize`. It is up to the caller to guarantee that it gets written into
+	/// storage after this call.
+	fn queue_upward_messages(
+		id: ParaId,
+		upward_messages: &[UpwardMessage],
+		ordered_needs_dispatch: &mut Vec<ParaId>,
+	) {
 		if !upward_messages.is_empty() {
-			<RelayDispatchQueueSize>::mutate(id, |&mut(ref mut count, ref mut len)| {
+			RelayDispatchQueueSize::mutate(id, |&mut(ref mut count, ref mut len)| {
 				*count += upward_messages.len() as u32;
 				*len += upward_messages.iter()
 					.fold(0, |a, x| a + x.data.len()) as u32;
 			});
 			// Should never be able to fail assuming our state is uncorrupted, but best not
 			// to panic, even if it does.
-			let _ = <RelayDispatchQueue>::append(id, upward_messages);
+			let _ = RelayDispatchQueue::append(id, upward_messages);
+			if let Err(i) = ordered_needs_dispatch.binary_search(&id) {
+				// same.
+				ordered_needs_dispatch.insert(i, id);
+			} else {
+				sr_primitives::print("ordered_needs_dispatch contains id?!");
+			}
 		}
 	}
 
-	/// Simple round-robin dispatcher, using block number modulo parachain count
-	/// to decide which takes precedence and proceeding from there.
+	/// Simple FIFO dispatcher.
 	fn dispatch_upward_messages(
-		now: T::BlockNumber,
-		active_parachains: &[ParaId],
 		max_queue_count: usize,
 		watermark_queue_size: usize,
 		mut dispatch_message: impl FnMut(ParaId, ParachainDispatchOrigin, &[u8]),
 	) {
-		let para_count = active_parachains.len();
-		let offset = (now % T::BlockNumber::from(para_count as u32))
-			.checked_into::<usize>()
-			.expect("value is modulo a usize value; qed");
-
+		let queueds = NeedsDispatch::get();
+		let mut drained_count = 0usize;
 		let mut dispatched_count = 0usize;
 		let mut dispatched_size = 0usize;
-		for id in active_parachains.iter().cycle().skip(offset).take(para_count) {
+		for id in queueds.iter() {
+			drained_count += 1;
+
 			let (count, size) = <RelayDispatchQueueSize>::get(id);
 			let count = count as usize;
 			let size = size as usize;
@@ -501,8 +474,8 @@ impl<T: Trait> Module<T> {
 			) {
 				if count > 0 {
 					// still dispatching messages...
-					<RelayDispatchQueueSize>::remove(id);
-					let messages = <RelayDispatchQueue>::take(id);
+					RelayDispatchQueueSize::remove(id);
+					let messages = RelayDispatchQueue::take(id);
 					for UpwardMessage { origin, data } in messages.into_iter() {
 						dispatch_message(*id, origin, &data);
 					}
@@ -516,6 +489,7 @@ impl<T: Trait> Module<T> {
 				}
 			}
 		}
+		NeedsDispatch::put(&queueds[drained_count..]);
 	}
 
 	/// Calculate the current block's duty roster using system's random seed.
@@ -523,19 +497,24 @@ impl<T: Trait> Module<T> {
 	pub fn calculate_duty_roster() -> (DutyRoster, [u8; 32]) {
 		let parachains = Self::active_parachains();
 		let parachain_count = parachains.len();
+
 		// TODO: use decode length. substrate #2794
 		let validator_count = Self::authorities().len();
-		let validators_per_parachain = if parachain_count != 0 { (validator_count - 1) / parachain_count } else { 0 };
+		let validators_per_parachain =
+			if parachain_count == 0 {
+				0
+			} else {
+				(validator_count - 1) / parachain_count
+			};
 
 		let mut roles_val = (0..validator_count).map(|i| match i {
 			i if i < parachain_count * validators_per_parachain => {
 				let idx = i / validators_per_parachain;
-				Chain::Parachain(parachains[idx].clone())
+				Chain::Parachain(parachains[idx].0.clone())
 			}
 			_ => Chain::Relay,
 		}).collect::<Vec<_>>();
 
-
 		let mut seed = {
 			let phrase = b"validator_role_pairs";
 			let seed = randomness_collective_flip::Module::<T>::random(&phrase[..]);
@@ -621,9 +600,17 @@ impl<T: Trait> Module<T> {
 		})
 	}
 
-	fn check_egress_queue_roots(head: &AttestedCandidate, active_parachains: &[ParaId]) -> Result {
+	/// Get the currently active set of parachains.
+	pub fn active_parachains() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> {
+		T::ActiveParachains::active_paras()
+	}
+
+	fn check_egress_queue_roots(
+		head: &AttestedCandidate,
+		active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
+	) -> Result {
 		let mut last_egress_id = None;
-		let mut iter = active_parachains.iter();
+		let mut iter = active_parachains.iter().map(|x| x.0);
 		for (egress_para_id, root) in &head.candidate.egress_queue_roots {
 			// egress routes should be ascending order by parachain ID without duplicate.
 			ensure!(
@@ -645,7 +632,7 @@ impl<T: Trait> Module<T> {
 
 			// can't route to a parachain which doesn't exist
 			ensure!(
-				iter.find(|x| x == &egress_para_id).is_some(),
+				iter.find(|x| x == egress_para_id).is_some(),
 				"Routing to non-existent parachain"
 			);
 
@@ -656,8 +643,10 @@ impl<T: Trait> Module<T> {
 
 	// check the attestations on these candidates. The candidates should have been checked
 	// that each candidates' chain ID is valid.
-	fn check_candidates(attested_candidates: &[AttestedCandidate], active_parachains: &[ParaId])
-		-> rstd::result::Result<IncludedBlocks<T>, &'static str>
+	fn check_candidates(
+		attested_candidates: &[AttestedCandidate],
+		active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
+	) -> rstd::result::Result<IncludedBlocks<T>, &'static str>
 	{
 		use primitives::parachain::ValidityAttestation;
 		use sr_primitives::traits::AppVerify;
@@ -815,7 +804,7 @@ impl<T: Trait> Module<T> {
 			actual_number: <system::Module<T>>::block_number(),
 			session: <session::Module<T>>::current_index(),
 			random_seed,
-			active_parachains: active_parachains.to_vec(),
+			active_parachains: active_parachains.iter().map(|x| x.0).collect(),
 			para_blocks: para_block_hashes,
 		})
 	}
@@ -877,6 +866,17 @@ impl<T: Trait> ProvideInherent for Module<T> {
 	}
 }
 
+/// Ensure that the origin `o` represents a parachain.
+/// Returns `Ok` with the parachain ID that effected the extrinsic or an `Err` otherwise.
+pub fn ensure_parachain<OuterOrigin>(o: OuterOrigin) -> result::Result<ParaId, &'static str>
+	where OuterOrigin: Into<result::Result<Origin, OuterOrigin>>
+{
+	match o.into() {
+		Ok(Origin::Parachain(id)) => Ok(id),
+		_ => Err("bad origin: expected to be a parachain origin"),
+	}
+}
+
 #[cfg(test)]
 mod tests {
 	use super::*;
@@ -887,12 +887,12 @@ mod tests {
 	use substrate_trie::NodeCodec;
 	use sr_primitives::{
 		Perbill,
-		traits::{BlakeTwo256, IdentityLookup, ConvertInto, OnInitialize},
+		traits::{BlakeTwo256, IdentityLookup, ConvertInto, OnInitialize, OnFinalize},
 		testing::{UintAuthorityId, Header},
 		curve::PiecewiseLinear,
 	};
 	use primitives::{
-		parachain::{CandidateReceipt, HeadData, ValidityAttestation, ValidatorId},
+		parachain::{CandidateReceipt, HeadData, ValidityAttestation, ValidatorId, Info as ParaInfo, Scheduling},
 		BlockNumber,
 	};
 	use crate::constants::time::*;
@@ -901,6 +901,8 @@ mod tests {
 		impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
 	};
 	use crate::parachains;
+	use crate::registrar;
+	use crate::slots;
 
 	impl_outer_origin! {
 		pub enum Origin for Test {
@@ -1048,15 +1050,47 @@ mod tests {
 		type RewardAttestation = ();
 	}
 
+	parameter_types!{
+		pub const LeasePeriod: u64 = 10;
+		pub const EndingPeriod: u64 = 3;
+	}
+
+	impl slots::Trait for Test {
+		type Event = ();
+		type Currency = balances::Module<Test>;
+		type Parachains = registrar::Module<Test>;
+		type EndingPeriod = EndingPeriod;
+		type LeasePeriod = LeasePeriod;
+	}
+
+	parameter_types! {
+		pub const ParathreadDeposit: Balance = 10;
+		pub const QueueSize: usize = 2;
+		pub const MaxRetries: u32 = 3;
+	}
+
+	impl registrar::Trait for Test {
+		type Event = ();
+		type Origin = Origin;
+		type Currency = balances::Module<Test>;
+		type ParathreadDeposit = ParathreadDeposit;
+		type SwapAux = slots::Module<Test>;
+		type QueueSize = QueueSize;
+		type MaxRetries = MaxRetries;
+	}
+
 	impl Trait for Test {
 		type Origin = Origin;
 		type Call = Call;
 		type ParachainCurrency = balances::Module<Test>;
+		type ActiveParachains = registrar::Module<Test>;
+		type Registrar = registrar::Module<Test>;
 	}
 
 	type Parachains = Module<Test>;
 	type System = system::Module<Test>;
 	type RandomnessCollectiveFlip = randomness_collective_flip::Module<Test>;
+	type Registrar = registrar::Module<Test>;
 
 	fn new_test_ext(parachains: Vec<(ParaId, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
 		use staking::StakerStatus;
@@ -1096,9 +1130,12 @@ mod tests {
 
 		let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();
 
-		GenesisConfig::<Test> {
-			parachains,
+		GenesisConfig {
 			authorities: authorities.clone(),
+		}.assimilate_storage(&mut t).unwrap();
+
+		registrar::GenesisConfig::<Test> {
+			parachains,
 			_phdata: Default::default(),
 		}.assimilate_storage(&mut t).unwrap();
 
@@ -1217,6 +1254,32 @@ mod tests {
 		}
 	}
 
+	fn init_block() {
+		println!("Initializing {}", System::block_number());
+		System::on_initialize(System::block_number());
+		Registrar::on_initialize(System::block_number());
+		Parachains::on_initialize(System::block_number());
+	}
+	fn run_to_block(n: u64) {
+		println!("Running until block {}", n);
+		while System::block_number() < n {
+			if System::block_number() > 1 {
+				println!("Finalizing {}", System::block_number());
+				Parachains::on_finalize(System::block_number());
+				Registrar::on_finalize(System::block_number());
+				System::on_finalize(System::block_number());
+			}
+			System::set_block_number(System::block_number() + 1);
+			init_block();
+		}
+	}
+
+	fn queue_upward_messages(id: ParaId, upward_messages: &[UpwardMessage]) {
+		NeedsDispatch::mutate(|nd|
+			Parachains::queue_upward_messages(id, upward_messages, nd)
+		);
+	}
+
 	#[test]
 	fn check_dispatch_upward_works() {
 		let parachains = vec![
@@ -1225,16 +1288,16 @@ mod tests {
 			(2u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains.clone()), || {
-			let parachains = vec![0.into(), 1.into(), 2.into()];
-			Parachains::queue_upward_messages(0.into(), &vec![
+			init_block();
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 4] }
 			]);
-			Parachains::queue_upward_messages(1.into(), &vec![
+			queue_upward_messages(1.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 4] }
 			]);
 			let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
 			let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
-			Parachains::dispatch_upward_messages(0, &parachains, 2, 3, dummy);
+			Parachains::dispatch_upward_messages(2, 3, dummy);
 			assert_eq!(dispatched, vec![
 				(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 4])
 			]);
@@ -1242,19 +1305,19 @@ mod tests {
 			assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
 		});
 		with_externalities(&mut new_test_ext(parachains.clone()), || {
-			let parachains = vec![0.into(), 1.into(), 2.into()];
-			Parachains::queue_upward_messages(0.into(), &vec![
+			init_block();
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
 			]);
-			Parachains::queue_upward_messages(1.into(), &vec![
+			queue_upward_messages(1.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
 			]);
-			Parachains::queue_upward_messages(2.into(), &vec![
+			queue_upward_messages(2.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
 			]);
 			let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
 			let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
-			Parachains::dispatch_upward_messages(0, &parachains, 2, 3, dummy);
+			Parachains::dispatch_upward_messages(2, 3, dummy);
 			assert_eq!(dispatched, vec![
 				(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
 				(2.into(), ParachainDispatchOrigin::Parachain, vec![2])
@@ -1264,44 +1327,44 @@ mod tests {
 			assert!(<RelayDispatchQueue>::get(ParaId::from(2)).is_empty());
 		});
 		with_externalities(&mut new_test_ext(parachains.clone()), || {
-			let parachains = vec![0.into(), 1.into(), 2.into()];
-			Parachains::queue_upward_messages(0.into(), &vec![
+			init_block();
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
 			]);
-			Parachains::queue_upward_messages(1.into(), &vec![
+			queue_upward_messages(1.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
 			]);
-			Parachains::queue_upward_messages(2.into(), &vec![
+			queue_upward_messages(2.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
 			]);
 			let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
 			let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
-			Parachains::dispatch_upward_messages(1, &parachains, 2, 3, dummy);
+			Parachains::dispatch_upward_messages(2, 3, dummy);
 			assert_eq!(dispatched, vec![
-				(1.into(), ParachainDispatchOrigin::Parachain, vec![1; 2]),
+				(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
 				(2.into(), ParachainDispatchOrigin::Parachain, vec![2])
 			]);
-			assert_eq!(<RelayDispatchQueue>::get(ParaId::from(0)).len(), 1);
-			assert!(<RelayDispatchQueue>::get(ParaId::from(1)).is_empty());
+			assert!(<RelayDispatchQueue>::get(ParaId::from(0)).is_empty());
+			assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
 			assert!(<RelayDispatchQueue>::get(ParaId::from(2)).is_empty());
 		});
 		with_externalities(&mut new_test_ext(parachains.clone()), || {
-			let parachains = vec![0.into(), 1.into(), 2.into()];
-			Parachains::queue_upward_messages(0.into(), &vec![
+			init_block();
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![0; 2] }
 			]);
-			Parachains::queue_upward_messages(1.into(), &vec![
+			queue_upward_messages(1.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1; 2] }
 			]);
-			Parachains::queue_upward_messages(2.into(), &vec![
+			queue_upward_messages(2.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![2] }
 			]);
 			let mut dispatched: Vec<(ParaId, ParachainDispatchOrigin, Vec<u8>)> = vec![];
 			let dummy = |id, origin, data: &[u8]| dispatched.push((id, origin, data.to_vec()));
-			Parachains::dispatch_upward_messages(2, &parachains, 2, 3, dummy);
+			Parachains::dispatch_upward_messages(2, 3, dummy);
 			assert_eq!(dispatched, vec![
+				(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2]),
 				(2.into(), ParachainDispatchOrigin::Parachain, vec![2]),
-				(0.into(), ParachainDispatchOrigin::Parachain, vec![0; 2])
 			]);
 			assert!(<RelayDispatchQueue>::get(ParaId::from(0)).is_empty());
 			assert_eq!(<RelayDispatchQueue>::get(ParaId::from(1)).len(), 1);
@@ -1315,20 +1378,21 @@ mod tests {
 			(0u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			let messages = vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] }
 			];
 			assert_ok!(Parachains::check_upward_messages(0.into(), &messages, 2, 3));
 
 			// all good.
-			Parachains::queue_upward_messages(0.into(), &vec![
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
 			]);
 			let messages = vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1, 2] }
 			];
 			assert_ok!(Parachains::check_upward_messages(0.into(), &messages, 2, 3));
-			Parachains::queue_upward_messages(0.into(), &messages);
+			queue_upward_messages(0.into(), &messages);
 			assert_eq!(<RelayDispatchQueue>::get(ParaId::from(0)), vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
 				UpwardMessage { origin: ParachainDispatchOrigin::Parachain, data: vec![1, 2] },
@@ -1342,6 +1406,7 @@ mod tests {
 			(0u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// oversize, but ok since it's just one and the queue is empty.
 			let messages = vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0; 4] },
@@ -1377,8 +1442,9 @@ mod tests {
 			(0u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// too many messages.
-			Parachains::queue_upward_messages(0.into(), &vec![
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
 			]);
 			let messages = vec![
@@ -1398,8 +1464,9 @@ mod tests {
 			(0u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// too much data.
-			Parachains::queue_upward_messages(0.into(), &vec![
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0, 1] },
 			]);
 			let messages = vec![
@@ -1418,8 +1485,9 @@ mod tests {
 			(0u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// bad - already an oversize messages queued.
-			Parachains::queue_upward_messages(0.into(), &vec![
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0; 4] },
 			]);
 			let messages = vec![
@@ -1438,8 +1506,9 @@ mod tests {
 			(0u32.into(), vec![], vec![]),
 		];
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// bad - oversized and already a message queued.
-			Parachains::queue_upward_messages(0.into(), &vec![
+			queue_upward_messages(0.into(), &vec![
 				UpwardMessage { origin: ParachainDispatchOrigin::Signed, data: vec![0] },
 			]);
 			let messages = vec![
@@ -1461,6 +1530,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// parachain 0 is self
 			let mut candidates = vec![
 				new_candidate_with_upward_messages(0, vec![
@@ -1490,9 +1560,10 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
-			assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 100u32.into()]);
-			assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1,2,3]));
-			assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4,5,6]));
+			run_to_block(2);
+			assert_eq!(Parachains::active_parachains(), vec![(5u32.into(), None), (100u32.into(), None)]);
+			assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1, 2, 3]));
+			assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4, 5, 6]));
 		});
 	}
 
@@ -1504,20 +1575,28 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
-			assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 100u32.into()]);
+			run_to_block(2);
+			assert_eq!(Parachains::active_parachains(), vec![(5u32.into(), None), (100u32.into(), None)]);
 
 			assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), Some(vec![1,2,3]));
 			assert_eq!(Parachains::parachain_code(ParaId::from(100u32)), Some(vec![4,5,6]));
 
-			assert_ok!(Parachains::register_parachain(Origin::ROOT, 99u32.into(), vec![7,8,9], vec![1, 1, 1]));
+			assert_ok!(Registrar::register_para(Origin::ROOT, 99u32.into(), ParaInfo{scheduling: Scheduling::Always}, vec![7,8,9], vec![1, 1, 1]));
+			assert_ok!(Parachains::set_heads(Origin::NONE, vec![]));
 
-			assert_eq!(Parachains::active_parachains(), vec![5u32.into(), 99u32.into(), 100u32.into()]);
-			assert_eq!(Parachains::parachain_code(ParaId::from(99u32)), Some(vec![7,8,9]));
+			run_to_block(3);
 
-			assert_ok!(Parachains::deregister_parachain(Origin::ROOT, 5u32.into()));
+			assert_eq!(Parachains::active_parachains(), vec![(5u32.into(), None), (99u32.into(), None), (100u32.into(), None)]);
+			assert_eq!(Parachains::parachain_code(&ParaId::from(99u32)), Some(vec![7,8,9]));
 
-			assert_eq!(Parachains::active_parachains(), vec![99u32.into(), 100u32.into()]);
-			assert_eq!(Parachains::parachain_code(ParaId::from(5u32)), None);
+			assert_ok!(Registrar::deregister_para(Origin::ROOT, 5u32.into()));
+			assert_ok!(Parachains::set_heads(Origin::NONE, vec![]));
+
+			// parachain still active this block. another block must pass before it's inactive.
+			run_to_block(4);
+
+			assert_eq!(Parachains::active_parachains(), vec![(99u32.into(), None), (100u32.into(), None)]);
+			assert_eq!(Parachains::parachain_code(&ParaId::from(5u32)), None);
 		});
 	}
 
@@ -1529,6 +1608,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			let check_roster = |duty_roster: &DutyRoster| {
 				assert_eq!(duty_roster.validator_duty.len(), 8);
 				for i in (0..2).map(ParaId::from) {
@@ -1564,6 +1644,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			let candidate = AttestedCandidate {
 				validity_votes: vec![],
 				validator_indices: BitVec::new(),
@@ -1592,6 +1673,9 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
+			assert_eq!(Parachains::active_parachains().len(), 2);
+
 			let mut candidate_a = AttestedCandidate {
 				validity_votes: vec![],
 				validator_indices: BitVec::new(),
@@ -1645,6 +1729,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			let mut candidate = AttestedCandidate {
 				validity_votes: vec![],
 				validator_indices: BitVec::new(),
@@ -1681,6 +1766,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			let mut candidate = AttestedCandidate {
 				validity_votes: vec![],
 				validator_indices: BitVec::new(),
@@ -1711,8 +1797,6 @@ mod tests {
 
 	#[test]
 	fn ingress_works() {
-		use sr_primitives::traits::OnFinalize;
-
 		let parachains = vec![
 			(0u32.into(), vec![], vec![]),
 			(1u32.into(), vec![], vec![]),
@@ -1723,8 +1807,9 @@ mod tests {
 			assert_eq!(Parachains::ingress(ParaId::from(1), None), Some(Vec::new()));
 			assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
 
+			init_block();
 			for i in 1..10 {
-				System::set_block_number(i);
+				run_to_block(i);
 
 				let from_a = vec![(1.into(), [i as u8; 32].into())];
 				let mut candidate_a = AttestedCandidate {
@@ -1765,11 +1850,9 @@ mod tests {
 					set_heads(vec![candidate_a, candidate_b]),
 					Origin::NONE,
 				));
-
-				Parachains::on_finalize(i);
 			}
 
-			System::set_block_number(10);
+			run_to_block(10);
 			assert_ok!(Parachains::dispatch(
 				set_heads(vec![]),
 				Origin::NONE,
@@ -1795,7 +1878,7 @@ mod tests {
 				))).collect::<Vec<_>>()),
 			);
 
-			assert_ok!(Parachains::deregister_parachain(Origin::ROOT, 1u32.into()));
+			assert_ok!(Registrar::deregister_para(Origin::ROOT, 1u32.into()));
 
 			// after deregistering, there is no ingress to 1, but unrouted messages
 			// from 1 stick around.
@@ -1804,8 +1887,7 @@ mod tests {
 				vec![(1.into(), [i as u8; 32].into())]
 			))).collect::<Vec<_>>()));
 
-			Parachains::on_finalize(10);
-			System::set_block_number(11);
+			run_to_block(11);
 
 			let mut candidate_c = AttestedCandidate {
 				validity_votes: vec![],
@@ -1828,8 +1910,7 @@ mod tests {
 				Origin::NONE,
 			));
 
-			Parachains::on_finalize(11);
-			System::set_block_number(12);
+			run_to_block(12);
 
 			// at the next block, ingress to 99 should be empty.
 			assert_eq!(Parachains::ingress(ParaId::from(99), None), Some(Vec::new()));
@@ -1845,6 +1926,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// parachain 99 does not exist
 			let non_existent = vec![(99.into(), [1; 32].into())];
 			let mut candidate = new_candidate_with_egress_roots(non_existent);
@@ -1869,6 +1951,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// parachain 0 is self
 			let to_self = vec![(0.into(), [1; 32].into())];
 			let mut candidate = new_candidate_with_egress_roots(to_self);
@@ -1893,6 +1976,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// parachain 0 is self
 			let out_of_order = vec![(1.into(), [1; 32].into()), ((0.into(), [1; 32].into()))];
 			let mut candidate = new_candidate_with_egress_roots(out_of_order);
@@ -1917,6 +2001,7 @@ mod tests {
 		];
 
 		with_externalities(&mut new_test_ext(parachains), || {
+			run_to_block(2);
 			// parachain 0 is self
 			let contains_empty_trie_root = vec![(1.into(), [1; 32].into()), ((2.into(), EMPTY_TRIE_ROOT.into()))];
 			let mut candidate = new_candidate_with_egress_roots(contains_empty_trie_root);
diff --git a/polkadot/runtime/src/registrar.rs b/polkadot/runtime/src/registrar.rs
new file mode 100644
index 00000000000..77b2663e443
--- /dev/null
+++ b/polkadot/runtime/src/registrar.rs
@@ -0,0 +1,1368 @@
+// Copyright 2017 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 which parachains/parathreads (collectively referred to as "paras") are
+//! registered and which are scheduled. Doesn't manage any of the actual execution/validation logic
+//! which is left to `parachains.rs`.
+
+use rstd::{prelude::*, result};
+#[cfg(any(feature = "std", test))]
+use rstd::marker::PhantomData;
+use codec::{Encode, Decode};
+
+use sr_primitives::{
+	weights::{SimpleDispatchInfo, DispatchInfo},
+	transaction_validity::{TransactionValidityError, ValidTransaction, TransactionValidity},
+	traits::{Hash as HashT, SignedExtension}
+};
+
+use srml_support::{
+	decl_storage, decl_module, decl_event, ensure,
+	dispatch::{Result, IsSubType}, traits::{Get, Currency, ReservableCurrency}
+};
+use system::{self, ensure_root, ensure_signed};
+use primitives::parachain::{
+	Id as ParaId, CollatorId, Scheduling, LOWEST_USER_ID, SwapAux, Info as ParaInfo, ActiveParas,
+	Retriable
+};
+use crate::parachains;
+use sr_primitives::transaction_validity::InvalidTransaction;
+
+/// Parachain registration API.
+pub trait Registrar<AccountId> {
+	/// Create a new unique parachain identity for later registration.
+	fn new_id() -> ParaId;
+
+	/// Register a parachain with given `code` and `initial_head_data`. `id` must not yet be registered or it will
+	/// result in a error.
+	fn register_para(
+		id: ParaId,
+		info: ParaInfo,
+		code: Vec<u8>,
+		initial_head_data: Vec<u8>,
+	) -> Result;
+
+	/// Deregister a parachain with given `id`. If `id` is not currently registered, an error is returned.
+	fn deregister_para(id: ParaId) -> Result;
+}
+
+impl<T: Trait> Registrar<T::AccountId> for Module<T> {
+	fn new_id() -> ParaId {
+		<NextFreeId>::mutate(|n| { let r = *n; *n = ParaId::from(u32::from(*n) + 1); r })
+	}
+
+	fn register_para(
+		id: ParaId,
+		info: ParaInfo,
+		code: Vec<u8>,
+		initial_head_data: Vec<u8>,
+	) -> Result {
+		ensure!(!Paras::exists(id), "Parachain already exists");
+		if let Scheduling::Always = info.scheduling {
+			Parachains::mutate(|parachains|
+				match parachains.binary_search(&id) {
+					Ok(_) => Err("Parachain already exists"),
+					Err(idx) => {
+						parachains.insert(idx, id);
+						Ok(())
+					}
+				}
+			)?;
+		}
+		<parachains::Module<T>>::initialize_para(id, code, initial_head_data);
+		Paras::insert(id, info);
+		Ok(())
+	}
+
+	fn deregister_para(id: ParaId) -> Result {
+		let info = Paras::take(id).ok_or("Invalid id")?;
+		if let Scheduling::Always = info.scheduling {
+			Parachains::mutate(|parachains|
+				parachains.binary_search(&id)
+					.map(|index| parachains.remove(index))
+					.map_err(|_| "Invalid id")
+			)?;
+		}
+		<parachains::Module<T>>::cleanup_para(id);
+		Paras::remove(id);
+		Ok(())
+	}
+}
+
+type BalanceOf<T> =
+	<<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
+
+pub trait Trait: parachains::Trait {
+	/// The overarching event type.
+	type Event: From<Event> + Into<<Self as system::Trait>::Event>;
+
+	/// 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 system::Trait>::Origin>
+		+ Into<result::Result<parachains::Origin, <Self as Trait>::Origin>>;
+
+	/// 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>>;
+
+	/// Handler for when two ParaIds are swapped.
+	type SwapAux: SwapAux;
+
+	/// The number of items in the parathread queue, aka the number of blocks in advance to schedule
+	/// parachain execution.
+	type QueueSize: Get<usize>;
+
+	/// The number of rotations that you will have as grace if you miss a block.
+	type MaxRetries: Get<u32>;
+}
+
+decl_storage! {
+	trait Store for Module<T: Trait> as Registrar {
+		// Vector of all parachain IDs, in ascending order.
+		Parachains: Vec<ParaId>;
+
+		/// The number of threads to schedule per block.
+		ThreadCount: u32;
+
+		/// An array of the queue of set of threads scheduled for the coming blocks; ordered by
+		/// ascending para ID. There can be no duplicates of para ID in each list item.
+		SelectedThreads: Vec<Vec<(ParaId, CollatorId)>>;
+
+		/// Parathreads/chains scheduled for execution this block. If the collator ID is set, then
+		/// a particular collator has already been chosen for the next block, and no other collator
+		/// may provide the block. In this case we allow the possibility of the combination being
+		/// retried in a later block, expressed by `Retriable`.
+		///
+		/// Ordered by ParaId.
+		Active: Vec<(ParaId, Option<(CollatorId, Retriable)>)>;
+
+		/// The next unused ParaId value. Start this high in order to keep low numbers for
+		/// system-level chains.
+		NextFreeId: ParaId = LOWEST_USER_ID;
+
+		/// Pending swap operations.
+		PendingSwap: map ParaId => Option<ParaId>;
+
+		/// Map of all registered parathreads/chains.
+		Paras get(paras): map ParaId => Option<ParaInfo>;
+
+		/// The current queue for parathreads that should be retried.
+		RetryQueue get(retry_queue): Vec<Vec<(ParaId, CollatorId)>>;
+
+		/// Users who have paid a parathread's deposit
+		Debtors: map ParaId => T::AccountId;
+	}
+	add_extra_genesis {
+		config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
+		config(_phdata): PhantomData<T>;
+		build(build::<T>);
+	}
+}
+
+#[cfg(feature = "std")]
+fn build<T: Trait>(config: &GenesisConfig<T>) {
+	use sr_primitives::traits::Zero;
+
+	let mut p = config.parachains.clone();
+	p.sort_unstable_by_key(|&(ref id, _, _)| *id);
+	p.dedup_by_key(|&mut (ref id, _, _)| *id);
+
+	let only_ids: Vec<ParaId> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
+
+	Parachains::put(&only_ids);
+
+	for (id, code, genesis) in p {
+		Paras::insert(id, &primitives::parachain::PARACHAIN_INFO);
+		// no ingress -- a chain cannot be routed to until it is live.
+		<parachains::Code>::insert(&id, &code);
+		<parachains::Heads>::insert(&id, &genesis);
+		<parachains::Watermarks<T>>::insert(&id, T::BlockNumber::zero());
+		// Save initial parachains in registrar
+		Paras::insert(id, ParaInfo { scheduling: Scheduling::Always })
+	}
+}
+
+/// Swap the existence of two items, provided by value, within an ordered list.
+///
+/// If neither item exists, or if both items exist this will do nothing. If exactly one of the
+/// items exists, then it will be removed and the other inserted.
+pub fn swap_ordered_existence<T: PartialOrd + Ord + Copy>(ids: &mut [T], one: T, other: T) {
+	let maybe_one_pos = ids.binary_search(&one);
+	let maybe_other_pos = ids.binary_search(&other);
+	match (maybe_one_pos, maybe_other_pos) {
+		(Ok(one_pos), Err(_)) => ids[one_pos] = other,
+		(Err(_), Ok(other_pos)) => ids[other_pos] = one,
+		_ => return,
+	};
+	ids.sort();
+}
+
+decl_module! {
+	/// Parachains module.
+	pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
+		fn deposit_event() = default;
+
+		/// Register a parachain with given code.
+		/// Fails if given ID is already used.
+		#[weight = SimpleDispatchInfo::FixedOperational(5_000_000)]
+		pub fn register_para(origin,
+			#[compact] id: ParaId,
+			info: ParaInfo,
+			code: Vec<u8>,
+			initial_head_data: Vec<u8>,
+		) -> Result {
+			ensure_root(origin)?;
+			<Self as Registrar<T::AccountId>>::
+				register_para(id, info, code, initial_head_data)
+		}
+
+		/// Deregister a parachain with given id
+		#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
+		pub fn deregister_para(origin, #[compact] id: ParaId) -> Result {
+			ensure_root(origin)?;
+			<Self as Registrar<T::AccountId>>::deregister_para(id)
+		}
+
+		/// Reset the number of parathreads that can pay to be scheduled in a single block.
+		///
+		/// - `count`: The number of parathreads.
+		///
+		/// Must be called from Root origin.
+		fn set_thread_count(origin, count: u32) {
+			ensure_root(origin)?;
+			ThreadCount::put(count);
+		}
+
+		/// Register a parathread for immediate use.
+		///
+		/// Must be sent from a Signed origin that is able to have ParathreadDeposit reserved.
+		/// `code` and `initial_head_data` are used to initialize the parathread's state.
+		fn register_parathread(origin,
+			code: Vec<u8>,
+			initial_head_data: Vec<u8>,
+		) {
+			let who = ensure_signed(origin)?;
+
+			T::Currency::reserve(&who, T::ParathreadDeposit::get())?;
+
+			let info = ParaInfo {
+				scheduling: Scheduling::Dynamic,
+			};
+			let id = <Self as Registrar<T::AccountId>>::new_id();
+
+			let _ = <Self as Registrar<T::AccountId>>::
+				register_para(id, info, code, initial_head_data);
+
+			<Debtors<T>>::insert(id, who);
+
+			Self::deposit_event(Event::ParathreadRegistered(id));
+		}
+
+		/// Place a bid for a parathread to be progressed in the next block.
+		///
+		/// This is a kind of special transaction that should by heavily prioritized in the
+		/// transaction pool according to the `value`; only `ThreadCount` of them may be presented
+		/// in any single block.
+		fn select_parathread(origin,
+			#[compact] _id: ParaId,
+			_collator: CollatorId,
+			_head_hash: T::Hash,
+		) {
+			ensure_signed(origin)?;
+			// Everything else is checked for in the transaction `SignedExtension`.
+		}
+
+		/// Deregister a parathread and retrieve 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 retrieve them (without
+		/// governance intervention).
+		fn deregister_parathread(origin) {
+			let id = parachains::ensure_parachain(<T as Trait>::Origin::from(origin))?;
+
+			let info = Paras::get(id).ok_or("invalid id")?;
+			if let Scheduling::Dynamic = info.scheduling {} else { Err("invalid parathread id")? }
+
+			<Self as Registrar<T::AccountId>>::deregister_para(id)?;
+			Self::force_unschedule(|i| i == id);
+
+			let debtor = <Debtors<T>>::take(id);
+			let _ = T::Currency::unreserve(&debtor, T::ParathreadDeposit::get());
+
+			Self::deposit_event(Event::ParathreadRegistered(id));
+		}
+
+		/// 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.
+		fn swap(origin, #[compact] other: ParaId) {
+			let id = parachains::ensure_parachain(<T as Trait>::Origin::from(origin))?;
+
+			if PendingSwap::get(other) == Some(id) {
+				// actually do the swap.
+				T::SwapAux::ensure_can_swap(id, other)?;
+
+				// Remove intention to swap.
+				PendingSwap::remove(other);
+				Self::force_unschedule(|i| i == id || i == other);
+				Parachains::mutate(|ids| swap_ordered_existence(ids, id, other));
+				Paras::mutate(id, |i|
+					Paras::mutate(other, |j|
+						rstd::mem::swap(i, j)
+					)
+				);
+
+				<Debtors<T>>::mutate(id, |i|
+					<Debtors<T>>::mutate(other, |j|
+						rstd::mem::swap(i, j)
+					)
+				);
+				let _ = T::SwapAux::on_swap(id, other);
+			} else {
+				PendingSwap::insert(id, other);
+			}
+		}
+
+		/// Block initializer. Clears SelectedThreads and constructs/replaces Active.
+		fn on_initialize() {
+			let next_up = SelectedThreads::mutate(|t| {
+				let r = if t.len() >= T::QueueSize::get() {
+					// Take the first set of parathreads in queue
+					t.remove(0)
+				} else {
+					vec![]
+				};
+				while t.len() < T::QueueSize::get() {
+					t.push(vec![]);
+				}
+				r
+			});
+			// mutable so that we can replace with `None` if parathread appears in new schedule.
+			let mut retrying = Self::take_next_retry();
+			if let Some(((para, _), _)) = retrying {
+				// this isn't really ideal: better would be if there were an earlier pass that set
+				// retrying to the first item in the Missed queue that isn't already scheduled, but
+				// this is potentially O(m*n) in terms of missed queue size and parathread pool size.
+				if next_up.iter().any(|x| x.0 == para) {
+					retrying = None
+				}
+			}
+
+			let mut paras = Parachains::get().into_iter()
+				.map(|id| (id, None))
+				.chain(next_up.into_iter()
+					.map(|(para, collator)|
+						(para, Some((collator, Retriable::WithRetries(0))))
+					)
+				).chain(retrying.into_iter()
+					.map(|((para, collator), retries)|
+						(para, Some((collator, Retriable::WithRetries(retries + 1))))
+					)
+				).collect::<Vec<_>>();
+			// for Rust's timsort algorithm, sorting a concatenation of two sorted ranges is near
+			// O(N).
+			paras.sort_by_key(|&(ref id, _)| *id);
+
+			Active::put(paras);
+		}
+
+		fn on_finalize() {
+			// a block without this will panic, but let's not panic here.
+			if let Some(proceeded_vec) = parachains::DidUpdate::get() {
+				// Active is sorted and DidUpdate is a sorted subset of its elements.
+				//
+				// We just go through the contents of active and find any items that don't appear in
+				// DidUpdate *and* which are enabled for retry.
+				let mut proceeded = proceeded_vec.into_iter();
+				let mut i = proceeded.next();
+				for sched in Active::get().into_iter() {
+					match i {
+						// Scheduled parachain proceeded properly. Move onto next item.
+						Some(para) if para == sched.0 => i = proceeded.next(),
+						// Scheduled `sched` missed their block.
+						// Queue for retry if it's allowed.
+						_ => if let (i, Some((c, Retriable::WithRetries(n)))) = sched {
+							Self::retry_later((i, c), n)
+						},
+					}
+				}
+			}
+		}
+	}
+}
+
+decl_event!{
+	pub enum Event {
+		/// A parathread was registered; its new ID is supplied.
+		ParathreadRegistered(ParaId),
+
+		/// The parathread of the supplied ID was de-registered.
+		ParathreadDeregistered(ParaId),
+	}
+}
+
+impl<T: Trait> Module<T> {
+        /// Ensures that the given `ParaId` corresponds to a registered parathread, and returns a descriptor if so.
+	pub fn ensure_thread_id(id: ParaId) -> Option<ParaInfo> {
+		Paras::get(id).and_then(|info| if let Scheduling::Dynamic = info.scheduling {
+			Some(info)
+		} else {
+			None
+		})
+	}
+
+	fn retry_later(sched: (ParaId, CollatorId), retries: u32) {
+		if retries < T::MaxRetries::get() {
+			RetryQueue::mutate(|q| {
+				q.resize(T::MaxRetries::get() as usize, vec![]);
+				q[retries as usize].push(sched);
+			});
+		}
+	}
+
+	fn take_next_retry() -> Option<((ParaId, CollatorId), u32)> {
+		RetryQueue::mutate(|q| {
+			for (i, q) in q.iter_mut().enumerate() {
+				if !q.is_empty() {
+					return Some((q.remove(0), i as u32));
+				}
+			}
+			None
+		})
+	}
+
+	/// Forcibly remove the threads matching `m` from all current and future scheduling.
+	fn force_unschedule(m: impl Fn(ParaId) -> bool) {
+		RetryQueue::mutate(|qs| for q in qs.iter_mut() {
+			q.retain(|i| !m(i.0))
+		});
+		SelectedThreads::mutate(|qs| for q in qs.iter_mut() {
+			q.retain(|i| !m(i.0))
+		});
+		Active::mutate(|a| for i in a.iter_mut() {
+			if m(i.0) {
+				if let Some((_, ref mut r)) = i.1 {
+					*r = Retriable::Never;
+				}
+			}
+		});
+	}
+}
+
+impl<T: Trait> ActiveParas for Module<T> {
+	fn active_paras() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> {
+		Active::get()
+	}
+}
+
+/// Ensure that parathread selections happen prioritized by fees.
+#[derive(Encode, Decode, Clone, Eq, PartialEq)]
+pub struct LimitParathreadCommits<T: Trait + Send + Sync>(rstd::marker::PhantomData<T>) where
+	<T as system::Trait>::Call: IsSubType<Module<T>, T>;
+
+#[cfg(feature = "std")]
+impl<T: Trait + Send + Sync> rstd::fmt::Debug for LimitParathreadCommits<T> where
+	<T as system::Trait>::Call: IsSubType<Module<T>, T>
+{
+	fn fmt(&self, f: &mut rstd::fmt::Formatter) -> rstd::fmt::Result {
+		write!(f, "LimitParathreadCommits<T>")
+	}
+}
+
+/// Custom validity errors used in Polkadot while validating transactions.
+#[repr(u8)]
+pub enum Error {
+	/// Parathread ID has already been submitted for this block.
+	Duplicate = 0,
+	/// Parathread ID does not identify a parathread.
+	InvalidId = 1,
+}
+
+impl<T: Trait + Send + Sync> SignedExtension for LimitParathreadCommits<T> where
+	<T as system::Trait>::Call: IsSubType<Module<T>, T>
+{
+	type AccountId = T::AccountId;
+	type Call = <T as system::Trait>::Call;
+	type AdditionalSigned = ();
+	type Pre = ();
+
+	fn additional_signed(&self)
+		-> rstd::result::Result<Self::AdditionalSigned, TransactionValidityError>
+	{
+		Ok(())
+	}
+
+	fn validate(
+		&self,
+		_who: &Self::AccountId,
+		call: &Self::Call,
+		_info: DispatchInfo,
+		_len: usize,
+	) -> TransactionValidity {
+		let mut r = ValidTransaction::default();
+		if let Some(local_call) = call.is_sub_type() {
+			if let Call::select_parathread(id, collator, hash) = local_call {
+				// ensure that the para ID is actually a parathread.
+				let e = TransactionValidityError::from(InvalidTransaction::Custom(Error::InvalidId as u8));
+				<Module<T>>::ensure_thread_id(*id).ok_or(e)?;
+
+				// ensure that we haven't already had a full complement of selected parathreads.
+				let mut upcoming_selected_threads = SelectedThreads::get();
+				if upcoming_selected_threads.is_empty() {
+					upcoming_selected_threads.push(vec![]);
+				}
+				let i = upcoming_selected_threads.len() - 1;
+				let selected_threads = &mut upcoming_selected_threads[i];
+				let thread_count = ThreadCount::get() as usize;
+				ensure!(
+					selected_threads.len() < thread_count,
+					InvalidTransaction::ExhaustsResources.into()
+				);
+
+				// ensure that this is not selecting a duplicate parathread ID
+				let e = TransactionValidityError::from(InvalidTransaction::Custom(Error::Duplicate as u8));
+				let pos = selected_threads
+					.binary_search_by(|&(ref other_id, _)| other_id.cmp(id))
+					.err()
+					.ok_or(e)?;
+
+				// ensure that this is a live bid (i.e. that the thread's chain head matches)
+				let e = TransactionValidityError::from(InvalidTransaction::Custom(Error::InvalidId as u8));
+				let head = <parachains::Module<T>>::parachain_head(id).ok_or(e)?;
+				let actual = T::Hashing::hash(&head);
+				ensure!(&actual == hash, InvalidTransaction::Stale.into());
+
+				// updated the selected threads.
+				selected_threads.insert(pos, (*id, collator.clone()));
+				rstd::mem::drop(selected_threads);
+				SelectedThreads::put(upcoming_selected_threads);
+
+				// provides the state-transition for this head-data-hash; this should cue the pool
+				// to throw out competing transactions with lesser fees.
+				r.provides = vec![hash.encode()];
+			}
+		}
+		Ok(r)
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use bitvec::vec::BitVec;
+	use sr_io::{TestExternalities, with_externalities};
+	use substrate_primitives::{H256, Blake2Hasher, Pair};
+	use sr_primitives::{
+		traits::{
+			BlakeTwo256, IdentityLookup, ConvertInto, OnInitialize, OnFinalize, Dispatchable,
+			AccountIdConversion,
+		}, testing::{UintAuthorityId, Header}, Perbill
+	};
+	use primitives::{
+		parachain::{
+			ValidatorId, Info as ParaInfo, Scheduling, LOWEST_USER_ID, AttestedCandidate,
+			CandidateReceipt, HeadData, ValidityAttestation, Statement, Chain, CollatorPair,
+		},
+		Balance, BlockNumber,
+	};
+	use srml_support::{
+		impl_outer_origin, impl_outer_dispatch, assert_ok, parameter_types, assert_noop,
+	};
+	use keyring::Sr25519Keyring;
+
+	use crate::parachains;
+	use crate::slots;
+	use crate::attestations;
+
+	impl_outer_origin! {
+		pub enum Origin for Test {
+			parachains,
+		}
+	}
+
+	impl_outer_dispatch! {
+		pub enum Call for Test where origin: Origin {
+			parachains::Parachains,
+			registrar::Registrar,
+		}
+	}
+
+	#[derive(Clone, Eq, PartialEq)]
+	pub struct Test;
+	parameter_types! {
+		pub const BlockHashCount: u32 = 250;
+		pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024;
+		pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
+		pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
+	}
+	impl system::Trait for Test {
+		type Origin = Origin;
+		type Call = Call;
+		type Index = u64;
+		type BlockNumber = u64;
+		type Hash = H256;
+		type Hashing = BlakeTwo256;
+		type AccountId = u64;
+		type Lookup = IdentityLookup<u64>;
+		type Header = Header;
+		type WeightMultiplierUpdate = ();
+		type Event = ();
+		type BlockHashCount = BlockHashCount;
+		type MaximumBlockWeight = MaximumBlockWeight;
+		type MaximumBlockLength = MaximumBlockLength;
+		type AvailableBlockRatio = AvailableBlockRatio;
+		type Version = ();
+	}
+
+	parameter_types! {
+		pub const ExistentialDeposit: Balance = 0;
+		pub const TransferFee: Balance = 0;
+		pub const CreationFee: Balance = 0;
+		pub const TransactionBaseFee: Balance = 0;
+		pub const TransactionByteFee: Balance = 0;
+	}
+
+	impl balances::Trait for Test {
+		type Balance = Balance;
+		type OnFreeBalanceZero = ();
+		type OnNewAccount = ();
+		type Event = ();
+		type TransactionPayment = ();
+		type DustRemoval = ();
+		type TransferPayment = ();
+		type ExistentialDeposit = ExistentialDeposit;
+		type TransferFee = TransferFee;
+		type CreationFee = CreationFee;
+		type TransactionBaseFee = TransactionBaseFee;
+		type TransactionByteFee = TransactionByteFee;
+		type WeightToFee = ConvertInto;
+	}
+
+	parameter_types!{
+		pub const LeasePeriod: u64 = 10;
+		pub const EndingPeriod: u64 = 3;
+	}
+
+	impl slots::Trait for Test {
+		type Event = ();
+		type Currency = balances::Module<Test>;
+		type Parachains = Registrar;
+		type EndingPeriod = EndingPeriod;
+		type LeasePeriod = LeasePeriod;
+	}
+
+	parameter_types!{
+		pub const AttestationPeriod: BlockNumber = 100;
+	}
+
+	impl attestations::Trait for Test {
+		type AttestationPeriod = AttestationPeriod;
+		type ValidatorIdentities = parachains::ValidatorIdentities<Test>;
+		type RewardAttestation = ();
+	}
+
+	parameter_types! {
+		pub const Period: BlockNumber = 1;
+		pub const Offset: BlockNumber = 0;
+		pub const DisabledValidatorsThreshold: Perbill = Perbill::from_percent(17);
+	}
+
+	impl session::Trait for Test {
+		type OnSessionEnding = ();
+		type Keys = UintAuthorityId;
+		type ShouldEndSession = session::PeriodicSessions<Period, Offset>;
+		type SessionHandler = ();
+		type Event = ();
+		type SelectInitialValidators = ();
+		type ValidatorId = u64;
+		type ValidatorIdOf = ();
+		type DisabledValidatorsThreshold = DisabledValidatorsThreshold;
+	}
+
+	impl parachains::Trait for Test {
+		type Origin = Origin;
+		type Call = Call;
+		type ParachainCurrency = balances::Module<Test>;
+		type ActiveParachains = Registrar;
+		type Registrar = Registrar;
+	}
+
+	parameter_types! {
+		pub const ParathreadDeposit: Balance = 10;
+		pub const QueueSize: usize = 2;
+		pub const MaxRetries: u32 = 3;
+	}
+
+	impl Trait for Test {
+		type Event = ();
+		type Origin = Origin;
+		type Currency = balances::Module<Test>;
+		type ParathreadDeposit = ParathreadDeposit;
+		type SwapAux = slots::Module<Test>;
+		type QueueSize = QueueSize;
+		type MaxRetries = MaxRetries;
+	}
+
+	type Balances = balances::Module<Test>;
+	type Parachains = parachains::Module<Test>;
+	type System = system::Module<Test>;
+	type Slots = slots::Module<Test>;
+	type Registrar = Module<Test>;
+
+	const AUTHORITY_KEYS: [Sr25519Keyring; 8] = [
+		Sr25519Keyring::Alice,
+		Sr25519Keyring::Bob,
+		Sr25519Keyring::Charlie,
+		Sr25519Keyring::Dave,
+		Sr25519Keyring::Eve,
+		Sr25519Keyring::Ferdie,
+		Sr25519Keyring::One,
+		Sr25519Keyring::Two,
+	];
+
+	fn new_test_ext(parachains: Vec<(ParaId, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
+		let mut t = 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,
+		];
+
+		// stashes are the index.
+		let session_keys: Vec<_> = authority_keys.iter().enumerate()
+			.map(|(i, _k)| (i as u64, UintAuthorityId(i as u64)))
+			.collect();
+
+		let authorities: Vec<_> = authority_keys.iter().map(|k| ValidatorId::from(k.public())).collect();
+
+		let balances: Vec<_> = (0..authority_keys.len()).map(|i| (i as u64, 10_000_000)).collect();
+
+		parachains::GenesisConfig {
+			authorities: authorities.clone(),
+		}.assimilate_storage(&mut t).unwrap();
+
+		GenesisConfig::<Test> {
+			parachains,
+			_phdata: Default::default(),
+		}.assimilate_storage(&mut t).unwrap();
+
+		session::GenesisConfig::<Test> {
+			keys: session_keys,
+		}.assimilate_storage(&mut t).unwrap();
+
+		balances::GenesisConfig::<Test> {
+			balances,
+			vesting: vec![],
+		}.assimilate_storage(&mut t).unwrap();
+
+		t.into()
+	}
+
+	fn init_block() {
+		println!("Initializing {}", System::block_number());
+		System::on_initialize(System::block_number());
+		Registrar::on_initialize(System::block_number());
+		Parachains::on_initialize(System::block_number());
+		Slots::on_initialize(System::block_number());
+	}
+
+	fn run_to_block(n: u64) {
+		println!("Running until block {}", n);
+		while System::block_number() < n {
+			if System::block_number() > 1 {
+				println!("Finalizing {}", System::block_number());
+				if !parachains::DidUpdate::exists() {
+					println!("Null heads update");
+					assert_ok!(Parachains::set_heads(system::RawOrigin::None.into(), vec![]));
+				}
+				Slots::on_finalize(System::block_number());
+				Parachains::on_finalize(System::block_number());
+				Registrar::on_finalize(System::block_number());
+				System::on_finalize(System::block_number());
+			}
+			System::set_block_number(System::block_number() + 1);
+			init_block();
+		}
+	}
+
+	fn schedule_thread(id: ParaId, head_data: &[u8], col: &CollatorId) {
+		let tx: LimitParathreadCommits<Test> = LimitParathreadCommits(Default::default());
+		let hdh = BlakeTwo256::hash(head_data);
+		let inner_call = super::Call::select_parathread(id, col.clone(), hdh);
+		let call = Call::Registrar(inner_call);
+		let origin = 4u64;
+		assert!(tx.validate(&origin, &call, Default::default(), 0).is_ok());
+		assert_ok!(call.dispatch(Origin::signed(origin)));
+	}
+
+	fn user_id(i: u32) -> ParaId {
+		(LOWEST_USER_ID.into_inner() + i).into()
+	}
+
+	fn attest(id: ParaId, collator: &CollatorPair, head_data: &[u8], block_data: &[u8]) -> AttestedCandidate {
+		let block_data_hash = BlakeTwo256::hash(block_data);
+		let candidate = CandidateReceipt {
+			parachain_index: id,
+			collator: collator.public(),
+			signature: block_data_hash.using_encoded(|d| collator.sign(d)),
+			head_data: HeadData(head_data.to_vec()),
+			egress_queue_roots: vec![],
+			fees: 0,
+			block_data_hash,
+			upward_messages: vec![],
+		};
+		let payload = (Statement::Valid(candidate.hash()), System::parent_hash()).encode();
+		let roster = Parachains::calculate_duty_roster().0.validator_duty;
+		AttestedCandidate {
+			candidate,
+			validity_votes: AUTHORITY_KEYS.iter()
+				.enumerate()
+				.filter(|(i, _)| roster[*i] == Chain::Parachain(id))
+				.map(|(_, k)| k.sign(&payload).into())
+				.map(ValidityAttestation::Explicit)
+				.collect(),
+			validator_indices: roster.iter()
+				.map(|i| i == &Chain::Parachain(id))
+				.collect::<BitVec>(),
+		}
+	}
+
+	#[test]
+	fn basic_setup_works() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			assert_eq!(super::Parachains::get(), vec![]);
+			assert_eq!(ThreadCount::get(), 0);
+			assert_eq!(Active::get(), vec![]);
+			assert_eq!(NextFreeId::get(), LOWEST_USER_ID);
+			assert_eq!(PendingSwap::get(&ParaId::from(0u32)), None);
+			assert_eq!(Paras::get(&ParaId::from(0u32)), None);
+		});
+	}
+
+	#[test]
+	fn genesis_registration_works() {
+		let parachains = vec![
+			(5u32.into(), vec![1,2,3], vec![1]),
+			(100u32.into(), vec![4,5,6], vec![2,]),
+		];
+
+		with_externalities(&mut new_test_ext(parachains), || {
+			// Need to trigger on_initialize
+			run_to_block(2);
+			// Genesis registration works
+			assert_eq!(Registrar::active_paras(), vec![(5u32.into(), None), (100u32.into(), None)]);
+			assert_eq!(Registrar::paras(&ParaId::from(5u32)), Some(ParaInfo { scheduling: Scheduling::Always }));
+			assert_eq!(Registrar::paras(&ParaId::from(100u32)), Some(ParaInfo { scheduling: Scheduling::Always }));
+			assert_eq!(Parachains::parachain_code(&ParaId::from(5u32)), Some(vec![1, 2, 3]));
+			assert_eq!(Parachains::parachain_code(&ParaId::from(100u32)), Some(vec![4, 5, 6]));
+		});
+	}
+
+	#[test]
+	fn swap_chain_and_thread_works() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 1));
+
+			// Need to trigger on_initialize
+			run_to_block(2);
+
+			// Register a new parathread
+			assert_ok!(Registrar::register_parathread(
+				Origin::signed(1u64),
+				vec![1; 3],
+				vec![1; 3],
+			));
+
+			// Lease out a new parachain
+			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
+			assert_ok!(Slots::bid(Origin::signed(1), 0, 1, 1, 4, 1));
+
+			run_to_block(9);
+			// Ensure that the thread is scheduled around the swap time.
+			let col = Sr25519Keyring::One.public().into();
+			schedule_thread(user_id(0), &[1; 3], &col);
+
+			run_to_block(10);
+			let h = BlakeTwo256::hash(&[2u8; 3]);
+			assert_ok!(Slots::fix_deploy_data(Origin::signed(1), 0, user_id(1), h, vec![2; 3]));
+			assert_ok!(Slots::elaborate_deploy_data(Origin::signed(0), user_id(1), vec![2; 3]));
+			assert_ok!(Slots::set_offboarding(Origin::signed(user_id(1).into_account()), 1));
+
+			run_to_block(11);
+			// should be one active parachain and one active parathread.
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(0), Some((col.clone(), Retriable::WithRetries(0)))),
+				(user_id(1), None),
+			]);
+
+			// One half of the swap call does not actually trigger the swap.
+			assert_ok!(Registrar::swap(parachains::Origin::Parachain(user_id(0)).into(), user_id(1)));
+
+			// Nothing changes from what was originally registered
+			assert_eq!(Registrar::paras(&user_id(0)), Some(ParaInfo { scheduling: Scheduling::Dynamic }));
+			assert_eq!(Registrar::paras(&user_id(1)), Some(ParaInfo { scheduling: Scheduling::Always }));
+			assert_eq!(super::Parachains::get(), vec![user_id(1)]);
+			assert_eq!(Slots::managed_ids(), vec![user_id(1)]);
+			assert_eq!(Slots::deposits(user_id(1)), vec![1; 3]);
+			assert_eq!(Slots::offboarding(user_id(1)), 1);
+			assert_eq!(Parachains::parachain_code(&user_id(0)), Some(vec![1u8; 3]));
+			assert_eq!(Parachains::parachain_head(&user_id(0)), Some(vec![1u8; 3]));
+			assert_eq!(Parachains::parachain_code(&user_id(1)), Some(vec![2u8; 3]));
+			assert_eq!(Parachains::parachain_head(&user_id(1)), Some(vec![2u8; 3]));
+			// Intention to swap is added
+			assert_eq!(PendingSwap::get(user_id(0)), Some(user_id(1)));
+
+			// Intention to swap is reciprocated, swap actually happens
+			assert_ok!(Registrar::swap(parachains::Origin::Parachain(user_id(1)).into(), user_id(0)));
+
+			assert_eq!(Registrar::paras(&user_id(0)), Some(ParaInfo { scheduling: Scheduling::Always }));
+			assert_eq!(Registrar::paras(&user_id(1)), Some(ParaInfo { scheduling: Scheduling::Dynamic }));
+			assert_eq!(super::Parachains::get(), vec![user_id(0)]);
+			assert_eq!(Slots::managed_ids(), vec![user_id(0)]);
+			assert_eq!(Slots::deposits(user_id(0)), vec![1; 3]);
+			assert_eq!(Slots::offboarding(user_id(0)), 1);
+			assert_eq!(Parachains::parachain_code(&user_id(0)), Some(vec![1u8; 3]));
+			assert_eq!(Parachains::parachain_head(&user_id(0)), Some(vec![1u8; 3]));
+			assert_eq!(Parachains::parachain_code(&user_id(1)), Some(vec![2u8; 3]));
+			assert_eq!(Parachains::parachain_head(&user_id(1)), Some(vec![2u8; 3]));
+
+			// Intention to swap is no longer present
+			assert_eq!(PendingSwap::get(user_id(0)), None);
+			assert_eq!(PendingSwap::get(user_id(1)), None);
+
+			run_to_block(12);
+			// thread should not be queued or scheduled any more, even though it would otherwise be
+			// being retried..
+			assert_eq!(Registrar::active_paras(), vec![(user_id(0), None)]);
+		});
+	}
+
+	#[test]
+	fn swap_handles_funds_correctly() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 1));
+
+			// Need to trigger on_initialize
+			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),
+				vec![1; 3],
+				vec![1; 3],
+			));
+
+			// User 2 leases out a new parachain
+			assert_ok!(Slots::new_auction(Origin::ROOT, 5, 1));
+			assert_ok!(Slots::bid(Origin::signed(2), 0, 1, 1, 4, 1));
+
+			run_to_block(9);
+
+			// Swap the parachain and parathread
+			assert_ok!(Registrar::swap(parachains::Origin::Parachain(user_id(0)).into(), user_id(1)));
+			assert_ok!(Registrar::swap(parachains::Origin::Parachain(user_id(1)).into(), user_id(0)));
+
+			// Deregister the parathread that was originally a parachain
+			assert_ok!(Registrar::deregister_parathread(parachains::Origin::Parachain(user_id(1)).into()));
+
+			// Go past when a parachain loses its slot
+			run_to_block(50);
+
+			// Funds are correctly returned
+			assert_eq!(Balances::free_balance(1), initial_1_balance);
+			assert_eq!(Balances::free_balance(2), initial_2_balance);
+		});
+	}
+
+	#[test]
+	fn register_deregister_chains_works() {
+		let parachains = vec![
+			(1u32.into(), vec![1; 3], vec![1; 3]),
+		];
+
+		with_externalities(&mut new_test_ext(parachains), || {
+			// Need to trigger on_initialize
+			run_to_block(2);
+
+			// Genesis registration works
+			assert_eq!(Registrar::active_paras(), vec![(1u32.into(), None)]);
+			assert_eq!(
+				Registrar::paras(&ParaId::from(1u32)),
+				Some(ParaInfo { scheduling: Scheduling::Always })
+			);
+			assert_eq!(Parachains::parachain_code(&ParaId::from(1u32)), Some(vec![1; 3]));
+
+			// Register a new parachain
+			assert_ok!(Registrar::register_para(
+				Origin::ROOT,
+				2u32.into(),
+				ParaInfo { scheduling: Scheduling::Always },
+				vec![2; 3],
+				vec![2; 3],
+			));
+
+			let orig_bal = Balances::free_balance(&3u64);
+			// Register a new parathread
+			assert_ok!(Registrar::register_parathread(
+				Origin::signed(3u64),
+				vec![3; 3],
+				vec![3; 3],
+			));
+			// deposit should be taken (reserved)
+			assert_eq!(Balances::free_balance(&3u64) + ParathreadDeposit::get(), orig_bal);
+			assert_eq!(Balances::reserved_balance(&3u64), ParathreadDeposit::get());
+
+			run_to_block(3);
+
+			// New paras are registered
+			assert_eq!(Registrar::active_paras(), vec![(1u32.into(), None), (2u32.into(), None)]);
+			assert_eq!(
+				Registrar::paras(&ParaId::from(2u32)),
+				Some(ParaInfo { scheduling: Scheduling::Always })
+			);
+			assert_eq!(
+				Registrar::paras(&user_id(0)),
+				Some(ParaInfo { scheduling: Scheduling::Dynamic })
+			);
+			assert_eq!(Parachains::parachain_code(&ParaId::from(2u32)), Some(vec![2; 3]));
+			assert_eq!(Parachains::parachain_code(&user_id(0)), Some(vec![3; 3]));
+
+			assert_ok!(Registrar::deregister_para(Origin::ROOT, 2u32.into()));
+			assert_ok!(Registrar::deregister_parathread(
+				parachains::Origin::Parachain(user_id(0)).into()
+			));
+			// reserved balance should be returned.
+			assert_eq!(Balances::free_balance(&3u64), orig_bal);
+			assert_eq!(Balances::reserved_balance(&3u64), 0);
+
+			run_to_block(4);
+
+			assert_eq!(Registrar::active_paras(), vec![(1u32.into(), None)]);
+			assert_eq!(Registrar::paras(&ParaId::from(2u32)), None);
+			assert_eq!(Parachains::parachain_code(&ParaId::from(2u32)), None);
+			assert_eq!(Registrar::paras(&user_id(0)), None);
+			assert_eq!(Parachains::parachain_code(&user_id(0)), None);
+		});
+	}
+
+	#[test]
+	fn parathread_scheduling_works() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 1));
+
+			run_to_block(2);
+
+			// Register a new parathread
+			assert_ok!(Registrar::register_parathread(
+				Origin::signed(3u64),
+				vec![3; 3],
+				vec![3; 3],
+			));
+
+			run_to_block(3);
+
+			// transaction submitted to get parathread progressed.
+			let col = Sr25519Keyring::One.public().into();
+			schedule_thread(user_id(0), &[3; 3], &col);
+
+			run_to_block(5);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(0), Some((col.clone(), Retriable::WithRetries(0))))
+			]);
+			assert_ok!(Parachains::set_heads(Origin::NONE, vec![
+				attest(user_id(0), &Sr25519Keyring::One.pair().into(), &[3; 3], &[0; 0])
+			]));
+
+			run_to_block(6);
+			// at next block, it shouldn't be retried.
+			assert_eq!(Registrar::active_paras(), vec![]);
+		});
+	}
+
+	#[test]
+	fn removing_scheduled_parathread_works() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 1));
+
+			run_to_block(2);
+
+			// Register some parathreads.
+			assert_ok!(Registrar::register_parathread(Origin::signed(3), vec![3; 3], vec![3; 3]));
+
+			run_to_block(3);
+			// transaction submitted to get parathread progressed.
+			let col = Sr25519Keyring::One.public().into();
+			schedule_thread(user_id(0), &[3; 3], &col);
+
+			// now we remove the parathread
+			assert_ok!(Registrar::deregister_parathread(
+				parachains::Origin::Parachain(user_id(0)).into()
+			));
+
+			run_to_block(5);
+			assert_eq!(Registrar::active_paras(), vec![]);  // should not be scheduled.
+
+			assert_ok!(Registrar::register_parathread(Origin::signed(3), vec![4; 3], vec![4; 3]));
+
+			run_to_block(6);
+			// transaction submitted to get parathread progressed.
+			schedule_thread(user_id(1), &[4; 3], &col);
+
+			run_to_block(9);
+			// thread's slot was missed and is now being re-scheduled.
+
+			assert_ok!(Registrar::deregister_parathread(
+				parachains::Origin::Parachain(user_id(1)).into()
+			));
+
+			run_to_block(10);
+			// thread's rescheduled slot was missed, but should not be reschedule since it was
+			// removed.
+			assert_eq!(Registrar::active_paras(), vec![]);  // should not be scheduled.
+		});
+	}
+
+	#[test]
+	fn parathread_rescheduling_works() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 1));
+
+			run_to_block(2);
+
+			// Register some parathreads.
+			assert_ok!(Registrar::register_parathread(Origin::signed(3), vec![3; 3], vec![3; 3]));
+			assert_ok!(Registrar::register_parathread(Origin::signed(4), vec![4; 3], vec![4; 3]));
+			assert_ok!(Registrar::register_parathread(Origin::signed(5), vec![5; 3], vec![5; 3]));
+
+			run_to_block(3);
+
+			// transaction submitted to get parathread progressed.
+			let col = Sr25519Keyring::One.public().into();
+			schedule_thread(user_id(0), &[3; 3], &col);
+
+			// 4x: the initial time it was scheduled, plus 3 retries.
+			for n in 5..9 {
+				run_to_block(n);
+				assert_eq!(Registrar::active_paras(), vec![
+					(user_id(0), Some((col.clone(), Retriable::WithRetries((n - 5) as u32))))
+				]);
+			}
+
+			// missed too many times. dropped.
+			run_to_block(9);
+			assert_eq!(Registrar::active_paras(), vec![]);
+
+			// schedule and miss all 3 and check that they go through the queueing system ok.
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 2));
+			schedule_thread(user_id(0), &[3; 3], &col);
+			schedule_thread(user_id(1), &[4; 3], &col);
+
+			run_to_block(10);
+			schedule_thread(user_id(2), &[5; 3], &col);
+
+			// 0 and 1 scheduled as normal.
+			run_to_block(11);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(0), Some((col.clone(), Retriable::WithRetries(0)))),
+				(user_id(1), Some((col.clone(), Retriable::WithRetries(0))))
+			]);
+
+			// 2 scheduled, 0 retried
+			run_to_block(12);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(0), Some((col.clone(), Retriable::WithRetries(1)))),
+				(user_id(2), Some((col.clone(), Retriable::WithRetries(0)))),
+			]);
+
+			// 1 retried
+			run_to_block(13);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(1), Some((col.clone(), Retriable::WithRetries(1))))
+			]);
+
+			// 2 retried
+			run_to_block(14);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(2), Some((col.clone(), Retriable::WithRetries(1))))
+			]);
+
+			run_to_block(15);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(0), Some((col.clone(), Retriable::WithRetries(2))))
+			]);
+
+			run_to_block(16);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(1), Some((col.clone(), Retriable::WithRetries(2))))
+			]);
+
+			run_to_block(17);
+			assert_eq!(Registrar::active_paras(), vec![
+				(user_id(2), Some((col.clone(), Retriable::WithRetries(2))))
+			]);
+		});
+	}
+
+	#[test]
+	fn parathread_auction_handles_basic_errors() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			run_to_block(2);
+			let o = Origin::signed(0);
+			assert_ok!(Registrar::register_parathread(o, vec![7, 8, 9], vec![1, 1, 1]));
+
+			run_to_block(3);
+			assert_eq!(
+				Registrar::paras(&user_id(0)),
+				Some(ParaInfo { scheduling: Scheduling::Dynamic })
+			);
+
+			let good_para_id = user_id(0);
+			let bad_para_id = user_id(1);
+			let bad_head_hash = <Test as system::Trait>::Hashing::hash(&vec![1, 2, 1]);
+			let good_head_hash = <Test as system::Trait>::Hashing::hash(&vec![1, 1, 1]);
+			let info = DispatchInfo::default();
+
+			// Allow for threads
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 10));
+
+			// Bad parathread id
+			let col = CollatorId::default();
+			let inner = super::Call::select_parathread(bad_para_id, col.clone(), good_head_hash);
+			let call = Call::Registrar(inner);
+			assert!(
+				LimitParathreadCommits::<Test>(std::marker::PhantomData)
+					.validate(&0, &call, info, 0).is_err()
+			);
+
+			// Bad head data
+			let inner = super::Call::select_parathread(good_para_id, col.clone(), bad_head_hash);
+			let call = Call::Registrar(inner);
+			assert!(
+				LimitParathreadCommits::<Test>(std::marker::PhantomData)
+					.validate(&0, &call, info, 0).is_err()
+			);
+
+			// No duplicates
+			let inner = super::Call::select_parathread(good_para_id, col.clone(), good_head_hash);
+			let call = Call::Registrar(inner);
+			assert!(
+				LimitParathreadCommits::<Test>(std::marker::PhantomData)
+					.validate(&0, &call, info, 0).is_ok()
+			);
+			assert!(
+				LimitParathreadCommits::<Test>(std::marker::PhantomData)
+					.validate(&0, &call, info, 0).is_err()
+			);
+		});
+	}
+
+	#[test]
+	fn parathread_auction_works() {
+		with_externalities(&mut new_test_ext(vec![]), || {
+			run_to_block(2);
+			// Register 5 parathreads
+			for x in 0..5 {
+				let o = Origin::signed(x as u64);
+				assert_ok!(Registrar::register_parathread(o, vec![x; 3], vec![x; 3]));
+			}
+
+			run_to_block(3);
+
+			for x in 0..5 {
+				assert_eq!(
+					Registrar::paras(&user_id(x)),
+					Some(ParaInfo { scheduling: Scheduling::Dynamic })
+				);
+			}
+
+			// Only 3 slots available... who will win??
+			assert_ok!(Registrar::set_thread_count(Origin::ROOT, 3));
+
+			// Everyone wants a thread
+			for x in 0..5 {
+				let para_id = user_id(x as u32);
+				let collator_id = CollatorId::default();
+				let head_hash = <Test as system::Trait>::Hashing::hash(&vec![x; 3]);
+				let inner = super::Call::select_parathread(para_id, collator_id, head_hash);
+				let call = Call::Registrar(inner);
+				let info = DispatchInfo::default();
+
+				// First 3 transactions win a slot
+				if x < 3 {
+					assert!(
+						LimitParathreadCommits::<Test>(std::marker::PhantomData)
+							.validate(&0, &call, info, 0)
+							.is_ok()
+					);
+				} else {
+					// All others lose
+					assert_noop!(
+						LimitParathreadCommits::<Test>(std::marker::PhantomData)
+							.validate(&0, &call, info, 0),
+						InvalidTransaction::ExhaustsResources.into()
+					);
+				}
+			}
+
+			// 3 Threads are selected
+			assert_eq!(
+				SelectedThreads::get()[1],
+				vec![
+					(user_id(0), CollatorId::default()),
+					(user_id(1), CollatorId::default()),
+					(user_id(2), CollatorId::default()),
+				]
+			);
+
+			// Assuming Queue Size is 2
+			assert_eq!(<Test as self::Trait>::QueueSize::get(), 2);
+
+			// 2 blocks later
+			run_to_block(5);
+			// Threads left queue
+			assert_eq!(SelectedThreads::get()[0], vec![]);
+			// Threads are active
+			assert_eq!(
+				Registrar::active_paras(),
+				vec![
+					(user_id(0), Some((CollatorId::default(), Retriable::WithRetries(0)))),
+					(user_id(1), Some((CollatorId::default(), Retriable::WithRetries(0)))),
+					(user_id(2), Some((CollatorId::default(), Retriable::WithRetries(0)))),
+				]
+			);
+		});
+	}
+}
diff --git a/polkadot/runtime/src/slots.rs b/polkadot/runtime/src/slots.rs
index 944c6b6057e..5c4f04f56b5 100644
--- a/polkadot/runtime/src/slots.rs
+++ b/polkadot/runtime/src/slots.rs
@@ -19,20 +19,21 @@
 //! information for commissioning and decommissioning them.
 
 use rstd::{prelude::*, mem::swap, convert::TryInto};
-use sr_primitives::traits::{CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash};
+use sr_primitives::traits::{CheckedSub, StaticLookup, Zero, One, CheckedConversion, Hash, AccountIdConversion};
 use sr_primitives::weights::SimpleDispatchInfo;
-use codec::{Encode, Decode};
+use codec::{Encode, Decode, Codec};
 use srml_support::{
 	decl_module, decl_storage, decl_event, ensure,
 	traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get},
 };
-use primitives::parachain::AccountIdConversion;
-use crate::parachains::ParachainRegistrar;
+use primitives::parachain::{
+	SwapAux, PARACHAIN_INFO, Id as ParaId
+};
 use system::{ensure_signed, ensure_root};
+use crate::registrar::{Registrar, swap_ordered_existence};
 use crate::slot_range::{SlotRange, SLOT_RANGE_COUNT};
 
 type BalanceOf<T> = <<T as Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
-type ParaIdOf<T> = <<T as Trait>::Parachains as ParachainRegistrar<<T as system::Trait>::AccountId>>::ParaId;
 
 /// The module's configuration trait.
 pub trait Trait: system::Trait {
@@ -43,7 +44,7 @@ pub trait Trait: system::Trait {
 	type Currency: ReservableCurrency<Self::AccountId>;
 
 	/// The parachain registrar type.
-	type Parachains: ParachainRegistrar<Self::AccountId>;
+	type Parachains: Registrar<Self::AccountId>;
 
 	/// The number of blocks over which an auction may be retroactively ended.
 	type EndingPeriod: Get<Self::BlockNumber>;
@@ -74,7 +75,7 @@ pub struct NewBidder<AccountId> {
 /// The desired target of a bidder in an auction.
 #[derive(Clone, Eq, PartialEq, Encode, Decode)]
 #[cfg_attr(feature = "std", derive(Debug))]
-pub enum Bidder<AccountId, ParaId> {
+pub enum Bidder<AccountId> {
 	/// An account ID, funds coming from that account.
 	New(NewBidder<AccountId>),
 
@@ -83,7 +84,7 @@ pub enum Bidder<AccountId, ParaId> {
 	Existing(ParaId),
 }
 
-impl<AccountId: Clone, ParaId: AccountIdConversion<AccountId>> Bidder<AccountId, ParaId> {
+impl<AccountId: Clone + Default + Codec> Bidder<AccountId> {
 	/// Get the account that will fund this bid.
 	fn funding_account(&self) -> AccountId {
 		match self {
@@ -110,10 +111,12 @@ pub enum IncomingParachain<AccountId, Hash> {
 
 type LeasePeriodOf<T> = <T as system::Trait>::BlockNumber;
 // Winning data type. This encodes the top bidders of each range together with their bid.
-type WinningData<T> = [Option<(Bidder<<T as system::Trait>::AccountId, ParaIdOf<T>>, BalanceOf<T>)>; SLOT_RANGE_COUNT];
+type WinningData<T> =
+	[Option<(Bidder<<T as system::Trait>::AccountId>, BalanceOf<T>)>; SLOT_RANGE_COUNT];
 // Winners data type. This encodes each of the final winners of a parachain auction, the parachain
 // index assigned to them, their winning bid and the range that they won.
-type WinnersData<T> = Vec<(Option<NewBidder<<T as system::Trait>::AccountId>>, ParaIdOf<T>, BalanceOf<T>, SlotRange)>;
+type WinnersData<T> =
+	Vec<(Option<NewBidder<<T as system::Trait>::AccountId>>, ParaId, BalanceOf<T>, SlotRange)>;
 
 // This module's storage items.
 decl_storage! {
@@ -122,9 +125,9 @@ decl_storage! {
 		/// The number of auctions that been started so far.
 		pub AuctionCounter get(auction_counter): AuctionIndex;
 
-		/// All `ParaId` values that are managed by this module. This includes chains that are not
-		/// yet deployed (but have won an auction in the future).
-		pub ManagedIds get(managed_ids): Vec<ParaIdOf<T>>;
+		/// Ordered list of all `ParaId` values that are managed by this module. This includes
+		/// chains that are not yet deployed (but have won an auction in the future).
+		pub ManagedIds get(managed_ids): Vec<ParaId>;
 
 		/// Various amounts on deposit for each parachain. An entry in `ManagedIds` implies a non-
 		/// default entry here.
@@ -139,7 +142,7 @@ decl_storage! {
 		/// If a parachain doesn't exist *yet* but is scheduled to exist in the future, then it
 		/// will be left-padded with one or more zeroes to denote the fact that nothing is held on
 		/// deposit for the non-existent chain currently, but is held at some point in the future.
-		pub Deposits get(deposits): map ParaIdOf<T> => Vec<BalanceOf<T>>;
+		pub Deposits get(deposits): map ParaId => Vec<BalanceOf<T>>;
 
 		/// Information relating to the current auction, if there is one.
 		///
@@ -155,22 +158,37 @@ decl_storage! {
 
 		/// Amounts currently reserved in the accounts of the bidders currently winning
 		/// (sub-)ranges.
-		pub ReservedAmounts get(reserved_amounts): map Bidder<T::AccountId, ParaIdOf<T>> => Option<BalanceOf<T>>;
+		pub ReservedAmounts get(reserved_amounts): map Bidder<T::AccountId> => Option<BalanceOf<T>>;
 
 		/// The set of Para IDs that have won and need to be on-boarded at an upcoming lease-period.
 		/// This is cleared out on the first block of the lease period.
-		pub OnboardQueue get(onboard_queue): map LeasePeriodOf<T> => Vec<ParaIdOf<T>>;
+		pub OnboardQueue get(onboard_queue): map LeasePeriodOf<T> => Vec<ParaId>;
 
 		/// The actual on-boarding information. Only exists when one of the following is true:
 		/// - It is before the lease period that the parachain should be on-boarded.
 		/// - The full on-boarding information has not yet been provided and the parachain is not
 		/// yet due to be off-boarded.
-		pub Onboarding get(onboarding): map ParaIdOf<T> =>
+		pub Onboarding get(onboarding): map ParaId =>
 			Option<(LeasePeriodOf<T>, IncomingParachain<T::AccountId, T::Hash>)>;
 
 		/// Off-boarding account; currency held on deposit for the parachain gets placed here if the
 		/// parachain gets off-boarded; i.e. its lease period is up and it isn't renewed.
-		pub Offboarding get(offboarding): map ParaIdOf<T> => T::AccountId;
+		pub Offboarding get(offboarding): map ParaId => T::AccountId;
+	}
+}
+
+impl<T: Trait> SwapAux for Module<T> {
+	fn ensure_can_swap(one: ParaId, other: ParaId) -> Result<(), &'static str> {
+		if <Onboarding<T>>::exists(one) || <Onboarding<T>>::exists(other) {
+			Err("can't swap an undeployed parachain")?
+		}
+		Ok(())
+	}
+	fn on_swap(one: ParaId, other: ParaId) -> Result<(), &'static str> {
+		<Offboarding<T>>::swap(one, other);
+		<Deposits<T>>::swap(one, other);
+		ManagedIds::mutate(|ids| swap_ordered_existence(ids, one, other));
+		Ok(())
 	}
 }
 
@@ -179,7 +197,7 @@ decl_event!(
 		AccountId = <T as system::Trait>::AccountId,
 		BlockNumber = <T as system::Trait>::BlockNumber,
 		LeasePeriod = LeasePeriodOf<T>,
-		ParaId = ParaIdOf<T>,
+		ParaId = ParaId,
 		Balance = BalanceOf<T>,
 	{
 		/// A new lease period is beginning.
@@ -281,7 +299,7 @@ decl_module! {
 		/// - `amount` is the amount to bid to be held as deposit for the parachain should the
 		/// bid win. This amount is held throughout the range.
 		#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
-		fn bid(origin,
+		pub fn bid(origin,
 			#[compact] sub: SubId,
 			#[compact] auction_index: AuctionIndex,
 			#[compact] first_slot: LeasePeriodOf<T>,
@@ -308,7 +326,7 @@ decl_module! {
 		/// absolute lease period index value, not an auction-specific offset.
 		/// - `amount` is the amount to bid to be held as deposit for the parachain should the
 		/// bid win. This amount is held throughout the range.
-    #[weight = SimpleDispatchInfo::FixedNormal(500_000)]
+		#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
 		fn bid_renew(origin,
 			#[compact] auction_index: AuctionIndex,
 			#[compact] first_slot: LeasePeriodOf<T>,
@@ -316,7 +334,7 @@ decl_module! {
 			#[compact] amount: BalanceOf<T>
 		) {
 			let who = ensure_signed(origin)?;
-			let para_id = <ParaIdOf<T>>::try_from_account(&who)
+			let para_id = <ParaId>::try_from_account(&who)
 				.ok_or("account is not a parachain")?;
 			let bidder = Bidder::Existing(para_id);
 			Self::handle_bid(bidder, auction_index, first_slot, last_slot, amount)?;
@@ -328,10 +346,10 @@ decl_module! {
 		///
 		/// - `dest` is the destination account to receive the parachain's deposit.
 		#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
-		fn set_offboarding(origin, dest: <T::Lookup as StaticLookup>::Source) {
+		pub fn set_offboarding(origin, dest: <T::Lookup as StaticLookup>::Source) {
 			let who = ensure_signed(origin)?;
 			let dest = T::Lookup::lookup(dest)?;
-			let para_id = <ParaIdOf<T>>::try_from_account(&who)
+			let para_id = <ParaId>::try_from_account(&who)
 				.ok_or("not a parachain origin")?;
 			<Offboarding<T>>::insert(para_id, dest);
 		}
@@ -343,10 +361,10 @@ decl_module! {
 		/// - `para_id` is the parachain ID allotted to the winning bidder.
 		/// - `code_hash` is the hash of the parachain's Wasm validation function.
 		/// - `initial_head_data` is the parachain's initial head data.
-    #[weight = SimpleDispatchInfo::FixedNormal(500_000)]
+		#[weight = SimpleDispatchInfo::FixedNormal(500_000)]
 		pub fn fix_deploy_data(origin,
 			#[compact] sub: SubId,
-			#[compact] para_id: ParaIdOf<T>,
+			#[compact] para_id: ParaId,
 			code_hash: T::Hash,
 			initial_head_data: Vec<u8>
 		) {
@@ -375,7 +393,7 @@ decl_module! {
 		/// - `para_id` is the parachain ID whose code will be elaborated.
 		/// - `code` is the preimage of the registered `code_hash` of `para_id`.
 		#[weight = SimpleDispatchInfo::FixedNormal(5_000_000)]
-		fn elaborate_deploy_data(_origin, #[compact] para_id: ParaIdOf<T>, code: Vec<u8>) {
+		pub fn elaborate_deploy_data(_origin, #[compact] para_id: ParaId, code: Vec<u8>) {
 			let (starts, details) = <Onboarding<T>>::get(&para_id)
 				.ok_or("parachain id not in onboarding")?;
 			if let IncomingParachain::Fixed{code_hash, initial_head_data} = details {
@@ -388,7 +406,8 @@ decl_module! {
 					// Should have already begun. Remove the on-boarding entry and register the
 					// parachain for its immediate start.
 					<Onboarding<T>>::remove(&para_id);
-					let _ = T::Parachains::register_parachain(para_id, code, initial_head_data);
+					let _ = T::Parachains::
+						register_para(para_id, PARACHAIN_INFO, code, initial_head_data);
 				}
 			} else {
 				return Err("deploy data not yet fixed")
@@ -399,7 +418,7 @@ decl_module! {
 
 impl<T: Trait> Module<T> {
 	/// Deposit currently held for a particular parachain that we administer.
-	fn deposit_held(para_id: &ParaIdOf<T>) -> BalanceOf<T> {
+	fn deposit_held(para_id: &ParaId) -> BalanceOf<T> {
 		<Deposits<T>>::get(para_id).into_iter().max().unwrap_or_else(Zero::zero)
 	}
 
@@ -493,8 +512,14 @@ impl<T: Trait> Module<T> {
 
 					// Add para IDs of any chains that will be newly deployed to our set of managed
 					// IDs.
-					<ManagedIds<T>>::mutate(|m| m.push(para_id));
-
+					ManagedIds::mutate(|ids|
+						if let Err(pos) = ids.binary_search(&para_id) {
+							ids.insert(pos, para_id)
+						} else {
+							// This can't happen as it's a winner being newly
+							// deployed and thus the para_id shouldn't already be being managed.
+						}
+					);
 					Self::deposit_event(RawEvent::WonDeploy(bidder.clone(), range, para_id, amount));
 
 					// Add a deployment record so we know to on-board them at the appropriate
@@ -573,7 +598,7 @@ impl<T: Trait> Module<T> {
 		Self::deposit_event(RawEvent::NewLeasePeriod(lease_period_index));
 		// First, bump off old deposits and decommission any managed chains that are coming
 		// to a close.
-		<ManagedIds<T>>::mutate(|ids| {
+		ManagedIds::mutate(|ids| {
 			let new = ids.drain(..).filter(|id| {
 				let mut d = <Deposits<T>>::get(id);
 				if !d.is_empty() {
@@ -586,7 +611,7 @@ impl<T: Trait> Module<T> {
 							// Only unregister it if it was actually registered in the first place.
 							// If the on-boarding entry still existed, then it was never actually
 							// commissioned.
-							let _ = T::Parachains::deregister_parachain(id.clone());
+							let _ = T::Parachains::deregister_para(id.clone());
 						}
 						// Return the full deposit to the off-boarding account.
 						T::Currency::deposit_creating(&<Offboarding<T>>::take(id), d[0]);
@@ -628,7 +653,8 @@ impl<T: Trait> Module<T> {
 			{
 				// The chain's deployment data is set; go ahead and register it, and remove the
 				// now-redundant on-boarding entry.
-				let _ = T::Parachains::register_parachain(para_id.clone(), code, initial_head_data);
+				let _ = T::Parachains::
+					register_para(para_id.clone(), PARACHAIN_INFO, code, initial_head_data);
 				// ^^ not much we can do if it fails for some reason.
 				<Onboarding<T>>::remove(para_id)
 			}
@@ -644,7 +670,7 @@ impl<T: Trait> Module<T> {
 	/// - `last_slot`: The last lease period index of the range to be bid on (inclusive).
 	/// - `amount`: The total amount to be the bid for deposit over the range.
 	pub fn handle_bid(
-		bidder: Bidder<T::AccountId, ParaIdOf<T>>,
+		bidder: Bidder<T::AccountId>,
 		auction_index: u32,
 		first_slot: LeasePeriodOf<T>,
 		last_slot: LeasePeriodOf<T>,
@@ -735,7 +761,7 @@ impl<T: Trait> Module<T> {
 	/// https://github.com/w3f/consensus/blob/master/NPoS/auctiondynamicthing.py
 	fn calculate_winners(
 		mut winning: WinningData<T>,
-		new_id: impl Fn() -> ParaIdOf<T>
+		new_id: impl Fn() -> ParaId
 	) -> WinnersData<T> {
 		let winning_ranges = {
 			let mut best_winners_ending_at:
@@ -783,7 +809,6 @@ impl<T: Trait> Module<T> {
 	}
 }
 
-
 /// tests for this module
 #[cfg(test)]
 mod tests {
@@ -799,7 +824,7 @@ mod tests {
 	};
 	use srml_support::{impl_outer_origin, parameter_types, assert_ok, assert_noop};
 	use balances;
-	use primitives::parachain::Id as ParaId;
+	use primitives::parachain::{Id as ParaId, Info as ParaInfo};
 
 	impl_outer_origin! {
 		pub enum Origin for Test {}
@@ -866,16 +891,16 @@ mod tests {
 	}
 
 	pub struct TestParachains;
-	impl ParachainRegistrar<u64> for TestParachains {
-		type ParaId = ParaId;
-		fn new_id() -> Self::ParaId {
+	impl Registrar<u64> for TestParachains {
+		fn new_id() -> ParaId {
 			PARACHAIN_COUNT.with(|p| {
 				*p.borrow_mut() += 1;
 				(*p.borrow() - 1).into()
 			})
 		}
-		fn register_parachain(
-			id: Self::ParaId,
+		fn register_para(
+			id: ParaId,
+			_info: ParaInfo,
 			code: Vec<u8>,
 			initial_head_data: Vec<u8>
 		) -> Result<(), &'static str> {
@@ -887,7 +912,7 @@ mod tests {
 				Ok(())
 			})
 		}
-		fn deregister_parachain(id: Self::ParaId) -> Result<(), &'static str> {
+		fn deregister_para(id: ParaId) -> Result<(), &'static str> {
 			PARACHAINS.with(|p| {
 				if !p.borrow().contains_key(&id.into_inner()) {
 					panic!("ID doesn't exist")
diff --git a/polkadot/runtime/src/testing.rs b/polkadot/runtime/src/testing.rs
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/polkadot/service/src/chain_spec.rs b/polkadot/service/src/chain_spec.rs
index 25943a2b1ad..2dde54059ca 100644
--- a/polkadot/service/src/chain_spec.rs
+++ b/polkadot/service/src/chain_spec.rs
@@ -22,7 +22,7 @@ use polkadot_runtime::{
 	GenesisConfig, CouncilConfig, ElectionsConfig, DemocracyConfig, SystemConfig,
 	SessionConfig, StakingConfig, BalancesConfig, SessionKeys, TechnicalCommitteeConfig,
 	SudoConfig, IndicesConfig, StakerStatus, WASM_BINARY,
-	ClaimsConfig, ParachainsConfig
+	ClaimsConfig, ParachainsConfig, RegistrarConfig
 };
 use polkadot_runtime::constants::{currency::DOTS, time::*};
 use sr_primitives::Perbill;
@@ -151,6 +151,8 @@ fn staging_testnet_config_genesis() -> GenesisConfig {
 		authority_discovery: Some(Default::default()),
 		parachains: Some(ParachainsConfig {
 			authorities: vec![],
+		}),
+		registrar: Some(RegistrarConfig {
 			parachains: vec![],
 			_phdata: Default::default(),
 		}),
@@ -289,6 +291,8 @@ pub fn testnet_genesis(
 		authority_discovery: Some(Default::default()),
 		parachains: Some(ParachainsConfig {
 			authorities: vec![],
+		}),
+		registrar: Some(RegistrarConfig{
 			parachains: vec![],
 			_phdata: Default::default(),
 		}),
diff --git a/polkadot/test-parachains/adder/wasm/Cargo.toml b/polkadot/test-parachains/adder/wasm/Cargo.toml
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/polkadot/validation/src/evaluation.rs b/polkadot/validation/src/evaluation.rs
index 0099f489a09..778a735925f 100644
--- a/polkadot/validation/src/evaluation.rs
+++ b/polkadot/validation/src/evaluation.rs
@@ -20,7 +20,7 @@ use super::MAX_TRANSACTIONS_SIZE;
 
 use codec::Encode;
 use polkadot_primitives::{Block, Hash, BlockNumber};
-use polkadot_primitives::parachain::Id as ParaId;
+use polkadot_primitives::parachain::{Id as ParaId, CollatorId, Retriable};
 
 /// Result type alias for block evaluation
 pub type Result<T> = std::result::Result<T, Error>;
@@ -66,7 +66,7 @@ pub fn evaluate_initial(
 	_now: u64,
 	parent_hash: &Hash,
 	parent_number: BlockNumber,
-	_active_parachains: &[ParaId],
+	_active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)],
 ) -> Result<()> {
 	let transactions_size = proposal.extrinsics.iter().fold(0, |a, tx| {
 		a + Encode::encode(tx).len()
diff --git a/polkadot/validation/src/lib.rs b/polkadot/validation/src/lib.rs
index ddf6d538dc6..8382ec0a034 100644
--- a/polkadot/validation/src/lib.rs
+++ b/polkadot/validation/src/lib.rs
@@ -763,7 +763,7 @@ impl<C, TxApi> CreateProposal<C, TxApi> where
 			self.believed_minimum_timestamp,
 			&self.parent_hash,
 			self.parent_number,
-			&active_parachains,
+			&active_parachains[..],
 		).is_ok());
 
 		Ok(new_block)
-- 
GitLab