improve quality of vote_collector module (#7984)

This commit is contained in:
Marek Kotewicz 2018-02-27 18:29:43 +01:00 committed by André Silva
parent df63341eb4
commit e32b600530
2 changed files with 21 additions and 23 deletions

View File

@ -223,7 +223,7 @@ impl Tendermint {
(Some(validator), Ok(signature)) => { (Some(validator), Ok(signature)) => {
let message_rlp = message_full_rlp(&signature, &vote_info); let message_rlp = message_full_rlp(&signature, &vote_info);
let message = ConsensusMessage::new(signature, h, r, s, block_hash); let message = ConsensusMessage::new(signature, h, r, s, block_hash);
self.votes.vote(message.clone(), &validator); self.votes.vote(message.clone(), validator);
debug!(target: "engine", "Generated {:?} as {}.", message, validator); debug!(target: "engine", "Generated {:?} as {}.", message, validator);
self.handle_valid_message(&message); self.handle_valid_message(&message);
@ -493,7 +493,7 @@ impl Engine<EthereumMachine> for Tendermint {
if let Ok(signature) = self.sign(keccak(&vote_info)).map(Into::into) { if let Ok(signature) = self.sign(keccak(&vote_info)).map(Into::into) {
// Insert Propose vote. // Insert Propose vote.
debug!(target: "engine", "Submitting proposal {} at height {} view {}.", header.bare_hash(), height, view); debug!(target: "engine", "Submitting proposal {} at height {} view {}.", header.bare_hash(), height, view);
self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), author); self.votes.vote(ConsensusMessage::new(signature, height, view, Step::Propose, bh), *author);
// Remember the owned block. // Remember the owned block.
*self.last_proposed.write() = header.bare_hash(); *self.last_proposed.write() = header.bare_hash();
// Remember proposal for later seal submission. // Remember proposal for later seal submission.
@ -527,7 +527,7 @@ impl Engine<EthereumMachine> for Tendermint {
return Err(EngineError::NotAuthorized(sender)); return Err(EngineError::NotAuthorized(sender));
} }
self.broadcast_message(rlp.as_raw().to_vec()); self.broadcast_message(rlp.as_raw().to_vec());
if let Some(double) = self.votes.vote(message.clone(), &sender) { if let Some(double) = self.votes.vote(message.clone(), sender) {
let height = message.vote_step.height as BlockNumber; let height = message.vote_step.height as BlockNumber;
self.validators.report_malicious(&sender, height, height, ::rlp::encode(&double).into_vec()); self.validators.report_malicious(&sender, height, height, ::rlp::encode(&double).into_vec());
return Err(EngineError::DoubleVote(sender)); return Err(EngineError::DoubleVote(sender));
@ -719,7 +719,7 @@ impl Engine<EthereumMachine> for Tendermint {
*self.proposal.write() = proposal.block_hash.clone(); *self.proposal.write() = proposal.block_hash.clone();
*self.proposal_parent.write() = header.parent_hash().clone(); *self.proposal_parent.write() = header.parent_hash().clone();
} }
self.votes.vote(proposal, &proposer); self.votes.vote(proposal, proposer);
true true
} }

View File

@ -45,18 +45,18 @@ pub struct VoteCollector<M: Message> {
#[derive(Debug, Default)] #[derive(Debug, Default)]
struct StepCollector<M: Message> { struct StepCollector<M: Message> {
voted: HashMap<Address, M>, voted: HashMap<Address, M>,
pub block_votes: HashMap<Option<H256>, HashMap<H520, Address>>, block_votes: HashMap<Option<H256>, HashMap<H520, Address>>,
messages: HashSet<M>, messages: HashSet<M>,
} }
#[derive(Debug)] #[derive(Debug)]
pub struct DoubleVote<'a, M: Message> { pub struct DoubleVote<M: Message> {
pub author: &'a Address, author: Address,
vote_one: M, vote_one: M,
vote_two: M, vote_two: M,
} }
impl<'a, M: Message> Encodable for DoubleVote<'a, M> { impl<M: Message> Encodable for DoubleVote<M> {
fn rlp_append(&self, s: &mut RlpStream) { fn rlp_append(&self, s: &mut RlpStream) {
s.begin_list(2) s.begin_list(2)
.append(&self.vote_one) .append(&self.vote_one)
@ -66,10 +66,10 @@ impl<'a, M: Message> Encodable for DoubleVote<'a, M> {
impl <M: Message> StepCollector<M> { impl <M: Message> StepCollector<M> {
/// Returns Some(&Address) when validator is double voting. /// Returns Some(&Address) when validator is double voting.
fn insert<'a>(&mut self, message: M, address: &'a Address) -> Option<DoubleVote<'a, M>> { fn insert(&mut self, message: M, address: Address) -> Option<DoubleVote<M>> {
// Do nothing when message was seen. // Do nothing when message was seen.
if self.messages.insert(message.clone()) { if self.messages.insert(message.clone()) {
if let Some(previous) = self.voted.insert(address.clone(), message.clone()) { if let Some(previous) = self.voted.insert(address, message.clone()) {
// Bad validator sent a different message. // Bad validator sent a different message.
return Some(DoubleVote { return Some(DoubleVote {
author: address, author: address,
@ -81,7 +81,7 @@ impl <M: Message> StepCollector<M> {
.block_votes .block_votes
.entry(message.block_hash()) .entry(message.block_hash())
.or_insert_with(HashMap::new) .or_insert_with(HashMap::new)
.insert(message.signature(), address.clone()); .insert(message.signature(), address);
} }
} }
None None
@ -124,7 +124,7 @@ impl <M: Message + Default> Default for VoteCollector<M> {
impl <M: Message + Default + Encodable + Debug> VoteCollector<M> { impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
/// Insert vote if it is newer than the oldest one. /// Insert vote if it is newer than the oldest one.
pub fn vote<'a>(&self, message: M, voter: &'a Address) -> Option<DoubleVote<'a, M>> { pub fn vote(&self, message: M, voter: Address) -> Option<DoubleVote<M>> {
self self
.votes .votes
.write() .write()
@ -198,12 +198,6 @@ impl <M: Message + Default + Encodable + Debug> VoteCollector<M> {
let guard = self.votes.read(); let guard = self.votes.read();
guard.get(&message.round()).and_then(|c| c.block_votes.get(&message.block_hash())).and_then(|origins| origins.get(&message.signature()).cloned()) guard.get(&message.round()).and_then(|c| c.block_votes.get(&message.block_hash())).and_then(|origins| origins.get(&message.signature()).cloned())
} }
/// Count the number of total rounds kept track of.
#[cfg(test)]
pub fn len(&self) -> usize {
self.votes.read().len()
}
} }
#[cfg(test)] #[cfg(test)]
@ -244,10 +238,10 @@ mod tests {
} }
fn random_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>) -> bool { fn random_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>) -> bool {
full_vote(collector, signature, step, block_hash, &H160::random()) full_vote(collector, signature, step, block_hash, H160::random())
} }
fn full_vote<'a>(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>, address: &'a Address) -> bool { fn full_vote(collector: &VoteCollector<TestMessage>, signature: H520, step: TestStep, block_hash: Option<H256>, address: Address) -> bool {
collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address).is_none() collector.vote(TestMessage { signature: signature, step: step, block_hash: block_hash }, address).is_none()
} }
@ -335,7 +329,11 @@ mod tests {
vote(1, Some(keccak("1"))); vote(1, Some(keccak("1")));
collector.throw_out_old(&7); collector.throw_out_old(&7);
assert_eq!(collector.len(), 2); assert_eq!(collector.count_round_votes(&1), 0);
assert_eq!(collector.count_round_votes(&3), 0);
assert_eq!(collector.count_round_votes(&6), 0);
assert_eq!(collector.count_round_votes(&7), 1);
assert_eq!(collector.count_round_votes(&8), 1);
} }
#[test] #[test]
@ -343,9 +341,9 @@ mod tests {
let collector = VoteCollector::default(); let collector = VoteCollector::default();
let round = 3; let round = 3;
// Vote is inserted fine. // Vote is inserted fine.
assert!(full_vote(&collector, H520::random(), round, Some(keccak("0")), &Address::default())); assert!(full_vote(&collector, H520::random(), round, Some(keccak("0")), Address::default()));
// Returns the double voting address. // Returns the double voting address.
assert!(!full_vote(&collector, H520::random(), round, Some(keccak("1")), &Address::default())); assert!(!full_vote(&collector, H520::random(), round, Some(keccak("1")), Address::default()));
assert_eq!(collector.count_round_votes(&round), 1); assert_eq!(collector.count_round_votes(&round), 1);
} }
} }