docs, tweaks

This commit is contained in:
keorn 2016-12-08 20:09:30 +01:00
parent 3ebfa1481d
commit dca752e9bb
3 changed files with 28 additions and 26 deletions

View File

@ -14,7 +14,12 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Tendermint BFT consensus engine with round robin proof-of-authority. /// Tendermint BFT consensus engine with round robin proof-of-authority.
/// At each blockchain `Height` there can be multiple `Round`s of voting.
/// Block is issued when there is enough `Precommit` votes collected on a particular block at the end of a `Round`.
/// Signatures always sign `Height`, `Round`, `Step` and `BlockHash` which is a block hash without seal.
/// First a block with `Seal::Proposal` is issued by the designated proposer.
/// Once enough votes have been gathered the proposer issues that block in the `Commit` step.
mod message; mod message;
mod transition; mod transition;
@ -191,10 +196,11 @@ impl Tendermint {
} }
} }
fn to_height(&self, height: Height) { fn to_next_height(&self, height: Height) {
debug!(target: "poa", "Transitioning to height {}.", height); let new_height = height + 1;
debug!(target: "poa", "Received a Commit, transitioning to height {}.", new_height);
self.last_lock.store(0, AtomicOrdering::SeqCst); self.last_lock.store(0, AtomicOrdering::SeqCst);
self.height.store(height, AtomicOrdering::SeqCst); self.height.store(new_height, AtomicOrdering::SeqCst);
self.round.store(0, AtomicOrdering::SeqCst); self.round.store(0, AtomicOrdering::SeqCst);
*self.lock_change.write() = None; *self.lock_change.write() = None;
} }
@ -232,18 +238,19 @@ impl Tendermint {
let height = self.height.load(AtomicOrdering::SeqCst); let height = self.height.load(AtomicOrdering::SeqCst);
if let Some(block_hash) = *self.proposal.read() { if let Some(block_hash) = *self.proposal.read() {
// Generate seal and remove old votes. // Generate seal and remove old votes.
if let Some(seal) = self.votes.seal_signatures(height, round, block_hash) { if self.is_proposer(&*self.authority.read()).is_ok() {
trace!(target: "poa", "to_step: Collected seal: {:?}", seal); if let Some(seal) = self.votes.seal_signatures(height, round, block_hash) {
if self.is_proposer(&*self.authority.read()).is_ok() { trace!(target: "poa", "to_step: Collected seal: {:?}", seal);
let seal = vec![ let seal = vec![
::rlp::encode(&round).to_vec(), ::rlp::encode(&round).to_vec(),
::rlp::encode(&seal.proposal).to_vec(), ::rlp::encode(&seal.proposal).to_vec(),
::rlp::encode(&seal.votes).to_vec() ::rlp::encode(&seal.votes).to_vec()
]; ];
self.submit_seal(block_hash, seal); self.submit_seal(block_hash, seal);
self.to_next_height(height);
} else {
warn!(target: "poa", "Proposal was not found!");
} }
} else {
warn!(target: "poa", "Proposal was not found!");
} }
} }
}, },
@ -289,10 +296,6 @@ impl Tendermint {
self.round.fetch_add(n, AtomicOrdering::SeqCst); self.round.fetch_add(n, AtomicOrdering::SeqCst);
} }
fn new_height(&self) {
self.to_height(self.height.load(AtomicOrdering::SeqCst) + 1);
}
fn should_unlock(&self, lock_change_round: Round) -> bool { fn should_unlock(&self, lock_change_round: Round) -> bool {
self.last_lock.load(AtomicOrdering::SeqCst) < lock_change_round self.last_lock.load(AtomicOrdering::SeqCst) < lock_change_round
&& lock_change_round < self.round.load(AtomicOrdering::SeqCst) && lock_change_round < self.round.load(AtomicOrdering::SeqCst)
@ -414,7 +417,7 @@ impl Engine for Tendermint {
let header = block.header(); let header = block.header();
let author = header.author(); let author = header.author();
// Only proposer can generate seal if None was generated. // Only proposer can generate seal if None was generated.
if self.is_proposer(author).is_err() && self.proposal.read().is_none() { if self.is_proposer(author).is_err() || self.proposal.read().is_some() {
return Seal::None; return Seal::None;
} }
@ -428,6 +431,7 @@ impl Engine for Tendermint {
self.votes.vote(ConsensusMessage::new(signature, height, round, Step::Propose, bh), *author); self.votes.vote(ConsensusMessage::new(signature, height, round, Step::Propose, bh), *author);
// Remember proposal for later seal submission. // Remember proposal for later seal submission.
*self.proposal.write() = bh; *self.proposal.write() = bh;
assert!(self.is_round_proposer(height, round, author).is_ok());
Seal::Proposal(vec![ Seal::Proposal(vec![
::rlp::encode(&round).to_vec(), ::rlp::encode(&round).to_vec(),
::rlp::encode(&signature).to_vec(), ::rlp::encode(&signature).to_vec(),
@ -509,13 +513,8 @@ impl Engine for Tendermint {
} }
} }
if self.is_above_threshold(signature_count) {
// Skip ahead if block is from the future.
if proposal.height > self.height.load(AtomicOrdering::SeqCst) {
self.to_height(proposal.height);
}
// Check if its a proposal if there is not enough precommits. // Check if its a proposal if there is not enough precommits.
} else { if !self.is_above_threshold(signature_count) {
let signatures_len = signatures_field.len(); let signatures_len = signatures_field.len();
// Proposal has to have an empty signature list. // Proposal has to have an empty signature list.
if signatures_len != 1 { if signatures_len != 1 {
@ -563,9 +562,9 @@ impl Engine for Tendermint {
} }
fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool {
trace!(target: "poa", "new_header: {}, best_header: {}", new_header.number(), best_header.number());
let new_number = new_header.number(); let new_number = new_header.number();
let best_number = best_header.number(); let best_number = best_header.number();
trace!(target: "poa", "new_header: {}, best_header: {}", new_number, best_number);
if new_number != best_number { if new_number != best_number {
new_number > best_number new_number > best_number
} else { } else {
@ -586,10 +585,12 @@ impl Engine for Tendermint {
fn is_proposal(&self, header: &Header) -> bool { fn is_proposal(&self, header: &Header) -> bool {
let signatures_len = header.seal()[2].len(); let signatures_len = header.seal()[2].len();
// Signatures have to be an empty list rlp. // Signatures have to be an empty list rlp.
let proposal = ConsensusMessage::new_proposal(header).expect("block went through full verification; this Engine verifies new_proposal creation; qed");
if signatures_len != 1 { if signatures_len != 1 {
// New Commit received, skip to next height.
self.to_next_height(proposal.height);
return false; return false;
} }
let proposal = ConsensusMessage::new_proposal(header).expect("block went through full verification; this Engine verifies new_proposal creation; qed");
let proposer = proposal.verify().expect("block went through full verification; this Engine tries verify; qed"); let proposer = proposal.verify().expect("block went through full verification; this Engine tries verify; qed");
debug!(target: "poa", "Received a new proposal for height {}, round {} from {}.", proposal.height, proposal.round, proposer); debug!(target: "poa", "Received a new proposal for height {}, round {} from {}.", proposal.height, proposal.round, proposer);
if self.is_round(&proposal) { if self.is_round(&proposal) {

View File

@ -106,7 +106,6 @@ impl IoHandler<Step> for TransitionHandler {
Step::Commit => { Step::Commit => {
trace!(target: "poa", "timeout: Commit timeout."); trace!(target: "poa", "timeout: Commit timeout.");
set_timeout(io, engine.our_params.timeouts.propose); set_timeout(io, engine.our_params.timeouts.propose);
engine.new_height();
Some(Step::Propose) Some(Step::Propose)
}, },
}; };

View File

@ -469,9 +469,11 @@ impl Miner {
// Save proposal for later seal submission and broadcast it. // Save proposal for later seal submission and broadcast it.
Seal::Proposal(seal) => { Seal::Proposal(seal) => {
trace!(target: "miner", "Received a Proposal seal."); trace!(target: "miner", "Received a Proposal seal.");
let mut sealing_work = self.sealing_work.lock(); {
sealing_work.queue.push(block.clone()); let mut sealing_work = self.sealing_work.lock();
sealing_work.queue.use_last_ref(); sealing_work.queue.push(block.clone());
sealing_work.queue.use_last_ref();
}
block block
.lock() .lock()
.seal(&*self.engine, seal) .seal(&*self.engine, seal)