move vote with addresses, remove recover check
This commit is contained in:
parent
a4ba7262ad
commit
f60d4645ed
@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user