diff --git a/ethash/Cargo.toml b/ethash/Cargo.toml index 4bba71a14..da08b9f92 100644 --- a/ethash/Cargo.toml +++ b/ethash/Cargo.toml @@ -7,5 +7,4 @@ authors = ["arkpar , + recent: Option>, + prev_epoch: Option, + prev: Option>, +} + /// Lighy/Full cache manager pub struct EthashManager { - lights: Mutex>> + cache: Mutex, } impl EthashManager { /// Create a new new instance of ethash manager pub fn new() -> EthashManager { EthashManager { - lights: Mutex::new(LruCache::new(2)) + cache: Mutex::new(LightCache { + recent_epoch: None, + recent: None, + prev_epoch: None, + prev: None, + }), } } @@ -50,8 +61,24 @@ impl EthashManager { pub fn compute_light(&self, block_number: u64, header_hash: &H256, nonce: u64) -> ProofOfWork { let epoch = block_number / ETHASH_EPOCH_LENGTH; let light = { - let mut lights = self.lights.lock().unwrap(); - match lights.get_mut(&epoch).map(|l| l.clone()) { + let mut lights = self.cache.lock().unwrap(); + let light = match lights.recent_epoch.clone() { + Some(ref e) if *e == epoch => lights.recent.clone(), + _ => match lights.prev_epoch.clone() { + Some(e) if e == epoch => { + // swap + let t = lights.prev_epoch; + lights.prev_epoch = lights.recent_epoch; + lights.recent_epoch = t; + let t = lights.prev.clone(); + lights.prev = lights.recent.clone(); + lights.recent = t; + lights.recent.clone() + } + _ => None, + } + }; + match light { None => { let light = match Light::from_file(block_number) { Ok(light) => Arc::new(light), @@ -64,7 +91,8 @@ impl EthashManager { Arc::new(light) } }; - lights.insert(epoch, light.clone()); + lights.prev_epoch = mem::replace(&mut lights.recent_epoch, Some(epoch)); + lights.prev = mem::replace(&mut lights.recent, Some(light.clone())); light } Some(light) => light @@ -73,3 +101,19 @@ impl EthashManager { light.compute(header_hash, nonce) } } + +#[test] +fn test_lru() { + let ethash = EthashManager::new(); + let hash = [0u8; 32]; + ethash.compute_light(1, &hash, 1); + ethash.compute_light(50000, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 1); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0); + ethash.compute_light(1, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 0); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 1); + ethash.compute_light(70000, &hash, 1); + assert_eq!(ethash.cache.lock().unwrap().recent_epoch.unwrap(), 2); + assert_eq!(ethash.cache.lock().unwrap().prev_epoch.unwrap(), 0); +}