move vote with addresses, remove recover check

This commit is contained in:
keorn 2016-08-26 19:27:02 +02:00
parent a4ba7262ad
commit f60d4645ed

View File

@ -17,9 +17,7 @@
//! Voting on a hash, where each vote has to come from a set of addresses. //! Voting on a hash, where each vote has to come from a set of addresses.
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use common::{HashSet, RwLock, H256, Address, Error, Hashable}; use common::{HashSet, RwLock, H256, Address};
use super::EngineError;
use ethkey::{recover, Signature};
/// Collect votes on a hash. /// Collect votes on a hash.
#[derive(Debug)] #[derive(Debug)]
@ -31,7 +29,7 @@ pub struct ProposeCollect {
/// Threshold vote number for success. /// Threshold vote number for success.
pub threshold: usize, pub threshold: usize,
/// Votes. /// Votes.
votes: RwLock<HashSet<Signature>>, votes: RwLock<HashSet<Address>>,
/// Was enough votes reached. /// Was enough votes reached.
is_won: AtomicBool is_won: AtomicBool
} }
@ -50,35 +48,24 @@ impl ProposeCollect {
} }
/// Vote on hash using the signed hash, true if vote counted. /// Vote on hash using the signed hash, true if vote counted.
pub fn vote(&self, signature: &Signature) -> bool { pub fn vote(&self, voter: Address) -> bool {
if self.votes.try_read().unwrap().contains(signature) { return false; } if self.votes.try_read().unwrap().contains(&voter) { return false; }
if !self.can_vote(signature).is_ok() { return false; } if !self.voters.contains(&voter) { return false; }
self.votes.try_write().unwrap().insert(signature.clone()); self.votes.try_write().unwrap().insert(voter);
true true
} }
fn can_vote(&self, signature: &Signature) -> Result<(), Error> {
let signer = Address::from(try!(recover(&signature, &self.hash)).sha3());
match self.voters.contains(&signer) {
false => try!(Err(EngineError::UnauthorisedVoter)),
true => Ok(()),
}
}
/// Some winner if voting threshold was reached. /// Some winner if voting threshold was reached.
pub fn winner(&self) -> Option<H256> { pub fn is_won(&self) -> bool {
let threshold_checker = || match self.votes.try_read().unwrap().len() >= self.threshold { let threshold_checker = || match self.votes.try_read().unwrap().len() >= self.threshold {
true => { self.is_won.store(true, Ordering::Relaxed); true }, true => { self.is_won.store(true, Ordering::Relaxed); true },
false => false, false => false,
}; };
match self.is_won.load(Ordering::Relaxed) || threshold_checker() { self.is_won.load(Ordering::Relaxed) || threshold_checker()
true => Some(self.hash),
false => None,
}
} }
/// Get signatures backing given hash. /// Get addresses backing given hash.
pub fn votes(&self) -> HashSet<Signature> { pub fn votes(&self) -> HashSet<Address> {
self.votes.try_read().unwrap().clone() self.votes.try_read().unwrap().clone()
} }
} }
@ -103,24 +90,21 @@ mod tests {
let header = Header::default(); let header = Header::default();
let bare_hash = header.bare_hash(); let bare_hash = header.bare_hash();
let voters: HashSet<_> = vec![addr1, addr2].into_iter().map(Into::into).collect(); let voters: HashSet<_> = vec![addr1.clone(), addr2.clone(), Address::default()].into_iter().map(Into::into).collect();
let vote = ProposeCollect::new(bare_hash, voters.into(), 1); let vote = ProposeCollect::new(bare_hash, voters.into(), 2);
assert!(vote.winner().is_none()); assert!(!vote.is_won());
// Unapproved voter. // Unapproved voter.
let signature = tap.sign(addr3, bare_hash).unwrap(); assert!(!vote.vote(addr3));
assert!(!vote.vote(&signature)); assert!(!vote.is_won());
assert!(vote.winner().is_none());
// First good vote. // First good vote.
let signature = tap.sign(addr1, bare_hash).unwrap(); assert!(vote.vote(addr1.clone()));
assert!(vote.vote(&signature)); assert!(!vote.is_won());
assert_eq!(vote.winner().unwrap(), bare_hash);
// Voting again is ineffective. // Voting again is ineffective.
let signature = tap.sign(addr1, bare_hash).unwrap(); assert!(!vote.vote(addr1));
assert!(!vote.vote(&signature)); assert!(!vote.is_won());
// Second valid vote. // Second valid vote thus win.
let signature = tap.sign(addr2, bare_hash).unwrap(); assert!(vote.vote(addr2));
assert!(vote.vote(&signature)); assert!(vote.is_won());
assert_eq!(vote.winner().unwrap(), bare_hash);
} }
} }