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(