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