From efece9e0c7787a30192d1f21b0c6a71be8c24057 Mon Sep 17 00:00:00 2001 From: Antioch Peverell Date: Mon, 17 Aug 2020 18:21:54 +0100 Subject: [PATCH] use sync pmmr for building locator (#3397) --- chain/src/chain.rs | 10 ++ servers/src/grin/sync/header_sync.rs | 165 +-------------------------- 2 files changed, 12 insertions(+), 163 deletions(-) diff --git a/chain/src/chain.rs b/chain/src/chain.rs index 1e85052d7e..c6693adf69 100644 --- a/chain/src/chain.rs +++ b/chain/src/chain.rs @@ -1511,6 +1511,16 @@ impl Chain { Ok(Tip::from_header(&header)) } + /// Gets multiple headers at the provided heights. + /// Note: Uses the sync pmmr, not the header pmmr. + pub fn get_locator_hashes(&self, heights: &[u64]) -> Result, Error> { + let pmmr = self.sync_pmmr.read(); + heights + .iter() + .map(|h| pmmr.get_header_hash_by_height(*h)) + .collect() + } + /// Builds an iterator on blocks starting from the current chain head and /// running backward. Specialized to return information pertaining to block /// difficulty calculation (timestamp and previous difficulties). diff --git a/servers/src/grin/sync/header_sync.rs b/servers/src/grin/sync/header_sync.rs index 592a3b3ff6..6fec87e134 100644 --- a/servers/src/grin/sync/header_sync.rs +++ b/servers/src/grin/sync/header_sync.rs @@ -25,10 +25,7 @@ pub struct HeaderSync { sync_state: Arc, peers: Arc, chain: Arc, - - history_locator: Vec<(u64, Hash)>, prev_header_sync: (DateTime, u64, u64), - syncing_peer: Option>, stalling_ts: Option>, } @@ -43,7 +40,6 @@ impl HeaderSync { sync_state, peers, chain, - history_locator: vec![], prev_header_sync: (Utc::now(), 0, 0), syncing_peer: None, stalling_ts: None, @@ -82,8 +78,6 @@ impl HeaderSync { // our last known "good" header_head. // self.chain.rebuild_sync_mmr(&header_head)?; - - self.history_locator.retain(|&x| x.0 == 0); true } _ => false, @@ -207,67 +201,11 @@ impl HeaderSync { fn get_locator(&mut self) -> Result, Error> { let tip = self.chain.get_sync_head()?; let heights = get_locator_heights(tip.height); - - // for security, clear history_locator[] in any case of header chain rollback, - // the easiest way is to check whether the sync head and the header head are identical. - if !self.history_locator.is_empty() && tip.hash() != self.chain.header_head()?.hash() { - self.history_locator.retain(|&x| x.0 == 0); - } - - // for each height we need, we either check if something is close enough from - // last locator, or go to the db - let mut locator: Vec<(u64, Hash)> = vec![(tip.height, tip.last_block_h)]; - for h in heights { - if let Some(l) = close_enough(&self.history_locator, h) { - locator.push(l); - } else { - // start at last known hash and go backward - let last_loc = locator.last().unwrap(); - let mut header_cursor = self.chain.get_block_header(&last_loc.1); - while let Ok(header) = header_cursor { - if header.height == h { - if header.height != last_loc.0 { - locator.push((header.height, header.hash())); - } - break; - } - header_cursor = self.chain.get_previous_header(&header); - } - } - } - locator.dedup_by(|a, b| a.0 == b.0); - debug!("sync: locator : {:?}", locator.clone()); - self.history_locator = locator.clone(); - - Ok(locator.iter().map(|l| l.1).collect()) + let locator = self.chain.get_locator_hashes(&heights)?; + Ok(locator) } } -// Whether we have a value close enough to the provided height in the locator -fn close_enough(locator: &[(u64, Hash)], height: u64) -> Option<(u64, Hash)> { - if locator.is_empty() { - return None; - } - // bounds, lower that last is last - if locator.last().unwrap().0 >= height { - return locator.last().copied(); - } - // higher than first is first if within an acceptable gap - if locator[0].0 < height && height.saturating_sub(127) < locator[0].0 { - return Some(locator[0]); - } - for hh in locator.windows(2) { - if height <= hh[0].0 && height > hh[1].0 { - if hh[0].0 - height < height - hh[1].0 { - return Some(hh[0]); - } else { - return Some(hh[1]); - } - } - } - None -} - // current height back to 0 decreasing in powers of 2 fn get_locator_heights(height: u64) -> Vec { let mut current = height; @@ -287,7 +225,6 @@ fn get_locator_heights(height: u64) -> Vec { #[cfg(test)] mod test { use super::*; - use crate::core::core::hash; #[test] fn test_get_locator_heights() { @@ -308,102 +245,4 @@ mod test { vec![10000, 9998, 9994, 9986, 9970, 9938, 9874, 9746, 9490, 8978, 7954, 5906, 1810, 0,] ); } - - #[test] - fn test_close_enough() { - let zh = hash::ZERO_HASH; - - // empty check - assert_eq!(close_enough(&vec![], 0), None); - - // just 1 locator in history - let heights: Vec = vec![64, 62, 58, 50, 34, 2, 0]; - let history_locator: Vec<(u64, Hash)> = vec![(0, zh.clone())]; - let mut locator: Vec<(u64, Hash)> = vec![]; - for h in heights { - if let Some(l) = close_enough(&history_locator, h) { - locator.push(l); - } - } - assert_eq!(locator, vec![(0, zh.clone())]); - - // simple dummy example - let locator = vec![ - (1000, zh.clone()), - (500, zh.clone()), - (250, zh.clone()), - (125, zh.clone()), - ]; - assert_eq!(close_enough(&locator, 2000), None); - assert_eq!(close_enough(&locator, 1050), Some((1000, zh))); - assert_eq!(close_enough(&locator, 900), Some((1000, zh))); - assert_eq!(close_enough(&locator, 270), Some((250, zh))); - assert_eq!(close_enough(&locator, 20), Some((125, zh))); - assert_eq!(close_enough(&locator, 125), Some((125, zh))); - assert_eq!(close_enough(&locator, 500), Some((500, zh))); - - // more realistic test with 11 history - let heights: Vec = vec![ - 2554, 2552, 2548, 2540, 2524, 2492, 2428, 2300, 2044, 1532, 508, 0, - ]; - let history_locator: Vec<(u64, Hash)> = vec![ - (2043, zh.clone()), - (2041, zh.clone()), - (2037, zh.clone()), - (2029, zh.clone()), - (2013, zh.clone()), - (1981, zh.clone()), - (1917, zh.clone()), - (1789, zh.clone()), - (1532, zh.clone()), - (1021, zh.clone()), - (0, zh.clone()), - ]; - let mut locator: Vec<(u64, Hash)> = vec![]; - for h in heights { - if let Some(l) = close_enough(&history_locator, h) { - locator.push(l); - } - } - locator.dedup_by(|a, b| a.0 == b.0); - assert_eq!( - locator, - vec![(2043, zh.clone()), (1532, zh.clone()), (0, zh.clone()),] - ); - - // more realistic test with 12 history - let heights: Vec = vec![ - 4598, 4596, 4592, 4584, 4568, 4536, 4472, 4344, 4088, 3576, 2552, 504, 0, - ]; - let history_locator: Vec<(u64, Hash)> = vec![ - (4087, zh.clone()), - (4085, zh.clone()), - (4081, zh.clone()), - (4073, zh.clone()), - (4057, zh.clone()), - (4025, zh.clone()), - (3961, zh.clone()), - (3833, zh.clone()), - (3576, zh.clone()), - (3065, zh.clone()), - (1532, zh.clone()), - (0, zh.clone()), - ]; - let mut locator: Vec<(u64, Hash)> = vec![]; - for h in heights { - if let Some(l) = close_enough(&history_locator, h) { - locator.push(l); - } - } - locator.dedup_by(|a, b| a.0 == b.0); - assert_eq!( - locator, - vec![ - (4087, zh.clone()), - (3576, zh.clone()), - (3065, zh.clone()), - (0, zh.clone()), - ] - ); - } }