referrerpolicy=no-referrer-when-downgrade

sc_network_sync/strategy/
chain_sync.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! Contains the state of the chain synchronization process
20//!
21//! At any given point in time, a running node tries as much as possible to be at the head of the
22//! chain. This module handles the logic of which blocks to request from remotes, and processing
23//! responses. It yields blocks to check and potentially move to the database.
24//!
25//! # Usage
26//!
27//! The `ChainSync` struct maintains the state of the block requests. Whenever something happens on
28//! the network, or whenever a block has been successfully verified, call the appropriate method in
29//! order to update it.
30
31use crate::{
32	block_relay_protocol::{BlockDownloader, BlockResponseError},
33	blocks::{BlockCollection, Metrics as BlockCollectionMetrics},
34	justification_requests::ExtraRequests,
35	schema::v1::{StateRequest, StateResponse},
36	service::network::NetworkServiceHandle,
37	strategy::{
38		disconnected_peers::DisconnectedPeers,
39		state_sync::{ImportResult, StateSync, StateSyncProvider},
40		warp::{WarpSyncPhase, WarpSyncProgress},
41		StrategyKey, SyncingAction, SyncingStrategy,
42	},
43	types::{BadPeer, SyncState, SyncStatus},
44	LOG_TARGET,
45};
46
47use codec::Encode;
48use futures::{channel::oneshot, FutureExt};
49use log::{debug, error, info, trace, warn};
50use prometheus_endpoint::{register, Counter, Gauge, PrometheusError, Registry, U64};
51use prost::Message;
52use sc_client_api::{blockchain::BlockGap, BlockBackend, ProofProvider};
53use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock};
54use sc_network::{IfDisconnected, ProtocolName};
55use sc_network_common::sync::message::{
56	BlockAnnounce, BlockAttributes, BlockData, BlockRequest, BlockResponse, Direction, FromBlock,
57};
58use sc_network_types::PeerId;
59use sp_arithmetic::traits::Saturating;
60use sp_blockchain::{Error as ClientError, HeaderBackend, HeaderMetadata};
61use sp_consensus::{BlockOrigin, BlockStatus};
62use sp_runtime::{
63	traits::{
64		Block as BlockT, CheckedSub, Header as HeaderT, NumberFor, One, SaturatedConversion, Zero,
65	},
66	EncodedJustification, Justifications,
67};
68
69use std::{
70	any::Any,
71	collections::{HashMap, HashSet},
72	fmt,
73	ops::{AddAssign, Range},
74	sync::Arc,
75};
76
77#[cfg(test)]
78mod test;
79
80/// Maximum blocks to store in the import queue.
81const MAX_IMPORTING_BLOCKS: usize = 2048;
82
83/// Maximum blocks to download ahead of any gap.
84const MAX_DOWNLOAD_AHEAD: u32 = 2048;
85
86/// Maximum blocks to look backwards. The gap is the difference between the highest block and the
87/// common block of a node.
88const MAX_BLOCKS_TO_LOOK_BACKWARDS: u32 = MAX_DOWNLOAD_AHEAD / 2;
89
90/// Pick the state to sync as the latest finalized number minus this.
91const STATE_SYNC_FINALITY_THRESHOLD: u32 = 8;
92
93/// We use a heuristic that with a high likelihood, by the time
94/// `MAJOR_SYNC_BLOCKS` have been imported we'll be on the same
95/// chain as (or at least closer to) the peer so we want to delay
96/// the ancestor search to not waste time doing that when we are
97/// so far behind.
98const MAJOR_SYNC_BLOCKS: u8 = 5;
99
100mod rep {
101	use sc_network::ReputationChange as Rep;
102	/// Reputation change when a peer sent us a message that led to a
103	/// database read error.
104	pub const BLOCKCHAIN_READ_ERROR: Rep = Rep::new(-(1 << 16), "DB Error");
105
106	/// Reputation change when a peer sent us a status message with a different
107	/// genesis than us.
108	pub const GENESIS_MISMATCH: Rep = Rep::new(i32::MIN, "Genesis mismatch");
109
110	/// Reputation change for peers which send us a block with an incomplete header.
111	pub const INCOMPLETE_HEADER: Rep = Rep::new(-(1 << 20), "Incomplete header");
112
113	/// Reputation change for peers which send us a block which we fail to verify.
114	pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 29), "Block verification failed");
115
116	/// Reputation change for peers which send us a known bad block.
117	pub const BAD_BLOCK: Rep = Rep::new(-(1 << 29), "Bad block");
118
119	/// Peer did not provide us with advertised block data.
120	pub const NO_BLOCK: Rep = Rep::new(-(1 << 29), "No requested block data");
121
122	/// Reputation change for peers which send us non-requested block data.
123	pub const NOT_REQUESTED: Rep = Rep::new(-(1 << 29), "Not requested block data");
124
125	/// Peer could not serve any body of a gap sync request that required them.
126	/// Mild, since the peer may still be backfilling its own block history.
127	pub const NO_GAP_BODIES: Rep = Rep::new(-(1 << 26), "No gap sync bodies");
128
129	/// Reputation change for peers which send us a block with bad justifications.
130	pub const BAD_JUSTIFICATION: Rep = Rep::new(-(1 << 16), "Bad justification");
131
132	/// Reputation change when a peer sent us invalid ancestry result.
133	pub const UNKNOWN_ANCESTOR: Rep = Rep::new(-(1 << 16), "DB Error");
134
135	/// Peer response data does not have requested bits.
136	pub const BAD_RESPONSE: Rep = Rep::new(-(1 << 12), "Incomplete response");
137
138	/// We received a message that failed to decode.
139	pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message");
140}
141
142struct Metrics {
143	queued_blocks: Gauge<U64>,
144	fork_targets: Gauge<U64>,
145	block_collection: BlockCollectionMetrics,
146	gap_body_empty_responses: Counter<U64>,
147	gap_header_only_downgrades: Counter<U64>,
148	gap_oldest_required_body: Gauge<U64>,
149}
150
151impl Metrics {
152	fn register(r: &Registry) -> Result<Self, PrometheusError> {
153		Ok(Self {
154			queued_blocks: {
155				let g =
156					Gauge::new("substrate_sync_queued_blocks", "Number of blocks in import queue")?;
157				register(g, r)?
158			},
159			fork_targets: {
160				let g = Gauge::new("substrate_sync_fork_targets", "Number of fork sync targets")?;
161				register(g, r)?
162			},
163			block_collection: BlockCollectionMetrics::register(r)?,
164			gap_body_empty_responses: {
165				let c = Counter::new(
166					"substrate_sync_gap_body_empty_responses_total",
167					"Number of empty responses to gap sync requests that required bodies; \
168					 each drops the responding peer",
169				)?;
170				register(c, r)?
171			},
172			gap_header_only_downgrades: {
173				let c = Counter::new(
174					"substrate_sync_gap_header_only_downgrades_total",
175					"Number of gap sync requests issued header-only because the moving body \
176					 cutoff passed the range",
177				)?;
178				register(c, r)?
179			},
180			gap_oldest_required_body: {
181				let g = Gauge::new(
182					"substrate_sync_gap_oldest_required_body",
183					"Oldest block number for which gap sync still requires a body; \
184					 0 when gap sync is inactive or bodies are not required",
185				)?;
186				register(g, r)?
187			},
188		})
189	}
190}
191
192#[derive(Debug, Clone)]
193enum AllowedRequests {
194	Some(HashSet<PeerId>),
195	All,
196}
197
198impl AllowedRequests {
199	fn add(&mut self, id: &PeerId) {
200		if let Self::Some(ref mut set) = self {
201			set.insert(*id);
202		}
203	}
204
205	fn take(&mut self) -> Self {
206		std::mem::take(self)
207	}
208
209	fn set_all(&mut self) {
210		*self = Self::All;
211	}
212
213	fn contains(&self, id: &PeerId) -> bool {
214		match self {
215			Self::Some(set) => set.contains(id),
216			Self::All => true,
217		}
218	}
219
220	fn is_empty(&self) -> bool {
221		match self {
222			Self::Some(set) => set.is_empty(),
223			Self::All => false,
224		}
225	}
226
227	fn clear(&mut self) {
228		std::mem::take(self);
229	}
230}
231
232impl Default for AllowedRequests {
233	fn default() -> Self {
234		Self::Some(HashSet::default())
235	}
236}
237
238/// Statistics for gap sync operations.
239#[derive(Debug, Default, Clone)]
240struct GapSyncStats {
241	/// Size of headers downloaded during gap sync
242	header_bytes: usize,
243	/// Size of bodies downloaded during gap sync
244	body_bytes: usize,
245	/// Size of justifications downloaded during gap sync
246	justification_bytes: usize,
247}
248
249impl GapSyncStats {
250	fn new() -> Self {
251		Self::default()
252	}
253
254	fn total_bytes(&self) -> usize {
255		self.header_bytes + self.body_bytes + self.justification_bytes
256	}
257
258	fn bytes_to_mib(bytes: usize) -> f64 {
259		bytes as f64 / (1024.0 * 1024.0)
260	}
261}
262
263impl fmt::Display for GapSyncStats {
264	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265		let total = self.total_bytes();
266		write!(
267			f,
268			"hdr: {} B ({:.2} MiB), body: {} B ({:.2} MiB), just: {} B ({:.2} MiB) | total: {} B ({:.2} MiB)",
269			self.header_bytes,
270			Self::bytes_to_mib(self.header_bytes),
271			self.body_bytes,
272			Self::bytes_to_mib(self.body_bytes),
273			self.justification_bytes,
274			Self::bytes_to_mib(self.justification_bytes),
275			total,
276			Self::bytes_to_mib(total),
277		)
278	}
279}
280
281impl AddAssign for GapSyncStats {
282	fn add_assign(&mut self, other: Self) {
283		self.header_bytes += other.header_bytes;
284		self.body_bytes += other.body_bytes;
285		self.justification_bytes += other.justification_bytes;
286	}
287}
288
289struct GapSync<B: BlockT> {
290	blocks: BlockCollection<B>,
291	best_queued_number: NumberFor<B>,
292	target: NumberFor<B>,
293	stats: GapSyncStats,
294}
295
296/// Sync operation mode.
297#[derive(Copy, Clone, Debug, Eq, PartialEq)]
298pub enum ChainSyncMode {
299	/// Full block download and verification.
300	Full,
301	/// Download blocks and the latest state.
302	LightState {
303		/// Skip state proof download and verification.
304		skip_proofs: bool,
305	},
306}
307
308/// Returns the base block attributes required for chain sync.
309fn required_block_attributes() -> BlockAttributes {
310	BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION | BlockAttributes::BODY
311}
312
313/// Which block bodies gap sync downloads while backfilling the block history below a
314/// warp-synced block.
315#[derive(Copy, Clone, Debug, Eq, PartialEq)]
316pub enum GapSyncBodyPolicy {
317	/// Backfill gap headers and justifications without bodies.
318	HeadersOnly,
319	/// Require bodies for the complete gap.
320	All,
321	/// Require bodies for blocks within the given window below the finalized block.
322	/// The window is expected to be pre-shrunk by the node with a safety margin, so
323	/// that peers whose finality runs ahead of ours still retain every requested body.
324	///
325	/// While the node is major syncing, local finality can lag the network beyond the
326	/// safety margin, so gap ranges above the cutoff are deferred until it has caught up.
327	BodiesWithinWindow(u32),
328}
329
330/// Resolves the [`GapSyncBodyPolicy`] lazily, when a `ChainSync` instance is created.
331///
332/// On a warp-syncing node this happens right after state sync completes, so the
333/// provider can query runtime state at the warp target. Errors fail `ChainSync`
334/// creation instead of silently degrading the policy.
335pub type GapSyncBodyPolicyProvider =
336	Arc<dyn Fn() -> Result<GapSyncBodyPolicy, ClientError> + Send + Sync>;
337
338/// All the data we have about a Peer that we are trying to sync with
339#[derive(Debug, Clone)]
340pub(crate) struct PeerSync<B: BlockT> {
341	/// Peer id of this peer.
342	pub peer_id: PeerId,
343	/// The common number is the block number that is a common point of
344	/// ancestry for both our chains (as far as we know).
345	pub common_number: NumberFor<B>,
346	/// The hash of the best block that we've seen for this peer.
347	pub best_hash: B::Hash,
348	/// The number of the best block that we've seen for this peer.
349	pub best_number: NumberFor<B>,
350	/// The state of syncing this peer is in for us, generally categories
351	/// into `Available` or "busy" with something as defined by `PeerSyncState`.
352	pub state: PeerSyncState<B>,
353}
354
355impl<B: BlockT> PeerSync<B> {
356	/// Update the `common_number` iff `new_common > common_number`.
357	fn update_common_number(&mut self, new_common: NumberFor<B>) {
358		if self.common_number < new_common {
359			trace!(
360				target: LOG_TARGET,
361				"Updating peer {} common number from={} => to={}.",
362				self.peer_id,
363				self.common_number,
364				new_common,
365			);
366			self.common_number = new_common;
367		}
368	}
369}
370
371struct ForkTarget<B: BlockT> {
372	number: NumberFor<B>,
373	parent_hash: Option<B::Hash>,
374	peers: HashSet<PeerId>,
375}
376
377/// The state of syncing between a Peer and ourselves.
378///
379/// Generally two categories, "busy" or `Available`. If busy, the enum
380/// defines what we are busy with.
381#[derive(Copy, Clone, Eq, PartialEq, Debug)]
382pub(crate) enum PeerSyncState<B: BlockT> {
383	/// Available for sync requests.
384	Available,
385	/// Searching for ancestors the Peer has in common with us.
386	AncestorSearch {
387		/// The best queued number when starting the ancestor search.
388		start: NumberFor<B>,
389		/// The current block that is being downloaded.
390		current: NumberFor<B>,
391		/// The state of the search.
392		state: AncestorSearchState<B>,
393	},
394	/// Actively downloading new blocks, starting from the given Number.
395	DownloadingNew(NumberFor<B>),
396	/// Downloading a stale block with given Hash. Stale means that it is a
397	/// block with a number that is lower than our best number. It might be
398	/// from a fork and not necessarily already imported.
399	DownloadingStale(B::Hash),
400	/// Downloading justification for given block hash.
401	DownloadingJustification(B::Hash),
402	/// Downloading state.
403	DownloadingState,
404	/// Actively downloading block history after warp sync.
405	DownloadingGap(NumberFor<B>),
406}
407
408impl<B: BlockT> PeerSyncState<B> {
409	pub fn is_available(&self) -> bool {
410		matches!(self, Self::Available)
411	}
412}
413
414/// The main data structure which contains all the state for a chains
415/// active syncing strategy.
416pub struct ChainSync<B: BlockT, Client> {
417	/// Chain client.
418	client: Arc<Client>,
419	/// The active peers that we are using to sync and their PeerSync status
420	peers: HashMap<PeerId, PeerSync<B>>,
421	disconnected_peers: DisconnectedPeers,
422	/// A `BlockCollection` of blocks that are being downloaded from peers
423	blocks: BlockCollection<B>,
424	/// The best block number in our queue of blocks to import
425	best_queued_number: NumberFor<B>,
426	/// The best block hash in our queue of blocks to import
427	best_queued_hash: B::Hash,
428	/// Current mode (full/light)
429	mode: ChainSyncMode,
430	/// Any extra justification requests.
431	extra_justifications: ExtraRequests<B>,
432	/// A set of hashes of blocks that are being downloaded or have been
433	/// downloaded and are queued for import.
434	queue_blocks: HashSet<B::Hash>,
435	/// A pending attempt to start the state sync.
436	///
437	/// The initiation of state sync may be deferred in cases where other conditions
438	/// are not yet met when the finalized block notification is received, such as
439	/// when `queue_blocks` is not empty or there are no peers. This field holds the
440	/// necessary information to attempt the state sync at a later point when
441	/// conditions are satisfied.
442	pending_state_sync_attempt: Option<(B::Hash, NumberFor<B>, bool)>,
443	/// Fork sync targets.
444	fork_targets: HashMap<B::Hash, ForkTarget<B>>,
445	/// A set of peers for which there might be potential block requests
446	allowed_requests: AllowedRequests,
447	/// Maximum number of peers to ask the same blocks in parallel.
448	max_parallel_downloads: u32,
449	/// Maximum blocks per request.
450	max_blocks_per_request: u32,
451	/// Protocol name used to send out state requests
452	state_request_protocol_name: ProtocolName,
453	/// Total number of downloaded blocks.
454	downloaded_blocks: usize,
455	/// State sync in progress, if any.
456	state_sync: Option<StateSync<B, Client>>,
457	/// Enable importing existing blocks. This is used after the state download to
458	/// catch up to the latest state while re-importing blocks.
459	import_existing: bool,
460	/// Block downloader
461	block_downloader: Arc<dyn BlockDownloader<B>>,
462	/// Which block bodies gap sync downloads.
463	gap_sync_body_policy: GapSyncBodyPolicy,
464	/// Gap download process.
465	gap_sync: Option<GapSync<B>>,
466	/// Pending actions.
467	actions: Vec<SyncingAction<B>>,
468	/// Prometheus metrics.
469	metrics: Option<Metrics>,
470}
471
472impl<B, Client> SyncingStrategy<B> for ChainSync<B, Client>
473where
474	B: BlockT,
475	Client: HeaderBackend<B>
476		+ BlockBackend<B>
477		+ HeaderMetadata<B, Error = sp_blockchain::Error>
478		+ ProofProvider<B>
479		+ Send
480		+ Sync
481		+ 'static,
482{
483	fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor<B>) {
484		match self.add_peer_inner(peer_id, best_hash, best_number) {
485			Ok(Some(request)) => {
486				let action = self.create_block_request_action(peer_id, request);
487				self.actions.push(action);
488			},
489			Ok(None) => {},
490			Err(bad_peer) => self.actions.push(SyncingAction::DropPeer(bad_peer)),
491		}
492	}
493
494	fn remove_peer(&mut self, peer_id: &PeerId) {
495		self.blocks.clear_peer_download(peer_id);
496		if let Some(gap_sync) = &mut self.gap_sync {
497			gap_sync.blocks.clear_peer_download(peer_id)
498		}
499
500		if let Some(state) = self.peers.remove(peer_id) {
501			if !state.state.is_available() {
502				if let Some(bad_peer) =
503					self.disconnected_peers.on_disconnect_during_request(*peer_id)
504				{
505					self.actions.push(SyncingAction::DropPeer(bad_peer));
506				}
507			}
508		}
509
510		self.extra_justifications.cancel_request(peer_id);
511		self.allowed_requests.set_all();
512		self.fork_targets.retain(|_, target| {
513			target.peers.remove(peer_id);
514			!target.peers.is_empty()
515		});
516		if let Some(metrics) = &self.metrics {
517			metrics.fork_targets.set(self.fork_targets.len().try_into().unwrap_or(u64::MAX));
518		}
519
520		let blocks = self.ready_blocks();
521
522		if !blocks.is_empty() {
523			self.validate_and_queue_blocks(blocks, false);
524		}
525	}
526
527	fn on_validated_block_announce(
528		&mut self,
529		is_best: bool,
530		peer_id: PeerId,
531		announce: &BlockAnnounce<B::Header>,
532	) -> Option<(B::Hash, NumberFor<B>)> {
533		let number = *announce.header.number();
534		let hash = announce.header.hash();
535		let parent_status =
536			self.block_status(announce.header.parent_hash()).unwrap_or(BlockStatus::Unknown);
537		let known_parent = parent_status != BlockStatus::Unknown;
538		let ancient_parent = parent_status == BlockStatus::InChainPruned;
539
540		let known = self.is_known(&hash);
541		let is_major_syncing = self.is_major_syncing();
542		let peer = if let Some(peer) = self.peers.get_mut(&peer_id) {
543			peer
544		} else {
545			error!(target: LOG_TARGET, "๐Ÿ’” Called `on_validated_block_announce` with a bad peer ID {peer_id}");
546			return Some((hash, number));
547		};
548
549		if let PeerSyncState::AncestorSearch { .. } = peer.state {
550			trace!(target: LOG_TARGET, "Peer {} is in the ancestor search state.", peer_id);
551			return None;
552		}
553
554		// The node is continuing a known fork if either the block itself is known, the
555		// parent is known or the block references the previously announced `best_hash`.
556		let continues_known_fork =
557			known || known_parent || announce.header.parent_hash() == &peer.best_hash;
558
559		let peer_info = is_best.then(|| {
560			// update their best block
561			peer.best_number = number;
562			peer.best_hash = hash;
563
564			(hash, number)
565		});
566
567		// If the announced block is the best they have and is not ahead of us, our common number
568		// is either one further ahead or it's the one they just announced, if we know about it.
569		if is_best {
570			let best_queued_number = self.best_queued_number;
571
572			if known && best_queued_number >= number {
573				peer.update_common_number(number);
574			} else if announce.header.parent_hash() == &self.best_queued_hash ||
575				known_parent && best_queued_number >= number
576			{
577				peer.update_common_number(number.saturating_sub(One::one()));
578			}
579
580			// If this announced block isn't following any known fork, we have to start an
581			// ancestor search to find out our real common block. However, we skip this during
582			// major sync to avoid pulling peers out of the download pool.
583			if !continues_known_fork && !is_major_syncing {
584				let current = number.min(best_queued_number);
585				peer.common_number = peer.common_number.min(self.client.info().finalized_number);
586				let old_state = std::mem::replace(
587					&mut peer.state,
588					PeerSyncState::AncestorSearch {
589						current,
590						start: best_queued_number,
591						state: AncestorSearchState::ExponentialBackoff(One::one()),
592					},
593				);
594				self.cancel_peer_request(peer_id, old_state);
595
596				let request = ancestry_request::<B>(current);
597				let action = self.create_block_request_action(peer_id, request);
598				self.actions.push(action);
599
600				return peer_info;
601			}
602		}
603		self.allowed_requests.add(&peer_id);
604
605		// known block case
606		if known || self.is_already_downloading(&hash) {
607			trace!(target: LOG_TARGET, "Known block announce from {}: {}", peer_id, hash);
608			if let Some(target) = self.fork_targets.get_mut(&hash) {
609				target.peers.insert(peer_id);
610			}
611			return peer_info;
612		}
613
614		if ancient_parent {
615			trace!(
616				target: LOG_TARGET,
617				"Ignored ancient block announced from {}: {} {:?}",
618				peer_id,
619				hash,
620				announce.header,
621			);
622			return peer_info;
623		}
624
625		if self.status().state == SyncState::Idle {
626			trace!(
627				target: LOG_TARGET,
628				"Added sync target for block announced from {}: {} {:?}",
629				peer_id,
630				hash,
631				announce.summary(),
632			);
633			self.fork_targets
634				.entry(hash)
635				.or_insert_with(|| {
636					if let Some(metrics) = &self.metrics {
637						metrics.fork_targets.inc();
638					}
639
640					ForkTarget {
641						number,
642						parent_hash: Some(*announce.header.parent_hash()),
643						peers: Default::default(),
644					}
645				})
646				.peers
647				.insert(peer_id);
648		}
649
650		peer_info
651	}
652
653	// The implementation is similar to `on_validated_block_announce` with unknown parent hash.
654	fn set_sync_fork_request(
655		&mut self,
656		mut peers: Vec<PeerId>,
657		hash: &B::Hash,
658		number: NumberFor<B>,
659	) {
660		if peers.is_empty() {
661			peers = self
662				.peers
663				.iter()
664				// Only request blocks from peers who are ahead or on a par.
665				.filter(|(_, peer)| peer.best_number >= number)
666				.map(|(id, _)| *id)
667				.collect();
668
669			debug!(
670				target: LOG_TARGET,
671				"Explicit sync request for block {hash:?} with no peers specified. \
672				Syncing from these peers {peers:?} instead.",
673			);
674		} else {
675			debug!(
676				target: LOG_TARGET,
677				"Explicit sync request for block {hash:?} with {peers:?}",
678			);
679		}
680
681		if self.is_known(hash) {
682			debug!(target: LOG_TARGET, "Refusing to sync known hash {hash:?}");
683			return;
684		}
685
686		trace!(target: LOG_TARGET, "Downloading requested old fork {hash:?}");
687		for peer_id in &peers {
688			if let Some(peer) = self.peers.get_mut(peer_id) {
689				if let PeerSyncState::AncestorSearch { .. } = peer.state {
690					continue;
691				}
692
693				if number > peer.best_number {
694					peer.best_number = number;
695					peer.best_hash = *hash;
696				}
697				self.allowed_requests.add(peer_id);
698			}
699		}
700
701		self.fork_targets
702			.entry(*hash)
703			.or_insert_with(|| {
704				if let Some(metrics) = &self.metrics {
705					metrics.fork_targets.inc();
706				}
707
708				ForkTarget { number, peers: Default::default(), parent_hash: None }
709			})
710			.peers
711			.extend(peers);
712	}
713
714	fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>) {
715		let client = &self.client;
716		self.extra_justifications
717			.schedule((*hash, number), |base, block| is_descendent_of(&**client, base, block))
718	}
719
720	fn clear_justification_requests(&mut self) {
721		self.extra_justifications.reset();
722	}
723
724	fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool) {
725		let finalization_result = if success { Ok((hash, number)) } else { Err(()) };
726		self.extra_justifications
727			.try_finalize_root((hash, number), finalization_result, true);
728		self.allowed_requests.set_all();
729	}
730
731	fn on_generic_response(
732		&mut self,
733		peer_id: &PeerId,
734		key: StrategyKey,
735		protocol_name: ProtocolName,
736		response: Box<dyn Any + Send>,
737	) {
738		if Self::STRATEGY_KEY != key {
739			warn!(
740				target: LOG_TARGET,
741				"Unexpected generic response strategy key {key:?}, protocol {protocol_name}",
742			);
743			debug_assert!(false);
744			return;
745		}
746
747		if protocol_name == self.state_request_protocol_name {
748			let Ok(response) = response.downcast::<Vec<u8>>() else {
749				warn!(target: LOG_TARGET, "Failed to downcast state response");
750				debug_assert!(false);
751				return;
752			};
753
754			if let Err(bad_peer) = self.on_state_data(&peer_id, &response) {
755				self.actions.push(SyncingAction::DropPeer(bad_peer));
756			}
757		} else if &protocol_name == self.block_downloader.protocol_name() {
758			let Ok(response) = response
759				.downcast::<(BlockRequest<B>, Result<Vec<BlockData<B>>, BlockResponseError>)>()
760			else {
761				warn!(target: LOG_TARGET, "Failed to downcast block response");
762				debug_assert!(false);
763				return;
764			};
765
766			let (request, response) = *response;
767			let blocks = match response {
768				Ok(blocks) => blocks,
769				Err(BlockResponseError::DecodeFailed(e)) => {
770					debug!(
771						target: LOG_TARGET,
772						"Failed to decode block response from peer {:?}: {:?}.",
773						peer_id,
774						e
775					);
776					self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE)));
777					return;
778				},
779				Err(BlockResponseError::ExtractionFailed(e)) => {
780					debug!(
781						target: LOG_TARGET,
782						"Failed to extract blocks from peer response {:?}: {:?}.",
783						peer_id,
784						e
785					);
786					self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE)));
787					return;
788				},
789			};
790
791			if let Err(bad_peer) = self.on_block_response(peer_id, key, request, blocks) {
792				self.actions.push(SyncingAction::DropPeer(bad_peer));
793			}
794		} else {
795			warn!(
796				target: LOG_TARGET,
797				"Unexpected generic response protocol {protocol_name}, strategy key \
798				{key:?}",
799			);
800			debug_assert!(false);
801		}
802	}
803
804	fn on_blocks_processed(
805		&mut self,
806		imported: usize,
807		count: usize,
808		results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
809	) {
810		trace!(target: LOG_TARGET, "Imported {imported} of {count}");
811
812		let mut has_error = false;
813		for (_, hash) in &results {
814			if self.queue_blocks.remove(hash) {
815				if let Some(metrics) = &self.metrics {
816					metrics.queued_blocks.dec();
817				}
818			}
819			self.blocks.clear_queued(hash);
820			if let Some(gap_sync) = &mut self.gap_sync {
821				gap_sync.blocks.clear_queued(hash);
822			}
823		}
824		for (result, hash) in results {
825			if has_error {
826				break;
827			}
828
829			has_error |= result.is_err();
830
831			match result {
832				Ok(BlockImportStatus::ImportedKnown(number, peer_id)) => {
833					if let Some(peer) = peer_id {
834						self.update_peer_common_number(&peer, number);
835					}
836					self.complete_gap_if_target(number);
837				},
838				Ok(BlockImportStatus::ImportedUnknown(number, aux, peer_id)) => {
839					if aux.clear_justification_requests {
840						trace!(
841							target: LOG_TARGET,
842							"Block imported clears all pending justification requests {number}: {hash:?}",
843						);
844						self.clear_justification_requests();
845					}
846
847					if aux.needs_justification {
848						trace!(
849							target: LOG_TARGET,
850							"Block imported but requires justification {number}: {hash:?}",
851						);
852						self.request_justification(&hash, number);
853					}
854
855					if aux.bad_justification {
856						if let Some(ref peer) = peer_id {
857							warn!("๐Ÿ’” Sent block with bad justification to import");
858							self.actions.push(SyncingAction::DropPeer(BadPeer(
859								*peer,
860								rep::BAD_JUSTIFICATION,
861							)));
862						}
863					}
864
865					if let Some(peer) = peer_id {
866						self.update_peer_common_number(&peer, number);
867					}
868					let state_sync_complete =
869						self.state_sync.as_ref().map_or(false, |s| s.target_hash() == hash);
870					if state_sync_complete {
871						info!(
872							target: LOG_TARGET,
873							"State sync is complete ({} MiB), restarting block sync.",
874							self.state_sync.as_ref().map_or(0, |s| s.progress().size / (1024 * 1024)),
875						);
876						self.state_sync = None;
877						self.mode = ChainSyncMode::Full;
878						self.restart();
879					}
880
881					self.complete_gap_if_target(number);
882				},
883				Err(BlockImportError::IncompleteHeader(peer_id)) => {
884					if let Some(peer) = peer_id {
885						warn!(
886							target: LOG_TARGET,
887							"๐Ÿ’” Peer sent block with incomplete header to import",
888						);
889						self.actions
890							.push(SyncingAction::DropPeer(BadPeer(peer, rep::INCOMPLETE_HEADER)));
891						self.restart();
892					}
893				},
894				Err(BlockImportError::VerificationFailed(peer_id, e)) => {
895					let extra_message = peer_id
896						.map_or_else(|| "".into(), |peer| format!(" received from ({peer})"));
897
898					warn!(
899						target: LOG_TARGET,
900						"๐Ÿ’” Verification failed for block {hash:?}{extra_message}: {e:?}",
901					);
902
903					if let Some(peer) = peer_id {
904						self.actions
905							.push(SyncingAction::DropPeer(BadPeer(peer, rep::VERIFICATION_FAIL)));
906					}
907
908					self.restart();
909				},
910				Err(BlockImportError::BadBlock(peer_id)) => {
911					if let Some(peer) = peer_id {
912						warn!(
913							target: LOG_TARGET,
914							"๐Ÿ’” Block {hash:?} received from peer {peer} has been blacklisted",
915						);
916						self.actions.push(SyncingAction::DropPeer(BadPeer(peer, rep::BAD_BLOCK)));
917					}
918				},
919				Err(BlockImportError::MissingState) => {
920					// This may happen if the chain we were requesting upon has been discarded
921					// in the meantime because other chain has been finalized.
922					// Don't mark it as bad as it still may be synced if explicitly requested.
923					trace!(target: LOG_TARGET, "Obsolete block {hash:?}");
924				},
925				e @ Err(BlockImportError::UnknownParent) | e @ Err(BlockImportError::Other(_)) => {
926					warn!(target: LOG_TARGET, "๐Ÿ’” Error importing block {hash:?}: {}", e.unwrap_err());
927					self.state_sync = None;
928					self.restart();
929				},
930				Err(BlockImportError::Cancelled) => {},
931			};
932		}
933
934		self.allowed_requests.set_all();
935	}
936
937	fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor<B>) {
938		let client = &self.client;
939		let r = self.extra_justifications.on_block_finalized(hash, number, |base, block| {
940			is_descendent_of(&**client, base, block)
941		});
942
943		if let ChainSyncMode::LightState { skip_proofs, .. } = &self.mode {
944			if self.state_sync.is_none() {
945				if !self.peers.is_empty() && self.queue_blocks.is_empty() {
946					self.attempt_state_sync(*hash, number, *skip_proofs);
947				} else {
948					self.pending_state_sync_attempt.replace((*hash, number, *skip_proofs));
949				}
950			}
951		}
952
953		if let Err(err) = r {
954			warn!(
955				target: LOG_TARGET,
956				"๐Ÿ’” Error cleaning up pending extra justification data requests: {err}",
957			);
958		}
959	}
960
961	fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor<B>) {
962		self.on_block_queued(best_hash, best_number);
963	}
964
965	fn is_major_syncing(&self) -> bool {
966		self.status().state.is_major_syncing()
967	}
968
969	fn num_peers(&self) -> usize {
970		self.peers.len()
971	}
972
973	fn status(&self) -> SyncStatus<B> {
974		let median_seen = self.median_seen();
975		let best_seen_block =
976			median_seen.and_then(|median| (median > self.best_queued_number).then_some(median));
977		let sync_state = if let Some(target) = median_seen {
978			// A chain is classified as downloading if the provided best block is
979			// more than `MAJOR_SYNC_BLOCKS` behind the best block or as importing
980			// if the same can be said about queued blocks.
981			let best_block = self.client.info().best_number;
982			if target > best_block && target - best_block > MAJOR_SYNC_BLOCKS.into() {
983				// If target is not queued, we're downloading, otherwise importing.
984				if target > self.best_queued_number {
985					SyncState::Downloading { target }
986				} else {
987					SyncState::Importing { target }
988				}
989			} else {
990				SyncState::Idle
991			}
992		} else {
993			SyncState::Idle
994		};
995
996		let warp_sync_progress = self.gap_sync.as_ref().map(|gap_sync| WarpSyncProgress {
997			phase: WarpSyncPhase::DownloadingBlocks(gap_sync.best_queued_number),
998			total_bytes: 0,
999			status: None,
1000		});
1001
1002		SyncStatus {
1003			state: sync_state,
1004			best_seen_block,
1005			num_peers: self.peers.len() as u32,
1006			queued_blocks: self.queue_blocks.len() as u32,
1007			state_sync: self.state_sync.as_ref().map(|s| s.progress()),
1008			warp_sync: warp_sync_progress,
1009		}
1010	}
1011
1012	fn num_downloaded_blocks(&self) -> usize {
1013		self.downloaded_blocks
1014	}
1015
1016	fn num_sync_requests(&self) -> usize {
1017		self.fork_targets
1018			.values()
1019			.filter(|f| f.number <= self.best_queued_number)
1020			.count()
1021	}
1022
1023	fn actions(
1024		&mut self,
1025		network_service: &NetworkServiceHandle,
1026	) -> Result<Vec<SyncingAction<B>>, ClientError> {
1027		if !self.peers.is_empty() && self.queue_blocks.is_empty() {
1028			if let Some((hash, number, skip_proofs)) = self.pending_state_sync_attempt.take() {
1029				self.attempt_state_sync(hash, number, skip_proofs);
1030			}
1031		}
1032
1033		let block_requests = self
1034			.block_requests()
1035			.into_iter()
1036			.map(|(peer_id, request)| self.create_block_request_action(peer_id, request))
1037			.collect::<Vec<_>>();
1038		self.actions.extend(block_requests);
1039
1040		let justification_requests = self
1041			.justification_requests()
1042			.into_iter()
1043			.map(|(peer_id, request)| self.create_block_request_action(peer_id, request))
1044			.collect::<Vec<_>>();
1045		self.actions.extend(justification_requests);
1046
1047		let state_request = self.state_request().into_iter().map(|(peer_id, request)| {
1048			trace!(
1049				target: LOG_TARGET,
1050				"Created `StateRequest` to {peer_id}.",
1051			);
1052
1053			let (tx, rx) = oneshot::channel();
1054
1055			network_service.start_request(
1056				peer_id,
1057				self.state_request_protocol_name.clone(),
1058				request.encode_to_vec(),
1059				tx,
1060				IfDisconnected::ImmediateError,
1061			);
1062
1063			SyncingAction::StartRequest {
1064				peer_id,
1065				key: Self::STRATEGY_KEY,
1066				request: async move {
1067					Ok(rx.await?.and_then(|(response, protocol_name)| {
1068						Ok((Box::new(response) as Box<dyn Any + Send>, protocol_name))
1069					}))
1070				}
1071				.boxed(),
1072			}
1073		});
1074		self.actions.extend(state_request);
1075
1076		Ok(std::mem::take(&mut self.actions))
1077	}
1078}
1079
1080impl<B, Client> ChainSync<B, Client>
1081where
1082	B: BlockT,
1083	Client: HeaderBackend<B>
1084		+ BlockBackend<B>
1085		+ HeaderMetadata<B, Error = sp_blockchain::Error>
1086		+ ProofProvider<B>
1087		+ Send
1088		+ Sync
1089		+ 'static,
1090{
1091	/// Strategy key used by chain sync.
1092	pub const STRATEGY_KEY: StrategyKey = StrategyKey::new("ChainSync");
1093
1094	/// Create a new instance.
1095	pub fn new(
1096		mode: ChainSyncMode,
1097		client: Arc<Client>,
1098		max_parallel_downloads: u32,
1099		max_blocks_per_request: u32,
1100		state_request_protocol_name: ProtocolName,
1101		block_downloader: Arc<dyn BlockDownloader<B>>,
1102		gap_sync_body_policy: GapSyncBodyPolicy,
1103		metrics_registry: Option<&Registry>,
1104		initial_peers: impl Iterator<Item = (PeerId, B::Hash, NumberFor<B>)>,
1105	) -> Result<Self, ClientError> {
1106		info!(target: LOG_TARGET, "Gap sync body policy: {gap_sync_body_policy:?}");
1107		let metrics = metrics_registry.and_then(|r| match Metrics::register(r) {
1108			Ok(metrics) => Some(metrics),
1109			Err(err) => {
1110				log::error!(target: LOG_TARGET, "Failed to register `ChainSync` metrics {err:?}");
1111				None
1112			},
1113		});
1114		let mut sync = Self {
1115			client,
1116			peers: HashMap::new(),
1117			disconnected_peers: DisconnectedPeers::new(),
1118			blocks: BlockCollection::with_metrics(
1119				metrics.as_ref().map(|m| m.block_collection.clone()),
1120			),
1121			best_queued_hash: Default::default(),
1122			best_queued_number: Zero::zero(),
1123			extra_justifications: ExtraRequests::new("justification", metrics_registry),
1124			mode,
1125			queue_blocks: Default::default(),
1126			pending_state_sync_attempt: None,
1127			fork_targets: Default::default(),
1128			allowed_requests: Default::default(),
1129			max_parallel_downloads,
1130			max_blocks_per_request,
1131			state_request_protocol_name,
1132			downloaded_blocks: 0,
1133			state_sync: None,
1134			import_existing: false,
1135			block_downloader,
1136			gap_sync_body_policy,
1137			gap_sync: None,
1138			actions: Vec::new(),
1139			metrics,
1140		};
1141
1142		sync.reset_sync_start_point()?;
1143		initial_peers.for_each(|(peer_id, best_hash, best_number)| {
1144			sync.add_peer(peer_id, best_hash, best_number);
1145		});
1146
1147		Ok(sync)
1148	}
1149
1150	/// Complete the gap sync if the target number is reached and there is a gap.
1151	fn complete_gap_if_target(&mut self, number: NumberFor<B>) {
1152		let Some(gap_sync) = &self.gap_sync else { return };
1153
1154		if gap_sync.target != number {
1155			return;
1156		}
1157
1158		info!(
1159			target: LOG_TARGET,
1160			"Block history download is complete. Downloaded {}.",
1161			gap_sync.stats,
1162		);
1163		self.gap_sync = None;
1164		if let Some(metrics) = &self.metrics {
1165			metrics.gap_oldest_required_body.set(0);
1166		}
1167	}
1168
1169	#[must_use]
1170	fn add_peer_inner(
1171		&mut self,
1172		peer_id: PeerId,
1173		best_hash: B::Hash,
1174		best_number: NumberFor<B>,
1175	) -> Result<Option<BlockRequest<B>>, BadPeer> {
1176		// There is nothing sync can get from the node that has no blockchain data.
1177		match self.block_status(&best_hash) {
1178			Err(e) => {
1179				debug!(target: LOG_TARGET, "Error reading blockchain: {e}");
1180				Err(BadPeer(peer_id, rep::BLOCKCHAIN_READ_ERROR))
1181			},
1182			Ok(BlockStatus::KnownBad) => {
1183				info!(
1184					"๐Ÿ’” New peer {peer_id} with known bad best block {best_hash} ({best_number})."
1185				);
1186				Err(BadPeer(peer_id, rep::BAD_BLOCK))
1187			},
1188			Ok(BlockStatus::Unknown) => {
1189				if best_number.is_zero() {
1190					info!(
1191						"๐Ÿ’” New peer {} with unknown genesis hash {} ({}).",
1192						peer_id, best_hash, best_number,
1193					);
1194					return Err(BadPeer(peer_id, rep::GENESIS_MISMATCH));
1195				}
1196
1197				// If there are more than `MAJOR_SYNC_BLOCKS` in the import queue then we have
1198				// enough to do in the import queue that it's not worth kicking off
1199				// an ancestor search, which is what we do in the next match case below.
1200				if self.queue_blocks.len() > MAJOR_SYNC_BLOCKS as usize {
1201					debug!(
1202						target: LOG_TARGET,
1203						"New peer {} with unknown best hash {} ({}), assuming common block.",
1204						peer_id,
1205						self.best_queued_hash,
1206						self.best_queued_number
1207					);
1208					self.peers.insert(
1209						peer_id,
1210						PeerSync {
1211							peer_id,
1212							common_number: self.best_queued_number,
1213							best_hash,
1214							best_number,
1215							state: PeerSyncState::Available,
1216						},
1217					);
1218					return Ok(None);
1219				}
1220
1221				// If we are at genesis, just start downloading.
1222				let (state, req) = if self.best_queued_number.is_zero() {
1223					debug!(
1224						target: LOG_TARGET,
1225						"New peer {peer_id} with best hash {best_hash} ({best_number}).",
1226					);
1227
1228					(PeerSyncState::Available, None)
1229				} else {
1230					let common_best = std::cmp::min(self.best_queued_number, best_number);
1231
1232					debug!(
1233						target: LOG_TARGET,
1234						"New peer {} with unknown best hash {} ({}), searching for common ancestor.",
1235						peer_id,
1236						best_hash,
1237						best_number
1238					);
1239
1240					(
1241						PeerSyncState::AncestorSearch {
1242							current: common_best,
1243							start: self.best_queued_number,
1244							state: AncestorSearchState::ExponentialBackoff(One::one()),
1245						},
1246						Some(ancestry_request::<B>(common_best)),
1247					)
1248				};
1249
1250				self.allowed_requests.add(&peer_id);
1251				self.peers.insert(
1252					peer_id,
1253					PeerSync {
1254						peer_id,
1255						common_number: Zero::zero(),
1256						best_hash,
1257						best_number,
1258						state,
1259					},
1260				);
1261
1262				Ok(req)
1263			},
1264			Ok(BlockStatus::Queued) |
1265			Ok(BlockStatus::InChainWithState) |
1266			Ok(BlockStatus::InChainPruned) => {
1267				debug!(
1268					target: LOG_TARGET,
1269					"New peer {peer_id} with known best hash {best_hash} ({best_number}).",
1270				);
1271				self.peers.insert(
1272					peer_id,
1273					PeerSync {
1274						peer_id,
1275						common_number: std::cmp::min(self.best_queued_number, best_number),
1276						best_hash,
1277						best_number,
1278						state: PeerSyncState::Available,
1279					},
1280				);
1281				self.allowed_requests.add(&peer_id);
1282				Ok(None)
1283			},
1284		}
1285	}
1286
1287	/// Release bookkeeping for a peer's old request and queue its cancellation.
1288	///
1289	/// The caller handles the peer's state transition and must call this before scheduling
1290	/// replacement work. The engine only drops the old response future.
1291	fn cancel_peer_request(&mut self, peer_id: PeerId, old_state: PeerSyncState<B>) {
1292		match old_state {
1293			PeerSyncState::Available => return,
1294			PeerSyncState::DownloadingNew(_) => self.blocks.clear_peer_download(&peer_id),
1295			PeerSyncState::DownloadingGap(_) => {
1296				if let Some(gap_sync) = &mut self.gap_sync {
1297					gap_sync.blocks.clear_peer_download(&peer_id);
1298				}
1299			},
1300			PeerSyncState::DownloadingJustification(_) => {
1301				self.extra_justifications.cancel_request(&peer_id);
1302			},
1303			// State requests are regenerated from the last imported cursor; fork targets
1304			// remain pending. Neither has a separate in-flight range reservation.
1305			PeerSyncState::DownloadingState |
1306			PeerSyncState::DownloadingStale(_) |
1307			PeerSyncState::AncestorSearch { .. } => {},
1308		}
1309		self.actions
1310			.push(SyncingAction::CancelRequest { peer_id, key: Self::STRATEGY_KEY });
1311		// Let any available peer pick up the released work, e.g. while this peer does
1312		// ancestry search.
1313		self.allowed_requests.set_all();
1314	}
1315
1316	fn create_block_request_action(
1317		&mut self,
1318		peer_id: PeerId,
1319		request: BlockRequest<B>,
1320	) -> SyncingAction<B> {
1321		let downloader = self.block_downloader.clone();
1322
1323		SyncingAction::StartRequest {
1324			peer_id,
1325			key: Self::STRATEGY_KEY,
1326			request: async move {
1327				Ok(downloader.download_blocks(peer_id, request.clone()).await?.and_then(
1328					|(response, protocol_name)| {
1329						let decoded_response =
1330							downloader.block_response_into_blocks(&request, response);
1331						let result = Box::new((request, decoded_response)) as Box<dyn Any + Send>;
1332						Ok((result, protocol_name))
1333					},
1334				))
1335			}
1336			.boxed(),
1337		}
1338	}
1339
1340	/// Submit a block response for processing.
1341	#[must_use]
1342	fn on_block_data(
1343		&mut self,
1344		peer_id: &PeerId,
1345		request: Option<BlockRequest<B>>,
1346		response: BlockResponse<B>,
1347	) -> Result<(), BadPeer> {
1348		self.downloaded_blocks += response.blocks.len();
1349		let mut gap = false;
1350		let new_blocks: Vec<IncomingBlock<B>> = if let Some(peer) = self.peers.get_mut(peer_id) {
1351			let mut blocks = response.blocks;
1352			if request.as_ref().map_or(false, |r| r.direction == Direction::Descending) {
1353				trace!(target: LOG_TARGET, "Reversing incoming block list");
1354				blocks.reverse()
1355			}
1356			self.allowed_requests.add(peer_id);
1357			if let Some(request) = request {
1358				match &mut peer.state {
1359					PeerSyncState::DownloadingNew(_) => {
1360						self.blocks.clear_peer_download(peer_id);
1361						peer.state = PeerSyncState::Available;
1362						if let Some(start_block) =
1363							validate_blocks::<B>(&blocks, peer_id, Some(request))?
1364						{
1365							self.blocks.insert(start_block, blocks, *peer_id);
1366						}
1367						self.ready_blocks()
1368					},
1369					PeerSyncState::DownloadingGap(_) => {
1370						peer.state = PeerSyncState::Available;
1371						if blocks.is_empty() && request.fields.contains(BlockAttributes::BODY) {
1372							// An empty response means the peer holds no body of the entire
1373							// range (bodies are pruned oldest-first). Disconnect it to free
1374							// the slot for a peer that does; the mild penalty lets it retry
1375							// later.
1376							debug!(
1377								target: LOG_TARGET,
1378								"Peer {peer_id} sent an empty response for gap block request \
1379								 {request:?} that required bodies; disconnecting it",
1380							);
1381							if let Some(metrics) = &self.metrics {
1382								metrics.gap_body_empty_responses.inc();
1383							}
1384							if let Some(gap_sync) = &mut self.gap_sync {
1385								gap_sync.blocks.clear_peer_download(peer_id);
1386							}
1387							return Err(BadPeer(*peer_id, rep::NO_GAP_BODIES));
1388						}
1389						if let Some(gap_sync) = &mut self.gap_sync {
1390							gap_sync.blocks.clear_peer_download(peer_id);
1391							if let Some(start_block) =
1392								validate_blocks::<B>(&blocks, peer_id, Some(request))?
1393							{
1394								gap_sync.blocks.insert(start_block, blocks, *peer_id);
1395							}
1396							gap = true;
1397							let mut batch_gap_sync_stats = GapSyncStats::new();
1398							let blocks: Vec<_> = gap_sync
1399								.blocks
1400								.ready_blocks(gap_sync.best_queued_number + One::one())
1401								.into_iter()
1402								.map(|block_data| {
1403									let justifications =
1404										block_data.block.justifications.or_else(|| {
1405											legacy_justification_mapping(
1406												block_data.block.justification,
1407											)
1408										});
1409									let gap_sync_stats = GapSyncStats {
1410										header_bytes: block_data
1411											.block
1412											.header
1413											.as_ref()
1414											.map(|h| h.encoded_size())
1415											.unwrap_or(0),
1416										body_bytes: block_data
1417											.block
1418											.body
1419											.as_ref()
1420											.map(|b| b.encoded_size())
1421											.unwrap_or(0),
1422										justification_bytes: justifications
1423											.as_ref()
1424											.map(|j| j.encoded_size())
1425											.unwrap_or(0),
1426									};
1427									batch_gap_sync_stats += gap_sync_stats;
1428
1429									IncomingBlock {
1430										hash: block_data.block.hash,
1431										header: block_data.block.header,
1432										body: block_data.block.body,
1433										justifications,
1434										origin: block_data.origin,
1435										allow_missing_state: true,
1436										// Warp-synced blocks are header-only. Allow re-import to
1437										// store bodies if gap sync requested them.
1438										import_existing: true,
1439										skip_execution: true,
1440										state: None,
1441									}
1442								})
1443								.collect();
1444
1445							debug!(
1446								target: LOG_TARGET,
1447								"Drained {} gap blocks from {}",
1448								blocks.len(),
1449								gap_sync.best_queued_number,
1450							);
1451
1452							gap_sync.stats += batch_gap_sync_stats;
1453
1454							if blocks.len() > 0 {
1455								trace!(
1456									target: LOG_TARGET,
1457									"Gap sync cumulative stats: {}",
1458									gap_sync.stats
1459								);
1460							}
1461							blocks
1462						} else {
1463							debug!(target: LOG_TARGET, "Unexpected gap block response from {peer_id}");
1464							return Err(BadPeer(*peer_id, rep::NO_BLOCK));
1465						}
1466					},
1467					PeerSyncState::DownloadingStale(_) => {
1468						peer.state = PeerSyncState::Available;
1469						if blocks.is_empty() {
1470							debug!(target: LOG_TARGET, "Empty block response from {peer_id}");
1471							return Err(BadPeer(*peer_id, rep::NO_BLOCK));
1472						}
1473						validate_blocks::<B>(&blocks, peer_id, Some(request))?;
1474						blocks
1475							.into_iter()
1476							.map(|b| {
1477								let justifications = b
1478									.justifications
1479									.or_else(|| legacy_justification_mapping(b.justification));
1480								IncomingBlock {
1481									hash: b.hash,
1482									header: b.header,
1483									body: b.body,
1484									justifications,
1485									origin: Some(*peer_id),
1486									allow_missing_state: true,
1487									import_existing: self.import_existing,
1488									skip_execution: self.skip_execution(),
1489									state: None,
1490								}
1491							})
1492							.collect()
1493					},
1494					PeerSyncState::AncestorSearch { current, start, state } => {
1495						let matching_hash = match (blocks.get(0), self.client.hash(*current)) {
1496							(Some(block), Ok(maybe_our_block_hash)) => {
1497								trace!(
1498									target: LOG_TARGET,
1499									"Got ancestry block #{} ({}) from peer {}",
1500									current,
1501									block.hash,
1502									peer_id,
1503								);
1504								maybe_our_block_hash.filter(|x| x == &block.hash)
1505							},
1506							(None, _) => {
1507								debug!(
1508									target: LOG_TARGET,
1509									"Invalid response when searching for ancestor from {peer_id}",
1510								);
1511								return Err(BadPeer(*peer_id, rep::UNKNOWN_ANCESTOR));
1512							},
1513							(_, Err(e)) => {
1514								info!(
1515									target: LOG_TARGET,
1516									"โŒ Error answering legitimate blockchain query: {e}",
1517								);
1518								return Err(BadPeer(*peer_id, rep::BLOCKCHAIN_READ_ERROR));
1519							},
1520						};
1521						if matching_hash.is_some() {
1522							if *start < self.best_queued_number &&
1523								self.best_queued_number <= peer.best_number
1524							{
1525								// We've made progress on this chain since the search was started.
1526								// Opportunistically set common number to updated number
1527								// instead of the one that started the search.
1528								trace!(
1529									target: LOG_TARGET,
1530									"Ancestry search: opportunistically updating peer {} common number from={} => to={}.",
1531									*peer_id,
1532									peer.common_number,
1533									self.best_queued_number,
1534								);
1535								peer.common_number = self.best_queued_number;
1536							} else if peer.common_number < *current {
1537								trace!(
1538									target: LOG_TARGET,
1539									"Ancestry search: updating peer {} common number from={} => to={}.",
1540									*peer_id,
1541									peer.common_number,
1542									*current,
1543								);
1544								peer.common_number = *current;
1545							}
1546						}
1547						if matching_hash.is_none() && current.is_zero() {
1548							trace!(
1549								target: LOG_TARGET,
1550								"Ancestry search: genesis mismatch for peer {peer_id}",
1551							);
1552							return Err(BadPeer(*peer_id, rep::GENESIS_MISMATCH));
1553						}
1554						if let Some((next_state, next_num)) =
1555							handle_ancestor_search_state(state, *current, matching_hash.is_some())
1556						{
1557							peer.state = PeerSyncState::AncestorSearch {
1558								current: next_num,
1559								start: *start,
1560								state: next_state,
1561							};
1562							let request = ancestry_request::<B>(next_num);
1563							let action = self.create_block_request_action(*peer_id, request);
1564							self.actions.push(action);
1565							return Ok(());
1566						} else {
1567							// Ancestry search is complete. Check if peer is on a stale fork unknown
1568							// to us and add it to sync targets if necessary.
1569							trace!(
1570								target: LOG_TARGET,
1571								"Ancestry search complete. Ours={} ({}), Theirs={} ({}), Common={:?} ({})",
1572								self.best_queued_hash,
1573								self.best_queued_number,
1574								peer.best_hash,
1575								peer.best_number,
1576								matching_hash,
1577								peer.common_number,
1578							);
1579							if peer.common_number < peer.best_number &&
1580								peer.best_number < self.best_queued_number
1581							{
1582								trace!(
1583									target: LOG_TARGET,
1584									"Added fork target {} for {}",
1585									peer.best_hash,
1586									peer_id,
1587								);
1588								self.fork_targets
1589									.entry(peer.best_hash)
1590									.or_insert_with(|| {
1591										if let Some(metrics) = &self.metrics {
1592											metrics.fork_targets.inc();
1593										}
1594
1595										ForkTarget {
1596											number: peer.best_number,
1597											parent_hash: None,
1598											peers: Default::default(),
1599										}
1600									})
1601									.peers
1602									.insert(*peer_id);
1603							}
1604							peer.state = PeerSyncState::Available;
1605							return Ok(());
1606						}
1607					},
1608					PeerSyncState::Available |
1609					PeerSyncState::DownloadingJustification(..) |
1610					PeerSyncState::DownloadingState => Vec::new(),
1611				}
1612			} else {
1613				// When request.is_none() this is a block announcement. Just accept blocks.
1614				validate_blocks::<B>(&blocks, peer_id, None)?;
1615				blocks
1616					.into_iter()
1617					.map(|b| {
1618						let justifications = b
1619							.justifications
1620							.or_else(|| legacy_justification_mapping(b.justification));
1621						IncomingBlock {
1622							hash: b.hash,
1623							header: b.header,
1624							body: b.body,
1625							justifications,
1626							origin: Some(*peer_id),
1627							allow_missing_state: true,
1628							import_existing: false,
1629							skip_execution: true,
1630							state: None,
1631						}
1632					})
1633					.collect()
1634			}
1635		} else {
1636			// We don't know of this peer, so we also did not request anything from it.
1637			return Err(BadPeer(*peer_id, rep::NOT_REQUESTED));
1638		};
1639
1640		self.validate_and_queue_blocks(new_blocks, gap);
1641
1642		Ok(())
1643	}
1644
1645	fn on_block_response(
1646		&mut self,
1647		peer_id: &PeerId,
1648		key: StrategyKey,
1649		request: BlockRequest<B>,
1650		blocks: Vec<BlockData<B>>,
1651	) -> Result<(), BadPeer> {
1652		if key != Self::STRATEGY_KEY {
1653			error!(
1654				target: LOG_TARGET,
1655				"`on_block_response()` called with unexpected key {key:?} for chain sync",
1656			);
1657			debug_assert!(false);
1658		}
1659		let block_response = BlockResponse::<B> { id: request.id, blocks };
1660
1661		let blocks_range = || match (
1662			block_response
1663				.blocks
1664				.first()
1665				.and_then(|b| b.header.as_ref().map(|h| h.number())),
1666			block_response.blocks.last().and_then(|b| b.header.as_ref().map(|h| h.number())),
1667		) {
1668			(Some(first), Some(last)) if first != last => format!(" ({}..{})", first, last),
1669			(Some(first), Some(_)) => format!(" ({})", first),
1670			_ => Default::default(),
1671		};
1672
1673		trace!(
1674			target: LOG_TARGET,
1675			"BlockResponse {} from {} with {} blocks {}",
1676			block_response.id,
1677			peer_id,
1678			block_response.blocks.len(),
1679			blocks_range(),
1680		);
1681
1682		if request.fields == BlockAttributes::JUSTIFICATION {
1683			self.on_block_justification(*peer_id, block_response)
1684		} else {
1685			self.on_block_data(peer_id, Some(request), block_response)
1686		}
1687	}
1688
1689	/// Submit a justification response for processing.
1690	#[must_use]
1691	fn on_block_justification(
1692		&mut self,
1693		peer_id: PeerId,
1694		response: BlockResponse<B>,
1695	) -> Result<(), BadPeer> {
1696		let peer = if let Some(peer) = self.peers.get_mut(&peer_id) {
1697			peer
1698		} else {
1699			error!(
1700				target: LOG_TARGET,
1701				"๐Ÿ’” Called on_block_justification with a peer ID of an unknown peer",
1702			);
1703			return Ok(());
1704		};
1705
1706		self.allowed_requests.add(&peer_id);
1707		if let PeerSyncState::DownloadingJustification(hash) = peer.state {
1708			peer.state = PeerSyncState::Available;
1709
1710			// We only request one justification at a time
1711			let justification = if let Some(block) = response.blocks.into_iter().next() {
1712				if hash != block.hash {
1713					warn!(
1714						target: LOG_TARGET,
1715						"๐Ÿ’” Invalid block justification provided by {}: requested: {:?} got: {:?}",
1716						peer_id,
1717						hash,
1718						block.hash,
1719					);
1720					return Err(BadPeer(peer_id, rep::BAD_JUSTIFICATION));
1721				}
1722
1723				block
1724					.justifications
1725					.or_else(|| legacy_justification_mapping(block.justification))
1726			} else {
1727				// we might have asked the peer for a justification on a block that we assumed it
1728				// had but didn't (regardless of whether it had a justification for it or not).
1729				trace!(
1730					target: LOG_TARGET,
1731					"Peer {peer_id:?} provided empty response for justification request {hash:?}",
1732				);
1733
1734				None
1735			};
1736
1737			if let Some((peer_id, hash, number, justifications)) =
1738				self.extra_justifications.on_response(peer_id, justification)
1739			{
1740				self.actions.push(SyncingAction::ImportJustifications {
1741					peer_id,
1742					hash,
1743					number,
1744					justifications,
1745				});
1746				return Ok(());
1747			}
1748		}
1749
1750		Ok(())
1751	}
1752
1753	/// Returns the median seen block number.
1754	fn median_seen(&self) -> Option<NumberFor<B>> {
1755		let mut best_seens = self.peers.values().map(|p| p.best_number).collect::<Vec<_>>();
1756
1757		if best_seens.is_empty() {
1758			None
1759		} else {
1760			let middle = best_seens.len() / 2;
1761
1762			// Not the "perfect median" when we have an even number of peers.
1763			Some(*best_seens.select_nth_unstable(middle).1)
1764		}
1765	}
1766
1767	fn skip_execution(&self) -> bool {
1768		match self.mode {
1769			ChainSyncMode::Full => false,
1770			ChainSyncMode::LightState { .. } => true,
1771		}
1772	}
1773
1774	fn validate_and_queue_blocks(&mut self, mut new_blocks: Vec<IncomingBlock<B>>, gap: bool) {
1775		let orig_len = new_blocks.len();
1776		new_blocks.retain(|b| !self.queue_blocks.contains(&b.hash));
1777		if new_blocks.len() != orig_len {
1778			debug!(
1779				target: LOG_TARGET,
1780				"Ignoring {} blocks that are already queued",
1781				orig_len - new_blocks.len(),
1782			);
1783		}
1784
1785		let origin = if gap {
1786			// Gap sync: filling historical blocks after warp sync
1787			BlockOrigin::GapSync
1788		} else if !self.status().state.is_major_syncing() {
1789			// Normal operation: receiving new blocks
1790			BlockOrigin::NetworkBroadcast
1791		} else {
1792			// Initial sync: catching up with the chain
1793			BlockOrigin::NetworkInitialSync
1794		};
1795
1796		if let Some((h, n)) = new_blocks
1797			.last()
1798			.and_then(|b| b.header.as_ref().map(|h| (&b.hash, *h.number())))
1799		{
1800			trace!(
1801				target: LOG_TARGET,
1802				"Accepted {} blocks ({:?}) with origin {:?}",
1803				new_blocks.len(),
1804				h,
1805				origin,
1806			);
1807			self.on_block_queued(h, n)
1808		}
1809		self.queue_blocks.extend(new_blocks.iter().map(|b| b.hash));
1810		if let Some(metrics) = &self.metrics {
1811			metrics
1812				.queued_blocks
1813				.set(self.queue_blocks.len().try_into().unwrap_or(u64::MAX));
1814		}
1815
1816		self.actions.push(SyncingAction::ImportBlocks { origin, blocks: new_blocks })
1817	}
1818
1819	fn update_peer_common_number(&mut self, peer_id: &PeerId, new_common: NumberFor<B>) {
1820		if let Some(peer) = self.peers.get_mut(peer_id) {
1821			peer.update_common_number(new_common);
1822		}
1823	}
1824
1825	/// Called when a block has been queued for import.
1826	///
1827	/// Updates our internal state for best queued block and then goes
1828	/// through all peers to update our view of their state as well.
1829	fn on_block_queued(&mut self, hash: &B::Hash, number: NumberFor<B>) {
1830		if self.fork_targets.remove(hash).is_some() {
1831			if let Some(metrics) = &self.metrics {
1832				metrics.fork_targets.dec();
1833			}
1834			trace!(target: LOG_TARGET, "Completed fork sync {hash:?}");
1835		}
1836		if let Some(gap_sync) = &mut self.gap_sync {
1837			if number > gap_sync.best_queued_number && number <= gap_sync.target {
1838				gap_sync.best_queued_number = number;
1839			}
1840		}
1841		if number > self.best_queued_number {
1842			self.best_queued_number = number;
1843			self.best_queued_hash = *hash;
1844			// Update common blocks
1845			for (n, peer) in self.peers.iter_mut() {
1846				if let PeerSyncState::AncestorSearch { .. } = peer.state {
1847					// Wait for ancestry search to complete first.
1848					continue;
1849				}
1850				let new_common_number =
1851					if peer.best_number >= number { number } else { peer.best_number };
1852				trace!(
1853					target: LOG_TARGET,
1854					"Updating peer {} info, ours={}, common={}->{}, their best={}",
1855					n,
1856					number,
1857					peer.common_number,
1858					new_common_number,
1859					peer.best_number,
1860				);
1861				peer.common_number = new_common_number;
1862			}
1863		}
1864		self.allowed_requests.set_all();
1865	}
1866
1867	/// Restart the sync process. This will reset all pending block requests and return an iterator
1868	/// of new block requests to make to peers. Peers that were downloading finality data (i.e.
1869	/// their state was `DownloadingJustification`) are unaffected and will stay in the same state.
1870	fn restart(&mut self) {
1871		self.blocks.clear();
1872		if let Err(e) = self.reset_sync_start_point() {
1873			warn!(target: LOG_TARGET, "๐Ÿ’”  Unable to restart sync: {e}");
1874		}
1875		self.allowed_requests.set_all();
1876		debug!(
1877			target: LOG_TARGET,
1878			"Restarted with {} ({})",
1879			self.best_queued_number,
1880			self.best_queued_hash,
1881		);
1882		let old_peers = std::mem::take(&mut self.peers);
1883
1884		old_peers.into_iter().for_each(|(peer_id, mut peer_sync)| {
1885			match peer_sync.state {
1886				PeerSyncState::DownloadingJustification(_) => {
1887					// Peers that were downloading justifications
1888					// should be kept in that state.
1889					// We make sure our common number is at least something we have.
1890					trace!(
1891						target: LOG_TARGET,
1892						"Keeping peer {} after restart, updating common number from={} => to={} (our best).",
1893						peer_id,
1894						peer_sync.common_number,
1895						self.best_queued_number,
1896					);
1897					peer_sync.common_number = self.best_queued_number;
1898					self.peers.insert(peer_id, peer_sync);
1899				},
1900				_ => {
1901					self.cancel_peer_request(peer_id, peer_sync.state);
1902					self.add_peer(peer_id, peer_sync.best_hash, peer_sync.best_number);
1903				},
1904			}
1905		});
1906	}
1907
1908	/// Find a block to start sync from. If we sync with state, that's the latest block we have
1909	/// state for.
1910	fn reset_sync_start_point(&mut self) -> Result<(), ClientError> {
1911		let info = self.client.info();
1912		debug!(target: LOG_TARGET, "Restarting sync with client info {info:?}");
1913
1914		if matches!(self.mode, ChainSyncMode::LightState { .. }) && info.finalized_state.is_some() {
1915			warn!(
1916				target: LOG_TARGET,
1917				"Can't use fast sync mode with a partially synced database. Reverting to full sync mode."
1918			);
1919			self.mode = ChainSyncMode::Full;
1920		}
1921
1922		self.import_existing = false;
1923		self.best_queued_hash = info.best_hash;
1924		self.best_queued_number = info.best_number;
1925
1926		if self.mode == ChainSyncMode::Full &&
1927			self.client.block_status(info.best_hash)? != BlockStatus::InChainWithState
1928		{
1929			self.import_existing = true;
1930			// Latest state is missing, start with the last finalized state or genesis instead.
1931			if let Some((hash, number)) = info.finalized_state {
1932				debug!(target: LOG_TARGET, "Starting from finalized state #{number}");
1933				self.best_queued_hash = hash;
1934				self.best_queued_number = number;
1935			} else {
1936				debug!(target: LOG_TARGET, "Restarting from genesis");
1937				self.best_queued_hash = Default::default();
1938				self.best_queued_number = Zero::zero();
1939			}
1940		}
1941
1942		// The client is the source of truth for the gap. Rebuild the gap sync state from it, or
1943		// drop ours if the database has already closed the gap.
1944		let old_gap = self.gap_sync.take().map(|g| (g.best_queued_number, g.target));
1945		if let Some(BlockGap { start, end, .. }) = info.block_gap {
1946			debug!(target: LOG_TARGET, "Starting gap sync #{start} - #{end} (old gap best and target: {old_gap:?})");
1947			self.gap_sync = Some(GapSync {
1948				best_queued_number: start - One::one(),
1949				target: end,
1950				blocks: BlockCollection::with_metrics(
1951					self.metrics.as_ref().map(|m| m.block_collection.clone()),
1952				),
1953				stats: GapSyncStats::new(),
1954			});
1955		} else if let Some((best, target)) = old_gap {
1956			debug!(
1957				target: LOG_TARGET,
1958				"Block gap is closed in the database, dropping gap sync state (best: #{best}, target: #{target})",
1959			);
1960			if let Some(metrics) = &self.metrics {
1961				metrics.gap_oldest_required_body.set(0);
1962			}
1963		}
1964		trace!(
1965			target: LOG_TARGET,
1966			"Restarted sync at #{} ({:?})",
1967			self.best_queued_number,
1968			self.best_queued_hash,
1969		);
1970		Ok(())
1971	}
1972
1973	/// What is the status of the block corresponding to the given hash?
1974	fn block_status(&self, hash: &B::Hash) -> Result<BlockStatus, ClientError> {
1975		if self.queue_blocks.contains(hash) {
1976			return Ok(BlockStatus::Queued);
1977		}
1978		self.client.block_status(*hash)
1979	}
1980
1981	/// Is the block corresponding to the given hash known?
1982	fn is_known(&self, hash: &B::Hash) -> bool {
1983		self.block_status(hash).ok().map_or(false, |s| s != BlockStatus::Unknown)
1984	}
1985
1986	/// Is any peer downloading the given hash?
1987	fn is_already_downloading(&self, hash: &B::Hash) -> bool {
1988		self.peers
1989			.iter()
1990			.any(|(_, p)| p.state == PeerSyncState::DownloadingStale(*hash))
1991	}
1992
1993	/// Get the set of downloaded blocks that are ready to be queued for import.
1994	fn ready_blocks(&mut self) -> Vec<IncomingBlock<B>> {
1995		self.blocks
1996			.ready_blocks(self.best_queued_number + One::one())
1997			.into_iter()
1998			.map(|block_data| {
1999				let justifications = block_data
2000					.block
2001					.justifications
2002					.or_else(|| legacy_justification_mapping(block_data.block.justification));
2003				IncomingBlock {
2004					hash: block_data.block.hash,
2005					header: block_data.block.header,
2006					body: block_data.block.body,
2007					justifications,
2008					origin: block_data.origin,
2009					allow_missing_state: true,
2010					import_existing: self.import_existing,
2011					skip_execution: self.skip_execution(),
2012					state: None,
2013				}
2014			})
2015			.collect()
2016	}
2017
2018	/// Get justification requests scheduled by sync to be sent out.
2019	fn justification_requests(&mut self) -> Vec<(PeerId, BlockRequest<B>)> {
2020		let peers = &mut self.peers;
2021		let mut matcher = self.extra_justifications.matcher();
2022		std::iter::from_fn(move || {
2023			if let Some((peer, request)) = matcher.next(peers) {
2024				peers
2025					.get_mut(&peer)
2026					.expect(
2027						"`Matcher::next` guarantees the `PeerId` comes from the given peers; qed",
2028					)
2029					.state = PeerSyncState::DownloadingJustification(request.0);
2030				let req = BlockRequest::<B> {
2031					id: 0,
2032					fields: BlockAttributes::JUSTIFICATION,
2033					from: FromBlock::Hash(request.0),
2034					direction: Direction::Ascending,
2035					max: Some(1),
2036				};
2037				Some((peer, req))
2038			} else {
2039				None
2040			}
2041		})
2042		.collect()
2043	}
2044
2045	/// Block attributes for gap requests, plus the body cutoff: bodies are required for
2046	/// gap blocks above the cutoff and stripped from ranges entirely at or below it.
2047	/// Recomputed every scheduling pass so the cutoff follows finality.
2048	fn gap_request_attributes(
2049		&self,
2050		finalized_number: NumberFor<B>,
2051	) -> (BlockAttributes, Option<NumberFor<B>>) {
2052		let attrs = required_block_attributes();
2053		match self.gap_sync_body_policy {
2054			GapSyncBodyPolicy::HeadersOnly => (attrs & !BlockAttributes::BODY, None),
2055			GapSyncBodyPolicy::All => (attrs, None),
2056			GapSyncBodyPolicy::BodiesWithinWindow(window) => {
2057				// The gap is created by importing a finalized block right above it,
2058				// so `gap.target + 1` is a lower bound for the finalized number even
2059				// while the client's finality info still lags right after warp sync.
2060				let anchor = self.gap_sync.as_ref().map_or(finalized_number, |gap| {
2061					std::cmp::max(finalized_number, gap.target + One::one())
2062				});
2063				(attrs, Some(anchor.saturating_sub(window.into())))
2064			},
2065		}
2066	}
2067
2068	/// Get block requests scheduled by sync to be sent out.
2069	fn block_requests(&mut self) -> Vec<(PeerId, BlockRequest<B>)> {
2070		if self.allowed_requests.is_empty() || self.state_sync.is_some() {
2071			return Vec::new();
2072		}
2073
2074		if self.queue_blocks.len() > MAX_IMPORTING_BLOCKS {
2075			trace!(target: LOG_TARGET, "Too many blocks in the queue.");
2076			return Vec::new();
2077		}
2078		let is_major_syncing = self.status().state.is_major_syncing();
2079		let finalized_number = self.client.info().finalized_number;
2080		let (gap_attrs, gap_body_cutoff) = self.gap_request_attributes(finalized_number);
2081		if let (Some(metrics), Some(cutoff), Some(gap)) =
2082			(self.metrics.as_ref(), gap_body_cutoff, self.gap_sync.as_ref())
2083		{
2084			// The oldest gap block still requiring a body: the lowest not-yet-queued
2085			// block, clamped from below by the cutoff.
2086			let oldest_required = std::cmp::max(gap.best_queued_number, cutoff) + One::one();
2087			metrics.gap_oldest_required_body.set(if oldest_required <= gap.target {
2088				oldest_required.saturated_into::<u64>()
2089			} else {
2090				0
2091			});
2092		}
2093		let blocks = &mut self.blocks;
2094		let fork_targets = &mut self.fork_targets;
2095		let last_finalized = std::cmp::min(self.best_queued_number, finalized_number);
2096		let best_queued = self.best_queued_number;
2097		let client = &self.client;
2098		let queue_blocks = &self.queue_blocks;
2099		let allowed_requests = self.allowed_requests.clone();
2100		let max_parallel = if is_major_syncing { 1 } else { self.max_parallel_downloads };
2101		let max_blocks_per_request = self.max_blocks_per_request;
2102		let gap_sync = &mut self.gap_sync;
2103		let disconnected_peers = &mut self.disconnected_peers;
2104		let metrics = self.metrics.as_ref();
2105		let requests = self
2106			.peers
2107			.iter_mut()
2108			.filter_map(move |(&id, peer)| {
2109				if !peer.state.is_available() ||
2110					!allowed_requests.contains(&id) ||
2111					!disconnected_peers.is_peer_available(&id)
2112				{
2113					return None;
2114				}
2115
2116				// If our best queued is more than `MAX_BLOCKS_TO_LOOK_BACKWARDS` blocks away from
2117				// the common number, the peer best number is higher than our best queued and the
2118				// common number is smaller than the last finalized block number, we should do an
2119				// ancestor search to find a better common block. If the queue is full we wait till
2120				// all blocks are imported though.
2121				if best_queued.saturating_sub(peer.common_number) >
2122					MAX_BLOCKS_TO_LOOK_BACKWARDS.into() &&
2123					best_queued < peer.best_number &&
2124					peer.common_number < last_finalized &&
2125					queue_blocks.len() <= MAJOR_SYNC_BLOCKS as usize
2126				{
2127					trace!(
2128						target: LOG_TARGET,
2129						"Peer {:?} common block {} too far behind of our best {}. Starting ancestry search.",
2130						id,
2131						peer.common_number,
2132						best_queued,
2133					);
2134					let current = std::cmp::min(peer.best_number, best_queued);
2135					peer.state = PeerSyncState::AncestorSearch {
2136						current,
2137						start: best_queued,
2138						state: AncestorSearchState::ExponentialBackoff(One::one()),
2139					};
2140					Some((id, ancestry_request::<B>(current)))
2141				} else if let Some((range, req)) = peer_block_request(
2142					&id,
2143					peer,
2144					blocks,
2145					required_block_attributes(),
2146					max_parallel,
2147					max_blocks_per_request,
2148					last_finalized,
2149					best_queued,
2150				) {
2151					peer.state = PeerSyncState::DownloadingNew(range.start);
2152					trace!(
2153						target: LOG_TARGET,
2154						"New block request for {}, (best:{}, common:{}) {:?}",
2155						id,
2156						peer.best_number,
2157						peer.common_number,
2158						req,
2159					);
2160					Some((id, req))
2161				} else if let Some((hash, req)) = fork_sync_request(
2162					&id,
2163					fork_targets,
2164					best_queued,
2165					last_finalized,
2166					required_block_attributes(),
2167					|hash| {
2168						if queue_blocks.contains(hash) {
2169							BlockStatus::Queued
2170						} else {
2171							client.block_status(*hash).unwrap_or(BlockStatus::Unknown)
2172						}
2173					},
2174					max_blocks_per_request,
2175					metrics,
2176				) {
2177					trace!(target: LOG_TARGET, "Downloading fork {hash:?} from {id}");
2178					peer.state = PeerSyncState::DownloadingStale(hash);
2179					Some((id, req))
2180				} else if let Some((range, req)) = gap_sync.as_mut().and_then(|sync| {
2181					peer_gap_block_request(
2182						&id,
2183						peer,
2184						&mut sync.blocks,
2185						gap_attrs,
2186						gap_body_cutoff,
2187						is_major_syncing,
2188						sync.target,
2189						sync.best_queued_number,
2190						max_blocks_per_request,
2191						metrics,
2192					)
2193				}) {
2194					peer.state = PeerSyncState::DownloadingGap(range.start);
2195					trace!(
2196						target: LOG_TARGET,
2197						"New gap block request for {}, (best:{}, common:{}) {:?}",
2198						id,
2199						peer.best_number,
2200						peer.common_number,
2201						req,
2202					);
2203					Some((id, req))
2204				} else {
2205					None
2206				}
2207			})
2208			.collect::<Vec<_>>();
2209
2210		// Clear the allowed_requests state when sending new block requests
2211		// to prevent multiple inflight block requests from being issued.
2212		if !requests.is_empty() {
2213			self.allowed_requests.take();
2214		}
2215
2216		requests
2217	}
2218
2219	/// Get a state request scheduled by sync to be sent out (if any).
2220	fn state_request(&mut self) -> Option<(PeerId, StateRequest)> {
2221		if self.allowed_requests.is_empty() {
2222			return None;
2223		}
2224		if self.state_sync.is_some() &&
2225			self.peers.iter().any(|(_, peer)| peer.state == PeerSyncState::DownloadingState)
2226		{
2227			// Only one pending state request is allowed.
2228			return None;
2229		}
2230		if let Some(sync) = &self.state_sync {
2231			if sync.is_complete() {
2232				return None;
2233			}
2234
2235			for (id, peer) in self.peers.iter_mut() {
2236				if peer.state.is_available() &&
2237					peer.common_number >= sync.target_number() &&
2238					self.disconnected_peers.is_peer_available(&id)
2239				{
2240					peer.state = PeerSyncState::DownloadingState;
2241					let request = sync.next_request();
2242					trace!(target: LOG_TARGET, "New StateRequest for {}: {:?}", id, request);
2243					self.allowed_requests.clear();
2244					return Some((*id, request));
2245				}
2246			}
2247		}
2248		None
2249	}
2250
2251	#[must_use]
2252	fn on_state_data(&mut self, peer_id: &PeerId, response: &[u8]) -> Result<(), BadPeer> {
2253		let response = match StateResponse::decode(response) {
2254			Ok(response) => response,
2255			Err(error) => {
2256				debug!(
2257					target: LOG_TARGET,
2258					"Failed to decode state response from peer {peer_id:?}: {error:?}.",
2259				);
2260
2261				return Err(BadPeer(*peer_id, rep::BAD_RESPONSE));
2262			},
2263		};
2264
2265		if let Some(peer) = self.peers.get_mut(peer_id) {
2266			if let PeerSyncState::DownloadingState = peer.state {
2267				peer.state = PeerSyncState::Available;
2268				self.allowed_requests.set_all();
2269			}
2270		}
2271		let import_result = if let Some(sync) = &mut self.state_sync {
2272			debug!(
2273				target: LOG_TARGET,
2274				"Importing state data from {} with {} keys, {} proof nodes.",
2275				peer_id,
2276				response.entries.len(),
2277				response.proof.len(),
2278			);
2279			sync.import(response)
2280		} else {
2281			debug!(target: LOG_TARGET, "Ignored obsolete state response from {peer_id}");
2282			return Err(BadPeer(*peer_id, rep::NOT_REQUESTED));
2283		};
2284
2285		match import_result {
2286			ImportResult::Import(hash, header, state, body, justifications) => {
2287				let origin = BlockOrigin::NetworkInitialSync;
2288				let block = IncomingBlock {
2289					hash,
2290					header: Some(header),
2291					body,
2292					justifications,
2293					origin: None,
2294					allow_missing_state: true,
2295					import_existing: true,
2296					skip_execution: self.skip_execution(),
2297					state: Some(state),
2298				};
2299				debug!(target: LOG_TARGET, "State download is complete. Import is queued");
2300				self.actions.push(SyncingAction::ImportBlocks { origin, blocks: vec![block] });
2301				Ok(())
2302			},
2303			ImportResult::Continue => Ok(()),
2304			ImportResult::BadResponse => {
2305				debug!(target: LOG_TARGET, "Bad state data received from {peer_id}");
2306				Err(BadPeer(*peer_id, rep::BAD_BLOCK))
2307			},
2308		}
2309	}
2310
2311	fn attempt_state_sync(
2312		&mut self,
2313		finalized_hash: B::Hash,
2314		finalized_number: NumberFor<B>,
2315		skip_proofs: bool,
2316	) {
2317		let mut heads: Vec<_> = self.peers.values().map(|peer| peer.best_number).collect();
2318		heads.sort();
2319		let median = heads[heads.len() / 2];
2320		if finalized_number + STATE_SYNC_FINALITY_THRESHOLD.saturated_into() >= median {
2321			if let Ok(Some(header)) = self.client.header(finalized_hash) {
2322				log::debug!(
2323					target: LOG_TARGET,
2324					"Starting state sync for #{finalized_number} ({finalized_hash})",
2325				);
2326				self.state_sync =
2327					Some(StateSync::new(self.client.clone(), header, None, None, skip_proofs));
2328				self.allowed_requests.set_all();
2329			} else {
2330				log::error!(
2331					target: LOG_TARGET,
2332					"Failed to start state sync: header for finalized block \
2333					  #{finalized_number} ({finalized_hash}) is not available",
2334				);
2335				debug_assert!(false);
2336			}
2337		}
2338	}
2339
2340	/// A version of `actions()` that doesn't schedule extra requests. For testing only.
2341	#[cfg(test)]
2342	#[must_use]
2343	fn take_actions(&mut self) -> impl Iterator<Item = SyncingAction<B>> {
2344		std::mem::take(&mut self.actions).into_iter()
2345	}
2346}
2347
2348// This is purely during a backwards compatible transitionary period and should be removed
2349// once we can assume all nodes can send and receive multiple Justifications
2350// The ID tag is hardcoded here to avoid depending on the GRANDPA crate.
2351// See: https://github.com/paritytech/substrate/issues/8172
2352fn legacy_justification_mapping(
2353	justification: Option<EncodedJustification>,
2354) -> Option<Justifications> {
2355	justification.map(|just| (*b"FRNK", just).into())
2356}
2357
2358/// Request the ancestry for a block. Sends a request for header and justification for the given
2359/// block number. Used during ancestry search.
2360fn ancestry_request<B: BlockT>(block: NumberFor<B>) -> BlockRequest<B> {
2361	BlockRequest::<B> {
2362		id: 0,
2363		fields: BlockAttributes::HEADER | BlockAttributes::JUSTIFICATION,
2364		from: FromBlock::Number(block),
2365		direction: Direction::Ascending,
2366		max: Some(1),
2367	}
2368}
2369
2370/// The ancestor search state expresses which algorithm, and its stateful parameters, we are using
2371/// to try to find an ancestor block
2372#[derive(Copy, Clone, Eq, PartialEq, Debug)]
2373pub(crate) enum AncestorSearchState<B: BlockT> {
2374	/// Use exponential backoff to find an ancestor, then switch to binary search.
2375	/// We keep track of the exponent.
2376	ExponentialBackoff(NumberFor<B>),
2377	/// Using binary search to find the best ancestor.
2378	/// We keep track of left and right bounds.
2379	BinarySearch(NumberFor<B>, NumberFor<B>),
2380}
2381
2382/// This function handles the ancestor search strategy used. The goal is to find a common point
2383/// that both our chains agree on that is as close to the tip as possible.
2384/// The way this works is we first have an exponential backoff strategy, where we try to step
2385/// forward until we find a block hash mismatch. The size of the step doubles each step we take.
2386///
2387/// When we've found a block hash mismatch we then fall back to a binary search between the two
2388/// last known points to find the common block closest to the tip.
2389fn handle_ancestor_search_state<B: BlockT>(
2390	state: &AncestorSearchState<B>,
2391	curr_block_num: NumberFor<B>,
2392	block_hash_match: bool,
2393) -> Option<(AncestorSearchState<B>, NumberFor<B>)> {
2394	let two = <NumberFor<B>>::one() + <NumberFor<B>>::one();
2395	match state {
2396		AncestorSearchState::ExponentialBackoff(next_distance_to_tip) => {
2397			let next_distance_to_tip = *next_distance_to_tip;
2398			if block_hash_match && next_distance_to_tip == One::one() {
2399				// We found the ancestor in the first step so there is no need to execute binary
2400				// search.
2401				return None;
2402			}
2403			if block_hash_match {
2404				let left = curr_block_num;
2405				let right = left + next_distance_to_tip / two;
2406				let middle = left + (right - left) / two;
2407				Some((AncestorSearchState::BinarySearch(left, right), middle))
2408			} else {
2409				let next_block_num =
2410					curr_block_num.checked_sub(&next_distance_to_tip).unwrap_or_else(Zero::zero);
2411				let next_distance_to_tip = next_distance_to_tip * two;
2412				Some((
2413					AncestorSearchState::ExponentialBackoff(next_distance_to_tip),
2414					next_block_num,
2415				))
2416			}
2417		},
2418		AncestorSearchState::BinarySearch(mut left, mut right) => {
2419			if left >= curr_block_num {
2420				return None;
2421			}
2422			if block_hash_match {
2423				left = curr_block_num;
2424			} else {
2425				right = curr_block_num;
2426			}
2427			assert!(right >= left);
2428			let middle = left + (right - left) / two;
2429			if middle == curr_block_num {
2430				None
2431			} else {
2432				Some((AncestorSearchState::BinarySearch(left, right), middle))
2433			}
2434		},
2435	}
2436}
2437
2438/// Get a new block request for the peer if any.
2439fn peer_block_request<B: BlockT>(
2440	id: &PeerId,
2441	peer: &PeerSync<B>,
2442	blocks: &mut BlockCollection<B>,
2443	attrs: BlockAttributes,
2444	max_parallel_downloads: u32,
2445	max_blocks_per_request: u32,
2446	finalized: NumberFor<B>,
2447	best_num: NumberFor<B>,
2448) -> Option<(Range<NumberFor<B>>, BlockRequest<B>)> {
2449	if best_num >= peer.best_number {
2450		// Will be downloaded as alternative fork instead.
2451		return None;
2452	} else if peer.common_number < finalized {
2453		trace!(
2454			target: LOG_TARGET,
2455			"Requesting pre-finalized chain from {:?}, common={}, finalized={}, peer best={}, our best={}",
2456			id, peer.common_number, finalized, peer.best_number, best_num,
2457		);
2458	}
2459	let range = blocks.needed_blocks(
2460		*id,
2461		max_blocks_per_request,
2462		peer.best_number,
2463		peer.common_number,
2464		max_parallel_downloads,
2465		MAX_DOWNLOAD_AHEAD,
2466	)?;
2467
2468	// The end is not part of the range.
2469	let last = range.end.saturating_sub(One::one());
2470
2471	let from = if peer.best_number == last {
2472		FromBlock::Hash(peer.best_hash)
2473	} else {
2474		FromBlock::Number(last)
2475	};
2476
2477	let request = BlockRequest::<B> {
2478		id: 0,
2479		fields: attrs,
2480		from,
2481		direction: Direction::Descending,
2482		max: Some((range.end - range.start).saturated_into::<u32>()),
2483	};
2484
2485	Some((range, request))
2486}
2487
2488/// Get a new gap block request for the peer if any.
2489///
2490/// Bodies are stripped from the request if the whole range is at or below
2491/// `body_cutoff`. A range straddling the cutoff requests bodies for all its blocks
2492/// rather than being split.
2493///
2494/// While the node is major syncing, the cutoff is a stale lower bound of the true one
2495/// (peers may have pruned bodies right above it), so scheduling is clamped to the
2496/// header-only region at or below it until the node has caught up.
2497fn peer_gap_block_request<B: BlockT>(
2498	id: &PeerId,
2499	peer: &PeerSync<B>,
2500	blocks: &mut BlockCollection<B>,
2501	attrs: BlockAttributes,
2502	body_cutoff: Option<NumberFor<B>>,
2503	is_major_syncing: bool,
2504	target: NumberFor<B>,
2505	common_number: NumberFor<B>,
2506	max_blocks_per_request: u32,
2507	metrics: Option<&Metrics>,
2508) -> Option<(Range<NumberFor<B>>, BlockRequest<B>)> {
2509	let mut scheduling_bound = std::cmp::min(peer.best_number, target);
2510	if let Some(cutoff) = body_cutoff.filter(|_| is_major_syncing) {
2511		scheduling_bound = std::cmp::min(scheduling_bound, cutoff);
2512	}
2513	let range = blocks.needed_blocks(
2514		*id,
2515		max_blocks_per_request,
2516		scheduling_bound,
2517		common_number,
2518		1,
2519		MAX_DOWNLOAD_AHEAD,
2520	)?;
2521
2522	// The end is not part of the range.
2523	let last = range.end.saturating_sub(One::one());
2524	let from = FromBlock::Number(last);
2525
2526	let attrs = match body_cutoff {
2527		Some(cutoff) if last <= cutoff => {
2528			if let Some(metrics) = metrics {
2529				metrics.gap_header_only_downgrades.inc();
2530			}
2531			attrs & !BlockAttributes::BODY
2532		},
2533		_ => attrs,
2534	};
2535
2536	let request = BlockRequest::<B> {
2537		id: 0,
2538		fields: attrs,
2539		from,
2540		direction: Direction::Descending,
2541		max: Some((range.end - range.start).saturated_into::<u32>()),
2542	};
2543	Some((range, request))
2544}
2545
2546/// Get pending fork sync targets for a peer.
2547fn fork_sync_request<B: BlockT>(
2548	id: &PeerId,
2549	fork_targets: &mut HashMap<B::Hash, ForkTarget<B>>,
2550	best_num: NumberFor<B>,
2551	finalized: NumberFor<B>,
2552	attributes: BlockAttributes,
2553	check_block: impl Fn(&B::Hash) -> BlockStatus,
2554	max_blocks_per_request: u32,
2555	metrics: Option<&Metrics>,
2556) -> Option<(B::Hash, BlockRequest<B>)> {
2557	fork_targets.retain(|hash, r| {
2558		if r.number <= finalized {
2559			trace!(
2560				target: LOG_TARGET,
2561				"Removed expired fork sync request {:?} (#{})",
2562				hash,
2563				r.number,
2564			);
2565			return false;
2566		}
2567		if check_block(hash) != BlockStatus::Unknown {
2568			trace!(
2569				target: LOG_TARGET,
2570				"Removed obsolete fork sync request {:?} (#{})",
2571				hash,
2572				r.number,
2573			);
2574			return false;
2575		}
2576		true
2577	});
2578	if let Some(metrics) = metrics {
2579		metrics.fork_targets.set(fork_targets.len().try_into().unwrap_or(u64::MAX));
2580	}
2581	for (hash, r) in fork_targets {
2582		if !r.peers.contains(&id) {
2583			continue;
2584		}
2585		// Download the fork only if it is behind or not too far ahead our tip of the chain
2586		// Otherwise it should be downloaded in full sync mode.
2587		if r.number <= best_num ||
2588			(r.number - best_num).saturated_into::<u32>() < max_blocks_per_request as u32
2589		{
2590			let parent_status = r.parent_hash.as_ref().map_or(BlockStatus::Unknown, check_block);
2591			let count = if parent_status == BlockStatus::Unknown {
2592				(r.number - finalized).saturated_into::<u32>() // up to the last finalized block
2593			} else {
2594				// request only single block
2595				1
2596			};
2597			trace!(
2598				target: LOG_TARGET,
2599				"Downloading requested fork {hash:?} from {id}, {count} blocks",
2600			);
2601			return Some((
2602				*hash,
2603				BlockRequest::<B> {
2604					id: 0,
2605					fields: attributes,
2606					from: FromBlock::Hash(*hash),
2607					direction: Direction::Descending,
2608					max: Some(count),
2609				},
2610			));
2611		} else {
2612			trace!(target: LOG_TARGET, "Fork too far in the future: {:?} (#{})", hash, r.number);
2613		}
2614	}
2615	None
2616}
2617
2618/// Returns `true` if the given `block` is a descendent of `base`.
2619fn is_descendent_of<Block, T>(
2620	client: &T,
2621	base: &Block::Hash,
2622	block: &Block::Hash,
2623) -> sp_blockchain::Result<bool>
2624where
2625	Block: BlockT,
2626	T: HeaderMetadata<Block, Error = sp_blockchain::Error> + ?Sized,
2627{
2628	if base == block {
2629		return Ok(false);
2630	}
2631
2632	let ancestor = sp_blockchain::lowest_common_ancestor(client, *block, *base)?;
2633
2634	Ok(ancestor.hash == *base)
2635}
2636
2637/// Validate that the given `blocks` are correct.
2638/// Returns the number of the first block in the sequence.
2639///
2640/// It is expected that `blocks` are in ascending order.
2641pub fn validate_blocks<Block: BlockT>(
2642	blocks: &Vec<BlockData<Block>>,
2643	peer_id: &PeerId,
2644	request: Option<BlockRequest<Block>>,
2645) -> Result<Option<NumberFor<Block>>, BadPeer> {
2646	if let Some(request) = request {
2647		if Some(blocks.len() as _) > request.max {
2648			debug!(
2649				target: LOG_TARGET,
2650				"Received more blocks than requested from {}. Expected in maximum {:?}, got {}.",
2651				peer_id,
2652				request.max,
2653				blocks.len(),
2654			);
2655
2656			return Err(BadPeer(*peer_id, rep::NOT_REQUESTED));
2657		}
2658
2659		let block_header =
2660			if request.direction == Direction::Descending { blocks.last() } else { blocks.first() }
2661				.and_then(|b| b.header.as_ref());
2662
2663		let expected_block = block_header.as_ref().map_or(false, |h| match request.from {
2664			FromBlock::Hash(hash) => h.hash() == hash,
2665			FromBlock::Number(n) => h.number() == &n,
2666		});
2667
2668		if !expected_block {
2669			debug!(
2670				target: LOG_TARGET,
2671				"Received block that was not requested. Requested {:?}, got {:?}.",
2672				request.from,
2673				block_header,
2674			);
2675
2676			return Err(BadPeer(*peer_id, rep::NOT_REQUESTED));
2677		}
2678
2679		if request.fields.contains(BlockAttributes::HEADER) &&
2680			blocks.iter().any(|b| b.header.is_none())
2681		{
2682			trace!(
2683				target: LOG_TARGET,
2684				"Missing requested header for a block in response from {peer_id}.",
2685			);
2686
2687			return Err(BadPeer(*peer_id, rep::BAD_RESPONSE));
2688		}
2689
2690		if request.fields.contains(BlockAttributes::BODY) && blocks.iter().any(|b| b.body.is_none())
2691		{
2692			trace!(
2693				target: LOG_TARGET,
2694				"Missing requested body for a block in response from {peer_id}.",
2695			);
2696
2697			return Err(BadPeer(*peer_id, rep::BAD_RESPONSE));
2698		}
2699	}
2700
2701	for b in blocks {
2702		if let Some(header) = &b.header {
2703			let hash = header.hash();
2704			if hash != b.hash {
2705				debug!(
2706					target: LOG_TARGET,
2707					"Bad header received from {}. Expected hash {:?}, got {:?}",
2708					peer_id,
2709					b.hash,
2710					hash,
2711				);
2712				return Err(BadPeer(*peer_id, rep::BAD_BLOCK));
2713			}
2714		}
2715	}
2716
2717	Ok(blocks.first().and_then(|b| b.header.as_ref()).map(|h| *h.number()))
2718}