diff --git a/cumulus/client/relay-chain-minimal-node/src/network.rs b/cumulus/client/relay-chain-minimal-node/src/network.rs index 95785063c1ae..6352e844b34e 100644 --- a/cumulus/client/relay-chain-minimal-node/src/network.rs +++ b/cumulus/client/relay-chain-minimal-node/src/network.rs @@ -165,6 +165,7 @@ fn get_block_announce_proto_config( best_number, best_hash, genesis_hash, + true, ))), // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement // protocol is still hardcoded into the peerset. diff --git a/substrate/client/cli/src/params/network_params.rs b/substrate/client/cli/src/params/network_params.rs index decf972b023a..232bf963edc5 100644 --- a/substrate/client/cli/src/params/network_params.rs +++ b/substrate/client/cli/src/params/network_params.rs @@ -171,6 +171,14 @@ pub struct NetworkParams { /// and observe block requests timing out. #[arg(long, value_name = "COUNT", default_value_t = 64)] pub max_blocks_per_request: u32, + + /// Parameter that allows node to forcefully assume it is synced, needed for network + /// bootstrapping only, as long as two synced nodes remain on the network at any time, this + /// doesn't need to be used. + /// + /// `--dev` enables this option automatically. + #[clap(long)] + pub force_synced: bool, } impl NetworkParams { @@ -267,6 +275,7 @@ impl NetworkParams { ipfs_server: self.ipfs_server, sync_mode: self.sync.into(), pause_sync: Arc::new(AtomicBool::new(false)), + force_synced: self.force_synced || is_dev, } } } diff --git a/substrate/client/informant/src/display.rs b/substrate/client/informant/src/display.rs index bcf3794032fe..f3aa9714fb99 100644 --- a/substrate/client/informant/src/display.rs +++ b/substrate/client/informant/src/display.rs @@ -135,6 +135,7 @@ impl InformantDisplay { (state.size as f32) / (1024f32 * 1024f32) ), ), + (SyncState::Pending, _, _) => ("⏳", "Pending".into(), "".into()), (SyncState::Idle, _, _) => ("💤", "Idle".into(), "".into()), (SyncState::Downloading { target }, _, _) => ("⚙️ ", format!("Syncing{}", speed), format!(", target=#{target}")), diff --git a/substrate/client/network/common/src/sync/message.rs b/substrate/client/network/common/src/sync/message.rs index 7cdb14172885..5bb00b16cca1 100644 --- a/substrate/client/network/common/src/sync/message.rs +++ b/substrate/client/network/common/src/sync/message.rs @@ -190,6 +190,8 @@ pub mod generic { pub struct BlockAnnounce { /// New block header. pub header: H, + /// Whether peer is synced. + pub is_synced: bool, /// Block state. TODO: Remove `Option` and custom encoding when v4 becomes common. pub state: Option, /// Data associated with this block announcement, e.g. a candidate message. @@ -202,6 +204,7 @@ pub mod generic { impl Encode for BlockAnnounce { fn encode_to(&self, dest: &mut T) { self.header.encode_to(dest); + self.is_synced.encode_to(dest); if let Some(state) = &self.state { state.encode_to(dest); } @@ -215,8 +218,9 @@ pub mod generic { fn decode(input: &mut I) -> Result { let header = H::decode(input)?; let state = BlockState::decode(input).ok(); + let is_synced = bool::decode(input)?; let data = Vec::decode(input).ok(); - Ok(Self { header, state, data }) + Ok(Self { header, is_synced, state, data }) } } } @@ -232,6 +236,8 @@ pub struct BlockAnnouncesHandshake { pub best_hash: B::Hash, /// Genesis block hash. pub genesis_hash: B::Hash, + /// Whether peer is synced. + pub is_synced: bool, } impl BlockAnnouncesHandshake { @@ -240,7 +246,8 @@ impl BlockAnnouncesHandshake { best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, + is_synced: bool, ) -> Self { - Self { genesis_hash, roles, best_number, best_hash } + Self { genesis_hash, roles, best_number, best_hash, is_synced } } } diff --git a/substrate/client/network/src/config.rs b/substrate/client/network/src/config.rs index 9181300afab0..f18c236cc5b4 100644 --- a/substrate/client/network/src/config.rs +++ b/substrate/client/network/src/config.rs @@ -659,6 +659,11 @@ pub struct NetworkConfiguration { /// a modification of the way the implementation works. Different nodes with different /// configured values remain compatible with each other. pub yamux_window_size: Option, + + /// Parameter that allows node to forcefully assume it is synced, needed for network + /// bootstrapping only, as long as two synced nodes remain on the network at any time, this + /// doesn't need to be used. + pub force_synced: bool, } impl NetworkConfiguration { @@ -692,6 +697,7 @@ impl NetworkConfiguration { .expect("value is a constant; constant is non-zero; qed."), yamux_window_size: None, ipfs_server: false, + force_synced: false, } } diff --git a/substrate/client/network/src/protocol/message.rs b/substrate/client/network/src/protocol/message.rs index 5f2511fd6ddc..231b15a919fb 100644 --- a/substrate/client/network/src/protocol/message.rs +++ b/substrate/client/network/src/protocol/message.rs @@ -136,6 +136,8 @@ pub mod generic { pub best_hash: Hash, /// Genesis block hash. pub genesis_hash: Hash, + /// Whether peer is synced. + pub is_synced: bool, } /// Status sent on connection. @@ -153,6 +155,8 @@ pub mod generic { pub best_hash: Hash, /// Genesis block hash. pub genesis_hash: Hash, + /// Whether peer is synced. + pub is_synced: bool, /// DEPRECATED. Chain-specific status. pub chain_status: Vec, } @@ -178,6 +182,7 @@ pub mod generic { best_number, best_hash, genesis_hash, + is_synced, } = compact; Ok(Self { @@ -187,6 +192,7 @@ pub mod generic { best_number, best_hash, genesis_hash, + is_synced, chain_status, }) } diff --git a/substrate/client/network/sync/src/engine.rs b/substrate/client/network/sync/src/engine.rs index 05084a531518..8bf396fa0e42 100644 --- a/substrate/client/network/sync/src/engine.rs +++ b/substrate/client/network/sync/src/engine.rs @@ -226,6 +226,11 @@ pub struct SyncingEngine { /// Are we actively catching up with the chain? is_major_syncing: Arc, + /// Parameter that allows node to forcefully assume it is synced, needed for network + /// bootstrapping only, as long as two synced nodes remain on the network at any time, this + /// doesn't need to be used. + force_synced: bool, + /// Network service. network_service: service::network::NetworkServiceHandle, @@ -346,6 +351,7 @@ where state_request_protocol_name: ProtocolName, warp_sync_protocol_name: Option, peer_store_handle: PeerStoreHandle, + force_synced: bool, ) -> Result<(Self, SyncingService, NonDefaultSetConfig), ClientError> { let mode = net_config.network_config.sync_mode; let pause_sync = Arc::clone(&net_config.network_config.pause_sync); @@ -427,6 +433,7 @@ where .ok() .flatten() .expect("Genesis block exists; qed"), + force_synced, ); // Split warp sync params into warp sync config and a channel to retreive target block @@ -483,6 +490,7 @@ where ), num_connected: num_connected.clone(), is_major_syncing: is_major_syncing.clone(), + force_synced: net_config.network_config.force_synced, service_rx, genesis_hash, important_peers, @@ -522,6 +530,15 @@ where )) } + fn is_synced(&self) -> bool { + if self.force_synced { + return true + } + + !self.is_major_syncing.load(Ordering::Relaxed) && + self.peers.iter().any(|(_peer_id, peer)| peer.info.is_synced) + } + /// Report Prometheus metrics. pub fn report_metrics(&self) { if let Some(metrics) = &self.metrics { @@ -536,10 +553,12 @@ where peer_id: &PeerId, best_hash: B::Hash, best_number: NumberFor, + is_synced: bool, ) { if let Some(ref mut peer) = self.peers.get_mut(peer_id) { peer.info.best_hash = best_hash; peer.info.best_number = best_number; + peer.info.is_synced = is_synced; } } @@ -551,10 +570,10 @@ where match validation_result { BlockAnnounceValidationResult::Skip { peer_id: _ } => {}, BlockAnnounceValidationResult::Process { is_new_best, peer_id, announce } => { - if let Some((best_hash, best_number)) = + if let Some((best_hash, best_number, is_synced)) = self.strategy.on_validated_block_announce(is_new_best, peer_id, &announce) { - self.update_peer_info(&peer_id, best_hash, best_number); + self.update_peer_info(&peer_id, best_hash, best_number, is_synced); } if let Some(data) = announce.data { @@ -628,6 +647,7 @@ where return } + let is_synced = self.is_synced(); let is_best = self.client.info().best_hash == hash; log::debug!(target: LOG_TARGET, "Reannouncing block {hash:?} is_best: {is_best}"); @@ -641,6 +661,7 @@ where log::trace!(target: LOG_TARGET, "Announcing block {hash:?} to {peer_id}"); let message = BlockAnnounce { header: header.clone(), + is_synced, state: if is_best { Some(BlockState::Best) } else { Some(BlockState::Normal) }, data: Some(data.clone()), }; @@ -761,6 +782,7 @@ where *peer_id, peer.info.best_hash, peer.info.best_number, + peer.info.is_synced, )) }); self.strategy.switch_to_next( @@ -849,6 +871,7 @@ where number, hash, self.genesis_hash, + self.is_synced(), ) .encode(), ); @@ -1140,6 +1163,7 @@ where roles: status.roles, best_hash: status.best_hash, best_number: status.best_number, + is_synced: status.is_synced, }, known_blocks: LruHashSet::new( NonZeroUsize::new(MAX_KNOWN_BLOCKS).expect("Constant is nonzero"), @@ -1149,7 +1173,12 @@ where // Only forward full peers to syncing strategy. if status.roles.is_full() { - self.strategy.add_peer(peer_id, peer.info.best_hash, peer.info.best_number); + self.strategy.add_peer( + peer_id, + peer.info.best_hash, + peer.info.best_number, + peer.info.is_synced, + ); } log::debug!(target: LOG_TARGET, "Connected {peer_id}"); @@ -1383,6 +1412,7 @@ where best_number: NumberFor, best_hash: B::Hash, genesis_hash: B::Hash, + force_synced: bool, ) -> (NonDefaultSetConfig, Box) { let block_announces_protocol = { let genesis_hash = genesis_hash.as_ref(); @@ -1406,6 +1436,7 @@ where best_number, best_hash, genesis_hash, + force_synced, ))), // NOTE: `set_config` will be ignored by `protocol.rs` as the block announcement // protocol is still hardcoded into the peerset. diff --git a/substrate/client/network/sync/src/extra_requests.rs b/substrate/client/network/sync/src/extra_requests.rs index cd3008d270b1..bf350384d684 100644 --- a/substrate/client/network/sync/src/extra_requests.rs +++ b/substrate/client/network/sync/src/extra_requests.rs @@ -564,6 +564,7 @@ mod tests { best_hash: Hash::random(), best_number: u64::arbitrary(g), state: ArbitraryPeerSyncState::arbitrary(g).0, + is_synced: bool::arbitrary(g), }; ArbitraryPeerSync(ps) } diff --git a/substrate/client/network/sync/src/strategy.rs b/substrate/client/network/sync/src/strategy.rs index 5f19193ff472..2bc3a08bd6c4 100644 --- a/substrate/client/network/sync/src/strategy.rs +++ b/substrate/client/network/sync/src/strategy.rs @@ -139,14 +139,20 @@ where } /// Notify that a new peer has connected. - pub fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { + pub fn add_peer( + &mut self, + peer_id: PeerId, + best_hash: B::Hash, + best_number: NumberFor, + is_synced: bool, + ) { match self { SyncingStrategy::WarpSyncStrategy(strategy) => strategy.add_peer(peer_id, best_hash, best_number), SyncingStrategy::StateSyncStrategy(strategy) => strategy.add_peer(peer_id, best_hash, best_number), SyncingStrategy::ChainSyncStrategy(strategy) => - strategy.add_peer(peer_id, best_hash, best_number), + strategy.add_peer(peer_id, best_hash, best_number, is_synced), } } @@ -167,7 +173,7 @@ where is_best: bool, peer_id: PeerId, announce: &BlockAnnounce, - ) -> Option<(B::Hash, NumberFor)> { + ) -> Option<(B::Hash, NumberFor, bool)> { match self { SyncingStrategy::WarpSyncStrategy(strategy) => strategy.on_validated_block_announce(is_best, peer_id, announce), @@ -404,7 +410,7 @@ where &mut self, config: SyncingConfig, client: Arc, - connected_peers: impl Iterator)>, + connected_peers: impl Iterator, bool)>, ) -> Result<(), ClientError> { match self { Self::WarpSyncStrategy(warp_sync) => { @@ -421,8 +427,11 @@ where res.target_justifications, // skip proofs, only set to `true` in `FastUnsafe` sync mode false, - connected_peers - .map(|(peer_id, _best_hash, best_number)| (peer_id, best_number)), + connected_peers.map( + |(peer_id, _best_hash, best_number, _is_synced)| { + (peer_id, best_number) + }, + ), ); *self = Self::StateSyncStrategy(state_sync); @@ -448,8 +457,8 @@ where }; // Let `ChainSync` know about connected peers. connected_peers.into_iter().for_each( - |(peer_id, best_hash, best_number)| { - chain_sync.add_peer(peer_id, best_hash, best_number) + |(peer_id, best_hash, best_number, is_synced)| { + chain_sync.add_peer(peer_id, best_hash, best_number, is_synced) }, ); @@ -478,9 +487,11 @@ where }, }; // Let `ChainSync` know about connected peers. - connected_peers.into_iter().for_each(|(peer_id, best_hash, best_number)| { - chain_sync.add_peer(peer_id, best_hash, best_number) - }); + connected_peers.into_iter().for_each( + |(peer_id, best_hash, best_number, is_synced)| { + chain_sync.add_peer(peer_id, best_hash, best_number, is_synced) + }, + ); *self = Self::ChainSyncStrategy(chain_sync); }, diff --git a/substrate/client/network/sync/src/strategy/chain_sync.rs b/substrate/client/network/sync/src/strategy/chain_sync.rs index 744f4eafa853..2df5f5046667 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync.rs @@ -306,6 +306,8 @@ pub(crate) struct PeerSync { /// The state of syncing this peer is in for us, generally categories /// into `Available` or "busy" with something as defined by `PeerSyncState`. pub state: PeerSyncState, + /// Whether peer is synced. + pub is_synced: bool, } impl PeerSync { @@ -435,6 +437,9 @@ where } else { SyncState::Idle } + } else if self.peers.len() > 0 { + // There are known peers, but none of them are synced + SyncState::Pending } else { SyncState::Idle }; @@ -474,8 +479,14 @@ where } /// Notify syncing state machine that a new sync peer has connected. - pub fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor) { - match self.add_peer_inner(peer_id, best_hash, best_number) { + pub fn add_peer( + &mut self, + peer_id: PeerId, + best_hash: B::Hash, + best_number: NumberFor, + is_synced: bool, + ) { + match self.add_peer_inner(peer_id, best_hash, best_number, is_synced) { Ok(Some(request)) => self.actions.push(ChainSyncAction::SendBlockRequest { peer_id, request }), Ok(None) => {}, @@ -489,6 +500,7 @@ where peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor, + is_synced: bool, ) -> Result>, BadPeer> { // There is nothing sync can get from the node that has no blockchain data. match self.block_status(&best_hash) { @@ -530,6 +542,7 @@ where best_hash, best_number, state: PeerSyncState::Available, + is_synced, }, ); return Ok(None) @@ -573,6 +586,7 @@ where best_hash, best_number, state, + is_synced, }, ); @@ -593,6 +607,7 @@ where best_hash, best_number, state: PeerSyncState::Available, + is_synced, }, ); self.allowed_requests.add(&peer_id); @@ -1053,9 +1068,10 @@ where is_best: bool, peer_id: PeerId, announce: &BlockAnnounce, - ) -> Option<(B::Hash, NumberFor)> { + ) -> Option<(B::Hash, NumberFor, bool)> { let number = *announce.header.number(); let hash = announce.header.hash(); + let is_synced = announce.is_synced; let parent_status = self.block_status(announce.header.parent_hash()).unwrap_or(BlockStatus::Unknown); let known_parent = parent_status != BlockStatus::Unknown; @@ -1066,7 +1082,7 @@ where peer } else { error!(target: LOG_TARGET, "💔 Called `on_validated_block_announce` with a bad peer ID"); - return Some((hash, number)) + return Some((hash, number, is_synced)) }; if let PeerSyncState::AncestorSearch { .. } = peer.state { @@ -1078,8 +1094,12 @@ where // update their best block peer.best_number = number; peer.best_hash = hash; + // Do not update synced status back to not synced. Announcements only happen + // occasionally and it is unlikely that actively connected peer will become not synced + // after being synced previously anyway. + peer.is_synced = peer.is_synced || is_synced; - (hash, number) + (hash, number, peer.is_synced) }); // If the announced block is the best they have and is not ahead of us, our common number @@ -1190,7 +1210,11 @@ where /// Returns the median seen block number. fn median_seen(&self) -> Option> { - let mut best_seens = self.peers.values().map(|p| p.best_number).collect::>(); + let mut best_seens = self + .peers + .values() + .filter_map(|p| p.is_synced.then_some(p.best_number)) + .collect::>(); if best_seens.is_empty() { None @@ -1337,7 +1361,8 @@ where } // handle peers that were in other states. - let action = match self.add_peer_inner(peer_id, p.best_hash, p.best_number) { + let action = match self.add_peer_inner(peer_id, p.best_hash, p.best_number, p.is_synced) + { // since the request is not a justification, remove it from pending responses Ok(None) => ChainSyncAction::CancelBlockRequest { peer_id }, // update the request if the new one is available diff --git a/substrate/client/network/sync/src/strategy/chain_sync/test.rs b/substrate/client/network/sync/src/strategy/chain_sync/test.rs index ead3d8d3c599..3eaf9379f91b 100644 --- a/substrate/client/network/sync/src/strategy/chain_sync/test.rs +++ b/substrate/client/network/sync/src/strategy/chain_sync/test.rs @@ -55,7 +55,7 @@ fn processes_empty_response_on_justification_request_for_unknown_block() { }; // add a new peer with the same best block - sync.add_peer(peer_id, a1_hash, a1_number); + sync.add_peer(peer_id, a1_hash, a1_number, true); // and request a justification for the block sync.request_justification(&a1_hash, a1_number); @@ -121,8 +121,8 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { let (b1_hash, b1_number) = new_blocks(50); // add 2 peers at blocks that we don't have locally - sync.add_peer(peer_id1, Hash::random(), 42); - sync.add_peer(peer_id2, Hash::random(), 10); + sync.add_peer(peer_id1, Hash::random(), 42, true); + sync.add_peer(peer_id2, Hash::random(), 10, true); // we wil send block requests to these peers // for these blocks we don't know about @@ -132,7 +132,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { .all(|(p, _)| { p == peer_id1 || p == peer_id2 })); // add a new peer at a known block - sync.add_peer(peer_id3, b1_hash, b1_number); + sync.add_peer(peer_id3, b1_hash, b1_number, true); // we request a justification for a block we have locally sync.request_justification(&b1_hash, b1_number); @@ -181,6 +181,7 @@ fn restart_doesnt_affect_peers_downloading_finality_data() { fn send_block_announce(header: Header, peer_id: PeerId, sync: &mut ChainSync) { let announce = BlockAnnounce { header: header.clone(), + is_synced: true, state: Some(BlockState::Best), data: Some(Vec::new()), }; @@ -289,8 +290,8 @@ fn do_ancestor_search_when_common_block_to_best_qeued_gap_is_to_big() { let best_block = blocks.last().unwrap().clone(); let max_blocks_to_request = sync.max_blocks_per_request; // Connect the node we will sync from - sync.add_peer(peer_id1, best_block.hash(), *best_block.header().number()); - sync.add_peer(peer_id2, info.best_hash, 0); + sync.add_peer(peer_id1, best_block.hash(), *best_block.header().number(), true); + sync.add_peer(peer_id2, info.best_hash, 0, true); let mut best_block_num = 0; while best_block_num < MAX_DOWNLOAD_AHEAD { @@ -440,7 +441,7 @@ fn can_sync_huge_fork() { let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); // Connect the node we will sync from - sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number()); + sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number(), true); send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); @@ -575,7 +576,7 @@ fn syncs_fork_without_duplicate_requests() { let common_block = blocks[MAX_BLOCKS_TO_LOOK_BACKWARDS as usize / 2].clone(); // Connect the node we will sync from - sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number()); + sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number(), true); send_block_announce(fork_blocks.last().unwrap().header().clone(), peer_id1, &mut sync); @@ -706,7 +707,7 @@ fn removes_target_fork_on_disconnect() { let peer_id1 = PeerId::random(); let common_block = blocks[1].clone(); // Connect the node we will sync from - sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number()); + sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number(), true); // Create a "new" header and announce it let mut header = blocks[0].header().clone(); @@ -732,7 +733,7 @@ fn can_import_response_with_missing_blocks() { let peer_id1 = PeerId::random(); let best_block = blocks[3].clone(); - sync.add_peer(peer_id1, best_block.hash(), *best_block.header().number()); + sync.add_peer(peer_id1, best_block.hash(), *best_block.header().number(), true); sync.peers.get_mut(&peer_id1).unwrap().state = PeerSyncState::Available; sync.peers.get_mut(&peer_id1).unwrap().common_number = 0; @@ -785,7 +786,7 @@ fn sync_restart_removes_block_but_not_justification_requests() { let (b1_hash, b1_number) = new_blocks(50); // add new peer and request blocks from them - sync.add_peer(peers[0], Hash::random(), 42); + sync.add_peer(peers[0], Hash::random(), 42, true); // we don't actually perform any requests, just keep track of peers waiting for a response let mut pending_responses = HashSet::new(); @@ -798,7 +799,7 @@ fn sync_restart_removes_block_but_not_justification_requests() { } // add a new peer at a known block - sync.add_peer(peers[1], b1_hash, b1_number); + sync.add_peer(peers[1], b1_hash, b1_number, true); // we request a justification for a block we have locally sync.request_justification(&b1_hash, b1_number); @@ -910,9 +911,9 @@ fn request_across_forks() { // Add the peers, all at the common ancestor 100. let common_block = blocks.last().unwrap(); let peer_id1 = PeerId::random(); - sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number()); + sync.add_peer(peer_id1, common_block.hash(), *common_block.header().number(), true); let peer_id2 = PeerId::random(); - sync.add_peer(peer_id2, common_block.hash(), *common_block.header().number()); + sync.add_peer(peer_id2, common_block.hash(), *common_block.header().number(), true); // Peer 1 announces 107 from fork 1, 100-107 get downloaded. { diff --git a/substrate/client/network/sync/src/strategy/state.rs b/substrate/client/network/sync/src/strategy/state.rs index ae3f7b600559..8e1450d75470 100644 --- a/substrate/client/network/sync/src/strategy/state.rs +++ b/substrate/client/network/sync/src/strategy/state.rs @@ -152,15 +152,16 @@ impl StateStrategy { is_best: bool, peer_id: PeerId, announce: &BlockAnnounce, - ) -> Option<(B::Hash, NumberFor)> { + ) -> Option<(B::Hash, NumberFor, bool)> { is_best.then_some({ let best_number = *announce.header.number(); let best_hash = announce.header.hash(); + let is_synced = announce.is_synced; if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { peer.best_number = best_number; } // Let `SyncingEngine` know that we should update the peer info. - (best_hash, best_number) + (best_hash, best_number, is_synced) }) } diff --git a/substrate/client/network/sync/src/strategy/warp.rs b/substrate/client/network/sync/src/strategy/warp.rs index 7935b5f29b68..cf9105bfb6ca 100644 --- a/substrate/client/network/sync/src/strategy/warp.rs +++ b/substrate/client/network/sync/src/strategy/warp.rs @@ -321,15 +321,16 @@ where is_best: bool, peer_id: PeerId, announce: &BlockAnnounce, - ) -> Option<(B::Hash, NumberFor)> { + ) -> Option<(B::Hash, NumberFor, bool)> { is_best.then_some({ let best_number = *announce.header.number(); let best_hash = announce.header.hash(); + let is_synced = announce.is_synced; if let Some(ref mut peer) = self.peers.get_mut(&peer_id) { peer.best_number = best_number; } // Let `SyncingEngine` know that we should update the peer info. - (best_hash, best_number) + (best_hash, best_number, is_synced) }) } diff --git a/substrate/client/network/sync/src/types.rs b/substrate/client/network/sync/src/types.rs index 4074b33eee1a..f4f143030707 100644 --- a/substrate/client/network/sync/src/types.rs +++ b/substrate/client/network/sync/src/types.rs @@ -36,6 +36,8 @@ pub struct PeerInfo { pub best_hash: Block::Hash, /// Their best block number. pub best_number: NumberFor, + /// Whether peer is synced. + pub is_synced: bool, } /// Info about a peer's known state (both full and light). @@ -47,11 +49,15 @@ pub struct ExtendedPeerInfo { pub best_hash: B::Hash, /// Peer best block number pub best_number: NumberFor, + /// Whether peer is synced. + pub is_synced: bool, } /// Reported sync state. #[derive(Clone, Eq, PartialEq, Debug)] pub enum SyncState { + /// Sync state can't be identified due to no known synced peers. + Pending, /// Initial sync is complete, keep-up sync is active. Idle, /// Actively catching up with the chain. diff --git a/substrate/client/network/test/src/lib.rs b/substrate/client/network/test/src/lib.rs index aeed2985ace4..120e26467401 100644 --- a/substrate/client/network/test/src/lib.rs +++ b/substrate/client/network/test/src/lib.rs @@ -906,6 +906,7 @@ pub trait TestNetFactory: Default + Sized + Send { state_request_protocol_config.name.clone(), Some(warp_protocol_config.name.clone()), peer_store_handle.clone(), + true, ) .unwrap(); let sync_service_import_queue = Box::new(sync_service.clone()); diff --git a/substrate/client/network/test/src/service.rs b/substrate/client/network/test/src/service.rs index 800c0d4369c2..54bd7be4ade4 100644 --- a/substrate/client/network/test/src/service.rs +++ b/substrate/client/network/test/src/service.rs @@ -205,6 +205,7 @@ impl TestNetworkBuilder { state_request_protocol_config.name.clone(), None, peer_store_handle.clone(), + true, ) .unwrap(); let mut link = self.link.unwrap_or(Box::new(chain_sync_service.clone())); diff --git a/substrate/client/service/src/builder.rs b/substrate/client/service/src/builder.rs index 0b8c86be92b5..8643ee0a3885 100644 --- a/substrate/client/service/src/builder.rs +++ b/substrate/client/service/src/builder.rs @@ -903,6 +903,7 @@ where state_request_protocol_name, warp_request_protocol_name, peer_store_handle.clone(), + config.network.force_synced, )?; let sync_service_import_queue = sync_service.clone(); let sync_service = Arc::new(sync_service);