use std::sync::{Arc, RwLock}; use sp_core::Decode; use sp_runtime::traits::{Hash, Header, Block}; use sc_network::PeerId; use sc_network_gossip::{Validator, ValidatorContext, ValidationResult}; use tendermint_machine::{ext::SignatureScheme, SignedMessage}; use crate::{TendermintValidator, validators::TendermintValidators}; #[derive(Clone)] pub(crate) struct TendermintGossip { number: Arc>, signature_scheme: TendermintValidators, } impl TendermintGossip { pub(crate) fn new(number: Arc>, signature_scheme: TendermintValidators) -> Self { TendermintGossip { number, signature_scheme } } pub(crate) fn topic(number: u64) -> ::Hash { <<::Header as Header>::Hashing as Hash>::hash( &[b"Tendermint Block Topic".as_ref(), &number.to_le_bytes()].concat(), ) } } impl Validator for TendermintGossip { fn validate( &self, _: &mut dyn ValidatorContext, _: &PeerId, data: &[u8], ) -> ValidationResult<::Hash> { let msg = match SignedMessage::< u16, T::Block, as SignatureScheme>::Signature, >::decode(&mut &*data) { Ok(msg) => msg, Err(_) => return ValidationResult::Discard, }; if msg.block().0 < *self.number.read().unwrap() { return ValidationResult::Discard; } // Verify the signature here so we don't carry invalid messages in our gossip layer // This will cause double verification of the signature, yet that's a minimal cost if !msg.verify_signature(&self.signature_scheme) { return ValidationResult::Discard; } ValidationResult::ProcessAndKeep(Self::topic(msg.block().0)) } fn message_expired<'a>( &'a self, ) -> Box::Hash, &[u8]) -> bool + 'a> { let number = self.number.clone(); Box::new(move |topic, _| topic != Self::topic(*number.read().unwrap())) } }