bp_header_chain/justification/verification/
equivocation.rs1use crate::{
20 justification::{
21 verification::{
22 Error as JustificationVerificationError, IterationFlow,
23 JustificationVerificationContext, JustificationVerifier, PrecommitError,
24 SignedPrecommit,
25 },
26 GrandpaJustification,
27 },
28 ChainWithGrandpa, FindEquivocations,
29};
30
31use bp_runtime::{BlockNumberOf, HashOf, HeaderOf};
32use sp_consensus_grandpa::{AuthorityId, AuthoritySignature, EquivocationProof, Precommit};
33use sp_runtime::traits::Header as HeaderT;
34use sp_std::{
35 collections::{btree_map::BTreeMap, btree_set::BTreeSet},
36 prelude::*,
37 vec,
38 vec::Vec,
39};
40
41enum AuthorityVotes<Header: HeaderT> {
42 SingleVote(SignedPrecommit<Header>),
43 Equivocation(
44 finality_grandpa::Equivocation<AuthorityId, Precommit<Header>, AuthoritySignature>,
45 ),
46}
47
48pub struct EquivocationsCollector<'a, Header: HeaderT> {
50 round: u64,
51 context: &'a JustificationVerificationContext,
52
53 votes: BTreeMap<AuthorityId, AuthorityVotes<Header>>,
54}
55
56impl<'a, Header: HeaderT> EquivocationsCollector<'a, Header> {
57 pub fn new(
59 context: &'a JustificationVerificationContext,
60 base_justification: &GrandpaJustification<Header>,
61 ) -> Result<Self, JustificationVerificationError> {
62 let mut checker = Self { round: base_justification.round, context, votes: BTreeMap::new() };
63
64 checker.verify_justification(
65 (base_justification.commit.target_hash, base_justification.commit.target_number),
66 checker.context,
67 base_justification,
68 )?;
69
70 Ok(checker)
71 }
72
73 pub fn parse_justifications(&mut self, justifications: &[GrandpaJustification<Header>]) {
75 let round = self.round;
76 for justification in
77 justifications.iter().filter(|justification| round == justification.round)
78 {
79 let _ = self.verify_justification(
82 (justification.commit.target_hash, justification.commit.target_number),
83 self.context,
84 justification,
85 );
86 }
87 }
88
89 pub fn into_equivocation_proofs(self) -> Vec<EquivocationProof<Header::Hash, Header::Number>> {
91 let mut equivocations = vec![];
92 for (_authority, vote) in self.votes {
93 if let AuthorityVotes::Equivocation(equivocation) = vote {
94 equivocations.push(EquivocationProof::new(
95 self.context.authority_set_id,
96 sp_consensus_grandpa::Equivocation::Precommit(equivocation),
97 ));
98 }
99 }
100
101 equivocations
102 }
103}
104
105impl<'a, Header: HeaderT> JustificationVerifier<Header> for EquivocationsCollector<'a, Header> {
106 fn process_duplicate_votes_ancestries(
107 &mut self,
108 _duplicate_votes_ancestries: Vec<usize>,
109 ) -> Result<(), JustificationVerificationError> {
110 Ok(())
111 }
112
113 fn process_redundant_vote(
114 &mut self,
115 _precommit_idx: usize,
116 ) -> Result<IterationFlow, PrecommitError> {
117 Ok(IterationFlow::Run)
118 }
119
120 fn process_known_authority_vote(
121 &mut self,
122 _precommit_idx: usize,
123 _signed: &SignedPrecommit<Header>,
124 ) -> Result<IterationFlow, PrecommitError> {
125 Ok(IterationFlow::Run)
126 }
127
128 fn process_unknown_authority_vote(
129 &mut self,
130 _precommit_idx: usize,
131 ) -> Result<(), PrecommitError> {
132 Ok(())
133 }
134
135 fn process_unrelated_ancestry_vote(
136 &mut self,
137 _precommit_idx: usize,
138 ) -> Result<IterationFlow, PrecommitError> {
139 Ok(IterationFlow::Run)
140 }
141
142 fn process_invalid_signature_vote(
143 &mut self,
144 _precommit_idx: usize,
145 ) -> Result<(), PrecommitError> {
146 Ok(())
147 }
148
149 fn process_valid_vote(&mut self, signed: &SignedPrecommit<Header>) {
150 match self.votes.get_mut(&signed.id) {
151 Some(vote) => match vote {
152 AuthorityVotes::SingleVote(first_vote) => {
153 if first_vote.precommit != signed.precommit {
154 *vote = AuthorityVotes::Equivocation(finality_grandpa::Equivocation {
155 round_number: self.round,
156 identity: signed.id.clone(),
157 first: (first_vote.precommit.clone(), first_vote.signature.clone()),
158 second: (signed.precommit.clone(), signed.signature.clone()),
159 });
160 }
161 },
162 AuthorityVotes::Equivocation(_) => {},
163 },
164 None => {
165 self.votes.insert(signed.id.clone(), AuthorityVotes::SingleVote(signed.clone()));
166 },
167 }
168 }
169
170 fn process_redundant_votes_ancestries(
171 &mut self,
172 _redundant_votes_ancestries: BTreeSet<Header::Hash>,
173 ) -> Result<(), JustificationVerificationError> {
174 Ok(())
175 }
176}
177
178pub struct GrandpaEquivocationsFinder<C>(sp_std::marker::PhantomData<C>);
180
181impl<C: ChainWithGrandpa>
182 FindEquivocations<
183 GrandpaJustification<HeaderOf<C>>,
184 JustificationVerificationContext,
185 EquivocationProof<HashOf<C>, BlockNumberOf<C>>,
186 > for GrandpaEquivocationsFinder<C>
187{
188 type Error = JustificationVerificationError;
189
190 fn find_equivocations(
191 verification_context: &JustificationVerificationContext,
192 synced_proof: &GrandpaJustification<HeaderOf<C>>,
193 source_proofs: &[GrandpaJustification<HeaderOf<C>>],
194 ) -> Result<Vec<EquivocationProof<HashOf<C>, BlockNumberOf<C>>>, Self::Error> {
195 let mut equivocations_collector =
196 EquivocationsCollector::new(verification_context, synced_proof)?;
197
198 equivocations_collector.parse_justifications(source_proofs);
199
200 Ok(equivocations_collector.into_equivocation_proofs())
201 }
202}