Files
pezkuwi-subxt/substrate/client/beefy/src/metrics.rs
T
Adrian Catangiu 498e8c181f Implement Lean BEEFY (#10882)
Simplified BEEFY worker logic based on the invariant that GRANDPA
will always finalize 1st block of each new session, meaning BEEFY
worker is guaranteed to receive finality notification for the
BEEFY mandatory blocks.

Under these conditions the current design is as follows:
- session changes are detected based on BEEFY Digest present in
  BEEFY mandatory blocks,
- on each new session new `Rounds` of voting is created, with old
  rounds being dropped (for gossip rounds, last 3 are still alive
  so votes are still being gossiped),
- after processing finality for a block, the worker votes if
  a new voting target has become available as a result of said
  block finality processing,
- incoming votes as well as self-created votes are processed
  and signed commitments are created for completed BEEFY voting
  rounds,
- the worker votes if a new voting target becomes available
  once a round successfully completes.

On worker startup, the current validator set is retrieved from
the BEEFY pallet. If it is the genesis validator set, worker
starts voting right away considering Block #1 as session start.

Otherwise (not genesis), the worker will vote starting with
mandatory block of the next session.

Later on when we add the BEEFY initial-sync (catch-up) logic,
the worker will sync all past mandatory blocks Signed Commitments
and will be able to start voting right away.

BEEFY mandatory block is the block with header containing the BEEFY
`AuthoritiesChange` Digest, this block is guaranteed to be finalized
by GRANDPA.

This session-boundary block is signed by the ending-session's
validator set. Next blocks will be signed by the new session's
validator set. This behavior is consistent with what GRANDPA does
as well.

Also drop the limit N on active gossip rounds. In an adversarial
network, a bad actor could create and gossip N invalid votes with
round numbers larger than the current correct round number. This
would lead to votes for correct rounds to no longer be gossiped.

Add unit-tests for all components, including full voter consensus
tests.

Signed-off-by: Adrian Catangiu <adrian@parity.io>
Co-authored-by: Tomasz Drwięga <tomusdrw@users.noreply.github.com>
Co-authored-by: David Salami <Wizdave97>
2022-03-25 17:31:42 +02:00

111 lines
3.2 KiB
Rust

// This file is part of Substrate.
// Copyright (C) 2021-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//! BEEFY Prometheus metrics definition
#[cfg(not(test))]
use prometheus::{register, PrometheusError, Registry};
use prometheus::{Counter, Gauge, U64};
/// BEEFY metrics exposed through Prometheus
pub(crate) struct Metrics {
/// Current active validator set id
pub beefy_validator_set_id: Gauge<U64>,
/// Total number of votes sent by this node
pub beefy_votes_sent: Counter<U64>,
/// Most recent concluded voting round
pub beefy_round_concluded: Gauge<U64>,
/// Best block finalized by BEEFY
pub beefy_best_block: Gauge<U64>,
/// Next block BEEFY should vote on
pub beefy_should_vote_on: Gauge<U64>,
/// Number of sessions without a signed commitment
pub beefy_skipped_sessions: Counter<U64>,
}
impl Metrics {
#[cfg(not(test))]
pub(crate) fn register(registry: &Registry) -> Result<Self, PrometheusError> {
Ok(Self {
beefy_validator_set_id: register(
Gauge::new(
"substrate_beefy_validator_set_id",
"Current BEEFY active validator set id.",
)?,
registry,
)?,
beefy_votes_sent: register(
Counter::new("substrate_beefy_votes_sent", "Number of votes sent by this node")?,
registry,
)?,
beefy_round_concluded: register(
Gauge::new(
"substrate_beefy_round_concluded",
"Voting round, that has been concluded",
)?,
registry,
)?,
beefy_best_block: register(
Gauge::new("substrate_beefy_best_block", "Best block finalized by BEEFY")?,
registry,
)?,
beefy_should_vote_on: register(
Gauge::new("substrate_beefy_should_vote_on", "Next block, BEEFY should vote on")?,
registry,
)?,
beefy_skipped_sessions: register(
Counter::new(
"substrate_beefy_skipped_sessions",
"Number of sessions without a signed commitment",
)?,
registry,
)?,
})
}
}
// Note: we use the `format` macro to convert an expr into a `u64`. This will fail,
// if expr does not derive `Display`.
#[macro_export]
macro_rules! metric_set {
($self:ident, $m:ident, $v:expr) => {{
let val: u64 = format!("{}", $v).parse().unwrap();
if let Some(metrics) = $self.metrics.as_ref() {
metrics.$m.set(val);
}
}};
}
#[macro_export]
macro_rules! metric_inc {
($self:ident, $m:ident) => {{
if let Some(metrics) = $self.metrics.as_ref() {
metrics.$m.inc();
}
}};
}
#[cfg(test)]
#[macro_export]
macro_rules! metric_get {
($self:ident, $m:ident) => {{
$self.metrics.as_ref().map(|metrics| metrics.$m.clone())
}};
}