diff --git a/polkadot/consensus/src/collation.rs b/polkadot/consensus/src/collation.rs
index 33fcb63628deb04878c4e5a5f7b5ed41331daddb..562e48d2ca7e43a91e12a5a33bd2236638654c5c 100644
--- a/polkadot/consensus/src/collation.rs
+++ b/polkadot/consensus/src/collation.rs
@@ -100,10 +100,7 @@ impl<C: Collators, P: ProvideRuntimeApi> Future for CollationFetch<C, P>
 			};
 
 			match validate_collation(&*self.client, &self.relay_parent, &x) {
-				Ok(()) => {
-					// TODO: generate extrinsic while verifying.
-					return Ok(Async::Ready((x, Extrinsic)));
-				}
+				Ok(e) => return Ok(Async::Ready((x, e))),
 				Err(e) => {
 					debug!("Failed to validate parachain due to API error: {}", e);
 
@@ -140,12 +137,12 @@ error_chain! {
 	}
 }
 
-/// Check whether a given collation is valid. Returns `Ok`  on success, error otherwise.
+/// Check whether a given collation is valid. Returns `Ok` on success, error otherwise.
 pub fn validate_collation<P>(
 	client: &P,
 	relay_parent: &BlockId,
 	collation: &Collation
-) -> Result<(), Error> where
+) -> Result<Extrinsic, Error> where
 	P: ProvideRuntimeApi,
 	P::Api: ParachainHost<Block>
 {
@@ -167,7 +164,7 @@ pub fn validate_collation<P>(
 	match parachain::wasm::validate_candidate(&validation_code, params) {
 		Ok(result) => {
 			if result.head_data == collation.receipt.head_data.0 {
-				Ok(())
+				Ok(Extrinsic)
 			} else {
 				Err(ErrorKind::WrongHeadData(
 					collation.receipt.head_data.0.clone(),
diff --git a/polkadot/consensus/src/lib.rs b/polkadot/consensus/src/lib.rs
index 096a4b214b31f4b52e390d6ac60f931fd2a2fce9..2d4876db207286966c88a1f5ebe230748c7fb816 100644
--- a/polkadot/consensus/src/lib.rs
+++ b/polkadot/consensus/src/lib.rs
@@ -92,7 +92,7 @@ use dynamic_inclusion::DynamicInclusion;
 
 pub use self::collation::{validate_collation, Collators};
 pub use self::error::{ErrorKind, Error};
-pub use self::shared_table::{SharedTable, StatementProducer, ProducedStatements, Statement, SignedStatement, GenericStatement};
+pub use self::shared_table::{SharedTable, ParachainWork, PrimedParachainWork, Validated, Statement, SignedStatement, GenericStatement};
 
 mod attestation_service;
 mod dynamic_inclusion;
@@ -147,12 +147,8 @@ pub trait Network {
 pub struct GroupInfo {
 	/// Authorities meant to check validity of candidates.
 	pub validity_guarantors: HashSet<SessionKey>,
-	/// Authorities meant to check availability of candidate data.
-	pub availability_guarantors: HashSet<SessionKey>,
 	/// Number of votes needed for validity.
 	pub needed_validity: usize,
-	/// Number of votes needed for availability.
-	pub needed_availability: usize,
 }
 
 /// Sign a table statement against a parent hash.
@@ -183,15 +179,11 @@ fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId], local_id: Au
 		bail!(ErrorKind::InvalidDutyRosterLength(authorities.len(), roster.validator_duty.len()))
 	}
 
-	if roster.guarantor_duty.len() != authorities.len() {
-		bail!(ErrorKind::InvalidDutyRosterLength(authorities.len(), roster.guarantor_duty.len()))
-	}
-
 	let mut local_validation = None;
 	let mut map = HashMap::new();
 
-	let duty_iter = authorities.iter().zip(&roster.validator_duty).zip(&roster.guarantor_duty);
-	for ((authority, v_duty), a_duty) in duty_iter {
+	let duty_iter = authorities.iter().zip(&roster.validator_duty);
+	for (authority, v_duty) in duty_iter {
 		if authority == &local_id {
 			local_validation = Some(v_duty.clone());
 		}
@@ -204,23 +196,11 @@ fn make_group_info(roster: DutyRoster, authorities: &[AuthorityId], local_id: Au
 					.insert(authority.clone());
 			}
 		}
-
-		match *a_duty {
-			Chain::Relay => {}, // does nothing for now.
-			Chain::Parachain(ref id) => {
-				map.entry(id.clone()).or_insert_with(GroupInfo::default)
-					.availability_guarantors
-					.insert(authority.clone());
-			}
-		}
 	}
 
 	for live_group in map.values_mut() {
 		let validity_len = live_group.validity_guarantors.len();
-		let availability_len = live_group.availability_guarantors.len();
-
 		live_group.needed_validity = validity_len / 2 + validity_len % 2;
-		live_group.needed_availability = availability_len / 2 + availability_len % 2;
 	}
 
 	match local_validation {
@@ -470,8 +450,11 @@ fn dispatch_collation_work<R, C, P>(
 			});
 
 			match res {
-				Ok(()) =>
-					router.local_candidate(collation.receipt, collation.block_data, extrinsic),
+				Ok(()) => {
+					// TODO: https://github.com/paritytech/polkadot/issues/51
+					// Erasure-code and provide merkle branches.
+					router.local_candidate(collation.receipt, collation.block_data, extrinsic)
+				}
 				Err(e) =>
 					warn!(target: "consensus", "Failed to make collation data available: {:?}", e),
 			}
diff --git a/polkadot/consensus/src/shared_table/mod.rs b/polkadot/consensus/src/shared_table/mod.rs
index 34087566214a67738fcdbbdf2f266f26542c2bd5..a74eae8ea6f49f92161b46435ef1f97209f8ad1c 100644
--- a/polkadot/consensus/src/shared_table/mod.rs
+++ b/polkadot/consensus/src/shared_table/mod.rs
@@ -22,18 +22,19 @@ use std::sync::Arc;
 
 use extrinsic_store::{Data, Store as ExtrinsicStore};
 use table::{self, Table, Context as TableContextTrait};
-use polkadot_primitives::{Hash, SessionKey};
+use polkadot_primitives::{Block, BlockId, Hash, SessionKey};
 use polkadot_primitives::parachain::{
 	Id as ParaId, BlockData, Collation, Extrinsic, CandidateReceipt,
-	AttestedCandidate,
+	AttestedCandidate, ParachainHost
 };
 
 use parking_lot::Mutex;
-use futures::{future, prelude::*};
+use futures::prelude::*;
 
 use super::{GroupInfo, TableRouter};
 use self::includable::IncludabilitySender;
 use primitives::ed25519;
+use runtime_primitives::{traits::ProvideRuntimeApi};
 
 mod includable;
 
@@ -52,15 +53,8 @@ impl table::Context for TableContext {
 		self.groups.get(group).map_or(false, |g| g.validity_guarantors.contains(authority))
 	}
 
-	fn is_availability_guarantor_of(&self, authority: &SessionKey, group: &ParaId) -> bool {
-		self.groups.get(group).map_or(false, |g| g.availability_guarantors.contains(authority))
-	}
-
-	fn requisite_votes(&self, group: &ParaId) -> (usize, usize) {
-		self.groups.get(group).map_or(
-			(usize::max_value(), usize::max_value()),
-			|g| (g.needed_validity, g.needed_availability),
-		)
+	fn requisite_votes(&self, group: &ParaId) -> usize {
+		self.groups.get(group).map_or(usize::max_value(), |g| g.needed_validity)
 	}
 }
 
@@ -85,7 +79,6 @@ struct SharedTableInner {
 	table: Table<TableContext>,
 	proposed_digest: Option<Hash>,
 	checked_validity: HashSet<Hash>,
-	checked_availability: HashSet<Hash>,
 	trackers: Vec<IncludabilitySender>,
 	extrinsic_store: ExtrinsicStore,
 }
@@ -101,9 +94,8 @@ impl SharedTableInner {
 		context: &TableContext,
 		router: &R,
 		statement: table::SignedStatement,
-	) -> Option<StatementProducer<
+	) -> Option<ParachainWork<
 		<R::FetchCandidate as IntoFuture>::Future,
-		<R::FetchExtrinsic as IntoFuture>::Future,
 	>> {
 		let summary = match self.table.import_statement(context, statement) {
 			Some(summary) => summary,
@@ -114,42 +106,25 @@ impl SharedTableInner {
 
 		let local_id = context.local_id();
 
-		let is_validity_member = context.is_member_of(&local_id, &summary.group_id);
-		let is_availability_member =
-			context.is_availability_guarantor_of(&local_id, &summary.group_id);
+		let para_member = context.is_member_of(&local_id, &summary.group_id);
 
 		let digest = &summary.candidate;
 
 		// TODO: consider a strategy based on the number of candidate votes as well.
 		// only check validity if this wasn't locally proposed.
-		let checking_validity = is_validity_member
+		let extra_work = para_member
 			&& self.proposed_digest.as_ref().map_or(true, |d| d != digest)
 			&& self.checked_validity.insert(digest.clone());
 
-		let checking_availability = is_availability_member
-			&& self.checked_availability.insert(digest.clone());
-
-		let work = if checking_validity || checking_availability {
+		let work = if extra_work {
 			match self.table.get_candidate(&digest) {
 				None => None, // TODO: handle table inconsistency somehow?
 				Some(candidate) => {
-					let fetch_block_data =
-						router.fetch_block_data(candidate).into_future().fuse();
-
-					let fetch_extrinsic = if checking_availability {
-						Some(
-							router.fetch_extrinsic_data(candidate).into_future().fuse()
-						)
-					} else {
-						None
-					};
+					let fetch_block_data = router.fetch_block_data(candidate).into_future();
 
 					Some(Work {
 						candidate_receipt: candidate.clone(),
 						fetch_block_data,
-						fetch_extrinsic,
-						evaluate: checking_validity,
-						ensure_available: checking_availability,
 					})
 				}
 			}
@@ -157,8 +132,7 @@ impl SharedTableInner {
 			None
 		};
 
-		work.map(|work| StatementProducer {
-			produced_statements: Default::default(),
+		work.map(|work| ParachainWork {
 			extrinsic_store: self.extrinsic_store.clone(),
 			relay_parent: context.parent_hash.clone(),
 			work
@@ -175,130 +149,114 @@ impl SharedTableInner {
 	}
 }
 
-/// Produced statements about a specific candidate.
-/// Both may be `None`.
-#[derive(Default)]
-pub struct ProducedStatements {
+/// Produced after validating a candidate.
+pub struct Validated {
 	/// A statement about the validity of the candidate.
-	pub validity: Option<table::Statement>,
-	/// A statement about availability of data. If this is `Some`,
-	/// then `block_data` and `extrinsic` should be `Some` as well.
-	pub availability: Option<table::Statement>,
+	pub validity: table::Statement,
 	/// Block data to ensure availability of.
-	pub block_data: Option<BlockData>,
+	pub block_data: BlockData,
 	/// Extrinsic data to ensure availability of.
-	pub extrinsic: Option<Extrinsic>,
+	pub extrinsic: Extrinsic,
 }
 
-/// Future that produces statements about a specific candidate.
-pub struct StatementProducer<D: Future, E: Future> {
-	produced_statements: ProducedStatements,
-	work: Work<D, E>,
+/// Future that performs parachain validation work.
+pub struct ParachainWork<D: Future> {
+	work: Work<D>,
 	relay_parent: Hash,
 	extrinsic_store: ExtrinsicStore,
 }
 
-impl<D: Future, E: Future> StatementProducer<D, E> {
-	/// Attach a function for verifying fetched collation to the statement producer.
-	/// This will transform it into a future.
-	///
-	/// The collation-checking function should return `true` if known to be valid,
-	/// `false` if known to be invalid, and `None` if unable to determine.
-	pub fn prime<C: FnMut(Collation) -> Option<bool>>(self, check_candidate: C) -> PrimedStatementProducer<D, E, C> {
-		PrimedStatementProducer {
-			inner: self,
-			check_candidate,
-		}
+impl<D: Future> ParachainWork<D> {
+	/// Prime the parachain work with an API reference for extracting
+	/// chain information.
+	pub fn prime<P: ProvideRuntimeApi>(self, api: Arc<P>)
+		-> PrimedParachainWork<
+			D,
+			impl Send + FnMut(&BlockId, &Collation) -> bool,
+		>
+		where
+			P: Send + Sync + 'static,
+			P::Api: ParachainHost<Block>,
+	{
+		let validate = move |id: &_, collation: &_| {
+			let res = ::collation::validate_collation(
+				&*api,
+				id,
+				collation,
+			);
+
+			match res {
+				Ok(_) => true,
+				Err(e) => {
+					debug!(target: "consensus", "Encountered bad collation: {}", e);
+					false
+				}
+			}
+		};
+
+		PrimedParachainWork { inner: self, validate }
+	}
+
+	/// Prime the parachain work with a custom validation function.
+	pub fn prime_with<F>(self, validate: F) -> PrimedParachainWork<D, F>
+		where F: FnMut(&BlockId, &Collation) -> bool
+	{
+		PrimedParachainWork { inner: self, validate }
 	}
 }
 
-struct Work<D: Future, E: Future> {
+struct Work<D: Future> {
 	candidate_receipt: CandidateReceipt,
-	fetch_block_data: future::Fuse<D>,
-	fetch_extrinsic: Option<future::Fuse<E>>,
-	evaluate: bool,
-	ensure_available: bool,
+	fetch_block_data: D,
 }
 
 /// Primed statement producer.
-pub struct PrimedStatementProducer<D: Future, E: Future, C> {
-	inner: StatementProducer<D, E>,
-	check_candidate: C,
+pub struct PrimedParachainWork<D: Future, F> {
+	inner: ParachainWork<D>,
+	validate: F,
 }
 
-impl<D, E, C, Err> Future for PrimedStatementProducer<D, E, C>
+impl<D, F, Err> Future for PrimedParachainWork<D, F>
 	where
 		D: Future<Item=BlockData,Error=Err>,
-		E: Future<Item=Extrinsic,Error=Err>,
-		C: FnMut(Collation) -> Option<bool>,
+		F: FnMut(&BlockId, &Collation) -> bool,
 		Err: From<::std::io::Error>,
 {
-	type Item = ProducedStatements;
+	type Item = Validated;
 	type Error = Err;
 
-	fn poll(&mut self) -> Poll<ProducedStatements, Err> {
+	fn poll(&mut self) -> Poll<Validated, Err> {
 		let work = &mut self.inner.work;
 		let candidate = &work.candidate_receipt;
-		let statements = &mut self.inner.produced_statements;
-
-		let mut candidate_hash = None;
-		let mut candidate_hash = move ||
-			candidate_hash.get_or_insert_with(|| candidate.hash()).clone();
-
-		if let Async::Ready(block_data) = work.fetch_block_data.poll()? {
-			statements.block_data = Some(block_data.clone());
-			if work.evaluate {
-				let is_good = (self.check_candidate)(Collation {
-					block_data,
-					receipt: work.candidate_receipt.clone(),
-				});
-
-				let hash = candidate_hash();
-
-				debug!(target: "consensus", "Making validity statement about candidate {}: is_good? {:?}", hash, is_good);
-				statements.validity = match is_good {
-					Some(true) => Some(GenericStatement::Valid(hash)),
-					Some(false) => Some(GenericStatement::Invalid(hash)),
-					None => None,
-				};
-
-				work.evaluate = false;
-			}
-		}
-
-		if let Async::Ready(Some(extrinsic)) = work.fetch_extrinsic.poll()? {
-			if work.ensure_available {
-				let hash = candidate_hash();
-				debug!(target: "consensus", "Claiming candidate {} available.", hash);
 
-				statements.extrinsic = Some(extrinsic);
-				statements.availability = Some(GenericStatement::Available(hash));
+		let block = try_ready!(work.fetch_block_data.poll());
+		let is_good = (self.validate)(
+			&BlockId::hash(self.inner.relay_parent),
+			&Collation { block_data: block.clone(), receipt: candidate.clone() },
+		);
 
-				work.ensure_available = false;
-			}
-		}
+		let candidate_hash = candidate.hash();
 
-		let done = match (work.evaluate, work.ensure_available) {
-			(false, false) => true,
-			_ => false,
+		debug!(target: "consensus", "Making validity statement about candidate {}: is_good? {:?}", candidate_hash, is_good);
+		let validity_statement = match is_good {
+			true => GenericStatement::Valid(candidate_hash),
+			false => GenericStatement::Invalid(candidate_hash),
 		};
 
-		if done {
-			// commit claimed-available data to disk before returning statements from the future.
-			if let (&Some(ref block), extrinsic) = (&statements.block_data, &statements.extrinsic) {
-				self.inner.extrinsic_store.make_available(Data {
-					relay_parent: self.inner.relay_parent,
-					parachain_id: work.candidate_receipt.parachain_index,
-					candidate_hash: candidate_hash(),
-					block_data: block.clone(),
-					extrinsic: extrinsic.clone(),
-				})?;
-			}
-
-			Ok(Async::Ready(::std::mem::replace(statements, Default::default())))
-		} else {
-			Ok(Async::NotReady)
-		}
+		let extrinsic = Extrinsic;
+		self.inner.extrinsic_store.make_available(Data {
+			relay_parent: self.inner.relay_parent,
+			parachain_id: work.candidate_receipt.parachain_index,
+			candidate_hash,
+			block_data: block.clone(),
+			extrinsic: Some(extrinsic.clone()),
+		})?;
+
+		Ok(Async::Ready(Validated {
+			validity: validity_statement,
+			block_data: block,
+			extrinsic,
+		}))
 	}
 }
 
@@ -334,7 +292,6 @@ impl SharedTable {
 				table: Table::default(),
 				proposed_digest: None,
 				checked_validity: HashSet::new(),
-				checked_availability: HashSet::new(),
 				trackers: Vec::new(),
 				extrinsic_store,
 			}))
@@ -364,9 +321,8 @@ impl SharedTable {
 		&self,
 		router: &R,
 		statement: table::SignedStatement,
-	) -> Option<StatementProducer<
+	) -> Option<ParachainWork<
 		<R::FetchCandidate as IntoFuture>::Future,
-		<R::FetchExtrinsic as IntoFuture>::Future,
 	>> {
 		self.inner.lock().import_remote_statement(&*self.context, router, statement)
 	}
@@ -381,9 +337,8 @@ impl SharedTable {
 		where
 			R: TableRouter,
 			I: IntoIterator<Item=table::SignedStatement>,
-			U: ::std::iter::FromIterator<Option<StatementProducer<
+			U: ::std::iter::FromIterator<Option<ParachainWork<
 				<R::FetchCandidate as IntoFuture>::Future,
-				<R::FetchExtrinsic as IntoFuture>::Future,
 			>>>,
 	{
 		let mut inner = self.inner.lock();
@@ -394,25 +349,12 @@ impl SharedTable {
 	}
 
 	/// Sign and import a local statement.
-	///
-	/// For candidate statements, this may also produce a second signed statement
-	/// concerning the availability of the candidate data.
 	pub fn sign_and_import(&self, statement: table::Statement)
-		-> (SignedStatement, Option<SignedStatement>)
+		-> SignedStatement
 	{
-		let (proposed_digest, availability) = match statement {
-			GenericStatement::Candidate(ref c) => {
-				let mut availability = None;
-				let hash = c.hash();
-
-				// TODO: actually store the data in an availability store of some kind.
-				if self.context.is_availability_guarantor_of(&self.context.local_id(), &c.parachain_index) {
-					availability = Some(self.context.sign_statement(GenericStatement::Available(hash)));
-				}
-
-				(Some(hash), availability)
-			}
-			_ => (None, None),
+		let proposed_digest = match statement {
+			GenericStatement::Candidate(ref c) => Some(c.hash()),
+			_ => None,
 		};
 
 		let signed_statement = self.context.sign_statement(statement);
@@ -424,12 +366,7 @@ impl SharedTable {
 
 		inner.table.import_statement(&*self.context, signed_statement.clone());
 
-		// ensure the availability statement is imported after the candidate.
-		if let Some(a) = availability.clone() {
-			inner.table.import_statement(&*self.context, a);
-		}
-
-		(signed_statement, availability)
+		signed_statement
 	}
 
 	/// Execute a closure using a specific candidate.
@@ -454,7 +391,6 @@ impl SharedTable {
 		table_attestations.into_iter()
 			.map(|attested| AttestedCandidate {
 				candidate: attested.candidate,
-				availability_votes: attested.availability_votes,
 				validity_votes: attested.validity_votes.into_iter().map(|(a, v)| match v {
 					GAttestation::Implicit(s) => (a, ValidityAttestation::Implicit(s)),
 					GAttestation::Explicit(s) => (a, ValidityAttestation::Explicit(s)),
@@ -468,7 +404,7 @@ impl SharedTable {
 		self.group_info().len()
 	}
 
-	/// Get the number of parachains which have available candidates.
+	/// Get the number of parachains whose candidates may be included.
 	pub fn includable_count(&self) -> usize {
 		self.inner.lock().table.includable_count()
 	}
@@ -501,22 +437,23 @@ impl SharedTable {
 mod tests {
 	use super::*;
 	use substrate_keyring::Keyring;
+	use futures::future;
 
 	#[derive(Clone)]
 	struct DummyRouter;
 	impl TableRouter for DummyRouter {
 		type Error = ::std::io::Error;
-		type FetchCandidate = ::futures::future::Empty<BlockData,Self::Error>;
-		type FetchExtrinsic = ::futures::future::Empty<Extrinsic,Self::Error>;
+		type FetchCandidate = ::futures::future::FutureResult<BlockData,Self::Error>;
+		type FetchExtrinsic = ::futures::future::FutureResult<Extrinsic,Self::Error>;
 
 		fn local_candidate(&self, _candidate: CandidateReceipt, _block_data: BlockData, _extrinsic: Extrinsic) {
 
 		}
 		fn fetch_block_data(&self, _candidate: &CandidateReceipt) -> Self::FetchCandidate {
-			::futures::future::empty()
+			future::ok(BlockData(vec![1, 2, 3, 4, 5]))
 		}
 		fn fetch_extrinsic_data(&self, _candidate: &CandidateReceipt) -> Self::FetchExtrinsic {
-			::futures::future::empty()
+			future::ok(Extrinsic)
 		}
 	}
 
@@ -534,9 +471,7 @@ mod tests {
 
 		groups.insert(para_id, GroupInfo {
 			validity_guarantors: [local_id, validity_other].iter().cloned().collect(),
-			availability_guarantors: Default::default(),
 			needed_validity: 2,
-			needed_availability: 0,
 		});
 
 		let shared_table = SharedTable::new(
@@ -566,17 +501,14 @@ mod tests {
 			sender: validity_other,
 		};
 
-		let producer = shared_table.import_remote_statement(
+		shared_table.import_remote_statement(
 			&DummyRouter,
 			signed_statement,
 		).expect("candidate and local validity group are same");
-
-		assert!(producer.work.evaluate, "should evaluate validity");
-		assert!(producer.work.fetch_extrinsic.is_none(), "should not fetch extrinsic");
 	}
 
 	#[test]
-	fn statement_triggers_fetch_and_availability() {
+	fn statement_triggers_fetch_and_validity() {
 		let mut groups = HashMap::new();
 
 		let para_id = ParaId::from(1);
@@ -588,10 +520,8 @@ mod tests {
 		let parent_hash = Default::default();
 
 		groups.insert(para_id, GroupInfo {
-			validity_guarantors: [validity_other].iter().cloned().collect(),
-			availability_guarantors: [local_id].iter().cloned().collect(),
+			validity_guarantors: [local_id, validity_other].iter().cloned().collect(),
 			needed_validity: 1,
-			needed_availability: 1,
 		});
 
 		let shared_table = SharedTable::new(
@@ -621,14 +551,10 @@ mod tests {
 			sender: validity_other,
 		};
 
-		let producer = shared_table.import_remote_statement(
+		shared_table.import_remote_statement(
 			&DummyRouter,
 			signed_statement,
 		).expect("should produce work");
-
-		assert!(producer.work.fetch_extrinsic.is_some(), "should fetch extrinsic when guaranteeing availability");
-		assert!(!producer.work.evaluate, "should not evaluate validity");
-		assert!(producer.work.ensure_available);
 	}
 
 	#[test]
@@ -651,28 +577,22 @@ mod tests {
 
 		let hash = candidate.hash();
 
-		let block_data_res: ::std::io::Result<_> = Ok(block_data.clone());
-		let producer: StatementProducer<_, future::Empty<_, _>> = StatementProducer {
-			produced_statements: Default::default(),
+		let producer: ParachainWork<future::FutureResult<_, ::std::io::Error>> = ParachainWork {
 			work: Work {
 				candidate_receipt: candidate,
-				fetch_block_data: block_data_res.into_future().fuse(),
-				fetch_extrinsic: None,
-				evaluate: true,
-				ensure_available: false,
+				fetch_block_data: future::ok(block_data.clone()),
 			},
 			relay_parent,
 			extrinsic_store: store.clone(),
 		};
 
-		let produced = producer.prime(|_| Some(true)).wait().unwrap();
+		let produced = producer.prime_with(|_, _| true).wait().unwrap();
 
-		assert_eq!(produced.block_data.as_ref(), Some(&block_data));
-		assert!(produced.validity.is_some());
-		assert!(produced.availability.is_none());
+		assert_eq!(produced.block_data, block_data);
+		assert_eq!(produced.validity, GenericStatement::Valid(hash));
 
 		assert_eq!(store.block_data(relay_parent, hash).unwrap(), block_data);
-		assert!(store.extrinsic(relay_parent, hash).is_none());
+		assert!(store.extrinsic(relay_parent, hash).is_some());
 	}
 
 	#[test]
@@ -695,26 +615,18 @@ mod tests {
 
 		let hash = candidate.hash();
 
-		let block_data_res: ::std::io::Result<_> = Ok(block_data.clone());
-		let extrinsic_res: ::std::io::Result<_> = Ok(Extrinsic);
-		let producer = StatementProducer {
-			produced_statements: Default::default(),
+		let producer = ParachainWork {
 			work: Work {
 				candidate_receipt: candidate,
-				fetch_block_data: block_data_res.into_future().fuse(),
-				fetch_extrinsic: Some(extrinsic_res.into_future().fuse()),
-				evaluate: false,
-				ensure_available: true,
+				fetch_block_data: future::ok::<_, ::std::io::Error>(block_data.clone()),
 			},
 			relay_parent,
 			extrinsic_store: store.clone(),
 		};
 
-		let produced = producer.prime(|_| Some(true)).wait().unwrap();
+		let produced = producer.prime_with(|_, _| true).wait().unwrap();
 
-		assert_eq!(produced.block_data.as_ref(), Some(&block_data));
-		assert!(produced.validity.is_none());
-		assert!(produced.availability.is_some());
+		assert_eq!(produced.block_data, block_data);
 
 		assert_eq!(store.block_data(relay_parent, hash).unwrap(), block_data);
 		assert!(store.extrinsic(relay_parent, hash).is_some());
diff --git a/polkadot/network/src/consensus.rs b/polkadot/network/src/consensus.rs
index 04263afed0f3e6051a33951a0e5ecf6860acb00c..75f69819b66b0b4ac7f20d828b007ecc8f1de23e 100644
--- a/polkadot/network/src/consensus.rs
+++ b/polkadot/network/src/consensus.rs
@@ -237,11 +237,6 @@ impl Knowledge {
 				entry.knows_block_data.push(from);
 				entry.knows_extrinsic.push(from);
 			}
-			GenericStatement::Available(ref hash) => {
-				let mut entry = self.candidates.entry(*hash).or_insert_with(Default::default);
-				entry.knows_block_data.push(from);
-				entry.knows_extrinsic.push(from);
-			}
 			GenericStatement::Valid(ref hash) | GenericStatement::Invalid(ref hash) => self.candidates.entry(*hash)
 				.or_insert_with(Default::default)
 				.knows_block_data
diff --git a/polkadot/network/src/router.rs b/polkadot/network/src/router.rs
index 205aff1e65e615f8156765338c462e2fa1d44f47..58d0c38500b3aa79de01679af8df6d5fcab044e0 100644
--- a/polkadot/network/src/router.rs
+++ b/polkadot/network/src/router.rs
@@ -23,8 +23,8 @@
 //! and dispatch evaluation work as necessary when new statements come in.
 
 use sr_primitives::traits::{ProvideRuntimeApi, BlakeTwo256, Hash as HashT};
-use polkadot_consensus::{SharedTable, TableRouter, SignedStatement, GenericStatement, StatementProducer};
-use polkadot_primitives::{Block, Hash, BlockId, SessionKey};
+use polkadot_consensus::{SharedTable, TableRouter, SignedStatement, GenericStatement, ParachainWork};
+use polkadot_primitives::{Block, Hash, SessionKey};
 use polkadot_primitives::parachain::{BlockData, Extrinsic, CandidateReceipt, ParachainHost};
 
 use codec::Encode;
@@ -115,7 +115,6 @@ impl<P: ProvideRuntimeApi + Send + Sync + 'static> Router<P>
 				GenericStatement::Candidate(ref c) => Some(c.hash()),
 				GenericStatement::Valid(ref hash)
 					| GenericStatement::Invalid(ref hash)
-					| GenericStatement::Available(ref hash)
 					=> self.table.with_candidate(hash, |c| c.map(|_| *hash)),
 			};
 			match candidate_data {
@@ -152,61 +151,33 @@ impl<P: ProvideRuntimeApi + Send + Sync + 'static> Router<P>
 		}
 	}
 
-	fn create_work<D, E>(&self, candidate_hash: Hash, producer: StatementProducer<D, E>)
+	fn create_work<D>(&self, candidate_hash: Hash, producer: ParachainWork<D>)
 		-> impl Future<Item=(),Error=()>
 		where
 		D: Future<Item=BlockData,Error=io::Error> + Send + 'static,
-		E: Future<Item=Extrinsic,Error=io::Error> + Send + 'static,
 	{
-		let parent_hash = self.parent_hash.clone();
-
-		let api = self.api.clone();
-		let validate = move |collation| -> Option<bool> {
-			let id = BlockId::hash(parent_hash);
-			match ::polkadot_consensus::validate_collation(&*api, &id, &collation) {
-				Ok(()) => Some(true),
-				Err(e) => {
-					debug!(target: "p_net", "Encountered bad collation: {}", e);
-					Some(false)
-				}
-			}
-		};
-
 		let table = self.table.clone();
 		let network = self.network.clone();
 		let knowledge = self.knowledge.clone();
 		let attestation_topic = self.attestation_topic.clone();
 
-		producer.prime(validate)
+		producer.prime(self.api.clone())
 			.map(move |produced| {
 				// store the data before broadcasting statements, so other peers can fetch.
 				knowledge.lock().note_candidate(
 					candidate_hash,
-					produced.block_data,
-					produced.extrinsic,
+					Some(produced.block_data),
+					Some(produced.extrinsic),
 				);
 
-				if produced.validity.is_none() && produced.availability.is_none() {
-					return
-				}
-
 				let mut gossip = network.consensus_gossip().write();
 
-				// propagate the statements
+				// propagate the statement.
 				// consider something more targeted than gossip in the future.
-				if let Some(validity) = produced.validity {
-					let signed = table.sign_and_import(validity.clone()).0;
-					network.with_spec(|_, ctx|
-						gossip.multicast(ctx, attestation_topic, signed.encode(), false)
-					);
-				}
-
-				if let Some(availability) = produced.availability {
-					let signed = table.sign_and_import(availability).0;
-					network.with_spec(|_, ctx|
-						gossip.multicast(ctx, attestation_topic, signed.encode(), false)
-					);
-				}
+				let signed = table.sign_and_import(produced.validity);
+				network.with_spec(|_, ctx|
+					gossip.multicast(ctx, attestation_topic, signed.encode(), false)
+				);
 			})
 			.map_err(|e| debug!(target: "p_net", "Failed to produce statements: {:?}", e))
 	}
@@ -222,15 +193,12 @@ impl<P: ProvideRuntimeApi + Send> TableRouter for Router<P>
 	fn local_candidate(&self, receipt: CandidateReceipt, block_data: BlockData, extrinsic: Extrinsic) {
 		// give to network to make available.
 		let hash = receipt.hash();
-		let (candidate, availability) = self.table.sign_and_import(GenericStatement::Candidate(receipt));
+		let candidate = self.table.sign_and_import(GenericStatement::Candidate(receipt));
 
 		self.knowledge.lock().note_candidate(hash, Some(block_data), Some(extrinsic));
 		let mut gossip = self.network.consensus_gossip().write();
 		self.network.with_spec(|_spec, ctx| {
 			gossip.multicast(ctx, self.attestation_topic, candidate.encode(), false);
-			if let Some(availability) = availability {
-				gossip.multicast(ctx, self.attestation_topic, availability.encode(), false);
-			}
 		});
 	}
 
@@ -274,7 +242,6 @@ impl Future for BlockDataReceiver {
 enum StatementTrace {
 	Valid(SessionKey, Hash),
 	Invalid(SessionKey, Hash),
-	Available(SessionKey, Hash),
 }
 
 // helper for deferring statements whose associated candidate is unknown.
@@ -296,7 +263,6 @@ impl DeferredStatements {
 			GenericStatement::Candidate(_) => return,
 			GenericStatement::Valid(hash) => (hash, StatementTrace::Valid(statement.sender, hash)),
 			GenericStatement::Invalid(hash) => (hash, StatementTrace::Invalid(statement.sender, hash)),
-			GenericStatement::Available(hash) => (hash, StatementTrace::Available(statement.sender, hash)),
 		};
 
 		if self.known_traces.insert(trace) {
@@ -314,7 +280,6 @@ impl DeferredStatements {
 						GenericStatement::Candidate(_) => continue,
 						GenericStatement::Valid(hash) => StatementTrace::Valid(statement.sender, hash),
 						GenericStatement::Invalid(hash) => StatementTrace::Invalid(statement.sender, hash),
-						GenericStatement::Available(hash) => StatementTrace::Available(statement.sender, hash),
 					};
 
 					self.known_traces.remove(&trace);
diff --git a/polkadot/parachain/src/lib.rs b/polkadot/parachain/src/lib.rs
index 7c105c6f99068fa5ecdf50ba2bf9079819588b62..e81df3a967f6a0ab09cd689ff29be8a6da4b5987 100644
--- a/polkadot/parachain/src/lib.rs
+++ b/polkadot/parachain/src/lib.rs
@@ -86,7 +86,7 @@ pub struct ValidationParams {
 #[cfg_attr(feature = "std", derive(Debug))]
 pub struct ValidationResult {
 	/// New head data that should be included in the relay chain state.
-	pub head_data: Vec<u8>
+	pub head_data: Vec<u8>,
 }
 
 /// Load the validation params from memory when implementing a Rust parachain.
diff --git a/polkadot/primitives/src/parachain.rs b/polkadot/primitives/src/parachain.rs
index 2e209011ab73504b89a9e287e67fcb25789653c0..d2bc3b46b65fad297483059cfd5fd9864c1d38a4 100644
--- a/polkadot/primitives/src/parachain.rs
+++ b/polkadot/primitives/src/parachain.rs
@@ -64,9 +64,6 @@ pub enum Chain {
 pub struct DutyRoster {
 	/// Lookup from validator index to chain on which that validator has a duty to validate.
 	pub validator_duty: Vec<Chain>,
-	/// Lookup from validator index to chain on which that validator has a duty to guarantee
-	/// availability.
-	pub guarantor_duty: Vec<Chain>,
 }
 
 /// Extrinsic data for a parachain.
@@ -206,9 +203,6 @@ pub enum Statement {
 	/// State a candidate is invalid.
 	#[codec(index = "3")]
 	Invalid(Hash),
-	/// State a candidate's associated data is unavailable.
-	#[codec(index = "4")]
-	Available(Hash),
 }
 
 /// An either implicit or explicit attestation to the validity of a parachain
@@ -234,8 +228,6 @@ pub struct AttestedCandidate {
 	pub candidate: CandidateReceipt,
 	/// Validity attestations.
 	pub validity_votes: Vec<(SessionKey, ValidityAttestation)>,
-	/// Availability attestations.
-	pub availability_votes: Vec<(SessionKey, CandidateSignature)>,
 }
 
 impl AttestedCandidate {
diff --git a/polkadot/runtime/src/parachains.rs b/polkadot/runtime/src/parachains.rs
index b4256c4001de0480a4908be476cdec80fe25e231..a1e24adb8407cfe7d0be4bcd69bb1588bbe32ba3 100644
--- a/polkadot/runtime/src/parachains.rs
+++ b/polkadot/runtime/src/parachains.rs
@@ -196,8 +196,6 @@ impl<T: Trait> Module<T> {
 			_ => Chain::Relay,
 		}).collect::<Vec<_>>();
 
-		let mut roles_gua = roles_val.clone();
-
 		let mut random_seed = system::Module::<T>::random_seed().as_ref().to_vec();
 		random_seed.extend(b"validator_role_pairs");
 		let mut seed = BlakeTwo256::hash(&random_seed);
@@ -212,7 +210,6 @@ impl<T: Trait> Module<T> {
 
 			// 4 * 2 32-bit ints per 256-bit seed.
 			let val_index = u32::decode(&mut &seed[offset..offset + 4]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
-			let gua_index = u32::decode(&mut &seed[offset + 4..offset + 8]).expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
 
 			if offset == 24 {
 				// into the last 8 bytes - rehash to gather new entropy
@@ -221,12 +218,10 @@ impl<T: Trait> Module<T> {
 
 			// exchange last item with randomly chosen first.
 			roles_val.swap(remaining - 1, val_index);
-			roles_gua.swap(remaining - 1, gua_index);
 		}
 
 		DutyRoster {
 			validator_duty: roles_val,
-			guarantor_duty: roles_gua,
 		}
 	}
 
@@ -302,38 +297,27 @@ impl<T: Trait> Module<T> {
 		};
 
 		let sorted_validators = make_sorted_duties(&duty_roster.validator_duty);
-		let sorted_guarantors = make_sorted_duties(&duty_roster.guarantor_duty);
 
 		let parent_hash = super::System::parent_hash();
 		let localized_payload = |statement: Statement| localized_payload(statement, parent_hash);
 
 		let mut validator_groups = GroupedDutyIter::new(&sorted_validators[..]);
-		let mut guarantor_groups = GroupedDutyIter::new(&sorted_guarantors[..]);
 
 		for candidate in attested_candidates {
 			let validator_group = validator_groups.group_for(candidate.parachain_index())
 				.ok_or("no validator group for parachain")?;
 
-			let availability_group = guarantor_groups.group_for(candidate.parachain_index())
-				.ok_or("no availability group for parachain")?;
-
 			ensure!(
 				candidate.validity_votes.len() >= majority_of(validator_group.len()),
 				"Not enough validity attestations"
 			);
 
-			ensure!(
-				candidate.availability_votes.len() >= majority_of(availability_group.len()),
-				"Not enough availability attestations"
-			);
-
 			let mut candidate_hash = None;
 			let mut encoded_implicit = None;
 			let mut encoded_explicit = None;
 
-			// track which voters have voted already. the first `authorities.len()`
-			// bits is for validity, the next are for availability.
-			let mut track_voters = bitvec![0; authorities.len() * 2];
+			// track which voters have voted already, 1 bit per authority.
+			let mut track_voters = bitvec![0; authorities.len()];
 			for (auth_id, validity_attestation) in &candidate.validity_votes {
 				// protect against double-votes.
 				match validator_group.iter().find(|&(idx, _)| &authorities[*idx] == auth_id) {
@@ -372,32 +356,6 @@ impl<T: Trait> Module<T> {
 					"Candidate validity attestation signature is bad."
 				);
 			}
-
-			let mut encoded_available = None;
-			for (auth_id, sig) in &candidate.availability_votes {
-				match availability_group.iter().find(|&(idx, _)| &authorities[*idx] == auth_id) {
-					None => return Err("Attesting validator not on this chain's availability duty."),
-					Some(&(idx, _)) => {
-						if track_voters.get(authorities.len() + idx) {
-							return Err("Voter already attested availability once")
-						}
-						track_voters.set(authorities.len() + idx, true)
-					}
-				}
-
-				let hash = candidate_hash
-					.get_or_insert_with(|| candidate.candidate.hash())
-					.clone();
-
-				let payload = encoded_available.get_or_insert_with(|| localized_payload(
-					Statement::Available(hash),
-				));
-
-				ensure!(
-					sig.verify(&payload[..], &auth_id.0.into()),
-					"Candidate availability attestation signature is bad."
-				)
-			}
 		}
 
 		Ok(())
@@ -544,39 +502,28 @@ mod tests {
 		};
 
 		let validation_entries = duty_roster.validator_duty.iter()
-			.enumerate()
-			.map(|(i, d)| (i, d, true));
+			.enumerate();
 
-		let availability_entries = duty_roster.guarantor_duty.iter()
-			.enumerate()
-			.map(|(i, d)| (i, d, false));
-
-		for (idx, &duty, is_validation) in validation_entries.chain(availability_entries) {
+		for (idx, &duty) in validation_entries {
 			if duty != Chain::Parachain(candidate.parachain_index()) { continue }
-			if is_validation { vote_implicit = !vote_implicit };
+			vote_implicit = !vote_implicit;
 
 			let key = extract_key(authorities[idx]);
 
-			let statement = if is_validation && vote_implicit {
+			let statement = if vote_implicit {
 				Statement::Candidate(candidate.candidate.clone())
-			} else if is_validation {
-				Statement::Valid(candidate_hash.clone())
 			} else {
-				Statement::Available(candidate_hash.clone())
+				Statement::Valid(candidate_hash.clone())
 			};
 
 			let payload = localized_payload(statement, parent_hash);
 			let signature = key.sign(&payload[..]).into();
 
-			if is_validation {
-				candidate.validity_votes.push((authorities[idx], if vote_implicit {
-					ValidityAttestation::Implicit(signature)
-				} else {
-					ValidityAttestation::Explicit(signature)
-				}));
+			candidate.validity_votes.push((authorities[idx], if vote_implicit {
+				ValidityAttestation::Implicit(signature)
 			} else {
-				candidate.availability_votes.push((authorities[idx], signature));
-			}
+				ValidityAttestation::Explicit(signature)
+			}));
 		}
 	}
 
@@ -629,13 +576,10 @@ mod tests {
 		with_externalities(&mut new_test_ext(parachains), || {
 			let check_roster = |duty_roster: &DutyRoster| {
 				assert_eq!(duty_roster.validator_duty.len(), 8);
-				assert_eq!(duty_roster.guarantor_duty.len(), 8);
 				for i in (0..2).map(ParaId::from) {
 					assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
-					assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Parachain(i)).count(), 3);
 				}
 				assert_eq!(duty_roster.validator_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
-				assert_eq!(duty_roster.guarantor_duty.iter().filter(|&&j| j == Chain::Relay).count(), 2);
 			};
 
 			system::Module::<Test>::set_random_seed([0u8; 32].into());
@@ -667,7 +611,6 @@ mod tests {
 			system::Module::<Test>::set_random_seed([0u8; 32].into());
 			let candidate = AttestedCandidate {
 				validity_votes: vec![],
-				availability_votes: vec![],
 				candidate: CandidateReceipt {
 					parachain_index: 0.into(),
 					collator: Default::default(),
@@ -695,7 +638,6 @@ mod tests {
 			system::Module::<Test>::set_random_seed([0u8; 32].into());
 			let mut candidate_a = AttestedCandidate {
 				validity_votes: vec![],
-				availability_votes: vec![],
 				candidate: CandidateReceipt {
 					parachain_index: 0.into(),
 					collator: Default::default(),
@@ -710,7 +652,6 @@ mod tests {
 
 			let mut candidate_b = AttestedCandidate {
 				validity_votes: vec![],
-				availability_votes: vec![],
 				candidate: CandidateReceipt {
 					parachain_index: 1.into(),
 					collator: Default::default(),
@@ -749,7 +690,6 @@ mod tests {
 			system::Module::<Test>::set_random_seed([0u8; 32].into());
 			let mut candidate = AttestedCandidate {
 				validity_votes: vec![],
-				availability_votes: vec![],
 				candidate: CandidateReceipt {
 					parachain_index: 0.into(),
 					collator: Default::default(),
@@ -771,14 +711,6 @@ mod tests {
 				Call::set_heads(vec![double_validity]),
 				Origin::INHERENT,
 			).is_err());
-
-			let mut double_availability = candidate.clone();
-			double_availability.availability_votes.push(candidate.availability_votes[0].clone());
-
-			assert!(Parachains::dispatch(
-				Call::set_heads(vec![double_availability]),
-				Origin::INHERENT,
-			).is_err());
 		});
 	}
 }
diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm
index f8b4553ae7dab3b0efa8dbe48970f44b6ad91dd9..7cddf58035c1a0259acf8c8905617619cf9faba4 100644
Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.compact.wasm differ
diff --git a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm
index 0bcff8ef9ced3b97c28c1ae43c85e7e7e2fb77fa..6566dee3b648003b6f7284ebd8a7653348100a84 100755
Binary files a/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm and b/polkadot/runtime/wasm/target/wasm32-unknown-unknown/release/polkadot_runtime.wasm differ
diff --git a/polkadot/statement-table/src/generic.rs b/polkadot/statement-table/src/generic.rs
index 6deece66df4a5c53e86f7bcd8443c6967c5b1eb0..2389efdbdf76c93d6b3815e79af852e3503bbcfd 100644
--- a/polkadot/statement-table/src/generic.rs
+++ b/polkadot/statement-table/src/generic.rs
@@ -20,12 +20,9 @@
 //!
 //! These messages are used to create a proposal submitted to a BFT consensus process.
 //!
-//! Proposals are formed of sets of candidates which have the requisite number of
-//! validity and availability votes.
-//!
-//! Each parachain is associated with two sets of authorities: those which can
-//! propose and attest to validity of candidates, and those who can only attest
-//! to availability.
+//! Each parachain is associated with a committee of authorities, who issue statements
+//! indicating whether the candidate is valid or invalid. Once a threshold of the committee
+//! has signed validity statements, the candidate may be marked includable.
 
 use std::collections::hash_map::{HashMap, Entry};
 use std::hash::Hash;
@@ -54,17 +51,8 @@ pub trait Context {
 	/// Members are meant to submit candidates and vote on validity.
 	fn is_member_of(&self, authority: &Self::AuthorityId, group: &Self::GroupId) -> bool;
 
-	/// Whether a authority is an availability guarantor of a group.
-	/// Guarantors are meant to vote on availability for candidates submitted
-	/// in a group.
-	fn is_availability_guarantor_of(
-		&self,
-		authority: &Self::AuthorityId,
-		group: &Self::GroupId,
-	) -> bool;
-
-	// requisite number of votes for validity and availability respectively from a group.
-	fn requisite_votes(&self, group: &Self::GroupId) -> (usize, usize);
+	// requisite number of votes for validity from a group.
+	fn requisite_votes(&self, group: &Self::GroupId) -> usize;
 }
 
 /// Statements circulated among peers.
@@ -84,10 +72,6 @@ pub enum Statement<C, D> {
 	/// is invalid.
 	#[codec(index = "3")]
 	Invalid(D),
-	/// Broadcast by a authority to attest that the auxiliary data for a candidate
-	/// with given digest is available.
-	#[codec(index = "4")]
-	Available(D),
 }
 
 /// A signed statement.
@@ -124,8 +108,6 @@ pub enum DoubleSign<C, D, S> {
 	Validity(D, S, S),
 	/// On invalidity.
 	Invalidity(D, S, S),
-	/// On availability.
-	Availability(D, S, S),
 }
 
 /// Misbehavior: declaring multiple candidates.
@@ -181,8 +163,6 @@ pub struct Summary<D, G> {
 	pub group_id: G,
 	/// How many validity votes are currently witnessed.
 	pub validity_votes: usize,
-	/// How many availability votes are currently witnessed.
-	pub availability_votes: usize,
 	/// Whether this has been signalled bad by at least one participant.
 	pub signalled_bad: bool,
 }
@@ -207,8 +187,6 @@ pub struct AttestedCandidate<Group, Candidate, AuthorityId, Signature> {
 	pub candidate: Candidate,
 	/// Validity attestations.
 	pub validity_votes: Vec<(AuthorityId, ValidityAttestation<Signature>)>,
-	/// Availability attestations.
-	pub availability_votes: Vec<(AuthorityId, Signature)>
 }
 
 /// Stores votes and data about a candidate.
@@ -216,7 +194,6 @@ pub struct CandidateData<C: Context> {
 	group_id: C::GroupId,
 	candidate: C::Candidate,
 	validity_votes: HashMap<C::AuthorityId, ValidityVote<C::Signature>>,
-	availability_votes: HashMap<C::AuthorityId, C::Signature>,
 	indicated_bad_by: Vec<C::AuthorityId>,
 }
 
@@ -228,12 +205,12 @@ impl<C: Context> CandidateData<C> {
 
 	/// Yield a full attestation for a candidate.
 	/// If the candidate can be included, it will return `Some`.
-	pub fn attested(&self, validity_threshold: usize, availability_threshold: usize)
+	pub fn attested(&self, validity_threshold: usize)
 		-> Option<AttestedCandidate<
 			C::GroupId, C::Candidate, C::AuthorityId, C::Signature,
 		>>
 	{
-		if self.can_be_included(validity_threshold, availability_threshold) {
+		if self.can_be_included(validity_threshold) {
 			let validity_votes: Vec<_> = self.validity_votes.iter()
 				.filter_map(|(a, v)| match *v {
 					ValidityVote::Invalid(_) => None,
@@ -252,21 +229,10 @@ impl<C: Context> CandidateData<C> {
 				"candidate is includable; therefore there are enough validity votes; qed",
 			);
 
-			let availability_votes: Vec<_> = self.availability_votes.iter()
-				.take(availability_threshold)
-				.map(|(k, v)| (k.clone(), v.clone()))
-				.collect();
-
-			assert!(
-				availability_votes.len() == availability_threshold,
-				"candidate is includable; therefore there are enough availability votes; qed",
-			);
-
 			Some(AttestedCandidate {
 				group_id: self.group_id.clone(),
 				candidate: self.candidate.clone(),
 				validity_votes,
-				availability_votes,
 			})
 		} else {
 			None
@@ -274,12 +240,11 @@ impl<C: Context> CandidateData<C> {
 	}
 
 	// Candidate data can be included in a proposal
-	// if it has enough validity and availability votes
+	// if it has enough validity votes
 	// and no authorities have called it bad.
-	fn can_be_included(&self, validity_threshold: usize, availability_threshold: usize) -> bool {
+	fn can_be_included(&self, validity_threshold: usize) -> bool {
 		self.indicated_bad_by.is_empty()
 			&& self.validity_votes.len() >= validity_threshold
-			&& self.availability_votes.len() >= availability_threshold
 	}
 
 	fn summary(&self, digest: C::Digest) -> Summary<C::Digest, C::GroupId> {
@@ -287,7 +252,6 @@ impl<C: Context> CandidateData<C> {
 			candidate: digest,
 			group_id: self.group_id.clone(),
 			validity_votes: self.validity_votes.len() - self.indicated_bad_by.len(),
-			availability_votes: self.availability_votes.len(),
 			signalled_bad: self.indicated_bad(),
 		}
 	}
@@ -352,12 +316,12 @@ impl<C: Context> Table<C> {
 				continue
 			}
 
-			let (validity_t, availability_t) = context.requisite_votes(group_id);
+			let threshold = context.requisite_votes(group_id);
 
-			if !candidate_data.can_be_included(validity_t, availability_t) { continue }
+			if !candidate_data.can_be_included(threshold) { continue }
 			match best_candidates.entry(group_id.clone()) {
 				BTreeEntry::Vacant(vacant) => {
-					vacant.insert((candidate_data, validity_t, availability_t));
+					vacant.insert((candidate_data, threshold));
 				},
 				BTreeEntry::Occupied(mut occ) => {
 					let candidate_ref = occ.get_mut();
@@ -369,8 +333,8 @@ impl<C: Context> Table<C> {
 		}
 
 		best_candidates.values()
-			.map(|&(candidate_data, validity_t, availability_t)|
-				candidate_data.attested(validity_t, availability_t)
+			.map(|&(candidate_data, threshold)|
+				candidate_data.attested(threshold)
 					.expect("candidate has been checked includable; \
 						therefore an attestation can be constructed; qed")
 			)
@@ -380,8 +344,8 @@ impl<C: Context> Table<C> {
 	/// Whether a candidate can be included.
 	pub fn candidate_includable(&self, digest: &C::Digest, context: &C) -> bool {
 		self.candidate_votes.get(digest).map_or(false, |data| {
-			let (v_threshold, a_threshold) = context.requisite_votes(&data.group_id);
-			data.can_be_included(v_threshold, a_threshold)
+			let v_threshold = context.requisite_votes(&data.group_id);
+			data.can_be_included(v_threshold)
 		})
 	}
 
@@ -415,12 +379,6 @@ impl<C: Context> Table<C> {
 				digest,
 				ValidityVote::Invalid(signature),
 			),
-			Statement::Available(digest) => self.availability_vote(
-				context,
-				signer.clone(),
-				digest,
-				signature,
-			),
 		};
 
 		match res {
@@ -517,7 +475,6 @@ impl<C: Context> Table<C> {
 				group_id: group,
 				candidate: candidate,
 				validity_votes: HashMap::new(),
-				availability_votes: HashMap::new(),
 				indicated_bad_by: Vec::new(),
 			});
 		}
@@ -542,8 +499,8 @@ impl<C: Context> Table<C> {
 			Some(votes) => votes,
 		};
 
-		let (v_threshold, a_threshold) = context.requisite_votes(&votes.group_id);
-		let was_includable = votes.can_be_included(v_threshold, a_threshold);
+		let v_threshold = context.requisite_votes(&votes.group_id);
+		let was_includable = votes.can_be_included(v_threshold);
 
 		// check that this authority actually can vote in this group.
 		if !context.is_member_of(&from, &votes.group_id) {
@@ -615,46 +572,7 @@ impl<C: Context> Table<C> {
 			}
 		}
 
-		let is_includable = votes.can_be_included(v_threshold, a_threshold);
-		update_includable_count(&mut self.includable_count, &votes.group_id, was_includable, is_includable);
-
-		Ok(Some(votes.summary(digest)))
-	}
-
-	fn availability_vote(
-		&mut self,
-		context: &C,
-		from: C::AuthorityId,
-		digest: C::Digest,
-		signature: C::Signature,
-	) -> ImportResult<C> {
-		let votes = match self.candidate_votes.get_mut(&digest) {
-			None => return Ok(None),
-			Some(votes) => votes,
-		};
-
-		let (v_threshold, a_threshold) = context.requisite_votes(&votes.group_id);
-		let was_includable = votes.can_be_included(v_threshold, a_threshold);
-
-		// check that this authority actually can vote in this group.
-		if !context.is_availability_guarantor_of(&from, &votes.group_id) {
-			return Err(Misbehavior::UnauthorizedStatement(UnauthorizedStatement {
-				statement: SignedStatement {
-					signature: signature,
-					statement: Statement::Available(digest),
-					sender: from,
-				}
-			}));
-		}
-
-		match votes.availability_votes.entry(from) {
-			Entry::Occupied(ref occ) if occ.get() != &signature => return Err(
-				Misbehavior::DoubleSign(DoubleSign::Availability(digest, signature, occ.get().clone()))
-			),
-			entry => { let _ = entry.or_insert(signature); },
-		}
-
-		let is_includable = votes.can_be_included(v_threshold, a_threshold);
+		let is_includable = votes.can_be_included(v_threshold);
 		update_includable_count(&mut self.includable_count, &votes.group_id, was_includable, is_includable);
 
 		Ok(Some(votes.summary(digest)))
@@ -703,8 +621,8 @@ mod tests {
 
 	#[derive(Debug, PartialEq, Eq)]
 	struct TestContext {
-		// v -> (validity, availability)
-		authorities: HashMap<AuthorityId, (GroupId, GroupId)>
+		// v -> parachain group
+		authorities: HashMap<AuthorityId, GroupId>
 	}
 
 	impl Context for TestContext {
@@ -727,27 +645,17 @@ mod tests {
 			authority: &AuthorityId,
 			group: &GroupId
 		) -> bool {
-			self.authorities.get(authority).map(|v| &v.0 == group).unwrap_or(false)
+			self.authorities.get(authority).map(|v| v == group).unwrap_or(false)
 		}
 
-		fn is_availability_guarantor_of(
-			&self,
-			authority: &AuthorityId,
-			group: &GroupId
-		) -> bool {
-			self.authorities.get(authority).map(|v| &v.1 == group).unwrap_or(false)
-		}
-
-		fn requisite_votes(&self, id: &GroupId) -> (usize, usize) {
+		fn requisite_votes(&self, id: &GroupId) -> usize {
 			let mut total_validity = 0;
-			let mut total_availability = 0;
 
-			for &(ref validity, ref availability) in self.authorities.values() {
+			for validity in self.authorities.values() {
 				if validity == id { total_validity += 1 }
-				if availability == id { total_availability += 1 }
 			}
 
-			(total_validity / 2 + 1, total_availability / 2 + 1)
+			total_validity / 2 + 1
 		}
 	}
 
@@ -756,7 +664,7 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
+				map.insert(AuthorityId(1), GroupId(2));
 				map
 			}
 		};
@@ -792,7 +700,7 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(3), GroupId(455)));
+				map.insert(AuthorityId(1), GroupId(3));
 				map
 			}
 		};
@@ -823,8 +731,8 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(3), GroupId(222)));
+				map.insert(AuthorityId(1), GroupId(2));
+				map.insert(AuthorityId(2), GroupId(3));
 				map
 			}
 		};
@@ -838,37 +746,10 @@ mod tests {
 		};
 		let candidate_a_digest = Digest(100);
 
-		let candidate_b = SignedStatement {
-			statement: Statement::Candidate(Candidate(3, 987)),
-			signature: Signature(2),
-			sender: AuthorityId(2),
-		};
-		let candidate_b_digest = Digest(987);
-
 		table.import_statement(&context, candidate_a);
-		table.import_statement(&context, candidate_b);
 		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
 		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
 
-		// authority 1 votes for availability on 2's candidate.
-		let bad_availability_vote = SignedStatement {
-			statement: Statement::Available(candidate_b_digest.clone()),
-			signature: Signature(1),
-			sender: AuthorityId(1),
-		};
-		table.import_statement(&context, bad_availability_vote);
-
-		assert_eq!(
-			table.detected_misbehavior.get(&AuthorityId(1)).unwrap(),
-			&Misbehavior::UnauthorizedStatement(UnauthorizedStatement {
-				statement: SignedStatement {
-					statement: Statement::Available(candidate_b_digest),
-					signature: Signature(1),
-					sender: AuthorityId(1),
-				},
-			})
-		);
-
 		// authority 2 votes for validity on 1's candidate.
 		let bad_validity_vote = SignedStatement {
 			statement: Statement::Valid(candidate_a_digest.clone()),
@@ -894,8 +775,8 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(2), GroupId(246)));
+				map.insert(AuthorityId(1), GroupId(2));
+				map.insert(AuthorityId(2), GroupId(2));
 				map
 			}
 		};
@@ -943,8 +824,8 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(2), GroupId(246)));
+				map.insert(AuthorityId(1), GroupId(2));
+				map.insert(AuthorityId(2), GroupId(2));
 				map
 			}
 		};
@@ -974,9 +855,9 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(2), GroupId(246)));
-				map.insert(AuthorityId(3), (GroupId(2), GroupId(222)));
+				map.insert(AuthorityId(1), GroupId(2));
+				map.insert(AuthorityId(2), GroupId(2));
+				map.insert(AuthorityId(3), GroupId(2));
 				map
 			}
 		};
@@ -1039,7 +920,7 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
+				map.insert(AuthorityId(1), GroupId(2));
 				map
 			}
 		};
@@ -1074,33 +955,25 @@ mod tests {
 	#[test]
 	fn candidate_can_be_included() {
 		let validity_threshold = 6;
-		let availability_threshold = 34;
 
 		let mut candidate = CandidateData::<TestContext> {
 			group_id: GroupId(4),
 			candidate: Candidate(4, 12345),
 			validity_votes: HashMap::new(),
-			availability_votes: HashMap::new(),
 			indicated_bad_by: Vec::new(),
 		};
 
-		assert!(!candidate.can_be_included(validity_threshold, availability_threshold));
+		assert!(!candidate.can_be_included(validity_threshold));
 
 		for i in 0..validity_threshold {
 			candidate.validity_votes.insert(AuthorityId(i + 100), ValidityVote::Valid(Signature(i + 100)));
 		}
 
-		assert!(!candidate.can_be_included(validity_threshold, availability_threshold));
-
-		for i in 0..availability_threshold {
-			candidate.availability_votes.insert(AuthorityId(i + 255), Signature(i + 255));
-		}
-
-		assert!(candidate.can_be_included(validity_threshold, availability_threshold));
+		assert!(candidate.can_be_included(validity_threshold));
 
 		candidate.indicated_bad_by.push(AuthorityId(1024));
 
-		assert!(!candidate.can_be_included(validity_threshold, availability_threshold));
+		assert!(!candidate.can_be_included(validity_threshold));
 	}
 
 	#[test]
@@ -1108,10 +981,9 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(3), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(4), (GroupId(455), GroupId(2)));
+				map.insert(AuthorityId(1), GroupId(2));
+				map.insert(AuthorityId(2), GroupId(2));
+				map.insert(AuthorityId(3), GroupId(2));
 				map
 			}
 		};
@@ -1126,6 +998,7 @@ mod tests {
 		let candidate_digest = Digest(100);
 
 		table.import_statement(&context, statement);
+
 		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
 		assert!(!table.candidate_includable(&candidate_digest, &context));
 		assert!(table.includable_count.is_empty());
@@ -1138,18 +1011,6 @@ mod tests {
 
 		table.import_statement(&context, vote);
 		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
-		assert!(!table.candidate_includable(&candidate_digest, &context));
-		assert!(table.includable_count.is_empty());
-
-		// have the availability guarantor note validity.
-		let vote = SignedStatement {
-			statement: Statement::Available(candidate_digest.clone()),
-			signature: Signature(4),
-			sender: AuthorityId(4),
-		};
-
-		table.import_statement(&context, vote);
-		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(4)));
 		assert!(table.candidate_includable(&candidate_digest, &context));
 		assert!(table.includable_count.get(&GroupId(2)).is_some());
 
@@ -1161,7 +1022,7 @@ mod tests {
 		};
 
 		table.import_statement(&context, vote);
-		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
+		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(3)));
 		assert!(!table.candidate_includable(&candidate_digest, &context));
 		assert!(table.includable_count.is_empty());
 	}
@@ -1171,7 +1032,7 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
+				map.insert(AuthorityId(1), GroupId(2));
 				map
 			}
 		};
@@ -1189,7 +1050,6 @@ mod tests {
 		assert_eq!(summary.candidate, Digest(100));
 		assert_eq!(summary.group_id, GroupId(2));
 		assert_eq!(summary.validity_votes, 1);
-		assert_eq!(summary.availability_votes, 0);
 	}
 
 	#[test]
@@ -1197,8 +1057,8 @@ mod tests {
 		let context = TestContext {
 			authorities: {
 				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(2), GroupId(455)));
+				map.insert(AuthorityId(1), GroupId(2));
+				map.insert(AuthorityId(2), GroupId(2));
 				map
 			}
 		};
@@ -1228,45 +1088,5 @@ mod tests {
 		assert_eq!(summary.candidate, Digest(100));
 		assert_eq!(summary.group_id, GroupId(2));
 		assert_eq!(summary.validity_votes, 2);
-		assert_eq!(summary.availability_votes, 0);
-	}
-
-	#[test]
-	fn availability_vote_gives_summary() {
-		let context = TestContext {
-			authorities: {
-				let mut map = HashMap::new();
-				map.insert(AuthorityId(1), (GroupId(2), GroupId(455)));
-				map.insert(AuthorityId(2), (GroupId(5), GroupId(2)));
-				map
-			}
-		};
-
-		let mut table = create();
-		let statement = SignedStatement {
-			statement: Statement::Candidate(Candidate(2, 100)),
-			signature: Signature(1),
-			sender: AuthorityId(1),
-		};
-		let candidate_digest = Digest(100);
-
-		table.import_statement(&context, statement);
-		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(1)));
-
-		let vote = SignedStatement {
-			statement: Statement::Available(candidate_digest.clone()),
-			signature: Signature(2),
-			sender: AuthorityId(2),
-		};
-
-		let summary = table.import_statement(&context, vote)
-			.expect("candidate vote to give summary");
-
-		assert!(!table.detected_misbehavior.contains_key(&AuthorityId(2)));
-
-		assert_eq!(summary.candidate, Digest(100));
-		assert_eq!(summary.group_id, GroupId(2));
-		assert_eq!(summary.validity_votes, 1);
-		assert_eq!(summary.availability_votes, 1);
 	}
 }
diff --git a/polkadot/statement-table/src/lib.rs b/polkadot/statement-table/src/lib.rs
index 91173aad680e28a23790d1b8f5297c0097849ffe..15078446126dc649f7ae6dff7f7dd0ddca1eee85 100644
--- a/polkadot/statement-table/src/lib.rs
+++ b/polkadot/statement-table/src/lib.rs
@@ -48,17 +48,8 @@ pub trait Context {
 	/// Members are meant to submit candidates and vote on validity.
 	fn is_member_of(&self, authority: &SessionKey, group: &Id) -> bool;
 
-	/// Whether a authority is an availability guarantor of a group.
-	/// Guarantors are meant to vote on availability for candidates submitted
-	/// in a group.
-	fn is_availability_guarantor_of(
-		&self,
-		authority: &SessionKey,
-		group: &Id,
-	) -> bool;
-
-	// requisite number of votes for validity and availability respectively from a group.
-	fn requisite_votes(&self, group: &Id) -> (usize, usize);
+	// requisite number of votes for validity from a group.
+	fn requisite_votes(&self, group: &Id) -> usize;
 }
 
 impl<C: Context> generic::Context for C {
@@ -80,11 +71,7 @@ impl<C: Context> generic::Context for C {
 		Context::is_member_of(self, authority, group)
 	}
 
-	fn is_availability_guarantor_of(&self, authority: &SessionKey, group: &Id) -> bool {
-		Context::is_availability_guarantor_of(self, authority, group)
-	}
-
-	fn requisite_votes(&self, group: &Id) -> (usize, usize) {
+	fn requisite_votes(&self, group: &Id) -> usize {
 		Context::requisite_votes(self, group)
 	}
 }
@@ -95,7 +82,6 @@ impl From<Statement> for PrimitiveStatement {
 			generic::Statement::Valid(s) => PrimitiveStatement::Valid(s),
 			generic::Statement::Invalid(s) => PrimitiveStatement::Invalid(s),
 			generic::Statement::Candidate(s) => PrimitiveStatement::Candidate(s),
-			generic::Statement::Available(s) => PrimitiveStatement::Available(s),
 		}
 	}
 }