referrerpolicy=no-referrer-when-downgrade

sc_consensus_grandpa/communication/
mod.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//! Communication streams for the polite-grandpa networking protocol.
20//!
21//! GRANDPA nodes communicate over a gossip network, where messages are not sent to
22//! peers until they have reached a given round.
23//!
24//! Rather than expressing protocol rules,
25//! polite-grandpa just carries a notion of impoliteness. Nodes which pass some arbitrary
26//! threshold of impoliteness are removed. Messages are either costly, or beneficial.
27//!
28//! For instance, it is _impolite_ to send the same message more than once.
29//! In the future, there will be a fallback for allowing sending the same message
30//! under certain conditions that are used to un-stick the protocol.
31
32use futures::{channel::mpsc, prelude::*};
33use log::{debug, trace};
34use parking_lot::Mutex;
35use prometheus_endpoint::Registry;
36use std::{
37	pin::Pin,
38	sync::Arc,
39	task::{Context, Poll},
40	time::Duration,
41};
42
43use codec::{Decode, DecodeAll, Encode};
44use finality_grandpa::{
45	voter,
46	voter_set::VoterSet,
47	Message::{Precommit, Prevote, PrimaryPropose},
48};
49use sc_network::{NetworkBlock, NetworkSyncForkRequest, NotificationService, ReputationChange};
50use sc_network_gossip::{GossipEngine, Network as GossipNetwork};
51use sc_telemetry::{telemetry, TelemetryHandle, CONSENSUS_DEBUG, CONSENSUS_INFO};
52use sp_keystore::KeystorePtr;
53use sp_runtime::traits::{Block as BlockT, Hash as HashT, Header as HeaderT, NumberFor};
54
55use crate::{
56	environment::HasVoted, CatchUp, Commit, CommunicationIn, CommunicationOutH, CompactCommit,
57	Error, Message, SignedMessage, LOG_TARGET,
58};
59use gossip::{
60	FullCatchUpMessage, FullCommitMessage, GossipMessage, GossipValidator, PeerReport, VoteMessage,
61};
62use sc_network_sync::SyncEventStream;
63use sc_utils::mpsc::TracingUnboundedReceiver;
64use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, RoundNumber, SetId as SetIdNumber};
65
66pub mod gossip;
67mod periodic;
68
69#[cfg(test)]
70pub(crate) mod tests;
71
72// How often to rebroadcast neighbor packets, in cases where no new packets are created.
73pub(crate) const NEIGHBOR_REBROADCAST_PERIOD: Duration = Duration::from_secs(2 * 60);
74
75pub mod grandpa_protocol_name {
76	use sc_chain_spec::ChainSpec;
77	use sc_network::types::ProtocolName;
78
79	pub(crate) const NAME: &str = "/grandpa/1";
80	/// Old names for the notifications protocol, used for backward compatibility.
81	pub(crate) const LEGACY_NAMES: [&str; 1] = ["/paritytech/grandpa/1"];
82
83	/// Name of the notifications protocol used by GRANDPA.
84	///
85	/// Must be registered towards the networking in order for GRANDPA to properly function.
86	pub fn standard_name<Hash: AsRef<[u8]>>(
87		genesis_hash: &Hash,
88		chain_spec: &Box<dyn ChainSpec>,
89	) -> ProtocolName {
90		let genesis_hash = genesis_hash.as_ref();
91		let chain_prefix = match chain_spec.fork_id() {
92			Some(fork_id) => format!("/{}/{}", array_bytes::bytes2hex("", genesis_hash), fork_id),
93			None => format!("/{}", array_bytes::bytes2hex("", genesis_hash)),
94		};
95		format!("{}{}", chain_prefix, NAME).into()
96	}
97}
98
99// cost scalars for reporting peers.
100mod cost {
101	use sc_network::ReputationChange as Rep;
102	pub(super) const PAST_REJECTION: Rep = Rep::new(-50, "Grandpa: Past message");
103	pub(super) const BAD_SIGNATURE: Rep = Rep::new(-100, "Grandpa: Bad signature");
104	pub(super) const MALFORMED_CATCH_UP: Rep = Rep::new(-1000, "Grandpa: Malformed cath-up");
105	pub(super) const MALFORMED_COMMIT: Rep = Rep::new(-1000, "Grandpa: Malformed commit");
106	pub(super) const FUTURE_MESSAGE: Rep = Rep::new(-500, "Grandpa: Future message");
107	pub(super) const UNKNOWN_VOTER: Rep = Rep::new(-150, "Grandpa: Unknown voter");
108
109	pub(super) const INVALID_VIEW_CHANGE: Rep = Rep::new(-500, "Grandpa: Invalid view change");
110	pub(super) const DUPLICATE_NEIGHBOR_MESSAGE: Rep =
111		Rep::new(-500, "Grandpa: Duplicate neighbor message without grace period");
112	pub(super) const PER_UNDECODABLE_BYTE: i32 = -5;
113	pub(super) const PER_SIGNATURE_CHECKED: i32 = -25;
114	pub(super) const PER_BLOCK_LOADED: i32 = -10;
115	pub(super) const INVALID_CATCH_UP: Rep = Rep::new(-5000, "Grandpa: Invalid catch-up");
116	pub(super) const INVALID_COMMIT: Rep = Rep::new(-5000, "Grandpa: Invalid commit");
117	pub(super) const OUT_OF_SCOPE_MESSAGE: Rep = Rep::new(-500, "Grandpa: Out-of-scope message");
118	pub(super) const CATCH_UP_REQUEST_TIMEOUT: Rep =
119		Rep::new(-200, "Grandpa: Catch-up request timeout");
120
121	// cost of answering a catch up request
122	pub(super) const CATCH_UP_REPLY: Rep = Rep::new(-200, "Grandpa: Catch-up reply");
123	pub(super) const HONEST_OUT_OF_SCOPE_CATCH_UP: Rep =
124		Rep::new(-200, "Grandpa: Out-of-scope catch-up");
125}
126
127// benefit scalars for reporting peers.
128mod benefit {
129	use sc_network::ReputationChange as Rep;
130	pub(super) const NEIGHBOR_MESSAGE: Rep = Rep::new(100, "Grandpa: Neighbor message");
131	pub(super) const ROUND_MESSAGE: Rep = Rep::new(100, "Grandpa: Round message");
132	pub(super) const BASIC_VALIDATED_CATCH_UP: Rep = Rep::new(200, "Grandpa: Catch-up message");
133	pub(super) const BASIC_VALIDATED_COMMIT: Rep = Rep::new(100, "Grandpa: Commit");
134	pub(super) const PER_EQUIVOCATION: i32 = 10;
135}
136
137/// A type that ties together our local authority id and a keystore where it is
138/// available for signing.
139pub struct LocalIdKeystore((AuthorityId, KeystorePtr));
140
141impl LocalIdKeystore {
142	/// Returns a reference to our local authority id.
143	fn local_id(&self) -> &AuthorityId {
144		&(self.0).0
145	}
146
147	/// Returns a reference to the keystore.
148	fn keystore(&self) -> KeystorePtr {
149		(self.0).1.clone()
150	}
151}
152
153impl From<(AuthorityId, KeystorePtr)> for LocalIdKeystore {
154	fn from(inner: (AuthorityId, KeystorePtr)) -> LocalIdKeystore {
155		LocalIdKeystore(inner)
156	}
157}
158
159/// If the voter set is larger than this value some telemetry events are not
160/// sent to avoid increasing usage resource on the node and flooding the
161/// telemetry server (e.g. received votes, received commits.)
162const TELEMETRY_VOTERS_LIMIT: usize = 10;
163
164/// A handle to the network.
165///
166/// Something that provides the capabilities needed for the `gossip_network::Network` trait.
167pub trait Network<Block: BlockT>: GossipNetwork<Block> + Clone + Send + 'static {}
168
169impl<Block, T> Network<Block> for T
170where
171	Block: BlockT,
172	T: GossipNetwork<Block> + Clone + Send + 'static,
173{
174}
175
176/// A handle to syncing-related services.
177///
178/// Something that provides the ability to set a fork sync request for a particular block.
179pub trait Syncing<Block: BlockT>:
180	NetworkSyncForkRequest<Block::Hash, NumberFor<Block>>
181	+ NetworkBlock<Block::Hash, NumberFor<Block>>
182	+ SyncEventStream
183	+ Clone
184	+ Send
185	+ 'static
186{
187}
188
189impl<Block, T> Syncing<Block> for T
190where
191	Block: BlockT,
192	T: NetworkSyncForkRequest<Block::Hash, NumberFor<Block>>
193		+ NetworkBlock<Block::Hash, NumberFor<Block>>
194		+ SyncEventStream
195		+ Clone
196		+ Send
197		+ 'static,
198{
199}
200
201/// Create a unique topic for a round and set-id combo.
202pub(crate) fn round_topic<B: BlockT>(round: RoundNumber, set_id: SetIdNumber) -> B::Hash {
203	<<B::Header as HeaderT>::Hashing as HashT>::hash(format!("{}-{}", set_id, round).as_bytes())
204}
205
206/// Create a unique topic for global messages on a set ID.
207pub(crate) fn global_topic<B: BlockT>(set_id: SetIdNumber) -> B::Hash {
208	<<B::Header as HeaderT>::Hashing as HashT>::hash(format!("{}-GLOBAL", set_id).as_bytes())
209}
210
211/// Bridge between the underlying network service, gossiping consensus messages and Grandpa
212pub(crate) struct NetworkBridge<B: BlockT, N: Network<B>, S: Syncing<B>> {
213	service: N,
214	sync: S,
215	gossip_engine: Arc<Mutex<GossipEngine<B>>>,
216	validator: Arc<GossipValidator<B>>,
217
218	/// Sender side of the neighbor packet channel.
219	///
220	/// Packets sent into this channel are processed by the `NeighborPacketWorker` and passed on to
221	/// the underlying `GossipEngine`.
222	neighbor_sender: periodic::NeighborPacketSender<B>,
223
224	/// `NeighborPacketWorker` processing packets sent through the `NeighborPacketSender`.
225	// `NetworkBridge` is required to be clonable, thus one needs to be able to clone its
226	// children, thus one has to wrap `neighbor_packet_worker` with an `Arc` `Mutex`.
227	neighbor_packet_worker: Arc<Mutex<periodic::NeighborPacketWorker<B>>>,
228
229	/// Receiver side of the peer report stream populated by the gossip validator, forwarded to the
230	/// gossip engine.
231	// `NetworkBridge` is required to be clonable, thus one needs to be able to clone its
232	// children, thus one has to wrap gossip_validator_report_stream with an `Arc` `Mutex`. Given
233	// that it is just an `UnboundedReceiver`, one could also switch to a
234	// multi-producer-*multi*-consumer channel implementation.
235	gossip_validator_report_stream: Arc<Mutex<TracingUnboundedReceiver<PeerReport>>>,
236
237	telemetry: Option<TelemetryHandle>,
238}
239
240impl<B: BlockT, N: Network<B>, S: Syncing<B>> Unpin for NetworkBridge<B, N, S> {}
241
242impl<B: BlockT, N: Network<B>, S: Syncing<B>> NetworkBridge<B, N, S> {
243	/// Create a new NetworkBridge to the given NetworkService. Returns the service
244	/// handle.
245	/// On creation it will register previous rounds' votes with the gossip
246	/// service taken from the VoterSetState.
247	pub(crate) fn new(
248		service: N,
249		sync: S,
250		notification_service: Box<dyn NotificationService>,
251		config: crate::Config,
252		set_state: crate::environment::SharedVoterSetState<B>,
253		prometheus_registry: Option<&Registry>,
254		telemetry: Option<TelemetryHandle>,
255	) -> Self {
256		let protocol = config.protocol_name.clone();
257		let (validator, report_stream) =
258			GossipValidator::new(config, set_state.clone(), prometheus_registry, telemetry.clone());
259
260		let validator = Arc::new(validator);
261		let gossip_engine = Arc::new(Mutex::new(GossipEngine::new(
262			service.clone(),
263			sync.clone(),
264			notification_service,
265			protocol,
266			validator.clone(),
267			prometheus_registry,
268		)));
269
270		{
271			// register all previous votes with the gossip service so that they're
272			// available to peers potentially stuck on a previous round.
273			let completed = set_state.read().completed_rounds();
274			let (set_id, voters) = completed.set_info();
275			validator.note_set(SetId(set_id), voters.to_vec(), |_, _| {});
276			for round in completed.iter() {
277				let topic = round_topic::<B>(round.number, set_id);
278
279				// we need to note the round with the gossip validator otherwise
280				// messages will be ignored.
281				validator.note_round(Round(round.number), |_, _| {});
282
283				for signed in round.votes.iter() {
284					let message = gossip::GossipMessage::Vote(gossip::VoteMessage::<B> {
285						message: signed.clone(),
286						round: Round(round.number),
287						set_id: SetId(set_id),
288					});
289
290					gossip_engine.lock().register_gossip_message(topic, message.encode());
291				}
292
293				trace!(
294					target: LOG_TARGET,
295					"Registered {} messages for topic {:?} (round: {}, set_id: {})",
296					round.votes.len(),
297					topic,
298					round.number,
299					set_id,
300				);
301			}
302		}
303
304		let (neighbor_packet_worker, neighbor_packet_sender) =
305			periodic::NeighborPacketWorker::new(NEIGHBOR_REBROADCAST_PERIOD);
306
307		NetworkBridge {
308			service,
309			sync,
310			gossip_engine,
311			validator,
312			neighbor_sender: neighbor_packet_sender,
313			neighbor_packet_worker: Arc::new(Mutex::new(neighbor_packet_worker)),
314			gossip_validator_report_stream: Arc::new(Mutex::new(report_stream)),
315			telemetry,
316		}
317	}
318
319	/// Note the beginning of a new round to the `GossipValidator`.
320	pub(crate) fn note_round(&self, round: Round, set_id: SetId, voters: &VoterSet<AuthorityId>) {
321		// is a no-op if currently in that set.
322		self.validator.note_set(
323			set_id,
324			voters.iter().map(|(v, _)| v.clone()).collect(),
325			|to, neighbor| self.neighbor_sender.send(to, neighbor),
326		);
327
328		self.validator
329			.note_round(round, |to, neighbor| self.neighbor_sender.send(to, neighbor));
330	}
331
332	/// Get a stream of signature-checked round messages from the network as well as a sink for
333	/// round messages to the network all within the current set.
334	pub(crate) fn round_communication(
335		&self,
336		keystore: Option<LocalIdKeystore>,
337		round: Round,
338		set_id: SetId,
339		voters: Arc<VoterSet<AuthorityId>>,
340		has_voted: HasVoted<B::Header>,
341	) -> (impl Stream<Item = SignedMessage<B::Header>> + Unpin, OutgoingMessages<B>) {
342		self.note_round(round, set_id, &voters);
343
344		let keystore = keystore.and_then(|ks| {
345			let id = ks.local_id();
346			if voters.contains(id) {
347				Some(ks)
348			} else {
349				None
350			}
351		});
352
353		let topic = round_topic::<B>(round.0, set_id.0);
354		let telemetry = self.telemetry.clone();
355		let incoming =
356			self.gossip_engine.lock().messages_for(topic).filter_map(move |notification| {
357				let decoded = GossipMessage::<B>::decode_all(&mut &notification.message[..]);
358
359				match decoded {
360					Err(ref e) => {
361						debug!(
362							target: LOG_TARGET,
363							"Skipping malformed message {:?}: {}", notification, e
364						);
365						future::ready(None)
366					},
367					Ok(GossipMessage::Vote(msg)) => {
368						// check signature.
369						if !voters.contains(&msg.message.id) {
370							debug!(
371								target: LOG_TARGET,
372								"Skipping message from unknown voter {}", msg.message.id
373							);
374							return future::ready(None);
375						}
376
377						if voters.len().get() <= TELEMETRY_VOTERS_LIMIT {
378							match &msg.message.message {
379								PrimaryPropose(propose) => {
380									telemetry!(
381										telemetry;
382										CONSENSUS_INFO;
383										"afg.received_propose";
384										"voter" => ?format!("{}", msg.message.id),
385										"target_number" => ?propose.target_number,
386										"target_hash" => ?propose.target_hash,
387									);
388								},
389								Prevote(prevote) => {
390									telemetry!(
391										telemetry;
392										CONSENSUS_INFO;
393										"afg.received_prevote";
394										"voter" => ?format!("{}", msg.message.id),
395										"target_number" => ?prevote.target_number,
396										"target_hash" => ?prevote.target_hash,
397									);
398								},
399								Precommit(precommit) => {
400									telemetry!(
401										telemetry;
402										CONSENSUS_INFO;
403										"afg.received_precommit";
404										"voter" => ?format!("{}", msg.message.id),
405										"target_number" => ?precommit.target_number,
406										"target_hash" => ?precommit.target_hash,
407									);
408								},
409							};
410						}
411
412						future::ready(Some(msg.message))
413					},
414					_ => {
415						debug!(target: LOG_TARGET, "Skipping unknown message type");
416						future::ready(None)
417					},
418				}
419			});
420
421		let (tx, out_rx) = mpsc::channel(0);
422		let outgoing = OutgoingMessages::<B> {
423			keystore,
424			round: round.0,
425			set_id: set_id.0,
426			network: self.gossip_engine.clone(),
427			sender: tx,
428			has_voted,
429			telemetry: self.telemetry.clone(),
430		};
431
432		// Combine incoming votes from external GRANDPA nodes with outgoing
433		// votes from our own GRANDPA voter to have a single
434		// vote-import-pipeline.
435		let incoming = stream::select(incoming, out_rx);
436
437		(incoming, outgoing)
438	}
439
440	/// Set up the global communication streams.
441	pub(crate) fn global_communication(
442		&self,
443		set_id: SetId,
444		voters: Arc<VoterSet<AuthorityId>>,
445		is_voter: bool,
446	) -> (
447		impl Stream<Item = CommunicationIn<B>>,
448		impl Sink<CommunicationOutH<B, B::Hash>, Error = Error> + Unpin,
449	) {
450		self.validator.note_set(
451			set_id,
452			voters.iter().map(|(v, _)| v.clone()).collect(),
453			|to, neighbor| self.neighbor_sender.send(to, neighbor),
454		);
455
456		let topic = global_topic::<B>(set_id.0);
457		let incoming = incoming_global(
458			self.gossip_engine.clone(),
459			topic,
460			voters,
461			self.validator.clone(),
462			self.neighbor_sender.clone(),
463			self.telemetry.clone(),
464		);
465
466		let outgoing = CommitsOut::<B>::new(
467			self.gossip_engine.clone(),
468			set_id.0,
469			is_voter,
470			self.validator.clone(),
471			self.neighbor_sender.clone(),
472			self.telemetry.clone(),
473		);
474
475		let outgoing = outgoing.with(|out| {
476			let voter::CommunicationOut::Commit(round, commit) = out;
477			future::ok((round, commit))
478		});
479
480		(incoming, outgoing)
481	}
482
483	/// Directly gossip a commit message to the network.
484	pub(crate) fn gossip_commit(
485		&self,
486		round: RoundNumber,
487		set_id: SetIdNumber,
488		commit: Commit<B::Header>,
489	) {
490		let target_number = commit.target_number;
491		let round = Round(round);
492		let set_id = SetId(set_id);
493		let topic = global_topic::<B>(set_id.0);
494		let encoded = encode_commit_message::<B>(round, set_id, commit);
495
496		self.validator
497			.note_commit_finalized(round, set_id, target_number, |to, neighbor| {
498				self.neighbor_sender.send(to, neighbor)
499			});
500		self.gossip_engine.lock().gossip_message(topic, encoded, false);
501	}
502
503	/// Notifies the sync service to try and sync the given block from the given
504	/// peers.
505	///
506	/// If the given vector of peers is empty then the underlying implementation
507	/// should make a best effort to fetch the block from any peers it is
508	/// connected to (NOTE: this assumption will change in the future #3629).
509	pub(crate) fn set_sync_fork_request(
510		&self,
511		peers: Vec<sc_network_types::PeerId>,
512		hash: B::Hash,
513		number: NumberFor<B>,
514	) {
515		self.sync.set_sync_fork_request(peers, hash, number)
516	}
517}
518
519impl<B: BlockT, N: Network<B>, S: Syncing<B>> Future for NetworkBridge<B, N, S> {
520	type Output = Result<(), Error>;
521
522	fn poll(self: Pin<&mut Self>, cx: &mut Context) -> Poll<Self::Output> {
523		loop {
524			match self.neighbor_packet_worker.lock().poll_next_unpin(cx) {
525				Poll::Ready(Some((to, packet))) => {
526					self.gossip_engine.lock().send_message(to, packet.encode());
527				},
528				Poll::Ready(None) => {
529					return Poll::Ready(Err(Error::Network(
530						"Neighbor packet worker stream closed.".into(),
531					)))
532				},
533				Poll::Pending => break,
534			}
535		}
536
537		loop {
538			match self.gossip_validator_report_stream.lock().poll_next_unpin(cx) {
539				Poll::Ready(Some(PeerReport { who, cost_benefit })) => {
540					self.gossip_engine.lock().report(who, cost_benefit);
541				},
542				Poll::Ready(None) => {
543					return Poll::Ready(Err(Error::Network(
544						"Gossip validator report stream closed.".into(),
545					)))
546				},
547				Poll::Pending => break,
548			}
549		}
550
551		match self.gossip_engine.lock().poll_unpin(cx) {
552			Poll::Ready(()) => {
553				return Poll::Ready(Err(Error::Network("Gossip engine future finished.".into())))
554			},
555			Poll::Pending => {},
556		}
557
558		Poll::Pending
559	}
560}
561
562fn incoming_global<B: BlockT>(
563	gossip_engine: Arc<Mutex<GossipEngine<B>>>,
564	topic: B::Hash,
565	voters: Arc<VoterSet<AuthorityId>>,
566	gossip_validator: Arc<GossipValidator<B>>,
567	neighbor_sender: periodic::NeighborPacketSender<B>,
568	telemetry: Option<TelemetryHandle>,
569) -> impl Stream<Item = CommunicationIn<B>> {
570	let process_commit = {
571		let telemetry = telemetry.clone();
572		move |msg: FullCommitMessage<B>,
573		      mut notification: sc_network_gossip::TopicNotification,
574		      gossip_engine: &Arc<Mutex<GossipEngine<B>>>,
575		      gossip_validator: &Arc<GossipValidator<B>>,
576		      voters: &VoterSet<AuthorityId>| {
577			if voters.len().get() <= TELEMETRY_VOTERS_LIMIT {
578				let precommits_signed_by: Vec<String> =
579					msg.message.auth_data.iter().map(move |(_, a)| format!("{}", a)).collect();
580
581				telemetry!(
582					telemetry;
583					CONSENSUS_INFO;
584					"afg.received_commit";
585					"contains_precommits_signed_by" => ?precommits_signed_by,
586					"target_number" => ?msg.message.target_number.clone(),
587					"target_hash" => ?msg.message.target_hash.clone(),
588				);
589			}
590
591			if let Err(cost) = check_compact_commit::<B>(
592				&msg.message,
593				voters,
594				msg.round,
595				msg.set_id,
596				telemetry.as_ref(),
597			) {
598				if let Some(who) = notification.sender {
599					gossip_engine.lock().report(who, cost);
600				}
601
602				return None;
603			}
604
605			let round = msg.round;
606			let set_id = msg.set_id;
607			let commit = msg.message;
608			let finalized_number = commit.target_number;
609			let gossip_validator = gossip_validator.clone();
610			let gossip_engine = gossip_engine.clone();
611			let neighbor_sender = neighbor_sender.clone();
612			let cb = move |outcome| match outcome {
613				voter::CommitProcessingOutcome::Good(_) => {
614					// if it checks out, gossip it. not accounting for
615					// any discrepancy between the actual ghost and the claimed
616					// finalized number.
617					let advanced = gossip_validator.note_commit_finalized(
618						round,
619						set_id,
620						finalized_number,
621						|to, neighbor| neighbor_sender.send(to, neighbor),
622					);
623
624					if advanced {
625						gossip_engine.lock().gossip_message(
626							topic,
627							notification.message.clone(),
628							false,
629						);
630					} else {
631						debug!(
632							target: LOG_TARGET,
633							"Not gossiping commit for round {}, set_id {}, block #{:?}: \
634							 finality gossip view didn't advance",
635							round.0,
636							set_id.0,
637							finalized_number,
638						);
639						// still mark it as known, so that peers sending it to us later aren't
640						// penalized for sending a past message.
641						gossip_engine.lock().mark_message_known(&notification.message);
642					}
643				},
644				voter::CommitProcessingOutcome::Bad(_) => {
645					// report peer and do not gossip.
646					if let Some(who) = notification.sender.take() {
647						gossip_engine.lock().report(who, cost::INVALID_COMMIT);
648					}
649				},
650			};
651
652			let cb = voter::Callback::Work(Box::new(cb));
653
654			Some(voter::CommunicationIn::Commit(round.0, commit, cb))
655		}
656	};
657
658	let process_catch_up = move |msg: FullCatchUpMessage<B>,
659	                             mut notification: sc_network_gossip::TopicNotification,
660	                             gossip_engine: &Arc<Mutex<GossipEngine<B>>>,
661	                             gossip_validator: &Arc<GossipValidator<B>>,
662	                             voters: &VoterSet<AuthorityId>| {
663		let gossip_validator = gossip_validator.clone();
664		let gossip_engine = gossip_engine.clone();
665
666		if let Err(cost) = check_catch_up::<B>(&msg.message, voters, msg.set_id, telemetry.clone())
667		{
668			if let Some(who) = notification.sender {
669				gossip_engine.lock().report(who, cost);
670			}
671
672			return None;
673		}
674
675		let cb = move |outcome| {
676			if let voter::CatchUpProcessingOutcome::Bad(_) = outcome {
677				// report peer
678				if let Some(who) = notification.sender.take() {
679					gossip_engine.lock().report(who, cost::INVALID_CATCH_UP);
680				}
681			}
682
683			gossip_validator.note_catch_up_message_processed();
684		};
685
686		let cb = voter::Callback::Work(Box::new(cb));
687
688		Some(voter::CommunicationIn::CatchUp(msg.message, cb))
689	};
690
691	gossip_engine
692		.clone()
693		.lock()
694		.messages_for(topic)
695		.filter_map(|notification| {
696			// this could be optimized by decoding piecewise.
697			let decoded = GossipMessage::<B>::decode_all(&mut &notification.message[..]);
698			if let Err(ref e) = decoded {
699				trace!(
700					target: LOG_TARGET,
701					"Skipping malformed commit message {:?}: {}",
702					notification,
703					e
704				);
705			}
706			future::ready(decoded.map(move |d| (notification, d)).ok())
707		})
708		.filter_map(move |(notification, msg)| {
709			future::ready(match msg {
710				GossipMessage::Commit(msg) => {
711					process_commit(msg, notification, &gossip_engine, &gossip_validator, &voters)
712				},
713				GossipMessage::CatchUp(msg) => {
714					process_catch_up(msg, notification, &gossip_engine, &gossip_validator, &voters)
715				},
716				_ => {
717					debug!(target: LOG_TARGET, "Skipping unknown message type");
718					None
719				},
720			})
721		})
722}
723
724impl<B: BlockT, N: Network<B>, S: Syncing<B>> Clone for NetworkBridge<B, N, S> {
725	fn clone(&self) -> Self {
726		NetworkBridge {
727			service: self.service.clone(),
728			sync: self.sync.clone(),
729			gossip_engine: self.gossip_engine.clone(),
730			validator: Arc::clone(&self.validator),
731			neighbor_sender: self.neighbor_sender.clone(),
732			neighbor_packet_worker: self.neighbor_packet_worker.clone(),
733			gossip_validator_report_stream: self.gossip_validator_report_stream.clone(),
734			telemetry: self.telemetry.clone(),
735		}
736	}
737}
738
739/// Type-safe wrapper around a round number.
740#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Encode, Decode)]
741pub struct Round(pub RoundNumber);
742
743/// Type-safe wrapper around a set ID.
744#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Encode, Decode)]
745pub struct SetId(pub SetIdNumber);
746
747/// A sink for outgoing messages to the network. Any messages that are sent will
748/// be replaced, as appropriate, according to the given `HasVoted`.
749/// NOTE: The votes are stored unsigned, which means that the signatures need to
750/// be "stable", i.e. we should end up with the exact same signed message if we
751/// use the same raw message and key to sign. This is currently true for
752/// `ed25519` and `BLS` signatures (which we might use in the future), care must
753/// be taken when switching to different key types.
754pub(crate) struct OutgoingMessages<Block: BlockT> {
755	round: RoundNumber,
756	set_id: SetIdNumber,
757	keystore: Option<LocalIdKeystore>,
758	sender: mpsc::Sender<SignedMessage<Block::Header>>,
759	network: Arc<Mutex<GossipEngine<Block>>>,
760	has_voted: HasVoted<Block::Header>,
761	telemetry: Option<TelemetryHandle>,
762}
763
764impl<B: BlockT> Unpin for OutgoingMessages<B> {}
765
766impl<Block: BlockT> Sink<Message<Block::Header>> for OutgoingMessages<Block> {
767	type Error = Error;
768
769	fn poll_ready(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
770		Sink::poll_ready(Pin::new(&mut self.sender), cx).map(|elem| {
771			elem.map_err(|e| {
772				Error::Network(format!("Failed to poll_ready channel sender: {:?}", e))
773			})
774		})
775	}
776
777	fn start_send(
778		mut self: Pin<&mut Self>,
779		mut msg: Message<Block::Header>,
780	) -> Result<(), Self::Error> {
781		// if we've voted on this round previously under the same key, send that vote instead
782		match &mut msg {
783			finality_grandpa::Message::PrimaryPropose(ref mut vote) => {
784				if let Some(propose) = self.has_voted.propose() {
785					*vote = propose.clone();
786				}
787			},
788			finality_grandpa::Message::Prevote(ref mut vote) => {
789				if let Some(prevote) = self.has_voted.prevote() {
790					*vote = prevote.clone();
791				}
792			},
793			finality_grandpa::Message::Precommit(ref mut vote) => {
794				if let Some(precommit) = self.has_voted.precommit() {
795					*vote = precommit.clone();
796				}
797			},
798		}
799
800		// when locals exist, sign messages on import
801		if let Some(ref keystore) = self.keystore {
802			let target_hash = *(msg.target().0);
803			let signed = sp_consensus_grandpa::sign_message(
804				keystore.keystore(),
805				msg,
806				keystore.local_id().clone(),
807				self.round,
808				self.set_id,
809			)
810			.ok_or_else(|| {
811				Error::Signing(format!(
812					"Failed to sign GRANDPA vote for round {} targeting {:?}",
813					self.round, target_hash
814				))
815			})?;
816
817			let message = GossipMessage::Vote(VoteMessage::<Block> {
818				message: signed.clone(),
819				round: Round(self.round),
820				set_id: SetId(self.set_id),
821			});
822
823			debug!(
824				target: LOG_TARGET,
825				"Announcing block {} to peers which we voted on in round {} in set {}",
826				target_hash,
827				self.round,
828				self.set_id,
829			);
830
831			telemetry!(
832				self.telemetry;
833				CONSENSUS_DEBUG;
834				"afg.announcing_blocks_to_voted_peers";
835				"block" => ?target_hash, "round" => ?self.round, "set_id" => ?self.set_id,
836			);
837
838			// announce the block we voted on to our peers.
839			self.network.lock().announce(target_hash, None);
840
841			// propagate the message to peers
842			let topic = round_topic::<Block>(self.round, self.set_id);
843			self.network.lock().gossip_message(topic, message.encode(), false);
844
845			// forward the message to the inner sender.
846			return self.sender.start_send(signed).map_err(|e| {
847				Error::Network(format!("Failed to start_send on channel sender: {:?}", e))
848			});
849		};
850
851		Ok(())
852	}
853
854	fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context) -> Poll<Result<(), Self::Error>> {
855		Poll::Ready(Ok(()))
856	}
857
858	fn poll_close(mut self: Pin<&mut Self>, cx: &mut Context) -> Poll<Result<(), Self::Error>> {
859		Sink::poll_close(Pin::new(&mut self.sender), cx).map(|elem| {
860			elem.map_err(|e| {
861				Error::Network(format!("Failed to poll_close channel sender: {:?}", e))
862			})
863		})
864	}
865}
866
867// checks a compact commit. returns the cost associated with processing it if
868// the commit was bad.
869fn check_compact_commit<Block: BlockT>(
870	msg: &CompactCommit<Block::Header>,
871	voters: &VoterSet<AuthorityId>,
872	round: Round,
873	set_id: SetId,
874	telemetry: Option<&TelemetryHandle>,
875) -> Result<(), ReputationChange> {
876	// 4f + 1 = equivocations from f voters.
877	let f = voters.total_weight() - voters.threshold();
878	let full_threshold = (f + voters.total_weight()).0;
879
880	// check total weight is not out of range.
881	let mut total_weight = 0;
882	for (_, ref id) in &msg.auth_data {
883		if let Some(weight) = voters.get(id).map(|info| info.weight()) {
884			total_weight += weight.get();
885			if total_weight > full_threshold {
886				return Err(cost::MALFORMED_COMMIT);
887			}
888		} else {
889			debug!(target: LOG_TARGET, "Skipping commit containing unknown voter {}", id);
890			return Err(cost::MALFORMED_COMMIT);
891		}
892	}
893
894	if total_weight < voters.threshold().get() {
895		return Err(cost::MALFORMED_COMMIT);
896	}
897
898	// check signatures on all contained precommits.
899	let mut buf = Vec::new();
900	for (i, (precommit, (sig, id))) in msg.precommits.iter().zip(&msg.auth_data).enumerate() {
901		use crate::communication::gossip::Misbehavior;
902		use finality_grandpa::Message as GrandpaMessage;
903
904		if !sp_consensus_grandpa::check_message_signature_with_buffer(
905			&GrandpaMessage::Precommit(precommit.clone()),
906			id,
907			sig,
908			round.0,
909			set_id.0,
910			&mut buf,
911		)
912		.is_valid()
913		{
914			debug!(target: LOG_TARGET, "Bad commit message signature {}", id);
915			telemetry!(
916				telemetry;
917				CONSENSUS_DEBUG;
918				"afg.bad_commit_msg_signature";
919				"id" => ?id,
920			);
921			let cost = Misbehavior::BadCommitMessage {
922				signatures_checked: i as i32,
923				blocks_loaded: 0,
924				equivocations_caught: 0,
925			}
926			.cost();
927
928			return Err(cost);
929		}
930	}
931
932	Ok(())
933}
934
935// checks a catch up. returns the cost associated with processing it if
936// the catch up was bad.
937fn check_catch_up<Block: BlockT>(
938	msg: &CatchUp<Block::Header>,
939	voters: &VoterSet<AuthorityId>,
940	set_id: SetId,
941	telemetry: Option<TelemetryHandle>,
942) -> Result<(), ReputationChange> {
943	// 4f + 1 = equivocations from f voters.
944	let f = voters.total_weight() - voters.threshold();
945	let full_threshold = (f + voters.total_weight()).0;
946
947	// check total weight is not out of range for a set of votes.
948	fn check_weight<'a>(
949		voters: &'a VoterSet<AuthorityId>,
950		votes: impl Iterator<Item = &'a AuthorityId>,
951		full_threshold: u64,
952	) -> Result<(), ReputationChange> {
953		let mut total_weight = 0;
954
955		for id in votes {
956			if let Some(weight) = voters.get(id).map(|info| info.weight()) {
957				total_weight += weight.get();
958				if total_weight > full_threshold {
959					return Err(cost::MALFORMED_CATCH_UP);
960				}
961			} else {
962				debug!(
963					target: LOG_TARGET,
964					"Skipping catch up message containing unknown voter {}", id
965				);
966				return Err(cost::MALFORMED_CATCH_UP);
967			}
968		}
969
970		if total_weight < voters.threshold().get() {
971			return Err(cost::MALFORMED_CATCH_UP);
972		}
973
974		Ok(())
975	}
976
977	check_weight(voters, msg.prevotes.iter().map(|vote| &vote.id), full_threshold)?;
978
979	check_weight(voters, msg.precommits.iter().map(|vote| &vote.id), full_threshold)?;
980
981	fn check_signatures<'a, B, I>(
982		messages: I,
983		round: RoundNumber,
984		set_id: SetIdNumber,
985		mut signatures_checked: usize,
986		buf: &mut Vec<u8>,
987		telemetry: Option<TelemetryHandle>,
988	) -> Result<usize, ReputationChange>
989	where
990		B: BlockT,
991		I: Iterator<Item = (Message<B::Header>, &'a AuthorityId, &'a AuthoritySignature)>,
992	{
993		use crate::communication::gossip::Misbehavior;
994
995		for (msg, id, sig) in messages {
996			signatures_checked += 1;
997
998			if !sp_consensus_grandpa::check_message_signature_with_buffer(
999				&msg, id, sig, round, set_id, buf,
1000			)
1001			.is_valid()
1002			{
1003				debug!(target: LOG_TARGET, "Bad catch up message signature {}", id);
1004				telemetry!(
1005					telemetry;
1006					CONSENSUS_DEBUG;
1007					"afg.bad_catch_up_msg_signature";
1008					"id" => ?id,
1009				);
1010
1011				let cost = Misbehavior::BadCatchUpMessage {
1012					signatures_checked: signatures_checked as i32,
1013				}
1014				.cost();
1015
1016				return Err(cost);
1017			}
1018		}
1019
1020		Ok(signatures_checked)
1021	}
1022
1023	let mut buf = Vec::new();
1024
1025	// check signatures on all contained prevotes.
1026	let signatures_checked = check_signatures::<Block, _>(
1027		msg.prevotes.iter().map(|vote| {
1028			(finality_grandpa::Message::Prevote(vote.prevote.clone()), &vote.id, &vote.signature)
1029		}),
1030		msg.round_number,
1031		set_id.0,
1032		0,
1033		&mut buf,
1034		telemetry.clone(),
1035	)?;
1036
1037	// check signatures on all contained precommits.
1038	check_signatures::<Block, _>(
1039		msg.precommits.iter().map(|vote| {
1040			(
1041				finality_grandpa::Message::Precommit(vote.precommit.clone()),
1042				&vote.id,
1043				&vote.signature,
1044			)
1045		}),
1046		msg.round_number,
1047		set_id.0,
1048		signatures_checked,
1049		&mut buf,
1050		telemetry,
1051	)?;
1052
1053	Ok(())
1054}
1055
1056/// Encode a commit into a gossip message.
1057fn encode_commit_message<Block: BlockT>(
1058	round: Round,
1059	set_id: SetId,
1060	commit: Commit<Block::Header>,
1061) -> Vec<u8> {
1062	let (precommits, auth_data) = commit
1063		.precommits
1064		.into_iter()
1065		.map(|signed| (signed.precommit, (signed.signature, signed.id)))
1066		.unzip();
1067
1068	let compact_commit = CompactCommit::<Block::Header> {
1069		target_hash: commit.target_hash,
1070		target_number: commit.target_number,
1071		precommits,
1072		auth_data,
1073	};
1074
1075	let message = GossipMessage::Commit(FullCommitMessage::<Block> {
1076		round,
1077		set_id,
1078		message: compact_commit,
1079	});
1080
1081	message.encode()
1082}
1083
1084/// An output sink for commit messages.
1085struct CommitsOut<Block: BlockT> {
1086	network: Arc<Mutex<GossipEngine<Block>>>,
1087	set_id: SetId,
1088	is_voter: bool,
1089	gossip_validator: Arc<GossipValidator<Block>>,
1090	neighbor_sender: periodic::NeighborPacketSender<Block>,
1091	telemetry: Option<TelemetryHandle>,
1092}
1093
1094impl<Block: BlockT> CommitsOut<Block> {
1095	/// Create a new commit output stream.
1096	pub(crate) fn new(
1097		network: Arc<Mutex<GossipEngine<Block>>>,
1098		set_id: SetIdNumber,
1099		is_voter: bool,
1100		gossip_validator: Arc<GossipValidator<Block>>,
1101		neighbor_sender: periodic::NeighborPacketSender<Block>,
1102		telemetry: Option<TelemetryHandle>,
1103	) -> Self {
1104		CommitsOut {
1105			network,
1106			set_id: SetId(set_id),
1107			is_voter,
1108			gossip_validator,
1109			neighbor_sender,
1110			telemetry,
1111		}
1112	}
1113}
1114
1115impl<Block: BlockT> Sink<(RoundNumber, Commit<Block::Header>)> for CommitsOut<Block> {
1116	type Error = Error;
1117
1118	fn poll_ready(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Self::Error>> {
1119		Poll::Ready(Ok(()))
1120	}
1121
1122	fn start_send(
1123		self: Pin<&mut Self>,
1124		input: (RoundNumber, Commit<Block::Header>),
1125	) -> Result<(), Self::Error> {
1126		if !self.is_voter {
1127			return Ok(());
1128		}
1129
1130		let (round, commit) = input;
1131		let round = Round(round);
1132
1133		telemetry!(
1134			self.telemetry;
1135			CONSENSUS_DEBUG;
1136			"afg.commit_issued";
1137			"target_number" => ?commit.target_number,
1138			"target_hash" => ?commit.target_hash,
1139		);
1140
1141		let target_number = commit.target_number;
1142		let topic = global_topic::<Block>(self.set_id.0);
1143		let encoded = encode_commit_message::<Block>(round, self.set_id, commit);
1144
1145		// the gossip validator needs to be made aware of the best commit-height we know of
1146		// before gossiping
1147		self.gossip_validator.note_commit_finalized(
1148			round,
1149			self.set_id,
1150			target_number,
1151			|to, neighbor| self.neighbor_sender.send(to, neighbor),
1152		);
1153		self.network.lock().gossip_message(topic, encoded, false);
1154
1155		Ok(())
1156	}
1157
1158	fn poll_close(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Self::Error>> {
1159		Poll::Ready(Ok(()))
1160	}
1161
1162	fn poll_flush(self: Pin<&mut Self>, _: &mut Context) -> Poll<Result<(), Self::Error>> {
1163		Poll::Ready(Ok(()))
1164	}
1165}