sc_consensus_grandpa_rpc/
report.rs1use 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
31pub trait ReportAuthoritySet {
33 fn get(&self) -> (u64, HashSet<AuthorityId>);
34}
35
36pub 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#[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, ¤t_voters)?
140 };
141
142 let background = voter_state
143 .background_rounds
144 .iter()
145 .map(|(round, round_state)| RoundState::from(*round, round_state, ¤t_voters))
146 .collect::<Result<Vec<_>, Error>>()?;
147
148 Ok(Self { set_id, best, background })
149 }
150}