use crate::Block;
use crate::backend::ChainQuery;
pub struct TreeRoute<B: Block> {
route: Vec<B::Identifier>,
pivot: usize,
}
impl<B: Block> TreeRoute<B> {
pub fn retracted(&self) -> &[B::Identifier] {
&self.route[..self.pivot]
}
pub fn common_block(&self) -> &B::Identifier {
self.route.get(self.pivot).expect("tree-routes are computed between blocks; \
which are included in the route; \
thus it is never empty; qed")
}
pub fn enacted(&self) -> &[B::Identifier] {
&self.route[self.pivot + 1 ..]
}
}
pub fn tree_route<Ba: ChainQuery>(
backend: &Ba,
from_id: &<Ba::Block as Block>::Identifier,
to_id: &<Ba::Block as Block>::Identifier,
) -> Result<TreeRoute<Ba::Block>, Ba::Error> {
let mut from = backend.block_at(from_id)?;
let mut to = backend.block_at(to_id)?;
let mut from_branch = Vec::new();
let mut to_branch = Vec::new();
{
let mut from_depth = backend.depth_at(from_id)?;
let mut to_depth = backend.depth_at(to_id)?;
while to_depth > from_depth {
let to_parent_id = match to.parent_id() {
Some(parent_id) => parent_id,
None => {
assert!(to_depth == 0, "When parent_id is None, depth should be 0");
break;
}
};
to_branch.push(to.id());
to = backend.block_at(&to_parent_id)?;
to_depth = backend.depth_at(&to_parent_id)?;
}
while from_depth > to_depth {
let from_parent_id = match from.parent_id() {
Some(parent_id) => parent_id,
None => {
assert!(to_depth == 0, "When parent_id is None, depth should be 0");
break;
}
};
from_branch.push(from.id());
from = backend.block_at(&from_parent_id)?;
from_depth = backend.depth_at(&from_parent_id)?;
}
}
while from.id() != to.id() {
let to_parent_id = match to.parent_id() {
Some(parent_id) => parent_id,
None => {
panic!("During backend import, all blocks are checked to have parent; this branch is when common parent does not exist; qed");
}
};
let from_parent_id = match from.parent_id() {
Some(parent_id) => parent_id,
None => {
panic!("During backend import, all blocks are checked to have parent; this branch is when common parent does not exist; qed");
}
};
to_branch.push(to.id());
to = backend.block_at(&to_parent_id)?;
from_branch.push(from.id());
from = backend.block_at(&from_parent_id)?;
}
let pivot = from_branch.len();
from_branch.push(to.id());
from_branch.extend(to_branch.into_iter().rev());
Ok(TreeRoute {
route: from_branch,
pivot,
})
}