diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock
index 64949da009e243c3bf7ad92956793308e92fae05..5bbe6f6f00296ff44ae1d6c06d6f301dc2c7e86b 100644
--- a/substrate/Cargo.lock
+++ b/substrate/Cargo.lock
@@ -1589,9 +1589,9 @@ dependencies = [
 
 [[package]]
 name = "finality-grandpa"
-version = "0.13.0"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2cd795898c348a8ec9edc66ec9e014031c764d4c88cc26d09b492cd93eb41339"
+checksum = "c6447e2f8178843749e8c8003206def83ec124a7859475395777a28b5338647c"
 dependencies = [
  "either",
  "futures 0.3.12",
@@ -7089,6 +7089,7 @@ version = "0.9.0"
 dependencies = [
  "assert_matches",
  "derive_more",
+ "dyn-clone",
  "finality-grandpa",
  "fork-tree",
  "futures 0.3.12",
diff --git a/substrate/bin/node/runtime/src/lib.rs b/substrate/bin/node/runtime/src/lib.rs
index 58c98e529c3196afed59536ecb69f6c18a99f977..53cc0545e9d863ce8fa72ddda568cf4f438ed3c4 100644
--- a/substrate/bin/node/runtime/src/lib.rs
+++ b/substrate/bin/node/runtime/src/lib.rs
@@ -113,7 +113,7 @@ pub const VERSION: RuntimeVersion = RuntimeVersion {
 	// implementation changes and behavior does not, then leave spec_version as
 	// is and increment impl_version.
 	spec_version: 264,
-	impl_version: 0,
+	impl_version: 1,
 	apis: RUNTIME_API_VERSIONS,
 	transaction_version: 2,
 };
diff --git a/substrate/client/finality-grandpa/Cargo.toml b/substrate/client/finality-grandpa/Cargo.toml
index d1ee2fe6b4522e467f52b018adda2d1b6c72a8c5..7ae5666c7bc8474a98fa28711e5c7e7377874c0e 100644
--- a/substrate/client/finality-grandpa/Cargo.toml
+++ b/substrate/client/finality-grandpa/Cargo.toml
@@ -16,6 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 derive_more = "0.99.2"
+dyn-clone = "1.0"
 fork-tree = { version = "3.0.0", path = "../../utils/fork-tree" }
 futures = "0.3.9"
 futures-timer = "3.0.1"
@@ -43,13 +44,13 @@ sc-network-gossip = { version = "0.9.0", path = "../network-gossip" }
 sp-finality-grandpa = { version = "3.0.0", path = "../../primitives/finality-grandpa" }
 prometheus-endpoint = { package = "substrate-prometheus-endpoint", path = "../../utils/prometheus", version = "0.9.0"}
 sc-block-builder = { version = "0.9.0", path = "../block-builder" }
-finality-grandpa = { version = "0.13.0", features = ["derive-codec"] }
+finality-grandpa = { version = "0.14.0", features = ["derive-codec"] }
 pin-project = "1.0.4"
 linked-hash-map = "0.5.2"
 
 [dev-dependencies]
 assert_matches = "1.3.0"
-finality-grandpa = { version = "0.13.0", features = ["derive-codec", "test-helpers"] }
+finality-grandpa = { version = "0.14.0", features = ["derive-codec", "test-helpers"] }
 sc-network = { version = "0.9.0", path = "../network" }
 sc-network-test = { version = "0.8.0", path = "../network/test" }
 sp-keyring = { version = "3.0.0", path = "../../primitives/keyring" }
diff --git a/substrate/client/finality-grandpa/rpc/Cargo.toml b/substrate/client/finality-grandpa/rpc/Cargo.toml
index 58aa78a38b103f20a8f1d12503616b26b6b1ed0f..ff5b4cafdae77c3f12f6f9090ffdc204f3089acf 100644
--- a/substrate/client/finality-grandpa/rpc/Cargo.toml
+++ b/substrate/client/finality-grandpa/rpc/Cargo.toml
@@ -14,7 +14,7 @@ sc-rpc = { version = "3.0.0", path = "../../rpc" }
 sp-blockchain = { version = "3.0.0", path = "../../../primitives/blockchain" }
 sp-core = { version = "3.0.0", path = "../../../primitives/core" }
 sp-runtime = { version = "3.0.0", path = "../../../primitives/runtime" }
-finality-grandpa = { version = "0.13.0", features = ["derive-codec"] }
+finality-grandpa = { version = "0.14.0", features = ["derive-codec"] }
 jsonrpc-core = "15.1.0"
 jsonrpc-core-client = "15.1.0"
 jsonrpc-derive = "15.1.0"
diff --git a/substrate/client/finality-grandpa/src/environment.rs b/substrate/client/finality-grandpa/src/environment.rs
index 55a60e16dfd31a4a14f95efd0dd0fed18456f653..7925a674c2983826ec70073830e8bd72f01ea3ca 100644
--- a/substrate/client/finality-grandpa/src/environment.rs
+++ b/substrate/client/finality-grandpa/src/environment.rs
@@ -592,100 +592,6 @@ where
 	fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result<Vec<Block::Hash>, GrandpaError> {
 		ancestry(&self.client, base, block)
 	}
-
-	fn best_chain_containing(&self, block: Block::Hash) -> Option<(Block::Hash, NumberFor<Block>)> {
-		// NOTE: when we finalize an authority set change through the sync protocol the voter is
-		//       signaled asynchronously. therefore the voter could still vote in the next round
-		//       before activating the new set. the `authority_set` is updated immediately thus we
-		//       restrict the voter based on that.
-		if self.set_id != self.authority_set.set_id() {
-			return None;
-		}
-
-		let base_header = match self.client.header(BlockId::Hash(block)).ok()? {
-			Some(h) => h,
-			None => {
-				debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find base block", block);
-				return None;
-			}
-		};
-
-		// we refuse to vote beyond the current limit number where transitions are scheduled to
-		// occur.
-		// once blocks are finalized that make that transition irrelevant or activate it,
-		// we will proceed onwards. most of the time there will be no pending transition.
-		// the limit, if any, is guaranteed to be higher than or equal to the given base number.
-		let limit = self.authority_set.current_limit(*base_header.number());
-		debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
-
-		match self.select_chain.finality_target(block, None) {
-			Ok(Some(best_hash)) => {
-				let best_header = self.client.header(BlockId::Hash(best_hash)).ok()?
-					.expect("Header known to exist after `finality_target` call; qed");
-
-				// check if our vote is currently being limited due to a pending change
-				let limit = limit.filter(|limit| limit < best_header.number());
-				let target;
-
-				let target_header = if let Some(target_number) = limit {
-					let mut target_header = best_header.clone();
-
-					// walk backwards until we find the target block
-					loop {
-						if *target_header.number() < target_number {
-							unreachable!(
-								"we are traversing backwards from a known block; \
-								 blocks are stored contiguously; \
-								 qed"
-							);
-						}
-
-						if *target_header.number() == target_number {
-							break;
-						}
-
-						target_header = self.client.header(BlockId::Hash(*target_header.parent_hash())).ok()?
-							.expect("Header known to exist after `finality_target` call; qed");
-					}
-
-					target = target_header;
-					&target
-				} else {
-					// otherwise just use the given best as the target
-					&best_header
-				};
-
-				// restrict vote according to the given voting rule, if the
-				// voting rule doesn't restrict the vote then we keep the
-				// previous target.
-				//
-				// note that we pass the original `best_header`, i.e. before the
-				// authority set limit filter, which can be considered a
-				// mandatory/implicit voting rule.
-				//
-				// we also make sure that the restricted vote is higher than the
-				// round base (i.e. last finalized), otherwise the value
-				// returned by the given voting rule is ignored and the original
-				// target is used instead.
-				self.voting_rule
-					.restrict_vote(&*self.client, &base_header, &best_header, target_header)
-					.filter(|(_, restricted_number)| {
-						// we can only restrict votes within the interval [base, target]
-						restricted_number >= base_header.number() &&
-							restricted_number < target_header.number()
-					})
-					.or_else(|| Some((target_header.hash(), *target_header.number())))
-			},
-			Ok(None) => {
-				debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block);
-				None
-			}
-			Err(e) => {
-				debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
-				None
-			}
-		}
-	}
 }
 
 
@@ -733,6 +639,14 @@ where
 	NumberFor<Block>: BlockNumberOps,
 {
 	type Timer = Pin<Box<dyn Future<Output = Result<(), Self::Error>> + Send + Sync>>;
+	type BestChain = Pin<
+		Box<
+			dyn Future<Output = Result<Option<(Block::Hash, NumberFor<Block>)>, Self::Error>>
+				+ Send
+				+ Sync
+		>,
+	>;
+
 	type Id = AuthorityId;
 	type Signature = AuthoritySignature;
 
@@ -747,6 +661,119 @@ where
 
 	type Error = CommandOrError<Block::Hash, NumberFor<Block>>;
 
+	fn best_chain_containing(&self, block: Block::Hash) -> Self::BestChain {
+		let find_best_chain = || {
+			// NOTE: when we finalize an authority set change through the sync protocol the voter is
+			//       signaled asynchronously. therefore the voter could still vote in the next round
+			//       before activating the new set. the `authority_set` is updated immediately thus we
+			//       restrict the voter based on that.
+			if self.set_id != self.authority_set.set_id() {
+				return None;
+			}
+
+			let base_header = match self.client.header(BlockId::Hash(block)).ok()? {
+				Some(h) => h,
+				None => {
+					debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find base block", block);
+					return None;
+				}
+			};
+
+			// we refuse to vote beyond the current limit number where transitions are scheduled to
+			// occur.
+			// once blocks are finalized that make that transition irrelevant or activate it,
+			// we will proceed onwards. most of the time there will be no pending transition.
+			// the limit, if any, is guaranteed to be higher than or equal to the given base number.
+			let limit = self.authority_set.current_limit(*base_header.number());
+			debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
+
+			match self.select_chain.finality_target(block, None) {
+				Ok(Some(best_hash)) => {
+					let best_header = self
+						.client
+						.header(BlockId::Hash(best_hash))
+						.ok()?
+						.expect("Header known to exist after `finality_target` call; qed");
+
+					// check if our vote is currently being limited due to a pending change
+					let limit = limit.filter(|limit| limit < best_header.number());
+
+					if let Some(target_number) = limit {
+						let mut target_header = best_header.clone();
+
+						// walk backwards until we find the target block
+						loop {
+							if *target_header.number() < target_number {
+								unreachable!(
+									"we are traversing backwards from a known block; \
+									 blocks are stored contiguously; \
+									 qed"
+								);
+							}
+
+							if *target_header.number() == target_number {
+								break;
+							}
+
+							target_header = self
+								.client
+								.header(BlockId::Hash(*target_header.parent_hash()))
+								.ok()?
+								.expect("Header known to exist after `finality_target` call; qed");
+						}
+
+						Some((base_header, best_header, target_header))
+					} else {
+						// otherwise just use the given best as the target
+						Some((base_header, best_header.clone(), best_header))
+					}
+				}
+				Ok(None) => {
+					debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block);
+					None
+				}
+				Err(e) => {
+					debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
+					None
+				}
+			}
+		};
+
+		if let Some((base_header, best_header, target_header)) = find_best_chain() {
+			// restrict vote according to the given voting rule, if the
+			// voting rule doesn't restrict the vote then we keep the
+			// previous target.
+			//
+			// note that we pass the original `best_header`, i.e. before the
+			// authority set limit filter, which can be considered a
+			// mandatory/implicit voting rule.
+			//
+			// we also make sure that the restricted vote is higher than the
+			// round base (i.e. last finalized), otherwise the value
+			// returned by the given voting rule is ignored and the original
+			// target is used instead.
+			let rule_fut = self.voting_rule.restrict_vote(
+				self.client.clone(),
+				&base_header,
+				&best_header,
+				&target_header,
+			);
+
+			Box::pin(async move {
+				Ok(rule_fut
+					.await
+					.filter(|(_, restricted_number)| {
+						// we can only restrict votes within the interval [base, target]
+						restricted_number >= base_header.number()
+							&& restricted_number < target_header.number()
+					})
+					.or_else(|| Some((target_header.hash(), *target_header.number()))))
+			})
+		} else {
+			Box::pin(future::ok(None))
+		}
+	}
+
 	fn round_data(
 		&self,
 		round: RoundNumber,
diff --git a/substrate/client/finality-grandpa/src/justification.rs b/substrate/client/finality-grandpa/src/justification.rs
index 9429acff06d8ce9f160bc78de66bf16032a79918..eba909bad5ef687d5091009d324dbc7f906e7d40 100644
--- a/substrate/client/finality-grandpa/src/justification.rs
+++ b/substrate/client/finality-grandpa/src/justification.rs
@@ -217,8 +217,4 @@ impl<Block: BlockT> finality_grandpa::Chain<Block::Hash, NumberFor<Block>> for A
 
 		Ok(route)
 	}
-
-	fn best_chain_containing(&self, _block: Block::Hash) -> Option<(Block::Hash, NumberFor<Block>)> {
-		None
-	}
 }
diff --git a/substrate/client/finality-grandpa/src/lib.rs b/substrate/client/finality-grandpa/src/lib.rs
index 75500a894d745293380d87aa7f07e00ef0795638..809e14e5c90b5e801ff41ad52f0c7538d659541b 100644
--- a/substrate/client/finality-grandpa/src/lib.rs
+++ b/substrate/client/finality-grandpa/src/lib.rs
@@ -127,7 +127,8 @@ pub use notification::{GrandpaJustificationSender, GrandpaJustificationStream};
 pub use import::GrandpaBlockImport;
 pub use justification::GrandpaJustification;
 pub use voting_rule::{
-	BeforeBestBlockBy, ThreeQuartersOfTheUnfinalizedChain, VotingRule, VotingRulesBuilder
+	BeforeBestBlockBy, ThreeQuartersOfTheUnfinalizedChain, VotingRule, VotingRuleResult,
+	VotingRulesBuilder,
 };
 pub use finality_grandpa::voter::report;
 pub use finality_proof::{prove_warp_sync, WarpSyncFragmentCache};
diff --git a/substrate/client/finality-grandpa/src/observer.rs b/substrate/client/finality-grandpa/src/observer.rs
index c9db917e1699a89f11c816e6b8edbc7a4f54fc47..3054a9df61c56e23d9bf4aa70ba04e4be191686f 100644
--- a/substrate/client/finality-grandpa/src/observer.rs
+++ b/substrate/client/finality-grandpa/src/observer.rs
@@ -57,11 +57,6 @@ impl<'a, Block, Client> finality_grandpa::Chain<Block::Hash, NumberFor<Block>>
 	fn ancestry(&self, base: Block::Hash, block: Block::Hash) -> Result<Vec<Block::Hash>, GrandpaError> {
 		environment::ancestry(&self.client, base, block)
 	}
-
-	fn best_chain_containing(&self, _block: Block::Hash) -> Option<(Block::Hash, NumberFor<Block>)> {
-		// only used by voter
-		None
-	}
 }
 
 fn grandpa_observer<BE, Block: BlockT, Client, S, F>(
diff --git a/substrate/client/finality-grandpa/src/tests.rs b/substrate/client/finality-grandpa/src/tests.rs
index 4918255d027a8f4913fc8f1a633a54600618d4c3..921b49db61c2558bd80f49bda6851d7e0e56f959 100644
--- a/substrate/client/finality-grandpa/src/tests.rs
+++ b/substrate/client/finality-grandpa/src/tests.rs
@@ -1355,7 +1355,7 @@ where
 
 #[test]
 fn grandpa_environment_respects_voting_rules() {
-	use finality_grandpa::Chain;
+	use finality_grandpa::voter::Environment;
 
 	let peers = &[Ed25519Keyring::Alice];
 	let voters = make_ids(peers);
@@ -1390,25 +1390,25 @@ fn grandpa_environment_respects_voting_rules() {
 
 	// the unrestricted environment should just return the best block
 	assert_eq!(
-		unrestricted_env.best_chain_containing(
+		futures::executor::block_on(unrestricted_env.best_chain_containing(
 			peer.client().info().finalized_hash
-		).unwrap().1,
+		)).unwrap().unwrap().1,
 		21,
 	);
 
 	// both the other environments should return block 16, which is 3/4 of the
 	// way in the unfinalized chain
 	assert_eq!(
-		three_quarters_env.best_chain_containing(
+		futures::executor::block_on(three_quarters_env.best_chain_containing(
 			peer.client().info().finalized_hash
-		).unwrap().1,
+		)).unwrap().unwrap().1,
 		16,
 	);
 
 	assert_eq!(
-		default_env.best_chain_containing(
+		futures::executor::block_on(default_env.best_chain_containing(
 			peer.client().info().finalized_hash
-		).unwrap().1,
+		)).unwrap().unwrap().1,
 		16,
 	);
 
@@ -1417,18 +1417,18 @@ fn grandpa_environment_respects_voting_rules() {
 
 	// the 3/4 environment should propose block 21 for voting
 	assert_eq!(
-		three_quarters_env.best_chain_containing(
+		futures::executor::block_on(three_quarters_env.best_chain_containing(
 			peer.client().info().finalized_hash
-		).unwrap().1,
+		)).unwrap().unwrap().1,
 		21,
 	);
 
 	// while the default environment will always still make sure we don't vote
 	// on the best block (2 behind)
 	assert_eq!(
-		default_env.best_chain_containing(
+		futures::executor::block_on(default_env.best_chain_containing(
 			peer.client().info().finalized_hash
-		).unwrap().1,
+		)).unwrap().unwrap().1,
 		19,
 	);
 
@@ -1439,9 +1439,9 @@ fn grandpa_environment_respects_voting_rules() {
 	// best block, there's a hard rule that we can't cast any votes lower than
 	// the given base (#21).
 	assert_eq!(
-		default_env.best_chain_containing(
+		futures::executor::block_on(default_env.best_chain_containing(
 			peer.client().info().finalized_hash
-		).unwrap().1,
+		)).unwrap().unwrap().1,
 		21,
 	);
 }
diff --git a/substrate/client/finality-grandpa/src/voting_rule.rs b/substrate/client/finality-grandpa/src/voting_rule.rs
index a861e792755feaed872caff1cc644ceab751e8b8..e7b74c3e3296e876a3a68a180d1382447895b13b 100644
--- a/substrate/client/finality-grandpa/src/voting_rule.rs
+++ b/substrate/client/finality-grandpa/src/voting_rule.rs
@@ -22,14 +22,22 @@
 //! restrictions that are taken into account by the GRANDPA environment when
 //! selecting a finality target to vote on.
 
+use std::future::Future;
 use std::sync::Arc;
+use std::pin::Pin;
+
+use dyn_clone::DynClone;
 
 use sc_client_api::blockchain::HeaderBackend;
 use sp_runtime::generic::BlockId;
 use sp_runtime::traits::{Block as BlockT, Header, NumberFor, One, Zero};
 
+/// A future returned by a `VotingRule` to restrict a given vote, if any restriction is necessary.
+pub type VotingRuleResult<Block> =
+	Pin<Box<dyn Future<Output = Option<(<Block as BlockT>::Hash, NumberFor<Block>)>> + Send + Sync>>;
+
 /// A trait for custom voting rules in GRANDPA.
-pub trait VotingRule<Block, B>: Send + Sync where
+pub trait VotingRule<Block, B>: DynClone + Send + Sync where
 	Block: BlockT,
 	B: HeaderBackend<Block>,
 {
@@ -47,11 +55,11 @@ pub trait VotingRule<Block, B>: Send + Sync where
 	/// execution of voting rules wherein `current_target <= best_target`.
 	fn restrict_vote(
 		&self,
-		backend: &B,
+		backend: Arc<B>,
 		base: &Block::Header,
 		best_target: &Block::Header,
 		current_target: &Block::Header,
-	) -> Option<(Block::Hash, NumberFor<Block>)>;
+	) -> VotingRuleResult<Block>;
 }
 
 impl<Block, B> VotingRule<Block, B> for () where
@@ -60,12 +68,12 @@ impl<Block, B> VotingRule<Block, B> for () where
 {
 	fn restrict_vote(
 		&self,
-		_backend: &B,
+		_backend: Arc<B>,
 		_base: &Block::Header,
 		_best_target: &Block::Header,
 		_current_target: &Block::Header,
-	) -> Option<(Block::Hash, NumberFor<Block>)> {
-		None
+	) -> VotingRuleResult<Block> {
+		Box::pin(async { None })
 	}
 }
 
@@ -80,15 +88,15 @@ impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>> wher
 {
 	fn restrict_vote(
 		&self,
-		backend: &B,
+		backend: Arc<B>,
 		_base: &Block::Header,
 		best_target: &Block::Header,
 		current_target: &Block::Header,
-	) -> Option<(Block::Hash, NumberFor<Block>)> {
+	) -> VotingRuleResult<Block> {
 		use sp_arithmetic::traits::Saturating;
 
 		if current_target.number().is_zero() {
-			return None;
+			return Box::pin(async { None });
 		}
 
 		// find the target number restricted by this rule
@@ -96,21 +104,24 @@ impl<Block, B> VotingRule<Block, B> for BeforeBestBlockBy<NumberFor<Block>> wher
 
 		// our current target is already lower than this rule would restrict
 		if target_number >= *current_target.number() {
-			return None;
+			return Box::pin(async { None });
 		}
 
+		let current_target = current_target.clone();
+
 		// find the block at the given target height
-		find_target(
-			backend,
-			target_number,
-			current_target,
-		)
+		Box::pin(std::future::ready(find_target(
+			&*backend,
+			target_number.clone(),
+			&current_target,
+		)))
 	}
 }
 
 /// A custom voting rule that limits votes towards 3/4 of the unfinalized chain,
 /// using the given `base` and `best_target` to figure where the 3/4 target
 /// should fall.
+#[derive(Clone)]
 pub struct ThreeQuartersOfTheUnfinalizedChain;
 
 impl<Block, B> VotingRule<Block, B> for ThreeQuartersOfTheUnfinalizedChain where
@@ -119,11 +130,11 @@ impl<Block, B> VotingRule<Block, B> for ThreeQuartersOfTheUnfinalizedChain where
 {
 	fn restrict_vote(
 		&self,
-		backend: &B,
+		backend: Arc<B>,
 		base: &Block::Header,
 		best_target: &Block::Header,
 		current_target: &Block::Header,
-	) -> Option<(Block::Hash, NumberFor<Block>)> {
+	) -> VotingRuleResult<Block> {
 		// target a vote towards 3/4 of the unfinalized chain (rounding up)
 		let target_number = {
 			let two = NumberFor::<Block>::one() + One::one();
@@ -138,15 +149,15 @@ impl<Block, B> VotingRule<Block, B> for ThreeQuartersOfTheUnfinalizedChain where
 
 		// our current target is already lower than this rule would restrict
 		if target_number >= *current_target.number() {
-			return None;
+			return Box::pin(async { None });
 		}
 
 		// find the block at the given target height
-		find_target(
-			backend,
+		Box::pin(std::future::ready(find_target(
+			&*backend,
 			target_number,
 			current_target,
-		)
+		)))
 	}
 }
 
@@ -195,37 +206,42 @@ impl<B, Block> Clone for VotingRules<B, Block> {
 
 impl<Block, B> VotingRule<Block, B> for VotingRules<Block, B> where
 	Block: BlockT,
-	B: HeaderBackend<Block>,
+	B: HeaderBackend<Block> + 'static,
 {
 	fn restrict_vote(
 		&self,
-		backend: &B,
+		backend: Arc<B>,
 		base: &Block::Header,
 		best_target: &Block::Header,
 		current_target: &Block::Header,
-	) -> Option<(Block::Hash, NumberFor<Block>)> {
-		let restricted_target = self.rules.iter().fold(
-			current_target.clone(),
-			|current_target, rule| {
-				rule.restrict_vote(
-					backend,
-					base,
-					best_target,
-					&current_target,
-				)
+	) -> VotingRuleResult<Block> {
+		let rules = self.rules.clone();
+		let base = base.clone();
+		let best_target = best_target.clone();
+		let current_target = current_target.clone();
+
+		Box::pin(async move {
+			let mut restricted_target = current_target.clone();
+
+			for rule in rules.iter() {
+				if let Some(header) = rule
+					.restrict_vote(backend.clone(), &base, &best_target, &restricted_target)
+					.await
 					.and_then(|(hash, _)| backend.header(BlockId::Hash(hash)).ok())
 					.and_then(std::convert::identity)
-					.unwrap_or(current_target)
-			},
-		);
-
-		let restricted_hash = restricted_target.hash();
-
-		if restricted_hash != current_target.hash() {
-			Some((restricted_hash, *restricted_target.number()))
-		} else {
-			None
-		}
+				{
+					restricted_target = header;
+				}
+			}
+
+			let restricted_hash = restricted_target.hash();
+
+			if restricted_hash != current_target.hash() {
+				Some((restricted_hash, *restricted_target.number()))
+			} else {
+				None
+			}
+		})
 	}
 }
 
@@ -237,7 +253,7 @@ pub struct VotingRulesBuilder<Block, B> {
 
 impl<Block, B> Default for VotingRulesBuilder<Block, B> where
 	Block: BlockT,
-	B: HeaderBackend<Block>,
+	B: HeaderBackend<Block> + 'static,
 {
 	fn default() -> Self {
 		VotingRulesBuilder::new()
@@ -248,7 +264,7 @@ impl<Block, B> Default for VotingRulesBuilder<Block, B> where
 
 impl<Block, B> VotingRulesBuilder<Block, B> where
 	Block: BlockT,
-	B: HeaderBackend<Block>,
+	B: HeaderBackend<Block> + 'static,
 {
 	/// Return a new voting rule builder using the given backend.
 	pub fn new() -> Self {
@@ -285,14 +301,15 @@ impl<Block, B> VotingRulesBuilder<Block, B> where
 impl<Block, B> VotingRule<Block, B> for Box<dyn VotingRule<Block, B>> where
 	Block: BlockT,
 	B: HeaderBackend<Block>,
+	Self: Clone,
 {
 	fn restrict_vote(
 		&self,
-		backend: &B,
+		backend: Arc<B>,
 		base: &Block::Header,
 		best_target: &Block::Header,
 		current_target: &Block::Header,
-	) -> Option<(Block::Hash, NumberFor<Block>)> {
+	) -> VotingRuleResult<Block> {
 		(**self).restrict_vote(backend, base, best_target, current_target)
 	}
 }
diff --git a/substrate/frame/grandpa/Cargo.toml b/substrate/frame/grandpa/Cargo.toml
index a9ba0ccc56f3b655ea5197039aa3ca3225e62de0..3e85ff50d3e12e600bbdeafa3f9d5829e1ee9a17 100644
--- a/substrate/frame/grandpa/Cargo.toml
+++ b/substrate/frame/grandpa/Cargo.toml
@@ -30,7 +30,7 @@ pallet-session = { version = "3.0.0", default-features = false, path = "../sessi
 
 [dev-dependencies]
 frame-benchmarking = { version = "3.0.0", path = "../benchmarking" }
-grandpa = { package = "finality-grandpa", version = "0.13.0", features = ["derive-codec"] }
+grandpa = { package = "finality-grandpa", version = "0.14.0", features = ["derive-codec"] }
 sp-io = { version = "3.0.0", path = "../../primitives/io" }
 sp-keyring = { version = "3.0.0", path = "../../primitives/keyring" }
 pallet-balances = { version = "3.0.0", path = "../balances" }
diff --git a/substrate/primitives/finality-grandpa/Cargo.toml b/substrate/primitives/finality-grandpa/Cargo.toml
index c8ff2fc0a2e651c8075bec0e7360eb5b5e73b78e..95aa65c930f7897d60cb1bc030542918870cd49c 100644
--- a/substrate/primitives/finality-grandpa/Cargo.toml
+++ b/substrate/primitives/finality-grandpa/Cargo.toml
@@ -16,7 +16,7 @@ targets = ["x86_64-unknown-linux-gnu"]
 
 [dependencies]
 codec = { package = "parity-scale-codec", version = "2.0.0", default-features = false, features = ["derive"] }
-grandpa = { package = "finality-grandpa", version = "0.13.0", default-features = false, features = ["derive-codec"] }
+grandpa = { package = "finality-grandpa", version = "0.14.0", default-features = false, features = ["derive-codec"] }
 log = { version = "0.4.8", optional = true }
 serde = { version = "1.0.101", optional = true, features = ["derive"] }
 sp-api = { version = "3.0.0", default-features = false, path = "../api" }