referrerpolicy=no-referrer-when-downgrade

sc_consensus_grandpa_rpc/
report.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
19use std::{
20	collections::{BTreeSet, HashSet},
21	fmt::Debug,
22	ops::Add,
23};
24
25use serde::{Deserialize, Serialize};
26
27use sc_consensus_grandpa::{report, AuthorityId, SharedAuthoritySet, SharedVoterState};
28
29use crate::error::Error;
30
31/// Utility trait to get reporting data for the current GRANDPA authority set.
32pub trait ReportAuthoritySet {
33	fn get(&self) -> (u64, HashSet<AuthorityId>);
34}
35
36/// Utility trait to get reporting data for the current GRANDPA voter state.
37pub trait ReportVoterState {
38	fn get(&self) -> Option<report::VoterState<AuthorityId>>;
39}
40
41impl<H, N> ReportAuthoritySet for SharedAuthoritySet<H, N>
42where
43	N: Add<Output = N> + Ord + Clone + Debug,
44	H: Clone + Debug + Eq,
45{
46	fn get(&self) -> (u64, HashSet<AuthorityId>) {
47		let current_voters: HashSet<AuthorityId> =
48			self.current_authorities().iter().map(|p| p.0.clone()).collect();
49
50		(self.set_id(), current_voters)
51	}
52}
53
54impl ReportVoterState for SharedVoterState {
55	fn get(&self) -> Option<report::VoterState<AuthorityId>> {
56		self.voter_state()
57	}
58}
59
60#[derive(Clone, Serialize, Deserialize)]
61#[serde(rename_all = "camelCase")]
62struct Prevotes {
63	current_weight: u32,
64	missing: BTreeSet<AuthorityId>,
65}
66
67#[derive(Clone, Serialize, Deserialize)]
68#[serde(rename_all = "camelCase")]
69struct Precommits {
70	current_weight: u32,
71	missing: BTreeSet<AuthorityId>,
72}
73
74#[derive(Clone, Serialize, Deserialize)]
75#[serde(rename_all = "camelCase")]
76struct RoundState {
77	round: u32,
78	total_weight: u32,
79	threshold_weight: u32,
80	prevotes: Prevotes,
81	precommits: Precommits,
82}
83
84impl RoundState {
85	fn from(
86		round: u64,
87		round_state: &report::RoundState<AuthorityId>,
88		voters: &HashSet<AuthorityId>,
89	) -> Result<Self, Error> {
90		let prevotes = &round_state.prevote_ids;
91		let missing_prevotes = voters.difference(prevotes).cloned().collect();
92
93		let precommits = &round_state.precommit_ids;
94		let missing_precommits = voters.difference(precommits).cloned().collect();
95
96		Ok(Self {
97			round: round.try_into()?,
98			total_weight: round_state.total_weight.get().try_into()?,
99			threshold_weight: round_state.threshold_weight.get().try_into()?,
100			prevotes: Prevotes {
101				current_weight: round_state.prevote_current_weight.0.try_into()?,
102				missing: missing_prevotes,
103			},
104			precommits: Precommits {
105				current_weight: round_state.precommit_current_weight.0.try_into()?,
106				missing: missing_precommits,
107			},
108		})
109	}
110}
111
112/// The state of the current best round, as well as the background rounds in a
113/// form suitable for serialization.
114#[derive(Clone, Serialize, Deserialize)]
115#[serde(rename_all = "camelCase")]
116pub struct ReportedRoundStates {
117	set_id: u32,
118	best: RoundState,
119	background: Vec<RoundState>,
120}
121
122impl ReportedRoundStates {
123	pub fn from<AuthoritySet, VoterState>(
124		authority_set: &AuthoritySet,
125		voter_state: &VoterState,
126	) -> Result<Self, Error>
127	where
128		AuthoritySet: ReportAuthoritySet,
129		VoterState: ReportVoterState,
130	{
131		let voter_state = voter_state.get().ok_or(Error::EndpointNotReady)?;
132
133		let (set_id, current_voters) = authority_set.get();
134		let set_id =
135			u32::try_from(set_id).map_err(|_| Error::AuthoritySetIdReportedAsUnreasonablyLarge)?;
136
137		let best = {
138			let (round, round_state) = voter_state.best_round;
139			RoundState::from(round, &round_state, &current_voters)?
140		};
141
142		let background = voter_state
143			.background_rounds
144			.iter()
145			.map(|(round, round_state)| RoundState::from(*round, round_state, &current_voters))
146			.collect::<Result<Vec<_>, Error>>()?;
147
148		Ok(Self { set_id, best, background })
149	}
150}