Optimize tree route to sync faster (#3665)

* Introduce HeaderMetadata and use it for tree_route. Add lowest_common_ancestor.
* Add tests.
This commit is contained in:
Marcio Diaz
2019-10-02 20:30:43 +02:00
committed by GitHub
parent 8646cd158e
commit f6bd58ac1f
22 changed files with 677 additions and 280 deletions
+31 -22
View File
@@ -51,6 +51,7 @@ use consensus::{
ImportResult, BlockOrigin, ForkChoiceStrategy,
SelectChain, self,
};
use header_metadata::{HeaderMetadata, CachedHeaderMetadata};
use crate::{
runtime_api::{
@@ -966,10 +967,10 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
};
let retracted = if is_new_best {
let route_from_best = crate::blockchain::tree_route(
|id| self.header(&id)?.ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))),
BlockId::Hash(info.best_hash),
BlockId::Hash(parent_hash),
let route_from_best = header_metadata::tree_route(
self.backend.blockchain(),
info.best_hash,
parent_hash,
)?;
route_from_best.retracted().iter().rev().map(|e| e.hash.clone()).collect()
} else {
@@ -1100,11 +1101,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
return Ok(());
}
let route_from_finalized = crate::blockchain::tree_route(
|id| self.header(&id)?.ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))),
BlockId::Hash(last_finalized),
BlockId::Hash(block),
)?;
let route_from_finalized = header_metadata::tree_route(self.backend.blockchain(), last_finalized, block)?;
if let Some(retracted) = route_from_finalized.retracted().get(0) {
warn!("Safety violation: attempted to revert finalized block {:?} which is not in the \
@@ -1113,11 +1110,7 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
return Err(error::Error::NotInFinalizedChain);
}
let route_from_best = crate::blockchain::tree_route(
|id| self.header(&id)?.ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))),
BlockId::Hash(best_block),
BlockId::Hash(block),
)?;
let route_from_best = header_metadata::tree_route(self.backend.blockchain(), best_block, block)?;
// if the block is not a direct ancestor of the current best chain,
// then some other block is the common ancestor.
@@ -1321,6 +1314,26 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
}
}
impl<B, E, Block, RA> HeaderMetadata<Block> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>,
Block: BlockT<Hash=H256>,
{
type Error = error::Error;
fn header_metadata(&self, hash: Block::Hash) -> Result<CachedHeaderMetadata<Block>, Self::Error> {
self.backend.blockchain().header_metadata(hash)
}
fn insert_header_metadata(&self, hash: Block::Hash, metadata: CachedHeaderMetadata<Block>) {
self.backend.blockchain().insert_header_metadata(hash, metadata)
}
fn remove_header_metadata(&self, hash: Block::Hash) {
self.backend.blockchain().remove_header_metadata(hash)
}
}
impl<B, E, Block, RA> ProvideUncles<Block> for Client<B, E, Block, RA> where
B: backend::Backend<Block, Blake2Hasher>,
E: CallExecutor<Block, Blake2Hasher>,
@@ -1798,7 +1811,7 @@ where
/// Utility methods for the client.
pub mod utils {
use super::*;
use crate::{blockchain, error};
use crate::error;
use primitives::H256;
use std::borrow::Borrow;
@@ -1812,7 +1825,7 @@ pub mod utils {
client: &'a T,
current: Option<(H, H)>,
) -> impl Fn(&H256, &H256) -> Result<bool, error::Error> + 'a
where T: ChainHeaderBackend<Block>,
where T: ChainHeaderBackend<Block> + HeaderMetadata<Block, Error=error::Error>,
{
move |base, hash| {
if base == hash { return Ok(false); }
@@ -1831,13 +1844,9 @@ pub mod utils {
}
}
let tree_route = blockchain::tree_route(
|id| client.header(id)?.ok_or_else(|| Error::UnknownBlock(format!("{:?}", id))),
BlockId::Hash(*hash),
BlockId::Hash(*base),
)?;
let ancestor = header_metadata::lowest_common_ancestor(client, *hash, *base)?;
Ok(tree_route.common_block().hash == *base)
Ok(ancestor.hash == *base)
}
}
}