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