diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 283014a50..2f43792e5 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -21,17 +21,12 @@ mod instant_seal; mod basic_authority; mod authority_round; mod tendermint; -mod signed_vote; -mod propose_collect; - pub use self::null_engine::NullEngine; pub use self::instant_seal::InstantSeal; pub use self::basic_authority::BasicAuthority; pub use self::authority_round::AuthorityRound; pub use self::tendermint::Tendermint; -pub use self::signed_vote::SignedVote; -pub use self::propose_collect::ProposeCollect; use rlp::UntrustedRlp; use util::*; diff --git a/ethcore/src/engines/propose_collect.rs b/ethcore/src/engines/propose_collect.rs deleted file mode 100644 index c60457c3a..000000000 --- a/ethcore/src/engines/propose_collect.rs +++ /dev/null @@ -1,109 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Voting on a hash, where each vote has to come from a set of addresses. - -use std::sync::atomic::{AtomicBool, Ordering}; -use util::{HashSet, RwLock, H256, Address}; - -/// Collect votes on a hash. -#[derive(Debug)] -pub struct ProposeCollect { - /// Proposed hash. - pub hash: H256, - /// Allowed voter addresses. - pub voters: HashSet
, - /// Threshold vote number for success. - pub threshold: usize, - /// Votes. - votes: RwLock>, - /// Was enough votes reached. - is_won: AtomicBool -} - -impl ProposeCollect { - /// Create a new instance of BFT engine - pub fn new(hash: H256, voters: HashSet
, threshold: usize) -> Self { - assert!(voters.len() > threshold); - ProposeCollect { - hash: hash, - voters: voters, - threshold: threshold, - votes: RwLock::new(HashSet::new()), - is_won: AtomicBool::new(false) - } - } - - /// Vote on hash using the signed hash, true if vote counted. - pub fn vote(&self, voter: Address) -> bool { - let is_known = self.votes.try_read().unwrap().contains(&voter); - if !is_known && self.voters.contains(&voter) { - self.votes.try_write().unwrap().insert(voter); - true - } else { - false - } - } - - /// Some winner if voting threshold was reached. - pub fn is_won(&self) -> bool { - let threshold_checker = || match self.votes.try_read().unwrap().len() >= self.threshold { - true => { self.is_won.store(true, Ordering::Relaxed); true }, - false => false, - }; - self.is_won.load(Ordering::Relaxed) || threshold_checker() - } -} - -#[cfg(test)] -mod tests { - use engines::propose_collect::ProposeCollect; - use account_provider::AccountProvider; - use util::*; - use header::Header; - - #[test] - fn simple_propose_collect() { - let tap = AccountProvider::transient_provider(); - let addr1 = tap.insert_account("1".sha3(), "1").unwrap(); - tap.unlock_account_permanently(addr1, "1".into()).unwrap(); - - let addr2 = tap.insert_account("2".sha3(), "2").unwrap(); - tap.unlock_account_permanently(addr2, "2".into()).unwrap(); - - let addr3 = tap.insert_account("3".sha3(), "3").unwrap(); - tap.unlock_account_permanently(addr3, "3".into()).unwrap(); - - let header = Header::default(); - let bare_hash = header.bare_hash(); - let voters: HashSet<_> = vec![addr1.clone(), addr2.clone(), Address::default()].into_iter().map(Into::into).collect(); - let vote = ProposeCollect::new(bare_hash, voters.into(), 2); - assert!(!vote.is_won()); - - // Unapproved voter. - assert!(!vote.vote(addr3)); - assert!(!vote.is_won()); - // First good vote. - assert!(vote.vote(addr1.clone())); - assert!(!vote.is_won()); - // Voting again is ineffective. - assert!(!vote.vote(addr1)); - assert!(!vote.is_won()); - // Second valid vote thus win. - assert!(vote.vote(addr2)); - assert!(vote.is_won()); - } -} diff --git a/ethcore/src/engines/signed_vote.rs b/ethcore/src/engines/signed_vote.rs deleted file mode 100644 index 0cef5c214..000000000 --- a/ethcore/src/engines/signed_vote.rs +++ /dev/null @@ -1,125 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Voting on hashes, where each vote has to come from a set of public keys. - -use super::EngineError; -use util::*; -use error::Error; -use ethkey::{Signature, recover}; - -/// Signed voting on hashes. -#[derive(Debug)] -pub struct SignedVote { - /// Voter public keys. - pub voters: HashSet
, - /// Number of voters. - pub voter_n: usize, - /// Threshold vote number for success. - pub threshold: usize, - /// Votes. - votes: RwLock>>, - /// Winner hash, set after enough votes are reached. - winner: RwLock> -} - -impl SignedVote { - /// Create a new instance of BFT engine - pub fn new(voters: HashSet
, threshold: usize) -> Self { - let voters_n = voters.len(); - assert!(voters_n > threshold); - SignedVote { - voter_n: voters_n, - voters: voters, - threshold: threshold, - votes: RwLock::new(HashMap::new()), - winner: RwLock::new(None) - } - } - - /// Vote on hash using the signed hash, true if vote counted. - pub fn vote(&self, bare_hash: H256, signature: Signature) -> bool { - if !self.can_vote(&bare_hash, &signature).is_ok() { return false; } - let mut guard = self.votes.try_write().unwrap(); - let set = guard.entry(bare_hash.clone()).or_insert_with(|| HashSet::new()); - if !set.insert(signature) { return false; } - // Set the winner if threshold is reached. - if set.len() >= self.threshold { - let mut guard = self.winner.try_write().unwrap(); - *guard = Some(bare_hash); - } - true - } - - fn can_vote(&self, bare_hash: &H256, signature: &Signature) -> Result<(), Error> { - let signer = Address::from(try!(recover(&signature, bare_hash)).sha3()); - match self.voters.contains(&signer) { - false => try!(Err(EngineError::UnauthorisedVoter)), - true => Ok(()), - } - } - - /// Some winner if voting threshold was reached. - pub fn winner(&self) -> Option { self.winner.try_read().unwrap().clone() } - - /// Get signatures backing given hash. - pub fn votes(&self, bare_hash: &H256) -> Option> { - self.votes.try_read().unwrap().get(bare_hash).cloned() - } -} - -#[cfg(test)] -mod tests { - use util::*; - use header::Header; - use engines::signed_vote::SignedVote; - use account_provider::AccountProvider; - - #[test] - fn simple_vote() { - let tap = AccountProvider::transient_provider(); - let addr1 = tap.insert_account("1".sha3(), "1").unwrap(); - tap.unlock_account_permanently(addr1, "1".into()).unwrap(); - - let addr2 = tap.insert_account("2".sha3(), "2").unwrap(); - tap.unlock_account_permanently(addr2, "2".into()).unwrap(); - - let addr3 = tap.insert_account("3".sha3(), "3").unwrap(); - tap.unlock_account_permanently(addr3, "3".into()).unwrap(); - - let voters: HashSet<_> = vec![addr1, addr2].into_iter().map(Into::into).collect(); - let vote = SignedVote::new(voters.into(), 1); - assert!(vote.winner().is_none()); - let header = Header::default(); - let bare_hash = header.bare_hash(); - - // Unapproved voter. - let signature = tap.sign(addr3, None, bare_hash).unwrap(); - assert!(!vote.vote(bare_hash, signature)); - assert!(vote.winner().is_none()); - // First good vote. - let signature = tap.sign(addr1, None, bare_hash).unwrap(); - assert!(vote.vote(bare_hash, signature)); - assert_eq!(vote.winner().unwrap(), bare_hash); - // Voting again is ineffective. - let signature = tap.sign(addr1, None, bare_hash).unwrap(); - assert!(!vote.vote(bare_hash, signature)); - // Second valid vote. - let signature = tap.sign(addr2, None, bare_hash).unwrap(); - assert!(vote.vote(bare_hash, signature)); - assert_eq!(vote.winner().unwrap(), bare_hash); - } -}