mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 21:01:05 +00:00
Fix longest chain finalization target lookup (#13289)
* Finalization target should be chosed as some ancestor of SelectChain::best_chain * More test assertions * Improve docs * Removed stale docs * Rename 'target' to 'base' in lookup method * Fix typo * Apply suggestions from code review Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> * Rename 'target_hash' to 'base_hash' in 'SelectChain::finality_target()' * Apply suggestions from code review Co-authored-by: Anton <anton.kalyaev@gmail.com> * Docs improvement * Doc fix * Apply suggestions from code review Co-authored-by: Bastian Köcher <git@kchr.de> * Apply more code suggestions --------- Co-authored-by: André Silva <123550+andresilva@users.noreply.github.com> Co-authored-by: Anton <anton.kalyaev@gmail.com> Co-authored-by: Bastian Köcher <git@kchr.de>
This commit is contained in:
@@ -183,96 +183,43 @@ pub trait Backend<Block: BlockT>:
|
||||
/// Return hashes of all blocks that are children of the block with `parent_hash`.
|
||||
fn children(&self, parent_hash: Block::Hash) -> Result<Vec<Block::Hash>>;
|
||||
|
||||
/// Get the most recent block hash of the best (longest) chains
|
||||
/// that contain block with the given `target_hash`.
|
||||
/// Get the most recent block hash of the longest chain that contains
|
||||
/// a block with the given `base_hash`.
|
||||
///
|
||||
/// The search space is always limited to blocks which are in the finalized
|
||||
/// chain or descendents of it.
|
||||
///
|
||||
/// If `maybe_max_block_number` is `Some(max_block_number)`
|
||||
/// the search is limited to block `numbers <= max_block_number`.
|
||||
/// in other words as if there were no blocks greater `max_block_number`.
|
||||
/// Returns `Ok(None)` if `target_hash` is not found in search space.
|
||||
/// TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444)
|
||||
fn best_containing(
|
||||
/// Returns `Ok(None)` if `base_hash` is not found in search space.
|
||||
// TODO: document time complexity of this, see [#1444](https://github.com/paritytech/substrate/issues/1444)
|
||||
fn longest_containing(
|
||||
&self,
|
||||
target_hash: Block::Hash,
|
||||
maybe_max_number: Option<NumberFor<Block>>,
|
||||
base_hash: Block::Hash,
|
||||
import_lock: &RwLock<()>,
|
||||
) -> Result<Option<Block::Hash>> {
|
||||
let target_header = {
|
||||
match self.header(target_hash)? {
|
||||
Some(x) => x,
|
||||
// target not in blockchain
|
||||
None => return Ok(None),
|
||||
}
|
||||
let Some(base_header) = self.header(base_hash)? else {
|
||||
return Ok(None)
|
||||
};
|
||||
|
||||
if let Some(max_number) = maybe_max_number {
|
||||
// target outside search range
|
||||
if target_header.number() > &max_number {
|
||||
return Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
let leaves = {
|
||||
// ensure no blocks are imported during this code block.
|
||||
// an import could trigger a reorg which could change the canonical chain.
|
||||
// we depend on the canonical chain staying the same during this code block.
|
||||
let _import_guard = import_lock.read();
|
||||
|
||||
let info = self.info();
|
||||
|
||||
// this can be `None` if the best chain is shorter than the target header.
|
||||
let maybe_canon_hash = self.hash(*target_header.number())?;
|
||||
|
||||
if maybe_canon_hash.as_ref() == Some(&target_hash) {
|
||||
// if a `max_number` is given we try to fetch the block at the
|
||||
// given depth, if it doesn't exist or `max_number` is not
|
||||
// provided, we continue to search from all leaves below.
|
||||
if let Some(max_number) = maybe_max_number {
|
||||
if let Some(header) = self.hash(max_number)? {
|
||||
return Ok(Some(header))
|
||||
}
|
||||
}
|
||||
} else if info.finalized_number >= *target_header.number() {
|
||||
// header is on a dead fork.
|
||||
if info.finalized_number > *base_header.number() {
|
||||
// `base_header` is on a dead fork.
|
||||
return Ok(None)
|
||||
}
|
||||
|
||||
self.leaves()?
|
||||
};
|
||||
|
||||
// for each chain. longest chain first. shortest last
|
||||
for leaf_hash in leaves {
|
||||
// start at the leaf
|
||||
let mut current_hash = leaf_hash;
|
||||
|
||||
// if search is not restricted then the leaf is the best
|
||||
let mut best_hash = leaf_hash;
|
||||
|
||||
// go backwards entering the search space
|
||||
// waiting until we are <= max_number
|
||||
if let Some(max_number) = maybe_max_number {
|
||||
loop {
|
||||
let current_header = self
|
||||
.header(current_hash)?
|
||||
.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
|
||||
|
||||
if current_header.number() <= &max_number {
|
||||
best_hash = current_header.hash();
|
||||
break
|
||||
}
|
||||
|
||||
current_hash = *current_header.parent_hash();
|
||||
}
|
||||
}
|
||||
|
||||
// go backwards through the chain (via parent links)
|
||||
loop {
|
||||
// until we find target
|
||||
if current_hash == target_hash {
|
||||
return Ok(Some(best_hash))
|
||||
if current_hash == base_hash {
|
||||
return Ok(Some(leaf_hash))
|
||||
}
|
||||
|
||||
let current_header = self
|
||||
@@ -280,7 +227,7 @@ pub trait Backend<Block: BlockT>:
|
||||
.ok_or_else(|| Error::MissingHeader(current_hash.to_string()))?;
|
||||
|
||||
// stop search in this chain once we go below the target's block number
|
||||
if current_header.number() < target_header.number() {
|
||||
if current_header.number() < base_header.number() {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -293,9 +240,8 @@ pub trait Backend<Block: BlockT>:
|
||||
//
|
||||
// FIXME #1558 only issue this warning when not on a dead fork
|
||||
warn!(
|
||||
"Block {:?} exists in chain but not found when following all \
|
||||
leaves backwards. Number limit = {:?}",
|
||||
target_hash, maybe_max_number,
|
||||
"Block {:?} exists in chain but not found when following all leaves backwards",
|
||||
base_hash,
|
||||
);
|
||||
|
||||
Ok(None)
|
||||
|
||||
Reference in New Issue
Block a user