diff --git a/substrate/native-runtime/support/src/lib.rs b/substrate/native-runtime/support/src/lib.rs
index 7adf9a904b85fe05692a9df192196a5494597561..47755c3f757510b58a317493e45322d692c6cc0c 100644
--- a/substrate/native-runtime/support/src/lib.rs
+++ b/substrate/native-runtime/support/src/lib.rs
@@ -151,4 +151,20 @@ mod tests {
 			false
 		}));
 	}
+
+	#[test]
+	fn read_storage_works() {
+		let mut t = TestExternalities { storage: map![
+			b":test".to_vec() => b"\x0b\0\0\0Hello world".to_vec()
+		], };
+
+		with_externalities(&mut t, || {
+			let mut v = [0u8; 4];
+			assert!(read_storage(b":test", &mut v[..], 0) >= 4);
+			assert_eq!(v, [11u8, 0, 0, 0]);
+			let mut w = [0u8; 11];
+			assert!(read_storage(b":test", &mut w[..], 4) >= 11);
+			assert_eq!(&w, b"Hello world");
+		});
+	}
 }
diff --git a/substrate/wasm-runtime/polkadot/src/codec/slicable.rs b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs
index 1c783e39dfd173f701ced473f7a8ef60ec454600..1ccf2ce32dacb172083de081ee5c6404b5cf8d76 100644
--- a/substrate/wasm-runtime/polkadot/src/codec/slicable.rs
+++ b/substrate/wasm-runtime/polkadot/src/codec/slicable.rs
@@ -96,3 +96,16 @@ impl Slicable for Vec<u8> {
 		u32::from_slice(&data[0..4]).map(|i| (i + 4) as usize)
 	}
 }
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+
+	#[test]
+	fn vec_is_slicable() {
+		let v = b"Hello world".to_vec();
+		v.as_slice_then(|ref slice|
+			assert_eq!(slice, &b"\x0b\0\0\0Hello world")
+		);
+	}
+}
diff --git a/substrate/wasm-runtime/polkadot/src/runtime/governance.rs b/substrate/wasm-runtime/polkadot/src/runtime/governance.rs
index d7d45fb0d07d67e81eb25b3b4f98fb80cc315d49..e4665d38383abd3e797cef2aadbb55ea9ecedb93 100644
--- a/substrate/wasm-runtime/polkadot/src/runtime/governance.rs
+++ b/substrate/wasm-runtime/polkadot/src/runtime/governance.rs
@@ -34,14 +34,19 @@ use runtime::{staking, system, session};
 
 // TRANSACTION API
 
-pub fn propose(transactor: &AccountID, proposal: &Proposal) {
+/// Propose a sensitive action to be taken. Any action that is enactable by `Proposal` is valid.
+/// Proposal is by the `transactor` and will automatically count as an approval. Transactor must
+/// be a current validator. It is illegal to propose when there is already a proposal in effect.
+pub fn propose(validator: &AccountID, proposal: &Proposal) {
 	if Proposal::lookup(b"gov:pro").is_some() {
 		panic!("there may only be one proposal per era.");
 	}
 	proposal.store(b"gov:pro");
-	approve(transactor, staking::current_era());
+	approve(validator, staking::current_era());
 }
 
+/// Approve the current era's proposal. Transactor must be a validator. This may not be done more
+/// than once for any validator in an era.
 pub fn approve(validator: &AccountID, era_index: BlockNumber) {
 	if era_index != staking::current_era() {
 		panic!("approval vote applied on non-current era.")
@@ -59,18 +64,25 @@ pub fn approve(validator: &AccountID, era_index: BlockNumber) {
 	true.store(&key);
 }
 
+/// Set the proportion of validators that must approve for a proposal to be enacted at the end of
+/// its era. The value, `ppm`, is measured as a fraction of 1000 rounded down to the nearest whole
+/// validator. `1000` would require the approval of all validators; `667` would require two-thirds
+/// (or there abouts) of validators.
 pub fn set_approval_ppm_required(ppm: u32) {
 	ppm.store(b"gov:apr");
 }
 
 // INSPECTION API
 
+/// The proportion of validators required for a propsal to be approved measured as the number out
+/// of 1000.
 pub fn approval_ppm_required() -> u32 {
 	Storable::lookup(b"gov:apr").unwrap_or(1000)
 }
 
+/// The number of concrete validator approvals required for a proposal to pass.
 pub fn approvals_required() -> u32 {
-	approval_ppm_required() * staking::validator_count() as u32 / 1000
+	approval_ppm_required() * session::validator_count() as u32 / 1000
 }
 
 // PUBLIC API
@@ -80,18 +92,270 @@ pub fn end_of_an_era() {
 	// tally up votes for the current proposal, if any. enact if there are sufficient approvals.
 	if let Some(proposal) = Proposal::lookup(b"gov:pro") {
 		kill(b"gov:pro");
-		let approved: u32 = session::validators().into_iter()
-			.map(|v| bool::take(&v.to_keyed_vec(b"gov:app:")).map(|_| 1).unwrap_or(0))
-			.sum();
-		if approved >= approvals_required() {
+		let approvals_required = approvals_required();
+		let approved = session::validators().into_iter()
+			.filter_map(|v| bool::take(&v.to_keyed_vec(b"gov:app:")))
+			.take(approvals_required as usize)
+			.count() as u32;
+		if approved == approvals_required {
 			proposal.enact();
 		}
 	}
 }
 
-// PRIVATE API
-
 #[cfg(test)]
 mod tests {
-	// TODO
+	use super::*;
+	use runtime_support::{with_externalities, twox_128};
+	use keyedvec::KeyedVec;
+	use joiner::Joiner;
+	use testing::{one, two, TestExternalities};
+	use primitives::AccountID;
+	use proposal::InternalFunction;
+	use runtime::{staking, session};
+	use environment::with_env;
+
+	fn new_test_ext() -> TestExternalities {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+
+		TestExternalities { storage: map![
+			twox_128(b"gov:apr").to_vec() => vec![].join(&667u32),
+			twox_128(b"ses:len").to_vec() => vec![].join(&1u64),
+			twox_128(b"ses:val:len").to_vec() => vec![].join(&3u32),
+			twox_128(&0u32.to_keyed_vec(b"ses:val:")).to_vec() => one.to_vec(),
+			twox_128(&1u32.to_keyed_vec(b"ses:val:")).to_vec() => two.to_vec(),
+			twox_128(&2u32.to_keyed_vec(b"ses:val:")).to_vec() => three.to_vec(),
+			twox_128(b"sta:wil:len").to_vec() => vec![].join(&3u32),
+			twox_128(&0u32.to_keyed_vec(b"sta:wil:")).to_vec() => one.to_vec(),
+			twox_128(&1u32.to_keyed_vec(b"sta:wil:")).to_vec() => two.to_vec(),
+			twox_128(&2u32.to_keyed_vec(b"sta:wil:")).to_vec() => three.to_vec(),
+			twox_128(b"sta:spe").to_vec() => vec![].join(&1u64),
+			twox_128(b"sta:vac").to_vec() => vec![].join(&3u64),
+			twox_128(b"sta:era").to_vec() => vec![].join(&1u64)
+		], }
+	}
+
+	#[test]
+	fn majority_voting_should_work() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Approve it. Era length changes.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			approve(&two, 1);
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 2);
+		});
+	}
+
+	#[test]
+	fn majority_voting_should_work_after_unsuccessful_previous() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Fail it.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+
+			// Block 2: Make proposal. Approve it. It should change era length.
+			with_env(|e| e.block_number = 2);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			approve(&two, 2);
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 2);
+		});
+	}
+
+	#[test]
+	fn minority_voting_should_not_succeed() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Will have only 1 vote. No change.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+		});
+	}
+
+	#[test]
+	#[should_panic]
+	fn old_voting_should_be_illegal() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Will have only 1 vote. No change.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			approve(&two, 0);
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+		});
+	}
+
+	#[test]
+	#[should_panic]
+	fn double_voting_should_be_illegal() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Will have only 1 vote. No change.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			approve(&two, 1);
+			approve(&two, 1);
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+		});
+	}
+
+	#[test]
+	#[should_panic]
+	fn over_proposing_should_be_illegal() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Will have only 1 vote. No change.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			propose(&two, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+		});
+	}
+
+	#[test]
+	#[should_panic]
+	fn approving_without_proposal_should_be_illegal() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Will have only 1 vote. No change.
+			with_env(|e| e.block_number = 1);
+			approve(&two, 1);
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+		});
+	}
+
+	#[test]
+	#[should_panic]
+	fn non_validator_approving_should_be_illegal() {
+		let one = one();
+		let two = two();
+		let three = [3u8; 32];
+		let four = [4u8; 32];
+		let mut t = new_test_ext();
+
+		with_externalities(&mut t, || {
+			assert_eq!(staking::era_length(), 1u64);
+			assert_eq!(staking::current_era(), 1u64);
+			assert_eq!(session::validator_count(), 3usize);
+			assert_eq!(session::validators(), vec![one.clone(), two.clone(), three.clone()]);
+			assert!(!session::validators().into_iter().position(|v| &v == &one).is_none());
+
+			// Block 1: Make proposal. Will have only 1 vote. No change.
+			with_env(|e| e.block_number = 1);
+			propose(&one, &Proposal {
+				function: InternalFunction::StakingSetSessionsPerEra,
+				input_data: vec![].join(&2u64),
+			});
+			approve(&four, 1);
+			staking::check_new_era();
+			assert_eq!(staking::era_length(), 1);
+		});
+	}
 }
diff --git a/substrate/wasm-runtime/polkadot/src/runtime/session.rs b/substrate/wasm-runtime/polkadot/src/runtime/session.rs
index 907b3e16b162e0313952817054b4c937234198fc..2034ff316886b965424492625ffac0281e80d344 100644
--- a/substrate/wasm-runtime/polkadot/src/runtime/session.rs
+++ b/substrate/wasm-runtime/polkadot/src/runtime/session.rs
@@ -59,6 +59,11 @@ pub fn length() -> BlockNumber {
 	Storable::lookup_default(b"ses:len")
 }
 
+/// The number of validators currently.
+pub fn validator_count() -> usize {
+	ValidatorStorageVec::count() as usize
+}
+
 /// The current era index.
 pub fn current_index() -> BlockNumber {
 	Storable::lookup_default(b"ses:ind")
diff --git a/substrate/wasm-runtime/polkadot/src/support/storable.rs b/substrate/wasm-runtime/polkadot/src/support/storable.rs
index 61d9f080d9e0aa1d6ef9833104fe961f0a9c6f6f..719415b8e86643436796b9f5bcb0818bc5c9deee 100644
--- a/substrate/wasm-runtime/polkadot/src/support/storable.rs
+++ b/substrate/wasm-runtime/polkadot/src/support/storable.rs
@@ -56,7 +56,7 @@ pub fn kill(key: &[u8]) {
 impl<T: Sized + Slicable> Storable for T {
 	fn lookup(key: &[u8]) -> Option<Self> {
 		Slicable::set_as_slice(&|out, offset|
-			runtime_support::read_storage(&twox_128(key)[..], out, offset) == out.len()
+			runtime_support::read_storage(&twox_128(key)[..], out, offset) >= out.len()
 		)
 	}
 	fn store(&self, key: &[u8]) {
@@ -104,3 +104,89 @@ pub trait StorageVec {
 		Storable::lookup_default(&b"len".to_keyed_vec(Self::PREFIX))
 	}
 }
+
+#[cfg(test)]
+mod tests {
+	use super::*;
+	use std::collections::HashMap;
+	use runtime_support::with_externalities;
+	use testing::{TestExternalities, HexDisplay};
+	use runtime_support::{storage, twox_128};
+
+	#[test]
+	fn integers_can_be_stored() {
+		let mut t = TestExternalities { storage: HashMap::new(), };
+		with_externalities(&mut t, || {
+			let x = 69u32;
+			x.store(b":test");
+			let y = u32::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+		});
+		with_externalities(&mut t, || {
+			let x = 69426942i64;
+			x.store(b":test");
+			let y = i64::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+		});
+	}
+
+	#[test]
+	fn bools_can_be_stored() {
+		let mut t = TestExternalities { storage: HashMap::new(), };
+		with_externalities(&mut t, || {
+			let x = true;
+			x.store(b":test");
+			let y = bool::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+		});
+
+		with_externalities(&mut t, || {
+			let x = false;
+			x.store(b":test");
+			let y = bool::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+		});
+	}
+
+	#[test]
+	fn vecs_can_be_retrieved() {
+		let mut t = TestExternalities { storage: HashMap::new(), };
+		with_externalities(&mut t, || {
+			runtime_support::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"))));
+			let y = <Vec<u8>>::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+
+		});
+	}
+
+	#[test]
+	fn vecs_can_be_stored() {
+		let mut t = TestExternalities { storage: HashMap::new(), };
+		let x = b"Hello world".to_vec();
+
+		with_externalities(&mut t, || {
+			x.store(b":test");
+		});
+
+		println!("Ext is {:?}", t);
+		with_externalities(&mut t, || {
+			println!("Hex: {}", HexDisplay::from(&storage(&twox_128(b":test"))));
+			let y = <Vec<u8>>::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+		});
+	}
+
+	#[test]
+	fn proposals_can_be_stored() {
+		use proposal::{Proposal, InternalFunction};
+		let mut t = TestExternalities { storage: HashMap::new(), };
+		with_externalities(&mut t, || {
+			let x = Proposal { function: InternalFunction::StakingSetSessionsPerEra, input_data: b"Hello world".to_vec() };
+			x.store(b":test");
+			let y = Proposal::lookup(b":test").unwrap();
+			assert_eq!(x, y);
+		});
+	}
+}