last_lock

This commit is contained in:
keorn 2016-11-17 17:12:37 +00:00
parent ce711e321a
commit 3bac68419a
3 changed files with 75 additions and 45 deletions

View File

@ -114,7 +114,7 @@ impl Decodable for ConsensusMessage {
false => Some(block_message), false => Some(block_message),
} }
}) })
} }
} }
impl Encodable for ConsensusMessage { impl Encodable for ConsensusMessage {

View File

@ -34,7 +34,7 @@ use ethkey::{recover, public_to_address};
use account_provider::AccountProvider; use account_provider::AccountProvider;
use block::*; use block::*;
use spec::CommonParams; use spec::CommonParams;
use engines::{Engine, EngineError, ProposeCollect}; use engines::{Engine, EngineError};
use blockchain::extras::BlockDetails; use blockchain::extras::BlockDetails;
use views::HeaderView; use views::HeaderView;
use evm::Schedule; use evm::Schedule;
@ -82,9 +82,9 @@ pub struct Tendermint {
proposed_block: Mutex<Option<ExecutedBlock>>, proposed_block: Mutex<Option<ExecutedBlock>>,
/// Channel for updating the sealing. /// Channel for updating the sealing.
message_channel: Mutex<Option<IoChannel<ClientIoMessage>>>, message_channel: Mutex<Option<IoChannel<ClientIoMessage>>>,
/// Last round when PoLC was seen. /// Message for the last PoLC.
last_lock_round: RwLock<ConsensusMessage>, last_lock: RwLock<Option<ConsensusMessage>>,
/// Proposed block. /// Bare hash of the proposed block, used for seal submission.
proposal: RwLock<Option<H256>> proposal: RwLock<Option<H256>>
} }
@ -105,7 +105,7 @@ impl Tendermint {
votes: VoteCollector::new(), votes: VoteCollector::new(),
proposed_block: Mutex::new(None), proposed_block: Mutex::new(None),
message_channel: Mutex::new(None), message_channel: Mutex::new(None),
last_lock_round: AtomicUsize::new(0), last_lock: RwLock::new(None),
proposal: RwLock::new(None) proposal: RwLock::new(None)
}); });
let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; let handler = TransitionHandler { engine: Arc::downgrade(&engine) };
@ -140,18 +140,28 @@ impl Tendermint {
} }
} }
fn generate_message(&self, block_hash: Option<BlockHash>) -> ConsensusMessage {
Ok(signature) = ap.sign(*author, None, block_hash(header))
ConsensusMessage { signatue
}
fn to_step(&self, step: Step) { fn to_step(&self, step: Step) {
*self.step.write() = step; *self.step.write() = step;
match step { match step {
Step::Propose => { Step::Propose => {
self.proposal.write() = None; *self.proposal.write() = None;
self.update_sealing() self.update_sealing()
}, },
Step::Prevote => { Step::Prevote => {
self.broadcast_message() self.broadcast_message()
}, },
Step::Precommit => { Step::Precommit => {
self.broadcast_message() let message = match self.last_lock.read() {
Some(m) =>
None => ConsensusMessage { signature: signature, height
}
self.broadcast_message(::rlp::encode(message))
}, },
Step::Commit => { Step::Commit => {
// Commit the block using a complete signature set. // Commit the block using a complete signature set.
@ -162,8 +172,11 @@ impl Tendermint {
::rlp::encode(proposer).to_vec(), ::rlp::encode(proposer).to_vec(),
::rlp::encode(&votes).to_vec() ::rlp::encode(&votes).to_vec()
]; ];
self.submit_seal(self.proposal.read(), seal) if let Some(block_hash) = *self.proposal.read() {
self.submit_seal(block_hash, seal);
}
} }
*self.last_lock.write() = None;
}, },
} }
} }
@ -203,7 +216,7 @@ impl Tendermint {
} }
fn has_enough_aligned_votes(&self, message: &ConsensusMessage) -> bool { fn has_enough_aligned_votes(&self, message: &ConsensusMessage) -> bool {
self.votes.aligned_signatures(&message).len() > self.threshold() self.votes.aligned_votes(&message).len() > self.threshold()
} }
} }
@ -258,9 +271,7 @@ impl Engine for Tendermint {
/// Get the address to be used as authority. /// Get the address to be used as authority.
fn on_new_block(&self, block: &mut ExecutedBlock) { fn on_new_block(&self, block: &mut ExecutedBlock) {
if let Some(mut authority) = self.authority.try_write() { *self.authority.write() = *block.header().author()
*authority = *block.header().author()
}
} }
/// Set the correct round in the seal. /// Set the correct round in the seal.
@ -280,7 +291,7 @@ impl Engine for Tendermint {
let header = block.header(); let header = block.header();
let author = header.author(); let author = header.author();
if let Ok(signature) = ap.sign(*author, None, block_hash(header)) { if let Ok(signature) = ap.sign(*author, None, block_hash(header)) {
self.proposal.write() = Some(block.hash()); *self.proposal.write() = Some(header.bare_hash());
Some(vec![ Some(vec![
::rlp::encode(&self.round.load(AtomicOrdering::SeqCst)).to_vec(), ::rlp::encode(&self.round.load(AtomicOrdering::SeqCst)).to_vec(),
::rlp::encode(&H520::from(signature)).to_vec(), ::rlp::encode(&H520::from(signature)).to_vec(),
@ -304,32 +315,41 @@ impl Engine for Tendermint {
try!(Err(BlockError::InvalidSeal)); try!(Err(BlockError::InvalidSeal));
} }
// Check if the message is known and should be handled right now. // Check if the message is known.
if self.votes.vote(message.clone(), sender).is_none() && self.is_current(&message) { if self.votes.vote(message.clone(), sender).is_none() {
let next_step = match *self.step.read() { let is_newer_than_lock = self.last_lock.read().map_or(true, |lock| message > lock);
Step::Precommit if self.has_enough_aligned_votes(&message) => { if is_newer_than_lock
if message.block_hash.is_none() { && message.step == Step::Prevote
self.round.fetch_add(1, AtomicOrdering::SeqCst); && self.has_enough_aligned_votes(&message) {
Some(Step::Propose) *self.last_lock.write() = Some(message);
} else { }
Some(Step::Commit) // Check if it can affect step transition.
} if self.is_current(&message) {
}, let next_step = match *self.step.read() {
Step::Precommit if self.has_enough_step_votes(&message) => { Step::Precommit if self.has_enough_aligned_votes(&message) => {
self.round.store(message.round, AtomicOrdering::SeqCst); if message.block_hash.is_none() {
Some(Step::Precommit) self.round.fetch_add(1, AtomicOrdering::SeqCst);
}, Some(Step::Propose)
Step::Prevote if self.has_enough_aligned_votes(&message) => Some(Step::Precommit), } else {
Step::Prevote if self.has_enough_step_votes(&message) => { Some(Step::Commit)
self.round.store(message.round, AtomicOrdering::SeqCst); }
Some(Step::Prevote) },
}, Step::Precommit if self.has_enough_step_votes(&message) => {
_ => None, self.round.store(message.round, AtomicOrdering::SeqCst);
}; Some(Step::Precommit)
},
Step::Prevote if self.has_enough_aligned_votes(&message) => Some(Step::Precommit),
Step::Prevote if self.has_enough_step_votes(&message) => {
self.round.store(message.round, AtomicOrdering::SeqCst);
Some(Step::Prevote)
},
_ => None,
};
if let Some(step) = next_step { if let Some(step) = next_step {
if let Err(io_err) = self.step_service.send_message(step) { if let Err(io_err) = self.step_service.send_message(step) {
warn!(target: "poa", "Could not proceed to next step {}.", io_err) warn!(target: "poa", "Could not proceed to next step {}.", io_err)
}
} }
} }
} }

View File

@ -36,19 +36,29 @@ impl VoteCollector {
self.votes.write().insert(message, voter) self.votes.write().insert(message, voter)
} }
pub fn seal_signatures(&self, height: Height, round: Round, block_hash: Option<H256>) -> (H520, Vec<H520>) { pub fn seal_signatures(&self, height: Height, round: Round, block_hash: Option<H256>) -> Option<(&H520, &[H520])> {
self.votes
.read()
.keys()
.cloned()
// Get only Propose and Precommits.
.filter(|m| m.is_aligned(height, round, block_hash) && m.step != Step::Prevote)
.map(|m| m.signature)
.collect::<Vec<H520>>()
.split_first()
}
pub fn aligned_votes(&self, message: &ConsensusMessage) -> Vec<&ConsensusMessage> {
self.votes self.votes
.read() .read()
.keys() .keys()
// Get only Propose and Precommits. // Get only Propose and Precommits.
.filter(|m| m.is_aligned(height, round, block_hash) && m.step != Step::Prevote) .filter(|m| m.is_aligned(message.height, message.round, message.block_hash) && m.step == message.step)
.map(|m| m.signature)
.collect() .collect()
.split_first()
} }
pub fn aligned_signatures(&self, message: &ConsensusMessage) -> Vec<H520> { pub fn aligned_signatures(&self, message: &ConsensusMessage) -> &[H520] {
self.seal_signatures(message.height, message.round, message.block_hash) self.seal_signatures(message.height, message.round, message.block_hash).map_or(&[], |s| s.1)
} }
pub fn count_step_votes(&self, height: Height, round: Round, step: Step) -> usize { pub fn count_step_votes(&self, height: Height, round: Round, step: Step) -> usize {