diff --git a/chain/src/chain.rs b/chain/src/chain.rs
index e3850b469..bef29cb90 100644
--- a/chain/src/chain.rs
+++ b/chain/src/chain.rs
@@ -15,13 +15,14 @@
 //! Facade and handler for the rest of the blockchain implementation
 //! and mostly the chain pipeline.
 
-use std::collections::{HashMap, VecDeque};
+use std::collections::HashMap;
 use std::fs::File;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::sync::{Arc, Mutex, RwLock};
 use std::time::{Duration, Instant};
 
 use lmdb;
+use lru_cache::LruCache;
 
 use core::core::hash::{Hash, Hashed};
 use core::core::merkle_proof::MerkleProof;
@@ -150,7 +151,7 @@ pub struct Chain {
 	orphans: Arc<OrphanBlockPool>,
 	txhashset: Arc<RwLock<txhashset::TxHashSet>>,
 	// Recently processed blocks to avoid double-processing
-	block_hashes_cache: Arc<RwLock<VecDeque<Hash>>>,
+	block_hashes_cache: Arc<RwLock<LruCache<Hash, bool>>>,
 	verifier_cache: Arc<RwLock<VerifierCache>>,
 	// POW verification function
 	pow_verifier: fn(&BlockHeader, u8) -> Result<(), pow::Error>,
@@ -202,7 +203,7 @@ impl Chain {
 			txhashset: Arc::new(RwLock::new(txhashset)),
 			pow_verifier,
 			verifier_cache,
-			block_hashes_cache: Arc::new(RwLock::new(VecDeque::with_capacity(HASHES_CACHE_SIZE))),
+			block_hashes_cache: Arc::new(RwLock::new(LruCache::new(HASHES_CACHE_SIZE))),
 			archive_mode,
 		})
 	}
@@ -244,8 +245,7 @@ impl Chain {
 			// only add to hash cache below if block is definitively accepted
 			// or rejected
 			let mut cache = self.block_hashes_cache.write().unwrap();
-			cache.push_front(bhash);
-			cache.truncate(HASHES_CACHE_SIZE);
+			cache.insert(bhash, true);
 		};
 
 		match res {
diff --git a/chain/src/pipe.rs b/chain/src/pipe.rs
index dd5c14b0d..a68920ff8 100644
--- a/chain/src/pipe.rs
+++ b/chain/src/pipe.rs
@@ -14,12 +14,13 @@
 
 //! Implementation of the chain block acceptance (or refusal) pipeline.
 
-use std::collections::VecDeque;
 use std::sync::{Arc, RwLock};
 
 use chrono::prelude::Utc;
 use chrono::Duration;
 
+use lru_cache::LruCache;
+
 use chain::OrphanBlockPool;
 use core::consensus;
 use core::core::hash::{Hash, Hashed};
@@ -53,7 +54,7 @@ pub struct BlockContext {
 	/// MMR sum tree states
 	pub txhashset: Arc<RwLock<txhashset::TxHashSet>>,
 	/// Recently processed blocks to avoid double-processing
-	pub block_hashes_cache: Arc<RwLock<VecDeque<Hash>>>,
+	pub block_hashes_cache: Arc<RwLock<LruCache<Hash, bool>>>,
 	/// Recent orphan blocks to avoid double-processing
 	pub orphans: Arc<OrphanBlockPool>,
 }
@@ -290,8 +291,8 @@ fn check_known_head(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(),
 /// Keeps duplicates from the network in check.
 /// Checks against the cache of recently processed block hashes.
 fn check_known_cache(header: &BlockHeader, ctx: &mut BlockContext) -> Result<(), Error> {
-	let cache = ctx.block_hashes_cache.read().unwrap();
-	if cache.contains(&header.hash()) {
+	let mut cache = ctx.block_hashes_cache.write().unwrap();
+	if cache.contains_key(&header.hash()) {
 		return Err(ErrorKind::Unfit("already known in cache".to_string()).into());
 	}
 	Ok(())
@@ -527,8 +528,7 @@ fn validate_block(
 			&prev.total_kernel_offset,
 			&prev.total_kernel_sum,
 			verifier_cache,
-		)
-		.map_err(|e| ErrorKind::InvalidBlockProof(e))?;
+		).map_err(|e| ErrorKind::InvalidBlockProof(e))?;
 	Ok(())
 }
 
@@ -568,7 +568,8 @@ fn verify_block_sums(b: &Block, ext: &mut txhashset::Extension) -> Result<(), Er
 	let offset = b.header.total_kernel_offset();
 
 	// Verify the kernel sums for the block_sums with the new block applied.
-	let (utxo_sum, kernel_sum) = (block_sums, b as &Committed).verify_kernel_sums(overage, offset)?;
+	let (utxo_sum, kernel_sum) =
+		(block_sums, b as &Committed).verify_kernel_sums(overage, offset)?;
 
 	// Save the new block_sums for the new block to the db via the batch.
 	ext.batch.save_block_sums(