import votes on validity

This commit is contained in:
Robert Habermeier
2017-12-12 17:48:13 +01:00
parent 4ec91d687c
commit cf4e4d7001
+71 -4
View File
@@ -28,6 +28,7 @@
//! to availability.
use std::collections::{HashSet, HashMap};
use std::collections::hash_map::Entry;
use std::hash::Hash;
/// Statements circulated among peers.
@@ -166,14 +167,27 @@ impl<C: Context> Table<C> {
candidate,
statement.signature
),
Statement::Valid(digest) => unimplemented!(),
Statement::Valid(digest) => self.validity_vote(
context,
signer.clone(),
digest,
true,
statement.signature,
),
Statement::Invalid(digest) => self.validity_vote(
context,
signer.clone(),
digest,
false,
statement.signature,
),
_ => unimplemented!(),
};
if let Some(misbehavior) = maybe_misbehavior {
// all misbehavior in agreement is provable and actively malicious.
// punishments are not cumulative.
self.detected_misbehavior.insert(validator, misbehavior);
self.detected_misbehavior.insert(signer, misbehavior);
}
}
@@ -184,8 +198,6 @@ impl<C: Context> Table<C> {
candidate: C::Candidate,
signature: C::Signature,
) -> Option<Misbehavior<C>> {
use std::collections::hash_map::Entry;
let group = context.candidate_group(&candidate);
if !context.is_member_of(&from, &group) {
return Some(Misbehavior::UnauthorizedStatement(UnauthorizedStatement {
@@ -231,4 +243,59 @@ impl<C: Context> Table<C> {
None
}
fn validity_vote(
&mut self,
context: &C,
from: C::ValidatorId,
digest: C::Digest,
valid: bool,
signature: C::Signature,
) -> Option<Misbehavior<C>> {
let statement = SignedStatement {
signature: signature.clone(),
statement: if valid {
Statement::Valid(digest.clone())
} else {
Statement::Invalid(digest.clone())
}
};
let votes = match self.candidate_votes.get_mut(&digest) {
None => return None, // TODO: queue up but don't get DoS'ed
Some(votes) => votes,
};
// check that this validator actually can vote in this group.
if !context.is_member_of(&from, &votes.group_id) {
return Some(Misbehavior::UnauthorizedStatement(UnauthorizedStatement {
statement
}));
}
// check for double votes.
match votes.validity_votes.entry(from.clone()) {
Entry::Occupied(occ) => {
if occ.get().0 != valid {
let (t_signature, f_signature) = if valid {
(signature, occ.get().1.clone())
} else {
(occ.get().1.clone(), signature)
};
return Some(Misbehavior::ValidityDoubleVote(ValidityDoubleVote {
digest: digest,
t_signature,
f_signature,
}));
}
}
Entry::Vacant(vacant) => {
vacant.insert((valid, signature));
votes.indicated_bad_by.push(from);
}
}
None
}
}