diff --git a/substrate/core/client/db/src/lib.rs b/substrate/core/client/db/src/lib.rs
index 13a0928e38cab0344c1484c6877e0c54051b8aee..e55c1eb281fa8804b5e565f437de26983aa395c0 100644
--- a/substrate/core/client/db/src/lib.rs
+++ b/substrate/core/client/db/src/lib.rs
@@ -257,6 +257,7 @@ pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
 	pending_block: Option<PendingBlock<Block>>,
 	aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
+	set_head: Option<BlockId<Block>>,
 }
 
 impl<Block: BlockT, H: Hasher> BlockImportOperation<Block, H> {
@@ -355,6 +356,12 @@ where Block: BlockT<Hash=H256>,
 		self.finalized_blocks.push((block, justification));
 		Ok(())
 	}
+
+	fn mark_head(&mut self, block: BlockId<Block>) -> Result<(), client::error::Error> {
+		assert!(self.set_head.is_none(), "Only one set head per operation is allowed");
+		self.set_head = Some(block);
+		Ok(())
+	}
 }
 
 struct StorageDb<Block: BlockT> {
@@ -563,6 +570,71 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 		})
 	}
 
+	/// Handle setting head within a transaction. `route_to` should be the last
+	/// block that existed in the database. `best_to` should be the best block
+	/// to be set.
+	///
+	/// In the case where the new best block is a block to be imported, `route_to`
+	/// should be the parent of `best_to`. In the case where we set an existing block
+	/// to be best, `route_to` should equal to `best_to`.
+	fn set_head_with_transaction(&self, transaction: &mut DBTransaction, route_to: Block::Hash, best_to: (NumberFor<Block>, Block::Hash)) -> Result<(Vec<Block::Hash>, Vec<Block::Hash>), client::error::Error> {
+		let mut enacted = Vec::default();
+		let mut retracted = Vec::default();
+
+		let meta = self.blockchain.meta.read();
+
+		// cannot find tree route with empty DB.
+		if meta.best_hash != Default::default() {
+			let tree_route = ::client::blockchain::tree_route(
+				&self.blockchain,
+				BlockId::Hash(meta.best_hash),
+				BlockId::Hash(route_to),
+			)?;
+
+			// uncanonicalize: check safety violations and ensure the numbers no longer
+			// point to these block hashes in the key mapping.
+			for r in tree_route.retracted() {
+				if r.hash == meta.finalized_hash {
+					warn!(
+						"Potential safety failure: reverting finalized block {:?}",
+						(&r.number, &r.hash)
+					);
+
+					return Err(::client::error::ErrorKind::NotInFinalizedChain.into());
+				}
+
+				retracted.push(r.hash.clone());
+				utils::remove_number_to_key_mapping(
+					transaction,
+					columns::KEY_LOOKUP,
+					r.number
+				);
+			}
+
+			// canonicalize: set the number lookup to map to this block's hash.
+			for e in tree_route.enacted() {
+				enacted.push(e.hash.clone());
+				utils::insert_number_to_key_mapping(
+					transaction,
+					columns::KEY_LOOKUP,
+					e.number,
+					e.hash
+				);
+			}
+		}
+
+		let lookup_key = utils::number_and_hash_to_lookup_key(best_to.0, &best_to.1);
+		transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
+		utils::insert_number_to_key_mapping(
+			transaction,
+			columns::KEY_LOOKUP,
+			best_to.0,
+			best_to.1,
+		);
+
+		Ok((enacted, retracted))
+	}
+
 	fn ensure_sequential_finalization(
 		&self,
 		header: &Block::Header,
@@ -592,7 +664,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 		if let Some(justification) = justification {
 			transaction.put(
 				columns::JUSTIFICATION,
-				&utils::number_and_hash_to_lookup_key(number, *hash),
+				&utils::number_and_hash_to_lookup_key(number, hash),
 				&justification.encode(),
 			);
 		}
@@ -657,7 +729,7 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 			}
 		}
 
-		if let Some(pending_block) = operation.pending_block {
+		let imported = if let Some(pending_block) = operation.pending_block {
 			let hash = pending_block.header.hash();
 			let parent_hash = *pending_block.header.parent_hash();
 			let number = pending_block.header.number().clone();
@@ -665,58 +737,11 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 			// blocks are keyed by number + hash.
 			let lookup_key = utils::number_and_hash_to_lookup_key(number, hash);
 
-			let mut enacted = Vec::default();
-			let mut retracted = Vec::default();
-
-			if pending_block.leaf_state.is_best() {
-				let meta = self.blockchain.meta.read();
-
-				// cannot find tree route with empty DB.
-				if meta.best_hash != Default::default() {
-					let tree_route = ::client::blockchain::tree_route(
-						&self.blockchain,
-						BlockId::Hash(meta.best_hash),
-						BlockId::Hash(parent_hash),
-					)?;
-
-					// uncanonicalize: check safety violations and ensure the numbers no longer
-					// point to these block hashes in the key mapping.
-					for r in tree_route.retracted() {
-						retracted.push(r.hash.clone());
-						if r.hash == meta.finalized_hash {
-							warn!("Potential safety failure: reverting finalized block {:?}",
-								(&r.number, &r.hash));
-
-							return Err(::client::error::ErrorKind::NotInFinalizedChain.into());
-						}
-
-						utils::remove_number_to_key_mapping(
-							&mut transaction,
-							columns::KEY_LOOKUP,
-							r.number
-						);
-					}
-
-					// canonicalize: set the number lookup to map to this block's hash.
-					for e in tree_route.enacted() {
-						enacted.push(e.hash.clone());
-						utils::insert_number_to_key_mapping(
-							&mut transaction,
-							columns::KEY_LOOKUP,
-							e.number,
-							e.hash
-						);
-					}
-				}
-
-				transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
-				utils::insert_number_to_key_mapping(
-					&mut transaction,
-					columns::KEY_LOOKUP,
-					number,
-					hash,
-				);
-			}
+			let (enacted, retracted) = if pending_block.leaf_state.is_best() {
+				self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))?
+			} else {
+				(Default::default(), Default::default())
+			};
 
 			utils::insert_hash_to_key_mapping(
 				&mut transaction,
@@ -752,15 +777,12 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 			apply_state_commit(&mut transaction, commit);
 
 			// Check if need to finalize. Genesis is always finalized instantly.
-			let finalized = number_u64 == 0 || match pending_block.leaf_state {
-				NewBlockState::Final => true,
-				_ => false,
-			};
+			let finalized = number_u64 == 0 || pending_block.leaf_state.is_final();
 
 			let header = &pending_block.header;
 			let is_best = pending_block.leaf_state.is_best();
 			let changes_trie_updates = operation.changes_trie_updates;
-		
+
 			self.changes_tries_storage.commit(&mut transaction, changes_trie_updates);
 
 			if finalized {
@@ -774,49 +796,60 @@ impl<Block: BlockT<Hash=H256>> Backend<Block> {
 
 			debug!(target: "db", "DB Commit {:?} ({}), best = {}", hash, number, is_best);
 
-			{
+			let displaced_leaf = {
 				let mut leaves = self.blockchain.leaves.write();
 				let displaced_leaf = leaves.import(hash, number, parent_hash);
 				leaves.prepare_transaction(&mut transaction, columns::META, meta_keys::LEAF_PREFIX);
 
-				let write_result = self.storage.db.write(transaction).map_err(db_err);
-				if let Err(e) = write_result {
-					// revert leaves set update, if there was one.
-					if let Some(displaced_leaf) = displaced_leaf {
-						leaves.undo(displaced_leaf);
-					}
-					return Err(e);
-				}
-				drop(leaves);
-			}
+				displaced_leaf
+			};
+
+			meta_updates.push((hash, number, pending_block.leaf_state.is_best(), finalized));
+
+			Some((number, hash, enacted, retracted, displaced_leaf, is_best))
+		} else {
+			None
+		};
+
+		if let Some(set_head) = operation.set_head {
+			if let Some(header) = ::client::blockchain::HeaderBackend::header(&self.blockchain, set_head)? {
+				let number = header.number();
+				let hash = header.hash();
 
-			for (hash, number, is_best, is_finalized) in meta_updates {
-				self.blockchain.update_meta(hash, number, is_best, is_finalized);
+				self.set_head_with_transaction(
+					&mut transaction,
+					hash.clone(),
+					(number.clone(), hash.clone())
+				)?;
+			} else {
+				return Err(client::error::ErrorKind::UnknownBlock(format!("Cannot set head {:?}", set_head)).into())
 			}
+		}
 
-			self.blockchain.update_meta(
-				hash.clone(),
-				number.clone(),
-				is_best,
-				finalized,
-			);
+		let write_result = self.storage.db.write(transaction).map_err(db_err);
+
+		if let Some((number, hash, enacted, retracted, displaced_leaf, is_best)) = imported {
+			if let Err(e) = write_result {
+				if let Some(displaced_leaf) = displaced_leaf {
+					self.blockchain.leaves.write().undo(displaced_leaf);
+				}
+				return Err(e)
+			}
 
-			// sync canonical state cache
 			operation.old_state.sync_cache(
 				&enacted,
 				&retracted,
 				operation.storage_updates,
 				Some(hash),
 				Some(number),
-				|| is_best
+				|| is_best,
 			);
-		} else {
-			// No pending block, just write the transaction and apply meta changes
-			self.storage.db.write(transaction).map_err(db_err)?;
-			for (hash, number, is_best, is_finalized) in meta_updates {
-				self.blockchain.update_meta(hash, number, is_best, is_finalized);
-			}
 		}
+
+		for (hash, number, is_best, is_finalized) in meta_updates {
+			self.blockchain.update_meta(hash, number, is_best, is_finalized);
+		}
+
 		Ok(())
 	}
 
@@ -911,6 +944,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
 			changes_trie_updates: MemoryDB::default(),
 			aux_ops: Vec::new(),
 			finalized_blocks: Vec::new(),
+			set_head: None,
 		})
 	}
 
@@ -990,7 +1024,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
 					let hash = self.blockchain.hash(best)?.ok_or_else(
 						|| client::error::ErrorKind::UnknownBlock(
 							format!("Error reverting to {}. Block hash not found.", best)))?;
-					let key = utils::number_and_hash_to_lookup_key(best.clone(), hash.clone());
+					let key = utils::number_and_hash_to_lookup_key(best.clone(), &hash);
 					transaction.put(columns::META, meta_keys::BEST_BLOCK, &key);
 					transaction.delete(columns::KEY_LOOKUP, removed.hash().as_ref());
 					self.storage.db.write(transaction).map_err(db_err)?;
@@ -1032,7 +1066,7 @@ impl<Block> client::backend::Backend<Block, Blake2Hasher> for Backend<Block> whe
 					Err(client::error::ErrorKind::UnknownBlock(format!("State already discarded for {:?}", block)).into())
 				}
 			},
-			Ok(None) => Err(client::error::ErrorKind::UnknownBlock(format!("{:?}", block)).into()),
+			Ok(None) => Err(client::error::ErrorKind::UnknownBlock(format!("Unknown state for block {:?}", block)).into()),
 			Err(e) => Err(e),
 		}
 	}
diff --git a/substrate/core/client/db/src/light.rs b/substrate/core/client/db/src/light.rs
index 4221edfa91fcfd6aa14f793fcabbdab0de7427c5..6a0c9646b0bd6d5a960f8fc5d09e51f9928d0988 100644
--- a/substrate/core/client/db/src/light.rs
+++ b/substrate/core/client/db/src/light.rs
@@ -189,6 +189,61 @@ impl<Block: BlockT> LightStorage<Block> {
 					.cloned()))
 	}
 
+	/// Handle setting head within a transaction. `route_to` should be the last
+	/// block that existed in the database. `best_to` should be the best block
+	/// to be set.
+	///
+	/// In the case where the new best block is a block to be imported, `route_to`
+	/// should be the parent of `best_to`. In the case where we set an existing block
+	/// to be best, `route_to` should equal to `best_to`.
+	fn set_head_with_transaction(&self, transaction: &mut DBTransaction, route_to: Block::Hash, best_to: (NumberFor<Block>, Block::Hash)) -> Result<(), client::error::Error> {
+		let lookup_key = utils::number_and_hash_to_lookup_key(best_to.0, &best_to.1);
+
+		// handle reorg.
+		let meta = self.meta.read();
+		if meta.best_hash != Default::default() {
+			let tree_route = ::client::blockchain::tree_route(
+				self,
+				BlockId::Hash(meta.best_hash),
+				BlockId::Hash(route_to),
+			)?;
+
+			// update block number to hash lookup entries.
+			for retracted in tree_route.retracted() {
+				if retracted.hash == meta.finalized_hash {
+					// TODO: can we recover here?
+					warn!("Safety failure: reverting finalized block {:?}",
+						  (&retracted.number, &retracted.hash));
+				}
+
+				utils::remove_number_to_key_mapping(
+					transaction,
+					columns::KEY_LOOKUP,
+					retracted.number
+				);
+			}
+
+			for enacted in tree_route.enacted() {
+				utils::insert_number_to_key_mapping(
+					transaction,
+					columns::KEY_LOOKUP,
+					enacted.number,
+					enacted.hash
+				);
+			}
+		}
+
+		transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
+		utils::insert_number_to_key_mapping(
+			transaction,
+			columns::KEY_LOOKUP,
+			best_to.0,
+			best_to.1,
+		);
+
+		Ok(())
+	}
+
 	// Note that a block is finalized. Only call with child of last finalized block.
 	fn note_finalized(
 		&self,
@@ -325,51 +380,10 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
 		}
 
 		// blocks are keyed by number + hash.
-		let lookup_key = utils::number_and_hash_to_lookup_key(number, hash);
+		let lookup_key = utils::number_and_hash_to_lookup_key(number, &hash);
 
 		if leaf_state.is_best() {
-			// handle reorg.
-			{
-				let meta = self.meta.read();
-				if meta.best_hash != Default::default() {
-					let tree_route = ::client::blockchain::tree_route(
-						self,
-						BlockId::Hash(meta.best_hash),
-						BlockId::Hash(parent_hash),
-					)?;
-
-					// update block number to hash lookup entries.
-					for retracted in tree_route.retracted() {
-						if retracted.hash == meta.finalized_hash {
-							warn!("Safety failure: reverting finalized block {:?}",
-								(&retracted.number, &retracted.hash));
-						}
-
-						utils::remove_number_to_key_mapping(
-							&mut transaction,
-							columns::KEY_LOOKUP,
-							retracted.number
-						);
-					}
-
-					for enacted in tree_route.enacted() {
-						utils::insert_number_to_key_mapping(
-							&mut transaction,
-							columns::KEY_LOOKUP,
-							enacted.number,
-							enacted.hash
-						);
-					}
-				}
-			}
-
-			transaction.put(columns::META, meta_keys::BEST_BLOCK, &lookup_key);
-			utils::insert_number_to_key_mapping(
-				&mut transaction,
-				columns::KEY_LOOKUP,
-				number,
-				hash,
-			);
+			self.set_head_with_transaction(&mut transaction, parent_hash, (number, hash))?;
 		}
 
 		utils::insert_hash_to_key_mapping(
@@ -426,6 +440,20 @@ impl<Block> LightBlockchainStorage<Block> for LightStorage<Block>
 		Ok(())
 	}
 
+	fn set_head(&self, id: BlockId<Block>) -> ClientResult<()> {
+		if let Some(header) = self.header(id)? {
+			let hash = header.hash();
+			let number = header.number();
+
+			let mut transaction = DBTransaction::new();
+			self.set_head_with_transaction(&mut transaction, hash.clone(), (number.clone(), hash.clone()))?;
+			self.db.write(transaction).map_err(db_err)?;
+			Ok(())
+		} else {
+			Err(ClientErrorKind::UnknownBlock(format!("Cannot set head {:?}", id)).into())
+		}
+	}
+
 	fn header_cht_root(&self, cht_size: u64, block: NumberFor<Block>) -> ClientResult<Block::Hash> {
 		self.read_cht_root(HEADER_CHT_PREFIX, cht_size, block)
 	}
diff --git a/substrate/core/client/src/backend.rs b/substrate/core/client/src/backend.rs
index 108b30df03b199a59c5fd411ebbfc2062a410932..386a65cfd0cab9d78ae71798799249f20abc756b 100644
--- a/substrate/core/client/src/backend.rs
+++ b/substrate/core/client/src/backend.rs
@@ -44,6 +44,14 @@ impl NewBlockState {
 			NewBlockState::Normal => false,
 		}
 	}
+
+	/// Whether this block is considered final.
+	pub fn is_final(self) -> bool {
+		match self {
+			NewBlockState::Final => true,
+			NewBlockState::Best | NewBlockState::Normal => false,
+		}
+	}
 }
 
 /// Block insertion operation. Keeps hold if the inserted block state and data.
@@ -81,6 +89,8 @@ pub trait BlockImportOperation<Block, H> where
 		where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>;
 	/// Mark a block as finalized.
 	fn mark_finalized(&mut self, id: BlockId<Block>, justification: Option<Justification>) -> error::Result<()>;
+	/// Mark a block as new head. If both block import and set head are specified, set head overrides block import's best block rule.
+	fn mark_head(&mut self, id: BlockId<Block>) -> error::Result<()>;
 }
 
 /// Provides access to an auxiliary database.
diff --git a/substrate/core/client/src/client.rs b/substrate/core/client/src/client.rs
index eec50c3a03c8915edd45f0459ceec54a5bc614ec..4eef88fad05c6729318402b07d9468f6b7049e36 100644
--- a/substrate/core/client/src/client.rs
+++ b/substrate/core/client/src/client.rs
@@ -650,6 +650,25 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
 		result
 	}
 
+	/// Set a block as best block.
+	pub fn set_head(
+		&self,
+		id: BlockId<Block>
+	) -> error::Result<()> {
+		self.lock_import_and_run(|operation| {
+			self.apply_head(operation, id)
+		})
+	}
+
+	/// Set a block as best block, and apply it to an operation.
+	pub fn apply_head(
+		&self,
+		operation: &mut ClientImportOperation<Block, Blake2Hasher, B>,
+		id: BlockId<Block>,
+	) -> error::Result<()> {
+		operation.op.mark_head(id)
+	}
+
 	/// Apply a checked and validated block to an operation. If a justification is provided
 	/// then `finalized` *must* be true.
 	pub fn apply_block(
diff --git a/substrate/core/client/src/in_mem.rs b/substrate/core/client/src/in_mem.rs
index 6f53ad7d2a348d085d5be7b625b974b949c22e80..c9080bb835b06f60a576b022ee7b71f7559441be 100644
--- a/substrate/core/client/src/in_mem.rs
+++ b/substrate/core/client/src/in_mem.rs
@@ -168,55 +168,24 @@ impl<Block: BlockT> Blockchain<Block> {
 		new_state: NewBlockState,
 	) -> crate::error::Result<()> {
 		let number = header.number().clone();
-		let best_tree_route = match new_state.is_best() {
-			false => None,
-			true => {
-				let best_hash = self.storage.read().best_hash;
-				if &best_hash == header.parent_hash() {
-					None
-				} else {
-					let route = crate::blockchain::tree_route(
-						self,
-						BlockId::Hash(best_hash),
-						BlockId::Hash(*header.parent_hash()),
-					)?;
-					Some(route)
-				}
-			}
-		};
-
-		let mut storage = self.storage.write();
-
-		storage.leaves.import(hash.clone(), number.clone(), header.parent_hash().clone());
 
 		if new_state.is_best() {
-			if let Some(tree_route) = best_tree_route {
-				// apply retraction and enaction when reorganizing up to parent hash
-				let enacted = tree_route.enacted();
-
-				for entry in enacted {
-					storage.hashes.insert(entry.number, entry.hash);
-				}
-
-				for entry in tree_route.retracted().iter().skip(enacted.len()) {
-					storage.hashes.remove(&entry.number);
-				}
-			}
-
-			storage.best_hash = hash.clone();
-			storage.best_number = number.clone();
-			storage.hashes.insert(number, hash.clone());
+			self.apply_head(&header)?;
 		}
 
-		storage.blocks.insert(hash.clone(), StoredBlock::new(header, body, justification));
+		{
+			let mut storage = self.storage.write();
+			storage.leaves.import(hash.clone(), number.clone(), header.parent_hash().clone());
+			storage.blocks.insert(hash.clone(), StoredBlock::new(header, body, justification));
 
-		if let NewBlockState::Final = new_state {
-			storage.finalized_hash = hash;
-			storage.finalized_number = number.clone();
-		}
+			if let NewBlockState::Final = new_state {
+				storage.finalized_hash = hash;
+				storage.finalized_number = number.clone();
+			}
 
-		if number == Zero::zero() {
-			storage.genesis_hash = hash;
+			if number == Zero::zero() {
+				storage.genesis_hash = hash;
+			}
 		}
 
 		Ok(())
@@ -247,6 +216,58 @@ impl<Block: BlockT> Blockchain<Block> {
 		self.storage.write().header_cht_roots.insert(block, cht_root);
 	}
 
+	/// Set an existing block as head.
+	pub fn set_head(&self, id: BlockId<Block>) -> error::Result<()> {
+		let header = match self.header(id)? {
+			Some(h) => h,
+			None => return Err(error::ErrorKind::UnknownBlock(format!("{}", id)).into()),
+		};
+
+		self.apply_head(&header)
+	}
+
+	fn apply_head(&self, header: &<Block as BlockT>::Header) -> error::Result<()> {
+		let hash = header.hash();
+		let number = header.number();
+
+		// Note: this may lock storage, so it must happen before obtaining storage
+		// write lock.
+		let best_tree_route = {
+			let best_hash = self.storage.read().best_hash;
+			if &best_hash == header.parent_hash() {
+				None
+			} else {
+				let route = crate::blockchain::tree_route(
+					self,
+					BlockId::Hash(best_hash),
+					BlockId::Hash(*header.parent_hash()),
+				)?;
+				Some(route)
+			}
+		};
+
+		let mut storage = self.storage.write();
+
+		if let Some(tree_route) = best_tree_route {
+			// apply retraction and enaction when reorganizing up to parent hash
+			let enacted = tree_route.enacted();
+
+			for entry in enacted {
+				storage.hashes.insert(entry.number, entry.hash);
+			}
+
+			for entry in tree_route.retracted().iter().skip(enacted.len()) {
+				storage.hashes.remove(&entry.number);
+			}
+		}
+
+		storage.best_hash = hash.clone();
+		storage.best_number = number.clone();
+		storage.hashes.insert(number.clone(), hash.clone());
+
+		Ok(())
+	}
+
 	fn finalize_header(&self, id: BlockId<Block>, justification: Option<Justification>) -> error::Result<()> {
 		let hash = match self.header(id)? {
 			Some(h) => h.hash(),
@@ -388,6 +409,10 @@ impl<Block: BlockT> light::blockchain::Storage<Block> for Blockchain<Block>
 		Ok(())
 	}
 
+	fn set_head(&self, id: BlockId<Block>) -> error::Result<()> {
+		Blockchain::set_head(self, id)
+	}
+
 	fn last_finalized(&self) -> error::Result<Block::Hash> {
 		Ok(self.storage.read().finalized_hash.clone())
 	}
@@ -420,6 +445,7 @@ pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
 	changes_trie_update: Option<MemoryDB<H>>,
 	aux: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	finalized_blocks: Vec<(BlockId<Block>, Option<Justification>)>,
+	set_head: Option<BlockId<Block>>,
 }
 
 impl<Block, H> backend::BlockImportOperation<Block, H> for BlockImportOperation<Block, H>
@@ -500,6 +526,12 @@ where
 		self.finalized_blocks.push((block, justification));
 		Ok(())
 	}
+
+	fn mark_head(&mut self, block: BlockId<Block>) -> error::Result<()> {
+		assert!(self.pending_block.is_none(), "Only one set block per operation is allowed");
+		self.set_head = Some(block);
+		Ok(())
+	}
 }
 
 /// In-memory backend. Keeps all states and blocks in memory. Useful for testing.
@@ -572,6 +604,7 @@ where
 			changes_trie_update: None,
 			aux: Default::default(),
 			finalized_blocks: Default::default(),
+			set_head: None,
 		})
 	}
 
@@ -615,6 +648,10 @@ where
 			self.blockchain.write_aux(operation.aux);
 		}
 
+		if let Some(set_head) = operation.set_head {
+			self.blockchain.set_head(set_head)?;
+		}
+
 		Ok(())
 	}
 
diff --git a/substrate/core/client/src/light/backend.rs b/substrate/core/client/src/light/backend.rs
index 8c08123fb677387b31be04bc9532d2cb397c83ed..172faecc7ca61c187595ad8187b26ab2966bcc01 100644
--- a/substrate/core/client/src/light/backend.rs
+++ b/substrate/core/client/src/light/backend.rs
@@ -50,6 +50,7 @@ pub struct ImportOperation<Block: BlockT, S, F, H> {
 	leaf_state: NewBlockState,
 	aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	finalized_blocks: Vec<BlockId<Block>>,
+	set_head: Option<BlockId<Block>>,
 	storage_update: Option<InMemoryState<H>>,
 	_phantom: ::std::marker::PhantomData<(S, F)>,
 }
@@ -120,6 +121,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where
 			leaf_state: NewBlockState::Normal,
 			aux_ops: Vec::new(),
 			finalized_blocks: Vec::new(),
+			set_head: None,
 			storage_update: None,
 			_phantom: Default::default(),
 		})
@@ -165,6 +167,10 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F, H> where
 			}
 		}
 
+		if let Some(set_head) = operation.set_head {
+			self.blockchain.storage().set_head(set_head)?;
+		}
+
 		Ok(())
 	}
 
@@ -294,6 +300,11 @@ where
 		self.finalized_blocks.push(block);
 		Ok(())
 	}
+
+	fn mark_head(&mut self, block: BlockId<Block>) -> ClientResult<()> {
+		self.set_head = Some(block);
+		Ok(())
+	}
 }
 
 impl<Block, S, F, H> StateBackend<H> for OnDemandState<Block, S, F>
diff --git a/substrate/core/client/src/light/blockchain.rs b/substrate/core/client/src/light/blockchain.rs
index 89fe5f8a3a4d7261d97f01486706c9f6781d19e4..36a236f32e2df06e83178e8140447d92c2832894 100644
--- a/substrate/core/client/src/light/blockchain.rs
+++ b/substrate/core/client/src/light/blockchain.rs
@@ -45,6 +45,9 @@ pub trait Storage<Block: BlockT>: AuxStore + BlockchainHeaderBackend<Block> {
 		aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	) -> ClientResult<()>;
 
+	/// Set an existing block as new best block.
+	fn set_head(&self, block: BlockId<Block>) -> ClientResult<()>;
+
 	/// Mark historic header as finalized.
 	fn finalize_header(&self, block: BlockId<Block>) -> ClientResult<()>;
 
@@ -246,6 +249,10 @@ pub mod tests {
 			Ok(())
 		}
 
+		fn set_head(&self, _block: BlockId<Block>) -> ClientResult<()> {
+			Err(ClientErrorKind::Backend("Test error".into()).into())
+		}
+
 		fn finalize_header(&self, _block: BlockId<Block>) -> ClientResult<()> {
 			Err(ClientErrorKind::Backend("Test error".into()).into())
 		}