Skip to content

Commit

Permalink
Add pending_state_sync_attempt
Browse files Browse the repository at this point in the history
There is an edge case where the finalized block notification
is received, but the conditions required to initiate the state sync are
not fully met. In such cases, state sync would fail to start as expected
and remain stalled.

This fixes it by storing the pending attempt and trying to start it
later.
  • Loading branch information
liuchengxu committed Sep 7, 2024
1 parent a58bf78 commit 3672c34
Showing 1 changed file with 21 additions and 2 deletions.
23 changes: 21 additions & 2 deletions substrate/client/network/sync/src/strategy/chain_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,14 @@ pub struct ChainSync<B: BlockT, Client> {
/// A set of hashes of blocks that are being downloaded or have been
/// downloaded and are queued for import.
queue_blocks: HashSet<B::Hash>,
/// A pending attempt to start the state sync.
///
/// The initiation of state sync may be deferred in cases where other conditions
/// are not yet met when the finalized block notification is received, such as
/// when `queue_blocks` is not empty or there are no peers. This field holds the
/// necessary information to attempt the state sync at a later point when
/// conditions are satisfied.
pending_state_sync_attempt: Option<(B::Hash, NumberFor<B>, bool)>,
/// Fork sync targets.
fork_targets: HashMap<B::Hash, ForkTarget<B>>,
/// A set of peers for which there might be potential block requests
Expand Down Expand Up @@ -376,6 +384,7 @@ where
extra_justifications: ExtraRequests::new("justification", metrics_registry),
mode,
queue_blocks: Default::default(),
pending_state_sync_attempt: None,
fork_targets: Default::default(),
allowed_requests: Default::default(),
max_parallel_downloads,
Expand Down Expand Up @@ -1013,8 +1022,12 @@ where
});

if let ChainSyncMode::LightState { skip_proofs, .. } = &self.mode {
if self.state_sync.is_none() && !self.peers.is_empty() && self.queue_blocks.is_empty() {
self.attempt_state_sync(*hash, number, *skip_proofs)
if self.state_sync.is_none() {
if !self.peers.is_empty() && self.queue_blocks.is_empty() {
self.attempt_state_sync(*hash, number, *skip_proofs);
} else {
self.pending_state_sync_attempt.replace((*hash, number, *skip_proofs));
}
}
}

Expand Down Expand Up @@ -1886,6 +1899,12 @@ where
/// Get pending actions to perform.
#[must_use]
pub fn actions(&mut self) -> impl Iterator<Item = ChainSyncAction<B>> {
if !self.peers.is_empty() && self.queue_blocks.is_empty() {
if let Some((hash, number, skip_proofs)) = self.pending_state_sync_attempt.take() {
self.attempt_state_sync(hash, number, skip_proofs);
}
}

let block_requests = self
.block_requests()
.into_iter()
Expand Down

0 comments on commit 3672c34

Please sign in to comment.