referrerpolicy=no-referrer-when-downgrade

sc_network_sync/
strategy.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
5
6// This program is free software: you can redistribute it and/or modify
7// it under the terms of the GNU General Public License as published by
8// the Free Software Foundation, either version 3 of the License, or
9// (at your option) any later version.
10
11// This program is distributed in the hope that it will be useful,
12// but WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14// GNU General Public License for more details.
15
16// You should have received a copy of the GNU General Public License
17// along with this program. If not, see <https://www.gnu.org/licenses/>.
18
19//! [`SyncingStrategy`] defines an interface [`crate::engine::SyncingEngine`] uses as a specific
20//! syncing algorithm.
21//!
22//! A few different strategies are provided by Substrate out of the box with custom strategies
23//! possible too.
24
25pub mod chain_sync;
26mod disconnected_peers;
27pub mod polkadot;
28pub mod state;
29pub mod state_sync;
30pub mod warp;
31
32use crate::{
33	pending_responses::ResponseFuture,
34	service::network::NetworkServiceHandle,
35	types::{BadPeer, SyncStatus},
36};
37use sc_consensus::{BlockImportError, BlockImportStatus, IncomingBlock};
38use sc_network::ProtocolName;
39use sc_network_common::sync::message::BlockAnnounce;
40use sc_network_types::PeerId;
41use sp_blockchain::Error as ClientError;
42use sp_consensus::BlockOrigin;
43use sp_runtime::{
44	traits::{Block as BlockT, NumberFor},
45	Justifications,
46};
47use std::any::Any;
48
49/// Syncing strategy for syncing engine to use
50pub trait SyncingStrategy<B: BlockT>: Send
51where
52	B: BlockT,
53{
54	/// Notify syncing state machine that a new sync peer has connected.
55	fn add_peer(&mut self, peer_id: PeerId, best_hash: B::Hash, best_number: NumberFor<B>);
56
57	/// Notify that a sync peer has disconnected.
58	fn remove_peer(&mut self, peer_id: &PeerId);
59
60	/// Submit a validated block announcement.
61	///
62	/// Returns new best hash & best number of the peer if they are updated.
63	#[must_use]
64	fn on_validated_block_announce(
65		&mut self,
66		is_best: bool,
67		peer_id: PeerId,
68		announce: &BlockAnnounce<B::Header>,
69	) -> Option<(B::Hash, NumberFor<B>)>;
70
71	/// Configure an explicit fork sync request in case external code has detected that there is a
72	/// stale fork missing.
73	///
74	/// Note that this function should not be used for recent blocks.
75	/// Sync should be able to download all the recent forks normally.
76	///
77	/// Passing empty `peers` set effectively removes the sync request.
78	fn set_sync_fork_request(&mut self, peers: Vec<PeerId>, hash: &B::Hash, number: NumberFor<B>);
79
80	/// Request extra justification.
81	fn request_justification(&mut self, hash: &B::Hash, number: NumberFor<B>);
82
83	/// Clear extra justification requests.
84	fn clear_justification_requests(&mut self);
85
86	/// Report a justification import (successful or not).
87	fn on_justification_import(&mut self, hash: B::Hash, number: NumberFor<B>, success: bool);
88
89	/// Process generic response.
90	///
91	/// Strategy has to create opaque response and should be to downcast it back into concrete type
92	/// internally. Failure to downcast is an implementation bug.
93	fn on_generic_response(
94		&mut self,
95		peer_id: &PeerId,
96		key: StrategyKey,
97		protocol_name: ProtocolName,
98		response: Box<dyn Any + Send>,
99	);
100
101	/// A batch of blocks that have been processed, with or without errors.
102	///
103	/// Call this when a batch of blocks that have been processed by the import queue, with or
104	/// without errors.
105	fn on_blocks_processed(
106		&mut self,
107		imported: usize,
108		count: usize,
109		results: Vec<(Result<BlockImportStatus<NumberFor<B>>, BlockImportError>, B::Hash)>,
110	);
111
112	/// Notify a syncing strategy that a block has been finalized.
113	fn on_block_finalized(&mut self, hash: &B::Hash, number: NumberFor<B>);
114
115	/// Inform sync about a new best imported block.
116	fn update_chain_info(&mut self, best_hash: &B::Hash, best_number: NumberFor<B>);
117
118	// Are we in major sync mode?
119	fn is_major_syncing(&self) -> bool;
120
121	/// Get the number of peers known to the syncing strategy.
122	fn num_peers(&self) -> usize;
123
124	/// Returns the current sync status.
125	fn status(&self) -> SyncStatus<B>;
126
127	/// Get the total number of downloaded blocks.
128	fn num_downloaded_blocks(&self) -> usize;
129
130	/// Get an estimate of the number of parallel sync requests.
131	fn num_sync_requests(&self) -> usize;
132
133	/// Get actions that should be performed by the owner on the strategy's behalf
134	#[must_use]
135	fn actions(
136		&mut self,
137		// TODO: Consider making this internal property of the strategy
138		network_service: &NetworkServiceHandle,
139	) -> Result<Vec<SyncingAction<B>>, ClientError>;
140}
141
142/// The key identifying a specific strategy for responses routing.
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144pub struct StrategyKey(&'static str);
145
146impl StrategyKey {
147	/// Instantiate opaque strategy key.
148	pub const fn new(key: &'static str) -> Self {
149		Self(key)
150	}
151}
152
153pub enum SyncingAction<B: BlockT> {
154	/// Start request to peer.
155	StartRequest {
156		peer_id: PeerId,
157		key: StrategyKey,
158		request: ResponseFuture,
159		// Whether to remove obsolete pending responses.
160		remove_obsolete: bool,
161	},
162	/// Drop stale request.
163	CancelRequest { peer_id: PeerId, key: StrategyKey },
164	/// Peer misbehaved. Disconnect, report it and cancel any requests to it.
165	DropPeer(BadPeer),
166	/// Import blocks.
167	ImportBlocks { origin: BlockOrigin, blocks: Vec<IncomingBlock<B>> },
168	/// Import justifications.
169	ImportJustifications {
170		peer_id: PeerId,
171		hash: B::Hash,
172		number: NumberFor<B>,
173		justifications: Justifications,
174	},
175	/// Strategy finished. Nothing to do, this is handled by `PolkadotSyncingStrategy`.
176	Finished,
177}
178
179// Note: Ideally we can deduce this information with #[derive(derive_more::Debug)].
180// However, we'd need a bump to the latest version 2 of the crate.
181impl<B> std::fmt::Debug for SyncingAction<B>
182where
183	B: BlockT,
184{
185	fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
186		match &self {
187			Self::StartRequest { peer_id, key, remove_obsolete, .. } => {
188				write!(
189					f,
190					"StartRequest {{ peer_id: {:?}, key: {:?}, remove_obsolete: {:?} }}",
191					peer_id, key, remove_obsolete
192				)
193			},
194			Self::CancelRequest { peer_id, key } => {
195				write!(f, "CancelRequest {{ peer_id: {:?}, key: {:?} }}", peer_id, key)
196			},
197			Self::DropPeer(peer) => write!(f, "DropPeer({:?})", peer),
198			Self::ImportBlocks { blocks, .. } => write!(f, "ImportBlocks({:?})", blocks),
199			Self::ImportJustifications { hash, number, .. } => {
200				write!(f, "ImportJustifications({:?}, {:?})", hash, number)
201			},
202			Self::Finished => write!(f, "Finished"),
203		}
204	}
205}
206
207impl<B: BlockT> SyncingAction<B> {
208	/// Returns `true` if the syncing action has completed.
209	pub fn is_finished(&self) -> bool {
210		matches!(self, SyncingAction::Finished)
211	}
212
213	#[cfg(test)]
214	pub(crate) fn name(&self) -> &'static str {
215		match self {
216			Self::StartRequest { .. } => "StartRequest",
217			Self::CancelRequest { .. } => "CancelRequest",
218			Self::DropPeer(_) => "DropPeer",
219			Self::ImportBlocks { .. } => "ImportBlocks",
220			Self::ImportJustifications { .. } => "ImportJustifications",
221			Self::Finished => "Finished",
222		}
223	}
224}