diff --git a/substrate/core/client/src/backend.rs b/substrate/core/client/src/backend.rs
index 615704361c6170b40540e914f7db1308318082dd..b994b1307dc2bcede3c24aa56fdec98f1a6f00d8 100644
--- a/substrate/core/client/src/backend.rs
+++ b/substrate/core/client/src/backend.rs
@@ -76,6 +76,9 @@ where
 	fn reset_storage<I: Iterator<Item=(Vec<u8>, Vec<u8>)>>(&mut self, iter: I) -> error::Result<()>;
 	/// Inject changes trie data into the database.
 	fn update_changes_trie(&mut self, update: MemoryDB<H>) -> error::Result<()>;
+	/// Update auxiliary keys. Values are `None` if should be deleted.
+	fn set_aux<I>(&mut self, ops: I) -> error::Result<()>
+		where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>;
 }
 
 /// Client backend. Manages the data layer.
diff --git a/substrate/core/client/src/in_mem.rs b/substrate/core/client/src/in_mem.rs
index 5548528cc7697e32bcf35a8855267e0c5d2e6e5f..88f94dfbede02f1febeb2b92180ad7d992ade0b4 100644
--- a/substrate/core/client/src/in_mem.rs
+++ b/substrate/core/client/src/in_mem.rs
@@ -96,6 +96,7 @@ struct BlockchainStorage<Block: BlockT> {
 	genesis_hash: Block::Hash,
 	cht_roots: HashMap<NumberFor<Block>, Block::Hash>,
 	leaves: LeafSet<Block::Hash, NumberFor<Block>>,
+	aux: HashMap<Vec<u8>, Vec<u8>>,
 }
 
 /// In-memory blockchain. Supports concurrent reads.
@@ -144,6 +145,7 @@ impl<Block: BlockT> Blockchain<Block> {
 				genesis_hash: Default::default(),
 				cht_roots: HashMap::new(),
 				leaves: LeafSet::new(),
+				aux: HashMap::new(),
 			}));
 		Blockchain {
 			storage: storage.clone(),
@@ -247,6 +249,16 @@ impl<Block: BlockT> Blockchain<Block> {
 		self.storage.write().finalized_hash = hash;
 		Ok(())
 	}
+
+	fn write_aux(&self, ops: Vec<(Vec<u8>, Option<Vec<u8>>)>) {
+		let mut storage = self.storage.write();
+		for (k, v) in ops {
+			match v {
+				Some(v) => storage.aux.insert(k, v),
+				None => storage.aux.remove(&k),
+			};
+		}
+	}
 }
 
 impl<Block: BlockT> HeaderBackend<Block> for Blockchain<Block> {
@@ -320,6 +332,7 @@ impl<Block: BlockT> light::blockchain::Storage<Block> for Blockchain<Block>
 		header: Block::Header,
 		authorities: Option<Vec<AuthorityId>>,
 		state: NewBlockState,
+		aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	) -> error::Result<()> {
 		let hash = header.hash();
 		let parent_hash = *header.parent_hash();
@@ -328,6 +341,7 @@ impl<Block: BlockT> light::blockchain::Storage<Block> for Blockchain<Block>
 			self.cache.insert(parent_hash, authorities);
 		}
 
+		self.write_aux(aux_ops);
 		Ok(())
 	}
 
@@ -356,6 +370,7 @@ pub struct BlockImportOperation<Block: BlockT, H: Hasher> {
 	old_state: InMemory<H>,
 	new_state: Option<InMemory<H>>,
 	changes_trie_update: Option<MemoryDB<H>>,
+	aux: Option<Vec<(Vec<u8>, Option<Vec<u8>>)>>,
 }
 
 impl<Block, H> backend::BlockImportOperation<Block, H> for BlockImportOperation<Block, H>
@@ -404,6 +419,13 @@ where
 		self.new_state = Some(InMemory::from(iter.collect::<HashMap<_, _>>()));
 		Ok(())
 	}
+
+	fn set_aux<I>(&mut self, ops: I) -> error::Result<()>
+		where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
+	{
+		self.aux = Some(ops.into_iter().collect());
+		Ok(())
+	}
 }
 
 /// In-memory backend. Keeps all states and blocks in memory. Useful for testing.
@@ -417,7 +439,6 @@ where
 	states: RwLock<HashMap<Block::Hash, InMemory<H>>>,
 	changes_trie_storage: InMemoryChangesTrieStorage<H>,
 	blockchain: Blockchain<Block>,
-	aux: RwLock<HashMap<Vec<u8>, Vec<u8>>>,
 }
 
 impl<Block, H> Backend<Block, H>
@@ -433,7 +454,6 @@ where
 			states: RwLock::new(HashMap::new()),
 			changes_trie_storage: InMemoryChangesTrieStorage::new(),
 			blockchain: Blockchain::new(),
-			aux: RwLock::new(HashMap::new()),
 		}
 	}
 }
@@ -461,6 +481,7 @@ where
 			old_state: state,
 			new_state: None,
 			changes_trie_update: None,
+			aux: None,
 		})
 	}
 
@@ -488,6 +509,10 @@ where
 				self.blockchain.cache.insert(parent_hash, operation.pending_authorities);
 			}
 		}
+
+		if let Some(ops) = operation.aux {
+			self.blockchain.write_aux(ops);
+		}
 		Ok(())
 	}
 
@@ -515,18 +540,18 @@ where
 	}
 
 	fn insert_aux<'a, 'b: 'a, 'c: 'a, I: IntoIterator<Item=&'a (&'c [u8], &'c [u8])>, D: IntoIterator<Item=&'a &'b [u8]>>(&self, insert: I, delete: D) -> error::Result<()> {
-		let mut aux = self.aux.write();
+		let mut storage = self.blockchain.storage.write();
 		for (k, v) in insert {
-			aux.insert(k.to_vec(), v.to_vec());
+			storage.aux.insert(k.to_vec(), v.to_vec());
 		}
 		for k in delete {
-			aux.remove(*k);
+			storage.aux.remove(*k);
 		}
 		Ok(())
 	}
 
 	fn get_aux(&self, key: &[u8]) -> error::Result<Option<Vec<u8>>> {
-		Ok(self.aux.read().get(key).cloned())
+		Ok(self.blockchain.storage.read().aux.get(key).cloned())
 	}
 }
 
diff --git a/substrate/core/client/src/light/backend.rs b/substrate/core/client/src/light/backend.rs
index e83640aa6c1985653ab04fc7929878b9e0327ef6..5a1cee15c6d32a510611d2bda0521204ccc93724 100644
--- a/substrate/core/client/src/light/backend.rs
+++ b/substrate/core/client/src/light/backend.rs
@@ -45,6 +45,7 @@ pub struct ImportOperation<Block: BlockT, S, F> {
 	header: Option<Block::Header>,
 	authorities: Option<Vec<AuthorityId>>,
 	leaf_state: NewBlockState,
+	aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	_phantom: ::std::marker::PhantomData<(S, F)>,
 }
 
@@ -86,6 +87,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F> where
 			header: None,
 			authorities: None,
 			leaf_state: NewBlockState::Normal,
+			aux_ops: Vec::new(),
 			_phantom: Default::default(),
 		})
 	}
@@ -96,6 +98,7 @@ impl<S, F, Block, H> ClientBackend<Block, H> for Backend<S, F> where
 			header,
 			operation.authorities,
 			operation.leaf_state,
+			operation.aux_ops,
 		)
 	}
 
@@ -193,6 +196,13 @@ where
 		// we're not storing anything locally => ignore changes
 		Ok(())
 	}
+
+	fn set_aux<I>(&mut self, ops: I) -> ClientResult<()>
+		where I: IntoIterator<Item=(Vec<u8>, Option<Vec<u8>>)>
+	{
+		self.aux_ops = ops.into_iter().collect();
+		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 97c20ecc907468a06e8497d17e14ffdbac98012b..2dd7097751a581a1521b6338898c70996de23cf6 100644
--- a/substrate/core/client/src/light/blockchain.rs
+++ b/substrate/core/client/src/light/blockchain.rs
@@ -35,11 +35,15 @@ use light::fetcher::{Fetcher, RemoteHeaderRequest};
 /// Light client blockchain storage.
 pub trait Storage<Block: BlockT>: BlockchainHeaderBackend<Block> {
 	/// Store new header. Should refuse to revert any finalized blocks.
+	///
+	/// Takes new authorities, the leaf state of the new block, and
+	/// any auxiliary storage updates to place in the same operation.
 	fn import_header(
 		&self,
 		header: Block::Header,
 		authorities: Option<Vec<AuthorityId>>,
 		state: NewBlockState,
+		aux_ops: Vec<(Vec<u8>, Option<Vec<u8>>)>,
 	) -> ClientResult<()>;
 
 	/// Mark historic header as finalized.