improve quality of vote_collector module (#7984)
This commit is contained in:
parent
df63341eb4
commit
e32b600530
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user