diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index e29aa3a664c20154197184ac96897af3fcf9bc67..d270ab4d0c558560e4b5a61678ccbdae4551d37b 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -1120,6 +1120,7 @@ dependencies = [
  "ed25519 0.1.0",
  "error-chain 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "futures 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)",
+ "log 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)",
  "parking_lot 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
  "polkadot-api 0.1.0",
  "polkadot-collator 0.1.0",
@@ -1173,6 +1174,7 @@ dependencies = [
  "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
  "substrate-codec 0.1.0",
  "substrate-keyring 0.1.0",
+ "substrate-misbehavior-check 0.1.0",
  "substrate-primitives 0.1.0",
  "substrate-runtime-io 0.1.0",
  "substrate-runtime-std 0.1.0",
@@ -1601,6 +1603,17 @@ dependencies = [
  "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
 ]
 
+[[package]]
+name = "substrate-misbehavior-check"
+version = "0.1.0"
+dependencies = [
+ "substrate-bft 0.1.0",
+ "substrate-codec 0.1.0",
+ "substrate-keyring 0.1.0",
+ "substrate-primitives 0.1.0",
+ "substrate-runtime-io 0.1.0",
+]
+
 [[package]]
 name = "substrate-network"
 version = "0.1.0"
diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml
index 635370e2dfcb8be558134b90d6243fa85ea81c4b..27ff076184e40a75d0834b8466e0996459b077ed 100644
--- a/substrate/Cargo.toml
+++ b/substrate/Cargo.toml
@@ -30,6 +30,7 @@ members = [
 	"substrate/executor",
 	"substrate/keyring",
 	"substrate/network",
+	"substrate/misbehavior-check",
 	"substrate/primitives",
 	"substrate/rpc-servers",
 	"substrate/rpc",
diff --git a/substrate/demo/primitives/src/transaction.rs b/substrate/demo/primitives/src/transaction.rs
index cc7e410a72c4412652d65b7296cae0251a4c1bf9..8f0027459a6b4f2d5ca189a548dae2cc189a4360 100644
--- a/substrate/demo/primitives/src/transaction.rs
+++ b/substrate/demo/primitives/src/transaction.rs
@@ -16,7 +16,7 @@
 
 //! Transaction type.
 
-use rstd::vec::Vec;
+use rstd::prelude::*;
 use codec::{Input, Slicable, NonTrivialSlicable};
 use {AccountId, SessionKey};
 
@@ -75,6 +75,7 @@ impl InternalFunctionId {
 	}
 }
 
+/// A means of determining whether a referendum has gone through or not.
 #[derive(Clone, Copy, PartialEq, Eq)]
 #[cfg_attr(feature = "std", derive(Serialize, Deserialize, Debug))]
 pub enum VoteThreshold {
diff --git a/substrate/demo/runtime/src/dispatch.rs b/substrate/demo/runtime/src/dispatch.rs
index 9a9aded039fb11a856a32aa5448e5a0e3ae454e4..ee5c03d9520fe151a05f148a0e4030c7ccba52d2 100644
--- a/substrate/demo/runtime/src/dispatch.rs
+++ b/substrate/demo/runtime/src/dispatch.rs
@@ -40,8 +40,6 @@ pub fn proposal(proposal: Proposal) {
 			democracy::privileged::cancel_referendum(a),
 		Proposal::DemocracyStartReferendum(a, b) =>
 			democracy::privileged::start_referendum(*a, b),
-		Proposal::DemocracyCancelReferendum(a) =>
-			democracy::privileged::cancel_referendum(a),
 		Proposal::CouncilSetDesiredSeats(a) =>
 			council::privileged::set_desired_seats(a),
 		Proposal::CouncilRemoveMember(a) =>
diff --git a/substrate/demo/runtime/src/runtime/council_vote.rs b/substrate/demo/runtime/src/runtime/council_vote.rs
index b40c79d79b486dab91204834bd60c57da3af4927..9887d14cae293cf48244a26602871b9ab31ce23e 100644
--- a/substrate/demo/runtime/src/runtime/council_vote.rs
+++ b/substrate/demo/runtime/src/runtime/council_vote.rs
@@ -190,7 +190,6 @@ pub mod internal {
 	pub fn end_block(now: BlockNumber) {
 		while let Some((proposal, proposal_hash)) = take_proposal_if_expiring_at(now) {
 			let tally = take_tally(&proposal_hash);
-			println!("Executing proposal {:?} {:?}", proposal, tally);
 			if let &Proposal::DemocracyCancelReferendum(ref_index) = &proposal {
 				if let (_, 0, 0) = tally {
 					democracy::privileged::cancel_referendum(ref_index);
diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm
index f542540c93e1ab432c2fed89067e577220d80c48..21685747dc5032d642e339bb5062e9b2f58d1f2a 100644
Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.compact.wasm differ
diff --git a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm
index 8ecf2b7224ed72d40b1bee2ca4d924177a099644..639cf3e8e4f2128ceac881d694983b02b7d3f0e8 100644
Binary files a/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm and b/substrate/demo/runtime/wasm/target/wasm32-unknown-unknown/release/demo_runtime.wasm differ
diff --git a/substrate/polkadot/consensus/Cargo.toml b/substrate/polkadot/consensus/Cargo.toml
index 60c8009b7c9d5652afe89b0dfbe49341b0fe9746..b7ccbc6534b048da19a4a12eea0c2ff297af23d6 100644
--- a/substrate/polkadot/consensus/Cargo.toml
+++ b/substrate/polkadot/consensus/Cargo.toml
@@ -9,6 +9,7 @@ parking_lot = "0.4"
 tokio-timer = "0.1.2"
 ed25519 = { path = "../../substrate/ed25519" }
 error-chain = "0.11"
+log = "0.4"
 polkadot-api = { path = "../api" }
 polkadot-collator = { path = "../collator" }
 polkadot-primitives = { path = "../primitives" }
diff --git a/substrate/polkadot/consensus/src/lib.rs b/substrate/polkadot/consensus/src/lib.rs
index 7321948dd773432f2fe09d24c1f9577d5d685290..a5c34e30ee406dfaf29f86990b8a78198edc5929 100644
--- a/substrate/polkadot/consensus/src/lib.rs
+++ b/substrate/polkadot/consensus/src/lib.rs
@@ -45,6 +45,9 @@ extern crate substrate_primitives as primitives;
 #[macro_use]
 extern crate error_chain;
 
+#[macro_use]
+extern crate log;
+
 use std::collections::{HashMap, HashSet};
 use std::sync::Arc;
 
@@ -55,9 +58,9 @@ use polkadot_api::{PolkadotApi, BlockBuilder};
 use polkadot_primitives::{Hash, Timestamp};
 use polkadot_primitives::block::Block as PolkadotBlock;
 use polkadot_primitives::parachain::{Id as ParaId, DutyRoster, BlockData, Extrinsic, CandidateReceipt};
-use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId};
+use primitives::block::{Block as SubstrateBlock, Header as SubstrateHeader, HeaderHash, Id as BlockId, Number as BlockNumber};
 use primitives::AuthorityId;
-use transaction_pool::TransactionPool;
+use transaction_pool::{Ready, TransactionPool};
 
 use futures::prelude::*;
 use futures::future;
@@ -477,17 +480,19 @@ impl<C: PolkadotApi, N: Network> bft::ProposerFactory for ProposerFactory<C, N>
 		let duty_roster = self.client.duty_roster(&checked_id)?;
 
 		let group_info = make_group_info(duty_roster, authorities)?;
-		let table = Arc::new(SharedTable::new(group_info, sign_with, parent_hash));
+		let table = Arc::new(SharedTable::new(group_info, sign_with.clone(), parent_hash));
 		let router = self.network.table_router(table.clone());
 
 		// TODO [PoC-2]: kick off collation process.
 		Ok(Proposer {
 			parent_hash,
+			parent_number: parent_header.number,
 			parent_id: checked_id,
-			_table: table,
-			_router: router,
+			local_key: sign_with,
 			client: self.client.clone(),
 			transaction_pool: self.transaction_pool.clone(),
+			_table: table,
+			_router: router,
 		})
 	}
 }
@@ -503,8 +508,10 @@ fn current_timestamp() -> Timestamp {
 /// The Polkadot proposer logic.
 pub struct Proposer<C: PolkadotApi, R> {
 	parent_hash: HeaderHash,
+	parent_number: BlockNumber,
 	parent_id: C::CheckedBlockId,
 	client: Arc<C>,
+	local_key: Arc<ed25519::Pair>,
 	transaction_pool: Arc<Mutex<TransactionPool>>,
 	_table: Arc<SharedTable>,
 	_router: R,
@@ -516,8 +523,6 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
 	type Evaluate = Result<bool, Error>;
 
 	fn propose(&self) -> Result<SubstrateBlock, Error> {
-		use transaction_pool::Ready;
-
 		// TODO: handle case when current timestamp behind that in state.
 		let mut block_builder = self.client.build_block(
 			&self.parent_id,
@@ -565,6 +570,65 @@ impl<C: PolkadotApi, R: TableRouter> bft::Proposer for Proposer<C, R> {
 	fn evaluate(&self, proposal: &SubstrateBlock) -> Result<bool, Error> {
 		evaluate_proposal(proposal, &*self.client, current_timestamp(), &self.parent_hash, &self.parent_id)
 	}
+
+	fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, bft::Misbehavior)>) {
+		use bft::generic::Misbehavior as GenericMisbehavior;
+		use primitives::bft::{MisbehaviorKind, MisbehaviorReport};
+		use polkadot_primitives::transaction::{Function, Transaction, UncheckedTransaction};
+
+		let local_id = self.local_key.public().0;
+		let mut pool = self.transaction_pool.lock();
+		let mut next_nonce = {
+			let readiness_evaluator = Ready::create(self.parent_id.clone(), &*self.client);
+
+			let cur_nonce = pool.pending(readiness_evaluator)
+				.filter(|tx| tx.as_transaction().transaction.signed == local_id)
+				.last()
+				.map(|tx| Ok(tx.as_transaction().transaction.nonce))
+				.unwrap_or_else(|| self.client.nonce(&self.parent_id, local_id));
+
+			match cur_nonce {
+				Ok(cur_nonce) => cur_nonce + 1,
+				Err(e) => {
+					warn!(target: "consensus", "Error computing next transaction nonce: {}", e);
+					return;
+				}
+			}
+		};
+
+		for (target, misbehavior) in misbehavior {
+			let report = MisbehaviorReport {
+				parent_hash: self.parent_hash,
+				parent_number: self.parent_number,
+				target,
+				misbehavior: match misbehavior {
+					GenericMisbehavior::ProposeOutOfTurn(_, _, _) => continue,
+					GenericMisbehavior::DoublePropose(_, _, _) => continue,
+					GenericMisbehavior::DoublePrepare(round, (h1, s1), (h2, s2))
+						=> MisbehaviorKind::BftDoublePrepare(round as u32, (h1, s1.signature), (h2, s2.signature)),
+					GenericMisbehavior::DoubleCommit(round, (h1, s1), (h2, s2))
+						=> MisbehaviorKind::BftDoubleCommit(round as u32, (h1, s1.signature), (h2, s2.signature)),
+				}
+			};
+
+			let tx = Transaction {
+				signed: local_id,
+				nonce: next_nonce,
+				function: Function::ReportMisbehavior(report),
+			};
+
+			next_nonce += 1;
+
+			let message = tx.encode();
+			let signature = self.local_key.sign(&message);
+			let tx = UncheckedTransaction {
+				transaction: tx,
+				signature,
+			};
+
+			pool.import(tx).expect("locally signed transaction is valid; qed");
+		}
+	}
 }
 
 fn evaluate_proposal<C: PolkadotApi>(
diff --git a/substrate/polkadot/executor/src/lib.rs b/substrate/polkadot/executor/src/lib.rs
index a1f472a859ec54bcc1a33b9afa9b5b5a0fcee613..186e5469ccfda52b66fde4587b4ad5f775b63a49 100644
--- a/substrate/polkadot/executor/src/lib.rs
+++ b/substrate/polkadot/executor/src/lib.rs
@@ -162,7 +162,7 @@ mod tests {
 		construct_block(
 			2,
 			block1().1,
-			hex!("c8776c92e8012bf6b3f206448eda3f00bca26d77f220f4714c81cbc92a30e1e2").into(),
+			hex!("5604fe023cd6effd93aec9b4a008398abdd32afb3fec988a19aa853ab0424a7c").into(),
 			200_000,
 			vec![
 				Transaction {
diff --git a/substrate/polkadot/primitives/src/lib.rs b/substrate/polkadot/primitives/src/lib.rs
index d65291476ab715fdfedce1a5cdccf387a1616086..fb02e3d121117e3c6fc56de29d86661f8ba75b5e 100644
--- a/substrate/polkadot/primitives/src/lib.rs
+++ b/substrate/polkadot/primitives/src/lib.rs
@@ -80,3 +80,9 @@ pub type Signature = primitives::hash::H512;
 
 /// A timestamp: seconds since the unix epoch.
 pub type Timestamp = u64;
+
+/// The balance of an account.
+pub type Balance = u64;
+
+/// The amount of bonding period left in an account. Measured in eras.
+pub type Bondage = u64;
diff --git a/substrate/polkadot/primitives/src/transaction.rs b/substrate/polkadot/primitives/src/transaction.rs
index 3d4095b86c8d7661f84985958504a957a5134a31..f13cf223a93e2a21642ea9826135ff4f8f0abda2 100644
--- a/substrate/polkadot/primitives/src/transaction.rs
+++ b/substrate/polkadot/primitives/src/transaction.rs
@@ -18,6 +18,7 @@
 
 use rstd::vec::Vec;
 use codec::{Input, Slicable};
+use primitives::bft::MisbehaviorReport;
 use ::Signature;
 
 #[cfg(feature = "std")]
@@ -168,6 +169,8 @@ enum FunctionId {
 	StakingUnstake = 0x21,
 	/// Staking subsystem: transfer stake.
 	StakingTransfer = 0x22,
+	/// Report misbehavior.
+	StakingReportMisbehavior = 0x23,
 	/// Make a proposal for the governance system.
 	GovernancePropose = 0x30,
 	/// Approve a proposal for the governance system.
@@ -178,9 +181,16 @@ impl FunctionId {
 	/// Derive `Some` value from a `u8`, or `None` if it's invalid.
 	fn from_u8(value: u8) -> Option<FunctionId> {
 		use self::*;
-		let functions = [FunctionId::StakingStake, FunctionId::StakingUnstake,
-			FunctionId::StakingTransfer, FunctionId::SessionSetKey, FunctionId::TimestampSet,
-			FunctionId::GovernancePropose, FunctionId::GovernanceApprove];
+		let functions = [
+			FunctionId::StakingStake,
+			FunctionId::StakingUnstake,
+			FunctionId::StakingTransfer,
+			FunctionId::StakingReportMisbehavior,
+			FunctionId::SessionSetKey,
+			FunctionId::TimestampSet,
+			FunctionId::GovernancePropose,
+			FunctionId::GovernanceApprove,
+		];
 		functions.iter().map(|&f| f).find(|&f| value == f as u8)
 	}
 }
@@ -222,6 +232,8 @@ pub enum Function {
 	StakingUnstake,
 	/// Staking subsystem: transfer stake.
 	StakingTransfer(::AccountId, u64),
+	/// Staking subsystem: report misbehavior of a validator.
+	ReportMisbehavior(MisbehaviorReport),
 	/// Make a proposal for the governance system.
 	GovernancePropose(Proposal),
 	/// Approve a proposal for the governance system.
@@ -269,6 +281,7 @@ impl Slicable for Function {
 
 				Function::StakingTransfer(to, amount)
 			}
+			FunctionId::StakingReportMisbehavior => Function::ReportMisbehavior(MisbehaviorReport::decode(input)?),
 			FunctionId::GovernancePropose =>
 				Function::GovernancePropose(try_opt!(Slicable::decode(input))),
 			FunctionId::GovernanceApprove =>
@@ -293,6 +306,10 @@ impl Slicable for Function {
 			Function::StakingUnstake => {
 				(FunctionId::StakingUnstake as u8).using_encoded(|s| v.extend(s));
 			}
+			Function::ReportMisbehavior(ref report) => {
+				(FunctionId::StakingReportMisbehavior as u8).using_encoded(|s| v.extend(s));
+				report.using_encoded(|s| v.extend(s));
+			}
 			Function::StakingTransfer(ref to, ref amount) => {
 				(FunctionId::StakingTransfer as u8).using_encoded(|s| v.extend(s));
 				to.using_encoded(|s| v.extend(s));
diff --git a/substrate/polkadot/runtime/Cargo.toml b/substrate/polkadot/runtime/Cargo.toml
index 4efe5c15e77ef0d41ab6af152f886c5a83824a45..ce4565025a21e37cd67e72f8c916fbfbc6cd7629 100644
--- a/substrate/polkadot/runtime/Cargo.toml
+++ b/substrate/polkadot/runtime/Cargo.toml
@@ -12,6 +12,7 @@ substrate-runtime-std = { path = "../../substrate/runtime-std" }
 substrate-runtime-io = { path = "../../substrate/runtime-io" }
 substrate-runtime-support = { path = "../../substrate/runtime-support" }
 substrate-primitives = { path = "../../substrate/primitives" }
+substrate-misbehavior-check = { path = "../../substrate/misbehavior-check" }
 polkadot-primitives = { path = "../primitives" }
 
 [dev-dependencies]
@@ -25,6 +26,7 @@ std = [
 	"substrate-runtime-io/std",
 	"substrate-runtime-support/std",
 	"substrate-primitives/std",
+	"substrate-misbehavior-check/std",
 	"polkadot-primitives/std",
 	"log"
 ]
diff --git a/substrate/polkadot/runtime/src/environment.rs b/substrate/polkadot/runtime/src/environment.rs
index 5b311ce1f98b9f74bcfd2457619a3876a520d8aa..b7fef7cdd87fdcad37bc628fa578123bd80e126d 100644
--- a/substrate/polkadot/runtime/src/environment.rs
+++ b/substrate/polkadot/runtime/src/environment.rs
@@ -31,8 +31,6 @@ pub struct Environment {
 	pub parent_hash: Hash,
 	/// The current block digest.
 	pub digest: Digest,
-	/// The current transaction index
-	pub transaction_index: u64,
 }
 
 /// Do something with the environment and return its value. Keep the function short.
diff --git a/substrate/polkadot/runtime/src/genesismap.rs b/substrate/polkadot/runtime/src/genesismap.rs
index 4100f411b0d31d739ab81843bf3505a0c3bd3dbe..d2b370fe4627b6cd3b7b2ad27d06a61227ac6393 100644
--- a/substrate/polkadot/runtime/src/genesismap.rs
+++ b/substrate/polkadot/runtime/src/genesismap.rs
@@ -21,8 +21,7 @@ use std::collections::HashMap;
 use runtime_io::twox_128;
 use runtime_support::Hashable;
 use primitives::Block;
-use polkadot_primitives::{BlockNumber, AccountId};
-use runtime::staking::Balance;
+use polkadot_primitives::{Balance, BlockNumber, AccountId};
 
 /// Configuration of a general Polkadot genesis block.
 pub struct GenesisConfig {
diff --git a/substrate/polkadot/runtime/src/lib.rs b/substrate/polkadot/runtime/src/lib.rs
index 16379cac8e41188e7d0cb1ab49d05fc1ea9e8552..caf8cb47c1e3bbb0c1f244c3970a2d10110939ef 100644
--- a/substrate/polkadot/runtime/src/lib.rs
+++ b/substrate/polkadot/runtime/src/lib.rs
@@ -19,23 +19,33 @@
 #![cfg_attr(not(feature = "std"), no_std)]
 
 extern crate substrate_runtime_std as rstd;
-#[macro_use] extern crate substrate_runtime_io as runtime_io;
 extern crate substrate_runtime_support as runtime_support;
-#[cfg(all(feature = "std", test))] extern crate substrate_keyring as keyring;
-
-#[cfg(feature = "std")] extern crate rustc_hex;
-
 extern crate substrate_codec as codec;
-#[cfg(feature = "std")] #[macro_use] extern crate substrate_primitives as primitives;
+extern crate substrate_misbehavior_check as misbehavior_check;
 extern crate polkadot_primitives;
 
-#[cfg(test)] #[macro_use] extern crate hex_literal;
+#[cfg(all(feature = "std", test))]
+extern crate substrate_keyring as keyring;
+
+#[cfg(feature = "std")]
+extern crate rustc_hex;
+
+#[cfg_attr(any(test, feature = "std"), macro_use)]
+extern crate substrate_primitives as primitives;
+
+#[macro_use]
+extern crate substrate_runtime_io as runtime_io;
+
+#[cfg(test)]
+#[macro_use]
+extern crate hex_literal;
 
 pub mod api;
 pub mod environment;
 pub mod runtime;
 
-#[cfg(feature = "std")] pub mod genesismap;
+#[cfg(feature = "std")]
+pub mod genesismap;
 
 /// Type definitions and helpers for transactions.
 pub mod transaction {
diff --git a/substrate/polkadot/runtime/src/runtime/consensus.rs b/substrate/polkadot/runtime/src/runtime/consensus.rs
index 7d50f6abd418f3cdfdf35adb96ed7f2c30c0ccf1..7841f1d47d5bcc0e9bb9f9c08326fa91c6fb635c 100644
--- a/substrate/polkadot/runtime/src/runtime/consensus.rs
+++ b/substrate/polkadot/runtime/src/runtime/consensus.rs
@@ -23,7 +23,7 @@ use polkadot_primitives::SessionKey;
 struct AuthorityStorageVec {}
 impl StorageVec for AuthorityStorageVec {
 	type Item = SessionKey;
-	const PREFIX: &'static[u8] = b":auth:";
+	const PREFIX: &'static [u8] = b":auth:";
 }
 
 /// Get the current set of authorities. These are the session keys.
@@ -37,7 +37,7 @@ pub mod internal {
 	/// Set the current set of authorities' session keys.
 	///
 	/// Called by `next_session` only.
-	pub fn set_authorities(authorities: &[SessionKey]) {
+	pub fn set_authorities<'a, I: IntoIterator<Item=&'a SessionKey>>(authorities: I) {
 		AuthorityStorageVec::set_items(authorities);
 	}
 
diff --git a/substrate/polkadot/runtime/src/runtime/session.rs b/substrate/polkadot/runtime/src/runtime/session.rs
index e9bf5f376564005ab01728be436a97e3a14f7227..01a5f78bbc5a090c2e6cd40b80ed97c93b589aec 100644
--- a/substrate/polkadot/runtime/src/runtime/session.rs
+++ b/substrate/polkadot/runtime/src/runtime/session.rs
@@ -25,14 +25,23 @@ use runtime::{system, staking, consensus};
 
 const SESSION_LENGTH: &[u8] = b"ses:len";
 const CURRENT_INDEX: &[u8] = b"ses:ind";
+const CURRENT_SESSION_START: &[u8] = b"ses:sta";
+const LAST_SESSION_START: &[u8] = b"ses:lst";
 const LAST_LENGTH_CHANGE: &[u8] = b"ses:llc";
 const NEXT_KEY_FOR: &[u8] = b"ses:nxt:";
 const NEXT_SESSION_LENGTH: &[u8] = b"ses:nln";
 
-struct ValidatorStorageVec {}
+struct ValidatorStorageVec;
 impl StorageVec for ValidatorStorageVec {
 	type Item = AccountId;
-	const PREFIX: &'static[u8] = b"ses:val:";
+	const PREFIX: &'static [u8] = b"ses:val:";
+}
+
+// the session keys before the previous.
+struct LastValidators;
+impl StorageVec for LastValidators {
+	type Item = (AccountId, SessionKey);
+	const PREFIX: &'static [u8] = b"ses:old:";
 }
 
 /// Get the current set of validators.
@@ -50,11 +59,31 @@ pub fn validator_count() -> u32 {
 	ValidatorStorageVec::count() as u32
 }
 
-/// The current era index.
+/// The current session index.
 pub fn current_index() -> BlockNumber {
 	storage::get_or(CURRENT_INDEX, 0)
 }
 
+/// Get the starting block of the current session.
+pub fn current_start_block() -> BlockNumber {
+	// this seems like it's computable just by examining the current block number, session length,
+	// and last length change, but it's not simple to tell whether we are before or after
+	// a session rotation on a block which will have one.
+	storage::get_or(CURRENT_SESSION_START, 0)
+}
+
+/// Get the last session's validators, paired with their authority keys.
+pub fn last_session_keys() -> Vec<(AccountId, SessionKey)> {
+	LastValidators::items()
+}
+
+/// Get the start block of the last session.
+/// In general this is computable from the session length,
+/// but when the current session is the first with a new length it is uncomputable.
+pub fn last_session_start() -> Option<BlockNumber> {
+	storage::get(LAST_SESSION_START)
+}
+
 /// The block number at which the era length last changed.
 pub fn last_length_change() -> BlockNumber {
 	storage::get_or(LAST_LENGTH_CHANGE, 0)
@@ -90,11 +119,14 @@ pub mod privileged {
 pub mod internal {
 	use super::*;
 
-	/// Set the current set of validators.
+	/// Transition to a new era, with a new set of valiators.
 	///
 	/// Called by staking::next_era() only. `next_session` should be called after this in order to
 	/// update the session keys to the next validator set.
 	pub fn set_validators(new: &[AccountId]) {
+		LastValidators::set_items(
+			new.iter().cloned().zip(consensus::authorities())
+		);
 		ValidatorStorageVec::set_items(new);
 		consensus::internal::set_authorities(new);
 	}
@@ -114,7 +146,6 @@ pub mod internal {
 fn rotate_session() {
 	// Increment current session index.
 	storage::put(CURRENT_INDEX, &(current_index() + 1));
-
 	// Enact era length change.
 	if let Some(next_len) = storage::get::<u64>(NEXT_SESSION_LENGTH) {
 		storage::put(SESSION_LENGTH, &next_len);
@@ -122,10 +153,23 @@ fn rotate_session() {
 		storage::kill(NEXT_SESSION_LENGTH);
 	}
 
+	let validators = validators();
+
+	storage::put(LAST_SESSION_START, &current_start_block());
+	storage::put(CURRENT_SESSION_START, &system::block_number());
+	LastValidators::set_items(
+		validators.iter()
+			.cloned()
+			.zip(consensus::authorities())
+	);
+
+
 	// Update any changes in session keys.
-	validators().iter().enumerate().for_each(|(i, v)| {
+	validators.iter().enumerate().for_each(|(i, v)| {
 		let k = v.to_keyed_vec(NEXT_KEY_FOR);
 		if let Some(n) = storage::take(&k) {
+			// this is fine because the authorities vector currently
+			// matches the validators length perfectly.
 			consensus::internal::set_authority(i as u32, &n);
 		}
 	});
diff --git a/substrate/polkadot/runtime/src/runtime/staking.rs b/substrate/polkadot/runtime/src/runtime/staking.rs
index 1b69698265ef3ae68ac6b82fb1356941ea099b62..cca0a92718420272b11db33de96d13889996bae9 100644
--- a/substrate/polkadot/runtime/src/runtime/staking.rs
+++ b/substrate/polkadot/runtime/src/runtime/staking.rs
@@ -22,18 +22,16 @@ use runtime_io::print;
 use codec::KeyedVec;
 use runtime_support::{storage, StorageVec};
 use polkadot_primitives::{BlockNumber, AccountId};
-use runtime::{system, session, governance};
+use primitives::bft::{MisbehaviorReport, MisbehaviorKind};
+use runtime::{system, session, governance, consensus};
 
-/// The balance of an account.
-pub type Balance = u64;
-
-/// The amount of bonding period left in an account. Measured in eras.
-pub type Bondage = u64;
+type Balance = u64;
+type Bondage = u64;
 
 struct IntentionStorageVec {}
 impl StorageVec for IntentionStorageVec {
 	type Item = AccountId;
-	const PREFIX: &'static[u8] = b"sta:wil:";
+	const PREFIX: &'static [u8] = b"sta:wil:";
 }
 
 const BONDING_DURATION: &[u8] = b"sta:loc";
@@ -81,11 +79,16 @@ pub fn balance(who: &AccountId) -> Balance {
 	storage::get_or_default(&who.to_keyed_vec(BALANCE_OF))
 }
 
-/// The liquidity-state of a given account.
+/// Gives the index of the era where the account's balance will no longer
+/// be bonded.
 pub fn bondage(who: &AccountId) -> Bondage {
 	storage::get_or_default(&who.to_keyed_vec(BONDAGE_OF))
 }
 
+fn set_balance(who: &AccountId, amount: Balance) {
+	storage::put(&who.to_keyed_vec(BALANCE_OF), &amount)
+}
+
 // Each identity's stake may be in one of three bondage states, given by an integer:
 // - n | n <= current_era(): inactive: free to be transferred.
 // - ~0: active: currently representing a validator.
@@ -114,7 +117,7 @@ pub mod public {
 	pub fn stake(transactor: &AccountId) {
 		let mut intentions = IntentionStorageVec::items();
 		// can't be in the list twice.
-		assert!(intentions.iter().find(|t| *t == transactor).is_none(), "Cannot stake if already staked.");
+		assert!(intentions.iter().find(|t| t == &transactor).is_none(), "Cannot stake if already staked.");
 		intentions.push(transactor.clone());
 		IntentionStorageVec::set_items(&intentions);
 		storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &u64::max_value());
@@ -133,6 +136,46 @@ pub mod public {
 		IntentionStorageVec::set_items(&intentions);
 		storage::put(&transactor.to_keyed_vec(BONDAGE_OF), &(current_era() + bonding_duration()));
 	}
+
+	/// Report misbehavior. Only validators may do this, signing under
+	/// the authority key of the session the report corresponds to.
+	///
+	/// Reports older than one session in the past will be ignored.
+	pub fn report_misbehavior(transactor: &AccountId, report: &MisbehaviorReport) {
+		let (validators, authorities) = if report.parent_number < session::last_session_start().unwrap_or(0) {
+			panic!("report is too old");
+		} else if report.parent_number < session::current_start_block() {
+			session::last_session_keys().into_iter().unzip()
+		} else {
+			(session::validators(), consensus::authorities())
+		};
+
+		if report.parent_hash != system::block_hash(report.parent_number) {
+			// report out of chain.
+			panic!("report not from this blockchain");
+		}
+
+		let reporting_validator = match authorities.iter().position(|x| x == transactor) {
+			None => panic!("only validators may report"),
+			Some(pos) => validators.get(pos).expect("validators and authorities have same cardinality; qed"),
+		};
+
+		// any invalidity beyond this point is actually its own misbehavior.
+		let target = match authorities.iter().position(|x| x == &report.target) {
+			None => {
+				slash(reporting_validator, None);
+				return;
+			}
+			Some(pos) => validators.get(pos).expect("validators and authorities have same cardinality; qed"),
+		};
+
+		let misbehaved = ::misbehavior_check::evaluate_misbehavior(&report.target, report.parent_hash, &report.misbehavior);
+		if misbehaved {
+			slash(target, Some(reporting_validator))
+		} else {
+			slash(reporting_validator, None);
+		}
+	}
 }
 
 pub mod privileged {
@@ -172,6 +215,23 @@ pub mod internal {
 	}
 }
 
+/// Slash a validator, with an optional benefactor.
+fn slash(who: &AccountId, benefactor: Option<&AccountId>) {
+	// the reciprocal of the proportion of the amount slashed to give
+	// to the benefactor.
+	const SLASH_REWARD_DENOMINATOR: Balance = 10;
+
+	let slashed = balance(who);
+	set_balance(who, 0);
+
+	if let Some(benefactor) = benefactor {
+		let reward = slashed / SLASH_REWARD_DENOMINATOR;
+
+		let prior = balance(benefactor);
+		set_balance(benefactor, prior + reward);
+	}
+}
+
 /// The era has changed - enact new staking set.
 ///
 /// NOTE: This always happens immediately before a session change to ensure that new validators
@@ -406,4 +466,31 @@ mod tests {
 			transfer(&one, &two, 69);
 		});
 	}
+
+	#[test]
+	#[should_panic]
+	fn misbehavior_report_by_non_validator_panics() {
+		let one = Keyring::One.to_raw_public();
+		let two = Keyring::Two.to_raw_public();
+
+		let mut t: TestExternalities = map![
+			twox_128(&one.to_keyed_vec(BALANCE_OF)).to_vec() => vec![].and(&111u64)
+		];
+
+		with_externalities(&mut t, || {
+			// the misbehavior report here is invalid, but that
+			// actually doesn't panic; instead it would slash the bad
+			// reporter.
+			report_misbehavior(&one, &MisbehaviorReport {
+				parent_hash: [0; 32].into(),
+				parent_number: 0,
+				target: two,
+				misbehavior: MisbehaviorKind::BftDoubleCommit(
+					2,
+					([1; 32].into(), [2; 64].into()),
+					([3; 32].into(), [4; 64].into()),
+				),
+			})
+		});
+	}
 }
diff --git a/substrate/polkadot/runtime/src/runtime/system.rs b/substrate/polkadot/runtime/src/runtime/system.rs
index aa6cfc45ce7120ac6389137eef15df5edf3932fd..c7972c949a131f9f98408c5a496e16d2a910593b 100644
--- a/substrate/polkadot/runtime/src/runtime/system.rs
+++ b/substrate/polkadot/runtime/src/runtime/system.rs
@@ -167,6 +167,9 @@ fn dispatch_function(function: &Function, transactor: &AccountId) {
 		Function::StakingTransfer(dest, value) => {
 			::runtime::staking::public::transfer(transactor, &dest, value);
 		}
+		Function::ReportMisbehavior(ref report) => {
+			::runtime::staking::public::report_misbehavior(transactor, report)
+		}
 		Function::SessionSetKey(session) => {
 			::runtime::session::public::set_key(transactor, &session);
 		}
diff --git a/substrate/polkadot/runtime/wasm/Cargo.lock b/substrate/polkadot/runtime/wasm/Cargo.lock
index 11fe2d48f84d0b5e9a18b35c4795185260062dc7..d2bf5b3e7875e0e9f2a4c1af07458a6271f529d0 100644
--- a/substrate/polkadot/runtime/wasm/Cargo.lock
+++ b/substrate/polkadot/runtime/wasm/Cargo.lock
@@ -392,6 +392,7 @@ version = "0.1.0"
 dependencies = [
  "polkadot-primitives 0.1.0",
  "substrate-codec 0.1.0",
+ "substrate-misbehavior-check 0.1.0",
  "substrate-primitives 0.1.0",
  "substrate-runtime-io 0.1.0",
  "substrate-runtime-std 0.1.0",
@@ -599,6 +600,15 @@ dependencies = [
  "substrate-runtime-std 0.1.0",
 ]
 
+[[package]]
+name = "substrate-misbehavior-check"
+version = "0.1.0"
+dependencies = [
+ "substrate-codec 0.1.0",
+ "substrate-primitives 0.1.0",
+ "substrate-runtime-io 0.1.0",
+]
+
 [[package]]
 name = "substrate-primitives"
 version = "0.1.0"
diff --git a/substrate/polkadot/runtime/wasm/Cargo.toml b/substrate/polkadot/runtime/wasm/Cargo.toml
index 2452ce9bd28e104126e598661ca6b1bb04e62dc1..0e30ce9ee68570069d299cbb1d3559eb7d92e074 100644
--- a/substrate/polkadot/runtime/wasm/Cargo.toml
+++ b/substrate/polkadot/runtime/wasm/Cargo.toml
@@ -12,6 +12,7 @@ substrate-runtime-std = { path = "../../../substrate/runtime-std", default-featu
 substrate-runtime-io = { path = "../../../substrate/runtime-io", default-features = false }
 substrate-runtime-support = { path = "../../../substrate/runtime-support", default-features = false }
 substrate-primitives = { path = "../../../substrate/primitives", default-features = false }
+substrate-misbehavior-check = { path = "../../../substrate/misbehavior-check", default-features = false }
 polkadot-primitives = { path = "../../primitives", default-features = false }
 
 [features]
@@ -22,6 +23,7 @@ std = [
 	"substrate-runtime-std/std",
 	"substrate-runtime-support/std",
 	"substrate-primitives/std",
+	"substrate-misbehavior-check/std",
 	"polkadot-primitives/std",
 ]
 
diff --git a/substrate/publish-wasm.sh b/substrate/publish-wasm.sh
index 42f60619200cef45cdc4a7830b46ab47abc0636c..8424817c66d7260d7f789a1a3b35cb4994e5d49f 100755
--- a/substrate/publish-wasm.sh
+++ b/substrate/publish-wasm.sh
@@ -7,7 +7,7 @@ REPO_AUTH="${GH_TOKEN}:@${REPO}"
 SRCS=( "polkadot/runtime/wasm" "substrate/executor/wasm" "substrate/test-runtime/wasm" )
 DST=".wasm-binaries"
 TARGET="wasm32-unknown-unknown"
-UTCDATE=`date -u "+%Y%m%d.%H%M%S"`
+UTCDATE=`date -u "+%Y%m%d.%H%M%S.0"`
 
 pushd .
 
diff --git a/substrate/substrate/bft/src/generic/accumulator.rs b/substrate/substrate/bft/src/generic/accumulator.rs
index a7b2076bba5e64f80ca83bb3bd5b08864adeb078..64c4f22254898ad0746e5fb3a8c0307509d556d1 100644
--- a/substrate/substrate/bft/src/generic/accumulator.rs
+++ b/substrate/substrate/bft/src/generic/accumulator.rs
@@ -14,13 +14,13 @@
 // You should have received a copy of the GNU General Public License
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
-//! Message accumulator for each round of BFT consensus.
+//! Vote accumulator for each round of BFT consensus.
 
 use std::collections::{HashMap, HashSet};
 use std::collections::hash_map::Entry;
 use std::hash::Hash;
 
-use generic::{Message, LocalizedMessage};
+use generic::{Vote, LocalizedMessage, LocalizedProposal};
 
 /// Justification for some state at a given round.
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -122,6 +122,26 @@ struct VoteCounts {
 	committed: usize,
 }
 
+#[derive(Debug)]
+struct Proposal<Candidate, Digest, Signature> {
+	proposal: Candidate,
+	digest: Digest,
+	digest_signature: Signature,
+}
+
+/// Misbehavior which can occur.
+#[derive(Debug, Clone)]
+pub enum Misbehavior<Digest, Signature> {
+	/// Proposed out-of-turn.
+	ProposeOutOfTurn(usize, Digest, Signature),
+	/// Issued two conflicting proposals.
+	DoublePropose(usize, (Digest, Signature), (Digest, Signature)),
+	/// Issued two conflicting prepare messages.
+	DoublePrepare(usize, (Digest, Signature), (Digest, Signature)),
+	/// Issued two conflicting commit messages.
+	DoubleCommit(usize, (Digest, Signature), (Digest, Signature)),
+}
+
 /// Accumulates messages for a given round of BFT consensus.
 ///
 /// This isn't tied to the "view" of a single authority. It
@@ -132,13 +152,13 @@ pub struct Accumulator<Candidate, Digest, AuthorityId, Signature>
 	where
 	Candidate: Eq + Clone,
 	Digest: Hash + Eq + Clone,
-	AuthorityId: Hash + Eq,
+	AuthorityId: Hash + Eq + Clone,
 	Signature: Eq + Clone,
 {
 	round_number: usize,
 	threshold: usize,
 	round_proposer: AuthorityId,
-	proposal: Option<Candidate>,
+	proposal: Option<Proposal<Candidate, Digest, Signature>>,
 	prepares: HashMap<AuthorityId, (Digest, Signature)>,
 	commits: HashMap<AuthorityId, (Digest, Signature)>,
 	vote_counts: HashMap<Digest, VoteCounts>,
@@ -150,7 +170,7 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 	where
 	Candidate: Eq + Clone,
 	Digest: Hash + Eq + Clone,
-	AuthorityId: Hash + Eq,
+	AuthorityId: Hash + Eq + Clone,
 	Signature: Eq + Clone,
 {
 	/// Create a new state accumulator.
@@ -179,7 +199,7 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 	}
 
 	pub fn proposal(&self) -> Option<&Candidate> {
-		self.proposal.as_ref()
+		self.proposal.as_ref().map(|p| &p.proposal)
 	}
 
 	/// Inspect the current consensus state.
@@ -192,32 +212,61 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 	pub fn import_message(
 		&mut self,
 		message: LocalizedMessage<Candidate, Digest, AuthorityId, Signature>,
-	)
-	{
+	) -> Result<(), Misbehavior<Digest, Signature>> {
 		// message from different round.
-		if message.message.round_number() != self.round_number {
-			return;
+		if message.round_number() != self.round_number {
+			return Ok(());
 		}
 
-		let (sender, signature) = (message.sender, message.signature);
-
-		match message.message {
-			Message::Propose(_, p) => self.import_proposal(p, sender),
-			Message::Prepare(_, d) => self.import_prepare(d, sender, signature),
-			Message::Commit(_, d) => self.import_commit(d, sender, signature),
-			Message::AdvanceRound(_) => self.import_advance_round(sender),
+		match message {
+			LocalizedMessage::Propose(proposal) => self.import_proposal(proposal),
+			LocalizedMessage::Vote(vote) => {
+				let (sender, signature) = (vote.sender, vote.signature);
+				match vote.vote {
+					Vote::Prepare(_, d) => self.import_prepare(d, sender, signature),
+					Vote::Commit(_, d) => self.import_commit(d, sender, signature),
+					Vote::AdvanceRound(_) => self.import_advance_round(sender),
+				}
+			}
 		}
 	}
 
 	fn import_proposal(
 		&mut self,
-		proposal: Candidate,
-		sender: AuthorityId,
-	) {
-		if sender != self.round_proposer || self.proposal.is_some() { return }
+		proposal: LocalizedProposal<Candidate, Digest, AuthorityId, Signature>,
+	) -> Result<(), Misbehavior<Digest, Signature>> {
+		let sender = proposal.sender;
+
+		if sender != self.round_proposer {
+			return Err(Misbehavior::ProposeOutOfTurn(
+				self.round_number,
+				proposal.digest,
+				proposal.digest_signature)
+			);
+		}
+
+		match self.proposal {
+			Some(ref p) if &p.digest != &proposal.digest => {
+				return Err(Misbehavior::DoublePropose(
+					self.round_number,
+					{
+						let old = self.proposal.as_ref().expect("just checked to be Some; qed");
+						(old.digest.clone(), old.digest_signature.clone())
+					},
+					(proposal.digest.clone(), proposal.digest_signature.clone())
+				))
+			}
+			_ => {},
+		}
+
+		self.proposal = Some(Proposal {
+			proposal: proposal.proposal.clone(),
+			digest: proposal.digest,
+			digest_signature: proposal.digest_signature,
+		});
 
-		self.proposal = Some(proposal.clone());
-		self.state = State::Proposed(proposal);
+		self.state = State::Proposed(proposal.proposal);
+		Ok(())
 	}
 
 	fn import_prepare(
@@ -225,21 +274,32 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 		digest: Digest,
 		sender: AuthorityId,
 		signature: Signature,
-	) {
+	) -> Result<(), Misbehavior<Digest, Signature>> {
 		// ignore any subsequent prepares by the same sender.
-		// TODO: if digest is different, that's misbehavior.
-		let threshold_prepared = if let Entry::Vacant(vacant) = self.prepares.entry(sender) {
-			vacant.insert((digest.clone(), signature));
-			let count = self.vote_counts.entry(digest.clone()).or_insert_with(Default::default);
-			count.prepared += 1;
-
-			if count.prepared >= self.threshold {
-				Some(digest)
-			} else {
+		let threshold_prepared = match self.prepares.entry(sender.clone()) {
+			Entry::Vacant(vacant) => {
+				vacant.insert((digest.clone(), signature));
+				let count = self.vote_counts.entry(digest.clone()).or_insert_with(Default::default);
+				count.prepared += 1;
+
+				if count.prepared >= self.threshold {
+					Some(digest)
+				} else {
+					None
+				}
+			}
+			Entry::Occupied(occupied) => {
+				// if digest is different, that's misbehavior.
+				if occupied.get().0 != digest {
+					return Err(Misbehavior::DoublePrepare(
+						self.round_number,
+						occupied.get().clone(),
+						(digest, signature)
+					));
+				}
+
 				None
 			}
-		} else {
-			None
 		};
 
 		// only allow transition to prepare from begin or proposed state.
@@ -261,6 +321,8 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 				signatures: signatures,
 			}));
 		}
+
+		Ok(())
 	}
 
 	fn import_commit(
@@ -268,21 +330,32 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 		digest: Digest,
 		sender: AuthorityId,
 		signature: Signature,
-	) {
+	) -> Result<(), Misbehavior<Digest, Signature>> {
 		// ignore any subsequent commits by the same sender.
-		// TODO: if digest is different, that's misbehavior.
-		let threshold_committed = if let Entry::Vacant(vacant) = self.commits.entry(sender) {
-			vacant.insert((digest.clone(), signature));
-			let count = self.vote_counts.entry(digest.clone()).or_insert_with(Default::default);
-			count.committed += 1;
-
-			if count.committed >= self.threshold {
-				Some(digest)
-			} else {
+		let threshold_committed = match self.commits.entry(sender.clone()) {
+			Entry::Vacant(vacant) => {
+				vacant.insert((digest.clone(), signature));
+				let count = self.vote_counts.entry(digest.clone()).or_insert_with(Default::default);
+				count.committed += 1;
+
+				if count.committed >= self.threshold {
+					Some(digest)
+				} else {
+					None
+				}
+			}
+			Entry::Occupied(occupied) => {
+				// if digest is different, that's misbehavior.
+				if occupied.get().0 != digest {
+					return Err(Misbehavior::DoubleCommit(
+						self.round_number,
+						occupied.get().clone(),
+						(digest, signature)
+					));
+				}
+
 				None
 			}
-		} else {
-			None
 		};
 
 		// transition to concluded state always valid.
@@ -302,15 +375,17 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 				signatures: signatures,
 			}));
 		}
+
+		Ok(())
 	}
 
 	fn import_advance_round(
 		&mut self,
 		sender: AuthorityId,
-	) {
+	) -> Result<(), Misbehavior<Digest, Signature>> {
 		self.advance_round.insert(sender);
 
-		if self.advance_round.len() < self.threshold { return }
+		if self.advance_round.len() < self.threshold { return Ok(()) }
 
 		// allow transition to new round only if we haven't produced a justification
 		// yet.
@@ -319,13 +394,16 @@ impl<Candidate, Digest, AuthorityId, Signature> Accumulator<Candidate, Digest, A
 			State::Prepared(j) => State::Advanced(Some(j)),
 			State::Advanced(j) => State::Advanced(j),
 			State::Begin | State::Proposed(_) => State::Advanced(None),
-		}
+		};
+
+		Ok(())
 	}
 }
 
 #[cfg(test)]
 mod tests {
 	use super::*;
+	use generic::{LocalizedMessage, LocalizedProposal, LocalizedVote};
 
 	#[derive(Clone, PartialEq, Eq, Debug)]
 	pub struct Candidate(usize);
@@ -333,7 +411,7 @@ mod tests {
 	#[derive(Hash, PartialEq, Eq, Clone, Debug)]
 	pub struct Digest(usize);
 
-	#[derive(Hash, PartialEq, Eq, Debug)]
+	#[derive(Hash, PartialEq, Eq, Debug, Clone)]
 	pub struct AuthorityId(usize);
 
 	#[derive(PartialEq, Eq, Clone, Debug)]
@@ -375,19 +453,27 @@ mod tests {
 		let mut accumulator = Accumulator::<_, Digest, _, _>::new(1, 7, AuthorityId(8));
 		assert_eq!(accumulator.state(), &State::Begin);
 
-		accumulator.import_message(LocalizedMessage {
+		let res = accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
 			sender: AuthorityId(5),
-			signature: Signature(999, 5),
-			message: Message::Propose(1, Candidate(999)),
-		});
+			full_signature: Signature(999, 5),
+			digest_signature: Signature(999, 5),
+			proposal: Candidate(999),
+			digest: Digest(999),
+			round_number: 1,
+		}));
+
+		assert!(res.is_err());
 
 		assert_eq!(accumulator.state(), &State::Begin);
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
 			sender: AuthorityId(8),
-			signature: Signature(999, 8),
-			message: Message::Propose(1, Candidate(999)),
-		});
+			full_signature: Signature(999, 8),
+			digest_signature: Signature(999, 8),
+			proposal: Candidate(999),
+			digest: Digest(999),
+			round_number: 1,
+		})).unwrap();
 
 		assert_eq!(accumulator.state(), &State::Proposed(Candidate(999)));
 	}
@@ -397,29 +483,32 @@ mod tests {
 		let mut accumulator = Accumulator::new(1, 7, AuthorityId(8));
 		assert_eq!(accumulator.state(), &State::Begin);
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
 			sender: AuthorityId(8),
-			signature: Signature(999, 8),
-			message: Message::Propose(1, Candidate(999)),
-		});
+			full_signature: Signature(999, 8),
+			digest_signature: Signature(999, 8),
+			round_number: 1,
+			proposal: Candidate(999),
+			digest: Digest(999),
+		})).unwrap();
 
 		assert_eq!(accumulator.state(), &State::Proposed(Candidate(999)));
 
 		for i in 0..6 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Prepare(1, Digest(999)),
-			});
+				vote: Vote::Prepare(1, Digest(999)),
+			}.into()).unwrap();
 
 			assert_eq!(accumulator.state(), &State::Proposed(Candidate(999)));
 		}
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedVote {
 			sender: AuthorityId(7),
 			signature: Signature(999, 7),
-			message: Message::Prepare(1, Digest(999)),
-		});
+			vote: Vote::Prepare(1, Digest(999)),
+		}.into()).unwrap();
 
 		match accumulator.state() {
 			&State::Prepared(ref j) => assert_eq!(j.digest, Digest(999)),
@@ -432,29 +521,32 @@ mod tests {
 		let mut accumulator = Accumulator::new(1, 7, AuthorityId(8));
 		assert_eq!(accumulator.state(), &State::Begin);
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
 			sender: AuthorityId(8),
-			signature: Signature(999, 8),
-			message: Message::Propose(1, Candidate(999)),
-		});
+			full_signature: Signature(999, 8),
+			digest_signature: Signature(999, 8),
+			round_number: 1,
+			proposal: Candidate(999),
+			digest: Digest(999),
+		})).unwrap();
 
 		assert_eq!(accumulator.state(), &State::Proposed(Candidate(999)));
 
 		for i in 0..6 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Prepare(1, Digest(999)),
-			});
+				vote: Vote::Prepare(1, Digest(999)),
+			}.into()).unwrap();
 
 			assert_eq!(accumulator.state(), &State::Proposed(Candidate(999)));
 		}
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedVote {
 			sender: AuthorityId(7),
 			signature: Signature(999, 7),
-			message: Message::Prepare(1, Digest(999)),
-		});
+			vote: Vote::Prepare(1, Digest(999)),
+		}.into()).unwrap();
 
 		match accumulator.state() {
 			&State::Prepared(ref j) => assert_eq!(j.digest, Digest(999)),
@@ -462,11 +554,11 @@ mod tests {
 		}
 
 		for i in 0..6 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Commit(1, Digest(999)),
-			});
+				vote: Vote::Commit(1, Digest(999)),
+			}.into()).unwrap();
 
 			match accumulator.state() {
 				&State::Prepared(_) => {},
@@ -474,11 +566,11 @@ mod tests {
 			}
 		}
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedVote {
 			sender: AuthorityId(7),
 			signature: Signature(999, 7),
-			message: Message::Commit(1, Digest(999)),
-		});
+			vote: Vote::Commit(1, Digest(999)),
+		}.into()).unwrap();
 
 		match accumulator.state() {
 			&State::Committed(ref j) => assert_eq!(j.digest, Digest(999)),
@@ -491,20 +583,23 @@ mod tests {
 		let mut accumulator = Accumulator::new(1, 7, AuthorityId(8));
 		assert_eq!(accumulator.state(), &State::Begin);
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
 			sender: AuthorityId(8),
-			signature: Signature(999, 8),
-			message: Message::Propose(1, Candidate(999)),
-		});
+			full_signature: Signature(999, 8),
+			digest_signature: Signature(999, 8),
+			round_number: 1,
+			proposal: Candidate(999),
+			digest: Digest(999),
+		})).unwrap();
 
 		assert_eq!(accumulator.state(), &State::Proposed(Candidate(999)));
 
 		for i in 0..7 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Prepare(1, Digest(999)),
-			});
+				vote: Vote::Prepare(1, Digest(999)),
+			}.into()).unwrap();
 		}
 
 		match accumulator.state() {
@@ -513,11 +608,11 @@ mod tests {
 		}
 
 		for i in 0..6 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::AdvanceRound(1),
-			});
+				vote: Vote::AdvanceRound(1),
+			}.into()).unwrap();
 
 			match accumulator.state() {
 				&State::Prepared(_) => {},
@@ -525,11 +620,11 @@ mod tests {
 			}
 		}
 
-		accumulator.import_message(LocalizedMessage {
+		accumulator.import_message(LocalizedVote {
 			sender: AuthorityId(7),
 			signature: Signature(999, 7),
-			message: Message::AdvanceRound(1),
-		});
+			vote: Vote::AdvanceRound(1),
+		}.into()).unwrap();
 
 		match accumulator.state() {
 			&State::Advanced(Some(_)) => {},
@@ -543,11 +638,11 @@ mod tests {
 		assert_eq!(accumulator.state(), &State::Begin);
 
 		for i in 0..7 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Prepare(1, Digest(999)),
-			});
+				vote: Vote::Prepare(1, Digest(999)),
+			}.into()).unwrap();
 		}
 
 		match accumulator.state() {
@@ -556,11 +651,11 @@ mod tests {
 		}
 
 		for i in 0..7 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Commit(1, Digest(999)),
-			});
+				vote: Vote::Commit(1, Digest(999)),
+			}.into()).unwrap();
 		}
 
 		match accumulator.state() {
@@ -575,11 +670,11 @@ mod tests {
 		assert_eq!(accumulator.state(), &State::Begin);
 
 		for i in 0..7 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(1, i),
-				message: Message::AdvanceRound(1),
-			});
+				vote: Vote::AdvanceRound(1),
+			}.into()).unwrap();
 		}
 
 		match accumulator.state() {
@@ -594,11 +689,11 @@ mod tests {
 		assert_eq!(accumulator.state(), &State::Begin);
 
 		for i in 0..7 {
-			accumulator.import_message(LocalizedMessage {
+			accumulator.import_message(LocalizedVote {
 				sender: AuthorityId(i),
 				signature: Signature(999, i),
-				message: Message::Commit(1, Digest(999)),
-			});
+				vote: Vote::Commit(1, Digest(999)),
+			}.into()).unwrap();
 		}
 
 		match accumulator.state() {
@@ -606,4 +701,76 @@ mod tests {
 			s => panic!("wrong state: {:?}", s),
 		}
 	}
+
+	#[test]
+	fn double_prepare_is_misbehavior() {
+		let mut accumulator = Accumulator::<Candidate, _, _, _>::new(1, 7, AuthorityId(8));
+		assert_eq!(accumulator.state(), &State::Begin);
+
+		for i in 0..7 {
+			accumulator.import_message(LocalizedVote {
+				sender: AuthorityId(i),
+				signature: Signature(999, i),
+				vote: Vote::Prepare(1, Digest(999)),
+			}.into()).unwrap();
+
+			let res = accumulator.import_message(LocalizedVote {
+				sender: AuthorityId(i),
+				signature: Signature(123, i),
+				vote: Vote::Prepare(1, Digest(123)),
+			}.into());
+
+			assert!(res.is_err());
+
+		}
+	}
+
+	#[test]
+	fn double_commit_is_misbehavior() {
+		let mut accumulator = Accumulator::<Candidate, _, _, _>::new(1, 7, AuthorityId(8));
+		assert_eq!(accumulator.state(), &State::Begin);
+
+		for i in 0..7 {
+			accumulator.import_message(LocalizedVote {
+				sender: AuthorityId(i),
+				signature: Signature(999, i),
+				vote: Vote::Commit(1, Digest(999)),
+			}.into()).unwrap();
+
+			let res = accumulator.import_message(LocalizedVote {
+				sender: AuthorityId(i),
+				signature: Signature(123, i),
+				vote: Vote::Commit(1, Digest(123)),
+			}.into());
+
+			assert!(res.is_err());
+
+		}
+	}
+
+	#[test]
+	fn double_propose_is_misbehavior() {
+		let mut accumulator = Accumulator::<Candidate, _, _, _>::new(1, 7, AuthorityId(8));
+		assert_eq!(accumulator.state(), &State::Begin);
+
+		accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
+			sender: AuthorityId(8),
+			full_signature: Signature(999, 8),
+			digest_signature: Signature(999, 8),
+			round_number: 1,
+			proposal: Candidate(999),
+			digest: Digest(999),
+		})).unwrap();
+
+		let res = accumulator.import_message(LocalizedMessage::Propose(LocalizedProposal {
+			sender: AuthorityId(8),
+			full_signature: Signature(500, 8),
+			digest_signature: Signature(500, 8),
+			round_number: 1,
+			proposal: Candidate(500),
+			digest: Digest(500),
+		}));
+
+		assert!(res.is_err());
+	}
 }
diff --git a/substrate/substrate/bft/src/generic/mod.rs b/substrate/substrate/bft/src/generic/mod.rs
index 4ebe508e36b0b1528a8858f2a008b170c64c1a82..aa0fe2c549a3fec73750e002a28bd5fe2686e875 100644
--- a/substrate/substrate/bft/src/generic/mod.rs
+++ b/substrate/substrate/bft/src/generic/mod.rs
@@ -18,6 +18,7 @@
 //! Very general implementation.
 
 use std::collections::{HashMap, VecDeque};
+use std::collections::hash_map;
 use std::fmt::Debug;
 use std::hash::Hash;
 
@@ -25,19 +26,16 @@ use futures::{future, Future, Stream, Sink, Poll, Async, AsyncSink};
 
 use self::accumulator::State;
 
-pub use self::accumulator::{Accumulator, Justification, PrepareJustification, UncheckedJustification};
+pub use self::accumulator::{Accumulator, Justification, PrepareJustification, UncheckedJustification, Misbehavior};
 
 mod accumulator;
 
 #[cfg(test)]
 mod tests;
 
-/// Messages over the proposal.
-/// Each message carries an associated round number.
+/// Votes during a round.
 #[derive(Debug, Clone, PartialEq, Eq)]
-pub enum Message<C, D> {
-	/// Send a full proposal.
-	Propose(usize, C),
+pub enum Vote<D> {
 	/// Prepare to vote for proposal with digest D.
 	Prepare(usize, D),
 	/// Commit to proposal with digest D..
@@ -46,29 +44,94 @@ pub enum Message<C, D> {
 	AdvanceRound(usize),
 }
 
-impl<C, D> Message<C, D> {
+impl<D> Vote<D> {
 	/// Extract the round number.
 	pub fn round_number(&self) -> usize {
 		match *self {
-			Message::Propose(round, _) => round,
-			Message::Prepare(round, _) => round,
-			Message::Commit(round, _) => round,
-			Message::AdvanceRound(round) => round,
+			Vote::Prepare(round, _) => round,
+			Vote::Commit(round, _) => round,
+			Vote::AdvanceRound(round) => round,
 		}
 	}
 }
 
-/// A localized message, including the sender.
+/// Messages over the proposal.
+/// Each message carries an associated round number.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub enum Message<C, D> {
+	/// A proposal itself.
+	Propose(usize, C),
+	/// A vote of some kind, localized to a round number.
+	Vote(Vote<D>),
+}
+
+impl<C, D> From<Vote<D>> for Message<C, D> {
+	fn from(vote: Vote<D>) -> Self {
+		Message::Vote(vote)
+	}
+}
+
+/// A localized proposal message. Contains two signed pieces of data.
+#[derive(Debug, Clone)]
+pub struct LocalizedProposal<C, D, V, S> {
+	/// The round number.
+	pub round_number: usize,
+	/// The proposal sent.
+	pub proposal: C,
+	/// The digest of the proposal.
+	pub digest: D,
+	/// The sender of the proposal
+	pub sender: V,
+	/// The signature on the message (propose, round number, digest)
+	pub digest_signature: S,
+	/// The signature on the message (propose, round number, proposal)
+	pub full_signature: S,
+}
+
+/// A localized vote message, including the sender.
 #[derive(Debug, Clone)]
-pub struct LocalizedMessage<C, D, V, S> {
-	/// The message received.
-	pub message: Message<C, D>,
+pub struct LocalizedVote<D, V, S> {
+	/// The message sent.
+	pub vote: Vote<D>,
 	/// The sender of the message
 	pub sender: V,
 	/// The signature of the message.
 	pub signature: S,
 }
 
+/// A localized message.
+#[derive(Debug, Clone)]
+pub enum LocalizedMessage<C, D, V, S> {
+	/// A proposal.
+	Propose(LocalizedProposal<C, D, V, S>),
+	/// A vote.
+	Vote(LocalizedVote<D, V, S>),
+}
+
+impl<C, D, V, S> LocalizedMessage<C, D, V, S> {
+	/// Extract the sender.
+	pub fn sender(&self) -> &V {
+		match *self {
+			LocalizedMessage::Propose(ref proposal) => &proposal.sender,
+			LocalizedMessage::Vote(ref vote) => &vote.sender,
+		}
+	}
+
+	/// Extract the round number.
+	pub fn round_number(&self) -> usize {
+		match *self {
+			LocalizedMessage::Propose(ref proposal) => proposal.round_number,
+			LocalizedMessage::Vote(ref vote) => vote.vote.round_number(),
+		}
+	}
+}
+
+impl<C, D, V, S> From<LocalizedVote<D, V, S>> for LocalizedMessage<C, D, V, S> {
+	fn from(vote: LocalizedVote<D, V, S>) -> Self {
+		LocalizedMessage::Vote(vote)
+	}
+}
+
 /// Context necessary for agreement.
 ///
 /// Provides necessary types for protocol messages, and functions necessary for a
@@ -101,6 +164,8 @@ pub trait Context {
 	fn candidate_digest(&self, candidate: &Self::Candidate) -> Self::Digest;
 
 	/// Sign a message using the local authority ID.
+	/// In the case of a proposal message, it should sign on the hash and
+	/// the bytes of the proposal.
 	fn sign_local(&self, message: Message<Self::Candidate, Self::Digest>)
 		-> LocalizedMessage<Self::Candidate, Self::Digest, Self::AuthorityId, Self::Signature>;
 
@@ -258,6 +323,7 @@ struct Strategy<C: Context> {
 	current_accumulator: Accumulator<C::Candidate, C::Digest, C::AuthorityId, C::Signature>,
 	future_accumulator: Accumulator<C::Candidate, C::Digest, C::AuthorityId, C::Signature>,
 	local_id: C::AuthorityId,
+	misbehavior: HashMap<C::AuthorityId, Misbehavior<C::Digest, C::Signature>>,
 }
 
 impl<C: Context> Strategy<C> {
@@ -289,6 +355,7 @@ impl<C: Context> Strategy<C> {
 			notable_candidates: HashMap::new(),
 			round_timeout: timeout.fuse(),
 			local_id: context.local_id(),
+			misbehavior: HashMap::new(),
 		}
 	}
 
@@ -296,12 +363,19 @@ impl<C: Context> Strategy<C> {
 		&mut self,
 		msg: LocalizedMessage<C::Candidate, C::Digest, C::AuthorityId, C::Signature>
 	) {
-		let round_number = msg.message.round_number();
+		let round_number = msg.round_number();
 
-		if round_number == self.current_accumulator.round_number() {
-			self.current_accumulator.import_message(msg);
+		let sender = msg.sender().clone();
+		let misbehavior = if round_number == self.current_accumulator.round_number() {
+			self.current_accumulator.import_message(msg)
 		} else if round_number == self.future_accumulator.round_number() {
-			self.future_accumulator.import_message(msg);
+			self.future_accumulator.import_message(msg)
+		} else {
+			Ok(())
+		};
+
+		if let Err(misbehavior) = misbehavior {
+			self.misbehavior.insert(sender, misbehavior);
 		}
 	}
 
@@ -526,10 +600,10 @@ impl<C: Context> Strategy<C> {
 		}
 
 		if let Some(digest) = prepare_for {
-			let message = Message::Prepare(
+			let message = Vote::Prepare(
 				self.current_accumulator.round_number(),
 				digest
-			);
+			).into();
 
 			self.import_and_send_message(message, context, sending);
 			self.local_state = LocalState::Prepared;
@@ -559,10 +633,10 @@ impl<C: Context> Strategy<C> {
 		}
 
 		if let Some(digest) = commit_for {
-			let message = Message::Commit(
+			let message = Vote::Commit(
 				self.current_accumulator.round_number(),
 				digest
-			);
+			).into();
 
 			self.import_and_send_message(message, context, sending);
 			self.local_state = LocalState::Committed;
@@ -588,9 +662,9 @@ impl<C: Context> Strategy<C> {
 		}
 
 		if attempt_advance {
-			let message = Message::AdvanceRound(
+			let message = Vote::AdvanceRound(
 				self.current_accumulator.round_number(),
-			);
+			).into();
 
 			self.import_and_send_message(message, context, sending);
 			self.local_state = LocalState::VoteAdvance;
@@ -715,6 +789,18 @@ impl<C, I, O> Future for Agreement<C, I, O>
 	}
 }
 
+impl<C: Context, I, O> Agreement<C, I, O> {
+	/// Get a reference to the underlying context.
+	pub fn context(&self) -> &C {
+		&self.context
+	}
+
+	/// Drain the misbehavior vector.
+	pub fn drain_misbehavior(&mut self) -> hash_map::Drain<C::AuthorityId, Misbehavior<C::Digest, C::Signature>> {
+		self.strategy.misbehavior.drain()
+	}
+}
+
 /// Attempt to reach BFT agreement on a candidate.
 ///
 /// `nodes` is the number of nodes in the system.
diff --git a/substrate/substrate/bft/src/generic/tests.rs b/substrate/substrate/bft/src/generic/tests.rs
index c64907cbeef770208cfc6433022a28968964c31a..349bec693f95da0b59fde534e03261140a471ab5 100644
--- a/substrate/substrate/bft/src/generic/tests.rs
+++ b/substrate/substrate/bft/src/generic/tests.rs
@@ -191,10 +191,21 @@ impl Context for TestContext {
 		-> LocalizedMessage<Candidate, Digest, AuthorityId, Signature>
 	{
 		let signature = Signature(message.clone(), self.local_id.clone());
-		LocalizedMessage {
-			message,
-			signature,
-			sender: self.local_id.clone()
+
+		match message {
+			Message::Propose(r, proposal) => LocalizedMessage::Propose(LocalizedProposal {
+				round_number: r,
+				digest: Digest(proposal.0),
+				proposal,
+				digest_signature: signature.clone(),
+				full_signature: signature,
+				sender: self.local_id.clone(),
+			}),
+			Message::Vote(vote) => LocalizedMessage::Vote(LocalizedVote {
+				vote,
+				signature,
+				sender: self.local_id.clone(),
+			}),
 		}
 	}
 
@@ -333,7 +344,7 @@ fn threshold_plus_one_locked_on_proposal_only_one_with_candidate() {
 		round_number: locked_round,
 		digest: locked_digest.clone(),
 		signatures: (0..7)
-			.map(|i| Signature(Message::Prepare(locked_round, locked_digest.clone()), AuthorityId(i)))
+			.map(|i| Signature(Message::Vote(Vote::Prepare(locked_round, locked_digest.clone())), AuthorityId(i)))
 			.collect()
 	}.check(7, |_, _, s| Some(s.1.clone())).unwrap();
 
diff --git a/substrate/substrate/bft/src/lib.rs b/substrate/substrate/bft/src/lib.rs
index 977245e26f4eee63b8e6a1fe2fa75aed65876339..f9d870799d38cda2468d1f6e0e0d86351d2b322a 100644
--- a/substrate/substrate/bft/src/lib.rs
+++ b/substrate/substrate/bft/src/lib.rs
@@ -100,6 +100,9 @@ pub type Committed = generic::Committed<Block, HeaderHash, LocalizedSignature>;
 /// Communication between BFT participants.
 pub type Communication = generic::Communication<Block, HeaderHash, AuthorityId, LocalizedSignature>;
 
+/// Misbehavior observed from BFT participants.
+pub type Misbehavior = generic::Misbehavior<HeaderHash, LocalizedSignature>;
+
 /// Proposer factory. Can be used to create a proposer instance.
 pub trait ProposerFactory {
 	/// The proposer type this creates.
@@ -129,6 +132,8 @@ pub trait Proposer {
 	/// Evaluate proposal. True means valid.
 	// TODO: change this to a future.
 	fn evaluate(&self, proposal: &Block) -> Self::Evaluate;
+	/// Import witnessed misbehavior.
+	fn import_misbehavior(&self, misbehavior: Vec<(AuthorityId, Misbehavior)>);
 }
 
 /// Block import trait.
@@ -269,6 +274,14 @@ impl<P: Proposer, I: BlockImport> Future for BftFuture<P, I> {
 	}
 }
 
+impl<P: Proposer, I> Drop for BftFuture<P, I> {
+	fn drop(&mut self) {
+		// TODO: have a trait member to pass misbehavior reports into.
+		let misbehavior = self.inner.drain_misbehavior().collect::<Vec<_>>();
+		self.inner.context().proposer.import_misbehavior(misbehavior);
+	}
+}
+
 struct AgreementHandle {
 	cancel: Arc<AtomicBool>,
 	task: Option<oneshot::Receiver<task::Task>>,
@@ -317,7 +330,6 @@ impl<P, E, I> BftService<P, E, I>
 
 		let authorities = self.client.authorities(&BlockId::Hash(hash))?;
 
-		// TODO: check key is one of the authorities.
 		let n = authorities.len();
 		let max_faulty = max_faulty_of(n);
 
@@ -426,28 +438,49 @@ pub fn check_prepare_justification(authorities: &[AuthorityId], parent: HeaderHa
 
 /// Sign a BFT message with the given key.
 pub fn sign_message(message: Message, key: &ed25519::Pair, parent_hash: HeaderHash) -> LocalizedMessage {
-	let action = match message.clone() {
-		::generic::Message::Propose(r, p) => PrimitiveAction::Propose(r as u32, p),
-		::generic::Message::Prepare(r, h) => PrimitiveAction::Prepare(r as u32, h),
-		::generic::Message::Commit(r, h) => PrimitiveAction::Commit(r as u32, h),
-		::generic::Message::AdvanceRound(r) => PrimitiveAction::AdvanceRound(r as u32),
-	};
+	let signer = key.public();
 
-	let primitive = PrimitiveMessage {
-		parent: parent_hash,
-		action,
-	};
+	let sign_action = |action| {
+		let primitive = PrimitiveMessage {
+			parent: parent_hash,
+			action,
+		};
 
-	let to_sign = Slicable::encode(&primitive);
-	let signature = LocalizedSignature {
-		signer: key.public(),
-		signature: key.sign(&to_sign),
+		let to_sign = Slicable::encode(&primitive);
+		LocalizedSignature {
+			signer: signer.clone(),
+			signature: key.sign(&to_sign),
+		}
 	};
 
-	LocalizedMessage {
-		message,
-		signature,
-		sender: key.public().0
+	match message {
+		::generic::Message::Propose(r, proposal) => {
+			let header_hash = proposal.header.hash();
+			let action_header = PrimitiveAction::ProposeHeader(r as u32, header_hash.clone());
+			let action_propose = PrimitiveAction::Propose(r as u32, proposal.clone());
+
+			::generic::LocalizedMessage::Propose(::generic::LocalizedProposal {
+				round_number: r,
+				proposal,
+				digest: header_hash,
+				sender: signer.0,
+				digest_signature: sign_action(action_header),
+				full_signature: sign_action(action_propose),
+			})
+		}
+		::generic::Message::Vote(vote) => {
+			let action = match vote {
+				::generic::Vote::Prepare(r, h) => PrimitiveAction::Prepare(r as u32, h),
+				::generic::Vote::Commit(r, h) => PrimitiveAction::Commit(r as u32, h),
+				::generic::Vote::AdvanceRound(r) => PrimitiveAction::AdvanceRound(r as u32),
+			};
+
+			::generic::LocalizedMessage::Vote(::generic::LocalizedVote {
+				vote: vote,
+				sender: signer.0,
+				signature: sign_action(action),
+			})
+		}
 	}
 }
 
@@ -506,6 +539,8 @@ mod tests {
 		fn evaluate(&self, proposal: &Block) -> Result<bool, Error> {
 			Ok(proposal.header.number == self.0)
 		}
+
+		fn import_misbehavior(&self, _misbehavior: Vec<(AuthorityId, Misbehavior)>) {}
 	}
 
 	fn make_service(client: FakeClient, handle: Handle)
@@ -522,6 +557,13 @@ mod tests {
 		}
 	}
 
+	fn sign_vote(vote: ::generic::Vote<HeaderHash>, key: &ed25519::Pair, parent_hash: HeaderHash) -> LocalizedSignature {
+		match sign_message(vote.into(), key, parent_hash) {
+			::generic::LocalizedMessage::Vote(vote) => vote.signature,
+			_ => panic!("signing vote leads to signed vote"),
+		}
+	}
+
 	#[test]
 	fn future_gets_preempted() {
 		let client = FakeClient {
@@ -591,7 +633,7 @@ mod tests {
 			digest: hash,
 			round_number: 1,
 			signatures: authorities_keys.iter().take(3).map(|key| {
-				sign_message(generic::Message::Commit(1, hash), key, parent_hash).signature
+				sign_vote(generic::Vote::Commit(1, hash).into(), key, parent_hash)
 			}).collect(),
 		};
 
@@ -601,7 +643,7 @@ mod tests {
 			digest: hash,
 			round_number: 0, // wrong round number (vs. the signatures)
 			signatures: authorities_keys.iter().take(3).map(|key| {
-				sign_message(generic::Message::Commit(1, hash), key, parent_hash).signature
+				sign_vote(generic::Vote::Commit(1, hash).into(), key, parent_hash)
 			}).collect(),
 		};
 
@@ -612,7 +654,7 @@ mod tests {
 			digest: hash,
 			round_number: 1,
 			signatures: authorities_keys.iter().take(2).map(|key| {
-				sign_message(generic::Message::Commit(1, hash), key, parent_hash).signature
+				sign_vote(generic::Vote::Commit(1, hash).into(), key, parent_hash)
 			}).collect(),
 		};
 
@@ -623,7 +665,7 @@ mod tests {
 			digest: [0xfe; 32].into(),
 			round_number: 1,
 			signatures: authorities_keys.iter().take(3).map(|key| {
-				sign_message(generic::Message::Commit(1, hash), key, parent_hash).signature
+				sign_vote(generic::Vote::Commit(1, hash).into(), key, parent_hash)
 			}).collect(),
 		};
 
diff --git a/substrate/substrate/client/src/client.rs b/substrate/substrate/client/src/client.rs
index 3ccc9debff5b438a91fe00f272ee22f634a63ad3..402a67ef2a7767ed78b0f8ec61583076bb116bed 100644
--- a/substrate/substrate/client/src/client.rs
+++ b/substrate/substrate/client/src/client.rs
@@ -393,11 +393,16 @@ mod tests {
 		bft::UncheckedJustification {
 			digest: hash,
 			signatures: authorities.iter().map(|key| {
-				bft::sign_message(
-					bft::generic::Message::Commit(1, hash),
+				let msg = bft::sign_message(
+					bft::generic::Vote::Commit(1, hash).into(),
 					key,
 					header.parent_hash
-				).signature
+				);
+
+				match msg {
+					bft::generic::LocalizedMessage::Vote(vote) => vote.signature,
+					_ => panic!("signing vote leads to signed vote"),
+				}
 			}).collect(),
 			round_number: 1,
 		}
diff --git a/substrate/substrate/keyring/src/lib.rs b/substrate/substrate/keyring/src/lib.rs
index 572e6775e6fe4dee70c134387eec66b42f425c3f..9749ef13449cf62cd2f5cd23a61a9cb6d0a605c0 100644
--- a/substrate/substrate/keyring/src/lib.rs
+++ b/substrate/substrate/keyring/src/lib.rs
@@ -18,7 +18,7 @@
 
 #[macro_use] extern crate hex_literal;
 #[macro_use] extern crate lazy_static;
-extern crate ed25519;
+pub extern crate ed25519;
 
 use std::collections::HashMap;
 use std::ops::Deref;
diff --git a/substrate/substrate/misbehavior-check/Cargo.toml b/substrate/substrate/misbehavior-check/Cargo.toml
new file mode 100644
index 0000000000000000000000000000000000000000..58d27f45c7e206862e0a1d78a4c391db9a69da12
--- /dev/null
+++ b/substrate/substrate/misbehavior-check/Cargo.toml
@@ -0,0 +1,17 @@
+[package]
+name = "substrate-misbehavior-check"
+version = "0.1.0"
+authors = ["Parity Technologies <admin@parity.io>"]
+
+[dependencies]
+substrate-codec = { path = "../codec", default-features = false }
+substrate-primitives = { path = "../primitives", default-features = false }
+substrate-runtime-io = { path = "../runtime-io", default-features = false }
+
+[dev-dependencies]
+substrate-bft = { path = "../bft" }
+substrate-keyring = { path = "../keyring" }
+
+[features]
+default = ["std"]
+std = ["substrate-codec/std", "substrate-primitives/std", "substrate-runtime-io/std"]
diff --git a/substrate/substrate/misbehavior-check/src/lib.rs b/substrate/substrate/misbehavior-check/src/lib.rs
new file mode 100644
index 0000000000000000000000000000000000000000..71236ef457ee6f3f6306bc2dddc01c763999e359
--- /dev/null
+++ b/substrate/substrate/misbehavior-check/src/lib.rs
@@ -0,0 +1,194 @@
+// Copyright 2017 Parity Technologies (UK) Ltd.
+// This file is part of Polkadot.
+
+// Polkadot is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Polkadot is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
+
+//! Utility for substrate-based runtimes that want to check misbehavior reports.
+
+#![cfg_attr(not(feature = "std"), no_std)]
+
+extern crate substrate_codec as codec;
+extern crate substrate_primitives as primitives;
+extern crate substrate_runtime_io as runtime_io;
+
+#[cfg(test)]
+extern crate substrate_bft;
+#[cfg(test)]
+extern crate substrate_keyring as keyring;
+
+use codec::Slicable;
+use primitives::{AuthorityId, Signature};
+use primitives::block::HeaderHash;
+use	primitives::bft::{Action, Message, MisbehaviorKind};
+
+// check a message signature. returns true if signed by that authority.
+fn check_message_sig(message: Message, signature: &Signature, from: &AuthorityId) -> bool {
+	let msg = message.encode();
+	runtime_io::ed25519_verify(&signature.0, &msg, from)
+}
+
+fn prepare(parent: HeaderHash, round_number: u32, hash: HeaderHash) -> Message {
+	Message {
+		parent,
+		action: Action::Prepare(round_number, hash),
+	}
+}
+
+fn commit(parent: HeaderHash, round_number: u32, hash: HeaderHash) -> Message {
+	Message {
+		parent,
+		action: Action::Commit(round_number, hash),
+	}
+}
+
+/// Evaluate misbehavior.
+///
+/// Doesn't check that the header hash in question is
+/// valid or whether the misbehaving authority was part of
+/// the set at that block.
+pub fn evaluate_misbehavior(
+	misbehaved: &AuthorityId,
+	parent_hash: HeaderHash,
+	kind: &MisbehaviorKind,
+) -> bool {
+	match *kind {
+		MisbehaviorKind::BftDoublePrepare(round, (h_1, ref s_1), (h_2, ref s_2)) => {
+			s_1 != s_2 &&
+			check_message_sig(prepare(parent_hash, round, h_1), s_1, misbehaved) &&
+			check_message_sig(prepare(parent_hash, round, h_2), s_2, misbehaved)
+		}
+		MisbehaviorKind::BftDoubleCommit(round, (h_1, ref s_1), (h_2, ref s_2)) => {
+			s_1 != s_2 &&
+			check_message_sig(commit(parent_hash, round, h_1), s_1, misbehaved) &&
+			check_message_sig(commit(parent_hash, round, h_2), s_2, misbehaved)
+		}
+	}
+}
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+
+	use substrate_bft::generic;
+	use keyring::ed25519;
+	use keyring::Keyring;
+
+	fn sign_prepare(key: &ed25519::Pair, round: u32, hash: HeaderHash, parent_hash: HeaderHash) -> (HeaderHash, Signature) {
+		let msg = substrate_bft::sign_message(
+			generic::Message::Vote(generic::Vote::Prepare(round as _, hash)),
+			key,
+			parent_hash
+		);
+
+		match msg {
+			generic::LocalizedMessage::Vote(vote) => (hash, vote.signature.signature),
+			_ => panic!("signing vote leads to signed vote"),
+		}
+	}
+
+	fn sign_commit(key: &ed25519::Pair, round: u32, hash: HeaderHash, parent_hash: HeaderHash) -> (HeaderHash, Signature) {
+		let msg = substrate_bft::sign_message(
+			generic::Message::Vote(generic::Vote::Commit(round as _, hash)),
+			key,
+			parent_hash
+		);
+
+		match msg {
+			generic::LocalizedMessage::Vote(vote) => (hash, vote.signature.signature),
+			_ => panic!("signing vote leads to signed vote"),
+		}
+	}
+
+	#[test]
+	fn evaluates_double_prepare() {
+		let key: ed25519::Pair = Keyring::One.into();
+		let parent_hash = [0xff; 32].into();
+		let hash_1 = [0; 32].into();
+		let hash_2 = [1; 32].into();
+
+		assert!(evaluate_misbehavior(
+			&key.public().0,
+			parent_hash,
+			&MisbehaviorKind::BftDoublePrepare(
+				1,
+				sign_prepare(&key, 1, hash_1, parent_hash),
+				sign_prepare(&key, 1, hash_2, parent_hash)
+			)
+		));
+
+		// same signature twice is not misbehavior.
+		let signed = sign_prepare(&key, 1, hash_1, parent_hash);
+		assert!(evaluate_misbehavior(
+			&key.public().0,
+			parent_hash,
+			&MisbehaviorKind::BftDoublePrepare(
+				1,
+				signed,
+				signed,
+			)
+		) == false);
+
+		// misbehavior has wrong target.
+		assert!(evaluate_misbehavior(
+			&Keyring::Two.to_raw_public(),
+			parent_hash,
+			&MisbehaviorKind::BftDoublePrepare(
+				1,
+				sign_prepare(&key, 1, hash_1, parent_hash),
+				sign_prepare(&key, 1, hash_2, parent_hash),
+			)
+		) == false);
+	}
+
+	#[test]
+	fn evaluates_double_commit() {
+		let key: ed25519::Pair = Keyring::One.into();
+		let parent_hash = [0xff; 32].into();
+		let hash_1 = [0; 32].into();
+		let hash_2 = [1; 32].into();
+
+		assert!(evaluate_misbehavior(
+			&key.public().0,
+			parent_hash,
+			&MisbehaviorKind::BftDoubleCommit(
+				1,
+				sign_commit(&key, 1, hash_1, parent_hash),
+				sign_commit(&key, 1, hash_2, parent_hash)
+			)
+		));
+
+		// same signature twice is not misbehavior.
+		let signed = sign_commit(&key, 1, hash_1, parent_hash);
+		assert!(evaluate_misbehavior(
+			&key.public().0,
+			parent_hash,
+			&MisbehaviorKind::BftDoubleCommit(
+				1,
+				signed,
+				signed,
+			)
+		) == false);
+
+		// misbehavior has wrong target.
+		assert!(evaluate_misbehavior(
+			&Keyring::Two.to_raw_public(),
+			parent_hash,
+			&MisbehaviorKind::BftDoubleCommit(
+				1,
+				sign_commit(&key, 1, hash_1, parent_hash),
+				sign_commit(&key, 1, hash_2, parent_hash),
+			)
+		) == false);
+	}
+}
diff --git a/substrate/substrate/network/src/test/mod.rs b/substrate/substrate/network/src/test/mod.rs
index 4cddc1bf8af8e609b2ca79c364bc7694949a3437..8aac22f16ee7de52fbad395d084d7be84c9f696c 100644
--- a/substrate/substrate/network/src/test/mod.rs
+++ b/substrate/substrate/network/src/test/mod.rs
@@ -167,11 +167,16 @@ impl Peer {
 		bft::UncheckedJustification {
 			digest: hash,
 			signatures: authorities.iter().map(|key| {
-				bft::sign_message(
-					bft::generic::Message::Commit(1, hash),
+				let msg = bft::sign_message(
+					bft::generic::Vote::Commit(1, hash).into(),
 					key,
 					header.parent_hash
-				).signature
+				);
+
+				match msg {
+					bft::generic::LocalizedMessage::Vote(vote) => vote.signature,
+					_ => panic!("signing vote leads to signed vote"),
+				}
 			}).collect(),
 			round_number: 1,
 		}
diff --git a/substrate/substrate/primitives/src/bft.rs b/substrate/substrate/primitives/src/bft.rs
index 49e14075285bf4c8b6069553a6aeed1cb3bb51f6..717ff8a4242ad35995a3189e37a196e20160348d 100644
--- a/substrate/substrate/primitives/src/bft.rs
+++ b/substrate/substrate/primitives/src/bft.rs
@@ -19,15 +19,17 @@
 use block::{Block, HeaderHash};
 use codec::{Slicable, Input};
 use rstd::vec::Vec;
+use ::{AuthorityId, Signature};
 
 #[derive(Clone, Copy, PartialEq, Eq)]
 #[cfg_attr(feature = "std", derive(Debug))]
 #[repr(u8)]
 enum ActionKind {
 	Propose = 1,
-	Prepare = 2,
-	Commit = 3,
-	AdvanceRound = 4,
+	ProposeHeader = 2,
+	Prepare = 3,
+	Commit = 4,
+	AdvanceRound = 5,
 }
 
 /// Actions which can be taken during the BFT process.
@@ -36,6 +38,9 @@ enum ActionKind {
 pub enum Action {
 	/// Proposal of a block candidate.
 	Propose(u32, Block),
+	/// Proposal header of a block candidate. Accompanies any proposal,
+	/// but is used for misbehavior reporting since blocks themselves are big.
+	ProposeHeader(u32, HeaderHash),
 	/// Preparation to commit for a candidate.
 	Prepare(u32, HeaderHash),
 	/// Vote to commit to a candidate.
@@ -53,6 +58,11 @@ impl Slicable for Action {
 				round.using_encoded(|s| v.extend(s));
 				block.using_encoded(|s| v.extend(s));
 			}
+			Action::ProposeHeader(ref round, ref hash) => {
+				v.push(ActionKind::ProposeHeader as u8);
+				round.using_encoded(|s| v.extend(s));
+				hash.using_encoded(|s| v.extend(s));
+			}
 			Action::Prepare(ref round, ref hash) => {
 				v.push(ActionKind::Prepare as u8);
 				round.using_encoded(|s| v.extend(s));
@@ -78,6 +88,11 @@ impl Slicable for Action {
 				let (round, block) = try_opt!(Slicable::decode(value));
 				Some(Action::Propose(round, block))
 			}
+			Some(x) if x == ActionKind::ProposeHeader as u8 => {
+				let (round, hash) = try_opt!(Slicable::decode(value));
+
+				Some(Action::ProposeHeader(round, hash))
+			}
 			Some(x) if x == ActionKind::Prepare as u8 => {
 				let (round, hash) = try_opt!(Slicable::decode(value));
 
@@ -152,3 +167,142 @@ impl Slicable for Justification {
 		})
 	}
 }
+
+// single-byte code to represent misbehavior kind.
+#[repr(u8)]
+enum MisbehaviorCode {
+	/// BFT: double prepare.
+	BftDoublePrepare = 0x11,
+	/// BFT: double commit.
+	BftDoubleCommit = 0x12,
+}
+
+impl MisbehaviorCode {
+	fn from_u8(x: u8) -> Option<Self> {
+		match x {
+			0x11 => Some(MisbehaviorCode::BftDoublePrepare),
+			0x12 => Some(MisbehaviorCode::BftDoubleCommit),
+			_ => None,
+		}
+	}
+}
+
+/// Misbehavior kinds.
+#[derive(Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
+pub enum MisbehaviorKind {
+	/// BFT: double prepare.
+	BftDoublePrepare(u32, (HeaderHash, Signature), (HeaderHash, Signature)),
+	/// BFT: double commit.
+	BftDoubleCommit(u32, (HeaderHash, Signature), (HeaderHash, Signature)),
+}
+
+/// A report of misbehavior by an authority.
+#[derive(Clone, PartialEq, Eq)]
+#[cfg_attr(feature = "std", derive(Debug, Serialize, Deserialize))]
+pub struct MisbehaviorReport {
+	/// The parent hash of the block where the misbehavior occurred.
+	pub parent_hash: HeaderHash,
+	/// The parent number of the block where the misbehavior occurred.
+	pub parent_number: ::block::Number,
+	/// The authority who misbehavior.
+	pub target: AuthorityId,
+	/// The misbehavior kind.
+	pub misbehavior: MisbehaviorKind,
+}
+
+impl Slicable for MisbehaviorReport {
+	fn encode(&self) -> Vec<u8> {
+		let mut v = Vec::new();
+		self.parent_hash.using_encoded(|s| v.extend(s));
+		self.parent_number.using_encoded(|s| v.extend(s));
+		self.target.using_encoded(|s| v.extend(s));
+
+		match self.misbehavior {
+			MisbehaviorKind::BftDoublePrepare(ref round, (ref h_a, ref s_a), (ref h_b, ref s_b)) => {
+				(MisbehaviorCode::BftDoublePrepare as u8).using_encoded(|s| v.extend(s));
+				round.using_encoded(|s| v.extend(s));
+				h_a.using_encoded(|s| v.extend(s));
+				s_a.using_encoded(|s| v.extend(s));
+				h_b.using_encoded(|s| v.extend(s));
+				s_b.using_encoded(|s| v.extend(s));
+			}
+			MisbehaviorKind::BftDoubleCommit(ref round, (ref h_a, ref s_a), (ref h_b, ref s_b)) => {
+				(MisbehaviorCode::BftDoubleCommit as u8).using_encoded(|s| v.extend(s));
+				round.using_encoded(|s| v.extend(s));
+				h_a.using_encoded(|s| v.extend(s));
+				s_a.using_encoded(|s| v.extend(s));
+				h_b.using_encoded(|s| v.extend(s));
+				s_b.using_encoded(|s| v.extend(s));
+			}
+		}
+
+		v
+	}
+
+	fn decode<I: Input>(input: &mut I) -> Option<Self> {
+		let parent_hash = HeaderHash::decode(input)?;
+		let parent_number = ::block::Number::decode(input)?;
+		let target = AuthorityId::decode(input)?;
+
+		let misbehavior = match u8::decode(input).and_then(MisbehaviorCode::from_u8)? {
+			MisbehaviorCode::BftDoublePrepare => {
+				MisbehaviorKind::BftDoublePrepare(
+					u32::decode(input)?,
+					(HeaderHash::decode(input)?, Signature::decode(input)?),
+					(HeaderHash::decode(input)?, Signature::decode(input)?),
+				)
+			}
+			MisbehaviorCode::BftDoubleCommit => {
+				MisbehaviorKind::BftDoubleCommit(
+					u32::decode(input)?,
+					(HeaderHash::decode(input)?, Signature::decode(input)?),
+					(HeaderHash::decode(input)?, Signature::decode(input)?),
+				)
+			}
+		};
+
+		Some(MisbehaviorReport {
+			parent_hash,
+			parent_number,
+			target,
+			misbehavior,
+		})
+	}
+}
+
+#[cfg(test)]
+mod test {
+	use super::*;
+
+	#[test]
+	fn misbehavior_report_roundtrip() {
+		let report = MisbehaviorReport {
+			parent_hash: [0; 32].into(),
+			parent_number: 999,
+			target: [1; 32].into(),
+			misbehavior: MisbehaviorKind::BftDoubleCommit(
+				511,
+				([2; 32].into(), [3; 64].into()),
+				([4; 32].into(), [5; 64].into()),
+			),
+		};
+
+		let encoded = report.encode();
+		assert_eq!(MisbehaviorReport::decode(&mut &encoded[..]).unwrap(), report);
+
+		let report = MisbehaviorReport {
+			parent_hash: [0; 32].into(),
+			parent_number: 999,
+			target: [1; 32].into(),
+			misbehavior: MisbehaviorKind::BftDoublePrepare(
+				511,
+				([2; 32].into(), [3; 64].into()),
+				([4; 32].into(), [5; 64].into()),
+			),
+		};
+
+		let encoded = report.encode();
+		assert_eq!(MisbehaviorReport::decode(&mut &encoded[..]).unwrap(), report);
+	}
+}
diff --git a/substrate/substrate/runtime-std/with_std.rs b/substrate/substrate/runtime-std/with_std.rs
index 581cc24d91cb9ac75ec1f5543cf87be1a8f3807a..2cfd266f48271aaa469fa38d14d6ca9fa1a184d2 100644
--- a/substrate/substrate/runtime-std/with_std.rs
+++ b/substrate/substrate/runtime-std/with_std.rs
@@ -14,6 +14,7 @@
 // You should have received a copy of the GNU General Public License
 // along with Substrate.  If not, see <http://www.gnu.org/licenses/>.
 
+pub use std::borrow;
 pub use std::boxed;
 pub use std::cell;
 pub use std::cmp;
diff --git a/substrate/substrate/runtime-std/without_std.rs b/substrate/substrate/runtime-std/without_std.rs
index 75b63407d1078181750a26b2331a1f686aa7a250..5fc2d7526b3ff01bde8b9c96ebc1293d81c56f9e 100644
--- a/substrate/substrate/runtime-std/without_std.rs
+++ b/substrate/substrate/runtime-std/without_std.rs
@@ -28,6 +28,7 @@ pub use alloc::vec;
 pub mod collections {
 	pub use alloc::btree_map;
 }
+pub use core::borrow;
 pub use core::cell;
 pub use core::cmp;
 pub use core::intrinsics;
diff --git a/substrate/substrate/runtime-support/src/storage.rs b/substrate/substrate/runtime-support/src/storage.rs
index 0960ecb0ba2843b40ade82717aa752664744e49f..54237200fb911f2a9ec8728715290cab1d507815 100644
--- a/substrate/substrate/runtime-support/src/storage.rs
+++ b/substrate/substrate/runtime-support/src/storage.rs
@@ -17,6 +17,7 @@
 //! Stuff to do with the runtime's storage.
 
 use rstd::prelude::*;
+use rstd::borrow::Borrow;
 use runtime_io::{self, twox_128};
 use codec::{Slicable, KeyedVec, Input};
 
@@ -131,9 +132,26 @@ pub trait StorageVec {
 	}
 
 	/// Set the current set of items.
-	fn set_items(items: &[Self::Item]) {
-		Self::set_count(items.len() as u32);
-		items.iter().enumerate().for_each(|(v, ref i)| Self::set_item(v as u32, i));
+	fn set_items<I, T>(items: I)
+		where
+			I: IntoIterator<Item=T>,
+			T: Borrow<Self::Item>,
+	{
+		let mut count: u32 = 0;
+
+		for i in items.into_iter() {
+			put(&count.to_keyed_vec(Self::PREFIX), i.borrow());
+			count = count.checked_add(1).expect("exceeded runtime storage capacity");
+		}
+
+		Self::set_count(count);
+	}
+
+	/// Push an item.
+	fn push(item: &Self::Item) {
+		let len = Self::count();
+		put(&len.to_keyed_vec(Self::PREFIX), item);
+		Self::set_count(len + 1);
 	}
 
 	fn set_item(index: u32, item: &Self::Item) {
@@ -163,6 +181,7 @@ pub trait StorageVec {
 }
 
 pub mod unhashed {
+	use rstd::borrow::Borrow;
 	use super::{runtime_io, Slicable, KeyedVec, Vec, IncrementalInput};
 
 	/// Return the value of the item in storage under `key`, or `None` if there is no explicit entry.
@@ -258,9 +277,19 @@ pub mod unhashed {
 		}
 
 		/// Set the current set of items.
-		fn set_items(items: &[Self::Item]) {
-			Self::set_count(items.len() as u32);
-			items.iter().enumerate().for_each(|(v, ref i)| Self::set_item(v as u32, i));
+		fn set_items<I, T>(items: I)
+			where
+				I: IntoIterator<Item=T>,
+				T: Borrow<Self::Item>,
+		{
+			let mut count: u32 = 0;
+
+			for i in items.into_iter() {
+				put(&count.to_keyed_vec(Self::PREFIX), i.borrow());
+				count = count.checked_add(1).expect("exceeded runtime storage capacity");
+			}
+
+			Self::set_count(count);
 		}
 
 		fn set_item(index: u32, item: &Self::Item) {
@@ -293,8 +322,8 @@ pub mod unhashed {
 #[cfg(test)]
 mod tests {
 	use super::*;
-	use primitives::hexdisplay::HexDisplay;
-	use runtime_io::{storage, twox_128, TestExternalities, with_externalities};
+	use primitives::hexdisplay;
+	use runtime_io::{twox_128, TestExternalities, with_externalities};
 
 	#[test]
 	fn integers_can_be_stored() {
@@ -337,7 +366,6 @@ mod tests {
 		with_externalities(&mut t, || {
 			runtime_io::set_storage(&twox_128(b":test"), b"\x0b\0\0\0Hello world");
 			let x = b"Hello world".to_vec();
-			println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test")).unwrap()));
 			let y = get::<Vec<u8>>(b":test").unwrap();
 			assert_eq!(x, y);
 
@@ -353,9 +381,7 @@ mod tests {
 			put(b":test", &x);
 		});
 
-		println!("Ext is {:?}", t);
 		with_externalities(&mut t, || {
-			println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test")).unwrap()));
 			let y: Vec<u8> = get(b":test").unwrap();
 			assert_eq!(x, y);
 		});