mirror of
https://github.com/mimblewimble/grin.git
synced 2025-02-01 08:51:08 +03:00
use sync pmmr for building locator (#3397)
This commit is contained in:
parent
599bf22cfc
commit
efece9e0c7
2 changed files with 12 additions and 163 deletions
|
@ -1511,6 +1511,16 @@ impl Chain {
|
||||||
Ok(Tip::from_header(&header))
|
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
|
/// Builds an iterator on blocks starting from the current chain head and
|
||||||
/// running backward. Specialized to return information pertaining to block
|
/// running backward. Specialized to return information pertaining to block
|
||||||
/// difficulty calculation (timestamp and previous difficulties).
|
/// difficulty calculation (timestamp and previous difficulties).
|
||||||
|
|
|
@ -25,10 +25,7 @@ pub struct HeaderSync {
|
||||||
sync_state: Arc<SyncState>,
|
sync_state: Arc<SyncState>,
|
||||||
peers: Arc<p2p::Peers>,
|
peers: Arc<p2p::Peers>,
|
||||||
chain: Arc<chain::Chain>,
|
chain: Arc<chain::Chain>,
|
||||||
|
|
||||||
history_locator: Vec<(u64, Hash)>,
|
|
||||||
prev_header_sync: (DateTime<Utc>, u64, u64),
|
prev_header_sync: (DateTime<Utc>, u64, u64),
|
||||||
|
|
||||||
syncing_peer: Option<Arc<Peer>>,
|
syncing_peer: Option<Arc<Peer>>,
|
||||||
stalling_ts: Option<DateTime<Utc>>,
|
stalling_ts: Option<DateTime<Utc>>,
|
||||||
}
|
}
|
||||||
|
@ -43,7 +40,6 @@ impl HeaderSync {
|
||||||
sync_state,
|
sync_state,
|
||||||
peers,
|
peers,
|
||||||
chain,
|
chain,
|
||||||
history_locator: vec![],
|
|
||||||
prev_header_sync: (Utc::now(), 0, 0),
|
prev_header_sync: (Utc::now(), 0, 0),
|
||||||
syncing_peer: None,
|
syncing_peer: None,
|
||||||
stalling_ts: None,
|
stalling_ts: None,
|
||||||
|
@ -82,8 +78,6 @@ impl HeaderSync {
|
||||||
// our last known "good" header_head.
|
// our last known "good" header_head.
|
||||||
//
|
//
|
||||||
self.chain.rebuild_sync_mmr(&header_head)?;
|
self.chain.rebuild_sync_mmr(&header_head)?;
|
||||||
|
|
||||||
self.history_locator.retain(|&x| x.0 == 0);
|
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
|
@ -207,67 +201,11 @@ impl HeaderSync {
|
||||||
fn get_locator(&mut self) -> Result<Vec<Hash>, Error> {
|
fn get_locator(&mut self) -> Result<Vec<Hash>, Error> {
|
||||||
let tip = self.chain.get_sync_head()?;
|
let tip = self.chain.get_sync_head()?;
|
||||||
let heights = get_locator_heights(tip.height);
|
let heights = get_locator_heights(tip.height);
|
||||||
|
let locator = self.chain.get_locator_hashes(&heights)?;
|
||||||
// for security, clear history_locator[] in any case of header chain rollback,
|
Ok(locator)
|
||||||
// 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())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
// current height back to 0 decreasing in powers of 2
|
||||||
fn get_locator_heights(height: u64) -> Vec<u64> {
|
fn get_locator_heights(height: u64) -> Vec<u64> {
|
||||||
let mut current = height;
|
let mut current = height;
|
||||||
|
@ -287,7 +225,6 @@ fn get_locator_heights(height: u64) -> Vec<u64> {
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::core::core::hash;
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_get_locator_heights() {
|
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,]
|
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()),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue