1use 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
72pub(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 pub(crate) const LEGACY_NAMES: [&str; 1] = ["/paritytech/grandpa/1"];
82
83 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
99mod 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 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
127mod 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
137pub struct LocalIdKeystore((AuthorityId, KeystorePtr));
140
141impl LocalIdKeystore {
142 fn local_id(&self) -> &AuthorityId {
144 &(self.0).0
145 }
146
147 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
159const TELEMETRY_VOTERS_LIMIT: usize = 10;
163
164pub 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
176pub 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
201pub(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
206pub(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
211pub(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 neighbor_sender: periodic::NeighborPacketSender<B>,
223
224 neighbor_packet_worker: Arc<Mutex<periodic::NeighborPacketWorker<B>>>,
228
229 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 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 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 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 pub(crate) fn note_round(&self, round: Round, set_id: SetId, voters: &VoterSet<AuthorityId>) {
321 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 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 ¬ification.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 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 let incoming = stream::select(incoming, out_rx);
436
437 (incoming, outgoing)
438 }
439
440 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 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 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 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 gossip_engine.lock().mark_message_known(¬ification.message);
642 }
643 },
644 voter::CommitProcessingOutcome::Bad(_) => {
645 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 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 let decoded = GossipMessage::<B>::decode_all(&mut ¬ification.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#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Encode, Decode)]
741pub struct Round(pub RoundNumber);
742
743#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Encode, Decode)]
745pub struct SetId(pub SetIdNumber);
746
747pub(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 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 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 self.network.lock().announce(target_hash, None);
840
841 let topic = round_topic::<Block>(self.round, self.set_id);
843 self.network.lock().gossip_message(topic, message.encode(), false);
844
845 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
867fn 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 let f = voters.total_weight() - voters.threshold();
878 let full_threshold = (f + voters.total_weight()).0;
879
880 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 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
935fn 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 let f = voters.total_weight() - voters.threshold();
945 let full_threshold = (f + voters.total_weight()).0;
946
947 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 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::<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
1056fn 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
1084struct 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 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 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}