mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-05-31 02:51:01 +00:00
core: grandpa limits votes to 3/4 of the unfinalized chain (#1554)
* core: grandpa limits votes to 3/4 of the unfinalized chain * core: test grandpa limited votes
This commit is contained in:
@@ -95,7 +95,7 @@ use consensus_common::{BlockImport, JustificationImport, Error as ConsensusError
|
||||
use runtime_primitives::Justification;
|
||||
use runtime_primitives::traits::{
|
||||
NumberFor, Block as BlockT, Header as HeaderT, DigestFor, ProvideRuntimeApi, Hash as HashT,
|
||||
DigestItemFor, DigestItem, As, Zero,
|
||||
DigestItemFor, DigestItem, As, One, Zero,
|
||||
};
|
||||
use fg_primitives::GrandpaApi;
|
||||
use runtime_primitives::generic::BlockId;
|
||||
@@ -422,16 +422,57 @@ impl<Block: BlockT<Hash=H256>, B, E, N, RA> grandpa::Chain<Block::Hash, NumberFo
|
||||
let limit = self.authority_set.current_limit();
|
||||
debug!(target: "afg", "Finding best chain containing block {:?} with number limit {:?}", block, limit);
|
||||
|
||||
match self.inner.best_containing(block, limit) {
|
||||
Ok(Some(hash)) => {
|
||||
let header = self.inner.header(&BlockId::Hash(hash)).ok()?
|
||||
match self.inner.best_containing(block, None) {
|
||||
Ok(Some(mut best_hash)) => {
|
||||
let base_header = self.inner.header(&BlockId::Hash(block)).ok()?
|
||||
.expect("Header known to exist after `best_containing` call; qed");
|
||||
|
||||
Some((hash, header.number().clone()))
|
||||
if let Some(limit) = limit {
|
||||
// this is a rare case which might cause issues,
|
||||
// might be better to return the header itself.
|
||||
if *base_header.number() > limit {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?} with limit {:?}: target block is after limit",
|
||||
block,
|
||||
limit,
|
||||
);
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
let mut best_header = self.inner.header(&BlockId::Hash(best_hash)).ok()?
|
||||
.expect("Header known to exist after `best_containing` call; qed");
|
||||
|
||||
// we target a vote towards 3/4 of the unfinalized chain (rounding up)
|
||||
let target = {
|
||||
let two = NumberFor::<Block>::one() + One::one();
|
||||
let three = two + One::one();
|
||||
let four = three + One::one();
|
||||
|
||||
let diff = *best_header.number() - *base_header.number();
|
||||
let diff = ((diff * three) + two) / four;
|
||||
|
||||
*base_header.number() + diff
|
||||
};
|
||||
|
||||
// unless our vote is currently being limited due to a pending change
|
||||
let target = limit.map(|limit| limit.min(target)).unwrap_or(target);
|
||||
|
||||
// walk backwards until we find the target block
|
||||
loop {
|
||||
if *best_header.number() < target { unreachable!(); }
|
||||
if *best_header.number() == target {
|
||||
return Some((best_hash, *best_header.number()));
|
||||
}
|
||||
|
||||
best_hash = *best_header.parent_hash();
|
||||
best_header = self.inner.header(&BlockId::Hash(best_hash)).ok()?
|
||||
.expect("Header known to exist after `best_containing` call; qed");
|
||||
}
|
||||
},
|
||||
Ok(None) => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: couldn't find target block", block);
|
||||
None
|
||||
}
|
||||
// Ok(None) can be returned when `block` is after `limit`. That might cause issues.
|
||||
// might be better to return the header itself in this (rare) case.
|
||||
Ok(None) => None,
|
||||
Err(e) => {
|
||||
debug!(target: "afg", "Encountered error finding best chain containing {:?}: {:?}", block, e);
|
||||
None
|
||||
|
||||
Reference in New Issue
Block a user