grandpa: avoid importing unnecessary justifications (#14423)

* grandpa: avoid importing unnecessary justifications

* grandpa: make justification_import_period configurable

* grandpa: keep the first justification

* grandpa: add test for justification import period

* grandpa: fix test
This commit is contained in:
André Silva
2023-07-17 18:38:34 +01:00
committed by GitHub
parent 58bbe568cb
commit c761d4c39e
8 changed files with 178 additions and 90 deletions
@@ -1102,7 +1102,7 @@ where
finalize_block(
self.client.clone(),
&self.authority_set,
Some(self.config.justification_period.into()),
Some(self.config.justification_generation_period),
hash,
number,
(round, commit).into(),
@@ -1315,6 +1315,38 @@ where
.or_else(|| Some((target_header.hash(), *target_header.number()))))
}
/// Whether we should process a justification for the given block.
///
/// This can be used to decide whether to import a justification (when
/// importing a block), or whether to generate a justification from a
/// commit (when validating). Justifications for blocks that change the
/// authority set will always be processed, otherwise we'll only process
/// justifications if the last one was `justification_period` blocks ago.
pub(crate) fn should_process_justification<BE, Block, Client>(
client: &Client,
justification_period: u32,
number: NumberFor<Block>,
enacts_change: bool,
) -> bool
where
Block: BlockT,
BE: BackendT<Block>,
Client: ClientForGrandpa<Block, BE>,
{
if enacts_change {
return true
}
let last_finalized_number = client.info().finalized_number;
// keep the first justification before reaching the justification period
if last_finalized_number.is_zero() {
return true
}
last_finalized_number / justification_period.into() != number / justification_period.into()
}
/// Finalize the given block and apply any authority set changes. If an
/// authority set change is enacted then a justification is created (if not
/// given) and stored with the block when finalizing it.
@@ -1322,7 +1354,7 @@ where
pub(crate) fn finalize_block<BE, Block, Client>(
client: Arc<Client>,
authority_set: &SharedAuthoritySet<Block::Hash, NumberFor<Block>>,
justification_period: Option<NumberFor<Block>>,
justification_generation_period: Option<u32>,
hash: Block::Hash,
number: NumberFor<Block>,
justification_or_commit: JustificationOrCommit<Block>,
@@ -1393,22 +1425,13 @@ where
let (justification_required, justification) = match justification_or_commit {
JustificationOrCommit::Justification(justification) => (true, justification),
JustificationOrCommit::Commit((round_number, commit)) => {
let mut justification_required =
// justification is always required when block that enacts new authorities
// set is finalized
status.new_set_block.is_some();
let enacts_change = status.new_set_block.is_some();
// justification is required every N blocks to be able to prove blocks
// finalization to remote nodes
if !justification_required {
if let Some(justification_period) = justification_period {
let last_finalized_number = client.info().finalized_number;
justification_required = (!last_finalized_number.is_zero() ||
number - last_finalized_number == justification_period) &&
(last_finalized_number / justification_period !=
number / justification_period);
}
}
let justification_required = justification_generation_period
.map(|period| {
should_process_justification(&*client, period, number, enacts_change)
})
.unwrap_or(enacts_change);
let justification =
GrandpaJustification::from_commit(&client, round_number, commit)?;