1use sc_consensus::IncomingBlock;
22use sp_consensus::BlockOrigin;
23
24use crate::{
25 block_relay_protocol::{BlockDownloader, BlockResponseError},
26 service::network::NetworkServiceHandle,
27 strategy::{
28 chain_sync::validate_blocks, disconnected_peers::DisconnectedPeers, StrategyKey,
29 SyncingAction,
30 },
31 types::{BadPeer, SyncState, SyncStatus},
32 LOG_TARGET,
33};
34use codec::{Decode, Encode};
35use futures::{channel::oneshot, FutureExt};
36use log::{debug, error, trace, warn};
37use sc_network::{IfDisconnected, ProtocolName};
38use sc_network_common::sync::message::{
39 BlockAnnounce, BlockAttributes, BlockData, BlockRequest, Direction, FromBlock,
40};
41use sc_network_types::PeerId;
42use sp_blockchain::HeaderBackend;
43use sp_runtime::{
44 traits::{Block as BlockT, Header, NumberFor, Zero},
45 Justifications, SaturatedConversion,
46};
47use std::{any::Any, collections::HashMap, fmt, sync::Arc};
48
49const MIN_PEERS_TO_START_WARP_SYNC: usize = 3;
51
52pub struct EncodedProof(pub Vec<u8>);
54
55#[derive(Encode, Decode, Debug, Clone)]
57pub struct WarpProofRequest<B: BlockT> {
58 pub begin: B::Hash,
60}
61
62pub trait Verifier<Block: BlockT>: Send + Sync {
64 fn verify(
66 &mut self,
67 proof: &EncodedProof,
68 ) -> Result<VerificationResult<Block>, Box<dyn std::error::Error + Send + Sync>>;
69 fn next_proof_context(&self) -> Block::Hash;
71 fn status(&self) -> Option<String>;
73}
74
75pub enum VerificationResult<Block: BlockT> {
77 Partial(Vec<(Block::Header, Justifications)>),
79 Complete(Block::Header, Vec<(Block::Header, Justifications)>),
81}
82
83pub trait WarpSyncProvider<Block: BlockT>: Send + Sync {
85 fn generate(
88 &self,
89 start: Block::Hash,
90 ) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>>;
91 fn create_verifier(&self) -> Box<dyn Verifier<Block>>;
93}
94
95mod rep {
96 use sc_network::ReputationChange as Rep;
97
98 pub const UNEXPECTED_RESPONSE: Rep = Rep::new(-(1 << 29), "Unexpected response");
100
101 pub const BAD_WARP_PROOF: Rep = Rep::new(-(1 << 29), "Bad warp proof");
103
104 pub const NO_BLOCK: Rep = Rep::new(-(1 << 29), "No requested block data");
106
107 pub const NOT_REQUESTED: Rep = Rep::new(-(1 << 29), "Not requested block data");
109
110 pub const VERIFICATION_FAIL: Rep = Rep::new(-(1 << 29), "Block verification failed");
112
113 pub const BAD_MESSAGE: Rep = Rep::new(-(1 << 12), "Bad message");
115}
116
117#[derive(Clone, Eq, PartialEq, Debug)]
119pub enum WarpSyncPhase<Block: BlockT> {
120 AwaitingPeers { required_peers: usize },
122 DownloadingWarpProofs,
124 DownloadingTargetBlock,
126 DownloadingState,
128 ImportingState,
130 DownloadingBlocks(NumberFor<Block>),
132 Complete,
134}
135
136impl<Block: BlockT> fmt::Display for WarpSyncPhase<Block> {
137 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
138 match self {
139 Self::AwaitingPeers { required_peers } => {
140 write!(f, "Waiting for {required_peers} peers to be connected")
141 },
142 Self::DownloadingWarpProofs => write!(f, "Downloading finality proofs"),
143 Self::DownloadingTargetBlock => write!(f, "Downloading target block"),
144 Self::DownloadingState => write!(f, "Downloading state"),
145 Self::ImportingState => write!(f, "Importing state"),
146 Self::DownloadingBlocks(n) => write!(f, "Downloading block history (#{})", n),
147 Self::Complete => write!(f, "Warp sync is complete"),
148 }
149 }
150}
151
152#[derive(Clone, Eq, PartialEq, Debug)]
154pub struct WarpSyncProgress<Block: BlockT> {
155 pub phase: WarpSyncPhase<Block>,
157 pub total_bytes: u64,
159 pub status: Option<String>,
161}
162
163pub enum WarpSyncConfig<Block: BlockT> {
165 WithProvider(Arc<dyn WarpSyncProvider<Block>>),
167 WithTarget(<Block as BlockT>::Header),
171}
172
173enum Phase<B: BlockT> {
175 WaitingForPeers { warp_sync_provider: Arc<dyn WarpSyncProvider<B>> },
177 WarpProof { verifier: Box<dyn Verifier<B>> },
179 TargetBlock(B::Header),
181 Complete,
183}
184
185enum PeerState {
186 Available,
187 DownloadingProofs,
188 DownloadingTargetBlock,
189}
190
191impl PeerState {
192 fn is_available(&self) -> bool {
193 matches!(self, PeerState::Available)
194 }
195}
196
197struct Peer<B: BlockT> {
198 best_number: NumberFor<B>,
199 state: PeerState,
200}
201
202pub struct WarpSyncResult<B: BlockT> {
203 pub target_header: B::Header,
204 pub target_body: Option<Vec<B::Extrinsic>>,
205 pub target_justifications: Option<Justifications>,
206}
207
208pub struct WarpSync<B: BlockT> {
210 phase: Phase<B>,
211 total_proof_bytes: u64,
212 total_state_bytes: u64,
213 peers: HashMap<PeerId, Peer<B>>,
214 disconnected_peers: DisconnectedPeers,
215 protocol_name: Option<ProtocolName>,
216 block_downloader: Arc<dyn BlockDownloader<B>>,
217 actions: Vec<SyncingAction<B>>,
218 result: Option<WarpSyncResult<B>>,
219 min_peers_to_start_warp_sync: usize,
221}
222
223impl<B> WarpSync<B>
224where
225 B: BlockT,
226{
227 pub const STRATEGY_KEY: StrategyKey = StrategyKey::new("Warp");
229
230 pub fn new<Client>(
234 client: Arc<Client>,
235 warp_sync_config: WarpSyncConfig<B>,
236 protocol_name: Option<ProtocolName>,
237 block_downloader: Arc<dyn BlockDownloader<B>>,
238 min_peers_to_start_warp_sync: Option<usize>,
239 ) -> Self
240 where
241 Client: HeaderBackend<B> + 'static,
242 {
243 let min_peers_to_start_warp_sync =
244 min_peers_to_start_warp_sync.unwrap_or(MIN_PEERS_TO_START_WARP_SYNC);
245 if client.info().finalized_state.is_some() {
246 error!(
247 target: LOG_TARGET,
248 "Can't use warp sync mode with a partially synced database. Reverting to full sync mode."
249 );
250 return Self {
251 phase: Phase::Complete,
252 total_proof_bytes: 0,
253 total_state_bytes: 0,
254 peers: HashMap::new(),
255 disconnected_peers: DisconnectedPeers::new(),
256 protocol_name,
257 block_downloader,
258 actions: vec![SyncingAction::Finished],
259 result: None,
260 min_peers_to_start_warp_sync,
261 };
262 }
263
264 let phase = match warp_sync_config {
265 WarpSyncConfig::WithProvider(warp_sync_provider) => {
266 Phase::WaitingForPeers { warp_sync_provider }
267 },
268 WarpSyncConfig::WithTarget(target_header) => Phase::TargetBlock(target_header),
269 };
270
271 Self {
272 phase,
273 total_proof_bytes: 0,
274 total_state_bytes: 0,
275 peers: HashMap::new(),
276 disconnected_peers: DisconnectedPeers::new(),
277 protocol_name,
278 block_downloader,
279 actions: Vec::new(),
280 result: None,
281 min_peers_to_start_warp_sync,
282 }
283 }
284
285 pub fn add_peer(&mut self, peer_id: PeerId, _best_hash: B::Hash, best_number: NumberFor<B>) {
287 self.peers.insert(peer_id, Peer { best_number, state: PeerState::Available });
288
289 self.try_to_start_warp_sync();
290 }
291
292 pub fn remove_peer(&mut self, peer_id: &PeerId) {
294 if let Some(state) = self.peers.remove(peer_id) {
295 if !state.state.is_available() {
296 if let Some(bad_peer) =
297 self.disconnected_peers.on_disconnect_during_request(*peer_id)
298 {
299 self.actions.push(SyncingAction::DropPeer(bad_peer));
300 }
301 }
302 }
303 }
304
305 #[must_use]
309 pub fn on_validated_block_announce(
310 &mut self,
311 is_best: bool,
312 peer_id: PeerId,
313 announce: &BlockAnnounce<B::Header>,
314 ) -> Option<(B::Hash, NumberFor<B>)> {
315 is_best.then(|| {
316 let best_number = *announce.header.number();
317 let best_hash = announce.header.hash();
318 if let Some(ref mut peer) = self.peers.get_mut(&peer_id) {
319 peer.best_number = best_number;
320 }
321 (best_hash, best_number)
323 })
324 }
325
326 fn try_to_start_warp_sync(&mut self) {
328 let Phase::WaitingForPeers { warp_sync_provider } = &self.phase else { return };
329
330 if self.peers.len() < self.min_peers_to_start_warp_sync {
331 return;
332 }
333
334 let verifier = warp_sync_provider.create_verifier();
335 self.phase = Phase::WarpProof { verifier };
336 debug!(target: LOG_TARGET, "Started warp sync with {} peers.", self.peers.len());
337 }
338
339 pub fn on_generic_response(
340 &mut self,
341 peer_id: &PeerId,
342 protocol_name: ProtocolName,
343 response: Box<dyn Any + Send>,
344 ) {
345 if &protocol_name == self.block_downloader.protocol_name() {
346 let Ok(response) = response
347 .downcast::<(BlockRequest<B>, Result<Vec<BlockData<B>>, BlockResponseError>)>()
348 else {
349 warn!(target: LOG_TARGET, "Failed to downcast block response");
350 debug_assert!(false);
351 return;
352 };
353
354 let (request, response) = *response;
355 let blocks = match response {
356 Ok(blocks) => blocks,
357 Err(BlockResponseError::DecodeFailed(e)) => {
358 debug!(
359 target: LOG_TARGET,
360 "Failed to decode block response from peer {:?}: {:?}.",
361 peer_id,
362 e
363 );
364 self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE)));
365 return;
366 },
367 Err(BlockResponseError::ExtractionFailed(e)) => {
368 debug!(
369 target: LOG_TARGET,
370 "Failed to extract blocks from peer response {:?}: {:?}.",
371 peer_id,
372 e
373 );
374 self.actions.push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_MESSAGE)));
375 return;
376 },
377 };
378
379 self.on_block_response(*peer_id, request, blocks);
380 } else {
381 let Ok(response) = response.downcast::<Vec<u8>>() else {
382 warn!(target: LOG_TARGET, "Failed to downcast warp sync response");
383 debug_assert!(false);
384 return;
385 };
386
387 self.on_warp_proof_response(peer_id, EncodedProof(*response));
388 }
389 }
390
391 pub fn on_warp_proof_response(&mut self, peer_id: &PeerId, response: EncodedProof) {
393 if let Some(peer) = self.peers.get_mut(peer_id) {
394 peer.state = PeerState::Available;
395 }
396
397 let Phase::WarpProof { verifier } = &mut self.phase else {
398 debug!(target: LOG_TARGET, "Unexpected warp proof response");
399 self.actions
400 .push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::UNEXPECTED_RESPONSE)));
401 return;
402 };
403
404 let proof_to_incoming_block =
405 |(header, justifications): (B::Header, Justifications)| -> IncomingBlock<B> {
406 IncomingBlock {
407 hash: header.hash(),
408 header: Some(header),
409 body: None,
410 justifications: Some(justifications),
411 origin: Some(*peer_id),
412 allow_missing_state: true,
415 skip_execution: true,
416 import_existing: false,
418 state: None,
419 }
420 };
421
422 match verifier.verify(&response) {
423 Err(e) => {
424 debug!(target: LOG_TARGET, "Bad warp proof response: {}", e);
425 self.actions
426 .push(SyncingAction::DropPeer(BadPeer(*peer_id, rep::BAD_WARP_PROOF)))
427 },
428 Ok(VerificationResult::Partial(proofs)) => {
429 debug!(target: LOG_TARGET, "Verified partial proof");
430 self.total_proof_bytes += response.0.len() as u64;
431 self.actions.push(SyncingAction::ImportBlocks {
432 origin: BlockOrigin::WarpSync,
433 blocks: proofs.into_iter().map(proof_to_incoming_block).collect(),
434 });
435 },
436 Ok(VerificationResult::Complete(header, proofs)) => {
437 debug!(
438 target: LOG_TARGET,
439 "Verified complete proof. Continuing with target block download: {} ({}).",
440 header.hash(),
441 header.number(),
442 );
443 self.total_proof_bytes += response.0.len() as u64;
444 self.phase = Phase::TargetBlock(header.clone());
445 let incoming_blocks: Vec<_> = proofs
446 .into_iter()
447 .map(proof_to_incoming_block)
448 .filter(|i| {
449 if header.number() != i.header.as_ref().unwrap().number() {
454 true
455 } else {
456 log::trace!(
457 target: LOG_TARGET,
458 "Filtered out target block: {} ({})",
459 header.hash(),
460 header.number()
461 );
462 false
463 }
464 })
465 .collect();
466 self.actions.push(SyncingAction::ImportBlocks {
467 origin: BlockOrigin::WarpSync,
468 blocks: incoming_blocks,
469 });
470 },
471 }
472 }
473
474 pub fn on_block_response(
476 &mut self,
477 peer_id: PeerId,
478 request: BlockRequest<B>,
479 blocks: Vec<BlockData<B>>,
480 ) {
481 if let Err(bad_peer) = self.on_block_response_inner(peer_id, request, blocks) {
482 self.actions.push(SyncingAction::DropPeer(bad_peer));
483 }
484 }
485
486 fn on_block_response_inner(
487 &mut self,
488 peer_id: PeerId,
489 request: BlockRequest<B>,
490 mut blocks: Vec<BlockData<B>>,
491 ) -> Result<(), BadPeer> {
492 if let Some(peer) = self.peers.get_mut(&peer_id) {
493 peer.state = PeerState::Available;
494 }
495
496 let Phase::TargetBlock(header) = &mut self.phase else {
497 debug!(target: LOG_TARGET, "Unexpected target block response from {peer_id}");
498 return Err(BadPeer(peer_id, rep::UNEXPECTED_RESPONSE));
499 };
500
501 if blocks.is_empty() {
502 debug!(
503 target: LOG_TARGET,
504 "Downloading target block failed: empty block response from {peer_id}",
505 );
506 return Err(BadPeer(peer_id, rep::NO_BLOCK));
507 }
508
509 if blocks.len() > 1 {
510 debug!(
511 target: LOG_TARGET,
512 "Too many blocks ({}) in warp target block response from {peer_id}",
513 blocks.len(),
514 );
515 return Err(BadPeer(peer_id, rep::NOT_REQUESTED));
516 }
517
518 validate_blocks::<B>(&blocks, &peer_id, Some(request))?;
519
520 let block = blocks.pop().expect("`blocks` len checked above; qed");
521
522 let Some(block_header) = &block.header else {
523 debug!(
524 target: LOG_TARGET,
525 "Downloading target block failed: missing header in response from {peer_id}.",
526 );
527 return Err(BadPeer(peer_id, rep::VERIFICATION_FAIL));
528 };
529
530 if block_header != header {
531 debug!(
532 target: LOG_TARGET,
533 "Downloading target block failed: different header in response from {peer_id}.",
534 );
535 return Err(BadPeer(peer_id, rep::VERIFICATION_FAIL));
536 }
537
538 if block.body.is_none() {
539 debug!(
540 target: LOG_TARGET,
541 "Downloading target block failed: missing body in response from {peer_id}.",
542 );
543 return Err(BadPeer(peer_id, rep::VERIFICATION_FAIL));
544 }
545
546 self.result = Some(WarpSyncResult {
547 target_header: header.clone(),
548 target_body: block.body,
549 target_justifications: block.justifications,
550 });
551 self.phase = Phase::Complete;
552 self.actions.push(SyncingAction::Finished);
553 Ok(())
554 }
555
556 fn schedule_next_peer(
558 &mut self,
559 new_state: PeerState,
560 min_best_number: Option<NumberFor<B>>,
561 ) -> Option<PeerId> {
562 let mut targets: Vec<_> = self.peers.values().map(|p| p.best_number).collect();
563 if targets.is_empty() {
564 return None;
565 }
566 targets.sort();
567 let median = targets[targets.len() / 2];
568 let threshold = std::cmp::max(median, min_best_number.unwrap_or(Zero::zero()));
569 for (peer_id, peer) in self.peers.iter_mut() {
572 if peer.state.is_available() &&
573 peer.best_number >= threshold &&
574 self.disconnected_peers.is_peer_available(peer_id)
575 {
576 peer.state = new_state;
577 return Some(*peer_id);
578 }
579 }
580 None
581 }
582
583 fn warp_proof_request(&mut self) -> Option<(PeerId, ProtocolName, WarpProofRequest<B>)> {
585 let Phase::WarpProof { verifier } = &self.phase else { return None };
586
587 let begin = verifier.next_proof_context();
589
590 if self
591 .peers
592 .values()
593 .any(|peer| matches!(peer.state, PeerState::DownloadingProofs))
594 {
595 return None;
597 }
598
599 let peer_id = self.schedule_next_peer(PeerState::DownloadingProofs, None)?;
600 trace!(target: LOG_TARGET, "New WarpProofRequest to {peer_id}, begin hash: {begin}.");
601
602 let request = WarpProofRequest { begin };
603
604 let Some(protocol_name) = self.protocol_name.clone() else {
605 warn!(
606 target: LOG_TARGET,
607 "Trying to send warp sync request when no protocol is configured {request:?}",
608 );
609 return None;
610 };
611
612 Some((peer_id, protocol_name, request))
613 }
614
615 fn target_block_request(&mut self) -> Option<(PeerId, BlockRequest<B>)> {
617 let Phase::TargetBlock(target_header) = &self.phase else { return None };
618
619 if self
620 .peers
621 .values()
622 .any(|peer| matches!(peer.state, PeerState::DownloadingTargetBlock))
623 {
624 return None;
626 }
627
628 let target_hash = target_header.hash();
630 let target_number = *target_header.number();
631
632 let peer_id =
633 self.schedule_next_peer(PeerState::DownloadingTargetBlock, Some(target_number))?;
634
635 trace!(
636 target: LOG_TARGET,
637 "New target block request to {peer_id}, target: {} ({}).",
638 target_hash,
639 target_number,
640 );
641
642 Some((
643 peer_id,
644 BlockRequest::<B> {
645 id: 0,
646 fields: BlockAttributes::HEADER |
647 BlockAttributes::BODY |
648 BlockAttributes::JUSTIFICATION,
649 from: FromBlock::Hash(target_hash),
650 direction: Direction::Ascending,
651 max: Some(1),
652 },
653 ))
654 }
655
656 pub fn progress(&self) -> WarpSyncProgress<B> {
658 match &self.phase {
659 Phase::WaitingForPeers { .. } => WarpSyncProgress {
660 phase: WarpSyncPhase::AwaitingPeers {
661 required_peers: self.min_peers_to_start_warp_sync,
662 },
663 total_bytes: self.total_proof_bytes,
664 status: None,
665 },
666 Phase::WarpProof { verifier } => WarpSyncProgress {
667 phase: WarpSyncPhase::DownloadingWarpProofs,
668 total_bytes: self.total_proof_bytes,
669 status: verifier.status(),
670 },
671 Phase::TargetBlock(_) => WarpSyncProgress {
672 phase: WarpSyncPhase::DownloadingTargetBlock,
673 total_bytes: self.total_proof_bytes,
674 status: None,
675 },
676 Phase::Complete => WarpSyncProgress {
677 phase: WarpSyncPhase::Complete,
678 total_bytes: self.total_proof_bytes + self.total_state_bytes,
679 status: None,
680 },
681 }
682 }
683
684 pub fn num_peers(&self) -> usize {
686 self.peers.len()
687 }
688
689 pub fn status(&self) -> SyncStatus<B> {
691 SyncStatus {
692 state: match &self.phase {
693 Phase::WaitingForPeers { .. } => SyncState::Downloading { target: Zero::zero() },
694 Phase::WarpProof { .. } => SyncState::Downloading { target: Zero::zero() },
695 Phase::TargetBlock(header) => SyncState::Downloading { target: *header.number() },
696 Phase::Complete => SyncState::Idle,
697 },
698 best_seen_block: match &self.phase {
699 Phase::WaitingForPeers { .. } => None,
700 Phase::WarpProof { .. } => None,
701 Phase::TargetBlock(header) => Some(*header.number()),
702 Phase::Complete => None,
703 },
704 num_peers: self.peers.len().saturated_into(),
705 queued_blocks: 0,
706 state_sync: None,
707 warp_sync: Some(self.progress()),
708 }
709 }
710
711 #[must_use]
713 pub fn actions(
714 &mut self,
715 network_service: &NetworkServiceHandle,
716 ) -> impl Iterator<Item = SyncingAction<B>> {
717 let warp_proof_request =
718 self.warp_proof_request().into_iter().map(|(peer_id, protocol_name, request)| {
719 trace!(
720 target: LOG_TARGET,
721 "Created `WarpProofRequest` to {}, request: {:?}.",
722 peer_id,
723 request,
724 );
725
726 let (tx, rx) = oneshot::channel();
727
728 network_service.start_request(
729 peer_id,
730 protocol_name,
731 request.encode(),
732 tx,
733 IfDisconnected::ImmediateError,
734 );
735
736 SyncingAction::StartRequest {
737 peer_id,
738 key: Self::STRATEGY_KEY,
739 request: async move {
740 Ok(rx.await?.and_then(|(response, protocol_name)| {
741 Ok((Box::new(response) as Box<dyn Any + Send>, protocol_name))
742 }))
743 }
744 .boxed(),
745 }
746 });
747 self.actions.extend(warp_proof_request);
748
749 let target_block_request =
750 self.target_block_request().into_iter().map(|(peer_id, request)| {
751 let downloader = self.block_downloader.clone();
752
753 SyncingAction::StartRequest {
754 peer_id,
755 key: Self::STRATEGY_KEY,
756 request: async move {
757 Ok(downloader.download_blocks(peer_id, request.clone()).await?.and_then(
758 |(response, protocol_name)| {
759 let decoded_response =
760 downloader.block_response_into_blocks(&request, response);
761 let result =
762 Box::new((request, decoded_response)) as Box<dyn Any + Send>;
763 Ok((result, protocol_name))
764 },
765 ))
766 }
767 .boxed(),
768 }
769 });
770 self.actions.extend(target_block_request);
771
772 std::mem::take(&mut self.actions).into_iter()
773 }
774
775 #[must_use]
777 pub fn take_result(&mut self) -> Option<WarpSyncResult<B>> {
778 self.result.take()
779 }
780}
781
782#[cfg(test)]
783mod test {
784 use super::*;
785 use crate::{mock::MockBlockDownloader, service::network::NetworkServiceProvider};
786 use sc_block_builder::BlockBuilderBuilder;
787 use sp_blockchain::{BlockStatus, Error as BlockchainError, HeaderBackend, Info};
788 use sp_core::H256;
789 use sp_runtime::{
790 traits::{Block as BlockT, Header as HeaderT, NumberFor},
791 ConsensusEngineId,
792 };
793 use std::{io::ErrorKind, sync::Arc};
794 use substrate_test_runtime_client::{
795 runtime::{Block, Hash},
796 BlockBuilderExt, DefaultTestClientBuilderExt, TestClientBuilder, TestClientBuilderExt,
797 };
798
799 pub const TEST_ENGINE_ID: ConsensusEngineId = *b"TEST";
800
801 mockall::mock! {
802 pub Client<B: BlockT> {}
803
804 impl<B: BlockT> HeaderBackend<B> for Client<B> {
805 fn header(&self, hash: B::Hash) -> Result<Option<B::Header>, BlockchainError>;
806 fn info(&self) -> Info<B>;
807 fn status(&self, hash: B::Hash) -> Result<BlockStatus, BlockchainError>;
808 fn number(
809 &self,
810 hash: B::Hash,
811 ) -> Result<Option<<<B as BlockT>::Header as HeaderT>::Number>, BlockchainError>;
812 fn hash(&self, number: NumberFor<B>) -> Result<Option<B::Hash>, BlockchainError>;
813 }
814 }
815
816 mockall::mock! {
817 pub WarpSyncProvider<B: BlockT> {}
818
819 impl<B: BlockT> super::WarpSyncProvider<B> for WarpSyncProvider<B> {
820 fn generate(
821 &self,
822 start: B::Hash,
823 ) -> Result<EncodedProof, Box<dyn std::error::Error + Send + Sync>>;
824 fn create_verifier(&self) -> Box<dyn super::Verifier<B>>;
825 }
826 }
827
828 mockall::mock! {
829 pub Verifier<B: BlockT> {}
830
831 impl<B: BlockT> super::Verifier<B> for Verifier<B> {
832 fn verify(
833 &mut self,
834 proof: &EncodedProof,
835 ) -> Result<VerificationResult<B>, Box<dyn std::error::Error + Send + Sync>>;
836 fn next_proof_context(&self) -> B::Hash;
837 fn status(&self) -> Option<String>;
838 }
839 }
840
841 fn mock_client_with_state() -> MockClient<Block> {
842 let mut client = MockClient::<Block>::new();
843 let genesis_hash = Hash::random();
844 client.expect_info().return_once(move || Info {
845 best_hash: genesis_hash,
846 best_number: 0,
847 genesis_hash,
848 finalized_hash: genesis_hash,
849 finalized_number: 0,
850 finalized_state: Some((genesis_hash, 0)),
852 number_leaves: 0,
853 block_gap: None,
854 });
855
856 client
857 }
858
859 fn mock_client_without_state() -> MockClient<Block> {
860 let mut client = MockClient::<Block>::new();
861 let genesis_hash = Hash::random();
862 client.expect_info().returning(move || Info {
863 best_hash: genesis_hash,
864 best_number: 0,
865 genesis_hash,
866 finalized_hash: genesis_hash,
867 finalized_number: 0,
868 finalized_state: None,
869 number_leaves: 0,
870 block_gap: None,
871 });
872
873 client
874 }
875
876 #[test]
877 fn warp_sync_with_provider_for_db_with_finalized_state_is_noop() {
878 let client = mock_client_with_state();
879 let provider = MockWarpSyncProvider::<Block>::new();
880 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
881 let mut warp_sync = WarpSync::new(
882 Arc::new(client),
883 config,
884 None,
885 Arc::new(MockBlockDownloader::new()),
886 None,
887 );
888
889 let network_provider = NetworkServiceProvider::new();
890 let network_handle = network_provider.handle();
891
892 let actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
894 assert_eq!(actions.len(), 1);
895 assert!(matches!(actions[0], SyncingAction::Finished));
896
897 assert!(warp_sync.take_result().is_none());
899 }
900
901 #[test]
902 fn warp_sync_to_target_for_db_with_finalized_state_is_noop() {
903 let client = mock_client_with_state();
904 let config = WarpSyncConfig::WithTarget(<Block as BlockT>::Header::new(
905 1,
906 Default::default(),
907 Default::default(),
908 Default::default(),
909 Default::default(),
910 ));
911 let mut warp_sync = WarpSync::new(
912 Arc::new(client),
913 config,
914 None,
915 Arc::new(MockBlockDownloader::new()),
916 None,
917 );
918
919 let network_provider = NetworkServiceProvider::new();
920 let network_handle = network_provider.handle();
921
922 let actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
924 assert_eq!(actions.len(), 1);
925 assert!(matches!(actions[0], SyncingAction::Finished));
926
927 assert!(warp_sync.take_result().is_none());
929 }
930
931 #[test]
932 fn warp_sync_with_provider_for_empty_db_doesnt_finish_instantly() {
933 let client = mock_client_without_state();
934 let provider = MockWarpSyncProvider::<Block>::new();
935 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
936 let mut warp_sync = WarpSync::new(
937 Arc::new(client),
938 config,
939 None,
940 Arc::new(MockBlockDownloader::new()),
941 None,
942 );
943
944 let network_provider = NetworkServiceProvider::new();
945 let network_handle = network_provider.handle();
946
947 assert_eq!(warp_sync.actions(&network_handle).count(), 0)
949 }
950
951 #[test]
952 fn warp_sync_to_target_for_empty_db_doesnt_finish_instantly() {
953 let client = mock_client_without_state();
954 let config = WarpSyncConfig::WithTarget(<Block as BlockT>::Header::new(
955 1,
956 Default::default(),
957 Default::default(),
958 Default::default(),
959 Default::default(),
960 ));
961 let mut warp_sync = WarpSync::new(
962 Arc::new(client),
963 config,
964 None,
965 Arc::new(MockBlockDownloader::new()),
966 None,
967 );
968
969 let network_provider = NetworkServiceProvider::new();
970 let network_handle = network_provider.handle();
971
972 assert_eq!(warp_sync.actions(&network_handle).count(), 0)
974 }
975
976 #[test]
977 fn warp_sync_is_started_only_when_there_is_enough_peers() {
978 let client = mock_client_without_state();
979 let mut provider = MockWarpSyncProvider::<Block>::new();
980 let mut verifier = MockVerifier::<Block>::new();
981 verifier.expect_next_proof_context().returning(|| Hash::random());
982 verifier
983 .expect_verify()
984 .returning(|_| unreachable!("verify should not be called in this test"));
985 provider.expect_create_verifier().return_once(move || Box::new(verifier));
986 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
987 let mut warp_sync = WarpSync::new(
988 Arc::new(client),
989 config,
990 None,
991 Arc::new(MockBlockDownloader::new()),
992 None,
993 );
994
995 for _ in 0..(MIN_PEERS_TO_START_WARP_SYNC - 1) {
997 warp_sync.add_peer(PeerId::random(), Hash::random(), 10);
998 assert!(matches!(warp_sync.phase, Phase::WaitingForPeers { .. }))
999 }
1000
1001 warp_sync.add_peer(PeerId::random(), Hash::random(), 10);
1003 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }))
1004 }
1005
1006 #[test]
1007 fn no_peer_is_scheduled_if_no_peers_connected() {
1008 let client = mock_client_without_state();
1009 let provider = MockWarpSyncProvider::<Block>::new();
1010 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1011 let mut warp_sync = WarpSync::new(
1012 Arc::new(client),
1013 config,
1014 None,
1015 Arc::new(MockBlockDownloader::new()),
1016 None,
1017 );
1018
1019 assert!(warp_sync.schedule_next_peer(PeerState::DownloadingProofs, None).is_none());
1020 }
1021
1022 #[test]
1023 fn enough_peers_are_used_in_tests() {
1024 assert!(
1026 10 >= MIN_PEERS_TO_START_WARP_SYNC,
1027 "Tests must be updated to use that many initial peers.",
1028 );
1029 }
1030
1031 #[test]
1032 fn at_least_median_synced_peer_is_scheduled() {
1033 for _ in 0..100 {
1034 let client = mock_client_without_state();
1035 let mut provider = MockWarpSyncProvider::<Block>::new();
1036 let mut verifier = MockVerifier::<Block>::new();
1037 verifier.expect_next_proof_context().returning(|| Hash::random());
1038 verifier
1039 .expect_verify()
1040 .returning(|_| unreachable!("verify should not be called in this test"));
1041 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1042 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1043 let mut warp_sync = WarpSync::new(
1044 Arc::new(client),
1045 config,
1046 None,
1047 Arc::new(MockBlockDownloader::new()),
1048 None,
1049 );
1050
1051 for best_number in 1..11 {
1052 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1053 }
1054
1055 let peer_id = warp_sync.schedule_next_peer(PeerState::DownloadingProofs, None);
1056 assert!(warp_sync.peers.get(&peer_id.unwrap()).unwrap().best_number >= 6);
1057 }
1058 }
1059
1060 #[test]
1061 fn min_best_number_peer_is_scheduled() {
1062 for _ in 0..10 {
1063 let client = mock_client_without_state();
1064 let mut provider = MockWarpSyncProvider::<Block>::new();
1065 let mut verifier = MockVerifier::<Block>::new();
1066 verifier.expect_next_proof_context().returning(|| Hash::random());
1067 verifier
1068 .expect_verify()
1069 .returning(|_| unreachable!("verify should not be called in this test"));
1070 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1071 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1072 let mut warp_sync = WarpSync::new(
1073 Arc::new(client),
1074 config,
1075 None,
1076 Arc::new(MockBlockDownloader::new()),
1077 None,
1078 );
1079
1080 for best_number in 1..11 {
1081 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1082 }
1083
1084 let peer_id = warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(10));
1085 assert!(warp_sync.peers.get(&peer_id.unwrap()).unwrap().best_number == 10);
1086 }
1087 }
1088
1089 #[test]
1090 fn backedoff_number_peer_is_not_scheduled() {
1091 let client = mock_client_without_state();
1092 let mut provider = MockWarpSyncProvider::<Block>::new();
1093 let mut verifier = MockVerifier::<Block>::new();
1094 verifier.expect_next_proof_context().returning(|| Hash::random());
1095 verifier
1096 .expect_verify()
1097 .returning(|_| unreachable!("verify should not be called in this test"));
1098 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1099 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1100 let mut warp_sync = WarpSync::new(
1101 Arc::new(client),
1102 config,
1103 None,
1104 Arc::new(MockBlockDownloader::new()),
1105 None,
1106 );
1107
1108 for best_number in 1..11 {
1109 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1110 }
1111
1112 let ninth_peer =
1113 *warp_sync.peers.iter().find(|(_, state)| state.best_number == 9).unwrap().0;
1114 let tenth_peer =
1115 *warp_sync.peers.iter().find(|(_, state)| state.best_number == 10).unwrap().0;
1116
1117 warp_sync.remove_peer(&tenth_peer);
1119 assert!(warp_sync.disconnected_peers.is_peer_available(&tenth_peer));
1120
1121 warp_sync.add_peer(tenth_peer, H256::random(), 10);
1122 let peer_id = warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(10));
1123 assert_eq!(tenth_peer, peer_id.unwrap());
1124 warp_sync.remove_peer(&tenth_peer);
1125
1126 assert!(!warp_sync.disconnected_peers.is_peer_available(&tenth_peer));
1128
1129 warp_sync.add_peer(tenth_peer, H256::random(), 10);
1131 let peer_id: Option<PeerId> =
1132 warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(10));
1133 assert!(peer_id.is_none());
1134
1135 let peer_id: Option<PeerId> =
1137 warp_sync.schedule_next_peer(PeerState::DownloadingProofs, Some(9));
1138 assert_eq!(ninth_peer, peer_id.unwrap());
1139 }
1140
1141 #[test]
1142 fn no_warp_proof_request_in_another_phase() {
1143 let client = mock_client_without_state();
1144 let mut provider = MockWarpSyncProvider::<Block>::new();
1145 let mut verifier = MockVerifier::<Block>::new();
1146 verifier.expect_next_proof_context().returning(|| Hash::random());
1147 verifier
1148 .expect_verify()
1149 .returning(|_| unreachable!("verify should not be called in this test"));
1150 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1151 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1152 let mut warp_sync = WarpSync::new(
1153 Arc::new(client),
1154 config,
1155 Some(ProtocolName::Static("")),
1156 Arc::new(MockBlockDownloader::new()),
1157 None,
1158 );
1159
1160 for best_number in 1..11 {
1162 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1163 }
1164
1165 warp_sync.phase = Phase::TargetBlock(<Block as BlockT>::Header::new(
1167 1,
1168 Default::default(),
1169 Default::default(),
1170 Default::default(),
1171 Default::default(),
1172 ));
1173
1174 assert!(warp_sync.warp_proof_request().is_none());
1176 }
1177
1178 #[test]
1179 fn warp_proof_request_starts_at_last_hash() {
1180 let client = mock_client_without_state();
1181 let mut provider = MockWarpSyncProvider::<Block>::new();
1182 let mut verifier = MockVerifier::<Block>::new();
1183 let known_last_hash = Hash::random();
1184 verifier.expect_next_proof_context().returning(move || known_last_hash);
1185 verifier
1186 .expect_verify()
1187 .returning(|_| unreachable!("verify should not be called in this test"));
1188 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1189 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1190 let mut warp_sync = WarpSync::new(
1191 Arc::new(client),
1192 config,
1193 Some(ProtocolName::Static("")),
1194 Arc::new(MockBlockDownloader::new()),
1195 None,
1196 );
1197
1198 for best_number in 1..11 {
1200 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1201 }
1202 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1203
1204 let (_peer_id, _protocol_name, request) = warp_sync.warp_proof_request().unwrap();
1205 assert_eq!(request.begin, known_last_hash);
1206 }
1207
1208 #[test]
1209 fn no_parallel_warp_proof_requests() {
1210 let client = mock_client_without_state();
1211 let mut provider = MockWarpSyncProvider::<Block>::new();
1212 let mut verifier = MockVerifier::<Block>::new();
1213 verifier.expect_next_proof_context().returning(|| Hash::random());
1214 verifier
1215 .expect_verify()
1216 .returning(|_| unreachable!("verify should not be called in this test"));
1217 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1218 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1219 let mut warp_sync = WarpSync::new(
1220 Arc::new(client),
1221 config,
1222 Some(ProtocolName::Static("")),
1223 Arc::new(MockBlockDownloader::new()),
1224 None,
1225 );
1226
1227 for best_number in 1..11 {
1229 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1230 }
1231 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1232
1233 assert!(warp_sync.warp_proof_request().is_some());
1235 assert!(warp_sync.warp_proof_request().is_none());
1237 }
1238
1239 #[test]
1240 fn bad_warp_proof_response_drops_peer() {
1241 let client = mock_client_without_state();
1242 let mut provider = MockWarpSyncProvider::<Block>::new();
1243 let mut verifier = MockVerifier::<Block>::new();
1244 verifier.expect_next_proof_context().returning(|| Hash::random());
1245 verifier.expect_verify().return_once(|_proof| {
1247 Err(Box::new(std::io::Error::new(ErrorKind::Other, "test-verification-failure")))
1248 });
1249 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1250 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1251 let mut warp_sync = WarpSync::new(
1252 Arc::new(client),
1253 config,
1254 Some(ProtocolName::Static("")),
1255 Arc::new(MockBlockDownloader::new()),
1256 None,
1257 );
1258
1259 for best_number in 1..11 {
1261 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1262 }
1263 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1264
1265 let network_provider = NetworkServiceProvider::new();
1266 let network_handle = network_provider.handle();
1267
1268 let actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
1270 assert_eq!(actions.len(), 1);
1271 let SyncingAction::StartRequest { peer_id: request_peer_id, .. } = actions[0] else {
1272 panic!("Invalid action");
1273 };
1274
1275 warp_sync.on_warp_proof_response(&request_peer_id, EncodedProof(Vec::new()));
1276
1277 let actions = std::mem::take(&mut warp_sync.actions);
1279 assert_eq!(actions.len(), 1);
1280 assert!(matches!(
1281 actions[0],
1282 SyncingAction::DropPeer(BadPeer(peer_id, _rep)) if peer_id == request_peer_id
1283 ));
1284 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1285 }
1286
1287 #[test]
1288 fn partial_warp_proof_doesnt_advance_phase() {
1289 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1290 let mut provider = MockWarpSyncProvider::<Block>::new();
1291 let target_block = BlockBuilderBuilder::new(&*client)
1292 .on_parent_block(client.chain_info().best_hash)
1293 .with_parent_block_number(client.chain_info().best_number)
1294 .build()
1295 .unwrap()
1296 .build()
1297 .unwrap()
1298 .block;
1299 let target_header = target_block.header().clone();
1300 let justifications = Justifications::new(vec![(TEST_ENGINE_ID, vec![1, 2, 3, 4, 5])]);
1301 let mut verifier = MockVerifier::<Block>::new();
1303 let context = client.info().genesis_hash;
1304 verifier.expect_next_proof_context().returning(move || context);
1305 let header_for_verify = target_header.clone();
1306 let just_for_verify = justifications.clone();
1307 verifier.expect_verify().return_once(move |_proof| {
1308 Ok(VerificationResult::Partial(vec![(
1309 header_for_verify.clone(),
1310 just_for_verify.clone(),
1311 )]))
1312 });
1313 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1314 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1315 let mut warp_sync = WarpSync::new(
1316 client,
1317 config,
1318 Some(ProtocolName::Static("")),
1319 Arc::new(MockBlockDownloader::new()),
1320 None,
1321 );
1322
1323 for best_number in 1..11 {
1325 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1326 }
1327 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1328
1329 let network_provider = NetworkServiceProvider::new();
1330 let network_handle = network_provider.handle();
1331
1332 let actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
1334 assert_eq!(actions.len(), 1);
1335 let SyncingAction::StartRequest { peer_id: request_peer_id, .. } = actions[0] else {
1336 panic!("Invalid action");
1337 };
1338
1339 warp_sync.on_warp_proof_response(&request_peer_id, EncodedProof(Vec::new()));
1340
1341 assert_eq!(warp_sync.actions.len(), 1);
1342 let SyncingAction::ImportBlocks { origin, mut blocks } = warp_sync.actions.pop().unwrap()
1343 else {
1344 panic!("Expected `ImportBlocks` action.");
1345 };
1346 assert_eq!(origin, BlockOrigin::WarpSync);
1347 assert_eq!(blocks.len(), 1);
1348 let import_block = blocks.pop().unwrap();
1349 assert_eq!(
1350 import_block,
1351 IncomingBlock {
1352 hash: target_header.hash(),
1353 header: Some(target_header),
1354 body: None,
1355 justifications: Some(justifications),
1356 origin: Some(request_peer_id),
1357 allow_missing_state: true,
1358 skip_execution: true,
1359 import_existing: false,
1360 state: None,
1361 }
1362 );
1363 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1364 }
1365
1366 #[test]
1367 fn complete_warp_proof_advances_phase() {
1368 use crate::{pending_responses::PendingResponses, service::network::ToServiceCommand};
1369 use futures::{executor::block_on, StreamExt};
1370
1371 sp_tracing::try_init_simple();
1373
1374 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1375 let mut provider = MockWarpSyncProvider::<Block>::new();
1376
1377 let warp_synced_header = <<Block as BlockT>::Header as HeaderT>::new(
1381 1,
1382 Default::default(),
1383 Default::default(),
1384 client.chain_info().best_hash,
1385 Default::default(),
1386 );
1387
1388 let target_header = <<Block as BlockT>::Header as HeaderT>::new(
1390 2,
1391 Default::default(),
1392 Default::default(),
1393 warp_synced_header.hash(),
1394 Default::default(),
1395 );
1396 let warp_justifications = Justifications::new(vec![(TEST_ENGINE_ID, vec![1, 2, 3, 4, 5])]);
1397 let target_justifications =
1398 Justifications::new(vec![(TEST_ENGINE_ID, vec![6, 7, 8, 9, 10])]);
1399
1400 let mut verifier = MockVerifier::<Block>::new();
1402 let context = client.info().genesis_hash;
1403 verifier.expect_next_proof_context().returning(move || context);
1404 let warp_synced_header_for_verify = warp_synced_header.clone();
1405 let warp_just_for_verify = warp_justifications.clone();
1406 let target_header_for_verify = target_header.clone();
1407 let target_just_for_verify = target_justifications.clone();
1408 verifier.expect_verify().return_once(move |_proof| {
1409 Ok(VerificationResult::Complete(
1410 target_header_for_verify.clone(),
1411 vec![
1412 (warp_synced_header_for_verify, warp_just_for_verify),
1413 (target_header_for_verify, target_just_for_verify),
1414 ],
1415 ))
1416 });
1417 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1418 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1419 let mut warp_sync = WarpSync::new(
1420 client,
1421 config,
1422 Some(ProtocolName::Static("")),
1423 Arc::new(MockBlockDownloader::new()),
1424 Some(1),
1425 );
1426
1427 let peer_id = PeerId::random();
1429 warp_sync.add_peer(peer_id, Hash::random(), 10);
1430 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1431
1432 let (tx, mut rx) = sc_utils::mpsc::tracing_unbounded("warp_test", 10);
1433 let network_handle = NetworkServiceHandle::new(tx);
1434 let mut pending = PendingResponses::new();
1435 let mut actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
1436 assert_eq!(actions.len(), 1);
1437 let SyncingAction::StartRequest { peer_id: request_peer_id, key, request } =
1438 actions.pop().unwrap()
1439 else {
1440 panic!("Expected warp proof request.");
1441 };
1442 assert_eq!(request_peer_id, peer_id);
1443 pending.insert(request_peer_id, key, request);
1444 let ToServiceCommand::StartRequest(_, protocol, _, response_tx, _) =
1445 block_on(rx.next()).unwrap()
1446 else {
1447 panic!("Expected network request.");
1448 };
1449 response_tx.send(Ok((Vec::new(), protocol))).unwrap();
1450 let event = block_on(pending.next()).unwrap();
1451 assert_eq!(pending.len(), 0);
1453 let (response, _) = event.response.unwrap().unwrap();
1454 warp_sync.on_warp_proof_response(
1455 &event.peer_id,
1456 EncodedProof(*response.downcast::<Vec<u8>>().unwrap()),
1457 );
1458
1459 assert_eq!(warp_sync.actions.len(), 1);
1460 let SyncingAction::ImportBlocks { origin, mut blocks } = warp_sync.actions.pop().unwrap()
1461 else {
1462 panic!("Expected `ImportBlocks` action.");
1463 };
1464 assert_eq!(origin, BlockOrigin::WarpSync);
1465 assert_eq!(blocks.len(), 1);
1467 let import_block = blocks.pop().unwrap();
1468 assert_eq!(
1469 import_block,
1470 IncomingBlock {
1471 hash: warp_synced_header.hash(),
1472 header: Some(warp_synced_header),
1473 body: None,
1474 justifications: Some(warp_justifications),
1475 origin: Some(request_peer_id),
1476 allow_missing_state: true,
1477 skip_execution: true,
1478 import_existing: false,
1479 state: None,
1480 }
1481 );
1482 assert!(matches!(&warp_sync.phase, Phase::TargetBlock(header) if *header == target_header));
1483
1484 let mut actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
1485 assert_eq!(actions.len(), 1);
1486 let SyncingAction::StartRequest { peer_id: target_peer, key, request } =
1487 actions.pop().unwrap()
1488 else {
1489 panic!("Expected target block request.");
1490 };
1491 assert_eq!(target_peer, request_peer_id);
1492 pending.insert(target_peer, key, request);
1494 assert_eq!(pending.len(), 1);
1495 assert_eq!(warp_sync.actions(&network_handle).count(), 0);
1496 }
1497
1498 #[test]
1499 fn no_target_block_requests_in_another_phase() {
1500 let client = mock_client_without_state();
1501 let mut provider = MockWarpSyncProvider::<Block>::new();
1502 let mut verifier = MockVerifier::<Block>::new();
1503 verifier.expect_next_proof_context().returning(|| Hash::random());
1504 verifier
1505 .expect_verify()
1506 .returning(|_| unreachable!("verify should not be called in this test"));
1507 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1508 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1509 let mut warp_sync = WarpSync::new(
1510 Arc::new(client),
1511 config,
1512 None,
1513 Arc::new(MockBlockDownloader::new()),
1514 None,
1515 );
1516
1517 for best_number in 1..11 {
1519 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1520 }
1521 assert!(matches!(warp_sync.phase, Phase::WarpProof { .. }));
1523
1524 assert!(warp_sync.target_block_request().is_none());
1526 }
1527
1528 #[test]
1529 fn target_block_request_is_correct() {
1530 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1531 let mut provider = MockWarpSyncProvider::<Block>::new();
1532 let mut verifier = MockVerifier::<Block>::new();
1533 let header_for_ctx = client.info().genesis_hash;
1534 verifier.expect_next_proof_context().returning(move || header_for_ctx);
1535 let target_block = BlockBuilderBuilder::new(&*client)
1536 .on_parent_block(client.chain_info().best_hash)
1537 .with_parent_block_number(client.chain_info().best_number)
1538 .build()
1539 .unwrap()
1540 .build()
1541 .unwrap()
1542 .block;
1543 let target_header = target_block.header().clone();
1544 let header_for_verify = target_header.clone();
1546 verifier.expect_verify().return_once(move |_proof| {
1547 Ok(VerificationResult::Complete(header_for_verify, Default::default()))
1548 });
1549 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1550 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1551 let mut warp_sync =
1552 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1553
1554 for best_number in 1..11 {
1556 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1557 }
1558
1559 warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1561
1562 let (_peer_id, request) = warp_sync.target_block_request().unwrap();
1563 assert_eq!(request.from, FromBlock::Hash(target_block.header().hash()));
1564 assert_eq!(
1565 request.fields,
1566 BlockAttributes::HEADER | BlockAttributes::BODY | BlockAttributes::JUSTIFICATION
1567 );
1568 assert_eq!(request.max, Some(1));
1569 }
1570
1571 #[test]
1572 fn externally_set_target_block_is_requested() {
1573 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1574 let target_block = BlockBuilderBuilder::new(&*client)
1575 .on_parent_block(client.chain_info().best_hash)
1576 .with_parent_block_number(client.chain_info().best_number)
1577 .build()
1578 .unwrap()
1579 .build()
1580 .unwrap()
1581 .block;
1582 let target_header = target_block.header().clone();
1583 let config = WarpSyncConfig::WithTarget(target_header);
1584 let mut warp_sync =
1585 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1586
1587 for best_number in 1..11 {
1589 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1590 }
1591
1592 assert!(matches!(warp_sync.phase, Phase::TargetBlock(_)));
1593
1594 let (_peer_id, request) = warp_sync.target_block_request().unwrap();
1595 assert_eq!(request.from, FromBlock::Hash(target_block.header().hash()));
1596 assert_eq!(
1597 request.fields,
1598 BlockAttributes::HEADER | BlockAttributes::BODY | BlockAttributes::JUSTIFICATION
1599 );
1600 assert_eq!(request.max, Some(1));
1601 }
1602
1603 #[test]
1604 fn no_parallel_target_block_requests() {
1605 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1606 let mut provider = MockWarpSyncProvider::<Block>::new();
1607 let mut verifier = MockVerifier::<Block>::new();
1608 let header_for_ctx = client.info().genesis_hash;
1609 verifier.expect_next_proof_context().returning(move || header_for_ctx);
1610 let target_block = BlockBuilderBuilder::new(&*client)
1611 .on_parent_block(client.chain_info().best_hash)
1612 .with_parent_block_number(client.chain_info().best_number)
1613 .build()
1614 .unwrap()
1615 .build()
1616 .unwrap()
1617 .block;
1618 let target_header = target_block.header().clone();
1619 let header_for_verify = target_header.clone();
1621 verifier.expect_verify().return_once(move |_proof| {
1622 Ok(VerificationResult::Complete(header_for_verify, Default::default()))
1623 });
1624 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1625 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1626 let mut warp_sync =
1627 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1628
1629 for best_number in 1..11 {
1631 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1632 }
1633
1634 warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1636
1637 assert!(warp_sync.target_block_request().is_some());
1639 assert!(warp_sync.target_block_request().is_none());
1641 }
1642
1643 #[test]
1644 fn target_block_response_with_no_blocks_drops_peer() {
1645 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1646 let mut provider = MockWarpSyncProvider::<Block>::new();
1647 let mut verifier = MockVerifier::<Block>::new();
1648 let header_for_ctx = client.info().genesis_hash;
1649 verifier.expect_next_proof_context().returning(move || header_for_ctx);
1650 let target_block = BlockBuilderBuilder::new(&*client)
1651 .on_parent_block(client.chain_info().best_hash)
1652 .with_parent_block_number(client.chain_info().best_number)
1653 .build()
1654 .unwrap()
1655 .build()
1656 .unwrap()
1657 .block;
1658 let target_header = target_block.header().clone();
1659 let header_for_verify = target_header.clone();
1661 verifier.expect_verify().return_once(move |_proof| {
1662 Ok(VerificationResult::Complete(header_for_verify, Default::default()))
1663 });
1664 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1665 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1666 let mut warp_sync =
1667 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1668
1669 for best_number in 1..11 {
1671 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1672 }
1673
1674 warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1676
1677 let (peer_id, request) = warp_sync.target_block_request().unwrap();
1678
1679 let response = Vec::new();
1681 assert!(matches!(
1683 warp_sync.on_block_response_inner(peer_id, request, response),
1684 Err(BadPeer(id, _rep)) if id == peer_id,
1685 ));
1686 }
1687
1688 #[test]
1689 fn target_block_response_with_extra_blocks_drops_peer() {
1690 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1691 let mut provider = MockWarpSyncProvider::<Block>::new();
1692 let mut verifier = MockVerifier::<Block>::new();
1693 let header_for_ctx = client.info().genesis_hash;
1694 verifier.expect_next_proof_context().returning(move || header_for_ctx);
1695 let target_block = BlockBuilderBuilder::new(&*client)
1696 .on_parent_block(client.chain_info().best_hash)
1697 .with_parent_block_number(client.chain_info().best_number)
1698 .build()
1699 .unwrap()
1700 .build()
1701 .unwrap()
1702 .block;
1703
1704 let mut extra_block_builder = BlockBuilderBuilder::new(&*client)
1705 .on_parent_block(client.chain_info().best_hash)
1706 .with_parent_block_number(client.chain_info().best_number)
1707 .build()
1708 .unwrap();
1709 extra_block_builder
1710 .push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6]))
1711 .unwrap();
1712 let extra_block = extra_block_builder.build().unwrap().block;
1713
1714 let target_header = target_block.header().clone();
1715 let header_for_verify = target_header.clone();
1717 verifier.expect_verify().return_once(move |_proof| {
1718 Ok(VerificationResult::Complete(header_for_verify, Default::default()))
1719 });
1720 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1721 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1722 let mut warp_sync =
1723 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1724
1725 for best_number in 1..11 {
1727 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1728 }
1729
1730 warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1732
1733 let (peer_id, request) = warp_sync.target_block_request().unwrap();
1734
1735 let response = vec![
1737 BlockData::<Block> {
1738 hash: target_block.header().hash(),
1739 header: Some(target_block.header().clone()),
1740 body: Some(target_block.extrinsics().iter().cloned().collect::<Vec<_>>()),
1741 receipt: None,
1742 message_queue: None,
1743 justification: None,
1744 justifications: None,
1745 },
1746 BlockData::<Block> {
1747 hash: extra_block.header().hash(),
1748 header: Some(extra_block.header().clone()),
1749 body: Some(extra_block.extrinsics().iter().cloned().collect::<Vec<_>>()),
1750 receipt: None,
1751 message_queue: None,
1752 justification: None,
1753 justifications: None,
1754 },
1755 ];
1756 assert!(matches!(
1758 warp_sync.on_block_response_inner(peer_id, request, response),
1759 Err(BadPeer(id, _rep)) if id == peer_id,
1760 ));
1761 }
1762
1763 #[test]
1764 fn target_block_response_with_wrong_block_drops_peer() {
1765 sp_tracing::try_init_simple();
1766
1767 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1768 let mut provider = MockWarpSyncProvider::<Block>::new();
1769 let mut verifier = MockVerifier::<Block>::new();
1770 let header_for_ctx = client.info().genesis_hash;
1771 verifier.expect_next_proof_context().returning(move || header_for_ctx);
1772 let target_block = BlockBuilderBuilder::new(&*client)
1773 .on_parent_block(client.chain_info().best_hash)
1774 .with_parent_block_number(client.chain_info().best_number)
1775 .build()
1776 .unwrap()
1777 .build()
1778 .unwrap()
1779 .block;
1780
1781 let mut wrong_block_builder = BlockBuilderBuilder::new(&*client)
1782 .on_parent_block(client.chain_info().best_hash)
1783 .with_parent_block_number(client.chain_info().best_number)
1784 .build()
1785 .unwrap();
1786 wrong_block_builder
1787 .push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6]))
1788 .unwrap();
1789 let wrong_block = wrong_block_builder.build().unwrap().block;
1790
1791 let target_header = target_block.header().clone();
1792 let header_for_verify = target_header.clone();
1794 verifier.expect_verify().return_once(move |_proof| {
1795 Ok(VerificationResult::Complete(header_for_verify, Default::default()))
1796 });
1797 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1798 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1799 let mut warp_sync =
1800 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1801
1802 for best_number in 1..11 {
1804 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1805 }
1806
1807 warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1809
1810 let (peer_id, request) = warp_sync.target_block_request().unwrap();
1811
1812 let response = vec![BlockData::<Block> {
1814 hash: wrong_block.header().hash(),
1815 header: Some(wrong_block.header().clone()),
1816 body: Some(wrong_block.extrinsics().iter().cloned().collect::<Vec<_>>()),
1817 receipt: None,
1818 message_queue: None,
1819 justification: None,
1820 justifications: None,
1821 }];
1822 assert!(matches!(
1824 warp_sync.on_block_response_inner(peer_id, request, response),
1825 Err(BadPeer(id, _rep)) if id == peer_id,
1826 ));
1827 }
1828
1829 #[test]
1830 fn correct_target_block_response_sets_strategy_result() {
1831 let client = Arc::new(TestClientBuilder::new().set_no_genesis().build());
1832 let mut provider = MockWarpSyncProvider::<Block>::new();
1833 let mut verifier = MockVerifier::<Block>::new();
1834 let header_for_ctx = client.info().genesis_hash;
1835 verifier.expect_next_proof_context().returning(move || header_for_ctx);
1836 let mut target_block_builder = BlockBuilderBuilder::new(&*client)
1837 .on_parent_block(client.chain_info().best_hash)
1838 .with_parent_block_number(client.chain_info().best_number)
1839 .build()
1840 .unwrap();
1841 target_block_builder
1842 .push_storage_change(vec![1, 2, 3], Some(vec![4, 5, 6]))
1843 .unwrap();
1844 let target_block = target_block_builder.build().unwrap().block;
1845 let target_header = target_block.header().clone();
1846 let header_for_verify = target_header.clone();
1848 verifier.expect_verify().return_once(move |_proof| {
1849 Ok(VerificationResult::Complete(header_for_verify, Default::default()))
1850 });
1851 provider.expect_create_verifier().return_once(move || Box::new(verifier));
1852 let config = WarpSyncConfig::WithProvider(Arc::new(provider));
1853 let mut warp_sync =
1854 WarpSync::new(client, config, None, Arc::new(MockBlockDownloader::new()), None);
1855
1856 for best_number in 1..11 {
1858 warp_sync.add_peer(PeerId::random(), Hash::random(), best_number);
1859 }
1860
1861 warp_sync.phase = Phase::TargetBlock(target_block.header().clone());
1863
1864 let (peer_id, request) = warp_sync.target_block_request().unwrap();
1865
1866 let body = Some(target_block.extrinsics().iter().cloned().collect::<Vec<_>>());
1868 let justifications = Some(Justifications::from((*b"FRNK", Vec::new())));
1869 let response = vec![BlockData::<Block> {
1870 hash: target_block.header().hash(),
1871 header: Some(target_block.header().clone()),
1872 body: body.clone(),
1873 receipt: None,
1874 message_queue: None,
1875 justification: None,
1876 justifications: justifications.clone(),
1877 }];
1878
1879 assert!(warp_sync.on_block_response_inner(peer_id, request, response).is_ok());
1880
1881 let network_provider = NetworkServiceProvider::new();
1882 let network_handle = network_provider.handle();
1883
1884 let actions = warp_sync.actions(&network_handle).collect::<Vec<_>>();
1886 assert_eq!(actions.len(), 1);
1887 assert!(matches!(actions[0], SyncingAction::Finished));
1888
1889 let result = warp_sync.take_result().unwrap();
1891 assert_eq!(result.target_header, *target_block.header());
1892 assert_eq!(result.target_body, body);
1893 assert_eq!(result.target_justifications, justifications);
1894 }
1895}