diff --git a/substrate/core/finality-grandpa/primitives/src/lib.rs b/substrate/core/finality-grandpa/primitives/src/lib.rs
index 27139bbeeffa8366e1313f1b40ff8e0cfaafae7d..e7d399a89200b5ea12436abd619e13006b4dc5a9 100644
--- a/substrate/core/finality-grandpa/primitives/src/lib.rs
+++ b/substrate/core/finality-grandpa/primitives/src/lib.rs
@@ -23,9 +23,10 @@ extern crate alloc;
 
 #[cfg(feature = "std")]
 use serde::Serialize;
-use codec::{Encode, Decode, Codec};
+use codec::{Encode, Decode, Input, Codec};
 use sr_primitives::{ConsensusEngineId, RuntimeDebug};
 use client::decl_runtime_apis;
+use rstd::borrow::Cow;
 use rstd::vec::Vec;
 
 mod app {
@@ -46,6 +47,10 @@ pub type AuthoritySignature = app::Signature;
 /// The `ConsensusEngineId` of GRANDPA.
 pub const GRANDPA_ENGINE_ID: ConsensusEngineId = *b"FRNK";
 
+/// The storage key for the current set of weighted Grandpa authorities.
+/// The value stored is an encoded VersionedAuthorityList.
+pub const GRANDPA_AUTHORITIES_KEY: &'static [u8] = b":grandpa_authorities";
+
 /// The weight of an authority.
 pub type AuthorityWeight = u64;
 
@@ -58,12 +63,15 @@ pub type SetId = u64;
 /// The round indicator.
 pub type RoundNumber = u64;
 
+/// A list of Grandpa authorities with associated weights.
+pub type AuthorityList = Vec<(AuthorityId, AuthorityWeight)>;
+
 /// A scheduled change of authority set.
 #[cfg_attr(feature = "std", derive(Serialize))]
 #[derive(Clone, Eq, PartialEq, Encode, Decode, RuntimeDebug)]
 pub struct ScheduledChange<N> {
 	/// The new authorities after the change, along with their respective weights.
-	pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>,
+	pub next_authorities: AuthorityList,
 	/// The number of blocks to delay.
 	pub delay: N,
 }
@@ -154,6 +162,55 @@ pub const PENDING_CHANGE_CALL: &str = "grandpa_pending_change";
 /// WASM function call to get current GRANDPA authorities.
 pub const AUTHORITIES_CALL: &str = "grandpa_authorities";
 
+/// The current version of the stored AuthorityList type. The encoding version MUST be updated any
+/// time the AuthorityList type changes.
+const AUTHORITIES_VERISON: u8 = 1;
+
+/// An AuthorityList that is encoded with a version specifier. The encoding version is updated any
+/// time the AuthorityList type changes. This ensures that encodings of different versions of an
+/// AuthorityList are differentiable. Attempting to decode an authority list with an unknown
+/// version will fail.
+#[derive(Default)]
+pub struct VersionedAuthorityList<'a>(Cow<'a, AuthorityList>);
+
+impl<'a> From<AuthorityList> for VersionedAuthorityList<'a> {
+	fn from(authorities: AuthorityList) -> Self {
+		VersionedAuthorityList(Cow::Owned(authorities))
+	}
+}
+
+impl<'a> From<&'a AuthorityList> for VersionedAuthorityList<'a> {
+	fn from(authorities: &'a AuthorityList) -> Self {
+		VersionedAuthorityList(Cow::Borrowed(authorities))
+	}
+}
+
+impl<'a> Into<AuthorityList> for VersionedAuthorityList<'a> {
+	fn into(self) -> AuthorityList {
+		self.0.into_owned()
+	}
+}
+
+impl<'a> Encode for VersionedAuthorityList<'a> {
+	fn size_hint(&self) -> usize {
+		(AUTHORITIES_VERISON, self.0.as_ref()).size_hint()
+	}
+
+	fn using_encoded<R, F: FnOnce(&[u8]) -> R>(&self, f: F) -> R {
+		(AUTHORITIES_VERISON, self.0.as_ref()).using_encoded(f)
+	}
+}
+
+impl<'a> Decode for VersionedAuthorityList<'a> {
+	fn decode<I: Input>(value: &mut I) -> Result<Self, codec::Error> {
+		let (version, authorities): (u8, AuthorityList) = Decode::decode(value)?;
+		if version != AUTHORITIES_VERISON {
+			return Err("unknown Grandpa authorities version".into());
+		}
+		Ok(authorities.into())
+	}
+}
+
 decl_runtime_apis! {
 	/// APIs for integrating the GRANDPA finality gadget into runtimes.
 	/// This should be implemented on the runtime side.
@@ -172,6 +229,6 @@ decl_runtime_apis! {
 		/// When called at block B, it will return the set of authorities that should be
 		/// used to finalize descendants of this block (B+1, B+2, ...). The block B itself
 		/// is finalized by the authorities from block B-1.
-		fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)>;
+		fn grandpa_authorities() -> AuthorityList;
 	}
 }
diff --git a/substrate/core/finality-grandpa/src/authorities.rs b/substrate/core/finality-grandpa/src/authorities.rs
index 9b83c9feb68710a3b60c5ebcef78cb64131a0094..263f2dc076e39991da9509bddfce2c3b84752cb2 100644
--- a/substrate/core/finality-grandpa/src/authorities.rs
+++ b/substrate/core/finality-grandpa/src/authorities.rs
@@ -22,7 +22,7 @@ use grandpa::voter_set::VoterSet;
 use codec::{Encode, Decode};
 use log::{debug, info};
 use substrate_telemetry::{telemetry, CONSENSUS_INFO};
-use fg_primitives::AuthorityId;
+use fg_primitives::{AuthorityId, AuthorityList};
 
 use std::cmp::Ord;
 use std::fmt::Debug;
@@ -86,7 +86,7 @@ pub(crate) struct Status<H, N> {
 /// A set of authorities.
 #[derive(Debug, Clone, Encode, Decode, PartialEq)]
 pub(crate) struct AuthoritySet<H, N> {
-	pub(crate) current_authorities: Vec<(AuthorityId, u64)>,
+	pub(crate) current_authorities: AuthorityList,
 	pub(crate) set_id: u64,
 	// Tree of pending standard changes across forks. Standard changes are
 	// enacted on finality and must be enacted (i.e. finalized) in-order across
@@ -103,7 +103,7 @@ where H: PartialEq,
 	  N: Ord,
 {
 	/// Get a genesis set with given authorities.
-	pub(crate) fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self {
+	pub(crate) fn genesis(initial: AuthorityList) -> Self {
 		AuthoritySet {
 			current_authorities: initial,
 			set_id: 0,
@@ -390,7 +390,7 @@ pub(crate) enum DelayKind<N> {
 #[derive(Debug, Clone, Encode, PartialEq)]
 pub(crate) struct PendingChange<H, N> {
 	/// The new authorities and weights to apply.
-	pub(crate) next_authorities: Vec<(AuthorityId, u64)>,
+	pub(crate) next_authorities: AuthorityList,
 	/// How deep in the chain the announcing block must be
 	/// before the change is applied.
 	pub(crate) delay: N,
diff --git a/substrate/core/finality-grandpa/src/aux_schema.rs b/substrate/core/finality-grandpa/src/aux_schema.rs
index a2b05a0cd60e1f4b237b45549b1efd1cf56ccc95..1aed0b95aba2828b6068f1b6864c874cfa11b556 100644
--- a/substrate/core/finality-grandpa/src/aux_schema.rs
+++ b/substrate/core/finality-grandpa/src/aux_schema.rs
@@ -25,7 +25,7 @@ use fork_tree::ForkTree;
 use grandpa::round::State as RoundState;
 use sr_primitives::traits::{Block as BlockT, NumberFor};
 use log::{info, warn};
-use fg_primitives::{AuthorityId, AuthorityWeight, SetId, RoundNumber};
+use fg_primitives::{AuthorityList, SetId, RoundNumber};
 
 use crate::authorities::{AuthoritySet, SharedAuthoritySet, PendingChange, DelayKind};
 use crate::consensus_changes::{SharedConsensusChanges, ConsensusChanges};
@@ -55,7 +55,7 @@ type V0VoterSetState<H, N> = (RoundNumber, RoundState<H, N>);
 
 #[derive(Debug, Clone, Encode, Decode, PartialEq)]
 struct V0PendingChange<H, N> {
-	next_authorities: Vec<(AuthorityId, AuthorityWeight)>,
+	next_authorities: AuthorityList,
 	delay: N,
 	canon_height: N,
 	canon_hash: H,
@@ -63,7 +63,7 @@ struct V0PendingChange<H, N> {
 
 #[derive(Debug, Clone, Encode, Decode, PartialEq)]
 struct V0AuthoritySet<H, N> {
-	current_authorities: Vec<(AuthorityId, AuthorityWeight)>,
+	current_authorities: AuthorityList,
 	set_id: SetId,
 	pending_changes: Vec<V0PendingChange<H, N>>,
 }
@@ -266,7 +266,7 @@ pub(crate) fn load_persistent<Block: BlockT, B, G>(
 	-> ClientResult<PersistentData<Block>>
 	where
 		B: AuxStore,
-		G: FnOnce() -> ClientResult<Vec<(AuthorityId, AuthorityWeight)>>,
+		G: FnOnce() -> ClientResult<AuthorityList>,
 {
 	let version: Option<u32> = load_decode(backend, VERSION_KEY)?;
 	let consensus_changes = load_decode(backend, CONSENSUS_CHANGES_KEY)?
@@ -426,6 +426,7 @@ pub(crate) fn load_authorities<B: AuxStore, H: Decode, N: Decode>(backend: &B)
 
 #[cfg(test)]
 mod test {
+	use fg_primitives::AuthorityId;
 	use primitives::H256;
 	use test_client;
 	use super::*;
diff --git a/substrate/core/finality-grandpa/src/communication/tests.rs b/substrate/core/finality-grandpa/src/communication/tests.rs
index f918f47258d499c4deb8692e65946276ef3e9a20..af6d842be3c027829290d6123b299fbcd5b85f58 100644
--- a/substrate/core/finality-grandpa/src/communication/tests.rs
+++ b/substrate/core/finality-grandpa/src/communication/tests.rs
@@ -28,6 +28,7 @@ use codec::Encode;
 use sr_primitives::traits::NumberFor;
 
 use crate::environment::SharedVoterSetState;
+use fg_primitives::AuthorityList;
 use super::gossip::{self, GossipValidator};
 use super::{AuthorityId, VoterSet, Round, SetId};
 
@@ -200,7 +201,7 @@ fn make_test_network() -> (
 	)
 }
 
-fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> {
+fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {
 	keys.iter()
 		.map(|key| key.clone().public().into())
 		.map(|id| (id, 1))
diff --git a/substrate/core/finality-grandpa/src/finality_proof.rs b/substrate/core/finality-grandpa/src/finality_proof.rs
index bd22a7bbac287ecc383ce58508852ccb069bb204..aa7207b4228817e351b841fb0694d3d6833906ce 100644
--- a/substrate/core/finality-grandpa/src/finality_proof.rs
+++ b/substrate/core/finality-grandpa/src/finality_proof.rs
@@ -34,13 +34,14 @@
 //! finality proof (that finalizes some block C that is ancestor of the B and descendant
 //! of the U) could be returned.
 
+use std::iter;
 use std::sync::Arc;
 use log::{trace, warn};
 
 use client::{
 	backend::Backend, blockchain::Backend as BlockchainBackend, CallExecutor, Client,
 	error::{Error as ClientError, Result as ClientResult},
-	light::fetcher::{FetchChecker, RemoteCallRequest, StorageProof}, ExecutionStrategy,
+	light::fetcher::{FetchChecker, RemoteReadRequest, StorageProof},
 };
 use codec::{Encode, Decode};
 use grandpa::BlockNumberOps;
@@ -48,9 +49,9 @@ use sr_primitives::{
 	Justification, generic::BlockId,
 	traits::{NumberFor, Block as BlockT, Header as HeaderT, One},
 };
-use primitives::{H256, Blake2Hasher};
+use primitives::{H256, Blake2Hasher, storage::StorageKey};
 use substrate_telemetry::{telemetry, CONSENSUS_INFO};
-use fg_primitives::AuthorityId;
+use fg_primitives::{AuthorityId, AuthorityList, VersionedAuthorityList, GRANDPA_AUTHORITIES_KEY};
 
 use crate::justification::GrandpaJustification;
 
@@ -59,9 +60,9 @@ const MAX_FRAGMENTS_IN_PROOF: usize = 8;
 
 /// GRANDPA authority set related methods for the finality proof provider.
 pub trait AuthoritySetForFinalityProver<Block: BlockT>: Send + Sync {
-	/// Call GrandpaApi::grandpa_authorities at given block.
-	fn authorities(&self, block: &BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>>;
-	/// Prove call of GrandpaApi::grandpa_authorities at given block.
+	/// Read GRANDPA_AUTHORITIES_KEY from storage at given block.
+	fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList>;
+	/// Prove storage read of GRANDPA_AUTHORITIES_KEY at given block.
 	fn prove_authorities(&self, block: &BlockId<Block>) -> ClientResult<StorageProof>;
 }
 
@@ -72,33 +73,28 @@ impl<B, E, Block: BlockT<Hash=H256>, RA> AuthoritySetForFinalityProver<Block> fo
 		E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
 		RA: Send + Sync,
 {
-	fn authorities(&self, block: &BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>> {
-		self.executor().call(
-			block,
-			"GrandpaApi_grandpa_authorities",
-			&[],
-			ExecutionStrategy::NativeElseWasm,
-			None,
-		).and_then(|call_result| Decode::decode(&mut &call_result[..])
-			.map_err(|err| ClientError::CallResultDecode(
-				"failed to decode GRANDPA authorities set proof".into(), err
-			)))
+	fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList> {
+		let storage_key = StorageKey(GRANDPA_AUTHORITIES_KEY.to_vec());
+		self.storage(block, &storage_key)?
+			.and_then(|encoded| VersionedAuthorityList::decode(&mut encoded.0.as_slice()).ok())
+			.map(|versioned| versioned.into())
+			.ok_or(ClientError::InvalidAuthoritiesSet)
 	}
 
 	fn prove_authorities(&self, block: &BlockId<Block>) -> ClientResult<StorageProof> {
-		self.execution_proof(block, "GrandpaApi_grandpa_authorities",&[]).map(|(_, proof)| proof)
+		self.read_proof(block, iter::once(GRANDPA_AUTHORITIES_KEY))
 	}
 }
 
 /// GRANDPA authority set related methods for the finality proof checker.
 pub trait AuthoritySetForFinalityChecker<Block: BlockT>: Send + Sync {
-	/// Check execution proof of Grandpa::grandpa_authorities at given block.
+	/// Check storage read proof of GRANDPA_AUTHORITIES_KEY at given block.
 	fn check_authorities_proof(
 		&self,
 		hash: Block::Hash,
 		header: Block::Header,
 		proof: StorageProof,
-	) -> ClientResult<Vec<(AuthorityId, u64)>>;
+	) -> ClientResult<AuthorityList>;
 }
 
 /// FetchChecker-based implementation of AuthoritySetForFinalityChecker.
@@ -108,22 +104,30 @@ impl<Block: BlockT> AuthoritySetForFinalityChecker<Block> for Arc<dyn FetchCheck
 		hash: Block::Hash,
 		header: Block::Header,
 		proof: StorageProof,
-	) -> ClientResult<Vec<(AuthorityId, u64)>> {
-		let request = RemoteCallRequest {
+	) -> ClientResult<AuthorityList> {
+		let storage_key = GRANDPA_AUTHORITIES_KEY.to_vec();
+		let request = RemoteReadRequest {
 			block: hash,
 			header,
-			method: "GrandpaApi_grandpa_authorities".into(),
-			call_data: vec![],
+			keys: vec![storage_key.clone()],
 			retry_count: None,
 		};
 
-		self.check_execution_proof(&request, proof)
-			.and_then(|authorities| {
-				let authorities: Vec<(AuthorityId, u64)> = Decode::decode(&mut &authorities[..])
-					.map_err(|err| ClientError::CallResultDecode(
-						"failed to decode GRANDPA authorities set proof".into(), err
-					))?;
-				Ok(authorities.into_iter().collect())
+		self.check_read_proof(&request, proof)
+			.and_then(|results| {
+				let maybe_encoded = results.get(&storage_key)
+					.expect(
+						"storage_key is listed in the request keys; \
+						check_read_proof must return a value for each requested key;
+						qed"
+					);
+				maybe_encoded
+					.as_ref()
+					.and_then(|encoded| {
+						VersionedAuthorityList::decode(&mut encoded.as_slice()).ok()
+					})
+					.map(|versioned| versioned.into())
+					.ok_or(ClientError::InvalidAuthoritiesSet)
 			})
 	}
 }
@@ -189,7 +193,7 @@ pub struct FinalityEffects<Header: HeaderT> {
 	/// New authorities set id that should be applied starting from block.
 	pub new_set_id: u64,
 	/// New authorities set that should be applied starting from block.
-	pub new_authorities: Vec<(AuthorityId, u64)>,
+	pub new_authorities: AuthorityList,
 }
 
 /// Single fragment of proof-of-finality.
@@ -408,7 +412,7 @@ pub(crate) fn prove_finality<Block: BlockT<Hash=H256>, B: BlockchainBackend<Bloc
 pub(crate) fn check_finality_proof<Block: BlockT<Hash=H256>, B>(
 	blockchain: &B,
 	current_set_id: u64,
-	current_authorities: Vec<(AuthorityId, u64)>,
+	current_authorities: AuthorityList,
 	authorities_provider: &dyn AuthoritySetForFinalityChecker<Block>,
 	remote_proof: Vec<u8>,
 ) -> ClientResult<FinalityEffects<Block::Header>>
@@ -427,7 +431,7 @@ pub(crate) fn check_finality_proof<Block: BlockT<Hash=H256>, B>(
 fn do_check_finality_proof<Block: BlockT<Hash=H256>, B, J>(
 	blockchain: &B,
 	current_set_id: u64,
-	current_authorities: Vec<(AuthorityId, u64)>,
+	current_authorities: AuthorityList,
 	authorities_provider: &dyn AuthoritySetForFinalityChecker<Block>,
 	remote_proof: Vec<u8>,
 ) -> ClientResult<FinalityEffects<Block::Header>>
@@ -522,12 +526,12 @@ fn check_finality_proof_fragment<Block: BlockT<Hash=H256>, B, J>(
 
 /// Authorities set from initial authorities set or finality effects.
 enum AuthoritiesOrEffects<Header: HeaderT> {
-	Authorities(u64, Vec<(AuthorityId, u64)>),
+	Authorities(u64, AuthorityList),
 	Effects(FinalityEffects<Header>),
 }
 
 impl<Header: HeaderT> AuthoritiesOrEffects<Header> {
-	pub fn extract_authorities(self) -> (u64, Vec<(AuthorityId, u64)>) {
+	pub fn extract_authorities(self) -> (u64, AuthorityList) {
 		match self {
 			AuthoritiesOrEffects::Authorities(set_id, authorities) => (set_id, authorities),
 			AuthoritiesOrEffects::Effects(effects) => (effects.new_set_id, effects.new_authorities),
@@ -581,10 +585,10 @@ pub(crate) mod tests {
 
 	impl<GetAuthorities, ProveAuthorities> AuthoritySetForFinalityProver<Block> for (GetAuthorities, ProveAuthorities)
 		where
-			GetAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>>,
+			GetAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<AuthorityList>,
 			ProveAuthorities: Send + Sync + Fn(BlockId<Block>) -> ClientResult<StorageProof>,
 	{
-		fn authorities(&self, block: &BlockId<Block>) -> ClientResult<Vec<(AuthorityId, u64)>> {
+		fn authorities(&self, block: &BlockId<Block>) -> ClientResult<AuthorityList> {
 			self.0(*block)
 		}
 
@@ -597,14 +601,14 @@ pub(crate) mod tests {
 
 	impl<Closure> AuthoritySetForFinalityChecker<Block> for ClosureAuthoritySetForFinalityChecker<Closure>
 		where
-			Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult<Vec<(AuthorityId, u64)>>,
+			Closure: Send + Sync + Fn(H256, Header, StorageProof) -> ClientResult<AuthorityList>,
 	{
 		fn check_authorities_proof(
 			&self,
 			hash: H256,
 			header: Header,
-			proof: StorageProof,
-		) -> ClientResult<Vec<(AuthorityId, u64)>> {
+			proof: StorageProof
+		) -> ClientResult<AuthorityList> {
 			self.0(hash, header, proof)
 		}
 	}
diff --git a/substrate/core/finality-grandpa/src/lib.rs b/substrate/core/finality-grandpa/src/lib.rs
index 0decea58117b0d9d6a90649f54b15f9e3f8f0ad6..88d7fbec0762234eacc663818e89c8ce895e96b1 100644
--- a/substrate/core/finality-grandpa/src/lib.rs
+++ b/substrate/core/finality-grandpa/src/lib.rs
@@ -57,14 +57,12 @@ use log::{debug, error, info};
 use futures::sync::mpsc;
 use client::{
 	BlockchainEvents, CallExecutor, Client, backend::Backend, error::Error as ClientError,
+	ExecutionStrategy,
 };
 use client::blockchain::HeaderBackend;
-use codec::Encode;
+use codec::{Decode, Encode};
 use sr_primitives::generic::BlockId;
-use sr_primitives::traits::{
-	NumberFor, Block as BlockT, DigestFor, ProvideRuntimeApi
-};
-use fg_primitives::{GrandpaApi, AuthorityPair};
+use sr_primitives::traits::{NumberFor, Block as BlockT, DigestFor, Zero};
 use keystore::KeyStorePtr;
 use inherents::InherentDataProviders;
 use consensus_common::SelectChain;
@@ -108,7 +106,7 @@ use environment::{Environment, VoterSetState};
 use import::GrandpaBlockImport;
 use until_imported::UntilGlobalMessageBlocksImported;
 use communication::NetworkBridge;
-use fg_primitives::{AuthoritySignature, SetId, AuthorityWeight};
+use fg_primitives::{AuthorityList, AuthorityPair, AuthoritySignature, SetId};
 
 // Re-export these two because it's just so damn convenient.
 pub use fg_primitives::{AuthorityId, ScheduledChange};
@@ -295,7 +293,7 @@ pub(crate) struct NewAuthoritySet<H, N> {
 	pub(crate) canon_number: N,
 	pub(crate) canon_hash: H,
 	pub(crate) set_id: SetId,
-	pub(crate) authorities: Vec<(AuthorityId, AuthorityWeight)>,
+	pub(crate) authorities: AuthorityList,
 }
 
 /// Commands issued to the voter.
@@ -367,11 +365,44 @@ pub struct LinkHalf<B, E, Block: BlockT<Hash=H256>, RA, SC> {
 	voter_commands_rx: mpsc::UnboundedReceiver<VoterCommand<Block::Hash, NumberFor<Block>>>,
 }
 
+/// Provider for the Grandpa authority set configured on the genesis block.
+pub trait GenesisAuthoritySetProvider<Block: BlockT> {
+	/// Get the authority set at the genesis block.
+	fn get(&self) -> Result<AuthorityList, ClientError>;
+}
+
+impl<B, E, Block: BlockT<Hash=H256>, RA> GenesisAuthoritySetProvider<Block> for Client<B, E, Block, RA>
+	where
+		B: Backend<Block, Blake2Hasher> + Send + Sync + 'static,
+		E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
+		RA: Send + Sync,
+{
+	fn get(&self) -> Result<AuthorityList, ClientError> {
+		// This implementation uses the Grandpa runtime API instead of reading directly from the
+		// `GRANDPA_AUTHORITIES_KEY` as the data may have been migrated since the genesis block of
+		// the chain, whereas the runtime API is backwards compatible.
+		self.executor()
+			.call(
+				&BlockId::Number(Zero::zero()),
+				"GrandpaApi_grandpa_authorities",
+				&[],
+				ExecutionStrategy::NativeElseWasm,
+				None,
+			)
+			.and_then(|call_result| {
+				Decode::decode(&mut &call_result[..])
+					.map_err(|err| ClientError::CallResultDecode(
+						"failed to decode GRANDPA authorities set proof".into(), err
+					))
+			})
+	}
+}
+
 /// Make block importer and link half necessary to tie the background voter
 /// to it.
-pub fn block_import<B, E, Block: BlockT<Hash=H256>, RA, PRA, SC>(
+pub fn block_import<B, E, Block: BlockT<Hash=H256>, RA, SC>(
 	client: Arc<Client<B, E, Block, RA>>,
-	api: &PRA,
+	genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
 	select_chain: SC,
 ) -> Result<(
 		GrandpaBlockImport<B, E, Block, RA, SC>,
@@ -381,12 +412,8 @@ where
 	B: Backend<Block, Blake2Hasher> + 'static,
 	E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
 	RA: Send + Sync,
-	PRA: ProvideRuntimeApi,
-	PRA::Api: GrandpaApi<Block>,
 	SC: SelectChain<Block>,
 {
-	use sr_primitives::traits::Zero;
-
 	let chain_info = client.info();
 	let genesis_hash = chain_info.chain.genesis_hash;
 
@@ -395,12 +422,11 @@ where
 		genesis_hash,
 		<NumberFor<Block>>::zero(),
 		|| {
-			let genesis_authorities = api.runtime_api()
-				.grandpa_authorities(&BlockId::number(Zero::zero()))?;
+			let authorities = genesis_authorities_provider.get()?;
 			telemetry!(CONSENSUS_DEBUG; "afg.loading_authorities";
-				"authorities_len" => ?genesis_authorities.len()
+				"authorities_len" => ?authorities.len()
 			);
-			Ok(genesis_authorities)
+			Ok(authorities)
 		}
 	)?;
 
diff --git a/substrate/core/finality-grandpa/src/light_import.rs b/substrate/core/finality-grandpa/src/light_import.rs
index 30af3a06d3f760fb405900b418be582b2bc17072..30008b51ece1e365ded3fa2457b5ab37e334b37c 100644
--- a/substrate/core/finality-grandpa/src/light_import.rs
+++ b/substrate/core/finality-grandpa/src/light_import.rs
@@ -34,17 +34,18 @@ use consensus_common::{
 };
 use network::config::{BoxFinalityProofRequestBuilder, FinalityProofRequestBuilder};
 use sr_primitives::Justification;
-use sr_primitives::traits::{
-	NumberFor, Block as BlockT, Header as HeaderT, ProvideRuntimeApi, DigestFor,
-};
-use fg_primitives::{self, GrandpaApi, AuthorityId};
+use sr_primitives::traits::{NumberFor, Block as BlockT, Header as HeaderT, DigestFor};
+use fg_primitives::{self, AuthorityList};
 use sr_primitives::generic::BlockId;
 use primitives::{H256, Blake2Hasher};
 
+use crate::GenesisAuthoritySetProvider;
 use crate::aux_schema::load_decode;
 use crate::consensus_changes::ConsensusChanges;
 use crate::environment::canonical_at_height;
-use crate::finality_proof::{AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request};
+use crate::finality_proof::{
+	AuthoritySetForFinalityChecker, ProvableJustification, make_finality_proof_request,
+};
 use crate::justification::GrandpaJustification;
 
 /// LightAuthoritySet is saved under this key in aux storage.
@@ -53,21 +54,23 @@ const LIGHT_AUTHORITY_SET_KEY: &[u8] = b"grandpa_voters";
 const LIGHT_CONSENSUS_CHANGES_KEY: &[u8] = b"grandpa_consensus_changes";
 
 /// Create light block importer.
-pub fn light_block_import<B, E, Block: BlockT<Hash=H256>, RA, PRA>(
+pub fn light_block_import<B, E, Block: BlockT<Hash=H256>, RA>(
 	client: Arc<Client<B, E, Block, RA>>,
 	backend: Arc<B>,
+	genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
 	authority_set_provider: Arc<dyn AuthoritySetForFinalityChecker<Block>>,
-	api: Arc<PRA>,
 ) -> Result<GrandpaLightBlockImport<B, E, Block, RA>, ClientError>
 	where
 		B: Backend<Block, Blake2Hasher> + 'static,
 		E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
 		RA: Send + Sync,
-		PRA: ProvideRuntimeApi,
-		PRA::Api: GrandpaApi<Block>,
 {
 	let info = client.info();
-	let import_data = load_aux_import_data(info.chain.finalized_hash, &*client, api)?;
+	let import_data = load_aux_import_data(
+		info.chain.finalized_hash,
+		&*client,
+		genesis_authorities_provider,
+	)?;
 	Ok(GrandpaLightBlockImport {
 		client,
 		backend,
@@ -110,7 +113,7 @@ struct LightImportData<Block: BlockT<Hash=H256>> {
 #[derive(Debug, Encode, Decode)]
 struct LightAuthoritySet {
 	set_id: u64,
-	authorities: Vec<(AuthorityId, u64)>,
+	authorities: AuthorityList,
 }
 
 impl<B, E, Block: BlockT<Hash=H256>, RA> GrandpaLightBlockImport<B, E, Block, RA> {
@@ -194,7 +197,7 @@ impl<B, E, Block: BlockT<Hash=H256>, RA> FinalityProofImport<Block>
 
 impl LightAuthoritySet {
 	/// Get a genesis set with given authorities.
-	pub fn genesis(initial: Vec<(AuthorityId, u64)>) -> Self {
+	pub fn genesis(initial: AuthorityList) -> Self {
 		LightAuthoritySet {
 			set_id: fg_primitives::SetId::default(),
 			authorities: initial,
@@ -207,12 +210,12 @@ impl LightAuthoritySet {
 	}
 
 	/// Get latest authorities set.
-	pub fn authorities(&self) -> Vec<(AuthorityId, u64)> {
+	pub fn authorities(&self) -> AuthorityList {
 		self.authorities.clone()
 	}
 
 	/// Set new authorities set.
-	pub fn update(&mut self, set_id: u64, authorities: Vec<(AuthorityId, u64)>) {
+	pub fn update(&mut self, set_id: u64, authorities: AuthorityList) {
 		self.set_id = set_id;
 		std::mem::replace(&mut self.authorities, authorities);
 	}
@@ -472,17 +475,14 @@ fn do_finalize_block<B, C, Block: BlockT<Hash=H256>>(
 }
 
 /// Load light import aux data from the store.
-fn load_aux_import_data<B, Block: BlockT<Hash=H256>, PRA>(
+fn load_aux_import_data<B, Block: BlockT<Hash=H256>>(
 	last_finalized: Block::Hash,
 	aux_store: &B,
-	api: Arc<PRA>,
+	genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
 ) -> Result<LightImportData<Block>, ClientError>
 	where
 		B: AuxStore,
-		PRA: ProvideRuntimeApi,
-		PRA::Api: GrandpaApi<Block>,
 {
-	use sr_primitives::traits::Zero;
 	let authority_set = match load_decode(aux_store, LIGHT_AUTHORITY_SET_KEY)? {
 		Some(authority_set) => authority_set,
 		None => {
@@ -490,7 +490,7 @@ fn load_aux_import_data<B, Block: BlockT<Hash=H256>, PRA>(
 				from genesis on what appears to be first startup.");
 
 			// no authority set on disk: fetch authorities from genesis state
-			let genesis_authorities = api.runtime_api().grandpa_authorities(&BlockId::number(Zero::zero()))?;
+			let genesis_authorities = genesis_authorities_provider.get()?;
 
 			let authority_set = LightAuthoritySet::genesis(genesis_authorities);
 			let encoded = authority_set.encode();
@@ -546,6 +546,7 @@ fn on_post_finalization_error(error: ClientError, value_type: &str) -> Consensus
 pub mod tests {
 	use super::*;
 	use consensus_common::ForkChoiceStrategy;
+	use fg_primitives::AuthorityId;
 	use primitives::{H256, crypto::Public};
 	use test_client::client::in_mem::Blockchain as InMemoryAuxStore;
 	use test_client::runtime::{Block, Header};
@@ -622,20 +623,19 @@ pub mod tests {
 	}
 
 	/// Creates light block import that ignores justifications that came outside of finality proofs.
-	pub fn light_block_import_without_justifications<B, E, Block: BlockT<Hash=H256>, RA, PRA>(
+	pub fn light_block_import_without_justifications<B, E, Block: BlockT<Hash=H256>, RA>(
 		client: Arc<Client<B, E, Block, RA>>,
 		backend: Arc<B>,
+		genesis_authorities_provider: &dyn GenesisAuthoritySetProvider<Block>,
 		authority_set_provider: Arc<dyn AuthoritySetForFinalityChecker<Block>>,
-		api: Arc<PRA>,
 	) -> Result<NoJustificationsImport<B, E, Block, RA>, ClientError>
 		where
 			B: Backend<Block, Blake2Hasher> + 'static,
 			E: CallExecutor<Block, Blake2Hasher> + 'static + Clone + Send + Sync,
 			RA: Send + Sync,
-			PRA: ProvideRuntimeApi,
-			PRA::Api: GrandpaApi<Block>,
 	{
-		light_block_import(client, backend, authority_set_provider, api).map(NoJustificationsImport)
+		light_block_import(client, backend, genesis_authorities_provider, authority_set_provider)
+			.map(NoJustificationsImport)
 	}
 
 	fn import_block(
@@ -729,14 +729,14 @@ pub mod tests {
 	#[test]
 	fn aux_data_updated_on_start() {
 		let aux_store = InMemoryAuxStore::<Block>::new();
-		let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]));
+		let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]);
 
 		// when aux store is empty initially
 		assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_none());
 		assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_none());
 
 		// it is updated on importer start
-		load_aux_import_data(Default::default(), &aux_store, api).unwrap();
+		load_aux_import_data(Default::default(), &aux_store, &api).unwrap();
 		assert!(aux_store.get_aux(LIGHT_AUTHORITY_SET_KEY).unwrap().is_some());
 		assert!(aux_store.get_aux(LIGHT_CONSENSUS_CHANGES_KEY).unwrap().is_some());
 	}
@@ -744,7 +744,7 @@ pub mod tests {
 	#[test]
 	fn aux_data_loaded_on_restart() {
 		let aux_store = InMemoryAuxStore::<Block>::new();
-		let api = Arc::new(TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]));
+		let api = TestApi::new(vec![(AuthorityId::from_slice(&[1; 32]), 1)]);
 
 		// when aux store is non-empty initially
 		let mut consensus_changes = ConsensusChanges::<H256, u64>::empty();
@@ -766,7 +766,7 @@ pub mod tests {
 		).unwrap();
 
 		// importer uses it on start
-		let data = load_aux_import_data(Default::default(), &aux_store, api).unwrap();
+		let data = load_aux_import_data(Default::default(), &aux_store, &api).unwrap();
 		assert_eq!(data.authority_set.authorities(), vec![(AuthorityId::from_slice(&[42; 32]), 2)]);
 		assert_eq!(data.consensus_changes.pending_changes(), &[(42, Default::default())]);
 	}
diff --git a/substrate/core/finality-grandpa/src/tests.rs b/substrate/core/finality-grandpa/src/tests.rs
index 2339379a609d480de4c76b4205b474bd774907ef..349859495198065ea7350c30c3d0c1b670b73f45 100644
--- a/substrate/core/finality-grandpa/src/tests.rs
+++ b/substrate/core/finality-grandpa/src/tests.rs
@@ -39,7 +39,7 @@ use codec::Decode;
 use sr_primitives::traits::{ApiRef, ProvideRuntimeApi, Header as HeaderT};
 use sr_primitives::generic::{BlockId, DigestItem};
 use primitives::{NativeOrEncoded, ExecutionContext, crypto::Public};
-use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityId};
+use fg_primitives::{GRANDPA_ENGINE_ID, AuthorityList, GrandpaApi};
 use state_machine::{backend::InMemory, prove_read, read_proof_check};
 
 use authorities::AuthoritySet;
@@ -137,8 +137,8 @@ impl TestNetFactory for GrandpaTestNet {
 				let import = light_block_import_without_justifications(
 					client.clone(),
 					backend.clone(),
+					&self.test_config,
 					authorities_provider,
-					Arc::new(self.test_config.clone())
 				).expect("Could not create block import for fresh peer.");
 				let finality_proof_req_builder = import.0.create_finality_proof_request_builder();
 				let proof_import = Box::new(import.clone());
@@ -188,11 +188,11 @@ impl Future for Exit {
 
 #[derive(Default, Clone)]
 pub(crate) struct TestApi {
-	genesis_authorities: Vec<(AuthorityId, u64)>,
+	genesis_authorities: AuthorityList,
 }
 
 impl TestApi {
-	pub fn new(genesis_authorities: Vec<(AuthorityId, u64)>) -> Self {
+	pub fn new(genesis_authorities: AuthorityList) -> Self {
 		TestApi {
 			genesis_authorities,
 		}
@@ -271,19 +271,20 @@ impl GrandpaApi<Block> for RuntimeApi {
 		_: ExecutionContext,
 		_: Option<()>,
 		_: Vec<u8>,
-	) -> Result<NativeOrEncoded<Vec<(AuthorityId, u64)>>> {
+	) -> Result<NativeOrEncoded<AuthorityList>> {
 		Ok(self.inner.genesis_authorities.clone()).map(NativeOrEncoded::Native)
 	}
 }
 
+impl GenesisAuthoritySetProvider<Block> for TestApi {
+	fn get(&self) -> Result<AuthorityList> {
+		Ok(self.genesis_authorities.clone())
+	}
+}
+
 impl AuthoritySetForFinalityProver<Block> for TestApi {
-	fn authorities(&self, block: &BlockId<Block>) -> Result<Vec<(AuthorityId, u64)>> {
-		let runtime_api = RuntimeApi { inner: self.clone() };
-		runtime_api.GrandpaApi_grandpa_authorities_runtime_api_impl(block, ExecutionContext::Syncing, None, Vec::new())
-			.map(|v| match v {
-				NativeOrEncoded::Native(value) => value,
-				_ => unreachable!("only providing native values"),
-			})
+	fn authorities(&self, _block: &BlockId<Block>) -> Result<AuthorityList> {
+		Ok(self.genesis_authorities.clone())
 	}
 
 	fn prove_authorities(&self, block: &BlockId<Block>) -> Result<StorageProof> {
@@ -303,7 +304,7 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
 		_hash: <Block as BlockT>::Hash,
 		header: <Block as BlockT>::Header,
 		proof: StorageProof,
-	) -> Result<Vec<(AuthorityId, u64)>> {
+	) -> Result<AuthorityList> {
 		let results = read_proof_check::<Blake2Hasher, _>(
 			*header.state_root(), proof, vec![b"authorities"]
 		)
@@ -320,7 +321,7 @@ impl AuthoritySetForFinalityChecker<Block> for TestApi {
 
 const TEST_GOSSIP_DURATION: Duration = Duration::from_millis(500);
 
-fn make_ids(keys: &[Ed25519Keyring]) -> Vec<(AuthorityId, u64)> {
+fn make_ids(keys: &[Ed25519Keyring]) -> AuthorityList {
 	keys.iter().map(|key| key.clone().public().into()).map(|id| (id, 1)).collect()
 }
 
diff --git a/substrate/node-template/runtime/src/lib.rs b/substrate/node-template/runtime/src/lib.rs
index c0cd2cf33770cebf96060cb6f5afc035164a2b54..071e07a52e8b5402b1223b306a7414718f08e1cd 100644
--- a/substrate/node-template/runtime/src/lib.rs
+++ b/substrate/node-template/runtime/src/lib.rs
@@ -23,7 +23,7 @@ use client::{
 	runtime_api as client_api, impl_runtime_apis
 };
 use aura_primitives::sr25519::AuthorityId as AuraId;
-use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight};
+use grandpa::AuthorityList as GrandpaAuthorityList;
 use grandpa::fg_primitives;
 use version::RuntimeVersion;
 #[cfg(feature = "std")]
@@ -355,7 +355,7 @@ impl_runtime_apis! {
 	}
 
 	impl fg_primitives::GrandpaApi<Block> for Runtime {
-		fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> {
+		fn grandpa_authorities() -> GrandpaAuthorityList {
 			Grandpa::grandpa_authorities()
 		}
 	}
diff --git a/substrate/node-template/src/service.rs b/substrate/node-template/src/service.rs
index 398795325fd04075ce025122209f6d6f8b3b060b..7967a1d2d4e8ffb748fb0168c9cbcb0fcbca840a 100644
--- a/substrate/node-template/src/service.rs
+++ b/substrate/node-template/src/service.rs
@@ -48,7 +48,7 @@ macro_rules! new_full_start {
 					.ok_or_else(|| substrate_service::Error::SelectChainRequired)?;
 
 				let (grandpa_block_import, grandpa_link) =
-					grandpa::block_import::<_, _, _, runtime::RuntimeApi, _, _>(
+					grandpa::block_import::<_, _, _, runtime::RuntimeApi, _>(
 						client.clone(), &*client, select_chain
 					)?;
 
@@ -197,8 +197,8 @@ pub fn new_light<C: Send + Default + 'static>(config: Configuration<C, GenesisCo
 			let fetch_checker = fetcher
 				.map(|fetcher| fetcher.checker().clone())
 				.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
-			let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>(
-				client.clone(), backend, Arc::new(fetch_checker), client.clone()
+			let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>(
+				client.clone(), backend, &*client.clone(), Arc::new(fetch_checker),
 			)?;
 			let finality_proof_import = grandpa_block_import.clone();
 			let finality_proof_request_builder =
diff --git a/substrate/node/cli/src/service.rs b/substrate/node/cli/src/service.rs
index 09056591143ec668e1e8c652af03d7e94c827be8..9f0726fc83637b6ac9b2cfedc66ad3d33bf1a3db 100644
--- a/substrate/node/cli/src/service.rs
+++ b/substrate/node/cli/src/service.rs
@@ -69,10 +69,11 @@ macro_rules! new_full_start {
 			.with_import_queue(|_config, client, mut select_chain, _transaction_pool| {
 				let select_chain = select_chain.take()
 					.ok_or_else(|| substrate_service::Error::SelectChainRequired)?;
-				let (grandpa_block_import, grandpa_link) =
-					grandpa::block_import::<_, _, _, node_runtime::RuntimeApi, _, _>(
-						client.clone(), &*client, select_chain
-					)?;
+				let (grandpa_block_import, grandpa_link) = grandpa::block_import(
+					client.clone(),
+					&*client,
+					select_chain,
+				)?;
 				let justification_import = grandpa_block_import.clone();
 
 				let (block_import, babe_link) = babe::block_import(
@@ -291,8 +292,11 @@ pub fn new_light<C: Send + Default + 'static>(config: NodeConfiguration<C>)
 			let fetch_checker = fetcher
 				.map(|fetcher| fetcher.checker().clone())
 				.ok_or_else(|| "Trying to start light import queue without active fetch checker")?;
-			let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi, _>(
-				client.clone(), backend, Arc::new(fetch_checker), client.clone()
+			let grandpa_block_import = grandpa::light_block_import::<_, _, _, RuntimeApi>(
+				client.clone(),
+				backend,
+				&*client,
+				Arc::new(fetch_checker),
 			)?;
 
 			let finality_proof_import = grandpa_block_import.clone();
diff --git a/substrate/node/runtime/src/lib.rs b/substrate/node/runtime/src/lib.rs
index 48263c934084c35287a1f73273665b73b55e706d..8dfa52b23f3b89a5b246297135cf89ed2cbb5a67 100644
--- a/substrate/node/runtime/src/lib.rs
+++ b/substrate/node/runtime/src/lib.rs
@@ -29,7 +29,6 @@ use node_primitives::{
 	AccountId, AccountIndex, Balance, BlockNumber, Hash, Index,
 	Moment, Signature,
 };
-use grandpa::fg_primitives;
 use client::{
 	block_builder::api::{self as block_builder_api, InherentData, CheckInherentsResult},
 	runtime_api as client_api, impl_runtime_apis
@@ -46,7 +45,8 @@ use version::RuntimeVersion;
 #[cfg(any(feature = "std", test))]
 use version::NativeVersion;
 use primitives::OpaqueMetadata;
-use grandpa::{AuthorityId as GrandpaId, AuthorityWeight as GrandpaWeight};
+use grandpa::AuthorityList as GrandpaAuthorityList;
+use grandpa::fg_primitives;
 use im_online::sr25519::{AuthorityId as ImOnlineId};
 use transaction_payment_rpc_runtime_api::RuntimeDispatchInfo;
 use contracts_rpc_runtime_api::ContractExecResult;
@@ -81,8 +81,8 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// and set impl_version to equal spec_version. If only runtime
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
-	spec_version: 192,
-	impl_version: 191,
+	spec_version: 193,
+	impl_version: 193,
 	apis: RUNTIME_API_VERSIONS,
 };
 
@@ -617,7 +617,7 @@ impl_runtime_apis! {
 	}
 
 	impl fg_primitives::GrandpaApi<Block> for Runtime {
-		fn grandpa_authorities() -> Vec<(GrandpaId, GrandpaWeight)> {
+		fn grandpa_authorities() -> GrandpaAuthorityList {
 			Grandpa::grandpa_authorities()
 		}
 	}
diff --git a/substrate/srml/grandpa/Cargo.toml b/substrate/srml/grandpa/Cargo.toml
index 4b494cfeff8d11979116deb598d03dc5920f690e..21b48d3cdc51dbc3e28fe16f4d9e67626f052eeb 100644
--- a/substrate/srml/grandpa/Cargo.toml
+++ b/substrate/srml/grandpa/Cargo.toml
@@ -35,3 +35,4 @@ std = [
 	"session/std",
 	"finality-tracker/std",
 ]
+migrate-authorities = []
diff --git a/substrate/srml/grandpa/src/lib.rs b/substrate/srml/grandpa/src/lib.rs
index f3e876f2c4e0e681cac3cc06b0ce5df3c12d48f8..877521c9746d9f1cb36f32ac64fa31e1e3678f23 100644
--- a/substrate/srml/grandpa/src/lib.rs
+++ b/substrate/srml/grandpa/src/lib.rs
@@ -32,9 +32,7 @@ pub use substrate_finality_grandpa_primitives as fg_primitives;
 
 use rstd::prelude::*;
 use codec::{self as codec, Encode, Decode, Error};
-use support::{
-	decl_event, decl_storage, decl_module, dispatch::Result,
-};
+use support::{decl_event, decl_storage, decl_module, dispatch::Result, storage};
 use sr_primitives::{
 	generic::{DigestItem, OpaqueDigestItemId}, traits::Zero, Perbill,
 };
@@ -42,8 +40,10 @@ use sr_staking_primitives::{
 	SessionIndex,
 	offence::{Offence, Kind},
 };
-use fg_primitives::{GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber};
-pub use fg_primitives::{AuthorityId, AuthorityWeight};
+use fg_primitives::{
+	GRANDPA_AUTHORITIES_KEY, GRANDPA_ENGINE_ID, ScheduledChange, ConsensusLog, SetId, RoundNumber,
+};
+pub use fg_primitives::{AuthorityId, AuthorityList, AuthorityWeight, VersionedAuthorityList};
 use system::{ensure_signed, DigestOf};
 
 mod mock;
@@ -64,7 +64,7 @@ pub struct OldStoredPendingChange<N> {
 	/// The delay in blocks until it will be applied.
 	pub delay: N,
 	/// The next authority set.
-	pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>,
+	pub next_authorities: AuthorityList,
 }
 
 /// A stored pending change.
@@ -75,7 +75,7 @@ pub struct StoredPendingChange<N> {
 	/// The delay in blocks until it will be applied.
 	pub delay: N,
 	/// The next authority set.
-	pub next_authorities: Vec<(AuthorityId, AuthorityWeight)>,
+	pub next_authorities: AuthorityList,
 	/// If defined it means the change was forced and the given block number
 	/// indicates the median last finalized block when the change was signaled.
 	pub forced: Option<N>,
@@ -126,7 +126,7 @@ pub enum StoredState<N> {
 decl_event!(
 	pub enum Event {
 		/// New authority set has been applied.
-		NewAuthorities(Vec<(AuthorityId, AuthorityWeight)>),
+		NewAuthorities(AuthorityList),
 		/// Current authority set has been paused.
 		Paused,
 		/// Current authority set has been resumed.
@@ -136,8 +136,12 @@ decl_event!(
 
 decl_storage! {
 	trait Store for Module<T: Trait> as GrandpaFinality {
-		/// The current authority set.
-		Authorities get(fn authorities): Vec<(AuthorityId, AuthorityWeight)>;
+		/// DEPRECATED
+		///
+		/// This used to store the current authority set, which has been migrated to the well-known
+		/// GRANDPA_AUTHORITES_KEY unhashed key.
+		#[cfg(feature = "migrate-authorities")]
+		pub(crate) Authorities get(fn authorities): AuthorityList;
 
 		/// State of the current authority set.
 		State get(fn state): StoredState<T::BlockNumber> = StoredState::Live;
@@ -159,7 +163,7 @@ decl_storage! {
 		SetIdSession get(fn session_for_set): map SetId => Option<SessionIndex>;
 	}
 	add_extra_genesis {
-		config(authorities): Vec<(AuthorityId, AuthorityWeight)>;
+		config(authorities): AuthorityList;
 		build(|config| Module::<T>::initialize_authorities(&config.authorities))
 	}
 }
@@ -174,6 +178,11 @@ decl_module! {
 			// FIXME: https://github.com/paritytech/substrate/issues/1112
 		}
 
+		fn on_initialize() {
+			#[cfg(feature = "migrate-authorities")]
+			Self::migrate_authorities();
+		}
+
 		fn on_finalize(block_number: T::BlockNumber) {
 			// check for scheduled pending authority set changes
 			if let Some(pending_change) = <PendingChange<T>>::get() {
@@ -199,7 +208,7 @@ decl_module! {
 
 				// enact the change if we've reached the enacting block
 				if block_number == pending_change.scheduled_at + pending_change.delay {
-					Authorities::put(&pending_change.next_authorities);
+					Self::set_grandpa_authorities(&pending_change.next_authorities);
 					Self::deposit_event(
 						Event::NewAuthorities(pending_change.next_authorities)
 					);
@@ -241,8 +250,16 @@ decl_module! {
 
 impl<T: Trait> Module<T> {
 	/// Get the current set of authorities, along with their respective weights.
-	pub fn grandpa_authorities() -> Vec<(AuthorityId, AuthorityWeight)> {
-		Authorities::get()
+	pub fn grandpa_authorities() -> AuthorityList {
+		storage::unhashed::get_or_default::<VersionedAuthorityList>(GRANDPA_AUTHORITIES_KEY).into()
+	}
+
+	/// Set the current set of authorities, along with their respective weights.
+	fn set_grandpa_authorities(authorities: &AuthorityList) {
+		storage::unhashed::put(
+			GRANDPA_AUTHORITIES_KEY,
+			&VersionedAuthorityList::from(authorities),
+		);
 	}
 
 	/// Schedule GRANDPA to pause starting in the given number of blocks.
@@ -293,7 +310,7 @@ impl<T: Trait> Module<T> {
 	/// No change should be signaled while any change is pending. Returns
 	/// an error if a change is already pending.
 	pub fn schedule_change(
-		next_authorities: Vec<(AuthorityId, AuthorityWeight)>,
+		next_authorities: AuthorityList,
 		in_blocks: T::BlockNumber,
 		forced: Option<T::BlockNumber>,
 	) -> Result {
@@ -329,10 +346,20 @@ impl<T: Trait> Module<T> {
 		<system::Module<T>>::deposit_log(log.into());
 	}
 
-	fn initialize_authorities(authorities: &[(AuthorityId, AuthorityWeight)]) {
+	fn initialize_authorities(authorities: &AuthorityList) {
 		if !authorities.is_empty() {
-			assert!(Authorities::get().is_empty(), "Authorities are already initialized!");
-			Authorities::put(authorities);
+			assert!(
+				Self::grandpa_authorities().is_empty(),
+				"Authorities are already initialized!"
+			);
+			Self::set_grandpa_authorities(authorities);
+		}
+	}
+
+	#[cfg(feature = "migrate-authorities")]
+	fn migrate_authorities() {
+		if Authorities::exists() {
+			Self::set_grandpa_authorities(&Authorities::take());
 		}
 	}
 }
diff --git a/substrate/srml/grandpa/src/mock.rs b/substrate/srml/grandpa/src/mock.rs
index fcacbade20490e19c961ddcfa7d94ba1b216322a..c6ea2075575c545ecb16f09129ec5346f6f3068f 100644
--- a/substrate/srml/grandpa/src/mock.rs
+++ b/substrate/srml/grandpa/src/mock.rs
@@ -23,7 +23,7 @@ use runtime_io;
 use support::{impl_outer_origin, impl_outer_event, parameter_types};
 use primitives::H256;
 use codec::{Encode, Decode};
-use crate::{AuthorityId, GenesisConfig, Trait, Module, ConsensusLog};
+use crate::{AuthorityId, AuthorityList, GenesisConfig, Trait, Module, ConsensusLog};
 use substrate_finality_grandpa_primitives::GRANDPA_ENGINE_ID;
 
 impl_outer_origin!{
@@ -75,7 +75,7 @@ impl_outer_event!{
 	}
 }
 
-pub fn to_authorities(vec: Vec<(u64, u64)>) -> Vec<(AuthorityId, u64)> {
+pub fn to_authorities(vec: Vec<(u64, u64)>) -> AuthorityList {
 	vec.into_iter()
 		.map(|(id, weight)| (UintAuthorityId(id).to_public_key::<AuthorityId>(), weight))
 		.collect()
diff --git a/substrate/srml/grandpa/src/tests.rs b/substrate/srml/grandpa/src/tests.rs
index 2efeb4b5bf3cfc87f69763ef1e07b5a56b3421f2..3d6a8752c5de3bd653ec0198c78e8ac87c2367b5 100644
--- a/substrate/srml/grandpa/src/tests.rs
+++ b/substrate/srml/grandpa/src/tests.rs
@@ -308,3 +308,21 @@ fn time_slot_have_sane_ord() {
 	];
 	assert!(FIXTURE.windows(2).all(|f| f[0] < f[1]));
 }
+
+#[test]
+#[cfg(feature = "migrate-authorities")]
+fn authorities_migration() {
+	use sr_primitives::traits::OnInitialize;
+
+	with_externalities(&mut new_test_ext(vec![]), || {
+		let authorities = to_authorities(vec![(1, 1), (2, 1), (3, 1)]);
+
+		Authorities::put(authorities.clone());
+		assert!(Grandpa::grandpa_authorities().is_empty());
+
+		Grandpa::on_initialize(1);
+
+		assert!(!Authorities::exists());
+		assert_eq!(Grandpa::grandpa_authorities(), authorities);
+	});
+}