Skip to content

Commit 5a52827

Browse files
bkchrgodcodehunter
authored andcommitted
BABE: Fix aux data cleaning (paritytech#11263)
With the latest optimizations of the `FinalityNotification` generation, the aux data pruning started to print a warning. The problem here was that we printed a warning and stopped the adding of blocks to prune when we hit the `heigh_limit`. This is now wrong, as we could for example have two 512 long forks and then we start finalizing one of them. The second fork head would be part of the stale heads at some point (in the current implementation when we finalize second fork head number + 1), but then we would actually need to go back into the past than `heigh_limit` (which was actually last_finalized - 1). We now go back until we reach the canonical chain. Also fixed some wrong comment that was added by be about the content of the `finalized` blocks in the `FinalityNotification`.
1 parent 7dd9505 commit 5a52827

File tree

3 files changed

+48
-22
lines changed

3 files changed

+48
-22
lines changed

client/api/src/client.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,7 @@ pub struct FinalityNotification<Block: BlockT> {
308308
pub header: Block::Header,
309309
/// Path from the old finalized to new finalized parent (implicitly finalized blocks).
310310
///
311-
/// This maps to the range `(old_finalized, new_finalized]`.
311+
/// This maps to the range `(old_finalized, new_finalized)`.
312312
pub tree_route: Arc<[Block::Hash]>,
313313
/// Stale branches heads.
314314
pub stale_heads: Arc<[Block::Hash]>,

client/consensus/babe/src/lib.rs

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -541,49 +541,66 @@ where
541541
// Remove obsolete block's weight data by leveraging finality notifications.
542542
// This includes data for all finalized blocks (excluding the most recent one)
543543
// and all stale branches.
544-
fn aux_storage_cleanup<C: HeaderMetadata<Block>, Block: BlockT>(
544+
fn aux_storage_cleanup<C: HeaderMetadata<Block> + HeaderBackend<Block>, Block: BlockT>(
545545
client: &C,
546546
notification: &FinalityNotification<Block>,
547547
) -> AuxDataOperations {
548548
let mut aux_keys = HashSet::new();
549549

550-
// Cleans data for finalized block's ancestors down to, and including, the previously
551-
// finalized one.
552-
553-
let first_new_finalized = notification.tree_route.get(0).unwrap_or(&notification.hash);
554-
match client.header_metadata(*first_new_finalized) {
550+
let first = notification.tree_route.first().unwrap_or(&notification.hash);
551+
match client.header_metadata(*first) {
555552
Ok(meta) => {
556553
aux_keys.insert(aux_schema::block_weight_key(meta.parent));
557554
},
558-
Err(err) => {
559-
warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", first_new_finalized.to_string(), err.to_string());
560-
},
555+
Err(err) => warn!(
556+
target: "babe",
557+
"Failed to lookup metadata for block `{:?}`: {}",
558+
first,
559+
err,
560+
),
561561
}
562562

563-
aux_keys.extend(notification.tree_route.iter().map(aux_schema::block_weight_key));
563+
// Cleans data for finalized block's ancestors
564+
aux_keys.extend(
565+
notification
566+
.tree_route
567+
.iter()
568+
// Ensure we don't prune latest finalized block.
569+
// This should not happen, but better be safe than sorry!
570+
.filter(|h| **h != notification.hash)
571+
.map(aux_schema::block_weight_key),
572+
);
564573

565574
// Cleans data for stale branches.
566575

567-
// A safenet in case of malformed notification.
568-
let height_limit = notification.header.number().saturating_sub(
569-
notification.tree_route.len().saturated_into::<NumberFor<Block>>() + One::one(),
570-
);
571576
for head in notification.stale_heads.iter() {
572577
let mut hash = *head;
573-
// Insert stale blocks hashes until canonical chain is not reached.
574-
// Soon or late we should hit an element already present within the `aux_keys` set.
578+
// Insert stale blocks hashes until canonical chain is reached.
579+
// If we reach a block that is already part of the `aux_keys` we can stop the processing the
580+
// head.
575581
while aux_keys.insert(aux_schema::block_weight_key(hash)) {
576582
match client.header_metadata(hash) {
577583
Ok(meta) => {
578-
// This should never happen and must be considered a bug.
579-
if meta.number <= height_limit {
580-
warn!(target: "babe", "unexpected canonical chain state or malformed finality notification");
584+
hash = meta.parent;
585+
586+
// If the parent is part of the canonical chain or there doesn't exist a block
587+
// hash for the parent number (bug?!), we can abort adding blocks.
588+
if client
589+
.hash(meta.number.saturating_sub(1u32.into()))
590+
.ok()
591+
.flatten()
592+
.map_or(true, |h| h == hash)
593+
{
581594
break
582595
}
583-
hash = meta.parent;
584596
},
585597
Err(err) => {
586-
warn!(target: "babe", "header lookup fail while cleaning data for block {}: {}", head.to_string(), err.to_string());
598+
warn!(
599+
target: "babe",
600+
"Header lookup fail while cleaning data for block {:?}: {}",
601+
hash,
602+
err,
603+
);
587604
break
588605
},
589606
}

client/consensus/babe/src/tests.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,4 +1043,13 @@ fn obsolete_blocks_aux_data_cleanup() {
10431043
assert!(aux_data_check(&fork2_hashes, false));
10441044
// Present C4, C5
10451045
assert!(aux_data_check(&fork3_hashes, true));
1046+
1047+
client.finalize_block(BlockId::Number(4), None, true).unwrap();
1048+
1049+
// Wiped: A3
1050+
assert!(aux_data_check(&fork1_hashes[2..3], false));
1051+
// Present: A4
1052+
assert!(aux_data_check(&fork1_hashes[3..], true));
1053+
// Present C4, C5
1054+
assert!(aux_data_check(&fork3_hashes, true));
10461055
}

0 commit comments

Comments
 (0)