diff --git a/polkadot/availability-store/src/lib.rs b/polkadot/availability-store/src/lib.rs
index 7abc444758f7c23409e7cc726ccff8c53ecd4bcc..4b973c7d027114101e1e4b0510ffe565ded5ea69 100644
--- a/polkadot/availability-store/src/lib.rs
+++ b/polkadot/availability-store/src/lib.rs
@@ -25,12 +25,10 @@
 use futures::prelude::*;
 use futures::channel::{mpsc, oneshot};
 use keystore::KeyStorePtr;
-use polkadot_primitives::{
+use polkadot_primitives::v0::{
 	Hash, Block,
-	parachain::{
-		PoVBlock, AbridgedCandidateReceipt, ErasureChunk,
-		ParachainHost, AvailableData, OmittedValidationData,
-	},
+	PoVBlock, AbridgedCandidateReceipt, ErasureChunk,
+	ParachainHost, AvailableData, OmittedValidationData,
 };
 use sp_runtime::traits::HashFor;
 use sp_blockchain::Result as ClientResult;
diff --git a/polkadot/availability-store/src/store.rs b/polkadot/availability-store/src/store.rs
index 851beabc6ac87888436e5ef08a1bb42d04960193..cd76de5d44adb9ebddf28d16db69fe9e2b15b8b2 100644
--- a/polkadot/availability-store/src/store.rs
+++ b/polkadot/availability-store/src/store.rs
@@ -19,11 +19,8 @@ use kvdb_rocksdb::{Database, DatabaseConfig};
 use kvdb::{KeyValueDB, DBTransaction};
 use codec::{Encode, Decode};
 use polkadot_erasure_coding as erasure;
-use polkadot_primitives::{
-	Hash,
-	parachain::{
-		ErasureChunk, AvailableData, AbridgedCandidateReceipt,
-	},
+use polkadot_primitives::v0::{
+	Hash, ErasureChunk, AvailableData, AbridgedCandidateReceipt,
 };
 use parking_lot::Mutex;
 
@@ -273,7 +270,7 @@ impl Store {
 			// If there are no block data in the store at this point,
 			// check that they can be reconstructed now and add them to store if they can.
 			if self.execution_data(&candidate_hash).is_none() {
-				if let Ok(available_data) = erasure::reconstruct(
+				if let Ok(available_data) = erasure::reconstruct_v0(
 					n_validators as usize,
 					v.iter().map(|chunk| (chunk.chunk.as_ref(), chunk.index as usize)),
 				)
@@ -390,7 +387,7 @@ impl Store {
 mod tests {
 	use super::*;
 	use polkadot_erasure_coding::{self as erasure};
-	use polkadot_primitives::parachain::{
+	use polkadot_primitives::v0::{
 		Id as ParaId, BlockData, AvailableData, PoVBlock, OmittedValidationData,
 	};
 
@@ -489,7 +486,7 @@ mod tests {
 		let available_data = available_data(&[42; 8]);
 		let n_validators = 5;
 
-		let erasure_chunks = erasure::obtain_chunks(
+		let erasure_chunks = erasure::obtain_chunks_v0(
 			n_validators,
 			&available_data,
 		).unwrap();
diff --git a/polkadot/availability-store/src/worker.rs b/polkadot/availability-store/src/worker.rs
index 8a3898579f54e736f0704728f4ceb4935e1c3e9c..a7cf7ec41dae3a01aa0c83e4ff7c17938dcfb233 100644
--- a/polkadot/availability-store/src/worker.rs
+++ b/polkadot/availability-store/src/worker.rs
@@ -33,8 +33,8 @@ use consensus_common::{
 	import_queue::CacheKeyId,
 };
 use sp_core::traits::SpawnNamed;
-use polkadot_primitives::{Block, BlockId, Hash};
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{
+	Block, BlockId, Hash,
 	ParachainHost, ValidatorId, AbridgedCandidateReceipt, AvailableData,
 	ValidatorPair, ErasureChunk,
 };
diff --git a/polkadot/collator/src/lib.rs b/polkadot/collator/src/lib.rs
index 0215b33ee6a1899c85523b3a04bc6430ee72eaf5..663cb825bfc1adb5d8ce747b81b330c91c4e262e 100644
--- a/polkadot/collator/src/lib.rs
+++ b/polkadot/collator/src/lib.rs
@@ -55,12 +55,11 @@ use log::warn;
 use sc_client_api::{StateBackend, BlockchainEvents};
 use sp_blockchain::HeaderBackend;
 use sp_core::Pair;
-use polkadot_primitives::{
+use polkadot_primitives::v0::{
 	BlockId, Hash, Block, DownwardMessage,
-	parachain::{
-		self, BlockData, DutyRoster, HeadData, Id as ParaId,
-		PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationSchedule,
-	}
+	BlockData, DutyRoster, HeadData, Id as ParaId,
+	PoVBlock, ValidatorId, CollatorPair, LocalValidationData, GlobalValidationSchedule,
+	Collation, CollationInfo, collator_signature_payload,
 };
 use polkadot_cli::{
 	ProvideRuntimeApi, ParachainHost, IdentifyVariant,
@@ -69,7 +68,7 @@ use polkadot_cli::{
 pub use polkadot_cli::service::Configuration;
 pub use polkadot_cli::Cli;
 pub use polkadot_validation::SignedStatement;
-pub use polkadot_primitives::parachain::CollatorId;
+pub use polkadot_primitives::v0::CollatorId;
 pub use sc_network::PeerId;
 pub use service::RuntimeApiCollection;
 pub use sc_cli::SubstrateCli;
@@ -164,7 +163,7 @@ pub async fn collate<P>(
 	downward_messages: Vec<DownwardMessage>,
 	mut para_context: P,
 	key: Arc<CollatorPair>,
-) -> Option<parachain::Collation>
+) -> Option<Collation>
 	where
 		P: ParachainContext,
 		P::ProduceCandidate: Send,
@@ -181,13 +180,13 @@ pub async fn collate<P>(
 	};
 
 	let pov_block_hash = pov_block.hash();
-	let signature = key.sign(&parachain::collator_signature_payload(
+	let signature = key.sign(&collator_signature_payload(
 		&relay_parent,
 		&local_id,
 		&pov_block_hash,
 	));
 
-	let info = parachain::CollationInfo {
+	let info = CollationInfo {
 		parachain_index: local_id,
 		relay_parent,
 		collator: key.public(),
@@ -196,7 +195,7 @@ pub async fn collate<P>(
 		pov_block_hash,
 	};
 
-	let collation = parachain::Collation {
+	let collation = Collation {
 		info,
 		pov: pov_block,
 	};
@@ -456,7 +455,7 @@ where
 
 #[cfg(not(feature = "service-rewr"))]
 fn compute_targets(para_id: ParaId, session_keys: &[ValidatorId], roster: DutyRoster) -> HashSet<ValidatorId> {
-	use polkadot_primitives::parachain::Chain;
+	use polkadot_primitives::v0::Chain;
 
 	roster.validator_duty.iter().enumerate()
 		.filter(|&(_, c)| c == &Chain::Parachain(para_id))
diff --git a/polkadot/core-primitives/src/lib.rs b/polkadot/core-primitives/src/lib.rs
index d91ed3cfc1973871613e589a6426f95a769d9ea8..ffb346467d9e53c0c64ebca4438a9260492fdd8e 100644
--- a/polkadot/core-primitives/src/lib.rs
+++ b/polkadot/core-primitives/src/lib.rs
@@ -94,3 +94,8 @@ pub enum DownwardMessage<AccountId = crate::AccountId> {
 	/// XCMP message for the Parachain.
 	XCMPMessage(sp_std::vec::Vec<u8>),
 }
+
+/// V1 primitives.
+pub mod v1 {
+	pub use super::*;
+}
diff --git a/polkadot/erasure-coding/src/lib.rs b/polkadot/erasure-coding/src/lib.rs
index 98a2776d8848a543b31e170e9cb3f56ff4906929..708a167d627675abaf3ec13befed01400bce219c 100644
--- a/polkadot/erasure-coding/src/lib.rs
+++ b/polkadot/erasure-coding/src/lib.rs
@@ -26,8 +26,8 @@
 
 use codec::{Encode, Decode};
 use reed_solomon::galois_16::{self, ReedSolomon};
-use primitives::{Hash as H256, BlakeTwo256, HashT};
-use primitives::parachain::AvailableData;
+use primitives::v0::{self, Hash as H256, BlakeTwo256, HashT};
+use primitives::v1;
 use sp_core::Blake2Hasher;
 use trie::{EMPTY_PREFIX, MemoryDB, Trie, TrieMut, trie_types::{TrieDBMut, TrieDB}};
 
@@ -124,14 +124,32 @@ fn code_params(n_validators: usize) -> Result<CodeParams, Error> {
 	})
 }
 
+/// Obtain erasure-coded chunks for v0 `AvailableData`, one for each validator.
+///
+/// Works only up to 65536 validators, and `n_validators` must be non-zero.
+pub fn obtain_chunks_v0(n_validators: usize, data: &v0::AvailableData)
+	-> Result<Vec<Vec<u8>>, Error>
+{
+	obtain_chunks(n_validators, data)
+}
+
+/// Obtain erasure-coded chunks for v1 `AvailableData`, one for each validator.
+///
+/// Works only up to 65536 validators, and `n_validators` must be non-zero.
+pub fn obtain_chunks_v1(n_validators: usize, data: &v1::AvailableData)
+	-> Result<Vec<Vec<u8>>, Error>
+{
+	obtain_chunks(n_validators, data)
+}
+
 /// Obtain erasure-coded chunks, one for each validator.
 ///
 /// Works only up to 65536 validators, and `n_validators` must be non-zero.
-pub fn obtain_chunks(n_validators: usize, available_data: &AvailableData)
+fn obtain_chunks<T: Encode>(n_validators: usize, data: &T)
 	-> Result<Vec<Vec<u8>>, Error>
 {
 	let params = code_params(n_validators)?;
-	let encoded = available_data.encode();
+	let encoded = data.encode();
 
 	if encoded.is_empty() {
 		return Err(Error::BadPayload);
@@ -145,15 +163,42 @@ pub fn obtain_chunks(n_validators: usize, available_data: &AvailableData)
 	Ok(shards.into_iter().map(|w| w.into_inner()).collect())
 }
 
-/// Reconstruct the block data from a set of chunks.
+/// Reconstruct the v0 available data from a set of chunks.
+///
+/// Provide an iterator containing chunk data and the corresponding index.
+/// The indices of the present chunks must be indicated. If too few chunks
+/// are provided, recovery is not possible.
+///
+/// Works only up to 65536 validators, and `n_validators` must be non-zero.
+pub fn reconstruct_v0<'a, I: 'a>(n_validators: usize, chunks: I)
+	-> Result<v0::AvailableData, Error>
+	where I: IntoIterator<Item=(&'a [u8], usize)>
+{
+	reconstruct(n_validators, chunks)
+}
+
+/// Reconstruct the v1 available data from a set of chunks.
+///
+/// Provide an iterator containing chunk data and the corresponding index.
+/// The indices of the present chunks must be indicated. If too few chunks
+/// are provided, recovery is not possible.
+///
+/// Works only up to 65536 validators, and `n_validators` must be non-zero.
+pub fn reconstruct_v1<'a, I: 'a>(n_validators: usize, chunks: I)
+	-> Result<v1::AvailableData, Error>
+	where I: IntoIterator<Item=(&'a [u8], usize)>
+{
+	reconstruct(n_validators, chunks)
+}
+
+/// Reconstruct decodable data from a set of chunks.
 ///
 /// Provide an iterator containing chunk data and the corresponding index.
 /// The indices of the present chunks must be indicated. If too few chunks
 /// are provided, recovery is not possible.
 ///
 /// Works only up to 65536 validators, and `n_validators` must be non-zero.
-pub fn reconstruct<'a, I: 'a>(n_validators: usize, chunks: I)
-	-> Result<AvailableData, Error>
+fn reconstruct<'a, I: 'a, T: Decode>(n_validators: usize, chunks: I) -> Result<T, Error>
 	where I: IntoIterator<Item=(&'a [u8], usize)>
 {
 	let params = code_params(n_validators)?;
@@ -343,7 +388,7 @@ impl<'a, I: Iterator<Item=&'a [u8]>> codec::Input for ShardInput<'a, I> {
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use primitives::parachain::{BlockData, PoVBlock};
+	use primitives::v0::{AvailableData, BlockData, PoVBlock};
 
 	#[test]
 	fn field_order_is_right_size() {
@@ -420,7 +465,7 @@ mod tests {
 		assert_eq!(chunks.len(), 10);
 
 		// any 4 chunks should work.
-		let reconstructed = reconstruct(
+		let reconstructed: AvailableData = reconstruct(
 			10,
 			[
 				(&*chunks[1], 1),
diff --git a/polkadot/network/src/legacy/collator_pool.rs b/polkadot/network/src/legacy/collator_pool.rs
index a0c0a0458e908eeb396883aa80304a29a47095ab..f2b168e0f592b3c85cf11c8948995d9f88e68465 100644
--- a/polkadot/network/src/legacy/collator_pool.rs
+++ b/polkadot/network/src/legacy/collator_pool.rs
@@ -17,8 +17,7 @@
 //! Bridge between the network and consensus service for getting collations to it.
 
 use codec::{Encode, Decode};
-use polkadot_primitives::Hash;
-use polkadot_primitives::parachain::{CollatorId, Id as ParaId, Collation};
+use polkadot_primitives::v0::{Hash, CollatorId, Id as ParaId, Collation};
 use sc_network::PeerId;
 use futures::channel::oneshot;
 
@@ -236,7 +235,7 @@ impl CollatorPool {
 mod tests {
 	use super::*;
 	use sp_core::crypto::UncheckedInto;
-	use polkadot_primitives::parachain::{CollationInfo, BlockData, PoVBlock};
+	use polkadot_primitives::v0::{CollationInfo, BlockData, PoVBlock};
 	use futures::executor::block_on;
 
 	fn make_pov(block_data: Vec<u8>) -> PoVBlock {
diff --git a/polkadot/network/src/legacy/gossip/attestation.rs b/polkadot/network/src/legacy/gossip/attestation.rs
index a47f75288bf40220bcc639003d30c38ab1e492fb..2d20ce63b995450fbcc229a9363691739397175e 100644
--- a/polkadot/network/src/legacy/gossip/attestation.rs
+++ b/polkadot/network/src/legacy/gossip/attestation.rs
@@ -33,7 +33,7 @@
 use sc_network_gossip::{ValidationResult as GossipValidationResult};
 use sc_network::ReputationChange;
 use polkadot_validation::GenericStatement;
-use polkadot_primitives::Hash;
+use polkadot_primitives::v0::Hash;
 
 use std::collections::HashMap;
 
diff --git a/polkadot/network/src/legacy/gossip/mod.rs b/polkadot/network/src/legacy/gossip/mod.rs
index 7dea99656667920363f315a07bf517b00dfd5275..9e18d7ce217109f8449740baffb69a37ce73308d 100644
--- a/polkadot/network/src/legacy/gossip/mod.rs
+++ b/polkadot/network/src/legacy/gossip/mod.rs
@@ -58,8 +58,8 @@ use sc_network_gossip::{
 	ValidatorContext, MessageIntent,
 };
 use polkadot_validation::{SignedStatement};
-use polkadot_primitives::{Block, Hash};
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{
+	Block, Hash,
 	ParachainHost, ValidatorId, ErasureChunk as PrimitiveChunk, SigningContext, PoVBlock,
 };
 use polkadot_erasure_coding::{self as erasure};
@@ -755,7 +755,7 @@ mod tests {
 	use sc_network_gossip::Validator as ValidatorT;
 	use std::sync::mpsc;
 	use parking_lot::Mutex;
-	use polkadot_primitives::parachain::{AbridgedCandidateReceipt, BlockData};
+	use polkadot_primitives::v0::{AbridgedCandidateReceipt, BlockData};
 	use sp_core::sr25519::Signature as Sr25519Signature;
 	use polkadot_validation::GenericStatement;
 
diff --git a/polkadot/network/src/legacy/local_collations.rs b/polkadot/network/src/legacy/local_collations.rs
index 6bc9b985a7c1a81b2fe0b5edc764015b808546c5..d85911548613bf4558755ec53386f0c2619e9360 100644
--- a/polkadot/network/src/legacy/local_collations.rs
+++ b/polkadot/network/src/legacy/local_collations.rs
@@ -19,7 +19,7 @@
 //! Collations are attempted to be repropagated when a new validator connects,
 //! a validator changes his session key, or when they are generated.
 
-use polkadot_primitives::{Hash, parachain::{ValidatorId}};
+use polkadot_primitives::v0::{Hash, ValidatorId};
 use crate::legacy::collator_pool::Role;
 use std::collections::{HashMap, HashSet};
 use std::time::Duration;
@@ -144,7 +144,7 @@ impl<C: Clone> LocalCollations<C> {
 mod tests {
 	use super::*;
 	use sp_core::crypto::UncheckedInto;
-	use polkadot_primitives::parachain::ValidatorId;
+	use polkadot_primitives::v0::ValidatorId;
 
 	#[test]
 	fn add_validator_with_ready_collation() {
diff --git a/polkadot/network/src/legacy/mod.rs b/polkadot/network/src/legacy/mod.rs
index 28ea77a6bdc10cac191bb184ae70f4f234071602..42698657c05355e2a2736fb0965d726c31dbfddb 100644
--- a/polkadot/network/src/legacy/mod.rs
+++ b/polkadot/network/src/legacy/mod.rs
@@ -25,7 +25,7 @@ pub mod gossip;
 
 use codec::Decode;
 use futures::prelude::*;
-use polkadot_primitives::Hash;
+use polkadot_primitives::v0::Hash;
 use sc_network::PeerId;
 use sc_network_gossip::TopicNotification;
 use log::debug;
diff --git a/polkadot/network/src/lib.rs b/polkadot/network/src/lib.rs
index 5048f09adaf51d17dd108686f783cb7c7d41d037..eaed7b34d2cb11af22d2dc996c86a456af2163bc 100644
--- a/polkadot/network/src/lib.rs
+++ b/polkadot/network/src/lib.rs
@@ -21,7 +21,7 @@
 
 #![recursion_limit="256"]
 
-use polkadot_primitives::{Block, Hash, BlakeTwo256, HashT};
+use polkadot_primitives::v0::{Block, Hash, BlakeTwo256, HashT};
 
 pub mod legacy;
 pub mod protocol;
diff --git a/polkadot/network/src/protocol/mod.rs b/polkadot/network/src/protocol/mod.rs
index 9a94065e5be6cbf8bc25335a3e64c7e70a923416..22e72dcfd6e46f5fda64558bea660dabf93eabb4 100644
--- a/polkadot/network/src/protocol/mod.rs
+++ b/polkadot/network/src/protocol/mod.rs
@@ -30,12 +30,10 @@ use futures::task::{Context, Poll};
 use futures::stream::{FuturesUnordered, StreamFuture};
 use log::{debug, trace};
 
-use polkadot_primitives::{
+use polkadot_primitives::v0::{
 	Hash, Block,
-	parachain::{
-		PoVBlock, ValidatorId, ValidatorIndex, Collation, AbridgedCandidateReceipt,
-		ErasureChunk, ParachainHost, Id as ParaId, CollatorId,
-	},
+	PoVBlock, ValidatorId, ValidatorIndex, Collation, AbridgedCandidateReceipt,
+	ErasureChunk, ParachainHost, Id as ParaId, CollatorId,
 };
 use polkadot_validation::{
 	SharedTable, TableRouter, Network as ParachainNetwork, Validated, GenericStatement, Collators,
diff --git a/polkadot/network/src/protocol/tests.rs b/polkadot/network/src/protocol/tests.rs
index 049af3f5aca703934db4482deca1aa4e2ebeba8c..711906797be4e63c8afab4aa6c60f416f6d354e5 100644
--- a/polkadot/network/src/protocol/tests.rs
+++ b/polkadot/network/src/protocol/tests.rs
@@ -17,8 +17,8 @@ use super::*;
 use crate::legacy::gossip::GossipPoVBlock;
 use parking_lot::Mutex;
 
-use polkadot_primitives::Block;
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{
+	Block,
 	Id as ParaId, Chain, DutyRoster, ParachainHost, ValidatorId,
 	Retriable, CollatorId, AbridgedCandidateReceipt,
 	GlobalValidationSchedule, LocalValidationData, ErasureChunk, SigningContext,
@@ -198,7 +198,7 @@ sp_api::mock_impl_runtime_apis! {
 				parent_hash: Default::default(),
 			}
 		}
-		fn downward_messages(_: ParaId) -> Vec<polkadot_primitives::DownwardMessage> {
+		fn downward_messages(_: ParaId) -> Vec<polkadot_primitives::v0::DownwardMessage> {
 			Vec::new()
 		}
 	}
diff --git a/polkadot/node/core/backing/src/lib.rs b/polkadot/node/core/backing/src/lib.rs
index e4490d20d3f1f299a2e2c02451bb27517c2a2ac0..281147847e19ef678ec9e28acd9896bc607e00de 100644
--- a/polkadot/node/core/backing/src/lib.rs
+++ b/polkadot/node/core/backing/src/lib.rs
@@ -21,6 +21,7 @@
 use std::collections::{HashMap, HashSet};
 use std::convert::TryFrom;
 use std::pin::Pin;
+use std::sync::Arc;
 use std::time::Duration;
 
 use bitvec::vec::BitVec;
@@ -36,17 +37,15 @@ use streamunordered::{StreamUnordered, StreamYield};
 
 use primitives::Pair;
 use keystore::KeyStorePtr;
-use polkadot_primitives::{
-	Hash,
-	parachain::{
-		AbridgedCandidateReceipt, BackedCandidate, Id as ParaId, ValidatorPair, ValidatorId,
-		ValidatorIndex, HeadData, SigningContext, PoVBlock, OmittedValidationData,
-		CandidateDescriptor, LocalValidationData, GlobalValidationSchedule, AvailableData,
-		ErasureChunk,
-	},
+use polkadot_primitives::v1::{
+	CommittedCandidateReceipt, BackedCandidate, Id as ParaId, ValidatorPair, ValidatorId,
+	ValidatorIndex, SigningContext, PoV, OmittedValidationData,
+	CandidateDescriptor, AvailableData, ErasureChunk, ValidatorSignature, Hash, CandidateReceipt,
+	CandidateCommitments,
 };
 use polkadot_node_primitives::{
 	FromTableMisbehavior, Statement, SignedFullStatement, MisbehaviorReport, ValidationResult,
+	ValidationOutputs,
 };
 use polkadot_subsystem::{
 	FromOverseer, OverseerSignal, Subsystem, SubsystemContext, SpawnedSubsystem,
@@ -59,8 +58,12 @@ use polkadot_subsystem::messages::{
 };
 use statement_table::{
 	generic::AttestedCandidate as TableAttestedCandidate,
-	Table, Context as TableContextTrait, Statement as TableStatement,
-	SignedStatement as TableSignedStatement, Summary as TableSummary, 
+	Context as TableContextTrait,
+	Table,
+	v1::{
+		Statement as TableStatement,
+		SignedStatement as TableSignedStatement, Summary as TableSummary,
+	},
 };
 
 #[derive(Debug, derive_more::From)]
@@ -90,8 +93,6 @@ struct CandidateBackingJob {
 	/// Outbound message channel sending part.
 	tx_from: mpsc::Sender<FromJob>,
 
-	/// `HeadData`s of the parachains that this validator is assigned to.
-	head_data: HeadData,
 	/// The `ParaId`s assigned to this validator.
 	assignment: ParaId,
 	/// We issued `Valid` or `Invalid` statements on about these candidates.
@@ -118,8 +119,22 @@ struct TableContext {
 }
 
 impl TableContextTrait for TableContext {
-	fn is_member_of(&self, authority: ValidatorIndex, group: &ParaId) -> bool {
-		self.groups.get(group).map_or(false, |g| g.iter().position(|&a| a == authority).is_some())
+	type AuthorityId = ValidatorIndex;
+	type Digest = Hash;
+	type GroupId = ParaId;
+	type Signature = ValidatorSignature;
+	type Candidate = CommittedCandidateReceipt;
+
+	fn candidate_digest(candidate: &CommittedCandidateReceipt) -> Hash {
+		candidate.hash()
+	}
+
+	fn candidate_group(candidate: &CommittedCandidateReceipt) -> ParaId {
+		candidate.descriptor().para_id
+	}
+
+	fn is_member_of(&self, authority: &ValidatorIndex, group: &ParaId) -> bool {
+		self.groups.get(group).map_or(false, |g| g.iter().position(|a| a == authority).is_some())
 	}
 
 	fn requisite_votes(&self, group: &ParaId) -> usize {
@@ -221,7 +236,7 @@ impl CandidateBackingJob {
 
 	async fn issue_candidate_invalid_message(
 		&mut self,
-		candidate: AbridgedCandidateReceipt,
+		candidate: CandidateReceipt,
 	) -> Result<(), Error> {
 		self.tx_from.send(FromJob::CandidateSelection(
 			CandidateSelectionMessage::Invalid(self.parent, candidate)
@@ -231,34 +246,69 @@ impl CandidateBackingJob {
 	}
 
 	/// Validate the candidate that is requested to be `Second`ed and distribute validation result.
+	///
+	/// Returns `Ok(true)` if we issued a `Seconded` statement about this candidate.
 	async fn validate_and_second(
 		&mut self,
-		candidate: AbridgedCandidateReceipt,
-		pov: PoVBlock,
-	) -> Result<ValidationResult, Error> {
-		let valid = self.request_candidate_validation(candidate.clone(), pov.clone()).await?;
-		let statement = match valid.0 {
-			ValidationResult::Valid => {
+		candidate: &CandidateReceipt,
+		pov: PoV,
+	) -> Result<bool, Error> {
+		let valid = self.request_candidate_validation(
+			candidate.descriptor().clone(),
+			Arc::new(pov.clone()),
+		).await?;
+
+		let candidate_hash = candidate.hash();
+
+		let statement = match valid {
+			ValidationResult::Valid(outputs) => {
 				// make PoV available for later distribution. Send data to the availability
 				// store to keep. Sign and dispatch `valid` statement to network if we
 				// have not seconded the given candidate.
-				self.make_pov_available(pov, valid.1, valid.2).await?;
-				self.issued_statements.insert(candidate.hash());
-				Statement::Seconded(candidate)
+				//
+				// If the commitments hash produced by validation is not the same as given by
+				// the collator, do not make available and report the collator.
+				let commitments_check = self.make_pov_available(
+					pov,
+					outputs,
+					|commitments| if commitments.hash() == candidate.commitments_hash {
+						Ok(CommittedCandidateReceipt {
+							descriptor: candidate.descriptor().clone(),
+							commitments,
+						})
+					} else {
+						Err(())
+					},
+				).await?;
+
+				match commitments_check {
+					Ok(candidate) => {
+						self.issued_statements.insert(candidate_hash);
+						Some(Statement::Seconded(candidate))
+					}
+					Err(()) => {
+						self.issue_candidate_invalid_message(candidate.clone()).await?;
+						None
+					}
+				}
 			}
 			ValidationResult::Invalid => {
-				let candidate_hash = candidate.hash();
-				self.issue_candidate_invalid_message(candidate).await?;
-				Statement::Invalid(candidate_hash)
+				// no need to issue a statement about this if we aren't seconding it.
+				//
+				// there's an infinite amount of garbage out there. no need to acknowledge
+				// all of it.
+				self.issue_candidate_invalid_message(candidate.clone()).await?;
+				None
 			}
 		};
 
-		if let Some(signed_statement) = self.sign_statement(statement) {
+		let issued_statement = statement.is_some();
+		if let Some(signed_statement) = statement.and_then(|s| self.sign_statement(s)) {
 			self.import_statement(&signed_statement).await?;
 			self.distribute_signed_statement(signed_statement).await?;
 		}
 
-		Ok(valid.0)
+		Ok(issued_statement)
 	}
 
 	fn get_backed(&self) -> Vec<NewBackedCandidate> {
@@ -303,7 +353,7 @@ impl CandidateBackingJob {
 	}
 
 	/// Check if there have happened any new misbehaviors and issue necessary messages.
-	/// 
+	///
 	/// TODO: Report multiple misbehaviors (https://github.com/paritytech/polkadot/issues/1387)
 	async fn issue_new_misbehaviors(&mut self) -> Result<(), Error> {
 		let mut reports = Vec::new();
@@ -354,7 +404,7 @@ impl CandidateBackingJob {
 		match msg {
 			CandidateBackingMessage::Second(_, candidate, pov) => {
 				// Sanity check that candidate is from our assignment.
-				if candidate.parachain_index != self.assignment {
+				if candidate.descriptor().para_id != self.assignment {
 					return Ok(());
 				}
 
@@ -367,8 +417,8 @@ impl CandidateBackingJob {
 						let candidate_hash = candidate.hash();
 
 						if !self.issued_statements.contains(&candidate_hash) {
-							if let Ok(ValidationResult::Valid) = self.validate_and_second(
-								candidate,
+							if let Ok(true) = self.validate_and_second(
+								&candidate,
 								pov,
 							).await {
 								self.seconded = Some(candidate_hash);
@@ -397,17 +447,40 @@ impl CandidateBackingJob {
 	async fn kick_off_validation_work(
 		&mut self,
 		summary: TableSummary,
-	) -> Result<ValidationResult, Error> {
-		let candidate = self.table.get_candidate(&summary.candidate).ok_or(Error::CandidateNotFound)?;
-		let candidate = candidate.clone();
-		let descriptor = candidate.to_descriptor();
-		let candidate_hash = candidate.hash();
-		let pov = self.request_pov_from_distribution(descriptor).await?;
-		let v = self.request_candidate_validation(candidate, pov).await?;
+	) -> Result<(), Error> {
+		let candidate_hash = summary.candidate.clone();
+
+		if self.issued_statements.contains(&candidate_hash) {
+			return Ok(())
+		}
+
+		// We clone the commitments here because there are borrowck
+		// errors relating to this being a struct and methods borrowing the entirety of self
+		// and not just those things that the function uses.
+		let candidate = self.table.get_candidate(&candidate_hash).ok_or(Error::CandidateNotFound)?;
+		let expected_commitments = candidate.commitments.clone();
+
+		let descriptor = candidate.descriptor().clone();
+		let pov = self.request_pov_from_distribution(descriptor.clone()).await?;
+		let v = self.request_candidate_validation(descriptor, pov.clone()).await?;
+
+		let statement = match v {
+			ValidationResult::Valid(outputs) => {
+				// If validation produces a new set of commitments, we vote the candidate as invalid.
+				let commitments_check = self.make_pov_available(
+					(&*pov).clone(),
+					outputs,
+					|commitments| if commitments == expected_commitments {
+						Ok(())
+					} else {
+						Err(())
+					}
+				).await?;
 
-		let statement = match v.0 {
-			ValidationResult::Valid => {
-				Statement::Valid(candidate_hash)
+				match commitments_check {
+					Ok(()) => Statement::Valid(candidate_hash),
+					Err(()) => Statement::Invalid(candidate_hash),
+				}
 			}
 			ValidationResult::Invalid => {
 				Statement::Invalid(candidate_hash)
@@ -420,7 +493,7 @@ impl CandidateBackingJob {
 			self.distribute_signed_statement(signed_statement).await?;
 		}
 
-		Ok(v.0)
+		Ok(())
 	}
 
 	/// Import the statement and kick off validation work if it is a part of our assignment.
@@ -478,29 +551,26 @@ impl CandidateBackingJob {
 	async fn request_pov_from_distribution(
 		&mut self,
 		descriptor: CandidateDescriptor,
-	) -> Result<PoVBlock, Error> {
+	) -> Result<Arc<PoV>, Error> {
 		let (tx, rx) = oneshot::channel();
 
 		self.tx_from.send(FromJob::PoVDistribution(
 			PoVDistributionMessage::FetchPoV(self.parent, descriptor, tx)
 		)).await?;
 
-		let pov = rx.await?;
-		Ok((*pov).clone())
+		Ok(rx.await?)
 	}
 
 	async fn request_candidate_validation(
 		&mut self,
-		candidate: AbridgedCandidateReceipt,
-		pov: PoVBlock,
-	) -> Result<(ValidationResult, GlobalValidationSchedule, LocalValidationData), Error> {
+		candidate: CandidateDescriptor,
+		pov: Arc<PoV>,
+	) -> Result<ValidationResult, Error> {
 		let (tx, rx) = oneshot::channel();
 
 		self.tx_from.send(FromJob::CandidateValidation(
-				CandidateValidationMessage::Validate(
-					self.parent,
+				CandidateValidationMessage::ValidateFromChainState(
 					candidate,
-					self.head_data.clone(),
 					pov,
 					tx,
 				)
@@ -523,32 +593,51 @@ impl CandidateBackingJob {
 		Ok(())
 	}
 
-	async fn make_pov_available(
+	// Compute the erasure-coding and make it available.
+	//
+	// This calls an inspection function before making the PoV available for any last checks
+	// that need to be done. If the inspection function returns an error, this function returns
+	// early without making the PoV available.
+	async fn make_pov_available<T, E>(
 		&mut self,
-		pov_block: PoVBlock,
-		global_validation: GlobalValidationSchedule,
-		local_validation: LocalValidationData,
-	) -> Result<(), Error> {
+		pov: PoV,
+		outputs: ValidationOutputs,
+		with_commitments: impl FnOnce(CandidateCommitments) -> Result<T, E>,
+	) -> Result<Result<T, E>, Error> {
 		let omitted_validation = OmittedValidationData {
-			global_validation,
-			local_validation,
+			global_validation: outputs.global_validation_schedule,
+			local_validation: outputs.local_validation_data,
 		};
 
 		let available_data = AvailableData {
-			pov_block,
+			pov,
 			omitted_validation,
 		};
 
-		let chunks = erasure_coding::obtain_chunks(
+		let chunks = erasure_coding::obtain_chunks_v1(
 			self.table_context.validators.len(),
 			&available_data,
 		)?;
 
 		let branches = erasure_coding::branches(chunks.as_ref());
+		let erasure_root = branches.root();
+
+		let commitments = CandidateCommitments {
+			fees: outputs.fees,
+			upward_messages: outputs.upward_messages,
+			erasure_root,
+			new_validation_code: outputs.new_validation_code,
+			head_data: outputs.head_data,
+		};
 
-		for (index, (chunk, proof)) in chunks.iter().zip(branches.map(|(proof, _)| proof)).enumerate() {
+		let res = match with_commitments(commitments) {
+			Ok(x) => x,
+			Err(e) => return Ok(Err(e)),
+		};
+
+		for (index, (proof, chunk)) in branches.enumerate() {
 			let chunk = ErasureChunk {
-				chunk: chunk.clone(),
+				chunk: chunk.to_vec(),
 				index: index as u32,
 				proof,
 			};
@@ -556,7 +645,7 @@ impl CandidateBackingJob {
 			self.store_chunk(index as ValidatorIndex, chunk).await?;
 		}
 
-		Ok(())
+		Ok(Ok(res))
 	}
 
 	async fn distribute_signed_statement(&mut self, s: SignedFullStatement) -> Result<(), Error> {
@@ -635,13 +724,7 @@ async fn run_job(
 		}
 	}
 
-	let (
-		head_data,
-		signing_context,
-	) = futures::try_join!(
-		request_head_data(parent, &mut tx_from, assignment).await?,
-		request_signing_context(parent, &mut tx_from).await?,
-	)?;
+	let signing_context = request_signing_context(parent, &mut tx_from).await?.await?;
 
 	let table_context = TableContext {
 		signing_context,
@@ -654,7 +737,6 @@ async fn run_job(
 		parent,
 		rx_to,
 		tx_from,
-		head_data,
 		assignment,
 		issued_statements: HashSet::new(),
 		seconded: None,
@@ -714,23 +796,6 @@ async fn request_signing_context(
 	Ok(rx)
 }
 
-/// Request `HeadData` for some `ParaId` from `RuntimeApi`.
-async fn request_head_data(
-	parent: Hash,
-	s: &mut mpsc::Sender<FromJob>,
-	id: ParaId,
-) -> Result<oneshot::Receiver<HeadData>, Error> {
-	let (tx, rx) = oneshot::channel();
-
-	s.send(FromJob::RuntimeApiMessage(RuntimeApiMessage::Request(
-			parent,
-			RuntimeApiRequest::HeadData(id, tx),
-		)
-	)).await?;
-
-	Ok(rx)
-}
-
 impl<S: Spawn> Jobs<S> {
 	fn new(spawner: S) -> Self {
 		Self {
@@ -910,8 +975,9 @@ mod tests {
 	use std::collections::HashMap;
 	use std::sync::Arc;
 	use sp_keyring::Sr25519Keyring;
-	use polkadot_primitives::parachain::{
+	use polkadot_primitives::v1::{
 		AssignmentKind, CollatorId, CoreAssignment, BlockData, CoreIndex, GroupIndex, ValidityAttestation,
+		CandidateCommitments, LocalValidationData, GlobalValidationSchedule, HeadData,
 	};
 	use assert_matches::assert_matches;
 
@@ -1006,6 +1072,7 @@ mod tests {
 				parent_head: HeadData(vec![7, 8, 9]),
 				balance: Default::default(),
 				code_upgrade_allowed: None,
+				validation_code_hash: Default::default(),
 			};
 
 			let global_validation_schedule = GlobalValidationSchedule {
@@ -1050,6 +1117,48 @@ mod tests {
 		executor::block_on(future::select(test_fut, subsystem));
 	}
 
+	fn make_erasure_root(test: &TestState, pov: PoV) -> Hash {
+		let omitted_validation = OmittedValidationData {
+			global_validation: test.global_validation_schedule.clone(),
+			local_validation: test.local_validation_data.clone(),
+		};
+
+		let available_data = AvailableData {
+			omitted_validation,
+			pov,
+		};
+
+		let chunks = erasure_coding::obtain_chunks_v1(test.validators.len(), &available_data).unwrap();
+		erasure_coding::branches(&chunks).root()
+	}
+
+	#[derive(Default)]
+	struct TestCandidateBuilder {
+		para_id: ParaId,
+		head_data: HeadData,
+		pov_hash: Hash,
+		relay_parent: Hash,
+		erasure_root: Hash,
+	}
+
+	impl TestCandidateBuilder {
+		fn build(self) -> CommittedCandidateReceipt {
+			CommittedCandidateReceipt {
+				descriptor: CandidateDescriptor {
+					para_id: self.para_id,
+					pov_hash: self.pov_hash,
+					relay_parent: self.relay_parent,
+					..Default::default()
+				},
+				commitments: CandidateCommitments {
+					head_data: self.head_data,
+					erasure_root: self.erasure_root,
+					..Default::default()
+				},
+			}
+		}
+	}
+
 	// Tests that the subsystem performs actions that are requied on startup.
 	async fn test_startup(
 		virtual_overseer: &mut subsystem_test::TestSubsystemContextHandle<CandidateBackingMessage>,
@@ -1080,16 +1189,6 @@ mod tests {
 			}
 		);
 
-		// Check that subsystem job issues a request for the head data.
-		assert_matches!(
-			virtual_overseer.recv().await,
-			AllMessages::RuntimeApi(
-				RuntimeApiMessage::Request(parent, RuntimeApiRequest::HeadData(id, tx))
-			) if parent == test_state.relay_parent => {
-				tx.send(test_state.head_data.get(&id).unwrap().clone()).unwrap();
-			}
-		);
-
 		// Check that subsystem job issues a request for the signing context.
 		assert_matches!(
 			virtual_overseer.recv().await,
@@ -1108,49 +1207,53 @@ mod tests {
 		let test_state = TestState::default();
 		test_harness(test_state.keystore.clone(), |test_harness| async move {
 			let TestHarness { mut virtual_overseer } = test_harness;
-			
+
 			test_startup(&mut virtual_overseer, &test_state).await;
-	
-			let pov_block = PoVBlock {
+
+			let pov = PoV {
 				block_data: BlockData(vec![42, 43, 44]),
 			};
 
-			let pov_block_hash = pov_block.hash();
-			let candidate = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
+
+			let pov_hash = pov.hash();
+			let candidate = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash,
+				pov_hash,
+				head_data: expected_head_data.clone(),
+				erasure_root: make_erasure_root(&test_state, pov.clone()),
 				..Default::default()
-			};
+			}.build();
 
 			let second = CandidateBackingMessage::Second(
 				test_state.relay_parent,
-				candidate.clone(),
-				pov_block.clone(),
+				candidate.to_plain(),
+				pov.clone(),
 			);
 
 			virtual_overseer.send(FromOverseer::Communication{ msg: second }).await;
 
-			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
 
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						parent_hash,
+					CandidateValidationMessage::ValidateFromChainState(
 						c,
-						head_data,
 						pov,
 						tx,
 					)
-				) if parent_hash == test_state.relay_parent &&
-					pov == pov_block && c == candidate => {
-					assert_eq!(head_data, *expected_head_data);
-					tx.send(Ok((
-						ValidationResult::Valid,
-						test_state.global_validation_schedule,
-						test_state.local_validation_data,
-					))).unwrap();
+				) if pov == pov && &c == candidate.descriptor() => {
+					tx.send(Ok(
+						ValidationResult::Valid(ValidationOutputs {
+							global_validation_schedule: test_state.global_validation_schedule,
+							local_validation_data: test_state.local_validation_data,
+							head_data: expected_head_data.clone(),
+							upward_messages: Vec::new(),
+							fees: Default::default(),
+							new_validation_code: None,
+						}),
+					)).unwrap();
 				}
 			);
 
@@ -1193,18 +1296,22 @@ mod tests {
 
 			test_startup(&mut virtual_overseer, &test_state).await;
 
-			let pov_block = PoVBlock {
+			let pov = PoV {
 				block_data: BlockData(vec![1, 2, 3]),
 			};
 
-			let pov_block_hash = pov_block.hash();
+			let pov_hash = pov.hash();
+
+			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
 
-			let candidate_a = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let candidate_a = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash,
+				pov_hash,
+				head_data: expected_head_data.clone(),
+				erasure_root: make_erasure_root(&test_state, pov.clone()),
 				..Default::default()
-			};
+			}.build();
 
 			let candidate_a_hash = candidate_a.hash();
 
@@ -1227,39 +1334,38 @@ mod tests {
 			virtual_overseer.send(FromOverseer::Communication{ msg: statement }).await;
 
 			// Sending a `Statement::Seconded` for our assignment will start
-			// validation process. The first thing requested is PoVBlock from the
+			// validation process. The first thing requested is PoV from the
 			// `PoVDistribution`.
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::PoVDistribution(
 					PoVDistributionMessage::FetchPoV(relay_parent, _, tx)
 				) if relay_parent == test_state.relay_parent => {
-					tx.send(Arc::new(pov_block.clone())).unwrap();
+					tx.send(Arc::new(pov.clone())).unwrap();
 				}
 			);
 
-			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
-
 			// The next step is the actual request to Validation subsystem
 			// to validate the `Seconded` candidate.
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						relay_parent,
-						candidate,
-						head_data,
+					CandidateValidationMessage::ValidateFromChainState(
+						c,
 						pov,
 						tx,
 					)
-				) if relay_parent == test_state.relay_parent && candidate == candidate_a => {
-					assert_eq!(head_data, *expected_head_data);
-					assert_eq!(pov, pov_block);
-					tx.send(Ok((
-						ValidationResult::Valid,
-						test_state.global_validation_schedule,
-						test_state.local_validation_data,
-					))).unwrap();
+				) if pov == pov && &c == candidate_a.descriptor() => {
+					tx.send(Ok(
+						ValidationResult::Valid(ValidationOutputs {
+							global_validation_schedule: test_state.global_validation_schedule,
+							local_validation_data: test_state.local_validation_data,
+							head_data: expected_head_data.clone(),
+							upward_messages: Vec::new(),
+							fees: Default::default(),
+							new_validation_code: None,
+						}),
+					)).unwrap();
 				}
 			);
 
@@ -1309,17 +1415,22 @@ mod tests {
 
 			test_startup(&mut virtual_overseer, &test_state).await;
 
-			let pov_block = PoVBlock {
+			let pov = PoV {
 				block_data: BlockData(vec![1, 2, 3]),
 			};
 
-			let pov_block_hash = pov_block.hash();
-			let candidate_a = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let pov_hash = pov.hash();
+
+			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
+
+			let candidate_a = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash,
+				pov_hash,
+				erasure_root: make_erasure_root(&test_state, pov.clone()),
+				head_data: expected_head_data.clone(),
 				..Default::default()
-			};
+			}.build();
 
 			let candidate_a_hash = candidate_a.hash();
 
@@ -1353,33 +1464,41 @@ mod tests {
 				AllMessages::PoVDistribution(
 					PoVDistributionMessage::FetchPoV(relay_parent, _, tx)
 				) if relay_parent == test_state.relay_parent => {
-					tx.send(Arc::new(pov_block.clone())).unwrap();
+					tx.send(Arc::new(pov.clone())).unwrap();
 				}
 			);
 
-			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
-
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						relay_parent,
-						candidate,
-						head_data,
+					CandidateValidationMessage::ValidateFromChainState(
+						c,
 						pov,
 						tx,
 					)
-				) if relay_parent == test_state.relay_parent && candidate == candidate_a => {
-					assert_eq!(pov, pov_block);
-					assert_eq!(head_data, *expected_head_data);
-					tx.send(Ok((
-						ValidationResult::Valid,
-						test_state.global_validation_schedule,
-						test_state.local_validation_data,
-					))).unwrap();
+				) if pov == pov && &c == candidate_a.descriptor() => {
+					tx.send(Ok(
+						ValidationResult::Valid(ValidationOutputs {
+							global_validation_schedule: test_state.global_validation_schedule,
+							local_validation_data: test_state.local_validation_data,
+							head_data: expected_head_data.clone(),
+							upward_messages: Vec::new(),
+							fees: Default::default(),
+							new_validation_code: None,
+						}),
+					)).unwrap();
 				}
 			);
 
+			for _ in 0..test_state.validators.len() {
+				assert_matches!(
+					virtual_overseer.recv().await,
+					AllMessages::AvailabilityStore(
+						AvailabilityStoreMessage::StoreChunk(parent_hash, _, _)
+					) if parent_hash == test_state.relay_parent
+				);
+			}
+
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::StatementDistribution(
@@ -1440,86 +1559,68 @@ mod tests {
 
 			test_startup(&mut virtual_overseer, &test_state).await;
 
-			let pov_block_a = PoVBlock {
+			let pov_block_a = PoV {
 				block_data: BlockData(vec![42, 43, 44]),
 			};
 
-			let pov_block_b = PoVBlock {
+			let pov_block_b = PoV {
 				block_data: BlockData(vec![45, 46, 47]),
 			};
 
-			let pov_block_hash_a = pov_block_a.hash();
-			let pov_block_hash_b = pov_block_b.hash();
+			let pov_hash_a = pov_block_a.hash();
+			let pov_hash_b = pov_block_b.hash();
+
+			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
 
-			let candidate_a = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let candidate_a = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash: pov_block_hash_a,
+				pov_hash: pov_hash_a,
+				erasure_root: make_erasure_root(&test_state, pov_block_a.clone()),
 				..Default::default()
-			};
-
-			let candidate_a_hash = candidate_a.hash();
+			}.build();
 
-			let candidate_b = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let candidate_b = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash: pov_block_hash_b,
+				pov_hash: pov_hash_b,
+				erasure_root: make_erasure_root(&test_state, pov_block_b.clone()),
+				head_data: expected_head_data.clone(),
 				..Default::default()
-			};
+			}.build();
 
 			let second = CandidateBackingMessage::Second(
 				test_state.relay_parent,
-				candidate_a.clone(),
+				candidate_a.to_plain(),
 				pov_block_a.clone(),
 			);
 
 			virtual_overseer.send(FromOverseer::Communication{ msg: second }).await;
 
-			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
 
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						parent_hash,
+					CandidateValidationMessage::ValidateFromChainState(
 						c,
-						head_data,
 						pov,
 						tx,
 					)
-				) if parent_hash == test_state.relay_parent &&
-					pov == pov_block_a && c == candidate_a => {
-					assert_eq!(head_data, *expected_head_data);
-					tx.send(Ok((
-						ValidationResult::Invalid,
-						test_state.global_validation_schedule.clone(),
-						test_state.local_validation_data.clone(),
-					))).unwrap();
+				) if pov == pov && &c == candidate_a.descriptor() => {
+					tx.send(Ok(ValidationResult::Invalid)).unwrap();
 				}
 			);
 
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateSelection(
-					CandidateSelectionMessage::Invalid(parent_hash, candidate)
-				) if parent_hash == test_state.relay_parent && candidate == candidate_a
-			);
-
-			assert_matches!(
-				virtual_overseer.recv().await,
-				AllMessages::StatementDistribution(
-					StatementDistributionMessage::Share(
-						relay_parent,
-						statement,
-					)
-				) if relay_parent == test_state.relay_parent => {
-					assert_eq!(*statement.payload(), Statement::Invalid(candidate_a_hash));
-				}
+					CandidateSelectionMessage::Invalid(parent_hash, c)
+				) if parent_hash == test_state.relay_parent && c == candidate_a.to_plain()
 			);
 
 			let second = CandidateBackingMessage::Second(
 				test_state.relay_parent,
-				candidate_b.clone(),
+				candidate_b.to_plain(),
 				pov_block_b.clone(),
 			);
 
@@ -1530,21 +1631,22 @@ mod tests {
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						parent_hash,
+					CandidateValidationMessage::ValidateFromChainState(
 						c,
-						head_data,
 						pov,
 						tx,
 					)
-				) if parent_hash == test_state.relay_parent &&
-					pov == pov_block_b && c == candidate_b => {
-					assert_eq!(head_data, *expected_head_data);
-					tx.send(Ok((
-						ValidationResult::Valid,
-						test_state.global_validation_schedule,
-						test_state.local_validation_data,
-					))).unwrap();
+				) if pov == pov && &c == candidate_b.descriptor() => {
+					tx.send(Ok(
+						ValidationResult::Valid(ValidationOutputs {
+							global_validation_schedule: test_state.global_validation_schedule,
+							local_validation_data: test_state.local_validation_data,
+							head_data: expected_head_data.clone(),
+							upward_messages: Vec::new(),
+							fees: Default::default(),
+							new_validation_code: None,
+						}),
+					)).unwrap();
 				}
 			);
 
@@ -1590,18 +1692,19 @@ mod tests {
 
 			test_startup(&mut virtual_overseer, &test_state).await;
 
-			let pov_block = PoVBlock {
+			let pov = PoV {
 				block_data: BlockData(vec![42, 43, 44]),
 			};
 
-			let pov_block_hash = pov_block.hash();
+			let pov_hash = pov.hash();
 
-			let candidate = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let candidate = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash,
+				pov_hash,
+				erasure_root: make_erasure_root(&test_state, pov.clone()),
 				..Default::default()
-			};
+			}.build();
 
 			let candidate_hash = candidate.hash();
 
@@ -1627,33 +1730,22 @@ mod tests {
 					PoVDistributionMessage::FetchPoV(relay_parent, _, tx)
 				) => {
 					assert_eq!(relay_parent, test_state.relay_parent);
-					tx.send(Arc::new(pov_block.clone())).unwrap();
+					tx.send(Arc::new(pov.clone())).unwrap();
 				}
 			);
 
-			let expected_head_data = test_state.head_data.get(&test_state.chain_ids[0]).unwrap();
 
 			// Tell subsystem that this candidate is invalid.
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						relay_parent,
-						candidate_recvd,
-						head_data,
+					CandidateValidationMessage::ValidateFromChainState(
+						c,
 						pov,
 						tx,
 					)
-				) => {
-					assert_eq!(relay_parent, test_state.relay_parent);
-					assert_eq!(candidate_recvd, candidate);
-					assert_eq!(head_data, *expected_head_data);
-					assert_eq!(pov, pov_block);
-					tx.send(Ok((
-						ValidationResult::Invalid,
-						test_state.global_validation_schedule,
-						test_state.local_validation_data,
-					))).unwrap();
+				) if pov == pov && &c == candidate.descriptor() => {
+					tx.send(Ok(ValidationResult::Invalid)).unwrap();
 				}
 			);
 
@@ -1679,28 +1771,29 @@ mod tests {
 			// This should emit no actions from subsystem.
 			let second = CandidateBackingMessage::Second(
 				test_state.relay_parent,
-				candidate.clone(),
-				pov_block.clone(),
+				candidate.to_plain(),
+				pov.clone(),
 			);
 
 			virtual_overseer.send(FromOverseer::Communication{ msg: second }).await;
 
-			let pov_to_second = PoVBlock {
+			let pov_to_second = PoV {
 				block_data: BlockData(vec![3, 2, 1]),
 			};
 
-			let pov_block_hash = pov_to_second.hash();
+			let pov_hash = pov_to_second.hash();
 
-			let candidate_to_second = AbridgedCandidateReceipt {
-				parachain_index: test_state.chain_ids[0],
+			let candidate_to_second = TestCandidateBuilder {
+				para_id: test_state.chain_ids[0],
 				relay_parent: test_state.relay_parent,
-				pov_block_hash,
+				pov_hash,
+				erasure_root: make_erasure_root(&test_state, pov_to_second.clone()),
 				..Default::default()
-			};
+			}.build();
 
 			let second = CandidateBackingMessage::Second(
 				test_state.relay_parent,
-				candidate_to_second.clone(),
+				candidate_to_second.to_plain(),
 				pov_to_second.clone(),
 			);
 
@@ -1712,16 +1805,13 @@ mod tests {
 			assert_matches!(
 				virtual_overseer.recv().await,
 				AllMessages::CandidateValidation(
-					CandidateValidationMessage::Validate(
-						relay_parent,
-						_,
+					CandidateValidationMessage::ValidateFromChainState(
 						_,
 						pov,
 						_,
 					)
 				) => {
-					assert_eq!(relay_parent, test_state.relay_parent);
-					assert_eq!(pov, pov_to_second);
+					assert_eq!(&*pov, &pov_to_second);
 				}
 			);
 		});
diff --git a/polkadot/node/core/proposer/src/lib.rs b/polkadot/node/core/proposer/src/lib.rs
index b53ac5729fa949a0176969bae47b5ad05b390b57..d43810227ba4ddd5e1c76f5001261966c39720af 100644
--- a/polkadot/node/core/proposer/src/lib.rs
+++ b/polkadot/node/core/proposer/src/lib.rs
@@ -2,9 +2,7 @@ use futures::prelude::*;
 use futures::select;
 use polkadot_node_subsystem::{messages::{AllMessages, ProvisionerInherentData, ProvisionerMessage}, SubsystemError};
 use polkadot_overseer::OverseerHandler;
-use polkadot_primitives::{
-	inclusion_inherent,
-	parachain::ParachainHost,
+use polkadot_primitives::v1::{
 	Block, Hash, Header,
 };
 use sc_block_builder::{BlockBuilderApi, BlockBuilderProvider};
@@ -53,7 +51,7 @@ where
 		+ Send
 		+ Sync,
 	Client::Api:
-		ParachainHost<Block> + BlockBuilderApi<Block> + ApiExt<Block, Error = sp_blockchain::Error>,
+		BlockBuilderApi<Block> + ApiExt<Block, Error = sp_blockchain::Error>,
 	Backend:
 		'static + sc_client_api::Backend<Block, State = sp_api::StateBackendFor<Client, Block>>,
 	// Rust bug: https://github.com/rust-lang/rust/issues/24159
@@ -104,7 +102,7 @@ where
 		+ Send
 		+ Sync,
 	Client::Api:
-		ParachainHost<Block> + BlockBuilderApi<Block> + ApiExt<Block, Error = sp_blockchain::Error>,
+		BlockBuilderApi<Block> + ApiExt<Block, Error = sp_blockchain::Error>,
 	Backend:
 		'static + sc_client_api::Backend<Block, State = sp_api::StateBackendFor<Client, Block>>,
 	// Rust bug: https://github.com/rust-lang/rust/issues/24159
@@ -155,7 +153,7 @@ where
 		+ Send
 		+ Sync,
 	Client::Api:
-		ParachainHost<Block> + BlockBuilderApi<Block> + ApiExt<Block, Error = sp_blockchain::Error>,
+		BlockBuilderApi<Block> + ApiExt<Block, Error = sp_blockchain::Error>,
 	Backend:
 		'static + sc_client_api::Backend<Block, State = sp_api::StateBackendFor<Client, Block>>,
 	// Rust bug: https://github.com/rust-lang/rust/issues/24159
@@ -186,7 +184,7 @@ where
 			};
 
 			inherent_data.put_data(
-				inclusion_inherent::INHERENT_IDENTIFIER,
+				polkadot_primitives::v1::INCLUSION_INHERENT_IDENTIFIER,
 				&provisioner_data,
 			)?;
 
diff --git a/polkadot/node/network/bridge/src/lib.rs b/polkadot/node/network/bridge/src/lib.rs
index 6f90779afe62c17058ecb2b4d2a7a800e8672b64..46b9dbd84024674706b95e779f963042c0aa1c76 100644
--- a/polkadot/node/network/bridge/src/lib.rs
+++ b/polkadot/node/network/bridge/src/lib.rs
@@ -33,7 +33,7 @@ use polkadot_subsystem::{
 };
 use polkadot_subsystem::messages::{NetworkBridgeEvent, NetworkBridgeMessage, AllMessages};
 use node_primitives::{ProtocolId, View};
-use polkadot_primitives::{Block, Hash};
+use polkadot_primitives::v1::{Block, Hash};
 
 use std::collections::btree_map::{BTreeMap, Entry as BEntry};
 use std::collections::hash_map::{HashMap, Entry as HEntry};
diff --git a/polkadot/node/network/pov-distribution/src/lib.rs b/polkadot/node/network/pov-distribution/src/lib.rs
index 589e33fde0d6cbf525890cebe06f7129be8e950d..84d6e803d2c7c8323503362a88a24d390ba4d585 100644
--- a/polkadot/node/network/pov-distribution/src/lib.rs
+++ b/polkadot/node/network/pov-distribution/src/lib.rs
@@ -19,8 +19,7 @@
 //! This is a gossip implementation of code that is responsible for distributing PoVs
 //! among validators.
 
-use polkadot_primitives::Hash;
-use polkadot_primitives::parachain::{PoVBlock as PoV, CandidateDescriptor};
+use polkadot_primitives::v1::{Hash, PoV, CandidateDescriptor};
 use polkadot_subsystem::{
 	OverseerSignal, SubsystemContext, Subsystem, SubsystemResult, FromOverseer, SpawnedSubsystem,
 };
@@ -550,7 +549,7 @@ async fn run(
 mod tests {
 	use super::*;
 	use futures::executor::{self, ThreadPool};
-	use polkadot_primitives::parachain::BlockData;
+	use polkadot_primitives::v1::BlockData;
 	use assert_matches::assert_matches;
 
 	fn make_pov(data: Vec<u8>) -> PoV {
diff --git a/polkadot/node/network/statement-distribution/src/lib.rs b/polkadot/node/network/statement-distribution/src/lib.rs
index f3d2653266f739e689beec98df18806349a8ea9d..cef499eae98b2c0247d6ff24cf85832c2c2001cc 100644
--- a/polkadot/node/network/statement-distribution/src/lib.rs
+++ b/polkadot/node/network/statement-distribution/src/lib.rs
@@ -29,9 +29,8 @@ use polkadot_subsystem::messages::{
 	RuntimeApiRequest,
 };
 use node_primitives::{ProtocolId, View, SignedFullStatement};
-use polkadot_primitives::Hash;
-use polkadot_primitives::parachain::{
-	CompactStatement, ValidatorIndex, ValidatorId, SigningContext, ValidatorSignature,
+use polkadot_primitives::v1::{
+	Hash, CompactStatement, ValidatorIndex, ValidatorId, SigningContext, ValidatorSignature,
 };
 use parity_scale_codec::{Encode, Decode};
 
@@ -891,7 +890,7 @@ mod tests {
 	use super::*;
 	use sp_keyring::Sr25519Keyring;
 	use node_primitives::Statement;
-	use polkadot_primitives::parachain::{AbridgedCandidateReceipt};
+	use polkadot_primitives::v1::CommittedCandidateReceipt;
 	use assert_matches::assert_matches;
 	use futures::executor::{self, ThreadPool};
 
@@ -911,23 +910,23 @@ mod tests {
 		};
 
 		let candidate_a = {
-			let mut c = AbridgedCandidateReceipt::default();
-			c.relay_parent = parent_hash;
-			c.parachain_index = 1.into();
+			let mut c = CommittedCandidateReceipt::default();
+			c.descriptor.relay_parent = parent_hash;
+			c.descriptor.para_id = 1.into();
 			c
 		};
 
 		let candidate_b = {
-			let mut c = AbridgedCandidateReceipt::default();
-			c.relay_parent = parent_hash;
-			c.parachain_index = 2.into();
+			let mut c = CommittedCandidateReceipt::default();
+			c.descriptor.relay_parent = parent_hash;
+			c.descriptor.para_id = 2.into();
 			c
 		};
 
 		let candidate_c = {
-			let mut c = AbridgedCandidateReceipt::default();
-			c.relay_parent = parent_hash;
-			c.parachain_index = 3.into();
+			let mut c = CommittedCandidateReceipt::default();
+			c.descriptor.relay_parent = parent_hash;
+			c.descriptor.para_id = 3.into();
 			c
 		};
 
@@ -1140,9 +1139,9 @@ mod tests {
 		let hash_c = [3; 32].into();
 
 		let candidate = {
-			let mut c = AbridgedCandidateReceipt::default();
-			c.relay_parent = hash_c;
-			c.parachain_index = 1.into();
+			let mut c = CommittedCandidateReceipt::default();
+			c.descriptor.relay_parent = hash_c;
+			c.descriptor.para_id = 1.into();
 			c
 		};
 		let candidate_hash = candidate.hash();
@@ -1275,9 +1274,9 @@ mod tests {
 		let hash_c = [3; 32].into();
 
 		let candidate = {
-			let mut c = AbridgedCandidateReceipt::default();
-			c.relay_parent = hash_b;
-			c.parachain_index = 1.into();
+			let mut c = CommittedCandidateReceipt::default();
+			c.descriptor.relay_parent = hash_b;
+			c.descriptor.para_id = 1.into();
 			c
 		};
 
diff --git a/polkadot/node/overseer/examples/minimal-example.rs b/polkadot/node/overseer/examples/minimal-example.rs
index 21e8eb3ab8fa90504d65cabdb29e43d4f4ea0817..d5f7f043ff43afc80f627ee4966893792cf35ad1 100644
--- a/polkadot/node/overseer/examples/minimal-example.rs
+++ b/polkadot/node/overseer/examples/minimal-example.rs
@@ -27,11 +27,11 @@ use futures::{
 use futures_timer::Delay;
 use kv_log_macro as log;
 
-use polkadot_primitives::parachain::{BlockData, PoVBlock};
+use polkadot_primitives::v1::{BlockData, PoV};
 use polkadot_overseer::{Overseer, AllSubsystems};
 
 use polkadot_subsystem::{
-	Subsystem, SubsystemContext, DummySubsystem, 
+	Subsystem, SubsystemContext, DummySubsystem,
 	SpawnedSubsystem, FromOverseer,
 };
 use polkadot_subsystem::messages::{
@@ -61,13 +61,11 @@ impl Subsystem1 {
 			let (tx, _) = oneshot::channel();
 
 			ctx.send_message(AllMessages::CandidateValidation(
-				CandidateValidationMessage::Validate(
+				CandidateValidationMessage::ValidateFromChainState(
 					Default::default(),
-					Default::default(),
-					Default::default(),
-					PoVBlock {
+					PoV {
 						block_data: BlockData(Vec::new()),
-					},
+					}.into(),
 					tx,
 				)
 			)).await.unwrap();
diff --git a/polkadot/node/overseer/src/lib.rs b/polkadot/node/overseer/src/lib.rs
index 458aae91e871e53271282c12912752c6ac18b1cd..91fceb0d3bb0409388c0e7bf29d4c3ba948ff7e9 100644
--- a/polkadot/node/overseer/src/lib.rs
+++ b/polkadot/node/overseer/src/lib.rs
@@ -72,7 +72,7 @@ use futures::{
 use futures_timer::Delay;
 use streamunordered::{StreamYield, StreamUnordered};
 
-use polkadot_primitives::{Block, BlockNumber, Hash};
+use polkadot_primitives::v1::{Block, BlockNumber, Hash};
 use client::{BlockImportNotification, BlockchainEvents, FinalityNotification};
 
 use polkadot_subsystem::messages::{
@@ -932,7 +932,7 @@ fn spawn<S: Spawn, M: Send + 'static>(
 mod tests {
 	use futures::{executor, pin_mut, select, channel::mpsc, FutureExt};
 
-	use polkadot_primitives::parachain::{BlockData, PoVBlock};
+	use polkadot_primitives::v1::{BlockData, PoV};
 	use polkadot_subsystem::DummySubsystem;
 	use super::*;
 
@@ -977,13 +977,11 @@ mod tests {
 						let (tx, _) = oneshot::channel();
 						ctx.send_message(
 							AllMessages::CandidateValidation(
-								CandidateValidationMessage::Validate(
+								CandidateValidationMessage::ValidateFromChainState(
 									Default::default(),
-									Default::default(),
-									Default::default(),
-									PoVBlock {
+									PoV {
 										block_data: BlockData(Vec::new()),
-									},
+									}.into(),
 									tx,
 								)
 							)
diff --git a/polkadot/node/primitives/src/lib.rs b/polkadot/node/primitives/src/lib.rs
index 25313c09154e985932d371af71b732675022f00e..f29be5737450ace1bcbd41e240fb3b785e435a25 100644
--- a/polkadot/node/primitives/src/lib.rs
+++ b/polkadot/node/primitives/src/lib.rs
@@ -21,26 +21,31 @@
 //! there.
 
 use parity_scale_codec::{Decode, Encode};
-use polkadot_primitives::{Hash,
-	parachain::{
-		AbridgedCandidateReceipt, CompactStatement,
-		EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
-	}
+use polkadot_primitives::v1::{
+	Hash, CommittedCandidateReceipt, CandidateReceipt, CompactStatement,
+	EncodeAs, Signed, SigningContext, ValidatorIndex, ValidatorId,
+	UpwardMessage, Balance, ValidationCode, GlobalValidationSchedule, LocalValidationData,
+	HeadData,
 };
 use polkadot_statement_table::{
 	generic::{
 		ValidityDoubleVote as TableValidityDoubleVote,
 		MultipleCandidates as TableMultipleCandidates,
 	},
-	Misbehavior as TableMisbehavior,
+	v1::Misbehavior as TableMisbehavior,
 };
 
 /// A statement, where the candidate receipt is included in the `Seconded` variant.
+///
+/// This is the committed candidate receipt instead of the bare candidate receipt. As such,
+/// it gives access to the commitments to validators who have not executed the candidate. This
+/// is necessary to allow a block-producing validator to include candidates from outside of the para
+/// it is assigned to.
 #[derive(Debug, Clone, PartialEq, Eq, Encode, Decode)]
 pub enum Statement {
 	/// A statement that a validator seconds a candidate.
 	#[codec(index = "1")]
-	Seconded(AbridgedCandidateReceipt),
+	Seconded(CommittedCandidateReceipt),
 	/// A statement that a validator has deemed a candidate valid.
 	#[codec(index = "2")]
 	Valid(Hash),
@@ -50,6 +55,8 @@ pub enum Statement {
 }
 
 impl Statement {
+	/// Transform this statement into its compact version, which references only the hash
+	/// of the candidate.
 	pub fn to_compact(&self) -> CompactStatement {
 		match *self {
 			Statement::Seconded(ref c) => CompactStatement::Candidate(c.hash()),
@@ -84,9 +91,9 @@ pub enum MisbehaviorReport {
 	/// this message should be dispatched with all of them, in arbitrary order.
 	///
 	/// This variant is also used when our own validity checks disagree with others'.
-	CandidateValidityDisagreement(AbridgedCandidateReceipt, Vec<SignedFullStatement>),
+	CandidateValidityDisagreement(CandidateReceipt, Vec<SignedFullStatement>),
 	/// I've noticed a peer contradicting itself about a particular candidate
-	SelfContradiction(AbridgedCandidateReceipt, SignedFullStatement, SignedFullStatement),
+	SelfContradiction(CandidateReceipt, SignedFullStatement, SignedFullStatement),
 	/// This peer has seconded more than one parachain candidate for this relay parent head
 	DoubleVote(SignedFullStatement, SignedFullStatement),
 }
@@ -103,11 +110,28 @@ pub struct FromTableMisbehavior {
 	pub key: ValidatorId,
 }
 
+/// Outputs of validating a candidate.
+#[derive(Debug)]
+pub struct ValidationOutputs {
+	/// The head-data produced by validation.
+	pub head_data: HeadData,
+	/// The global validation schedule.
+	pub global_validation_schedule: GlobalValidationSchedule,
+	/// The local validation data.
+	pub local_validation_data: LocalValidationData,
+	/// Upward messages to the relay chain.
+	pub upward_messages: Vec<UpwardMessage>,
+	/// Fees paid to the validators of the relay-chain.
+	pub fees: Balance,
+	/// The new validation code submitted by the execution, if any.
+	pub new_validation_code: Option<ValidationCode>,
+}
+
 /// Result of the validation of the candidate.
 #[derive(Debug)]
 pub enum ValidationResult {
-	/// Candidate is valid.
-	Valid,
+	/// Candidate is valid. The validation process yields these outputs.
+	Valid(ValidationOutputs),
 	/// Candidate is invalid.
 	Invalid,
 }
@@ -136,7 +160,7 @@ impl std::convert::TryFrom<FromTableMisbehavior> for MisbehaviorReport {
 					&f.key,
 				).ok_or(())?;
 
-				Ok(MisbehaviorReport::SelfContradiction(receipt, signed_1, signed_2))
+				Ok(MisbehaviorReport::SelfContradiction(receipt.to_plain(), signed_1, signed_2))
 			}
 			TableMisbehavior::ValidityDoubleVote(
 				TableValidityDoubleVote::IssuedAndInvalidity((c, s1), (d, s2))
@@ -157,7 +181,7 @@ impl std::convert::TryFrom<FromTableMisbehavior> for MisbehaviorReport {
 					&f.key,
 				).ok_or(())?;
 
-				Ok(MisbehaviorReport::SelfContradiction(receipt, signed_1, signed_2))
+				Ok(MisbehaviorReport::SelfContradiction(receipt.to_plain(), signed_1, signed_2))
 			}
 			TableMisbehavior::ValidityDoubleVote(
 				TableValidityDoubleVote::ValidityAndInvalidity(c, s1, s2)
@@ -177,7 +201,7 @@ impl std::convert::TryFrom<FromTableMisbehavior> for MisbehaviorReport {
 					&f.key,
 				).ok_or(())?;
 
-				Ok(MisbehaviorReport::SelfContradiction(c, signed_1, signed_2))
+				Ok(MisbehaviorReport::SelfContradiction(c.to_plain(), signed_1, signed_2))
 			}
 			TableMisbehavior::MultipleCandidates(
 				TableMultipleCandidates {
diff --git a/polkadot/node/service/src/chain_spec.rs b/polkadot/node/service/src/chain_spec.rs
index 0659d08083016a953407ad4aa7c532ff4898d76c..db9d9c5dded9bf6bd2cf277792fb727b1c2f5aa2 100644
--- a/polkadot/node/service/src/chain_spec.rs
+++ b/polkadot/node/service/src/chain_spec.rs
@@ -17,7 +17,7 @@
 //! Polkadot chain configurations.
 
 use sp_core::{Pair, Public, crypto::UncheckedInto, sr25519};
-use polkadot_primitives::{AccountId, AccountPublic, parachain::ValidatorId};
+use polkadot_primitives::v1::{AccountId, AccountPublic, ValidatorId};
 use polkadot_runtime as polkadot;
 use kusama_runtime as kusama;
 use westend_runtime as westend;
@@ -48,9 +48,9 @@ const DEFAULT_PROTOCOL_ID: &str = "dot";
 #[serde(rename_all = "camelCase")]
 pub struct Extensions {
 	/// Block numbers with known hashes.
-	pub fork_blocks: sc_client_api::ForkBlocks<polkadot_primitives::Block>,
+	pub fork_blocks: sc_client_api::ForkBlocks<polkadot_primitives::v1::Block>,
 	/// Known bad block hashes.
-	pub bad_blocks: sc_client_api::BadBlocks<polkadot_primitives::Block>,
+	pub bad_blocks: sc_client_api::BadBlocks<polkadot_primitives::v1::Block>,
 }
 
 /// The `ChainSpec parametrised for polkadot runtime`.
diff --git a/polkadot/node/service/src/grandpa_support.rs b/polkadot/node/service/src/grandpa_support.rs
index 806a189d9fe530a75e65d1fecf092fc316c45229..2a9b73b0868e5af977fecb060d9c1c0f3b36857e 100644
--- a/polkadot/node/service/src/grandpa_support.rs
+++ b/polkadot/node/service/src/grandpa_support.rs
@@ -16,7 +16,7 @@
 
 //! Polkadot-specific GRANDPA integration utilities.
 
-use polkadot_primitives::Hash;
+use polkadot_primitives::v1::Hash;
 use sp_runtime::traits::{Block as BlockT, NumberFor};
 
 /// A custom GRANDPA voting rule that "pauses" voting (i.e. keeps voting for the
@@ -98,7 +98,7 @@ impl<Block, B> grandpa::VotingRule<Block, B> for PauseAfterBlockFor<NumberFor<Bl
 /// #1500988).
 pub(crate) fn kusama_hard_forks() -> Vec<(
 	grandpa_primitives::SetId,
-	(Hash, polkadot_primitives::BlockNumber),
+	(Hash, polkadot_primitives::v1::BlockNumber),
 	grandpa_primitives::AuthorityList,
 )> {
 	use sp_core::crypto::Ss58Codec;
diff --git a/polkadot/node/service/src/lib.rs b/polkadot/node/service/src/lib.rs
index 8a435e6b595b193a5976cc4c7d0eb36f4f437f3e..1205d9f3ef19f22f4aaebc6a30d3619b0a9e0b72 100644
--- a/polkadot/node/service/src/lib.rs
+++ b/polkadot/node/service/src/lib.rs
@@ -22,7 +22,7 @@ mod client;
 
 use std::sync::Arc;
 use std::time::Duration;
-use polkadot_primitives::{parachain, AccountId, Nonce, Balance};
+use polkadot_primitives::v1::{AccountId, Nonce, Balance};
 #[cfg(feature = "full-node")]
 use service::{error::Error as ServiceError, ServiceBuilder};
 use grandpa::{self, FinalityProofProvider as GrandpaFinalityProofProvider};
@@ -45,8 +45,7 @@ pub use sc_consensus::LongestChain;
 pub use sp_api::{ApiRef, Core as CoreApi, ConstructRuntimeApi, ProvideRuntimeApi, StateBackend};
 pub use sp_runtime::traits::{DigestFor, HashFor, NumberFor};
 pub use consensus_common::{Proposal, SelectChain, BlockImport, RecordProof, block_validation::Chain};
-pub use polkadot_primitives::parachain::{CollatorId, ParachainHost};
-pub use polkadot_primitives::{Block, BlockId};
+pub use polkadot_primitives::v1::{Block, BlockId, CollatorId, Id as ParaId};
 pub use sp_runtime::traits::{Block as BlockT, self as runtime_traits, BlakeTwo256};
 pub use chain_spec::{PolkadotChainSpec, KusamaChainSpec, WestendChainSpec};
 #[cfg(feature = "full-node")]
@@ -84,7 +83,6 @@ pub trait RuntimeApiCollection<Extrinsic: codec::Codec + Send + Sync + 'static>:
 	+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
 	+ babe_primitives::BabeApi<Block>
 	+ grandpa_primitives::GrandpaApi<Block>
-	+ ParachainHost<Block>
 	+ sp_block_builder::BlockBuilder<Block>
 	+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
 	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance, Extrinsic>
@@ -104,7 +102,6 @@ where
 	+ sp_api::ApiExt<Block, Error = sp_blockchain::Error>
 	+ babe_primitives::BabeApi<Block>
 	+ grandpa_primitives::GrandpaApi<Block>
-	+ ParachainHost<Block>
 	+ sp_block_builder::BlockBuilder<Block>
 	+ system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Nonce>
 	+ pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance, Extrinsic>
@@ -578,7 +575,7 @@ macro_rules! new_light {
 /// Builds a new object suitable for chain operations.
 pub fn new_chain_ops<Runtime, Dispatch, Extrinsic>(mut config: Configuration) -> Result<
 	(
-		Arc<service::TFullClient<Block, Runtime, Dispatch>>, 
+		Arc<service::TFullClient<Block, Runtime, Dispatch>>,
 		Arc<TFullBackend<Block>>,
 		consensus_common::import_queue::BasicQueue<Block, PrefixedMemoryDB<BlakeTwo256>>,
 		TaskManager,
@@ -601,7 +598,7 @@ where
 #[cfg(feature = "full-node")]
 pub fn polkadot_new_full(
 	mut config: Configuration,
-	collating_for: Option<(CollatorId, parachain::Id)>,
+	collating_for: Option<(CollatorId, ParaId)>,
 	_max_block_data_size: Option<u64>,
 	_authority_discovery_enabled: bool,
 	_slot_duration: u64,
@@ -633,7 +630,7 @@ pub fn polkadot_new_full(
 #[cfg(feature = "full-node")]
 pub fn kusama_new_full(
 	mut config: Configuration,
-	collating_for: Option<(CollatorId, parachain::Id)>,
+	collating_for: Option<(CollatorId, ParaId)>,
 	_max_block_data_size: Option<u64>,
 	_authority_discovery_enabled: bool,
 	_slot_duration: u64,
@@ -665,7 +662,7 @@ pub fn kusama_new_full(
 #[cfg(feature = "full-node")]
 pub fn westend_new_full(
 	mut config: Configuration,
-	collating_for: Option<(CollatorId, parachain::Id)>,
+	collating_for: Option<(CollatorId, ParaId)>,
 	_max_block_data_size: Option<u64>,
 	_authority_discovery_enabled: bool,
 	_slot_duration: u64,
diff --git a/polkadot/node/subsystem/src/lib.rs b/polkadot/node/subsystem/src/lib.rs
index db9a0629cfd407a53c8add8f277329304a108b64..e374eb9cfcdd60a631893617fb3f74f607aaf59a 100644
--- a/polkadot/node/subsystem/src/lib.rs
+++ b/polkadot/node/subsystem/src/lib.rs
@@ -26,7 +26,7 @@ use futures::prelude::*;
 use futures::channel::{mpsc, oneshot};
 use futures::future::BoxFuture;
 
-use polkadot_primitives::Hash;
+use polkadot_primitives::v1::Hash;
 use async_trait::async_trait;
 
 use crate::messages::AllMessages;
diff --git a/polkadot/node/subsystem/src/messages.rs b/polkadot/node/subsystem/src/messages.rs
index 36c293e49fe9e8d606f4b1cc5ad47d4561618fe9..10c861f1410cf8e7bbb15b26cb3bcd1c21b18837 100644
--- a/polkadot/node/subsystem/src/messages.rs
+++ b/polkadot/node/subsystem/src/messages.rs
@@ -24,12 +24,12 @@
 
 use futures::channel::{mpsc, oneshot};
 
-use polkadot_primitives::{BlockNumber, Hash, Signature};
-use polkadot_primitives::parachain::{
-	AbridgedCandidateReceipt, PoVBlock, ErasureChunk, BackedCandidate, Id as ParaId,
+use polkadot_primitives::v1::{
+	BlockNumber, Hash,
+	CandidateReceipt, PoV, ErasureChunk, BackedCandidate, Id as ParaId,
 	SignedAvailabilityBitfield, SigningContext, ValidatorId, ValidationCode, ValidatorIndex,
-	CoreAssignment, CoreOccupied, HeadData, CandidateDescriptor, GlobalValidationSchedule,
-	LocalValidationData,
+	CoreAssignment, CoreOccupied, HeadData, CandidateDescriptor,
+	ValidatorSignature, OmittedValidationData,
 };
 use polkadot_node_primitives::{
 	MisbehaviorReport, SignedFullStatement, View, ProtocolId, ValidationResult,
@@ -48,7 +48,7 @@ pub struct NewBackedCandidate(pub BackedCandidate);
 pub enum CandidateSelectionMessage {
 	/// We recommended a particular candidate to be seconded, but it was invalid; penalize the collator.
 	/// The hash is the relay parent.
-	Invalid(Hash, AbridgedCandidateReceipt),
+	Invalid(Hash, CandidateReceipt),
 }
 
 /// Messages received by the Candidate Backing subsystem.
@@ -59,7 +59,7 @@ pub enum CandidateBackingMessage {
 	GetBackedCandidates(Hash, oneshot::Sender<Vec<NewBackedCandidate>>),
 	/// Note that the Candidate Backing subsystem should second the given candidate in the context of the
 	/// given relay-parent (ref. by hash). This candidate must be validated.
-	Second(Hash, AbridgedCandidateReceipt, PoVBlock),
+	Second(Hash, CandidateReceipt, PoV),
 	/// Note a validator's statement about a particular candidate. Disagreements about validity must be escalated
 	/// to a broader check by Misbehavior Arbitration. Agreements are simply tallied until a quorum is reached.
 	Statement(Hash, SignedFullStatement),
@@ -69,22 +69,36 @@ pub enum CandidateBackingMessage {
 #[derive(Debug)]
 pub struct ValidationFailed;
 
-/// Messages received by the Validation subsystem
+/// Messages received by the Validation subsystem.
+///
+/// ## Validation Requests
+///
+/// Validation requests made to the subsystem should return an error only on internal error.
+/// Otherwise, they should return either `Ok(ValidationResult::Valid(_))`
+/// or `Ok(ValidationResult::Invalid)`.
 #[derive(Debug)]
 pub enum CandidateValidationMessage {
-	/// Validate a candidate, sending a side-channel response of valid or invalid.
+	/// Validate a candidate with provided parameters using relay-chain state.
+	///
+	/// This will implicitly attempt to gather the `OmittedValidationData` and `ValidationCode`
+	/// from the runtime API of the chain, based on the `relay_parent`
+	/// of the `CandidateDescriptor`.
+	/// If there is no state available which can provide this data, an error is returned.
+	ValidateFromChainState(
+		CandidateDescriptor,
+		Arc<PoV>,
+		oneshot::Sender<Result<ValidationResult, ValidationFailed>>,
+	),
+	/// Validate a candidate with provided, exhaustive parameters for validation.
 	///
-	/// Provide the relay-parent in whose context this should be validated, the full candidate receipt,
-	/// and the PoV.
-	Validate(
-		Hash,
-		AbridgedCandidateReceipt,
-		HeadData,
-		PoVBlock,
-		oneshot::Sender<Result<
-			(ValidationResult, GlobalValidationSchedule, LocalValidationData),
-			ValidationFailed,
-		>>,
+	/// Explicitly provide the `OmittedValidationData` and `ValidationCode` so this can do full
+	/// validation without needing to access the state of the relay-chain.
+	ValidateFromExhaustive(
+		OmittedValidationData,
+		ValidationCode,
+		CandidateDescriptor,
+		Arc<PoV>,
+		oneshot::Sender<Result<ValidationResult, ValidationFailed>>,
 	),
 }
 
@@ -146,8 +160,8 @@ pub enum BitfieldDistributionMessage {
 /// Availability store subsystem message.
 #[derive(Debug)]
 pub enum AvailabilityStoreMessage {
-	/// Query a `PoVBlock` from the AV store.
-	QueryPoV(Hash, oneshot::Sender<Option<PoVBlock>>),
+	/// Query a `PoV` from the AV store.
+	QueryPoV(Hash, oneshot::Sender<Option<PoV>>),
 
 	/// Query an `ErasureChunk` from the AV store.
 	QueryChunk(Hash, ValidatorIndex, oneshot::Sender<ErasureChunk>),
@@ -213,7 +227,7 @@ pub enum ProvisionableData {
 	/// Misbehavior reports are self-contained proofs of validator misbehavior.
 	MisbehaviorReport(Hash, MisbehaviorReport),
 	/// Disputes trigger a broad dispute resolution process.
-	Dispute(Hash, Signature),
+	Dispute(Hash, ValidatorSignature),
 }
 
 /// This data needs to make its way from the provisioner into the InherentData.
@@ -246,10 +260,10 @@ pub enum PoVDistributionMessage {
 	///
 	/// This `CandidateDescriptor` should correspond to a candidate seconded under the provided
 	/// relay-parent hash.
-	FetchPoV(Hash, CandidateDescriptor, oneshot::Sender<Arc<PoVBlock>>),
+	FetchPoV(Hash, CandidateDescriptor, oneshot::Sender<Arc<PoV>>),
 	/// Distribute a PoV for the given relay-parent and CandidateDescriptor.
 	/// The PoV should correctly hash to the PoV hash mentioned in the CandidateDescriptor
-	DistributePoV(Hash, CandidateDescriptor, Arc<PoVBlock>),
+	DistributePoV(Hash, CandidateDescriptor, Arc<PoV>),
 	/// An update from the network bridge.
 	NetworkBridgeUpdate(NetworkBridgeEvent),
 }
diff --git a/polkadot/node/test-service/src/chain_spec.rs b/polkadot/node/test-service/src/chain_spec.rs
index cbb08c470f07003b9682b0e3f6f299045302fa37..e81050afdbbe5f9c3a8cc0dc1440b81bcfb3f036 100644
--- a/polkadot/node/test-service/src/chain_spec.rs
+++ b/polkadot/node/test-service/src/chain_spec.rs
@@ -17,7 +17,7 @@
 use babe_primitives::AuthorityId as BabeId;
 use grandpa::AuthorityId as GrandpaId;
 use pallet_staking::Forcing;
-use polkadot_primitives::{parachain::ValidatorId, AccountId};
+use polkadot_primitives::v0::{ValidatorId, AccountId};
 use polkadot_service::chain_spec::{get_account_id_from_seed, get_from_seed, Extensions};
 use polkadot_test_runtime::constants::currency::DOTS;
 use sc_chain_spec::{ChainSpec, ChainType};
diff --git a/polkadot/node/test-service/src/lib.rs b/polkadot/node/test-service/src/lib.rs
index 7fc75d9f3719c7731228eeaff7959e3de48ecf58..751373265fc33690cb2d199e5e750d2e29d38a85 100644
--- a/polkadot/node/test-service/src/lib.rs
+++ b/polkadot/node/test-service/src/lib.rs
@@ -26,9 +26,8 @@ use futures::future::Future;
 use grandpa::FinalityProofProvider as GrandpaFinalityProofProvider;
 use log::info;
 use polkadot_network::{legacy::gossip::Known, protocol as network_protocol};
-use polkadot_primitives::{
-	parachain::{self, CollatorId},
-	Block, BlockId, Hash,
+use polkadot_primitives::v0::{
+	Block, BlockId, Hash, CollatorId, Id as ParaId,
 };
 use polkadot_runtime_common::{parachains, registrar, BlockHashCount};
 use polkadot_service::{
@@ -68,7 +67,7 @@ native_executor_instance!(
 /// Create a new Polkadot test service for a full node.
 pub fn polkadot_test_new_full(
 	config: Configuration,
-	collating_for: Option<(CollatorId, parachain::Id)>,
+	collating_for: Option<(CollatorId, ParaId)>,
 	max_block_data_size: Option<u64>,
 	authority_discovery_enabled: bool,
 	slot_duration: u64,
@@ -287,7 +286,7 @@ where
 		let extrinsic = polkadot_test_runtime::UncheckedExtrinsic::new_signed(
 			function.clone(),
 			polkadot_test_runtime::Address::Id(caller.public().into()),
-			polkadot_primitives::Signature::Sr25519(signature.clone()),
+			polkadot_primitives::v0::Signature::Sr25519(signature.clone()),
 			extra.clone(),
 		);
 
diff --git a/polkadot/parachain/test-parachains/adder/collator/src/main.rs b/polkadot/parachain/test-parachains/adder/collator/src/main.rs
index 42c3c824004a730ea41171a0660e18a787f2d837..ec5b626883c1296c44d1ee27c526db656218575b 100644
--- a/polkadot/parachain/test-parachains/adder/collator/src/main.rs
+++ b/polkadot/parachain/test-parachains/adder/collator/src/main.rs
@@ -22,9 +22,9 @@ use std::sync::Arc;
 use adder::{HeadData as AdderHead, BlockData as AdderBody};
 use sp_core::Pair;
 use codec::{Encode, Decode};
-use primitives::{
+use primitives::v0::{
 	Hash, DownwardMessage,
-	parachain::{HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationSchedule},
+	HeadData, BlockData, Id as ParaId, LocalValidationData, GlobalValidationSchedule,
 };
 use collator::{ParachainContext, Network, BuildParachainContext, Cli, SubstrateCli};
 use parking_lot::Mutex;
diff --git a/polkadot/primitives/src/inclusion_inherent.rs b/polkadot/primitives/src/inclusion_inherent.rs
deleted file mode 100644
index ca3f5ec23a16c9d6d9daedbdb76a136a77ea3061..0000000000000000000000000000000000000000
--- a/polkadot/primitives/src/inclusion_inherent.rs
+++ /dev/null
@@ -1,23 +0,0 @@
-// Copyright 2017-2020 Parity Technologies (UK) Ltd.
-// This file is part of Polkadot.
-
-// Polkadot is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-
-// Polkadot is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-// GNU General Public License for more details.
-
-// You should have received a copy of the GNU General Public License
-// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
-
-//! Inclusion Inherent primitives define types and constants which can be imported
-//! without needing to import the entire inherent module.
-
-use inherents::InherentIdentifier;
-
-/// Unique identifier for the Inclusion Inherent
-pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0";
diff --git a/polkadot/primitives/src/lib.rs b/polkadot/primitives/src/lib.rs
index 6f0a0986c933c698c3097ca522ea5025f2994dbd..82a5e7ca2e03988dd94d5d50616e7bfd31e11739 100644
--- a/polkadot/primitives/src/lib.rs
+++ b/polkadot/primitives/src/lib.rs
@@ -20,58 +20,5 @@
 
 #![cfg_attr(not(feature = "std"), no_std)]
 
-pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT, Verify, IdentifyAccount};
-pub use polkadot_core_primitives::*;
-
-pub mod inclusion_inherent;
-pub mod parachain;
-
-pub use parity_scale_codec::Compact;
-
-/// Custom validity errors used in Polkadot while validating transactions.
-#[repr(u8)]
-pub enum ValidityError {
-	/// The Ethereum signature is invalid.
-	InvalidEthereumSignature = 0,
-	/// The signer has no claim.
-	SignerHasNoClaim = 1,
-	/// No permission to execute the call.
-	NoPermission = 2,
-	/// An invalid statement was made for a claim.
-	InvalidStatement = 3,
-}
-
-impl From<ValidityError> for u8 {
-	fn from(err: ValidityError) -> Self {
-		err as u8
-	}
-}
-
-/// App-specific crypto used for reporting equivocation/misbehavior in BABE,
-/// GRANDPA and Parachains, described in the white paper as the fisherman role.
-/// Any rewards for misbehavior reporting will be paid out to this account.
-pub mod fisherman {
-	use super::{Signature, Verify};
-	use primitives::crypto::KeyTypeId;
-
-	/// Key type for the reporting module. Used for reporting BABE, GRANDPA
-	/// and Parachain equivocations.
-	pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"fish");
-
-	mod app {
-		use application_crypto::{app_crypto, sr25519};
-		app_crypto!(sr25519, super::KEY_TYPE);
-	}
-
-	/// Identity of the equivocation/misbehavior reporter.
-	pub type FishermanId = app::Public;
-
-	/// An `AppCrypto` type to allow submitting signed transactions using the fisherman
-	/// application key as signer.
-	pub struct FishermanAppCrypto;
-	impl frame_system::offchain::AppCrypto<<Signature as Verify>::Signer, Signature> for FishermanAppCrypto {
-		type RuntimeAppPublic = FishermanId;
-		type GenericSignature = primitives::sr25519::Signature;
-		type GenericPublic = primitives::sr25519::Public;
-	}
-}
+pub mod v0;
+pub mod v1;
diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/v0.rs
similarity index 83%
rename from polkadot/primitives/src/parachain.rs
rename to polkadot/primitives/src/v0.rs
index 19937798c64647d44b7e5df1f1e3c35dc5c94c7f..e1ec3a55463c6d18503abf998e6f5f72382d4f8e 100644
--- a/polkadot/primitives/src/parachain.rs
+++ b/polkadot/primitives/src/v0.rs
@@ -21,18 +21,20 @@ use sp_std::prelude::*;
 use sp_std::cmp::Ordering;
 use parity_scale_codec::{Encode, Decode};
 use bitvec::vec::BitVec;
-use super::{Hash, Balance, BlockNumber};
 
 #[cfg(feature = "std")]
 use serde::{Serialize, Deserialize};
 
 #[cfg(feature = "std")]
-use primitives::{bytes, crypto::Pair};
+use primitives::crypto::Pair;
 use primitives::RuntimeDebug;
 use runtime_primitives::traits::{AppVerify, Block as BlockT};
 use inherents::InherentIdentifier;
 use application_crypto::KeyTypeId;
-use polkadot_core_primitives::DownwardMessage;
+
+pub use runtime_primitives::traits::{BlakeTwo256, Hash as HashT, Verify, IdentifyAccount};
+pub use polkadot_core_primitives::*;
+pub use parity_scale_codec::Compact;
 
 pub use polkadot_parachain::primitives::{
 	Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage, HeadData, BlockData,
@@ -171,100 +173,6 @@ pub struct DutyRoster {
 	pub validator_duty: Vec<Chain>,
 }
 
-/// The unique (during session) index of a core.
-#[derive(Encode, Decode, Default, PartialOrd, Ord, Eq, PartialEq, Clone, Copy)]
-#[cfg_attr(feature = "std", derive(Debug))]
-pub struct CoreIndex(pub u32);
-
-impl From<u32> for CoreIndex {
-	fn from(i: u32) -> CoreIndex {
-		CoreIndex(i)
-	}
-}
-
-/// The unique (during session) index of a validator group.
-#[derive(Encode, Decode, Default, Clone, Copy)]
-#[cfg_attr(feature = "std", derive(Eq, Hash, PartialEq, Debug))]
-pub struct GroupIndex(pub u32);
-
-impl From<u32> for GroupIndex {
-	fn from(i: u32) -> GroupIndex {
-		GroupIndex(i)
-	}
-}
-
-/// A claim on authoring the next block for a given parathread.
-#[derive(Clone, Encode, Decode, Default)]
-#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
-pub struct ParathreadClaim(pub Id, pub CollatorId);
-
-/// An entry tracking a claim to ensure it does not pass the maximum number of retries.
-#[derive(Clone, Encode, Decode, Default)]
-#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
-pub struct ParathreadEntry {
-	/// The claim.
-	pub claim: ParathreadClaim,
-	/// Number of retries.
-	pub retries: u32,
-}
-
-/// What is occupying a specific availability core.
-#[derive(Clone, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
-pub enum CoreOccupied {
-	/// A parathread.
-	Parathread(ParathreadEntry),
-	/// A parachain.
-	Parachain,
-}
-
-/// The assignment type.
-#[derive(Clone, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
-pub enum AssignmentKind {
-	/// A parachain.
-	Parachain,
-	/// A parathread.
-	Parathread(CollatorId, u32),
-}
-
-/// How a free core is scheduled to be assigned.
-#[derive(Clone, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
-pub struct CoreAssignment {
-	/// The core that is assigned.
-	pub core: CoreIndex,
-	/// The unique ID of the para that is assigned to the core.
-	pub para_id: Id,
-	/// The kind of the assignment.
-	pub kind: AssignmentKind,
-	/// The index of the validator group assigned to the core.
-	pub group_idx: GroupIndex,
-}
-
-impl CoreAssignment {
-	/// Get the ID of a collator who is required to collate this block.
-	pub fn required_collator(&self) -> Option<&CollatorId> {
-		match self.kind {
-			AssignmentKind::Parachain => None,
-			AssignmentKind::Parathread(ref id, _) => Some(id),
-		}
-	}
-
-	/// Get the `CoreOccupied` from this.
-	pub fn to_core_occupied(&self) -> CoreOccupied {
-		match self.kind {
-			AssignmentKind::Parachain => CoreOccupied::Parachain,
-			AssignmentKind::Parathread(ref collator, retries) => CoreOccupied::Parathread(
-				ParathreadEntry {
-					claim: ParathreadClaim(self.para_id, collator.clone()),
-					retries,
-				}
-			),
-		}
-	}
-}
-
 /// Extra data that is needed along with the other fields in a `CandidateReceipt`
 /// to fully validate the candidate.
 ///
@@ -505,7 +413,6 @@ impl<H: AsRef<[u8]> + Encode> AbridgedCandidateReceipt<H> {
 	/// the relay-chain block in which context it should be executed, which implies
 	/// any blockchain state that must be referenced.
 	pub fn hash(&self) -> Hash {
-		use runtime_primitives::traits::{BlakeTwo256, Hash};
 		BlakeTwo256::hash_of(self)
 	}
 }
@@ -687,7 +594,6 @@ impl PoVBlock {
 	/// Compute hash of block data.
 	#[cfg(feature = "std")]
 	pub fn hash(&self) -> Hash {
-		use runtime_primitives::traits::{BlakeTwo256, Hash};
 		BlakeTwo256::hash_of(&self)
 	}
 }
@@ -716,16 +622,6 @@ pub struct ErasureChunk {
 	pub proof: Vec<Vec<u8>>,
 }
 
-/// Parachain header raw bytes wrapper type.
-#[derive(PartialEq, Eq)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
-pub struct Header(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
-
-/// Activity bit field.
-#[derive(PartialEq, Eq, Clone, Default, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
-pub struct Activity(#[cfg_attr(feature = "std", serde(with="bytes"))] pub Vec<u8>);
-
 /// Statements that can be made about parachain candidates. These are the
 /// actual values that are signed.
 #[derive(Clone, PartialEq, Eq, Encode, Decode, Hash)]
@@ -854,87 +750,6 @@ impl FeeSchedule {
 	}
 }
 
-/// A bitfield concerning availability of backed candidates.
-#[derive(PartialEq, Eq, Clone, Encode, Decode)]
-#[cfg_attr(feature = "std", derive(Debug))]
-pub struct AvailabilityBitfield(pub BitVec<bitvec::order::Lsb0, u8>);
-
-impl From<BitVec<bitvec::order::Lsb0, u8>> for AvailabilityBitfield {
-	fn from(inner: BitVec<bitvec::order::Lsb0, u8>) -> Self {
-		AvailabilityBitfield(inner)
-	}
-}
-
-/// A bitfield signed by a particular validator about the availability of pending candidates.
-pub type SignedAvailabilityBitfield = Signed<AvailabilityBitfield>;
-
-/// A set of signed availability bitfields. Should be sorted by validator index, ascending.
-pub type SignedAvailabilityBitfields = Vec<SignedAvailabilityBitfield>;
-
-/// A backed (or backable, depending on context) candidate.
-// TODO: yes, this is roughly the same as AttestedCandidate.
-// After https://github.com/paritytech/polkadot/issues/1250
-// they should be unified to this type.
-#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
-pub struct BackedCandidate<H = Hash> {
-	/// The candidate referred to.
-	pub candidate: AbridgedCandidateReceipt<H>,
-	/// The validity votes themselves, expressed as signatures.
-	pub validity_votes: Vec<ValidityAttestation>,
-	/// The indices of the validators within the group, expressed as a bitfield.
-	pub validator_indices: BitVec<bitvec::order::Lsb0, u8>,
-}
-
-/// Verify the backing of the given candidate.
-///
-/// Provide a lookup from the index of a validator within the group assigned to this para,
-/// as opposed to the index of the validator within the overall validator set, as well as
-/// the number of validators in the group.
-///
-/// Also provide the signing context.
-///
-/// Returns either an error, indicating that one of the signatures was invalid or that the index
-/// was out-of-bounds, or the number of signatures checked.
-pub fn check_candidate_backing<H: AsRef<[u8]> + Encode>(
-	backed: &BackedCandidate<H>,
-	signing_context: &SigningContext<H>,
-	group_len: usize,
-	validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
-) -> Result<usize, ()> {
-	if backed.validator_indices.len() != group_len {
-		return Err(())
-	}
-
-	if backed.validity_votes.len() > group_len {
-		return Err(())
-	}
-
-	// this is known, even in runtime, to be blake2-256.
-	let hash: Hash = backed.candidate.hash();
-
-	let mut signed = 0;
-	for ((val_in_group_idx, _), attestation) in backed.validator_indices.iter().enumerate()
-		.filter(|(_, signed)| **signed)
-		.zip(backed.validity_votes.iter())
-	{
-		let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
-		let payload = attestation.signed_payload(hash.clone(), signing_context);
-		let sig = attestation.signature();
-
-		if sig.verify(&payload[..], &validator_id) {
-			signed += 1;
-		} else {
-			return Err(())
-		}
-	}
-
-	if signed != backed.validity_votes.len() {
-		return Err(())
-	}
-
-	Ok(signed)
-}
-
 sp_api::decl_runtime_apis! {
 	/// The API for querying the state of parachains on-chain.
 	#[api_version(3)]
@@ -1098,6 +913,55 @@ impl<Payload: EncodeAs<RealPayload>, RealPayload: Encode> Signed<Payload, RealPa
 	}
 }
 
+/// Custom validity errors used in Polkadot while validating transactions.
+#[repr(u8)]
+pub enum ValidityError {
+	/// The Ethereum signature is invalid.
+	InvalidEthereumSignature = 0,
+	/// The signer has no claim.
+	SignerHasNoClaim = 1,
+	/// No permission to execute the call.
+	NoPermission = 2,
+	/// An invalid statement was made for a claim.
+	InvalidStatement = 3,
+}
+
+impl From<ValidityError> for u8 {
+	fn from(err: ValidityError) -> Self {
+		err as u8
+	}
+}
+
+/// App-specific crypto used for reporting equivocation/misbehavior in BABE,
+/// GRANDPA and Parachains, described in the white paper as the fisherman role.
+/// Any rewards for misbehavior reporting will be paid out to this account.
+pub mod fisherman {
+	use super::{Signature, Verify};
+	use primitives::crypto::KeyTypeId;
+
+	/// Key type for the reporting module. Used for reporting BABE, GRANDPA
+	/// and Parachain equivocations.
+	pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"fish");
+
+	mod app {
+		use application_crypto::{app_crypto, sr25519};
+		app_crypto!(sr25519, super::KEY_TYPE);
+	}
+
+	/// Identity of the equivocation/misbehavior reporter.
+	pub type FishermanId = app::Public;
+
+	/// An `AppCrypto` type to allow submitting signed transactions using the fisherman
+	/// application key as signer.
+	pub struct FishermanAppCrypto;
+	impl frame_system::offchain::AppCrypto<<Signature as Verify>::Signer, Signature> for FishermanAppCrypto {
+		type RuntimeAppPublic = FishermanId;
+		type GenericSignature = primitives::sr25519::Signature;
+		type GenericPublic = primitives::sr25519::Public;
+	}
+}
+
+
 #[cfg(test)]
 mod tests {
 	use super::*;
diff --git a/polkadot/primitives/src/v1.rs b/polkadot/primitives/src/v1.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9fb3d1662ec772526191d12beb4af89619447ba8
--- /dev/null
+++ b/polkadot/primitives/src/v1.rs
@@ -0,0 +1,478 @@
+// Copyright 2017-2020 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! V1 Primitives.
+
+use sp_std::prelude::*;
+use parity_scale_codec::{Encode, Decode};
+use bitvec::vec::BitVec;
+
+use primitives::RuntimeDebug;
+use runtime_primitives::traits::AppVerify;
+use inherents::InherentIdentifier;
+
+use runtime_primitives::traits::{BlakeTwo256, Hash as HashT};
+
+// Export some core primitives.
+pub use polkadot_core_primitives::v1::{
+	BlockNumber, Moment, Signature, AccountPublic, AccountId, AccountIndex,
+	ChainId, Hash, Nonce, Balance, Header, Block, BlockId, UncheckedExtrinsic,
+	Remark, DownwardMessage,
+};
+
+// Export some polkadot-parachain primitives
+pub use polkadot_parachain::primitives::{
+	Id, ParachainDispatchOrigin, LOWEST_USER_ID, UpwardMessage, HeadData, BlockData,
+	ValidationCode,
+};
+
+// Export some basic parachain primitives from v0.
+pub use crate::v0::{
+	CollatorId, CollatorSignature, PARACHAIN_KEY_TYPE_ID, ValidatorId, ValidatorIndex,
+	ValidatorSignature, SigningContext, Signed, ValidityAttestation,
+	CompactStatement, SignedStatement, ErasureChunk, EncodeAs,
+};
+
+// More exports from v0 for std.
+#[cfg(feature = "std")]
+pub use crate::v0::{ValidatorPair, CollatorPair};
+
+/// Unique identifier for the Inclusion Inherent
+pub const INCLUSION_INHERENT_IDENTIFIER: InherentIdentifier = *b"inclusn0";
+
+/// Get a collator signature payload on a relay-parent, block-data combo.
+pub fn collator_signature_payload<H: AsRef<[u8]>>(
+	relay_parent: &H,
+	para_id: &Id,
+	pov_hash: &Hash,
+) -> [u8; 68] {
+	// 32-byte hash length is protected in a test below.
+	let mut payload = [0u8; 68];
+
+	payload[0..32].copy_from_slice(relay_parent.as_ref());
+	u32::from(*para_id).using_encoded(|s| payload[32..32 + s.len()].copy_from_slice(s));
+	payload[36..68].copy_from_slice(pov_hash.as_ref());
+
+	payload
+}
+
+fn check_collator_signature<H: AsRef<[u8]>>(
+	relay_parent: &H,
+	para_id: &Id,
+	pov_hash: &Hash,
+	collator: &CollatorId,
+	signature: &CollatorSignature,
+) -> Result<(),()> {
+	let payload = collator_signature_payload(relay_parent, para_id, pov_hash);
+	if signature.verify(&payload[..], collator) {
+		Ok(())
+	} else {
+		Err(())
+	}
+}
+
+/// A unique descriptor of the candidate receipt.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct CandidateDescriptor<H = Hash> {
+	/// The ID of the para this is a candidate for.
+	pub para_id: Id,
+	/// The hash of the relay-chain block this is executed in the context of.
+	pub relay_parent: H,
+	/// The collator's sr25519 public key.
+	pub collator: CollatorId,
+	/// Signature on blake2-256 of components of this receipt:
+	/// The parachain index, the relay parent, and the pov_hash.
+	pub signature: CollatorSignature,
+	/// The blake2-256 hash of the pov.
+	pub pov_hash: Hash,
+}
+
+impl<H: AsRef<[u8]>> CandidateDescriptor<H> {
+	/// Check the signature of the collator within this descriptor.
+	pub fn check_collator_signature(&self) -> Result<(), ()> {
+		check_collator_signature(
+			&self.relay_parent,
+			&self.para_id,
+			&self.pov_hash,
+			&self.collator,
+			&self.signature,
+		)
+	}
+}
+
+/// A candidate-receipt.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct CandidateReceipt<H = Hash> {
+	/// The descriptor of the candidate.
+	pub descriptor: CandidateDescriptor<H>,
+	/// The hash of the encoded commitments made as a result of candidate execution.
+	pub commitments_hash: Hash,
+}
+
+impl<H> CandidateReceipt<H> {
+	/// Get a reference to the candidate descriptor.
+	pub fn descriptor(&self) -> &CandidateDescriptor<H> {
+		&self.descriptor
+	}
+
+	/// Computes the blake2-256 hash of the receipt.
+	pub fn hash(&self) -> Hash where H: Encode {
+		BlakeTwo256::hash_of(self)
+	}
+}
+
+/// All data pertaining to the execution of a para candidate.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct FullCandidateReceipt<H = Hash> {
+	/// The inner candidate receipt.
+	pub inner: CandidateReceipt<H>,
+	/// The global validation schedule.
+	pub global_validation: GlobalValidationSchedule,
+	/// The local validation data.
+	pub local_validation: LocalValidationData,
+}
+
+/// A candidate-receipt with commitments directly included.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct CommittedCandidateReceipt<H = Hash> {
+	/// The descriptor of the candidate.
+	pub descriptor: CandidateDescriptor<H>,
+	/// The commitments of the candidate receipt.
+	pub commitments: CandidateCommitments,
+}
+
+impl<H> CommittedCandidateReceipt<H> {
+	/// Get a reference to the candidate descriptor.
+	pub fn descriptor(&self) -> &CandidateDescriptor<H> {
+		&self.descriptor
+	}
+}
+
+impl<H: Clone> CommittedCandidateReceipt<H> {
+	/// Transforms this into a plain CandidateReceipt.
+	pub fn to_plain(&self) -> CandidateReceipt<H> {
+		CandidateReceipt {
+			descriptor: self.descriptor.clone(),
+			commitments_hash: self.commitments.hash(),
+		}
+	}
+
+	/// Computes the hash of the committed candidate receipt.
+	///
+	/// This computes the canonical hash, not the hash of the directly encoded data.
+	/// Thus this is a shortcut for `candidate.to_plain().hash()`.
+	pub fn hash(&self) -> Hash where H: Encode {
+		self.to_plain().hash()
+	}
+}
+
+impl PartialOrd for CommittedCandidateReceipt {
+	fn partial_cmp(&self, other: &Self) -> Option<sp_std::cmp::Ordering> {
+		Some(self.cmp(other))
+	}
+}
+
+impl Ord for CommittedCandidateReceipt {
+	fn cmp(&self, other: &Self) -> sp_std::cmp::Ordering {
+		// TODO: compare signatures or something more sane
+		// https://github.com/paritytech/polkadot/issues/222
+		self.descriptor().para_id.cmp(&other.descriptor().para_id)
+			.then_with(|| self.commitments.head_data.cmp(&other.commitments.head_data))
+	}
+}
+
+/// Extra data that is needed along with the other fields in a `CandidateReceipt`
+/// to fully validate the candidate. These fields are parachain-specific.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct LocalValidationData {
+	/// The parent head-data.
+	pub parent_head: HeadData,
+	/// The balance of the parachain at the moment of validation.
+	pub balance: Balance,
+	/// The blake2-256 hash of the validation code used to execute the candidate.
+	pub validation_code_hash: Hash,
+	/// Whether the parachain is allowed to upgrade its validation code.
+	///
+	/// This is `Some` if so, and contains the number of the minimum relay-chain
+	/// height at which the upgrade will be applied, if an upgrade is signaled
+	/// now.
+	///
+	/// A parachain should enact its side of the upgrade at the end of the first
+	/// parablock executing in the context of a relay-chain block with at least this
+	/// height. This may be equal to the current perceived relay-chain block height, in
+	/// which case the code upgrade should be applied at the end of the signaling
+	/// block.
+	pub code_upgrade_allowed: Option<BlockNumber>,
+}
+
+/// Extra data that is needed along with the other fields in a `CandidateReceipt`
+/// to fully validate the candidate.
+///
+/// These are global parameters that apply to all candidates in a block.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct GlobalValidationSchedule {
+	/// The maximum code size permitted, in bytes.
+	pub max_code_size: u32,
+	/// The maximum head-data size permitted, in bytes.
+	pub max_head_data_size: u32,
+	/// The relay-chain block number this is in the context of.
+	pub block_number: BlockNumber,
+}
+
+/// Commitments made in a `CandidateReceipt`. Many of these are outputs of validation.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug, Default))]
+pub struct CandidateCommitments {
+	/// Fees paid from the chain to the relay chain validators.
+	pub fees: Balance,
+	/// Messages destined to be interpreted by the Relay chain itself.
+	pub upward_messages: Vec<UpwardMessage>,
+	/// The root of a block's erasure encoding Merkle tree.
+	pub erasure_root: Hash,
+	/// New validation code.
+	pub new_validation_code: Option<ValidationCode>,
+	/// The head-data produced as a result of execution.
+	pub head_data: HeadData,
+}
+
+impl CandidateCommitments {
+	/// Compute the blake2-256 hash of the commitments.
+	pub fn hash(&self) -> Hash {
+		BlakeTwo256::hash_of(self)
+	}
+}
+
+/// A Proof-of-Validity
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct PoV {
+	/// The block witness data.
+	pub block_data: BlockData,
+}
+
+impl PoV {
+	/// Get the blake2-256 hash of the PoV.
+	#[cfg(feature = "std")]
+	pub fn hash(&self) -> Hash {
+		BlakeTwo256::hash_of(self)
+	}
+}
+
+/// A bitfield concerning availability of backed candidates.
+#[derive(PartialEq, Eq, Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct AvailabilityBitfield(pub BitVec<bitvec::order::Lsb0, u8>);
+
+impl From<BitVec<bitvec::order::Lsb0, u8>> for AvailabilityBitfield {
+	fn from(inner: BitVec<bitvec::order::Lsb0, u8>) -> Self {
+		AvailabilityBitfield(inner)
+	}
+}
+
+/// A bitfield signed by a particular validator about the availability of pending candidates.
+pub type SignedAvailabilityBitfield = Signed<AvailabilityBitfield>;
+
+/// A set of signed availability bitfields. Should be sorted by validator index, ascending.
+pub type SignedAvailabilityBitfields = Vec<SignedAvailabilityBitfield>;
+
+/// A backed (or backable, depending on context) candidate.
+#[derive(Encode, Decode, Clone, PartialEq, Eq, RuntimeDebug)]
+pub struct BackedCandidate<H = Hash> {
+	/// The candidate referred to.
+	pub candidate: CommittedCandidateReceipt<H>,
+	/// The validity votes themselves, expressed as signatures.
+	pub validity_votes: Vec<ValidityAttestation>,
+	/// The indices of the validators within the group, expressed as a bitfield.
+	pub validator_indices: BitVec<bitvec::order::Lsb0, u8>,
+}
+
+impl<H> BackedCandidate<H> {
+	/// Get a reference to the descriptor of the para.
+	pub fn descriptor(&self) -> &CandidateDescriptor<H> {
+		&self.candidate.descriptor
+	}
+}
+
+/// Verify the backing of the given candidate.
+///
+/// Provide a lookup from the index of a validator within the group assigned to this para,
+/// as opposed to the index of the validator within the overall validator set, as well as
+/// the number of validators in the group.
+///
+/// Also provide the signing context.
+///
+/// Returns either an error, indicating that one of the signatures was invalid or that the index
+/// was out-of-bounds, or the number of signatures checked.
+pub fn check_candidate_backing<H: AsRef<[u8]> + Clone + Encode>(
+	backed: &BackedCandidate<H>,
+	signing_context: &SigningContext<H>,
+	group_len: usize,
+	validator_lookup: impl Fn(usize) -> Option<ValidatorId>,
+) -> Result<usize, ()> {
+	if backed.validator_indices.len() != group_len {
+		return Err(())
+	}
+
+	if backed.validity_votes.len() > group_len {
+		return Err(())
+	}
+
+	// this is known, even in runtime, to be blake2-256.
+	let hash: Hash = backed.candidate.hash();
+
+	let mut signed = 0;
+	for ((val_in_group_idx, _), attestation) in backed.validator_indices.iter().enumerate()
+		.filter(|(_, signed)| **signed)
+		.zip(backed.validity_votes.iter())
+	{
+		let validator_id = validator_lookup(val_in_group_idx).ok_or(())?;
+		let payload = attestation.signed_payload(hash.clone(), signing_context);
+		let sig = attestation.signature();
+
+		if sig.verify(&payload[..], &validator_id) {
+			signed += 1;
+		} else {
+			return Err(())
+		}
+	}
+
+	if signed != backed.validity_votes.len() {
+		return Err(())
+	}
+
+	Ok(signed)
+}
+
+/// The unique (during session) index of a core.
+#[derive(Encode, Decode, Default, PartialOrd, Ord, Eq, PartialEq, Clone, Copy)]
+#[cfg_attr(feature = "std", derive(Debug))]
+pub struct CoreIndex(pub u32);
+
+impl From<u32> for CoreIndex {
+	fn from(i: u32) -> CoreIndex {
+		CoreIndex(i)
+	}
+}
+
+/// The unique (during session) index of a validator group.
+#[derive(Encode, Decode, Default, Clone, Copy)]
+#[cfg_attr(feature = "std", derive(Eq, Hash, PartialEq, Debug))]
+pub struct GroupIndex(pub u32);
+
+impl From<u32> for GroupIndex {
+	fn from(i: u32) -> GroupIndex {
+		GroupIndex(i)
+	}
+}
+
+/// A claim on authoring the next block for a given parathread.
+#[derive(Clone, Encode, Decode, Default)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub struct ParathreadClaim(pub Id, pub CollatorId);
+
+/// An entry tracking a claim to ensure it does not pass the maximum number of retries.
+#[derive(Clone, Encode, Decode, Default)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub struct ParathreadEntry {
+	/// The claim.
+	pub claim: ParathreadClaim,
+	/// Number of retries.
+	pub retries: u32,
+}
+
+/// What is occupying a specific availability core.
+#[derive(Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub enum CoreOccupied {
+	/// A parathread.
+	Parathread(ParathreadEntry),
+	/// A parachain.
+	Parachain,
+}
+
+/// The assignment type.
+#[derive(Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub enum AssignmentKind {
+	/// A parachain.
+	Parachain,
+	/// A parathread.
+	Parathread(CollatorId, u32),
+}
+
+/// How a free core is scheduled to be assigned.
+#[derive(Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub struct CoreAssignment {
+	/// The core that is assigned.
+	pub core: CoreIndex,
+	/// The unique ID of the para that is assigned to the core.
+	pub para_id: Id,
+	/// The kind of the assignment.
+	pub kind: AssignmentKind,
+	/// The index of the validator group assigned to the core.
+	pub group_idx: GroupIndex,
+}
+
+impl CoreAssignment {
+	/// Get the ID of a collator who is required to collate this block.
+	pub fn required_collator(&self) -> Option<&CollatorId> {
+		match self.kind {
+			AssignmentKind::Parachain => None,
+			AssignmentKind::Parathread(ref id, _) => Some(id),
+		}
+	}
+
+	/// Get the `CoreOccupied` from this.
+	pub fn to_core_occupied(&self) -> CoreOccupied {
+		match self.kind {
+			AssignmentKind::Parachain => CoreOccupied::Parachain,
+			AssignmentKind::Parathread(ref collator, retries) => CoreOccupied::Parathread(
+				ParathreadEntry {
+					claim: ParathreadClaim(self.para_id, collator.clone()),
+					retries,
+				}
+			),
+		}
+	}
+}
+
+/// Validation data omitted from most candidate descriptor structs, as it can be derived from the
+/// relay-parent.
+#[derive(Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub struct OmittedValidationData {
+	/// The global validation schedule.
+	pub global_validation: GlobalValidationSchedule,
+	/// The local validation data.
+	pub local_validation: LocalValidationData,
+}
+
+/// This is the data we keep available for each candidate included in the relay chain.
+#[derive(Clone, Encode, Decode)]
+#[cfg_attr(feature = "std", derive(PartialEq, Debug))]
+pub struct AvailableData {
+	/// The Proof-of-Validation of the candidate.
+	pub pov: PoV,
+	/// The omitted validation data.
+	pub omitted_validation: OmittedValidationData,
+}
diff --git a/polkadot/roadmap/implementers-guide/src/types/availability.md b/polkadot/roadmap/implementers-guide/src/types/availability.md
index 3362908d6b63f659a09c0885bacafc6c32b59aa1..be42c7a9278a0e9016150155741453137eeed073 100644
--- a/polkadot/roadmap/implementers-guide/src/types/availability.md
+++ b/polkadot/roadmap/implementers-guide/src/types/availability.md
@@ -9,7 +9,7 @@ A bitfield [signed](backing.md#signed-wrapper) by a particular validator about t
 
 
 ```rust
-pub type SignedAvailabilityBitfield = Signed<Bitvec>;
+type SignedAvailabilityBitfield = Signed<Bitvec>;
 
 struct Bitfields(Vec<(SignedAvailabilityBitfield)>), // bitfields sorted by validator index, ascending
 ```
@@ -21,3 +21,50 @@ Often referred to as PoV, this is a type-safe wrapper around bytes (`Vec<u8>`) w
 ```rust
 struct PoV(Vec<u8>);
 ```
+
+## Omitted Validation Data
+
+Validation data that is often omitted from types describing candidates as it can be derived from the relay-parent of the candidate. However, with the expectation of state pruning, these are best kept available elsewhere as well.
+
+This contains the [`GlobalValidationSchedule`](candidate.md#globalvalidationschedule) and [`LocalValidationData`](candidate.md#localvalidationdata)
+
+```rust
+struct OmittedValidationData {
+    /// The global validation schedule.
+    global_validation: GlobalValidationSchedule,
+    /// The local validation data.
+    local_validation: LocalValidationData,
+}
+```
+
+
+## Available Data
+
+This is the data we want to keep available for each [candidate](candidate.md) included in the relay chain.
+
+```rust
+struct AvailableData {
+    /// The Proof-of-Validation of the candidate.
+    pov: PoV,
+    /// The omitted validation data.
+    omitted_validation: OmittedValidationData,
+}
+```
+
+> TODO: With XCMP, we also need to keep available the outgoing messages as a result of para-validation.
+
+## Erasure Chunk
+
+The [`AvailableData`](#availabledata) is split up into an erasure-coding as part of the availability process. Each validator gets a chunk. This describes one of those chunks, along with its proof against a merkle root hash, which should be apparent from context, and is the `erasure_root` field of a [`CandidateDescriptor`](candidate.md#candidatedescriptor).
+
+
+```rust
+struct ErasureChunk {
+    /// The erasure-encoded chunk of data belonging to the candidate block.
+    chunk: Vec<u8>,
+    /// The index of this erasure-encoded chunk of data.
+    index: u32,
+    /// Proof for this chunk's branch in the Merkle tree.
+    proof: Vec<Vec<u8>>,
+}
+```
diff --git a/polkadot/roadmap/implementers-guide/src/types/candidate.md b/polkadot/roadmap/implementers-guide/src/types/candidate.md
index fdba6919e57ce340df8eab39be92798a376fd1ef..0ed38590a733cc31f830e9e22d84610c4895215f 100644
--- a/polkadot/roadmap/implementers-guide/src/types/candidate.md
+++ b/polkadot/roadmap/implementers-guide/src/types/candidate.md
@@ -1,6 +1,7 @@
 # Candidate Types
 
 Para candidates are some of the most common types, both within the runtime and on the Node-side.
+Candidates are the fundamental datatype for advancing parachains and parathreads, encapsulating the collator's signature, the context of the parablock, the commitments to the output, and a commitment to the data which proves it valid.
 
 In a way, this entire guide is about these candidates: how they are scheduled, constructed, backed, included, and challenged.
 
@@ -179,3 +180,24 @@ struct SigningContext {
 	session_index: SessionIndex,
 }
 ```
+
+## Validation Outputs
+
+This struct encapsulates the outputs of candidate validation.
+
+```rust
+struct ValidationOutputs {
+	/// The head-data produced by validation.
+	head_data: HeadData,
+	/// The global validation schedule.
+	global_validation_schedule: GlobalValidationSchedule,
+	/// The local validation data.
+	local_validation_data: LocalValidationData,
+	/// Upwards messages to the relay chain.
+	upwards_messages: Vec<UpwardsMessage>,
+	/// Fees paid to the validators of the relay-chain.
+	fees: Balance,
+	/// The new validation code submitted by the execution, if any.
+	new_validation_code: Option<ValidationCode>,
+}
+```
diff --git a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md
index 1e59eedff8db0970ae9762bfc3aa9a25e8b10a77..b822508f4a3ea9dc934cc49af0e67dc773697e54 100644
--- a/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md
+++ b/polkadot/roadmap/implementers-guide/src/types/overseer-protocol.md
@@ -91,6 +91,7 @@ enum CandidateBackingMessage {
   GetBackedCandidates(Hash, ResponseChannel<Vec<NewBackedCandidate>>),
   /// Note that the Candidate Backing subsystem should second the given candidate in the context of the
   /// given relay-parent (ref. by hash). This candidate must be validated using the provided PoV.
+  /// The PoV is expected to match the `pov_hash` in the descriptor.
   Second(Hash, CandidateReceipt, PoV),
   /// Note a peer validator's statement about a particular candidate. Disagreements about validity must be escalated
   /// to a broader check by Misbehavior Arbitration. Agreements are simply tallied until a quorum is reached.
@@ -282,29 +283,41 @@ enum StatementDistributionMessage {
 
 ## Validation Request Type
 
-Various modules request that the [Candidate Validation subsystem](../node/utility/candidate-validation.md) validate a block with this message
+Various modules request that the [Candidate Validation subsystem](../node/utility/candidate-validation.md) validate a block with this message. It returns [`ValidationOutputs`](candidate.md#validationoutputs) for successful validation.
 
 ```rust
 
 /// Result of the validation of the candidate.
 enum ValidationResult {
-	/// Candidate is valid.
-	Valid,
+	/// Candidate is valid, and here are the outputs. In practice, this should be a shared type
+	/// so that validation caching can be done.
+	Valid(ValidationOutputs),
 	/// Candidate is invalid.
 	Invalid,
 }
 
+/// Messages issued to the candidate validation subsystem.
+///
+/// ## Validation Requests
+///
+/// Validation requests made to the subsystem should return an error only on internal error.
+/// Otherwise, they should return either `Ok(ValidationResult::Valid(_))` or `Ok(ValidationResult::Invalid)`.
 enum CandidateValidationMessage {
-	/// Validate a candidate with provided parameters. Returns `Err` if an only if an internal
-	/// error is encountered.
-	/// In case no internal error was encontered it returns a tuple containing the result of
-	/// validation and `GlobalValidationSchedule` and `LocalValidationData` structures that
-	/// may be used by the caller to make the candidate available.
-	/// A bad candidate will return `Ok((ValidationResult::Invalid, _, _)`, while a good one will
-	/// return `Ok((ValidationResult::Valid, _, _))`.
-	Validate(
-		Hash, CandidateReceipt, HeadData, PoV, ResponseChannel<
-			Result<(ValidationResult, GlobalValidationSchedule, LocalValidationData)>
-		>),
+	/// Validate a candidate with provided parameters. This will implicitly attempt to gather the
+	/// `OmittedValidationData` and `ValidationCode` from the runtime API of the chain,
+	/// based on the `relay_parent` of the `CandidateDescriptor`.
+	/// If there is no state available which can provide this data, an error is returned.
+	ValidateFromChainState(CandidateDescriptor, PoV, ResponseChannel<Result<ValidationResult>>),
+
+	/// Validate a candidate with provided parameters. Explicitly provide the `OmittedValidationData`
+	/// and `ValidationCode` so this can do full validation without needing to access the state of
+	/// the relay-chain.
+	ValidateFromExhaustive(
+		OmittedValidationData,
+		ValidationCode,
+		CandidateDescriptor,
+		PoV,
+		ResponseChannel<Result<ValidationResult>>,
+	),
 }
 ```
diff --git a/polkadot/rpc/src/lib.rs b/polkadot/rpc/src/lib.rs
index 6bddc8ad8dafeccb39f4d8248aa21c06224d3959..c73b478329ee6a5e0e17e499c1355b79a78b7fec 100644
--- a/polkadot/rpc/src/lib.rs
+++ b/polkadot/rpc/src/lib.rs
@@ -20,7 +20,7 @@
 
 use std::sync::Arc;
 
-use polkadot_primitives::{Block, BlockNumber, AccountId, Nonce, Balance, Hash};
+use polkadot_primitives::v0::{Block, BlockNumber, AccountId, Nonce, Balance, Hash};
 use sp_api::ProvideRuntimeApi;
 use txpool_api::TransactionPool;
 use sp_blockchain::{HeaderBackend, HeaderMetadata, Error as BlockChainError};
diff --git a/polkadot/runtime/common/src/attestations.rs b/polkadot/runtime/common/src/attestations.rs
index f27874117aaad1b898b6614fd787c3ff067a4f5b..e7a6854bbb132258baaae5d87c38cc4fd25e3921 100644
--- a/polkadot/runtime/common/src/attestations.rs
+++ b/polkadot/runtime/common/src/attestations.rs
@@ -28,7 +28,7 @@ use frame_support::{
 	weights::DispatchClass,
 };
 
-use primitives::{Hash, parachain::{AttestedCandidate, AbridgedCandidateReceipt, Id as ParaId}};
+use primitives::v0::{Hash, AttestedCandidate, AbridgedCandidateReceipt, Id as ParaId};
 use sp_runtime::RuntimeDebug;
 use sp_staking::SessionIndex;
 
diff --git a/polkadot/runtime/common/src/claims.rs b/polkadot/runtime/common/src/claims.rs
index fd8c1c1c880a06eb00983fb898b79ea631aff005..6efc3d31d75de4831436a68c521570395660ae87 100644
--- a/polkadot/runtime/common/src/claims.rs
+++ b/polkadot/runtime/common/src/claims.rs
@@ -35,7 +35,7 @@ use sp_runtime::{
 		TransactionSource, TransactionValidityError,
 	},
 };
-use primitives::ValidityError;
+use primitives::v0::ValidityError;
 
 type CurrencyOf<T> = <<T as Trait>::VestingSchedule as VestingSchedule<<T as system::Trait>::AccountId>>::Currency;
 type BalanceOf<T> = <CurrencyOf<T> as Currency<<T as system::Trait>::AccountId>>::Balance;
diff --git a/polkadot/runtime/common/src/crowdfund.rs b/polkadot/runtime/common/src/crowdfund.rs
index ee2b740745b7d5c80a54b3c2a0d8e0caf0dc70e9..fc233d107abe147e688c17f43c29e17e67ae62f6 100644
--- a/polkadot/runtime/common/src/crowdfund.rs
+++ b/polkadot/runtime/common/src/crowdfund.rs
@@ -79,7 +79,7 @@ use sp_runtime::{ModuleId,
 use crate::slots;
 use codec::{Encode, Decode};
 use sp_std::vec::Vec;
-use primitives::parachain::{Id as ParaId, HeadData};
+use primitives::v0::{Id as ParaId, HeadData};
 
 pub type BalanceOf<T> =
 	<<T as slots::Trait>::Currency as Currency<<T as system::Trait>::AccountId>>::Balance;
@@ -568,7 +568,7 @@ mod tests {
 	};
 	use frame_support::traits::{Contains, ContainsLengthBound};
 	use sp_core::H256;
-	use primitives::parachain::{Info as ParaInfo, Id as ParaId, Scheduling, ValidationCode};
+	use primitives::v0::{Info as ParaInfo, Id as ParaId, Scheduling, ValidationCode};
 	// 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 sp_runtime::{
diff --git a/polkadot/runtime/common/src/impls.rs b/polkadot/runtime/common/src/impls.rs
index 543e2c739adb1cc1bf340f67b2e3170c88b740c6..7e3b6d917f776998b171338aac4ac6bc99dfa244 100644
--- a/polkadot/runtime/common/src/impls.rs
+++ b/polkadot/runtime/common/src/impls.rs
@@ -26,8 +26,8 @@ pub struct ToAuthor<R>(sp_std::marker::PhantomData<R>);
 impl<R> OnUnbalanced<NegativeImbalance<R>> for ToAuthor<R>
 where
 	R: balances::Trait + authorship::Trait,
-	<R as system::Trait>::AccountId: From<primitives::AccountId>,
-	<R as system::Trait>::AccountId: Into<primitives::AccountId>,
+	<R as system::Trait>::AccountId: From<primitives::v0::AccountId>,
+	<R as system::Trait>::AccountId: Into<primitives::v0::AccountId>,
 	<R as system::Trait>::Event: From<balances::RawEvent<
 		<R as system::Trait>::AccountId,
 		<R as balances::Trait>::Balance,
diff --git a/polkadot/runtime/common/src/lib.rs b/polkadot/runtime/common/src/lib.rs
index da6fc5fcc27bd27005700f5c11c5926ab1497a1c..d32db38e05be96f23f3a33ffdcfb5cb86581b5ef 100644
--- a/polkadot/runtime/common/src/lib.rs
+++ b/polkadot/runtime/common/src/lib.rs
@@ -27,7 +27,7 @@ pub mod slots;
 pub mod crowdfund;
 pub mod impls;
 
-use primitives::BlockNumber;
+use primitives::v0::BlockNumber;
 use sp_runtime::{Perquintill, Perbill, FixedPointNumber, traits::Saturating};
 use frame_support::{
 	parameter_types, traits::{Currency},
diff --git a/polkadot/runtime/common/src/parachains.rs b/polkadot/runtime/common/src/parachains.rs
index 25d93b6fde78e99e36b4c461bc9feb6eabcc667b..b0228a5a53c8b426793d2018cbc96349ad649940 100644
--- a/polkadot/runtime/common/src/parachains.rs
+++ b/polkadot/runtime/common/src/parachains.rs
@@ -37,16 +37,13 @@ use frame_support::{
 	dispatch::IsSubType,
 	weights::{DispatchClass, Weight},
 };
-use primitives::{
-	Balance,
-	BlockNumber,
-	parachain::{
-		Id as ParaId, Chain, DutyRoster, AttestedCandidate, CompactStatement as Statement, ParachainDispatchOrigin,
-		UpwardMessage, ValidatorId, ActiveParas, CollatorId, Retriable, OmittedValidationData,
-		CandidateReceipt, GlobalValidationSchedule, AbridgedCandidateReceipt,
-		LocalValidationData, Scheduling, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
-		ValidatorSignature, SigningContext, HeadData, ValidationCode,
-	},
+use primitives::v0::{
+	Balance, BlockNumber,
+	Id as ParaId, Chain, DutyRoster, AttestedCandidate, CompactStatement as Statement, ParachainDispatchOrigin,
+	UpwardMessage, ValidatorId, ActiveParas, CollatorId, Retriable, OmittedValidationData,
+	CandidateReceipt, GlobalValidationSchedule, AbridgedCandidateReceipt,
+	LocalValidationData, Scheduling, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
+	ValidatorSignature, SigningContext, HeadData, ValidationCode,
 	Remark, DownwardMessage
 };
 use frame_support::{
@@ -329,7 +326,7 @@ pub trait Trait: CreateSignedTransaction<Call<Self>> + attestations::Trait + ses
 	>;
 
 	/// A type that converts the opaque hash type to exact one.
-	type BlockHashConversion: Convert<Self::Hash, primitives::Hash>;
+	type BlockHashConversion: Convert<Self::Hash, primitives::v0::Hash>;
 }
 
 /// Origin for the parachains module.
@@ -1681,13 +1678,10 @@ mod tests {
 		},
 		testing::TestXt,
 	};
-	use primitives::{
-		parachain::{
-			CandidateReceipt, ValidityAttestation, ValidatorId, Info as ParaInfo,
-			Scheduling, CandidateCommitments,
-		},
-		BlockNumber,
-		Header,
+	use primitives::v0::{
+		CandidateReceipt, ValidityAttestation, ValidatorId, Info as ParaInfo,
+		Scheduling, CandidateCommitments,
+		BlockNumber, Header,
 	};
 	use keyring::Sr25519Keyring;
 	use frame_support::{
@@ -1819,7 +1813,7 @@ mod tests {
 	}
 
 	mod time {
-		use primitives::{Moment, BlockNumber};
+		use primitives::v0::{Moment, BlockNumber};
 		pub const MILLISECS_PER_BLOCK: Moment = 6000;
 		pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * HOURS;
 		// These time units are defined in number of blocks.
@@ -2246,7 +2240,7 @@ mod tests {
 			println!("session index {}", i);
 			Staking::on_finalize(System::block_number());
 			System::set_block_number((i + 1).into());
-			Timestamp::set_timestamp(System::block_number() as primitives::Moment * 6000);
+			Timestamp::set_timestamp(System::block_number() as primitives::v0::Moment * 6000);
 
 			// In order to be able to use `System::parent_hash()` in the tests
 			// we need to first get it via `System::finalize` and then set it
diff --git a/polkadot/runtime/common/src/registrar.rs b/polkadot/runtime/common/src/registrar.rs
index de152d9379b530924f0fbeceb60cf1340abfeecf..d7b9cb40caf9c7a1edee3f58d498a1b965b3d6f8 100644
--- a/polkadot/runtime/common/src/registrar.rs
+++ b/polkadot/runtime/common/src/registrar.rs
@@ -34,7 +34,7 @@ use frame_support::{
 	weights::{DispatchClass, Weight},
 };
 use system::{self, ensure_root, ensure_signed};
-use primitives::parachain::{
+use primitives::v0::{
 	Id as ParaId, CollatorId, Scheduling, LOWEST_USER_ID, SwapAux, Info as ParaInfo, ActiveParas,
 	Retriable, ValidationCode, HeadData,
 };
@@ -213,7 +213,7 @@ fn build<T: Trait>(config: &GenesisConfig<T>) {
 	Parachains::put(&only_ids);
 
 	for (id, code, genesis) in p {
-		Paras::insert(id, &primitives::parachain::PARACHAIN_INFO);
+		Paras::insert(id, &primitives::v0::PARACHAIN_INFO);
 		// no ingress -- a chain cannot be routed to until it is live.
 		<parachains::Code>::insert(&id, &code);
 		<parachains::Heads>::insert(&id, &genesis);
@@ -670,12 +670,10 @@ mod tests {
 			AccountIdConversion, Extrinsic as ExtrinsicT,
 		}, testing::{UintAuthorityId, TestXt}, KeyTypeId, Perbill, curve::PiecewiseLinear,
 	};
-	use primitives::{
-		parachain::{
-			ValidatorId, Info as ParaInfo, Scheduling, LOWEST_USER_ID, AttestedCandidate,
-			CandidateReceipt, HeadData, ValidityAttestation, CompactStatement as Statement, Chain,
-			CollatorPair, CandidateCommitments,
-		},
+	use primitives::v0::{
+		ValidatorId, Info as ParaInfo, Scheduling, LOWEST_USER_ID, AttestedCandidate,
+		CandidateReceipt, HeadData, ValidityAttestation, CompactStatement as Statement, Chain,
+		CollatorPair, CandidateCommitments,
 		Balance, BlockNumber, Header, Signature,
 	};
 	use frame_support::{
@@ -869,7 +867,7 @@ mod tests {
 	// This is needed for a custom `AccountId` type which is `u64` in testing here.
 	pub mod test_keys {
 		use sp_core::{crypto::KeyTypeId, sr25519};
-		use primitives::Signature;
+		use primitives::v0::Signature;
 
 		pub const KEY_TYPE: KeyTypeId = KeyTypeId(*b"test");
 
diff --git a/polkadot/runtime/common/src/slots.rs b/polkadot/runtime/common/src/slots.rs
index 5618a680c5a0ab06982d8b653e8a4d7525a60fec..eb0a7aff7d72e80bb05b162df1bbb81a31d589cf 100644
--- a/polkadot/runtime/common/src/slots.rs
+++ b/polkadot/runtime/common/src/slots.rs
@@ -28,7 +28,7 @@ use frame_support::{
 	traits::{Currency, ReservableCurrency, WithdrawReason, ExistenceRequirement, Get, Randomness},
 	weights::{DispatchClass, Weight},
 };
-use primitives::parachain::{
+use primitives::v0::{
 	SwapAux, PARACHAIN_INFO, Id as ParaId, ValidationCode, HeadData,
 };
 use system::{ensure_signed, ensure_root};
@@ -890,8 +890,7 @@ mod tests {
 		traits::{OnInitialize, OnFinalize}
 	};
 	use balances;
-	use primitives::{BlockNumber, Header};
-	use primitives::parachain::{Id as ParaId, Info as ParaInfo, Scheduling};
+	use primitives::v0::{BlockNumber, Header, Id as ParaId, Info as ParaInfo, Scheduling};
 
 	impl_outer_origin! {
 		pub enum Origin for Test {}
diff --git a/polkadot/runtime/kusama/src/constants.rs b/polkadot/runtime/kusama/src/constants.rs
index e06325d1bb95eca4ecbbfd6736fc161a2e603601..560d83347d9bf85accbc9c364986fa930feef7be 100644
--- a/polkadot/runtime/kusama/src/constants.rs
+++ b/polkadot/runtime/kusama/src/constants.rs
@@ -16,7 +16,7 @@
 
 /// Money matters.
 pub mod currency {
-	use primitives::Balance;
+	use primitives::v0::Balance;
 
 	pub const DOTS: Balance = 1_000_000_000_000;
 	pub const DOLLARS: Balance = DOTS / 6;
@@ -30,7 +30,7 @@ pub mod currency {
 
 /// Time and blocks.
 pub mod time {
-	use primitives::{Moment, BlockNumber};
+	use primitives::v0::{Moment, BlockNumber};
 	// Kusama & mainnet
 	pub const MILLISECS_PER_BLOCK: Moment = 6000;
 	// Testnet
@@ -55,7 +55,7 @@ pub mod time {
 /// Fee-related.
 pub mod fee {
 	pub use sp_runtime::Perbill;
-	use primitives::Balance;
+	use primitives::v0::Balance;
 	use runtime_common::ExtrinsicBaseWeight;
 	use frame_support::weights::{
 		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients,
diff --git a/polkadot/runtime/kusama/src/lib.rs b/polkadot/runtime/kusama/src/lib.rs
index ee25e8961decc88f231617029365afeb84011d8d..569d055ccafe8d1795b7818cdfdc416da84f1611 100644
--- a/polkadot/runtime/kusama/src/lib.rs
+++ b/polkadot/runtime/kusama/src/lib.rs
@@ -23,9 +23,10 @@
 use sp_std::prelude::*;
 use sp_core::u32_trait::{_1, _2, _3, _4, _5};
 use codec::{Encode, Decode};
-use primitives::{
+use primitives::v0::{
+	self as parachain,
 	AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
-	parachain::{self, ActiveParas, AbridgedCandidateReceipt, SigningContext},
+	ActiveParas, AbridgedCandidateReceipt, SigningContext,
 };
 use runtime_common::{
 	attestations, claims, parachains, registrar, slots, SlowAdjustingFeeUpdate,
@@ -560,7 +561,7 @@ impl grandpa::Trait for Runtime {
 
 	type HandleEquivocation = grandpa::EquivocationHandler<
 		Self::KeyOwnerIdentification,
-		primitives::fisherman::FishermanAppCrypto,
+		primitives::v0::fisherman::FishermanAppCrypto,
 		Runtime,
 		Offences,
 	>;
@@ -596,7 +597,7 @@ parameter_types! {
 }
 
 impl parachains::Trait for Runtime {
-	type AuthorityId = primitives::fisherman::FishermanAppCrypto;
+	type AuthorityId = primitives::v0::fisherman::FishermanAppCrypto;
 	type Origin = Origin;
 	type Call = Call;
 	type ParachainCurrency = Balances;
@@ -939,7 +940,7 @@ impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
 construct_runtime! {
 	pub enum Runtime where
 		Block = Block,
-		NodeBlock = primitives::Block,
+		NodeBlock = primitives::v0::Block,
 		UncheckedExtrinsic = UncheckedExtrinsic
 	{
 		// Basic stuff; balances is uncallable initially.
@@ -1147,7 +1148,7 @@ sp_api::impl_runtime_apis! {
 		fn signing_context() -> SigningContext {
 			Parachains::signing_context()
 		}
-		fn downward_messages(id: parachain::Id) -> Vec<primitives::DownwardMessage> {
+		fn downward_messages(id: parachain::Id) -> Vec<primitives::v0::DownwardMessage> {
 			Parachains::downward_messages(id)
 		}
 	}
diff --git a/polkadot/runtime/parachains/src/configuration.rs b/polkadot/runtime/parachains/src/configuration.rs
index 792dfe89a7b2d0ea85140e67e63b969de7f0ca36..40688041b265de8d1f24456e16606c2e499b44a2 100644
--- a/polkadot/runtime/parachains/src/configuration.rs
+++ b/polkadot/runtime/parachains/src/configuration.rs
@@ -19,9 +19,7 @@
 //! Configuration can change only at session boundaries and is buffered until then.
 
 use sp_std::prelude::*;
-use primitives::{
-	parachain::{ValidatorId},
-};
+use primitives::v1::ValidatorId;
 use frame_support::{
 	decl_storage, decl_module, decl_error,
 	dispatch::DispatchResult,
diff --git a/polkadot/runtime/parachains/src/inclusion.rs b/polkadot/runtime/parachains/src/inclusion.rs
index 33a5e2d1e919483ad8ef0eb728410195aa3c8dd9..a2480f1c80345dff98d9f189d76de73dbe1fa33e 100644
--- a/polkadot/runtime/parachains/src/inclusion.rs
+++ b/polkadot/runtime/parachains/src/inclusion.rs
@@ -21,12 +21,10 @@
 //! to included.
 
 use sp_std::prelude::*;
-use primitives::{
-	parachain::{
-		ValidatorId, AbridgedCandidateReceipt, ValidatorIndex, Id as ParaId,
-		AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
-		BackedCandidate, CoreIndex, GroupIndex, CoreAssignment,
-	},
+use primitives::v1::{
+	ValidatorId, CommittedCandidateReceipt, ValidatorIndex, Id as ParaId,
+	AvailabilityBitfield as AvailabilityBitfield, SignedAvailabilityBitfields, SigningContext,
+	BackedCandidate, CoreIndex, GroupIndex, CoreAssignment,
 };
 use frame_support::{
 	decl_storage, decl_module, decl_error, ensure, dispatch::DispatchResult, IterableStorageMap,
@@ -53,13 +51,15 @@ pub struct AvailabilityBitfieldRecord<N> {
 }
 
 /// A backed candidate pending availability.
+// TODO: split this type and change this to hold a plain `CandidateReceipt`.
+// https://github.com/paritytech/polkadot/issues/1357
 #[derive(Encode, Decode, PartialEq)]
 #[cfg_attr(test, derive(Debug))]
 pub struct CandidatePendingAvailability<H, N> {
 	/// The availability core this is assigned to.
 	core: CoreIndex,
 	/// The candidate receipt itself.
-	receipt: AbridgedCandidateReceipt<H>,
+	receipt: CommittedCandidateReceipt<H>,
 	/// The received availability votes. One bit per validator.
 	availability_votes: BitVec<BitOrderLsb0, u8>,
 	/// The block number of the relay-parent of the receipt.
@@ -213,7 +213,10 @@ impl<T: Trait> Module<T> {
 
 				let validator_public = &validators[signed_bitfield.validator_index() as usize];
 
-				signed_bitfield.check_signature(&signing_context, validator_public).map_err(|_| Error::<T>::InvalidBitfieldSignature)?;
+				signed_bitfield.check_signature(
+					&signing_context,
+					validator_public,
+				).map_err(|_| Error::<T>::InvalidBitfieldSignature)?;
 
 				last_index = Some(signed_bitfield.validator_index());
 			}
@@ -331,11 +334,11 @@ impl<T: Trait> Module<T> {
 			// list.
 			'a:
 			for candidate in &candidates {
-				let para_id = candidate.candidate.parachain_index;
+				let para_id = candidate.descriptor().para_id;
 
 				// we require that the candidate is in the context of the parent block.
 				ensure!(
-					candidate.candidate.relay_parent == parent_hash,
+					candidate.descriptor().relay_parent == parent_hash,
 					Error::<T>::CandidateNotInParentContext,
 				);
 
@@ -348,17 +351,17 @@ impl<T: Trait> Module<T> {
 
 				ensure!(code_upgrade_allowed, Error::<T>::PrematureCodeUpgrade);
 				ensure!(
-					candidate.candidate.check_signature().is_ok(),
+					candidate.descriptor().check_collator_signature().is_ok(),
 					Error::<T>::NotCollatorSigned,
 				);
 
 				for (i, assignment) in scheduled[skip..].iter().enumerate() {
 					check_assignment_in_order(assignment)?;
 
-					if candidate.candidate.parachain_index == assignment.para_id {
+					if candidate.descriptor().para_id == assignment.para_id {
 						if let Some(required_collator) = assignment.required_collator() {
 							ensure!(
-								required_collator == &candidate.candidate.collator,
+								required_collator == &candidate.descriptor().collator,
 								Error::<T>::WrongCollator,
 							);
 						}
@@ -377,7 +380,7 @@ impl<T: Trait> Module<T> {
 						// check the signatures in the backing and that it is a majority.
 						{
 							let maybe_amount_validated
-								= primitives::parachain::check_candidate_backing(
+								= primitives::v1::check_candidate_backing(
 									&candidate,
 									&signing_context,
 									group_vals.len(),
@@ -419,7 +422,7 @@ impl<T: Trait> Module<T> {
 
 		// one more sweep for actually writing to storage.
 		for (candidate, core) in candidates.into_iter().zip(core_indices.iter().cloned()) {
-			let para_id = candidate.candidate.parachain_index;
+			let para_id = candidate.descriptor().para_id;
 
 			// initialize all availability votes to 0.
 			let availability_votes: BitVec<BitOrderLsb0, u8>
@@ -438,7 +441,7 @@ impl<T: Trait> Module<T> {
 
 	fn enact_candidate(
 		relay_parent_number: T::BlockNumber,
-		receipt: AbridgedCandidateReceipt<T::Hash>,
+		receipt: CommittedCandidateReceipt<T::Hash>,
 	) -> Weight {
 		let commitments = receipt.commitments;
 		let config = <configuration::Module<T>>::config();
@@ -447,15 +450,15 @@ impl<T: Trait> Module<T> {
 		let mut weight = T::DbWeight::get().reads_writes(1, 0);
 		if let Some(new_code) = commitments.new_validation_code {
 			weight += <paras::Module<T>>::schedule_code_upgrade(
-				receipt.parachain_index,
+				receipt.descriptor.para_id,
 				new_code,
 				relay_parent_number + config.validation_upgrade_delay,
 			);
 		}
 
 		weight + <paras::Module<T>>::note_new_head(
-			receipt.parachain_index,
-			receipt.head_data,
+			receipt.descriptor.para_id,
+			commitments.head_data,
 			relay_parent_number,
 		)
 	}
@@ -495,10 +498,11 @@ const fn availability_threshold(n_validators: usize) -> usize {
 mod tests {
 	use super::*;
 
-	use primitives::{BlockNumber, Hash};
-	use primitives::parachain::{
+	use primitives::v1::{BlockNumber, Hash};
+	use primitives::v1::{
 		SignedAvailabilityBitfield, CompactStatement as Statement, ValidityAttestation, CollatorId,
-		CandidateCommitments, SignedStatement, AssignmentKind,
+		CandidateCommitments, SignedStatement, CandidateDescriptor, HeadData, ValidationCode,
+		AssignmentKind,
 	};
 	use frame_support::traits::{OnFinalize, OnInitialize};
 	use keyring::Sr25519Keyring;
@@ -545,22 +549,22 @@ mod tests {
 
 	fn collator_sign_candidate(
 		collator: Sr25519Keyring,
-		candidate: &mut AbridgedCandidateReceipt,
+		candidate: &mut CommittedCandidateReceipt,
 	) {
-		candidate.collator = collator.public().into();
+		candidate.descriptor.collator = collator.public().into();
 
-		let payload = primitives::parachain::collator_signature_payload(
-			&candidate.relay_parent,
-			&candidate.parachain_index,
-			&candidate.pov_block_hash,
+		let payload = primitives::v1::collator_signature_payload(
+			&candidate.descriptor.relay_parent,
+			&candidate.descriptor.para_id,
+			&candidate.descriptor.pov_hash,
 		);
 
-		candidate.signature = collator.sign(&payload[..]).into();
-		assert!(candidate.check_signature().is_ok());
+		candidate.descriptor.signature = collator.sign(&payload[..]).into();
+		assert!(candidate.descriptor().check_collator_signature().is_ok());
 	}
 
 	fn back_candidate(
-		candidate: AbridgedCandidateReceipt,
+		candidate: CommittedCandidateReceipt,
 		validators: &[Sr25519Keyring],
 		group: &[ValidatorIndex],
 		signing_context: &SigningContext,
@@ -603,7 +607,7 @@ mod tests {
 			BackingKind::Lacking => false,
 		};
 
-		let successfully_backed = primitives::parachain::check_candidate_backing(
+		let successfully_backed = primitives::v1::check_candidate_backing(
 			&backed,
 			signing_context,
 			group.len(),
@@ -674,6 +678,33 @@ mod tests {
 		)
 	}
 
+	#[derive(Default)]
+	struct TestCandidateBuilder {
+		para_id: ParaId,
+		head_data: HeadData,
+		pov_hash: Hash,
+		relay_parent: Hash,
+		new_validation_code: Option<ValidationCode>,
+	}
+
+	impl TestCandidateBuilder {
+		fn build(self) -> CommittedCandidateReceipt {
+			CommittedCandidateReceipt {
+				descriptor: CandidateDescriptor {
+					para_id: self.para_id,
+					pov_hash: self.pov_hash,
+					relay_parent: self.relay_parent,
+					..Default::default()
+				},
+				commitments: CandidateCommitments {
+					head_data: self.head_data,
+					new_validation_code: self.new_validation_code,
+					..Default::default()
+				},
+			}
+		}
+	}
+
 	#[test]
 	fn collect_pending_cleans_up_pending() {
 		let chain_a = ParaId::from(1);
@@ -895,11 +926,11 @@ mod tests {
 
 			<PendingAvailability<Test>>::insert(chain_a, CandidatePendingAvailability {
 				core: CoreIndex::from(0),
-				receipt: AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				receipt: TestCandidateBuilder {
+					para_id: chain_a,
 					head_data: vec![1, 2, 3, 4].into(),
 					..Default::default()
-				},
+				}.build(),
 				availability_votes: default_availability_votes(),
 				relay_parent_number: 0,
 				backed_in_number: 0,
@@ -907,11 +938,11 @@ mod tests {
 
 			<PendingAvailability<Test>>::insert(chain_b, CandidatePendingAvailability {
 				core: CoreIndex::from(1),
-				receipt: AbridgedCandidateReceipt {
-					parachain_index: chain_b,
+				receipt: TestCandidateBuilder {
+					para_id: chain_b,
 					head_data: vec![5, 6, 7, 8].into(),
 					..Default::default()
-				},
+				}.build(),
 				availability_votes: default_availability_votes(),
 				relay_parent_number: 0,
 				backed_in_number: 0,
@@ -1043,12 +1074,12 @@ mod tests {
 
 			// unscheduled candidate.
 			{
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: chain_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
+				}.build();
 				collator_sign_candidate(
 					Sr25519Keyring::One,
 					&mut candidate,
@@ -1071,18 +1102,18 @@ mod tests {
 
 			// candidates out of order.
 			{
-				let mut candidate_a = AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				let mut candidate_a = TestCandidateBuilder {
+					para_id: chain_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
-				let mut candidate_b = AbridgedCandidateReceipt {
-					parachain_index: chain_b,
+				}.build();
+				let mut candidate_b = TestCandidateBuilder {
+					para_id: chain_b,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([2; 32]),
+					pov_hash: Hash::from([2; 32]),
 					..Default::default()
-				};
+				}.build();
 
 				collator_sign_candidate(
 					Sr25519Keyring::One,
@@ -1119,12 +1150,12 @@ mod tests {
 
 			// candidate not backed.
 			{
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: chain_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
+				}.build();
 				collator_sign_candidate(
 					Sr25519Keyring::One,
 					&mut candidate,
@@ -1150,12 +1181,12 @@ mod tests {
 				let wrong_parent_hash = Hash::from([222; 32]);
 				assert!(System::parent_hash() != wrong_parent_hash);
 
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: chain_a,
 					relay_parent: wrong_parent_hash,
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
+				}.build();
 				collator_sign_candidate(
 					Sr25519Keyring::One,
 					&mut candidate,
@@ -1178,12 +1209,12 @@ mod tests {
 
 			// candidate has wrong collator.
 			{
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: thread_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: thread_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
+				}.build();
 
 				assert!(CollatorId::from(Sr25519Keyring::One.public()) != thread_collator);
 				collator_sign_candidate(
@@ -1212,12 +1243,12 @@ mod tests {
 
 			// candidate not well-signed by collator.
 			{
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: thread_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: thread_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
+				}.build();
 
 				assert_eq!(CollatorId::from(Sr25519Keyring::Two.public()), thread_collator);
 				collator_sign_candidate(
@@ -1225,7 +1256,8 @@ mod tests {
 					&mut candidate,
 				);
 
-				candidate.pov_block_hash = Hash::from([2; 32]);
+				// change the candidate after signing.
+				candidate.descriptor.pov_hash = Hash::from([2; 32]);
 
 				let backed = back_candidate(
 					candidate,
@@ -1244,12 +1276,12 @@ mod tests {
 
 			// para occupied - reject.
 			{
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: chain_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
+					pov_hash: Hash::from([1; 32]),
 					..Default::default()
-				};
+				}.build();
 
 				collator_sign_candidate(
 					Sr25519Keyring::One,
@@ -1283,16 +1315,13 @@ mod tests {
 
 			// interfering code upgrade - reject
 			{
-				let mut candidate = AbridgedCandidateReceipt {
-					parachain_index: chain_a,
+				let mut candidate = TestCandidateBuilder {
+					para_id: chain_a,
 					relay_parent: System::parent_hash(),
-					pov_block_hash: Hash::from([1; 32]),
-					commitments: CandidateCommitments {
-						new_validation_code: Some(vec![5, 6, 7, 8].into()),
-						..Default::default()
-					},
+					pov_hash: Hash::from([1; 32]),
+					new_validation_code: Some(vec![5, 6, 7, 8].into()),
 					..Default::default()
-				};
+				}.build();
 
 				collator_sign_candidate(
 					Sr25519Keyring::One,
@@ -1381,34 +1410,34 @@ mod tests {
 				group_idx: GroupIndex::from(2),
 			};
 
-			let mut candidate_a = AbridgedCandidateReceipt {
-				parachain_index: chain_a,
+			let mut candidate_a = TestCandidateBuilder {
+				para_id: chain_a,
 				relay_parent: System::parent_hash(),
-				pov_block_hash: Hash::from([1; 32]),
+				pov_hash: Hash::from([1; 32]),
 				..Default::default()
-			};
+			}.build();
 			collator_sign_candidate(
 				Sr25519Keyring::One,
 				&mut candidate_a,
 			);
 
-			let mut candidate_b = AbridgedCandidateReceipt {
-				parachain_index: chain_b,
+			let mut candidate_b = TestCandidateBuilder {
+				para_id: chain_b,
 				relay_parent: System::parent_hash(),
-				pov_block_hash: Hash::from([2; 32]),
+				pov_hash: Hash::from([2; 32]),
 				..Default::default()
-			};
+			}.build();
 			collator_sign_candidate(
 				Sr25519Keyring::One,
 				&mut candidate_b,
 			);
 
-			let mut candidate_c = AbridgedCandidateReceipt {
-				parachain_index: thread_a,
+			let mut candidate_c = TestCandidateBuilder {
+				para_id: thread_a,
 				relay_parent: System::parent_hash(),
-				pov_block_hash: Hash::from([3; 32]),
+				pov_hash: Hash::from([3; 32]),
 				..Default::default()
-			};
+			}.build();
 			collator_sign_candidate(
 				Sr25519Keyring::Two,
 				&mut candidate_c,
diff --git a/polkadot/runtime/parachains/src/inclusion_inherent.rs b/polkadot/runtime/parachains/src/inclusion_inherent.rs
index 282b6f3b8a21b6dd898fcd49e75b51cf7f442c1d..6d06961b461a16dfdc8c73cc893d66e1abac8c7c 100644
--- a/polkadot/runtime/parachains/src/inclusion_inherent.rs
+++ b/polkadot/runtime/parachains/src/inclusion_inherent.rs
@@ -22,9 +22,8 @@
 //! this module.
 
 use sp_std::prelude::*;
-use primitives::{
-	inclusion_inherent,
-	parachain::{BackedCandidate, SignedAvailabilityBitfields},
+use primitives::v1::{
+	BackedCandidate, SignedAvailabilityBitfields, INCLUSION_INHERENT_IDENTIFIER,
 };
 use frame_support::{
 	decl_error, decl_module, decl_storage, ensure,
@@ -127,7 +126,7 @@ decl_module! {
 impl<T: Trait> ProvideInherent for Module<T> {
 	type Call = Call<T>;
 	type Error = MakeFatalError<()>;
-	const INHERENT_IDENTIFIER: InherentIdentifier = inclusion_inherent::INHERENT_IDENTIFIER;
+	const INHERENT_IDENTIFIER: InherentIdentifier = INCLUSION_INHERENT_IDENTIFIER;
 
 	fn create_inherent(data: &InherentData) -> Option<Self::Call> {
 		data.get_data(&Self::INHERENT_IDENTIFIER)
diff --git a/polkadot/runtime/parachains/src/initializer.rs b/polkadot/runtime/parachains/src/initializer.rs
index 9c0cda29697a5c401a12e923aaf0334fe6bf6e41..0c4f83cccea10db2c8436146f4199168f6364a4d 100644
--- a/polkadot/runtime/parachains/src/initializer.rs
+++ b/polkadot/runtime/parachains/src/initializer.rs
@@ -21,9 +21,7 @@
 
 use sp_std::prelude::*;
 use frame_support::weights::Weight;
-use primitives::{
-	parachain::{ValidatorId},
-};
+use primitives::v1::ValidatorId;
 use frame_support::{
 	decl_storage, decl_module, decl_error, traits::Randomness,
 };
diff --git a/polkadot/runtime/parachains/src/mock.rs b/polkadot/runtime/parachains/src/mock.rs
index 9cc9f2329b8f1e28240236b1739f4e349860a172..8eb45359da4870be25a58ccba94f77911c637d19 100644
--- a/polkadot/runtime/parachains/src/mock.rs
+++ b/polkadot/runtime/parachains/src/mock.rs
@@ -24,10 +24,7 @@ use sp_runtime::{
 		BlakeTwo256, IdentityLookup,
 	},
 };
-use primitives::{
-	BlockNumber,
-	Header,
-};
+use primitives::v1::{BlockNumber, Header};
 use frame_support::{
 	impl_outer_origin, impl_outer_dispatch, parameter_types,
 	weights::Weight, traits::Randomness as RandomnessT,
diff --git a/polkadot/runtime/parachains/src/paras.rs b/polkadot/runtime/parachains/src/paras.rs
index 8c095751b3f6766a673ce43a99359fd662ec602d..0117089f11063b3c7650e664c3f36663b11413ad 100644
--- a/polkadot/runtime/parachains/src/paras.rs
+++ b/polkadot/runtime/parachains/src/paras.rs
@@ -26,8 +26,8 @@
 use sp_std::prelude::*;
 use sp_std::marker::PhantomData;
 use sp_runtime::traits::One;
-use primitives::{
-	parachain::{Id as ParaId, ValidationCode, HeadData},
+use primitives::v1::{
+	Id as ParaId, ValidationCode, HeadData,
 };
 use frame_support::{
 	decl_storage, decl_module, decl_error,
@@ -541,7 +541,7 @@ impl<T: Trait> Module<T> {
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use primitives::BlockNumber;
+	use primitives::v1::BlockNumber;
 	use frame_support::traits::{OnFinalize, OnInitialize};
 
 	use crate::mock::{new_test_ext, Paras, System, GenesisConfig as MockGenesisConfig};
diff --git a/polkadot/runtime/parachains/src/scheduler.rs b/polkadot/runtime/parachains/src/scheduler.rs
index 772ab25cf4fd8793a725dfdb31a95805e043d8c1..9cc2bd72bd810c4463be1b3c49ee15141c8b3e91 100644
--- a/polkadot/runtime/parachains/src/scheduler.rs
+++ b/polkadot/runtime/parachains/src/scheduler.rs
@@ -37,11 +37,9 @@
 
 use sp_std::prelude::*;
 use sp_std::convert::TryInto;
-use primitives::{
-	parachain::{
-		Id as ParaId, ValidatorIndex, CoreAssignment, CoreOccupied, CoreIndex, AssignmentKind,
-		GroupIndex, ParathreadClaim, ParathreadEntry,
-	},
+use primitives::v1::{
+	Id as ParaId, ValidatorIndex, CoreAssignment, CoreOccupied, CoreIndex, AssignmentKind,
+	GroupIndex, ParathreadClaim, ParathreadEntry,
 };
 use frame_support::{
 	decl_storage, decl_module, decl_error,
@@ -586,7 +584,7 @@ impl<T: Trait> Module<T> {
 mod tests {
 	use super::*;
 
-	use primitives::{BlockNumber, parachain::{CollatorId, ValidatorId}};
+	use primitives::v1::{BlockNumber, ValidatorId, CollatorId};
 	use frame_support::traits::{OnFinalize, OnInitialize};
 	use keyring::Sr25519Keyring;
 
diff --git a/polkadot/runtime/polkadot/src/constants.rs b/polkadot/runtime/polkadot/src/constants.rs
index 331d97f364cf52ac7597c571d5f7e93ba661c0c1..8ad5478bcab89af3638439ace72aebc7b1b5695f 100644
--- a/polkadot/runtime/polkadot/src/constants.rs
+++ b/polkadot/runtime/polkadot/src/constants.rs
@@ -16,7 +16,7 @@
 
 /// Money matters.
 pub mod currency {
-	use primitives::Balance;
+	use primitives::v0::Balance;
 
 	pub const DOTS: Balance = 1_000_000_000_000;
 	pub const DOLLARS: Balance = DOTS / 100;       // 10_000_000_000
@@ -30,7 +30,7 @@ pub mod currency {
 
 /// Time and blocks.
 pub mod time {
-	use primitives::{Moment, BlockNumber};
+	use primitives::v0::{Moment, BlockNumber};
 	pub const MILLISECS_PER_BLOCK: Moment = 6000;
 	pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK;
 	pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 4 * HOURS;
@@ -47,7 +47,7 @@ pub mod time {
 /// Fee-related.
 pub mod fee {
 	pub use sp_runtime::Perbill;
-	use primitives::Balance;
+	use primitives::v0::Balance;
 	use runtime_common::ExtrinsicBaseWeight;
 	use frame_support::weights::{
 		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients,
diff --git a/polkadot/runtime/polkadot/src/lib.rs b/polkadot/runtime/polkadot/src/lib.rs
index abd9687164c23e74de0f5e71bbe9c57627155e8f..258a7b4781b4ce8abc50223b8921464372265fc3 100644
--- a/polkadot/runtime/polkadot/src/lib.rs
+++ b/polkadot/runtime/polkadot/src/lib.rs
@@ -31,9 +31,10 @@ use runtime_common::{
 use sp_std::prelude::*;
 use sp_core::u32_trait::{_1, _2, _3, _4, _5};
 use codec::{Encode, Decode};
-use primitives::{
+use primitives::v0::{
+	self as parachain,
 	AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
-	parachain::{self, ActiveParas, AbridgedCandidateReceipt, SigningContext},
+	ActiveParas, AbridgedCandidateReceipt, SigningContext,
 };
 use sp_runtime::{
 	create_runtime_str, generic, impl_opaque_keys, ModuleId,
@@ -629,7 +630,7 @@ impl grandpa::Trait for Runtime {
 
 	type HandleEquivocation = grandpa::EquivocationHandler<
 		Self::KeyOwnerIdentification,
-		primitives::fisherman::FishermanAppCrypto,
+		primitives::v0::fisherman::FishermanAppCrypto,
 		Runtime,
 		Offences,
 	>;
@@ -666,7 +667,7 @@ parameter_types! {
 }
 
 impl parachains::Trait for Runtime {
-	type AuthorityId = primitives::fisherman::FishermanAppCrypto;
+	type AuthorityId = primitives::v0::fisherman::FishermanAppCrypto;
 	type Origin = Origin;
 	type Call = Call;
 	type ParachainCurrency = Balances;
@@ -943,7 +944,7 @@ impl frame_support::traits::OnRuntimeUpgrade for CustomOnRuntimeUpgrade {
 construct_runtime! {
 	pub enum Runtime where
 		Block = Block,
-		NodeBlock = primitives::Block,
+		NodeBlock = primitives::v0::Block,
 		UncheckedExtrinsic = UncheckedExtrinsic
 	{
 		// Basic stuff; balances is uncallable initially.
@@ -1147,7 +1148,7 @@ sp_api::impl_runtime_apis! {
 		fn signing_context() -> SigningContext {
 			Parachains::signing_context()
 		}
-		fn downward_messages(id: parachain::Id) -> Vec<primitives::DownwardMessage> {
+		fn downward_messages(id: parachain::Id) -> Vec<primitives::v0::DownwardMessage> {
 			Parachains::downward_messages(id)
 		}
 	}
diff --git a/polkadot/runtime/polkadot/tests/weights.rs b/polkadot/runtime/polkadot/tests/weights.rs
index 533783a4e4917b9a92a40c6c5550b528c299e78f..3cdb71995801dd57f64ba87707471110c013d05d 100644
--- a/polkadot/runtime/polkadot/tests/weights.rs
+++ b/polkadot/runtime/polkadot/tests/weights.rs
@@ -29,7 +29,7 @@ use frame_support::{
 use keyring::AccountKeyring;
 use polkadot_runtime::constants::currency::*;
 use polkadot_runtime::{self, Runtime};
-use primitives::AccountId;
+use primitives::v0::AccountId;
 use runtime_common::MaximumBlockWeight;
 
 use democracy::Call as DemocracyCall;
diff --git a/polkadot/runtime/test-runtime/client/src/lib.rs b/polkadot/runtime/test-runtime/client/src/lib.rs
index 2554f4f1c8249aaca5627ce88cf9cd6b205250de..58282d32b46b2104eae1b866795dacc9bd7cc158 100644
--- a/polkadot/runtime/test-runtime/client/src/lib.rs
+++ b/polkadot/runtime/test-runtime/client/src/lib.rs
@@ -326,7 +326,7 @@ pub fn new_native_executor() -> sc_executor::NativeExecutor<LocalExecutor> {
 /// The index of the block must be provided to calculate a valid timestamp for the block. The value starts at 0 and
 /// should be incremented by one for every block produced.
 pub fn needed_extrinsics(
-	heads: Vec<polkadot_primitives::parachain::AttestedCandidate>,
+	heads: Vec<polkadot_primitives::v0::AttestedCandidate>,
 	i: u64,
 ) -> Vec<polkadot_test_runtime::UncheckedExtrinsic> {
 	use polkadot_runtime_common::parachains;
diff --git a/polkadot/runtime/test-runtime/src/constants.rs b/polkadot/runtime/test-runtime/src/constants.rs
index b0431e55f26820379765bdad0a89efebf431cf42..ac90417b214c5a987eb18a87faeee39e205e302a 100644
--- a/polkadot/runtime/test-runtime/src/constants.rs
+++ b/polkadot/runtime/test-runtime/src/constants.rs
@@ -16,7 +16,7 @@
 
 /// Money matters.
 pub mod currency {
-	use primitives::Balance;
+	use primitives::v0::Balance;
 
 	pub const DOTS: Balance = 1_000_000_000_000;
 	pub const DOLLARS: Balance = DOTS;
@@ -26,7 +26,7 @@ pub mod currency {
 
 /// Time and blocks.
 pub mod time {
-	use primitives::{Moment, BlockNumber};
+	use primitives::v0::{Moment, BlockNumber};
 	// Testnet
 	pub const MILLISECS_PER_BLOCK: Moment = 1000;
 	pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK;
@@ -45,7 +45,7 @@ pub mod time {
 /// Fee-related.
 pub mod fee {
 	pub use sp_runtime::Perbill;
-	use primitives::Balance;
+	use primitives::v0::Balance;
 	use runtime_common::ExtrinsicBaseWeight;
 	use frame_support::weights::{
 		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients,
diff --git a/polkadot/runtime/test-runtime/src/lib.rs b/polkadot/runtime/test-runtime/src/lib.rs
index 57ceffa4a96f6f4ebf8e6c9053209a55181101dc..45d5a04c313fb3835a139641c0080b1d7d129679 100644
--- a/polkadot/runtime/test-runtime/src/lib.rs
+++ b/polkadot/runtime/test-runtime/src/lib.rs
@@ -22,9 +22,10 @@
 
 use rstd::prelude::*;
 use codec::{Encode, Decode};
-use primitives::{
+use primitives::v0::{
+	self as parachain,
 	AccountId, AccountIndex, Balance, BlockNumber, Hash as HashT, Nonce, Signature, Moment,
-	parachain::{self, ActiveParas, AbridgedCandidateReceipt, SigningContext}, ValidityError,
+	ActiveParas, AbridgedCandidateReceipt, SigningContext, ValidityError,
 };
 use runtime_common::{
 	attestations, claims, parachains, registrar, slots, SlowAdjustingFeeUpdate,
@@ -375,7 +376,7 @@ parameter_types! {
 }
 
 impl parachains::Trait for Runtime {
-	type AuthorityId = primitives::fisherman::FishermanAppCrypto;
+	type AuthorityId = primitives::v0::fisherman::FishermanAppCrypto;
 	type Origin = Origin;
 	type Call = Call;
 	type ParachainCurrency = Balances;
@@ -521,7 +522,7 @@ impl sudo::Trait for Runtime {
 construct_runtime! {
 	pub enum Runtime where
 		Block = Block,
-		NodeBlock = primitives::Block,
+		NodeBlock = primitives::v0::Block,
 		UncheckedExtrinsic = UncheckedExtrinsic
 	{
 		// Basic stuff; balances is uncallable initially.
@@ -702,7 +703,7 @@ sp_api::impl_runtime_apis! {
 		fn signing_context() -> SigningContext {
 			Parachains::signing_context()
 		}
-		fn downward_messages(id: parachain::Id) -> Vec<primitives::DownwardMessage> {
+		fn downward_messages(id: parachain::Id) -> Vec<primitives::v0::DownwardMessage> {
 			Parachains::downward_messages(id)
 		}
 	}
diff --git a/polkadot/runtime/westend/src/constants.rs b/polkadot/runtime/westend/src/constants.rs
index ac25d621d8561d527bf1f595566bb8da571afd91..f59a384fba8b7a75eda91ad01c90ae53dbfcebac 100644
--- a/polkadot/runtime/westend/src/constants.rs
+++ b/polkadot/runtime/westend/src/constants.rs
@@ -16,7 +16,7 @@
 
 /// Money matters.
 pub mod currency {
-	use primitives::Balance;
+	use primitives::v0::Balance;
 
 	pub const DOTS: Balance = 1_000_000_000_000;
 	pub const DOLLARS: Balance = DOTS;
@@ -30,7 +30,7 @@ pub mod currency {
 
 /// Time and blocks.
 pub mod time {
-	use primitives::{Moment, BlockNumber};
+	use primitives::v0::{Moment, BlockNumber};
 	pub const MILLISECS_PER_BLOCK: Moment = 6000;
 	pub const SLOT_DURATION: Moment = MILLISECS_PER_BLOCK;
 	pub const EPOCH_DURATION_IN_BLOCKS: BlockNumber = 1 * HOURS;
@@ -47,7 +47,7 @@ pub mod time {
 /// Fee-related.
 pub mod fee {
 	pub use sp_runtime::Perbill;
-	use primitives::Balance;
+	use primitives::v0::Balance;
 	use runtime_common::ExtrinsicBaseWeight;
 	use frame_support::weights::{
 		WeightToFeePolynomial, WeightToFeeCoefficient, WeightToFeeCoefficients,
diff --git a/polkadot/runtime/westend/src/lib.rs b/polkadot/runtime/westend/src/lib.rs
index 41613bbb011873069c420c7362dabf4cf2011751..a40c4e3dd5a71c32a8ed29361937996c13d53408 100644
--- a/polkadot/runtime/westend/src/lib.rs
+++ b/polkadot/runtime/westend/src/lib.rs
@@ -22,9 +22,10 @@
 
 use sp_std::prelude::*;
 use codec::{Encode, Decode};
-use primitives::{
+use primitives::v0::{
+	self as parachain,
 	AccountId, AccountIndex, Balance, BlockNumber, Hash, Nonce, Signature, Moment,
-	parachain::{self, ActiveParas, AbridgedCandidateReceipt, SigningContext},
+	ActiveParas, AbridgedCandidateReceipt, SigningContext,
 };
 use runtime_common::{
 	attestations, parachains, registrar, SlowAdjustingFeeUpdate,
@@ -385,7 +386,7 @@ impl grandpa::Trait for Runtime {
 
 	type HandleEquivocation = grandpa::EquivocationHandler<
 		Self::KeyOwnerIdentification,
-		primitives::fisherman::FishermanAppCrypto,
+		primitives::v0::fisherman::FishermanAppCrypto,
 		Runtime,
 		Offences,
 	>;
@@ -421,7 +422,7 @@ parameter_types! {
 }
 
 impl parachains::Trait for Runtime {
-	type AuthorityId = primitives::fisherman::FishermanAppCrypto;
+	type AuthorityId = primitives::v0::fisherman::FishermanAppCrypto;
 	type Origin = Origin;
 	type Call = Call;
 	type ParachainCurrency = Balances;
@@ -698,7 +699,7 @@ impl proxy::Trait for Runtime {
 construct_runtime! {
 	pub enum Runtime where
 		Block = Block,
-		NodeBlock = primitives::Block,
+		NodeBlock = primitives::v0::Block,
 		UncheckedExtrinsic = UncheckedExtrinsic
 	{
 		// Basic stuff; balances is uncallable initially.
@@ -887,7 +888,7 @@ sp_api::impl_runtime_apis! {
 		fn signing_context() -> SigningContext {
 			Parachains::signing_context()
 		}
-		fn downward_messages(id: parachain::Id) -> Vec<primitives::DownwardMessage> {
+		fn downward_messages(id: parachain::Id) -> Vec<primitives::v0::DownwardMessage> {
 			Parachains::downward_messages(id)
 		}
 	}
diff --git a/polkadot/service/src/chain_spec.rs b/polkadot/service/src/chain_spec.rs
index 5e1bfbbdbab0c24a926453b793a2d4edbec0b4ae..fe8d98d0553fe58ab4649ff7ed1e7ad46f4732bb 100644
--- a/polkadot/service/src/chain_spec.rs
+++ b/polkadot/service/src/chain_spec.rs
@@ -17,7 +17,7 @@
 //! Polkadot chain configurations.
 
 use sp_core::{Pair, Public, crypto::UncheckedInto, sr25519};
-use polkadot_primitives::{AccountId, AccountPublic, parachain::ValidatorId};
+use polkadot_primitives::v0::{AccountId, AccountPublic, ValidatorId};
 use polkadot_runtime as polkadot;
 use kusama_runtime as kusama;
 use westend_runtime as westend;
@@ -48,9 +48,9 @@ const DEFAULT_PROTOCOL_ID: &str = "dot";
 #[serde(rename_all = "camelCase")]
 pub struct Extensions {
 	/// Block numbers with known hashes.
-	pub fork_blocks: sc_client_api::ForkBlocks<polkadot_primitives::Block>,
+	pub fork_blocks: sc_client_api::ForkBlocks<polkadot_primitives::v0::Block>,
 	/// Known bad block hashes.
-	pub bad_blocks: sc_client_api::BadBlocks<polkadot_primitives::Block>,
+	pub bad_blocks: sc_client_api::BadBlocks<polkadot_primitives::v0::Block>,
 }
 
 /// The `ChainSpec parametrised for polkadot runtime`.
diff --git a/polkadot/service/src/grandpa_support.rs b/polkadot/service/src/grandpa_support.rs
index 794b4e4fc180e8f782a200c8f0feaa4350473e65..89a0691b360d4f2d80529378d31bc50019cf3154 100644
--- a/polkadot/service/src/grandpa_support.rs
+++ b/polkadot/service/src/grandpa_support.rs
@@ -16,7 +16,7 @@
 
 //! Polkadot-specific GRANDPA integration utilities.
 
-use polkadot_primitives::Hash;
+use polkadot_primitives::v0::Hash;
 use sp_runtime::traits::{Block as BlockT, NumberFor};
 
 /// A custom GRANDPA voting rule that "pauses" voting (i.e. keeps voting for the
@@ -98,7 +98,7 @@ impl<Block, B> grandpa::VotingRule<Block, B> for PauseAfterBlockFor<NumberFor<Bl
 /// #1500988).
 pub(crate) fn kusama_hard_forks() -> Vec<(
 	grandpa_primitives::SetId,
-	(Hash, polkadot_primitives::BlockNumber),
+	(Hash, polkadot_primitives::v0::BlockNumber),
 	grandpa_primitives::AuthorityList,
 )> {
 	use sp_core::crypto::Ss58Codec;
diff --git a/polkadot/service/src/lib.rs b/polkadot/service/src/lib.rs
index eaa5f9682f0c4e03fd24ef59d4ef94b3be680f04..d0b443ea7d88c886d5761d334bfefc3ad3f20d9d 100644
--- a/polkadot/service/src/lib.rs
+++ b/polkadot/service/src/lib.rs
@@ -22,7 +22,7 @@ mod client;
 
 use std::sync::Arc;
 use std::time::Duration;
-use polkadot_primitives::{parachain, Hash, BlockId, AccountId, Nonce, Balance};
+use polkadot_primitives::v0::{self as parachain, Hash, BlockId, AccountId, Nonce, Balance};
 #[cfg(feature = "full-node")]
 use polkadot_network::{legacy::gossip::Known, protocol as network_protocol};
 use service::{error::Error as ServiceError, ServiceBuilder};
@@ -42,8 +42,7 @@ pub use sc_consensus::LongestChain;
 pub use sp_api::{Core as CoreApi, ConstructRuntimeApi, ProvideRuntimeApi, StateBackend};
 pub use sp_runtime::traits::{HashFor, NumberFor};
 pub use consensus_common::{SelectChain, BlockImport, block_validation::Chain};
-pub use polkadot_primitives::parachain::{CollatorId, ParachainHost};
-pub use polkadot_primitives::Block;
+pub use polkadot_primitives::v0::{Block, CollatorId, ParachainHost};
 pub use sp_runtime::traits::{Block as BlockT, self as runtime_traits, BlakeTwo256};
 pub use chain_spec::{PolkadotChainSpec, KusamaChainSpec, WestendChainSpec};
 #[cfg(feature = "full-node")]
diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs
index 11c6a3c024787e56f1cc3092889d7801859163e0..cb95d74d62237f48fd38aa25d0cc8bcf3456cda8 100644
--- a/polkadot/statement-table/src/generic.rs
+++ b/polkadot/statement-table/src/generic.rs
@@ -28,7 +28,7 @@ use std::collections::hash_map::{HashMap, Entry};
 use std::hash::Hash;
 use std::fmt::Debug;
 
-use primitives::parachain::{ValidityAttestation as PrimitiveValidityAttestation, ValidatorSignature};
+use primitives::v1::{ValidityAttestation as PrimitiveValidityAttestation, ValidatorSignature};
 
 use codec::{Encode, Decode};
 
diff --git a/polkadot/statement-table/src/lib.rs b/polkadot/statement-table/src/lib.rs
index 97d0cda76344c9a3a14321f4753f426a5252ce25..fed60ded0da2a08a60e82d37ec80c3951e1a810b 100644
--- a/polkadot/statement-table/src/lib.rs
+++ b/polkadot/statement-table/src/lib.rs
@@ -16,75 +16,87 @@
 
 pub mod generic;
 
-pub use generic::Table;
-
-use primitives::parachain::{
-	Id, AbridgedCandidateReceipt, CompactStatement as PrimitiveStatement, ValidatorSignature, ValidatorIndex,
-};
-use primitives::Hash;
-
-/// Statements about candidates on the network.
-pub type Statement = generic::Statement<AbridgedCandidateReceipt, Hash>;
-
-/// Signed statements about candidates.
-pub type SignedStatement = generic::SignedStatement<
-	AbridgedCandidateReceipt,
-	Hash,
-	ValidatorIndex,
-	ValidatorSignature,
->;
-
-/// Kinds of misbehavior, along with proof.
-pub type Misbehavior = generic::Misbehavior<
-	AbridgedCandidateReceipt,
-	Hash,
-	ValidatorIndex,
-	ValidatorSignature,
->;
-
-/// A summary of import of a statement.
-pub type Summary = generic::Summary<Hash, Id>;
-
-/// Context necessary to construct a table.
-pub trait Context {
-	/// Whether a authority is a member of a group.
-	/// Members are meant to submit candidates and vote on validity.
-	fn is_member_of(&self, authority: ValidatorIndex, group: &Id) -> bool;
-
-	/// requisite number of votes for validity from a group.
-	fn requisite_votes(&self, group: &Id) -> usize;
-}
-
-impl<C: Context> generic::Context for C {
-	type AuthorityId = ValidatorIndex;
-	type Digest = Hash;
-	type GroupId = Id;
-	type Signature = ValidatorSignature;
-	type Candidate = AbridgedCandidateReceipt;
-
-	fn candidate_digest(candidate: &AbridgedCandidateReceipt) -> Hash {
-		candidate.hash()
-	}
-
-	fn candidate_group(candidate: &AbridgedCandidateReceipt) -> Id {
-		candidate.parachain_index.clone()
-	}
-
-	fn is_member_of(&self, authority: &Self::AuthorityId, group: &Id) -> bool {
-		Context::is_member_of(self, *authority, group)
-	}
-
-	fn requisite_votes(&self, group: &Id) -> usize {
-		Context::requisite_votes(self, group)
+pub use generic::{Table, Context};
+
+/// Concrete instantiations suitable for v0 primitives.
+pub mod v0 {
+	use crate::generic;
+	use primitives::v0::{
+		Hash,
+		Id, AbridgedCandidateReceipt, CompactStatement as PrimitiveStatement, ValidatorSignature, ValidatorIndex,
+	};
+
+	/// Statements about candidates on the network.
+	pub type Statement = generic::Statement<AbridgedCandidateReceipt, Hash>;
+
+	/// Signed statements about candidates.
+	pub type SignedStatement = generic::SignedStatement<
+		AbridgedCandidateReceipt,
+		Hash,
+		ValidatorIndex,
+		ValidatorSignature,
+	>;
+
+	/// Kinds of misbehavior, along with proof.
+	pub type Misbehavior = generic::Misbehavior<
+		AbridgedCandidateReceipt,
+		Hash,
+		ValidatorIndex,
+		ValidatorSignature,
+	>;
+
+	/// A summary of import of a statement.
+	pub type Summary = generic::Summary<Hash, Id>;
+
+	impl<'a> From<&'a Statement> for PrimitiveStatement {
+		fn from(s: &'a Statement) -> PrimitiveStatement {
+			match *s {
+				generic::Statement::Valid(s) => PrimitiveStatement::Valid(s),
+				generic::Statement::Invalid(s) => PrimitiveStatement::Invalid(s),
+				generic::Statement::Candidate(ref s) => PrimitiveStatement::Candidate(s.hash()),
+			}
+		}
 	}
 }
 
-impl<'a> From<&'a Statement> for PrimitiveStatement {
-	fn from(s: &'a Statement) -> PrimitiveStatement {
-		match *s {
-			generic::Statement::Valid(s) => PrimitiveStatement::Valid(s),
-			generic::Statement::Invalid(s) => PrimitiveStatement::Invalid(s),
-			generic::Statement::Candidate(ref s) => PrimitiveStatement::Candidate(s.hash()),
+/// Concrete instantiations suitable for v1 primitives.
+pub mod v1 {
+	use crate::generic;
+	use primitives::v1::{
+		Hash,
+		Id, CommittedCandidateReceipt, CompactStatement as PrimitiveStatement,
+		ValidatorSignature, ValidatorIndex,
+	};
+
+	/// Statements about candidates on the network.
+	pub type Statement = generic::Statement<CommittedCandidateReceipt, Hash>;
+
+	/// Signed statements about candidates.
+	pub type SignedStatement = generic::SignedStatement<
+		CommittedCandidateReceipt,
+		Hash,
+		ValidatorIndex,
+		ValidatorSignature,
+	>;
+
+	/// Kinds of misbehavior, along with proof.
+	pub type Misbehavior = generic::Misbehavior<
+		CommittedCandidateReceipt,
+		Hash,
+		ValidatorIndex,
+		ValidatorSignature,
+	>;
+
+	/// A summary of import of a statement.
+	pub type Summary = generic::Summary<Hash, Id>;
+
+	impl<'a> From<&'a Statement> for PrimitiveStatement {
+		fn from(s: &'a Statement) -> PrimitiveStatement {
+			match *s {
+				generic::Statement::Valid(s) => PrimitiveStatement::Valid(s),
+				generic::Statement::Invalid(s) => PrimitiveStatement::Invalid(s),
+				generic::Statement::Candidate(ref s) => PrimitiveStatement::Candidate(s.hash()),
+			}
 		}
 	}
 }
diff --git a/polkadot/validation/src/block_production.rs b/polkadot/validation/src/block_production.rs
index 30b7ac3ccd46b979acb9cf91a337a729b10c0334..4804ba230c96d025ef3389c66aed548aa9d3a6e7 100644
--- a/polkadot/validation/src/block_production.rs
+++ b/polkadot/validation/src/block_production.rs
@@ -28,8 +28,8 @@ use std::{
 use sp_blockchain::HeaderBackend;
 use block_builder::{BlockBuilderApi, BlockBuilderProvider};
 use consensus::{Proposal, RecordProof};
-use polkadot_primitives::{Block, Header};
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{Block, Header};
+use polkadot_primitives::v0::{
 	ParachainHost, NEW_HEADS_IDENTIFIER,
 };
 use runtime_primitives::traits::{DigestFor, HashFor};
diff --git a/polkadot/validation/src/collation.rs b/polkadot/validation/src/collation.rs
index a2e682a066d68e07a369bb3aa0660decde88dae3..b79b049b225f37e32a3e2304fe301611369f5e04 100644
--- a/polkadot/validation/src/collation.rs
+++ b/polkadot/validation/src/collation.rs
@@ -21,11 +21,9 @@
 
 use std::sync::Arc;
 
-use polkadot_primitives::{
+use polkadot_primitives::v0::{
 	BlakeTwo256, Block, Hash, HashT,
-	parachain::{
-		CollatorId, ParachainHost, Id as ParaId, Collation, ErasureChunk, CollationInfo,
-	},
+	CollatorId, ParachainHost, Id as ParaId, Collation, ErasureChunk, CollationInfo,
 };
 use polkadot_erasure_coding as erasure;
 use sp_api::ProvideRuntimeApi;
diff --git a/polkadot/validation/src/error.rs b/polkadot/validation/src/error.rs
index 83b51ed23670625ff7589ee4231c8e5f2bbe843e..5fd990a0713327469277910242d7a48c9375a2a4 100644
--- a/polkadot/validation/src/error.rs
+++ b/polkadot/validation/src/error.rs
@@ -16,7 +16,7 @@
 
 //! Errors that can occur during the validation process.
 
-use polkadot_primitives::{parachain::ValidatorId, Hash};
+use polkadot_primitives::v0::{ValidatorId, Hash};
 
 /// Error type for validation
 #[derive(Debug, derive_more::Display, derive_more::From)]
@@ -77,7 +77,7 @@ pub enum Error {
 	CommitmentsMismatch,
 	/// The parachain for which validation work is being done is not active.
 	#[display(fmt = "Parachain {:?} is not active", _0)]
-	InactiveParachain(polkadot_primitives::parachain::Id),
+	InactiveParachain(polkadot_primitives::v0::Id),
 	/// Block data is too big
 	#[display(fmt = "Block data is too big (maximum allowed size: {}, actual size: {})", size, max_size)]
 	BlockDataTooBig { size: u64, max_size: u64 },
diff --git a/polkadot/validation/src/lib.rs b/polkadot/validation/src/lib.rs
index 667f66e275a9d738213d37ef9de68ff135542563..a5b1c1d5c2df349f486efac583bd3f067ac8e5ce 100644
--- a/polkadot/validation/src/lib.rs
+++ b/polkadot/validation/src/lib.rs
@@ -34,7 +34,7 @@ use std::{
 	sync::Arc,
 };
 use codec::Encode;
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{
 	Id as ParaId, Chain, DutyRoster, AbridgedCandidateReceipt,
 	CompactStatement as PrimitiveStatement,
 	PoVBlock, ErasureChunk, ValidatorSignature, ValidatorIndex,
diff --git a/polkadot/validation/src/pipeline.rs b/polkadot/validation/src/pipeline.rs
index b29285716dd36ea5ac587f3143702fd35d8561da..f2a705ba101daf41aa9b59fed9c609a9b3848ed8 100644
--- a/polkadot/validation/src/pipeline.rs
+++ b/polkadot/validation/src/pipeline.rs
@@ -19,12 +19,12 @@
 
 use codec::Encode;
 use polkadot_erasure_coding as erasure;
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{
 	CollationInfo, PoVBlock, LocalValidationData, GlobalValidationSchedule, OmittedValidationData,
 	AvailableData, FeeSchedule, CandidateCommitments, ErasureChunk, ParachainHost,
 	Id as ParaId, AbridgedCandidateReceipt, ValidationCode,
 };
-use polkadot_primitives::{Block, BlockId, Balance, Hash};
+use polkadot_primitives::v0::{Block, BlockId, Balance, Hash};
 use parachain::{
 	wasm_executor::{self, ExecutionMode},
 	primitives::{UpwardMessage, ValidationParams},
@@ -125,7 +125,7 @@ impl<'a> ValidatedCandidate<'a> {
 			omitted_validation,
 		};
 
-		let erasure_chunks = erasure::obtain_chunks(
+		let erasure_chunks = erasure::obtain_chunks_v0(
 			n_validators,
 			&available_data,
 		)?;
diff --git a/polkadot/validation/src/shared_table/includable.rs b/polkadot/validation/src/shared_table/includable.rs
index 1396f66c596724c8ba50e045816a7c55242fc2cc..317b9e0f7bfed87b36a615a9aa01598024526e7c 100644
--- a/polkadot/validation/src/shared_table/includable.rs
+++ b/polkadot/validation/src/shared_table/includable.rs
@@ -18,7 +18,7 @@
 
 use std::collections::HashMap;
 use futures::channel::oneshot;
-use polkadot_primitives::Hash;
+use polkadot_primitives::v0::Hash;
 
 /// Track includability of a set of candidates,
 pub(super) fn track<I: IntoIterator<Item=(Hash, bool)>>(candidates: I)
diff --git a/polkadot/validation/src/shared_table/mod.rs b/polkadot/validation/src/shared_table/mod.rs
index fd6702a7e640c30d7028b25247963e38538ac5c9..d42c9b7e561c1a4c4d8c7732c33b58b7df0fdcad 100644
--- a/polkadot/validation/src/shared_table/mod.rs
+++ b/polkadot/validation/src/shared_table/mod.rs
@@ -21,11 +21,12 @@ use std::collections::hash_map::{HashMap, Entry};
 use std::sync::Arc;
 
 use availability_store::{Store as AvailabilityStore};
-use table::{self, Table, Context as TableContextTrait};
-use polkadot_primitives::{Block, Hash};
-use polkadot_primitives::parachain::{
+use table::{v0 as table_v0, Table, Context as TableContextTrait};
+use polkadot_primitives::v0::{
+	Block, Hash,
 	Id as ParaId, AbridgedCandidateReceipt, ValidatorPair, ValidatorId,
 	AttestedCandidate, ParachainHost, PoVBlock, ValidatorIndex, SigningContext,
+	ValidatorSignature,
 };
 
 use parking_lot::Mutex;
@@ -44,7 +45,7 @@ use crate::Error;
 
 mod includable;
 
-pub use table::{SignedStatement, Statement};
+pub use table_v0::{SignedStatement, Statement};
 pub use table::generic::Statement as GenericStatement;
 
 struct TableContext {
@@ -54,9 +55,23 @@ struct TableContext {
 	validators: Vec<ValidatorId>,
 }
 
-impl table::Context for TableContext {
-	fn is_member_of(&self, authority: ValidatorIndex, group: &ParaId) -> bool {
-		let key = match self.validators.get(authority as usize) {
+impl TableContextTrait for TableContext {
+	type AuthorityId = ValidatorIndex;
+	type Digest = Hash;
+	type GroupId = ParaId;
+	type Signature = ValidatorSignature;
+	type Candidate = AbridgedCandidateReceipt;
+
+	fn candidate_digest(candidate: &AbridgedCandidateReceipt) -> Hash {
+		candidate.hash()
+	}
+
+	fn candidate_group(candidate: &AbridgedCandidateReceipt) -> ParaId {
+		candidate.parachain_index
+	}
+
+	fn is_member_of(&self, authority: &ValidatorIndex, group: &ParaId) -> bool {
+		let key = match self.validators.get(*authority as usize) {
 			Some(val) => val,
 			None => return false,
 		};
@@ -84,7 +99,7 @@ impl TableContext {
 		)
 	}
 
-	fn sign_statement(&self, statement: table::Statement) -> Option<table::SignedStatement> {
+	fn sign_statement(&self, statement: table_v0::Statement) -> Option<table_v0::SignedStatement> {
 		self.local_index().and_then(move |sender|
 			self.key.as_ref()
 				.map(|key| crate::sign_table_statement(
@@ -93,7 +108,7 @@ impl TableContext {
 						&self.signing_context,
 					).into()
 				)
-				.map(move |signature| table::SignedStatement { statement, signature, sender })
+				.map(move |signature| table_v0::SignedStatement { statement, signature, sender })
 		)
 	}
 }
@@ -145,7 +160,7 @@ impl SharedTableInner {
 		&mut self,
 		context: &TableContext,
 		fetch_pov_block: impl Fn(&AbridgedCandidateReceipt) -> Fetch,
-		statement: table::SignedStatement,
+		statement: table_v0::SignedStatement,
 		max_block_data_size: Option<u64>,
 	) -> Option<ParachainWork<
 		Fetch,
@@ -154,7 +169,7 @@ impl SharedTableInner {
 		self.update_trackers(&summary.candidate, context);
 
 		let local_index = context.local_index()?;
-		let para_member = context.is_member_of(local_index, &summary.group_id);
+		let para_member = context.is_member_of(&local_index, &summary.group_id);
 		let digest = &summary.candidate;
 
 		// TODO: consider a strategy based on the number of candidate votes as well.
@@ -216,7 +231,7 @@ impl SharedTableInner {
 /// Produced after validating a candidate.
 pub struct Validated {
 	/// A statement about the validity of the candidate.
-	statement: table::Statement,
+	statement: table_v0::Statement,
 	/// The result of validation.
 	result: Validation,
 }
@@ -461,7 +476,7 @@ impl SharedTable {
 	pub fn import_remote_statement<Fetch>(
 		&self,
 		fetch_pov_block: impl Fn(&AbridgedCandidateReceipt) -> Fetch,
-		statement: table::SignedStatement,
+		statement: table_v0::SignedStatement,
 	) -> Option<ParachainWork<
 		Fetch,
 	>> {
@@ -487,7 +502,7 @@ impl SharedTable {
 		iterable: I,
 	) -> U
 		where
-			I: IntoIterator<Item=table::SignedStatement>,
+			I: IntoIterator<Item=table_v0::SignedStatement>,
 			U: ::std::iter::FromIterator<Option<ParachainWork<
 				Fetch,
 			>>>,
@@ -539,7 +554,7 @@ impl SharedTable {
 	/// Get a set of candidates that can be proposed.
 	pub fn proposed_set(&self) -> Vec<AttestedCandidate> {
 		use table::generic::{ValidityAttestation as GAttestation};
-		use polkadot_primitives::parachain::ValidityAttestation;
+		use polkadot_primitives::v0::ValidityAttestation;
 
 		// we transform the types of the attestations gathered from the table
 		// into the type expected by the runtime. This may do signature
@@ -583,7 +598,7 @@ impl SharedTable {
 	}
 
 	/// Get all witnessed misbehavior.
-	pub fn get_misbehavior(&self) -> HashMap<ValidatorIndex, table::Misbehavior> {
+	pub fn get_misbehavior(&self) -> HashMap<ValidatorIndex, table_v0::Misbehavior> {
 		self.inner.lock().table.get_misbehavior().clone()
 	}
 
@@ -615,7 +630,7 @@ impl SharedTable {
 mod tests {
 	use super::*;
 	use sp_keyring::Sr25519Keyring;
-	use polkadot_primitives::parachain::{
+	use polkadot_primitives::v0::{
 		BlockData, ErasureChunk, AvailableData,
 	};
 	use polkadot_erasure_coding::{self as erasure};
@@ -706,7 +721,7 @@ mod tests {
 			&validity_other_key.into(),
 			&signing_context,
 		);
-		let signed_statement = ::table::generic::SignedStatement {
+		let signed_statement = table::generic::SignedStatement {
 			statement: candidate_statement,
 			signature: signature.into(),
 			sender: validity_other_index,
@@ -763,7 +778,7 @@ mod tests {
 			&validity_other_key.into(),
 			&signing_context,
 		);
-		let signed_statement = ::table::generic::SignedStatement {
+		let signed_statement = table::generic::SignedStatement {
 			statement: candidate_statement,
 			signature: signature.into(),
 			sender: validity_other_index,
@@ -860,7 +875,7 @@ mod tests {
 			omitted_validation: Default::default(),
 		};
 
-		let chunks = erasure::obtain_chunks(n_validators, &available_data).unwrap();
+		let chunks = erasure::obtain_chunks_v0(n_validators, &available_data).unwrap();
 
 		store.note_validator_index_and_n_validators(
 			&relay_parent,
@@ -947,7 +962,7 @@ mod tests {
 			&validity_other_key.into(),
 			&signing_context,
 		);
-		let signed_statement = ::table::generic::SignedStatement {
+		let signed_statement = table::generic::SignedStatement {
 			statement: candidate_statement,
 			signature: signature.into(),
 			sender: validity_other_index,
diff --git a/polkadot/validation/src/validation_service/mod.rs b/polkadot/validation/src/validation_service/mod.rs
index d84b1be078ad299afbc1ad865af1290778fe2e75..7f332f4c0d1aa73b783d159b18264e8bf8cf90c9 100644
--- a/polkadot/validation/src/validation_service/mod.rs
+++ b/polkadot/validation/src/validation_service/mod.rs
@@ -32,8 +32,8 @@ use crate::pipeline::FullOutput;
 use sc_client_api::{BlockchainEvents, BlockBackend};
 use consensus::SelectChain;
 use futures::prelude::*;
-use polkadot_primitives::{Block, Hash, BlockId};
-use polkadot_primitives::parachain::{
+use polkadot_primitives::v0::{
+	Block, Hash, BlockId,
 	Chain, ParachainHost, Id as ParaId, ValidatorIndex, ValidatorId, ValidatorPair,
 	CollationInfo, SigningContext,
 };
@@ -545,7 +545,7 @@ mod tests {
 	use super::*;
 	use futures::{executor, future::ready, channel::mpsc};
 	use availability_store::ErasureNetworking;
-	use polkadot_primitives::parachain::{
+	use polkadot_primitives::v0::{
 		PoVBlock, AbridgedCandidateReceipt, ErasureChunk, ValidatorIndex,
 		CollationInfo, DutyRoster, GlobalValidationSchedule, LocalValidationData,
 		Retriable, CollatorId, BlockData, Chain, AvailableData, SigningContext, ValidationCode,
@@ -706,7 +706,7 @@ mod tests {
 			fn signing_context() -> SigningContext {
 				Default::default()
 			}
-			fn downward_messages(_: ParaId) -> Vec<polkadot_primitives::DownwardMessage> {
+			fn downward_messages(_: ParaId) -> Vec<polkadot_primitives::v0::DownwardMessage> {
 				Vec::new()
 			}
 		}