sc_network_sync/strategy/
warp.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//! Warp syncing strategy. Bootstraps chain by downloading warp proofs and state.
20
21pub use sp_consensus_grandpa::{AuthorityList, SetId};
22
23use crate::{
24	strategy::{chain_sync::validate_blocks, disconnected_peers::DisconnectedPeers},
25	types::{BadPeer, SyncState, SyncStatus},
26	LOG_TARGET,
27};
28use codec::{Decode, Encode};
29use log::{debug, error, trace, warn};
30use sc_network::ProtocolName;
31use sc_network_common::sync::message::{
32	BlockAnnounce, BlockAttributes, BlockData, BlockRequest, Direction, FromBlock,
33};
34use sc_network_types::PeerId;
35use sp_blockchain::HeaderBackend;
36use sp_runtime::{
37	traits::{Block as BlockT, Header, NumberFor, Zero},
38	Justifications, SaturatedConversion,
39};
40use std::{collections::HashMap, fmt, sync::Arc};
41
42/// Number of peers that need to be connected before warp sync is started.
43const MIN_PEERS_TO_START_WARP_SYNC: usize = 3;
44
45/// Scale-encoded warp sync proof response.
46pub struct EncodedProof(pub Vec<u8>);
47
48/// Warp sync request
49#[derive(Encode, Decode, Debug, Clone)]
50pub struct WarpProofRequest<B: BlockT> {
51	/// Start collecting proofs from this block.
52	pub begin: B::Hash,
53}
54
55/// Proof verification result.
56pub enum VerificationResult<Block: BlockT> {
57	/// Proof is valid, but the target was not reached.
58	Partial(SetId, AuthorityList, Block::Hash),
59	/// Target finality is proved.
60	Complete(SetId, AuthorityList, Block::Header),
61}
62
63/// Warp sync backend. Handles retrieving and verifying warp sync proofs.
64pub trait WarpSyncProvider<Block: BlockT>: Send + Sync {
65	/// Generate proof starting at given block hash. The proof is accumulated until maximum proof
66	/// size is reached.
67	fn generate(
68		&self,
69		start: Block::Hash,
70	) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>>;
71	/// Verify warp proof against current set of authorities.
72	fn verify(
73		&self,
74		proof: &EncodedProof,
75		set_id: SetId,
76		authorities: AuthorityList,
77	) -> Result<VerificationResult<Block>, Box<dyn std::error::Error + Send + Sync>>;
78	/// Get current list of authorities. This is supposed to be genesis authorities when starting
79	/// sync.
80	fn current_authorities(&self) -> AuthorityList;
81}
82
83mod rep {
84	use sc_network::ReputationChange as Rep;
85
86	/// Unexpected response received form a peer
87	pub const UNEXPECTED_RESPONSE: Rep = Rep::new(-(1 << 29), "Unexpected response");
88
89	/// Peer provided invalid warp proof data
90	pub const BAD_WARP_PROOF: Rep = Rep::new(-(1 << 29), "Bad warp proof");
91
92	/// Peer did not provide us with advertised block data.
93	pub const NO_BLOCK: Rep = Rep::new(-(1 << 29), "No requested block data");
94
95	/// Reputation change for peers which send us non-requested block data.
96	pub const NOT_REQUESTED: Rep = Rep::new(-(1 << 29), "Not requested block data");
97
98	/// Reputation change for peers which send us a block which we fail to verify.
99	pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 29), "Block verification failed");
100}
101
102/// Reported warp sync phase.
103#[derive(Clone, Eq, PartialEq, Debug)]
104pub enum WarpSyncPhase<Block: BlockT> {
105	/// Waiting for peers to connect.
106	AwaitingPeers { required_peers: usize },
107	/// Downloading and verifying grandpa warp proofs.
108	DownloadingWarpProofs,
109	/// Downloading target block.
110	DownloadingTargetBlock,
111	/// Downloading state data.
112	DownloadingState,
113	/// Importing state.
114	ImportingState,
115	/// Downloading block history.
116	DownloadingBlocks(NumberFor<Block>),
117	/// Warp sync is complete.
118	Complete,
119}
120
121impl<Block: BlockT> fmt::Display for WarpSyncPhase<Block> {
122	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
123		match self {
124			Self::AwaitingPeers { required_peers } =>
125				write!(f, "Waiting for {required_peers} peers to be connected"),
126			Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"),
127			Self::DownloadingTargetBlock => write!(f, "Downloading target block"),
128			Self::DownloadingState => write!(f, "Downloading state"),
129			Self::ImportingState => write!(f, "Importing state"),
130			Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n),
131			Self::Complete => write!(f, "Warp sync is complete"),
132		}
133	}
134}
135
136/// Reported warp sync progress.
137#[derive(Clone, Eq, PartialEq, Debug)]
138pub struct WarpSyncProgress<Block: BlockT> {
139	/// Estimated download percentage.
140	pub phase: WarpSyncPhase<Block>,
141	/// Total bytes downloaded so far.
142	pub total_bytes: u64,
143}
144
145/// Warp sync configuration as accepted by [`WarpSync`].
146pub enum WarpSyncConfig<Block: BlockT> {
147	/// Standard warp sync for the chain.
148	WithProvider(Arc<dyn WarpSyncProvider<Block>>),
149	/// Skip downloading proofs and use provided header of the state that should be downloaded.
150	///
151	/// It is expected that the header provider ensures that the header is trusted.
152	WithTarget(<Block as BlockT>::Header),
153}
154
155/// Warp sync phase used by warp sync state machine.
156enum Phase<B: BlockT> {
157	/// Waiting for enough peers to connect.
158	WaitingForPeers { warp_sync_provider: Arc<dyn WarpSyncProvider<B>> },
159	/// Downloading warp proofs.
160	WarpProof {
161		set_id: SetId,
162		authorities: AuthorityList,
163		last_hash: B::Hash,
164		warp_sync_provider: Arc<dyn WarpSyncProvider<B>>,
165	},
166	/// Downloading target block.
167	TargetBlock(B::Header),
168	/// Warp sync is complete.
169	Complete,
170}
171
172enum PeerState {
173	Available,
174	DownloadingProofs,
175	DownloadingTargetBlock,
176}
177
178impl PeerState {
179	fn is_available(&self) -> bool {
180		matches!(self, PeerState::Available)
181	}
182}
183
184struct Peer<B: BlockT> {
185	best_number: NumberFor<B>,
186	state: PeerState,
187}
188
189/// Action that should be performed on [`WarpSync`]'s behalf.
190pub enum WarpSyncAction<B: BlockT> {
191	/// Send warp proof request to peer.
192	SendWarpProofRequest {
193		peer_id: PeerId,
194		protocol_name: ProtocolName,
195		request: WarpProofRequest<B>,
196	},
197	/// Send block request to peer. Always implies dropping a stale block request to the same peer.
198	SendBlockRequest { peer_id: PeerId, request: BlockRequest<B> },
199	/// Disconnect and report peer.
200	DropPeer(BadPeer),
201	/// Warp sync has finished.
202	Finished,
203}
204
205pub struct WarpSyncResult<B: BlockT> {
206	pub target_header: B::Header,
207	pub target_body: Option<Vec<B::Extrinsic>>,
208	pub target_justifications: Option<Justifications>,
209}
210
211/// Warp sync state machine. Accumulates warp proofs and state.
212pub struct WarpSync<B: BlockT, Client> {
213	phase: Phase<B>,
214	client: Arc<Client>,
215	total_proof_bytes: u64,
216	total_state_bytes: u64,
217	peers: HashMap<PeerId, Peer<B>>,
218	disconnected_peers: DisconnectedPeers,
219	protocol_name: Option<ProtocolName>,
220	actions: Vec<WarpSyncAction<B>>,
221	result: Option<WarpSyncResult<B>>,
222}
223
224impl<B, Client> WarpSync<B, Client>
225where
226	B: BlockT,
227	Client: HeaderBackend<B> + 'static,
228{
229	/// Create a new instance. When passing a warp sync provider we will be checking for proof and
230	/// authorities. Alternatively we can pass a target block when we want to skip downloading
231	/// proofs, in this case we will continue polling until the target block is known.
232	pub fn new(
233		client: Arc<Client>,
234		warp_sync_config: WarpSyncConfig<B>,
235		protocol_name: Option<ProtocolName>,
236	) -> Self {
237		if client.info().finalized_state.is_some() {
238			error!(
239				target: LOG_TARGET,
240				"Can't use warp sync mode with a partially synced database. Reverting to full sync mode."
241			);
242			return Self {
243				client,
244				phase: Phase::Complete,
245				total_proof_bytes: 0,
246				total_state_bytes: 0,
247				peers: HashMap::new(),
248				disconnected_peers: DisconnectedPeers::new(),
249				protocol_name,
250				actions: vec![WarpSyncAction::Finished],
251				result: None,
252			}
253		}
254
255		let phase = match warp_sync_config {
256			WarpSyncConfig::WithProvider(warp_sync_provider) =>
257				Phase::WaitingForPeers { warp_sync_provider },
258			WarpSyncConfig::WithTarget(target_header) => Phase::TargetBlock(target_header),
259		};
260
261		Self {
262			client,
263			phase,
264			total_proof_bytes: 0,
265			total_state_bytes: 0,
266			peers: HashMap::new(),
267			disconnected_peers: DisconnectedPeers::new(),
268			protocol_name,
269			actions: Vec::new(),
270			result: None,
271		}
272	}
273
274	/// Notify that a new peer has connected.
275	pub fn add_peer(&mut self, peer_id: PeerId, _best_hash: B::Hash, best_number: NumberFor<B>) {
276		self.peers.insert(peer_id, Peer { best_number, state: PeerState::Available });
277
278		self.try_to_start_warp_sync();
279	}
280
281	/// Notify that a peer has disconnected.
282	pub fn remove_peer(&mut self, peer_id: &PeerId) {
283		if let Some(state) = self.peers.remove(peer_id) {
284			if !state.state.is_available() {
285				if let Some(bad_peer) =
286					self.disconnected_peers.on_disconnect_during_request(*peer_id)
287				{
288					self.actions.push(WarpSyncAction::DropPeer(bad_peer));
289				}
290			}
291		}
292	}
293
294	/// Submit a validated block announcement.
295	///
296	/// Returns new best hash & best number of the peer if they are updated.
297	#[must_use]
298	pub fn on_validated_block_announce(
299		&mut self,
300		is_best: bool,
301		peer_id: PeerId,
302		announce: &BlockAnnounce<B::Header>,
303	) -> Option<(B::Hash, NumberFor<B>)> {
304		is_best.then_some({
305			let best_number = *announce.header.number();
306			let best_hash = announce.header.hash();
307			if let Some(ref mut peer) = self.peers.get_mut(&peer_id) {
308				peer.best_number = best_number;
309			}
310			// Let `SyncingEngine` know that we should update the peer info.
311			(best_hash, best_number)
312		})
313	}
314
315	/// Start warp sync as soon as we have enough peers.
316	fn try_to_start_warp_sync(&mut self) {
317		let Phase::WaitingForPeers { warp_sync_provider } = &self.phase else { return };
318
319		if self.peers.len() < MIN_PEERS_TO_START_WARP_SYNC {
320			return
321		}
322
323		self.phase = Phase::WarpProof {
324			set_id: 0,
325			authorities: warp_sync_provider.current_authorities(),
326			last_hash: self.client.info().genesis_hash,
327			warp_sync_provider: Arc::clone(warp_sync_provider),
328		};
329		trace!(target: LOG_TARGET, "Started warp sync with {} peers.", self.peers.len());
330	}
331
332	/// Process warp proof response.
333	pub fn on_warp_proof_response(&mut self, peer_id: &PeerId, response: EncodedProof) {
334		if let Some(peer) = self.peers.get_mut(peer_id) {
335			peer.state = PeerState::Available;
336		}
337
338		let Phase::WarpProof { set_id, authorities, last_hash, warp_sync_provider } =
339			&mut self.phase
340		else {
341			debug!(target: LOG_TARGET, "Unexpected warp proof response");
342			self.actions
343				.push(WarpSyncAction::DropPeer(BadPeer(*peer_id, rep::UNEXPECTED_RESPONSE)));
344			return
345		};
346
347		match warp_sync_provider.verify(&response, *set_id, authorities.clone()) {
348			Err(e) => {
349				debug!(target: LOG_TARGET, "Bad warp proof response: {}", e);
350				self.actions
351					.push(WarpSyncAction::DropPeer(BadPeer(*peer_id, rep::BAD_WARP_PROOF)))
352			},
353			Ok(VerificationResult::Partial(new_set_id, new_authorities, new_last_hash)) => {
354				log::debug!(target: LOG_TARGET, "Verified partial proof, set_id={:?}", new_set_id);
355				*set_id = new_set_id;
356				*authorities = new_authorities;
357				*last_hash = new_last_hash;
358				self.total_proof_bytes += response.0.len() as u64;
359			},
360			Ok(VerificationResult::Complete(new_set_id, _, header)) => {
361				log::debug!(
362					target: LOG_TARGET,
363					"Verified complete proof, set_id={:?}. Continuing with target block download: {} ({}).",
364					new_set_id,
365					header.hash(),
366					header.number(),
367				);
368				self.total_proof_bytes += response.0.len() as u64;
369				self.phase = Phase::TargetBlock(header);
370			},
371		}
372	}
373
374	/// Process (target) block response.
375	pub fn on_block_response(
376		&mut self,
377		peer_id: PeerId,
378		request: BlockRequest<B>,
379		blocks: Vec<BlockData<B>>,
380	) {
381		if let Err(bad_peer) = self.on_block_response_inner(peer_id, request, blocks) {
382			self.actions.push(WarpSyncAction::DropPeer(bad_peer));
383		}
384	}
385
386	fn on_block_response_inner(
387		&mut self,
388		peer_id: PeerId,
389		request: BlockRequest<B>,
390		mut blocks: Vec<BlockData<B>>,
391	) -> Result<(), BadPeer> {
392		if let Some(peer) = self.peers.get_mut(&peer_id) {
393			peer.state = PeerState::Available;
394		}
395
396		let Phase::TargetBlock(header) = &mut self.phase else {
397			debug!(target: LOG_TARGET, "Unexpected target block response from {peer_id}");
398			return Err(BadPeer(peer_id, rep::UNEXPECTED_RESPONSE))
399		};
400
401		if blocks.is_empty() {
402			debug!(
403				target: LOG_TARGET,
404				"Downloading target block failed: empty block response from {peer_id}",
405			);
406			return Err(BadPeer(peer_id, rep::NO_BLOCK))
407		}
408
409		if blocks.len() > 1 {
410			debug!(
411				target: LOG_TARGET,
412				"Too many blocks ({}) in warp target block response from {peer_id}",
413				blocks.len(),
414			);
415			return Err(BadPeer(peer_id, rep::NOT_REQUESTED))
416		}
417
418		validate_blocks::<B>(&blocks, &peer_id, Some(request))?;
419
420		let block = blocks.pop().expect("`blocks` len checked above; qed");
421
422		let Some(block_header) = &block.header else {
423			debug!(
424				target: LOG_TARGET,
425				"Downloading target block failed: missing header in response from {peer_id}.",
426			);
427			return Err(BadPeer(peer_id, rep::VERIFICATION_FAIL))
428		};
429
430		if block_header != header {
431			debug!(
432				target: LOG_TARGET,
433				"Downloading target block failed: different header in response from {peer_id}.",
434			);
435			return Err(BadPeer(peer_id, rep::VERIFICATION_FAIL))
436		}
437
438		if block.body.is_none() {
439			debug!(
440				target: LOG_TARGET,
441				"Downloading target block failed: missing body in response from {peer_id}.",
442			);
443			return Err(BadPeer(peer_id, rep::VERIFICATION_FAIL))
444		}
445
446		self.result = Some(WarpSyncResult {
447			target_header: header.clone(),
448			target_body: block.body,
449			target_justifications: block.justifications,
450		});
451		self.phase = Phase::Complete;
452		self.actions.push(WarpSyncAction::Finished);
453		Ok(())
454	}
455
456	/// Reserve a peer for a request assigning `new_state`.
457	fn schedule_next_peer(
458		&mut self,
459		new_state: PeerState,
460		min_best_number: Option<NumberFor<B>>,
461	) -> Option<PeerId> {
462		let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect();
463		if targets.is_empty() {
464			return None
465		}
466		targets.sort();
467		let median = targets[targets.len() / 2];
468		let threshold = std::cmp::max(median, min_best_number.unwrap_or(Zero::zero()));
469		// Find a random peer that is synced as much as peer majority and is above
470		// `min_best_number`.
471		for (peer_id, peer) in self.peers.iter_mut() {
472			if peer.state.is_available() &&
473				peer.best_number >= threshold &&
474				self.disconnected_peers.is_peer_available(peer_id)
475			{
476				peer.state = new_state;
477				return Some(*peer_id)
478			}
479		}
480		None
481	}
482
483	/// Produce warp proof request.
484	fn warp_proof_request(&mut self) -> Option<(PeerId, ProtocolName, WarpProofRequest<B>)> {
485		let Phase::WarpProof { last_hash, .. } = &self.phase else { return None };
486
487		// Copy `last_hash` early to cut the borrowing tie.
488		let begin = *last_hash;
489
490		if self
491			.peers
492			.values()
493			.any(|peer| matches!(peer.state, PeerState::DownloadingProofs))
494		{
495			// Only one warp proof request at a time is possible.
496			return None
497		}
498
499		let peer_id = self.schedule_next_peer(PeerState::DownloadingProofs, None)?;
500		trace!(target: LOG_TARGET, "New WarpProofRequest to {peer_id}, begin hash: {begin}.");
501
502		let request = WarpProofRequest { begin };
503
504		let Some(protocol_name) = self.protocol_name.clone() else {
505			warn!(
506				target: LOG_TARGET,
507				"Trying to send warp sync request when no protocol is configured {request:?}",
508			);
509			return None;
510		};
511
512		Some((peer_id, protocol_name, request))
513	}
514
515	/// Produce target block request.
516	fn target_block_request(&mut self) -> Option<(PeerId, BlockRequest<B>)> {
517		let Phase::TargetBlock(target_header) = &self.phase else { return None };
518
519		if self
520			.peers
521			.values()
522			.any(|peer| matches!(peer.state, PeerState::DownloadingTargetBlock))
523		{
524			// Only one target block request at a time is possible.
525			return None
526		}
527
528		// Cut the borrowing tie.
529		let target_hash = target_header.hash();
530		let target_number = *target_header.number();
531
532		let peer_id =
533			self.schedule_next_peer(PeerState::DownloadingTargetBlock, Some(target_number))?;
534
535		trace!(
536			target: LOG_TARGET,
537			"New target block request to {peer_id}, target: {} ({}).",
538			target_hash,
539			target_number,
540		);
541
542		Some((
543			peer_id,
544			BlockRequest::<B> {
545				id: 0,
546				fields: BlockAttributes::HEADER |
547					BlockAttributes::BODY |
548					BlockAttributes::JUSTIFICATION,
549				from: FromBlock::Hash(target_hash),
550				direction: Direction::Ascending,
551				max: Some(1),
552			},
553		))
554	}
555
556	/// Returns warp sync estimated progress (stage, bytes received).
557	pub fn progress(&self) -> WarpSyncProgress<B> {
558		match &self.phase {
559			Phase::WaitingForPeers { .. } => WarpSyncProgress {
560				phase: WarpSyncPhase::AwaitingPeers {
561					required_peers: MIN_PEERS_TO_START_WARP_SYNC,
562				},
563				total_bytes: self.total_proof_bytes,
564			},
565			Phase::WarpProof { .. } => WarpSyncProgress {
566				phase: WarpSyncPhase::DownloadingWarpProofs,
567				total_bytes: self.total_proof_bytes,
568			},
569			Phase::TargetBlock(_) => WarpSyncProgress {
570				phase: WarpSyncPhase::DownloadingTargetBlock,
571				total_bytes: self.total_proof_bytes,
572			},
573			Phase::Complete => WarpSyncProgress {
574				phase: WarpSyncPhase::Complete,
575				total_bytes: self.total_proof_bytes + self.total_state_bytes,
576			},
577		}
578	}
579
580	/// Get the number of peers known to warp sync.
581	pub fn num_peers(&self) -> usize {
582		self.peers.len()
583	}
584
585	/// Returns the current sync status.
586	pub fn status(&self) -> SyncStatus<B> {
587		SyncStatus {
588			state: match &self.phase {
589				Phase::WaitingForPeers { .. } => SyncState::Downloading { target: Zero::zero() },
590				Phase::WarpProof { .. } => SyncState::Downloading { target: Zero::zero() },
591				Phase::TargetBlock(header) => SyncState::Downloading { target: *header.number() },
592				Phase::Complete => SyncState::Idle,
593			},
594			best_seen_block: match &self.phase {
595				Phase::WaitingForPeers { .. } => None,
596				Phase::WarpProof { .. } => None,
597				Phase::TargetBlock(header) => Some(*header.number()),
598				Phase::Complete => None,
599			},
600			num_peers: self.peers.len().saturated_into(),
601			queued_blocks: 0,
602			state_sync: None,
603			warp_sync: Some(self.progress()),
604		}
605	}
606
607	/// Get actions that should be performed by the owner on [`WarpSync`]'s behalf
608	#[must_use]
609	pub fn actions(&mut self) -> impl Iterator<Item = WarpSyncAction<B>> {
610		let warp_proof_request =
611			self.warp_proof_request().into_iter().map(|(peer_id, protocol_name, request)| {
612				WarpSyncAction::SendWarpProofRequest { peer_id, protocol_name, request }
613			});
614		self.actions.extend(warp_proof_request);
615
616		let target_block_request = self
617			.target_block_request()
618			.into_iter()
619			.map(|(peer_id, request)| WarpSyncAction::SendBlockRequest { peer_id, request });
620		self.actions.extend(target_block_request);
621
622		std::mem::take(&mut self.actions).into_iter()
623	}
624
625	/// Take the result of finished warp sync, returning `None` if the sync was unsuccessful.
626	#[must_use]
627	pub fn take_result(&mut self) -> Option<WarpSyncResult<B>> {
628		self.result.take()
629	}
630}
631
632#[cfg(test)]
633mod test {
634	use super::*;
635	use sc_block_builder::BlockBuilderBuilder;
636	use sp_blockchain::{BlockStatus, Error as BlockchainError, HeaderBackend, Info};
637	use sp_consensus_grandpa::{AuthorityList, SetId};
638	use sp_core::H256;
639	use sp_runtime::traits::{Block as BlockT, Header as HeaderT, NumberFor};
640	use std::{io::ErrorKind, sync::Arc};
641	use substrate_test_runtime_client::{
642		runtime::{Block, Hash},
643		BlockBuilderExt, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
644	};
645
646	mockall::mock! {
647		pub Client<B: BlockT> {}
648
649		impl<B: BlockT> HeaderBackend<B> for Client<B> {
650			fn header(&self, hash: B::Hash) -> Result<Option<B::Header>, BlockchainError>;
651			fn info(&self) -> Info<B>;
652			fn status(&self, hash: B::Hash) -> Result<BlockStatus, BlockchainError>;
653			fn number(
654				&self,
655				hash: B::Hash,
656			) -> Result<Option<<<B as BlockT>::Header as HeaderT>::Number>, BlockchainError>;
657			fn hash(&self, number: NumberFor<B>) -> Result<Option<B::Hash>, BlockchainError>;
658		}
659	}
660
661	mockall::mock! {
662		pub WarpSyncProvider<B: BlockT> {}
663
664		impl<B: BlockT> super::WarpSyncProvider<B> for WarpSyncProvider<B> {
665			fn generate(
666				&self,
667				start: B::Hash,
668			) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>>;
669			fn verify(
670				&self,
671				proof: &EncodedProof,
672				set_id: SetId,
673				authorities: AuthorityList,
674			) -> Result<VerificationResult<B>, Box<dyn std::error::Error + Send + Sync>>;
675			fn current_authorities(&self) -> AuthorityList;
676		}
677	}
678
679	fn mock_client_with_state() -> MockClient<Block> {
680		let mut client = MockClient::<Block>::new();
681		let genesis_hash = Hash::random();
682		client.expect_info().return_once(move || Info {
683			best_hash: genesis_hash,
684			best_number: 0,
685			genesis_hash,
686			finalized_hash: genesis_hash,
687			finalized_number: 0,
688			// We need some finalized state to render warp sync impossible.
689			finalized_state: Some((genesis_hash, 0)),
690			number_leaves: 0,
691			block_gap: None,
692		});
693
694		client
695	}
696
697	fn mock_client_without_state() -> MockClient<Block> {
698		let mut client = MockClient::<Block>::new();
699		let genesis_hash = Hash::random();
700		client.expect_info().returning(move || Info {
701			best_hash: genesis_hash,
702			best_number: 0,
703			genesis_hash,
704			finalized_hash: genesis_hash,
705			finalized_number: 0,
706			finalized_state: None,
707			number_leaves: 0,
708			block_gap: None,
709		});
710
711		client
712	}
713
714	#[test]
715	fn warp_sync_with_provider_for_db_with_finalized_state_is_noop() {
716		let client = mock_client_with_state();
717		let provider = MockWarpSyncProvider::<Block>::new();
718		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
719		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
720
721		// Warp sync instantly finishes
722		let actions = warp_sync.actions().collect::<Vec<_>>();
723		assert_eq!(actions.len(), 1);
724		assert!(matches!(actions[0], WarpSyncAction::Finished));
725
726		// ... with no result.
727		assert!(warp_sync.take_result().is_none());
728	}
729
730	#[test]
731	fn warp_sync_to_target_for_db_with_finalized_state_is_noop() {
732		let client = mock_client_with_state();
733		let config = WarpSyncConfig::WithTarget(<Block as BlockT>::Header::new(
734			1,
735			Default::default(),
736			Default::default(),
737			Default::default(),
738			Default::default(),
739		));
740		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
741
742		// Warp sync instantly finishes
743		let actions = warp_sync.actions().collect::<Vec<_>>();
744		assert_eq!(actions.len(), 1);
745		assert!(matches!(actions[0], WarpSyncAction::Finished));
746
747		// ... with no result.
748		assert!(warp_sync.take_result().is_none());
749	}
750
751	#[test]
752	fn warp_sync_with_provider_for_empty_db_doesnt_finish_instantly() {
753		let client = mock_client_without_state();
754		let provider = MockWarpSyncProvider::<Block>::new();
755		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
756		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
757
758		// No actions are emitted.
759		assert_eq!(warp_sync.actions().count(), 0)
760	}
761
762	#[test]
763	fn warp_sync_to_target_for_empty_db_doesnt_finish_instantly() {
764		let client = mock_client_without_state();
765		let config = WarpSyncConfig::WithTarget(<Block as BlockT>::Header::new(
766			1,
767			Default::default(),
768			Default::default(),
769			Default::default(),
770			Default::default(),
771		));
772		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
773
774		// No actions are emitted.
775		assert_eq!(warp_sync.actions().count(), 0)
776	}
777
778	#[test]
779	fn warp_sync_is_started_only_when_there_is_enough_peers() {
780		let client = mock_client_without_state();
781		let mut provider = MockWarpSyncProvider::<Block>::new();
782		provider
783			.expect_current_authorities()
784			.once()
785			.return_const(AuthorityList::default());
786		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
787		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
788
789		// Warp sync is not started when there is not enough peers.
790		for _ in 0..(MIN_PEERS_TO_START_WARP_SYNC - 1) {
791			warp_sync.add_peer(PeerId::random(), Hash::random(), 10);
792			assert!(matches!(warp_sync.phase, Phase::WaitingForPeers { .. }))
793		}
794
795		// Now we have enough peers and warp sync is started.
796		warp_sync.add_peer(PeerId::random(), Hash::random(), 10);
797		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }))
798	}
799
800	#[test]
801	fn no_peer_is_scheduled_if_no_peers_connected() {
802		let client = mock_client_without_state();
803		let provider = MockWarpSyncProvider::<Block>::new();
804		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
805		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
806
807		assert!(warp_sync.schedule_next_peer(PeerState::DownloadingProofs, None).is_none());
808	}
809
810	#[test]
811	fn enough_peers_are_used_in_tests() {
812		// Tests below use 10 peers. Fail early if it's less than a threshold for warp sync.
813		assert!(
814			10 >= MIN_PEERS_TO_START_WARP_SYNC,
815			"Tests must be updated to use that many initial peers.",
816		);
817	}
818
819	#[test]
820	fn at_least_median_synced_peer_is_scheduled() {
821		for _ in 0..100 {
822			let client = mock_client_without_state();
823			let mut provider = MockWarpSyncProvider::<Block>::new();
824			provider
825				.expect_current_authorities()
826				.once()
827				.return_const(AuthorityList::default());
828			let config = WarpSyncConfig::WithProvider(Arc::new(provider));
829			let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
830
831			for best_number in 1..11 {
832				warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
833			}
834
835			let peer_id = warp_sync.schedule_next_peer(PeerState::DownloadingProofs, None);
836			assert!(warp_sync.peers.get(&peer_id.unwrap()).unwrap().best_number >= 6);
837		}
838	}
839
840	#[test]
841	fn min_best_number_peer_is_scheduled() {
842		for _ in 0..10 {
843			let client = mock_client_without_state();
844			let mut provider = MockWarpSyncProvider::<Block>::new();
845			provider
846				.expect_current_authorities()
847				.once()
848				.return_const(AuthorityList::default());
849			let config = WarpSyncConfig::WithProvider(Arc::new(provider));
850			let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
851
852			for best_number in 1..11 {
853				warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
854			}
855
856			let peer_id = warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(10));
857			assert!(warp_sync.peers.get(&peer_id.unwrap()).unwrap().best_number == 10);
858		}
859	}
860
861	#[test]
862	fn backedoff_number_peer_is_not_scheduled() {
863		let client = mock_client_without_state();
864		let mut provider = MockWarpSyncProvider::<Block>::new();
865		provider
866			.expect_current_authorities()
867			.once()
868			.return_const(AuthorityList::default());
869		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
870		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
871
872		for best_number in 1..11 {
873			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
874		}
875
876		let ninth_peer =
877			*warp_sync.peers.iter().find(|(_, state)| state.best_number == 9).unwrap().0;
878		let tenth_peer =
879			*warp_sync.peers.iter().find(|(_, state)| state.best_number == 10).unwrap().0;
880
881		// Disconnecting a peer without an inflight request has no effect on persistent states.
882		warp_sync.remove_peer(&tenth_peer);
883		assert!(warp_sync.disconnected_peers.is_peer_available(&tenth_peer));
884
885		warp_sync.add_peer(tenth_peer, H256::random(), 10);
886		let peer_id = warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(10));
887		assert_eq!(tenth_peer, peer_id.unwrap());
888		warp_sync.remove_peer(&tenth_peer);
889
890		// Peer is backed off.
891		assert!(!warp_sync.disconnected_peers.is_peer_available(&tenth_peer));
892
893		// No peer available for 10'th best block because of the backoff.
894		warp_sync.add_peer(tenth_peer, H256::random(), 10);
895		let peer_id: Option<PeerId> =
896			warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(10));
897		assert!(peer_id.is_none());
898
899		// Other requests can still happen.
900		let peer_id: Option<PeerId> =
901			warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(9));
902		assert_eq!(ninth_peer, peer_id.unwrap());
903	}
904
905	#[test]
906	fn no_warp_proof_request_in_another_phase() {
907		let client = mock_client_without_state();
908		let mut provider = MockWarpSyncProvider::<Block>::new();
909		provider
910			.expect_current_authorities()
911			.once()
912			.return_const(AuthorityList::default());
913		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
914		let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static("")));
915
916		// Make sure we have enough peers to make a request.
917		for best_number in 1..11 {
918			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
919		}
920
921		// Manually set to another phase.
922		warp_sync.phase = Phase::TargetBlock(<Block as BlockT>::Header::new(
923			1,
924			Default::default(),
925			Default::default(),
926			Default::default(),
927			Default::default(),
928		));
929
930		// No request is made.
931		assert!(warp_sync.warp_proof_request().is_none());
932	}
933
934	#[test]
935	fn warp_proof_request_starts_at_last_hash() {
936		let client = mock_client_without_state();
937		let mut provider = MockWarpSyncProvider::<Block>::new();
938		provider
939			.expect_current_authorities()
940			.once()
941			.return_const(AuthorityList::default());
942		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
943		let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static("")));
944
945		// Make sure we have enough peers to make a request.
946		for best_number in 1..11 {
947			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
948		}
949		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
950
951		let known_last_hash = Hash::random();
952
953		// Manually set last hash to known value.
954		match &mut warp_sync.phase {
955			Phase::WarpProof { last_hash, .. } => {
956				*last_hash = known_last_hash;
957			},
958			_ => panic!("Invalid phase."),
959		}
960
961		let (_peer_id, _protocol_name, request) = warp_sync.warp_proof_request().unwrap();
962		assert_eq!(request.begin, known_last_hash);
963	}
964
965	#[test]
966	fn no_parallel_warp_proof_requests() {
967		let client = mock_client_without_state();
968		let mut provider = MockWarpSyncProvider::<Block>::new();
969		provider
970			.expect_current_authorities()
971			.once()
972			.return_const(AuthorityList::default());
973		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
974		let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static("")));
975
976		// Make sure we have enough peers to make requests.
977		for best_number in 1..11 {
978			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
979		}
980		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
981
982		// First request is made.
983		assert!(warp_sync.warp_proof_request().is_some());
984		// Second request is not made.
985		assert!(warp_sync.warp_proof_request().is_none());
986	}
987
988	#[test]
989	fn bad_warp_proof_response_drops_peer() {
990		let client = mock_client_without_state();
991		let mut provider = MockWarpSyncProvider::<Block>::new();
992		provider
993			.expect_current_authorities()
994			.once()
995			.return_const(AuthorityList::default());
996		// Warp proof verification fails.
997		provider.expect_verify().return_once(|_proof, _set_id, _authorities| {
998			Err(Box::new(std::io::Error::new(ErrorKind::Other, "test-verification-failure")))
999		});
1000		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1001		let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static("")));
1002
1003		// Make sure we have enough peers to make a request.
1004		for best_number in 1..11 {
1005			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1006		}
1007		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1008
1009		// Consume `SendWarpProofRequest` action.
1010		let actions = warp_sync.actions().collect::<Vec<_>>();
1011		assert_eq!(actions.len(), 1);
1012		let WarpSyncAction::SendWarpProofRequest { peer_id: request_peer_id, .. } = actions[0]
1013		else {
1014			panic!("Invalid action");
1015		};
1016
1017		warp_sync.on_warp_proof_response(&request_peer_id, EncodedProof(Vec::new()));
1018
1019		// We only interested in already generated actions, not new requests.
1020		let actions = std::mem::take(&mut warp_sync.actions);
1021		assert_eq!(actions.len(), 1);
1022		assert!(matches!(
1023			actions[0],
1024			WarpSyncAction::DropPeer(BadPeer(peer_id, _rep)) if peer_id == request_peer_id
1025		));
1026		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1027	}
1028
1029	#[test]
1030	fn partial_warp_proof_doesnt_advance_phase() {
1031		let client = mock_client_without_state();
1032		let mut provider = MockWarpSyncProvider::<Block>::new();
1033		provider
1034			.expect_current_authorities()
1035			.once()
1036			.return_const(AuthorityList::default());
1037		// Warp proof is partial.
1038		provider.expect_verify().return_once(|_proof, set_id, authorities| {
1039			Ok(VerificationResult::Partial(set_id, authorities, Hash::random()))
1040		});
1041		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1042		let mut warp_sync = WarpSync::new(Arc::new(client), config, Some(ProtocolName::Static("")));
1043
1044		// Make sure we have enough peers to make a request.
1045		for best_number in 1..11 {
1046			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1047		}
1048		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1049
1050		// Consume `SendWarpProofRequest` action.
1051		let actions = warp_sync.actions().collect::<Vec<_>>();
1052		assert_eq!(actions.len(), 1);
1053		let WarpSyncAction::SendWarpProofRequest { peer_id: request_peer_id, .. } = actions[0]
1054		else {
1055			panic!("Invalid action");
1056		};
1057
1058		warp_sync.on_warp_proof_response(&request_peer_id, EncodedProof(Vec::new()));
1059
1060		assert!(warp_sync.actions.is_empty(), "No extra actions generated");
1061		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1062	}
1063
1064	#[test]
1065	fn complete_warp_proof_advances_phase() {
1066		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1067		let mut provider = MockWarpSyncProvider::<Block>::new();
1068		provider
1069			.expect_current_authorities()
1070			.once()
1071			.return_const(AuthorityList::default());
1072		let target_block = BlockBuilderBuilder::new(&*client)
1073			.on_parent_block(client.chain_info().best_hash)
1074			.with_parent_block_number(client.chain_info().best_number)
1075			.build()
1076			.unwrap()
1077			.build()
1078			.unwrap()
1079			.block;
1080		let target_header = target_block.header().clone();
1081		// Warp proof is complete.
1082		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1083			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1084		});
1085		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1086		let mut warp_sync = WarpSync::new(client, config, Some(ProtocolName::Static("")));
1087
1088		// Make sure we have enough peers to make a request.
1089		for best_number in 1..11 {
1090			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1091		}
1092		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1093
1094		// Consume `SendWarpProofRequest` action.
1095		let actions = warp_sync.actions().collect::<Vec<_>>();
1096		assert_eq!(actions.len(), 1);
1097		let WarpSyncAction::SendWarpProofRequest { peer_id: request_peer_id, .. } = actions[0]
1098		else {
1099			panic!("Invalid action.");
1100		};
1101
1102		warp_sync.on_warp_proof_response(&request_peer_id, EncodedProof(Vec::new()));
1103
1104		assert!(warp_sync.actions.is_empty(), "No extra actions generated.");
1105		assert!(
1106			matches!(warp_sync.phase, Phase::TargetBlock(header) if header == *target_block.header())
1107		);
1108	}
1109
1110	#[test]
1111	fn no_target_block_requests_in_another_phase() {
1112		let client = mock_client_without_state();
1113		let mut provider = MockWarpSyncProvider::<Block>::new();
1114		provider
1115			.expect_current_authorities()
1116			.once()
1117			.return_const(AuthorityList::default());
1118		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1119		let mut warp_sync = WarpSync::new(Arc::new(client), config, None);
1120
1121		// Make sure we have enough peers to make a request.
1122		for best_number in 1..11 {
1123			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1124		}
1125		// We are not in `Phase::TargetBlock`
1126		assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1127
1128		// No request is made.
1129		assert!(warp_sync.target_block_request().is_none());
1130	}
1131
1132	#[test]
1133	fn target_block_request_is_correct() {
1134		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1135		let mut provider = MockWarpSyncProvider::<Block>::new();
1136		provider
1137			.expect_current_authorities()
1138			.once()
1139			.return_const(AuthorityList::default());
1140		let target_block = BlockBuilderBuilder::new(&*client)
1141			.on_parent_block(client.chain_info().best_hash)
1142			.with_parent_block_number(client.chain_info().best_number)
1143			.build()
1144			.unwrap()
1145			.build()
1146			.unwrap()
1147			.block;
1148		let target_header = target_block.header().clone();
1149		// Warp proof is complete.
1150		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1151			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1152		});
1153		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1154		let mut warp_sync = WarpSync::new(client, config, None);
1155
1156		// Make sure we have enough peers to make a request.
1157		for best_number in 1..11 {
1158			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1159		}
1160
1161		// Manually set `TargetBlock` phase.
1162		warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1163
1164		let (_peer_id, request) = warp_sync.target_block_request().unwrap();
1165		assert_eq!(request.from, FromBlock::Hash(target_block.header().hash()));
1166		assert_eq!(
1167			request.fields,
1168			BlockAttributes::HEADER | BlockAttributes::BODY | BlockAttributes::JUSTIFICATION
1169		);
1170		assert_eq!(request.max, Some(1));
1171	}
1172
1173	#[test]
1174	fn externally_set_target_block_is_requested() {
1175		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1176		let target_block = BlockBuilderBuilder::new(&*client)
1177			.on_parent_block(client.chain_info().best_hash)
1178			.with_parent_block_number(client.chain_info().best_number)
1179			.build()
1180			.unwrap()
1181			.build()
1182			.unwrap()
1183			.block;
1184		let target_header = target_block.header().clone();
1185		let config = WarpSyncConfig::WithTarget(target_header);
1186		let mut warp_sync = WarpSync::new(client, config, None);
1187
1188		// Make sure we have enough peers to make a request.
1189		for best_number in 1..11 {
1190			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1191		}
1192
1193		assert!(matches!(warp_sync.phase, Phase::TargetBlock(_)));
1194
1195		let (_peer_id, request) = warp_sync.target_block_request().unwrap();
1196		assert_eq!(request.from, FromBlock::Hash(target_block.header().hash()));
1197		assert_eq!(
1198			request.fields,
1199			BlockAttributes::HEADER | BlockAttributes::BODY | BlockAttributes::JUSTIFICATION
1200		);
1201		assert_eq!(request.max, Some(1));
1202	}
1203
1204	#[test]
1205	fn no_parallel_target_block_requests() {
1206		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1207		let mut provider = MockWarpSyncProvider::<Block>::new();
1208		provider
1209			.expect_current_authorities()
1210			.once()
1211			.return_const(AuthorityList::default());
1212		let target_block = BlockBuilderBuilder::new(&*client)
1213			.on_parent_block(client.chain_info().best_hash)
1214			.with_parent_block_number(client.chain_info().best_number)
1215			.build()
1216			.unwrap()
1217			.build()
1218			.unwrap()
1219			.block;
1220		let target_header = target_block.header().clone();
1221		// Warp proof is complete.
1222		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1223			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1224		});
1225		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1226		let mut warp_sync = WarpSync::new(client, config, None);
1227
1228		// Make sure we have enough peers to make a request.
1229		for best_number in 1..11 {
1230			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1231		}
1232
1233		// Manually set `TargetBlock` phase.
1234		warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1235
1236		// First target block request is made.
1237		assert!(warp_sync.target_block_request().is_some());
1238		// No parallel request is made.
1239		assert!(warp_sync.target_block_request().is_none());
1240	}
1241
1242	#[test]
1243	fn target_block_response_with_no_blocks_drops_peer() {
1244		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1245		let mut provider = MockWarpSyncProvider::<Block>::new();
1246		provider
1247			.expect_current_authorities()
1248			.once()
1249			.return_const(AuthorityList::default());
1250		let target_block = BlockBuilderBuilder::new(&*client)
1251			.on_parent_block(client.chain_info().best_hash)
1252			.with_parent_block_number(client.chain_info().best_number)
1253			.build()
1254			.unwrap()
1255			.build()
1256			.unwrap()
1257			.block;
1258		let target_header = target_block.header().clone();
1259		// Warp proof is complete.
1260		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1261			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1262		});
1263		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1264		let mut warp_sync = WarpSync::new(client, config, None);
1265
1266		// Make sure we have enough peers to make a request.
1267		for best_number in 1..11 {
1268			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1269		}
1270
1271		// Manually set `TargetBlock` phase.
1272		warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1273
1274		let (peer_id, request) = warp_sync.target_block_request().unwrap();
1275
1276		// Empty block response received.
1277		let response = Vec::new();
1278		// Peer is dropped.
1279		assert!(matches!(
1280			warp_sync.on_block_response_inner(peer_id, request, response),
1281			Err(BadPeer(id, _rep)) if id == peer_id,
1282		));
1283	}
1284
1285	#[test]
1286	fn target_block_response_with_extra_blocks_drops_peer() {
1287		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1288		let mut provider = MockWarpSyncProvider::<Block>::new();
1289		provider
1290			.expect_current_authorities()
1291			.once()
1292			.return_const(AuthorityList::default());
1293		let target_block = BlockBuilderBuilder::new(&*client)
1294			.on_parent_block(client.chain_info().best_hash)
1295			.with_parent_block_number(client.chain_info().best_number)
1296			.build()
1297			.unwrap()
1298			.build()
1299			.unwrap()
1300			.block;
1301
1302		let mut extra_block_builder = BlockBuilderBuilder::new(&*client)
1303			.on_parent_block(client.chain_info().best_hash)
1304			.with_parent_block_number(client.chain_info().best_number)
1305			.build()
1306			.unwrap();
1307		extra_block_builder
1308			.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6]))
1309			.unwrap();
1310		let extra_block = extra_block_builder.build().unwrap().block;
1311
1312		let target_header = target_block.header().clone();
1313		// Warp proof is complete.
1314		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1315			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1316		});
1317		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1318		let mut warp_sync = WarpSync::new(client, config, None);
1319
1320		// Make sure we have enough peers to make a request.
1321		for best_number in 1..11 {
1322			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1323		}
1324
1325		// Manually set `TargetBlock` phase.
1326		warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1327
1328		let (peer_id, request) = warp_sync.target_block_request().unwrap();
1329
1330		// Block response with extra blocks received.
1331		let response = vec![
1332			BlockData::<Block> {
1333				hash: target_block.header().hash(),
1334				header: Some(target_block.header().clone()),
1335				body: Some(target_block.extrinsics().iter().cloned().collect::<Vec<_>>()),
1336				indexed_body: None,
1337				receipt: None,
1338				message_queue: None,
1339				justification: None,
1340				justifications: None,
1341			},
1342			BlockData::<Block> {
1343				hash: extra_block.header().hash(),
1344				header: Some(extra_block.header().clone()),
1345				body: Some(extra_block.extrinsics().iter().cloned().collect::<Vec<_>>()),
1346				indexed_body: None,
1347				receipt: None,
1348				message_queue: None,
1349				justification: None,
1350				justifications: None,
1351			},
1352		];
1353		// Peer is dropped.
1354		assert!(matches!(
1355			warp_sync.on_block_response_inner(peer_id, request, response),
1356			Err(BadPeer(id, _rep)) if id == peer_id,
1357		));
1358	}
1359
1360	#[test]
1361	fn target_block_response_with_wrong_block_drops_peer() {
1362		sp_tracing::try_init_simple();
1363
1364		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1365		let mut provider = MockWarpSyncProvider::<Block>::new();
1366		provider
1367			.expect_current_authorities()
1368			.once()
1369			.return_const(AuthorityList::default());
1370		let target_block = BlockBuilderBuilder::new(&*client)
1371			.on_parent_block(client.chain_info().best_hash)
1372			.with_parent_block_number(client.chain_info().best_number)
1373			.build()
1374			.unwrap()
1375			.build()
1376			.unwrap()
1377			.block;
1378
1379		let mut wrong_block_builder = BlockBuilderBuilder::new(&*client)
1380			.on_parent_block(client.chain_info().best_hash)
1381			.with_parent_block_number(client.chain_info().best_number)
1382			.build()
1383			.unwrap();
1384		wrong_block_builder
1385			.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6]))
1386			.unwrap();
1387		let wrong_block = wrong_block_builder.build().unwrap().block;
1388
1389		let target_header = target_block.header().clone();
1390		// Warp proof is complete.
1391		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1392			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1393		});
1394		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1395		let mut warp_sync = WarpSync::new(client, config, None);
1396
1397		// Make sure we have enough peers to make a request.
1398		for best_number in 1..11 {
1399			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1400		}
1401
1402		// Manually set `TargetBlock` phase.
1403		warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1404
1405		let (peer_id, request) = warp_sync.target_block_request().unwrap();
1406
1407		// Wrong block received.
1408		let response = vec![BlockData::<Block> {
1409			hash: wrong_block.header().hash(),
1410			header: Some(wrong_block.header().clone()),
1411			body: Some(wrong_block.extrinsics().iter().cloned().collect::<Vec<_>>()),
1412			indexed_body: None,
1413			receipt: None,
1414			message_queue: None,
1415			justification: None,
1416			justifications: None,
1417		}];
1418		// Peer is dropped.
1419		assert!(matches!(
1420			warp_sync.on_block_response_inner(peer_id, request, response),
1421			Err(BadPeer(id, _rep)) if id == peer_id,
1422		));
1423	}
1424
1425	#[test]
1426	fn correct_target_block_response_sets_strategy_result() {
1427		let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1428		let mut provider = MockWarpSyncProvider::<Block>::new();
1429		provider
1430			.expect_current_authorities()
1431			.once()
1432			.return_const(AuthorityList::default());
1433		let mut target_block_builder = BlockBuilderBuilder::new(&*client)
1434			.on_parent_block(client.chain_info().best_hash)
1435			.with_parent_block_number(client.chain_info().best_number)
1436			.build()
1437			.unwrap();
1438		target_block_builder
1439			.push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6]))
1440			.unwrap();
1441		let target_block = target_block_builder.build().unwrap().block;
1442		let target_header = target_block.header().clone();
1443		// Warp proof is complete.
1444		provider.expect_verify().return_once(move |_proof, set_id, authorities| {
1445			Ok(VerificationResult::Complete(set_id, authorities, target_header))
1446		});
1447		let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1448		let mut warp_sync = WarpSync::new(client, config, None);
1449
1450		// Make sure we have enough peers to make a request.
1451		for best_number in 1..11 {
1452			warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1453		}
1454
1455		// Manually set `TargetBlock` phase.
1456		warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1457
1458		let (peer_id, request) = warp_sync.target_block_request().unwrap();
1459
1460		// Correct block received.
1461		let body = Some(target_block.extrinsics().iter().cloned().collect::<Vec<_>>());
1462		let justifications = Some(Justifications::from((*b"FRNK", Vec::new())));
1463		let response = vec![BlockData::<Block> {
1464			hash: target_block.header().hash(),
1465			header: Some(target_block.header().clone()),
1466			body: body.clone(),
1467			indexed_body: None,
1468			receipt: None,
1469			message_queue: None,
1470			justification: None,
1471			justifications: justifications.clone(),
1472		}];
1473
1474		assert!(warp_sync.on_block_response_inner(peer_id, request, response).is_ok());
1475
1476		// Strategy finishes.
1477		let actions = warp_sync.actions().collect::<Vec<_>>();
1478		assert_eq!(actions.len(), 1);
1479		assert!(matches!(actions[0], WarpSyncAction::Finished));
1480
1481		// With correct result.
1482		let result = warp_sync.take_result().unwrap();
1483		assert_eq!(result.target_header, *target_block.header());
1484		assert_eq!(result.target_body, body);
1485		assert_eq!(result.target_justifications, justifications);
1486	}
1487}