Skip to content

Commit a9e7b04

Browse files
bkchrgithub-actions[bot]
authored andcommitted
FinalityNotification: Directly include stale blocks (#9904)
The finality notification was already carrying the information about the stale heads. However, most users of the stale heads were expanding these stale heads to all the stale blocks. So, we were iterating the same forks multiple times in the node for each finality notification. Also in a possible future where we start actually pruning headers as well, expanding these forks would fail. So, this pull request is changing the finality notification to directly carry the stale blocks (which were calculated any way already). --------- Co-authored-by: cmd[bot] <41898282+github-actions[bot]@users.noreply.github.com>
1 parent 29b6cbe commit a9e7b04

File tree

12 files changed

+185
-161
lines changed

12 files changed

+185
-161
lines changed

cumulus/client/pov-recovery/src/tests.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1203,7 +1203,7 @@ async fn candidate_is_finalized_while_awaiting_recovery() {
12031203
let (unpin_sender, _unpin_receiver) = sc_utils::mpsc::tracing_unbounded("test_unpin", 10);
12041204
finality_notifications_tx
12051205
.unbounded_send(FinalityNotification::from_summary(
1206-
FinalizeSummary { header: header.clone(), finalized: vec![], stale_heads: vec![] },
1206+
FinalizeSummary { header: header.clone(), finalized: vec![], stale_blocks: vec![] },
12071207
unpin_sender,
12081208
))
12091209
.unwrap();

prdoc/pr_9904.prdoc

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
title: 'FinalityNotification: Directly include stale blocks'
2+
doc:
3+
- audience: Node Dev
4+
description: |-
5+
The finality notification was already carrying the information about the stale heads. However, most users of the stale heads were expanding these stale heads to all the stale blocks. So, we were iterating the same forks multiple times in the node for each finality notification. Also in a possible future where we start actually pruning headers as well, expanding these forks would fail.
6+
7+
So, this pull request is changing the finality notification to directly carry the stale blocks (which were calculated any way already).
8+
crates:
9+
- name: cumulus-client-pov-recovery
10+
bump: major
11+
- name: sc-client-api
12+
bump: major
13+
- name: sc-consensus-babe
14+
bump: major
15+
- name: sc-client-db
16+
bump: major
17+
- name: mmr-gadget
18+
bump: major
19+
- name: sc-rpc-spec-v2
20+
bump: major
21+
- name: sc-service
22+
bump: major
23+
- name: sp-blockchain
24+
bump: major

substrate/client/api/src/backend.rs

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,15 @@ pub struct ImportSummary<Block: BlockT> {
7979
pub import_notification_action: ImportNotificationAction,
8080
}
8181

82+
/// A stale block.
83+
#[derive(Clone, Debug)]
84+
pub struct StaleBlock<Block: BlockT> {
85+
/// The hash of this block.
86+
pub hash: Block::Hash,
87+
/// Is this a head?
88+
pub is_head: bool,
89+
}
90+
8291
/// Finalization operation summary.
8392
///
8493
/// Contains information about the block that just got finalized,
@@ -87,10 +96,11 @@ pub struct FinalizeSummary<Block: BlockT> {
8796
/// Last finalized block header.
8897
pub header: Block::Header,
8998
/// Blocks that were finalized.
99+
///
90100
/// The last entry is the one that has been explicitly finalized.
91101
pub finalized: Vec<Block::Hash>,
92-
/// Heads that became stale during this finalization operation.
93-
pub stale_heads: Vec<Block::Hash>,
102+
/// Blocks that became stale during this finalization operation.
103+
pub stale_blocks: Vec<StaleBlock<Block>>,
94104
}
95105

96106
/// Import operation wrapper.

substrate/client/api/src/client.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ use std::{
3131
sync::Arc,
3232
};
3333

34-
use crate::{blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary};
34+
use crate::{
35+
blockchain::Info, notifications::StorageEventStream, FinalizeSummary, ImportSummary, StaleBlock,
36+
};
3537

3638
use sc_transaction_pool_api::ChainEvent;
3739
use sc_utils::mpsc::{TracingUnboundedReceiver, TracingUnboundedSender};
@@ -404,8 +406,8 @@ pub struct FinalityNotification<Block: BlockT> {
404406
///
405407
/// This maps to the range `(old_finalized, new_finalized)`.
406408
pub tree_route: Arc<[Block::Hash]>,
407-
/// Stale branches heads.
408-
pub stale_heads: Arc<[Block::Hash]>,
409+
/// Stale blocks.
410+
pub stale_blocks: Arc<[Arc<StaleBlock<Block>>]>,
409411
/// Handle to unpin the block this notification is for
410412
unpin_handle: UnpinHandle<Block>,
411413
}
@@ -439,7 +441,9 @@ impl<Block: BlockT> FinalityNotification<Block> {
439441
hash,
440442
header: summary.header,
441443
tree_route: Arc::from(summary.finalized),
442-
stale_heads: Arc::from(summary.stale_heads),
444+
stale_blocks: Arc::from(
445+
summary.stale_blocks.into_iter().map(Arc::from).collect::<Vec<_>>(),
446+
),
443447
unpin_handle: UnpinHandle::new(hash, unpin_worker_sender),
444448
}
445449
}

substrate/client/consensus/babe/src/lib.rs

Lines changed: 2 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ use sp_api::{ApiExt, ProvideRuntimeApi};
113113
use sp_application_crypto::AppCrypto;
114114
use sp_block_builder::BlockBuilder as BlockBuilderApi;
115115
use sp_blockchain::{
116-
Backend as _, BlockStatus, Error as ClientError, ForkBackend, HeaderBackend, HeaderMetadata,
116+
Backend as _, BlockStatus, Error as ClientError, HeaderBackend, HeaderMetadata,
117117
Result as ClientResult,
118118
};
119119
use sp_consensus::{BlockOrigin, Environment, Error as ConsensusError, Proposer, SelectChain};
@@ -561,16 +561,7 @@ fn aux_storage_cleanup<C: HeaderMetadata<Block> + HeaderBackend<Block>, Block: B
561561
.filter(|h| **h != notification.hash),
562562
);
563563

564-
// Cleans data for stale forks.
565-
let stale_forks = match client.expand_forks(&notification.stale_heads) {
566-
Ok(stale_forks) => stale_forks,
567-
Err(e) => {
568-
warn!(target: LOG_TARGET, "{:?}", e);
569-
570-
Default::default()
571-
},
572-
};
573-
hashes.extend(stale_forks.iter());
564+
hashes.extend(notification.stale_blocks.iter().map(|b| b.hash));
574565

575566
hashes
576567
.into_iter()

substrate/client/db/src/lib.rs

Lines changed: 54 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,7 +1898,11 @@ impl<Block: BlockT> Backend<Block> {
18981898
}
18991899

19001900
if remove_displaced {
1901-
let new_displaced = self.blockchain.displaced_leaves_after_finalizing(f_hash, f_num)?;
1901+
let new_displaced = self.blockchain.displaced_leaves_after_finalizing(
1902+
f_hash,
1903+
f_num,
1904+
*f_header.parent_hash(),
1905+
)?;
19021906

19031907
self.blockchain.leaves.write().remove_displaced_leaves(FinalizationOutcome::new(
19041908
new_displaced.displaced_leaves.iter().copied(),
@@ -3289,16 +3293,18 @@ pub(crate) mod tests {
32893293
let a4_hash =
32903294
insert_disconnected_header(&backend, a4_number, a3_hash, H256::from([2; 32]), true);
32913295
{
3292-
let displaced =
3293-
blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap();
3296+
let displaced = blockchain
3297+
.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([200; 32]))
3298+
.unwrap();
32943299
assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, genesis_hash]);
32953300
assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]);
32963301
assert_eq!(displaced.displaced_blocks, vec![]);
32973302
}
32983303

32993304
{
3300-
let displaced =
3301-
blockchain.displaced_leaves_after_finalizing(a4_hash, a4_number).unwrap();
3305+
let displaced = blockchain
3306+
.displaced_leaves_after_finalizing(a4_hash, a4_number, a3_hash)
3307+
.unwrap();
33023308
assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, genesis_hash]);
33033309
assert_eq!(displaced.displaced_leaves, vec![(genesis_number, genesis_hash)]);
33043310
assert_eq!(displaced.displaced_blocks, vec![]);
@@ -3315,8 +3321,9 @@ pub(crate) mod tests {
33153321
false,
33163322
);
33173323
{
3318-
let displaced =
3319-
blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap();
3324+
let displaced = blockchain
3325+
.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([2; 32]))
3326+
.unwrap();
33203327
assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, a1_hash]);
33213328
assert_eq!(displaced.displaced_leaves, vec![]);
33223329
assert_eq!(displaced.displaced_blocks, vec![]);
@@ -3334,8 +3341,9 @@ pub(crate) mod tests {
33343341
false,
33353342
);
33363343
{
3337-
let displaced =
3338-
blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap();
3344+
let displaced = blockchain
3345+
.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([2; 32]))
3346+
.unwrap();
33393347
assert_eq!(blockchain.leaves().unwrap(), vec![a4_hash, a1_hash, b1_hash]);
33403348
assert_eq!(displaced.displaced_leaves, vec![]);
33413349
assert_eq!(displaced.displaced_blocks, vec![]);
@@ -3358,8 +3366,9 @@ pub(crate) mod tests {
33583366
let b5_hash =
33593367
insert_disconnected_header(&backend, b5_number, b4_hash, H256::from([43; 32]), false);
33603368
{
3361-
let displaced =
3362-
blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap();
3369+
let displaced = blockchain
3370+
.displaced_leaves_after_finalizing(a3_hash, a3_number, H256::from([2; 32]))
3371+
.unwrap();
33633372
assert_eq!(blockchain.leaves().unwrap(), vec![b5_hash, a4_hash, a1_hash]);
33643373
assert_eq!(displaced.displaced_leaves, vec![]);
33653374
assert_eq!(displaced.displaced_blocks, vec![]);
@@ -3374,8 +3383,9 @@ pub(crate) mod tests {
33743383
let c4_hash =
33753384
insert_disconnected_header(&backend, c4_number, a3_hash, H256::from([44; 32]), false);
33763385
{
3377-
let displaced =
3378-
blockchain.displaced_leaves_after_finalizing(a4_hash, a4_number).unwrap();
3386+
let displaced = blockchain
3387+
.displaced_leaves_after_finalizing(a4_hash, a4_number, a3_hash)
3388+
.unwrap();
33793389
assert_eq!(blockchain.leaves().unwrap(), vec![b5_hash, a4_hash, c4_hash, a1_hash]);
33803390
assert_eq!(displaced.displaced_leaves, vec![(c4_number, c4_hash)]);
33813391
assert_eq!(displaced.displaced_blocks, vec![c4_hash]);
@@ -3404,33 +3414,37 @@ pub(crate) mod tests {
34043414

34053415
{
34063416
let displaced = blockchain
3407-
.displaced_leaves_after_finalizing(genesis_hash, genesis_number)
3417+
.displaced_leaves_after_finalizing(genesis_hash, genesis_number, Default::default())
34083418
.unwrap();
34093419
assert_eq!(displaced.displaced_leaves, vec![]);
34103420
assert_eq!(displaced.displaced_blocks, vec![]);
34113421
}
34123422
{
3413-
let displaced_a1 =
3414-
blockchain.displaced_leaves_after_finalizing(a1_hash, a1_number).unwrap();
3423+
let displaced_a1 = blockchain
3424+
.displaced_leaves_after_finalizing(a1_hash, a1_number, genesis_hash)
3425+
.unwrap();
34153426
assert_eq!(displaced_a1.displaced_leaves, vec![]);
34163427
assert_eq!(displaced_a1.displaced_blocks, vec![]);
34173428

3418-
let displaced_a2 =
3419-
blockchain.displaced_leaves_after_finalizing(a2_hash, a3_number).unwrap();
3429+
let displaced_a2 = blockchain
3430+
.displaced_leaves_after_finalizing(a2_hash, a2_number, a1_hash)
3431+
.unwrap();
34203432
assert_eq!(displaced_a2.displaced_leaves, vec![]);
34213433
assert_eq!(displaced_a2.displaced_blocks, vec![]);
34223434

3423-
let displaced_a3 =
3424-
blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap();
3435+
let displaced_a3 = blockchain
3436+
.displaced_leaves_after_finalizing(a3_hash, a3_number, a2_hash)
3437+
.unwrap();
34253438
assert_eq!(displaced_a3.displaced_leaves, vec![]);
34263439
assert_eq!(displaced_a3.displaced_blocks, vec![]);
34273440
}
34283441
{
34293442
// Finalized block is above leaves and not imported yet.
34303443
// We will not be able to make a connection,
34313444
// nothing can be marked as displaced.
3432-
let displaced =
3433-
blockchain.displaced_leaves_after_finalizing(H256::from([57; 32]), 10).unwrap();
3445+
let displaced = blockchain
3446+
.displaced_leaves_after_finalizing(H256::from([57; 32]), 10, H256::from([56; 32]))
3447+
.unwrap();
34343448
assert_eq!(displaced.displaced_leaves, vec![]);
34353449
assert_eq!(displaced.displaced_blocks, vec![]);
34363450
}
@@ -3454,8 +3468,9 @@ pub(crate) mod tests {
34543468
let d2_hash = insert_header(&backend, d2_number, d1_hash, None, Default::default());
34553469

34563470
{
3457-
let displaced_a1 =
3458-
blockchain.displaced_leaves_after_finalizing(a1_hash, a1_number).unwrap();
3471+
let displaced_a1 = blockchain
3472+
.displaced_leaves_after_finalizing(a1_hash, a1_number, genesis_hash)
3473+
.unwrap();
34593474
assert_eq!(
34603475
displaced_a1.displaced_leaves,
34613476
vec![(c2_number, c2_hash), (d2_number, d2_hash)]
@@ -3464,27 +3479,31 @@ pub(crate) mod tests {
34643479
displaced_blocks.sort();
34653480
assert_eq!(displaced_a1.displaced_blocks, displaced_blocks);
34663481

3467-
let displaced_a2 =
3468-
blockchain.displaced_leaves_after_finalizing(a2_hash, a2_number).unwrap();
3482+
let displaced_a2 = blockchain
3483+
.displaced_leaves_after_finalizing(a2_hash, a2_number, a1_hash)
3484+
.unwrap();
34693485
assert_eq!(displaced_a1.displaced_leaves, displaced_a2.displaced_leaves);
34703486
assert_eq!(displaced_a1.displaced_blocks, displaced_a2.displaced_blocks);
34713487

3472-
let displaced_a3 =
3473-
blockchain.displaced_leaves_after_finalizing(a3_hash, a3_number).unwrap();
3488+
let displaced_a3 = blockchain
3489+
.displaced_leaves_after_finalizing(a3_hash, a3_number, a2_hash)
3490+
.unwrap();
34743491
assert_eq!(displaced_a1.displaced_leaves, displaced_a3.displaced_leaves);
34753492
assert_eq!(displaced_a1.displaced_blocks, displaced_a3.displaced_blocks);
34763493
}
34773494
{
3478-
let displaced =
3479-
blockchain.displaced_leaves_after_finalizing(b1_hash, b1_number).unwrap();
3495+
let displaced = blockchain
3496+
.displaced_leaves_after_finalizing(b1_hash, b1_number, genesis_hash)
3497+
.unwrap();
34803498
assert_eq!(displaced.displaced_leaves, vec![(a3_number, a3_hash)]);
34813499
let mut displaced_blocks = vec![a1_hash, a2_hash, a3_hash];
34823500
displaced_blocks.sort();
34833501
assert_eq!(displaced.displaced_blocks, displaced_blocks);
34843502
}
34853503
{
3486-
let displaced =
3487-
blockchain.displaced_leaves_after_finalizing(b2_hash, b2_number).unwrap();
3504+
let displaced = blockchain
3505+
.displaced_leaves_after_finalizing(b2_hash, b2_number, b1_hash)
3506+
.unwrap();
34883507
assert_eq!(
34893508
displaced.displaced_leaves,
34903509
vec![(a3_number, a3_hash), (d2_number, d2_hash)]
@@ -3494,8 +3513,9 @@ pub(crate) mod tests {
34943513
assert_eq!(displaced.displaced_blocks, displaced_blocks);
34953514
}
34963515
{
3497-
let displaced =
3498-
blockchain.displaced_leaves_after_finalizing(c2_hash, c2_number).unwrap();
3516+
let displaced = blockchain
3517+
.displaced_leaves_after_finalizing(c2_hash, c2_number, c1_hash)
3518+
.unwrap();
34993519
assert_eq!(
35003520
displaced.displaced_leaves,
35013521
vec![(a3_number, a3_hash), (d2_number, d2_hash)]

substrate/client/merkle-mountain-range/src/offchain_mmr.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ use crate::{aux_schema, MmrClient, LOG_TARGET};
2525
use log::{debug, error, info, warn};
2626
use sc_client_api::{Backend, FinalityNotification};
2727
use sc_offchain::OffchainDb;
28-
use sp_blockchain::{CachedHeaderMetadata, ForkBackend};
28+
use sp_blockchain::CachedHeaderMetadata;
2929
use sp_consensus_beefy::MmrRootHash;
3030
use sp_core::offchain::{DbExternalities, StorageKind};
3131
use sp_mmr_primitives::{utils, utils::NodesUtils, MmrApi, NodeIndex};
3232
use sp_runtime::{
3333
traits::{Block, Header, NumberFor, One},
3434
Saturating,
3535
};
36-
use std::{collections::VecDeque, default::Default, sync::Arc};
36+
use std::{collections::VecDeque, sync::Arc};
3737

3838
/// `OffchainMMR` exposes MMR offchain canonicalization and pruning logic.
3939
pub struct OffchainMmr<B: Block, BE: Backend<B>, C> {
@@ -273,14 +273,7 @@ where
273273
self.write_gadget_state_or_log();
274274

275275
// Remove offchain MMR nodes for stale forks.
276-
let stale_forks = self.client.expand_forks(&notification.stale_heads).unwrap_or_else(|e| {
277-
warn!(target: LOG_TARGET, "{:?}", e);
278-
279-
Default::default()
280-
});
281-
for hash in stale_forks.iter() {
282-
self.prune_branch(hash);
283-
}
276+
notification.stale_blocks.iter().for_each(|s| self.prune_branch(&s.hash));
284277
}
285278
}
286279

0 commit comments

Comments
 (0)