Skip to content

Commit

Permalink
use sync pmmr for building locator (#3397)
Browse files Browse the repository at this point in the history
  • Loading branch information
antiochp committed Aug 17, 2020
1 parent 599bf22 commit efece9e
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 163 deletions.
10 changes: 10 additions & 0 deletions chain/src/chain.rs
Expand Up @@ -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<Vec<Hash>, 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).
Expand Down
165 changes: 2 additions & 163 deletions servers/src/grin/sync/header_sync.rs
Expand Up @@ -25,10 +25,7 @@ pub struct HeaderSync {
sync_state: Arc<SyncState>,
peers: Arc<p2p::Peers>,
chain: Arc<chain::Chain>,

history_locator: Vec<(u64, Hash)>,
prev_header_sync: (DateTime<Utc>, u64, u64),

syncing_peer: Option<Arc<Peer>>,
stalling_ts: Option<DateTime<Utc>>,
}
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -207,67 +201,11 @@ impl HeaderSync {
fn get_locator(&mut self) -> Result<Vec<Hash>, 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<u64> {
let mut current = height;
Expand All @@ -287,7 +225,6 @@ fn get_locator_heights(height: u64) -> Vec<u64> {
#[cfg(test)]
mod test {
use super::*;
use crate::core::core::hash;

#[test]
fn test_get_locator_heights() {
Expand All @@ -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<u64> = 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<u64> = 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<u64> = 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()),
]
);
}
}

0 comments on commit efece9e

Please sign in to comment.