polkadot_node_primitives/disputes/
mod.rs1use std::collections::{
18 btree_map::{Entry as Bentry, Keys as Bkeys},
19 BTreeMap, BTreeSet,
20};
21
22use codec::{Decode, Encode};
23
24use sp_application_crypto::AppCrypto;
25use sp_keystore::{Error as KeystoreError, KeystorePtr};
26
27use polkadot_primitives::{
28 CandidateHash, CandidateReceiptV2 as CandidateReceipt, CompactStatement, DisputeStatement,
29 EncodeAs, InvalidDisputeStatementKind, SessionIndex, SigningContext, UncheckedSigned,
30 ValidDisputeStatementKind, ValidatorId, ValidatorIndex, ValidatorSignature,
31};
32
33mod message;
35pub use message::{DisputeMessage, Error as DisputeMessageCheckError, UncheckedDisputeMessage};
36mod status;
37pub use status::{dispute_is_inactive, DisputeStatus, Timestamp, ACTIVE_DURATION_SECS};
38
39#[derive(Debug, Clone)]
41pub struct SignedDisputeStatement {
42 dispute_statement: DisputeStatement,
43 candidate_hash: CandidateHash,
44 validator_public: ValidatorId,
45 validator_signature: ValidatorSignature,
46 session_index: SessionIndex,
47}
48
49#[derive(Debug)]
51pub enum SignedDisputeStatementError {
52 KeyStoreError(KeystoreError),
54 PayloadError,
56}
57
58#[derive(Debug, Clone)]
60pub struct CandidateVotes {
61 pub candidate_receipt: CandidateReceipt,
63 pub valid: ValidCandidateVotes,
65 pub invalid: BTreeMap<ValidatorIndex, (InvalidDisputeStatementKind, ValidatorSignature)>,
67}
68
69pub type ValidVoteData = (ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature));
71
72pub type InvalidVoteData = (ValidatorIndex, (InvalidDisputeStatementKind, ValidatorSignature));
74
75impl CandidateVotes {
76 pub fn voted_indices(&self) -> BTreeSet<ValidatorIndex> {
78 let mut keys: BTreeSet<_> = self.valid.keys().cloned().collect();
79 keys.extend(self.invalid.keys().cloned());
80 keys
81 }
82}
83
84#[derive(Debug, Clone)]
85pub struct ValidCandidateVotes {
89 votes: BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)>,
90}
91
92impl ValidCandidateVotes {
93 pub fn new() -> Self {
95 Self { votes: BTreeMap::new() }
96 }
97 pub fn insert_vote(
105 &mut self,
106 validator_index: ValidatorIndex,
107 kind: ValidDisputeStatementKind,
108 sig: ValidatorSignature,
109 ) -> bool {
110 match self.votes.entry(validator_index) {
111 Bentry::Vacant(vacant) => {
112 vacant.insert((kind, sig));
113 true
114 },
115 Bentry::Occupied(mut occupied) => match occupied.get().0 {
116 ValidDisputeStatementKind::BackingValid(_) |
117 ValidDisputeStatementKind::BackingSeconded(_) => false,
118 ValidDisputeStatementKind::Explicit |
119 ValidDisputeStatementKind::ApprovalChecking |
120 ValidDisputeStatementKind::ApprovalCheckingMultipleCandidates(_) => {
121 occupied.insert((kind.clone(), sig));
122 kind != occupied.get().0
123 },
124 },
125 }
126 }
127
128 pub fn retain<F>(&mut self, f: F)
130 where
131 F: FnMut(&ValidatorIndex, &mut (ValidDisputeStatementKind, ValidatorSignature)) -> bool,
132 {
133 self.votes.retain(f)
134 }
135
136 pub fn keys(
138 &self,
139 ) -> Bkeys<'_, ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> {
140 self.votes.keys()
141 }
142
143 pub fn raw(
145 &self,
146 ) -> &BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> {
147 &self.votes
148 }
149}
150
151impl FromIterator<(ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature))>
152 for ValidCandidateVotes
153{
154 fn from_iter<T>(iter: T) -> Self
155 where
156 T: IntoIterator<Item = (ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature))>,
157 {
158 Self { votes: BTreeMap::from_iter(iter) }
159 }
160}
161
162impl From<ValidCandidateVotes>
163 for BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)>
164{
165 fn from(wrapped: ValidCandidateVotes) -> Self {
166 wrapped.votes
167 }
168}
169impl IntoIterator for ValidCandidateVotes {
170 type Item = (ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature));
171 type IntoIter = <BTreeMap<ValidatorIndex, (ValidDisputeStatementKind, ValidatorSignature)> as IntoIterator>::IntoIter;
172
173 fn into_iter(self) -> Self::IntoIter {
174 self.votes.into_iter()
175 }
176}
177
178impl SignedDisputeStatement {
179 pub fn new_unchecked_from_trusted_source(
184 dispute_statement: DisputeStatement,
185 candidate_hash: CandidateHash,
186 session_index: SessionIndex,
187 validator_public: ValidatorId,
188 validator_signature: ValidatorSignature,
189 ) -> Self {
190 SignedDisputeStatement {
191 dispute_statement,
192 candidate_hash,
193 validator_public,
194 validator_signature,
195 session_index,
196 }
197 }
198
199 pub fn new_checked(
201 dispute_statement: DisputeStatement,
202 candidate_hash: CandidateHash,
203 session_index: SessionIndex,
204 validator_public: ValidatorId,
205 validator_signature: ValidatorSignature,
206 ) -> Result<Self, ()> {
207 dispute_statement
208 .check_signature(&validator_public, candidate_hash, session_index, &validator_signature)
209 .map(|_| SignedDisputeStatement {
210 dispute_statement,
211 candidate_hash,
212 validator_public,
213 validator_signature,
214 session_index,
215 })
216 }
217
218 pub fn sign_explicit(
221 keystore: &KeystorePtr,
222 valid: bool,
223 candidate_hash: CandidateHash,
224 session_index: SessionIndex,
225 validator_public: ValidatorId,
226 ) -> Result<Option<Self>, SignedDisputeStatementError> {
227 let dispute_statement = if valid {
228 DisputeStatement::Valid(ValidDisputeStatementKind::Explicit)
229 } else {
230 DisputeStatement::Invalid(InvalidDisputeStatementKind::Explicit)
231 };
232
233 let data = dispute_statement
234 .payload_data(candidate_hash, session_index)
235 .map_err(|_| SignedDisputeStatementError::PayloadError)?;
236 let signature = keystore
237 .sr25519_sign(ValidatorId::ID, validator_public.as_ref(), &data)
238 .map_err(SignedDisputeStatementError::KeyStoreError)?
239 .map(|sig| Self {
240 dispute_statement,
241 candidate_hash,
242 validator_public,
243 validator_signature: sig.into(),
244 session_index,
245 });
246 Ok(signature)
247 }
248
249 pub fn statement(&self) -> &DisputeStatement {
251 &self.dispute_statement
252 }
253
254 pub fn candidate_hash(&self) -> &CandidateHash {
256 &self.candidate_hash
257 }
258
259 pub fn validator_public(&self) -> &ValidatorId {
261 &self.validator_public
262 }
263
264 pub fn validator_signature(&self) -> &ValidatorSignature {
266 &self.validator_signature
267 }
268
269 pub fn into_validator_signature(self) -> ValidatorSignature {
271 self.validator_signature
272 }
273
274 pub fn session_index(&self) -> SessionIndex {
276 self.session_index
277 }
278
279 pub fn from_backing_statement<T>(
287 backing_statement: &UncheckedSigned<T, CompactStatement>,
288 signing_context: SigningContext,
289 validator_public: ValidatorId,
290 ) -> Result<Self, ()>
291 where
292 for<'a> &'a T: Into<CompactStatement>,
293 T: EncodeAs<CompactStatement>,
294 {
295 let (statement_kind, candidate_hash) = match backing_statement.unchecked_payload().into() {
296 CompactStatement::Seconded(candidate_hash) => (
297 ValidDisputeStatementKind::BackingSeconded(signing_context.parent_hash),
298 candidate_hash,
299 ),
300 CompactStatement::Valid(candidate_hash) => (
301 ValidDisputeStatementKind::BackingValid(signing_context.parent_hash),
302 candidate_hash,
303 ),
304 };
305
306 let dispute_statement = DisputeStatement::Valid(statement_kind);
307 Self::new_checked(
308 dispute_statement,
309 candidate_hash,
310 signing_context.session_index,
311 validator_public,
312 backing_statement.unchecked_signature().clone(),
313 )
314 }
315}
316
317#[derive(Clone, Encode, Decode, Debug)]
319pub struct InvalidDisputeVote {
320 pub validator_index: ValidatorIndex,
322
323 pub signature: ValidatorSignature,
326
327 pub kind: InvalidDisputeStatementKind,
329}
330
331#[derive(Clone, Encode, Decode, Debug)]
333pub struct ValidDisputeVote {
334 pub validator_index: ValidatorIndex,
336
337 pub signature: ValidatorSignature,
340
341 pub kind: ValidDisputeStatementKind,
343}