use sync pmmr for building locator (#3397)

This commit is contained in:
Antioch Peverell 2020-08-17 18:21:54 +01:00 committed by GitHub
parent 599bf22cfc
commit efece9e0c7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 12 additions and 163 deletions

View file

@ -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).

View file

@ -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>>,
}
@ -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,65 +201,9 @@ 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);
let locator = self.chain.get_locator_hashes(&heights)?;
Ok(locator)
}
// 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())
}
}
// 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
@ -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() {
@ -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()),
]
);
}
}