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