diff --git a/substrate/client/finality-grandpa/src/communication/gossip.rs b/substrate/client/finality-grandpa/src/communication/gossip.rs index 77c3543aae175c2d4a386f8ee8257fdbf4ae4dab..89c507f39af2e52e7fc8766ddd86b2019d74b85f 100644 --- a/substrate/client/finality-grandpa/src/communication/gossip.rs +++ b/substrate/client/finality-grandpa/src/communication/gossip.rs @@ -91,6 +91,7 @@ use sp_finality_grandpa::AuthorityId; use sc_telemetry::{telemetry, CONSENSUS_DEBUG}; use log::{trace, debug}; use futures::channel::mpsc; +use prometheus_endpoint::{CounterVec, Opts, PrometheusError, register, Registry, U64}; use rand::seq::SliceRandom; use crate::{environment, CatchUp, CompactCommit, SignedMessage}; @@ -1197,11 +1198,34 @@ impl<Block: BlockT> Inner<Block> { } } +// Prometheus metrics for [`GossipValidator`]. +pub(crate) struct Metrics { + messages_validated: CounterVec<U64>, +} + +impl Metrics { + pub(crate) fn register(registry: &prometheus_endpoint::Registry) -> Result<Self, PrometheusError> { + Ok(Self { + messages_validated: register( + CounterVec::new( + Opts::new( + "finality_grandpa_communication_gossip_validator_messages", + "Number of messages validated by the finality grandpa gossip validator." + ), + &["message", "action"] + )?, + registry, + )?, + }) + } +} + /// A validator for GRANDPA gossip messages. pub(super) struct GossipValidator<Block: BlockT> { inner: parking_lot::RwLock<Inner<Block>>, set_state: environment::SharedVoterSetState<Block>, report_sender: mpsc::UnboundedSender<PeerReport>, + metrics: Option<Metrics>, } impl<Block: BlockT> GossipValidator<Block> { @@ -1211,12 +1235,23 @@ impl<Block: BlockT> GossipValidator<Block> { pub(super) fn new( config: crate::Config, set_state: environment::SharedVoterSetState<Block>, + prometheus_registry: Option<&Registry>, ) -> (GossipValidator<Block>, mpsc::UnboundedReceiver<PeerReport>) { + let metrics = match prometheus_registry.map(Metrics::register) { + Some(Ok(metrics)) => Some(metrics), + Some(Err(e)) => { + debug!(target: "afg", "Failed to register metrics: {:?}", e); + None + }, + None => None, + }; + let (tx, rx) = mpsc::unbounded(); let val = GossipValidator { inner: parking_lot::RwLock::new(Inner::new(config)), set_state, report_sender: tx, + metrics: metrics, }; (val, rx) @@ -1279,12 +1314,21 @@ impl<Block: BlockT> GossipValidator<Block> { let mut broadcast_topics = Vec::new(); let mut peer_reply = None; + // Message name for Prometheus metric recording. + let message_name; + let action = { match GossipMessage::<Block>::decode(&mut data) { - Ok(GossipMessage::Vote(ref message)) - => self.inner.write().validate_round_message(who, message), - Ok(GossipMessage::Commit(ref message)) => self.inner.write().validate_commit_message(who, message), + Ok(GossipMessage::Vote(ref message)) => { + message_name = Some("vote"); + self.inner.write().validate_round_message(who, message) + }, + Ok(GossipMessage::Commit(ref message)) => { + message_name = Some("commit"); + self.inner.write().validate_commit_message(who, message) + }, Ok(GossipMessage::Neighbor(update)) => { + message_name = Some("neighbor"); let (topics, action, catch_up, report) = self.inner.write().import_neighbor_message( who, update.into_neighbor_packet(), @@ -1298,9 +1342,12 @@ impl<Block: BlockT> GossipValidator<Block> { peer_reply = catch_up; action } - Ok(GossipMessage::CatchUp(ref message)) - => self.inner.write().validate_catch_up_message(who, message), + Ok(GossipMessage::CatchUp(ref message)) => { + message_name = Some("catch_up"); + self.inner.write().validate_catch_up_message(who, message) + }, Ok(GossipMessage::CatchUpRequest(request)) => { + message_name = Some("catch_up_request"); let (reply, action) = self.inner.write().handle_catch_up_request( who, request, @@ -1311,6 +1358,7 @@ impl<Block: BlockT> GossipValidator<Block> { action } Err(e) => { + message_name = None; debug!(target: "afg", "Error decoding message: {}", e.what()); telemetry!(CONSENSUS_DEBUG; "afg.err_decoding_msg"; "" => ""); @@ -1320,6 +1368,16 @@ impl<Block: BlockT> GossipValidator<Block> { } }; + // Prometheus metric recording. + if let (Some(metrics), Some(message_name)) = (&self.metrics, message_name) { + let action_name = match action { + Action::Keep(_, _) => "keep", + Action::ProcessAndDiscard(_, _) => "process_and_discard", + Action::Discard(_) => "discard", + }; + metrics.messages_validated.with_label_values(&[message_name, action_name]).inc(); + } + (action, broadcast_topics, peer_reply) } } @@ -1679,6 +1737,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); let set_id = 1; @@ -1714,6 +1773,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); let set_id = 1; let auth = AuthorityId::from_slice(&[1u8; 32]); @@ -1758,6 +1818,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); let set_id = 1; @@ -1826,6 +1887,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), set_state.clone(), + None, ); let set_id = 1; @@ -1880,6 +1942,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), set_state.clone(), + None, ); // the validator starts at set id 2 @@ -1959,6 +2022,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); // the validator starts at set id 1. @@ -2032,6 +2096,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config, voter_set_state(), + None, ); // the validator starts at set id 1. @@ -2065,6 +2130,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); // the validator starts at set id 1. @@ -2124,6 +2190,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config, voter_set_state(), + None, ); // the validator starts at set id 1. @@ -2162,6 +2229,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); // the validator starts at set id 1. @@ -2194,6 +2262,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config, voter_set_state(), + None, ); // the validator start at set id 0 @@ -2271,6 +2340,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config(), voter_set_state(), + None, ); // the validator start at set id 0 @@ -2310,6 +2380,7 @@ mod tests { let (val, _) = GossipValidator::<Block>::new( config, voter_set_state(), + None, ); // the validator start at set id 0 @@ -2358,7 +2429,7 @@ mod tests { #[test] fn only_gossip_commits_to_peers_on_same_set() { - let (val, _) = GossipValidator::<Block>::new(config(), voter_set_state()); + let (val, _) = GossipValidator::<Block>::new(config(), voter_set_state(), None); // the validator start at set id 1 val.note_set(SetId(1), Vec::new(), |_, _| {}); @@ -2436,7 +2507,7 @@ mod tests { #[test] fn expire_commits_from_older_rounds() { - let (val, _) = GossipValidator::<Block>::new(config(), voter_set_state()); + let (val, _) = GossipValidator::<Block>::new(config(), voter_set_state(), None); let commit = |round, set_id, target_number| { let commit = finality_grandpa::CompactCommit { diff --git a/substrate/client/finality-grandpa/src/communication/mod.rs b/substrate/client/finality-grandpa/src/communication/mod.rs index d496f305fc5c8cfee812a79dc4b2cbc1d8671ba5..82f24ff05b3d5f028c6485d7f7daf02beb64f695 100644 --- a/substrate/client/finality-grandpa/src/communication/mod.rs +++ b/substrate/client/finality-grandpa/src/communication/mod.rs @@ -30,6 +30,7 @@ use futures::{prelude::*, channel::mpsc}; use log::{debug, trace}; use parking_lot::Mutex; +use prometheus_endpoint::Registry; use std::{pin::Pin, sync::Arc, task::{Context, Poll}}; use finality_grandpa::Message::{Prevote, Precommit, PrimaryPropose}; @@ -178,10 +179,12 @@ impl<B: BlockT, N: Network<B>> NetworkBridge<B, N> { service: N, config: crate::Config, set_state: crate::environment::SharedVoterSetState<B>, + prometheus_registry: Option<&Registry>, ) -> Self { let (validator, report_stream) = GossipValidator::new( config, set_state.clone(), + prometheus_registry, ); let validator = Arc::new(validator); diff --git a/substrate/client/finality-grandpa/src/communication/tests.rs b/substrate/client/finality-grandpa/src/communication/tests.rs index 284e457750aa8c110bd9852613c130227d8edbf2..f964cea469c3f3435e520e3370e8bdfb1c1e06ee 100644 --- a/substrate/client/finality-grandpa/src/communication/tests.rs +++ b/substrate/client/finality-grandpa/src/communication/tests.rs @@ -179,6 +179,7 @@ pub(crate) fn make_test_network() -> ( net.clone(), config(), voter_set_state(), + None, ); ( diff --git a/substrate/client/finality-grandpa/src/lib.rs b/substrate/client/finality-grandpa/src/lib.rs index afee2bec53576a56c3aeba69716ad4d144bbd851..91da62848c534b7db461b82e01b0678a288a642a 100644 --- a/substrate/client/finality-grandpa/src/lib.rs +++ b/substrate/client/finality-grandpa/src/lib.rs @@ -591,6 +591,7 @@ pub fn run_grandpa_voter<Block: BlockT, BE: 'static, C, N, SC, VR>( network, config.clone(), persistent_data.set_state.clone(), + prometheus_registry.as_ref(), ); register_finality_tracker_inherent_data_provider(client.clone(), &inherent_data_providers)?; diff --git a/substrate/client/finality-grandpa/src/observer.rs b/substrate/client/finality-grandpa/src/observer.rs index 921e5a3dd5b1453846a606b633f9e228e4017232..971c2132904f6b325d6f76934a133fd178e87c0d 100644 --- a/substrate/client/finality-grandpa/src/observer.rs +++ b/substrate/client/finality-grandpa/src/observer.rs @@ -178,6 +178,7 @@ where network, config.clone(), persistent_data.set_state.clone(), + None, ); let observer_work = ObserverWork::new( diff --git a/substrate/client/finality-grandpa/src/tests.rs b/substrate/client/finality-grandpa/src/tests.rs index 0774194d7eb5200d21222e754b71b4aa78b52dc2..50800f478476f02d36a346a519af9bb081d18dad 100644 --- a/substrate/client/finality-grandpa/src/tests.rs +++ b/substrate/client/finality-grandpa/src/tests.rs @@ -1220,6 +1220,7 @@ fn voter_persists_its_votes() { net.lock().peers[1].network_service().clone(), config.clone(), set_state, + None, ); let (round_rx, round_tx) = network.round_communication( @@ -1616,6 +1617,7 @@ fn grandpa_environment_respects_voting_rules() { network_service.clone(), config.clone(), set_state.clone(), + None, ); Environment {