return errors from constructor
This commit is contained in:
		
							parent
							
								
									dd8ed42270
								
							
						
					
					
						commit
						54e4956345
					
				@ -19,11 +19,11 @@
 | 
				
			|||||||
mod message;
 | 
					mod message;
 | 
				
			||||||
mod timeout;
 | 
					mod timeout;
 | 
				
			||||||
mod params;
 | 
					mod params;
 | 
				
			||||||
mod vote;
 | 
					 | 
				
			||||||
mod vote_collector;
 | 
					mod vote_collector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
 | 
					use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
 | 
				
			||||||
use util::*;
 | 
					use util::*;
 | 
				
			||||||
 | 
					use basic_types::Seal;
 | 
				
			||||||
use error::{Error, BlockError};
 | 
					use error::{Error, BlockError};
 | 
				
			||||||
use header::Header;
 | 
					use header::Header;
 | 
				
			||||||
use builtin::Builtin;
 | 
					use builtin::Builtin;
 | 
				
			||||||
@ -42,16 +42,14 @@ use io::IoService;
 | 
				
			|||||||
use self::message::ConsensusMessage;
 | 
					use self::message::ConsensusMessage;
 | 
				
			||||||
use self::timeout::{TimerHandler, NextStep};
 | 
					use self::timeout::{TimerHandler, NextStep};
 | 
				
			||||||
use self::params::TendermintParams;
 | 
					use self::params::TendermintParams;
 | 
				
			||||||
use self::vote::Vote;
 | 
					use self::vote_collector::VoteCollector;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#[derive(Debug)]
 | 
					#[derive(Debug, PartialEq, Eq)]
 | 
				
			||||||
enum Step {
 | 
					pub enum Step {
 | 
				
			||||||
	Propose,
 | 
						Propose,
 | 
				
			||||||
	Prevote(ProposeCollect),
 | 
						Prevote,
 | 
				
			||||||
	/// Precommit step storing the precommit vote and accumulating seal.
 | 
						Precommit,
 | 
				
			||||||
	Precommit(ProposeCollect, Signatures),
 | 
						Commit
 | 
				
			||||||
	/// Commit step storing a complete valid seal.
 | 
					 | 
				
			||||||
	Commit(BlockHash, Signatures)
 | 
					 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
pub type Height = usize;
 | 
					pub type Height = usize;
 | 
				
			||||||
@ -69,43 +67,45 @@ pub struct Tendermint {
 | 
				
			|||||||
	timeout_service: IoService<NextStep>,
 | 
						timeout_service: IoService<NextStep>,
 | 
				
			||||||
	/// Address to be used as authority.
 | 
						/// Address to be used as authority.
 | 
				
			||||||
	authority: RwLock<Address>,
 | 
						authority: RwLock<Address>,
 | 
				
			||||||
 | 
						/// Blockchain height.
 | 
				
			||||||
 | 
						height: AtomicUsize,
 | 
				
			||||||
	/// Consensus round.
 | 
						/// Consensus round.
 | 
				
			||||||
	r: AtomicUsize,
 | 
						round: AtomicUsize,
 | 
				
			||||||
	/// Consensus step.
 | 
						/// Consensus step.
 | 
				
			||||||
	s: RwLock<Step>,
 | 
						step: RwLock<Step>,
 | 
				
			||||||
	/// Current step timeout in ms.
 | 
						/// Current step timeout in ms.
 | 
				
			||||||
	timeout: AtomicMs,
 | 
						timeout: AtomicMs,
 | 
				
			||||||
	/// Used to swith proposer.
 | 
						/// Used to swith proposer.
 | 
				
			||||||
	proposer_nonce: AtomicUsize,
 | 
						proposer_nonce: AtomicUsize,
 | 
				
			||||||
 | 
						/// Vote accumulator.
 | 
				
			||||||
 | 
						votes: VoteCollector
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Tendermint {
 | 
					impl Tendermint {
 | 
				
			||||||
	/// Create a new instance of Tendermint engine
 | 
						/// Create a new instance of Tendermint engine
 | 
				
			||||||
	pub fn new(params: CommonParams, our_params: TendermintParams, builtins: BTreeMap<Address, Builtin>) -> Arc<Self> {
 | 
						pub fn new(params: CommonParams, our_params: TendermintParams, builtins: BTreeMap<Address, Builtin>) -> Result<Arc<Self>, Error> {
 | 
				
			||||||
		let engine = Arc::new(
 | 
							let engine = Arc::new(
 | 
				
			||||||
			Tendermint {
 | 
								Tendermint {
 | 
				
			||||||
				params: params,
 | 
									params: params,
 | 
				
			||||||
				timeout: AtomicUsize::new(our_params.timeouts.propose),
 | 
									timeout: AtomicUsize::new(our_params.timeouts.propose),
 | 
				
			||||||
				our_params: our_params,
 | 
									our_params: our_params,
 | 
				
			||||||
				builtins: builtins,
 | 
									builtins: builtins,
 | 
				
			||||||
				timeout_service: IoService::<NextStep>::start().expect("Error creating engine timeout service"),
 | 
									timeout_service: try!(IoService::<NextStep>::start()),
 | 
				
			||||||
				authority: RwLock::new(Address::default()),
 | 
									authority: RwLock::new(Address::default()),
 | 
				
			||||||
				r: AtomicUsize::new(0),
 | 
									height: AtomicUsize::new(0),
 | 
				
			||||||
				s: RwLock::new(Step::Propose),
 | 
									round: AtomicUsize::new(0),
 | 
				
			||||||
				proposer_nonce: AtomicUsize::new(0)
 | 
									step: RwLock::new(Step::Propose),
 | 
				
			||||||
 | 
									proposer_nonce: AtomicUsize::new(0),
 | 
				
			||||||
 | 
									votes: VoteCollector::new()
 | 
				
			||||||
			});
 | 
								});
 | 
				
			||||||
		let handler = TimerHandler::new(Arc::downgrade(&engine));
 | 
							let handler = TimerHandler { engine: Arc::downgrade(&engine) };
 | 
				
			||||||
		engine.timeout_service.register_handler(Arc::new(handler)).expect("Error creating engine timeout service");
 | 
							try!(engine.timeout_service.register_handler(Arc::new(handler)));
 | 
				
			||||||
		engine
 | 
							Ok(engine)
 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	fn is_proposer(&self, address: &Address) -> bool {
 | 
					 | 
				
			||||||
		self.is_nonce_proposer(self.proposer_nonce.load(AtomicOrdering::SeqCst), address)
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn nonce_proposer(&self, proposer_nonce: usize) -> &Address {
 | 
						fn nonce_proposer(&self, proposer_nonce: usize) -> &Address {
 | 
				
			||||||
		let ref p = self.our_params;
 | 
							let ref p = self.our_params;
 | 
				
			||||||
		p.authorities.get(proposer_nonce%p.authority_n).unwrap()
 | 
							p.authorities.get(proposer_nonce % p.authority_n).unwrap()
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn is_nonce_proposer(&self, proposer_nonce: usize, address: &Address) -> bool {
 | 
						fn is_nonce_proposer(&self, proposer_nonce: usize, address: &Address) -> bool {
 | 
				
			||||||
@ -123,12 +123,12 @@ impl Tendermint {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn to_step(&self, step: Step) {
 | 
						fn to_step(&self, step: Step) {
 | 
				
			||||||
		let mut guard = self.s.try_write().unwrap();
 | 
							let mut guard = self.step.try_write().unwrap();
 | 
				
			||||||
		*guard = step;
 | 
							*guard = step;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn to_propose(&self) {
 | 
						fn to_propose(&self) {
 | 
				
			||||||
		trace!(target: "tendermint", "step: entering propose");
 | 
							trace!(target: "poa", "step: entering propose");
 | 
				
			||||||
		println!("step: entering propose");
 | 
							println!("step: entering propose");
 | 
				
			||||||
		self.proposer_nonce.fetch_add(1, AtomicOrdering::Relaxed);
 | 
							self.proposer_nonce.fetch_add(1, AtomicOrdering::Relaxed);
 | 
				
			||||||
		self.to_step(Step::Propose);
 | 
							self.to_step(Step::Propose);
 | 
				
			||||||
@ -136,7 +136,7 @@ impl Tendermint {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fn propose_message(&self, message: UntrustedRlp) -> Result<Bytes, Error> {
 | 
						fn propose_message(&self, message: UntrustedRlp) -> Result<Bytes, Error> {
 | 
				
			||||||
		// Check if message is for correct step.
 | 
							// Check if message is for correct step.
 | 
				
			||||||
		match *self.s.try_read().unwrap() {
 | 
							match *self.step.try_read().unwrap() {
 | 
				
			||||||
			Step::Propose => (),
 | 
								Step::Propose => (),
 | 
				
			||||||
			_ => try!(Err(EngineError::WrongStep)),
 | 
								_ => try!(Err(EngineError::WrongStep)),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
@ -146,7 +146,7 @@ impl Tendermint {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn to_prevote(&self, proposal: BlockHash) {
 | 
						fn to_prevote(&self, proposal: BlockHash) {
 | 
				
			||||||
		trace!(target: "tendermint", "step: entering prevote");
 | 
							trace!(target: "poa", "step: entering prevote");
 | 
				
			||||||
		println!("step: entering prevote");
 | 
							println!("step: entering prevote");
 | 
				
			||||||
		// Proceed to the prevote step.
 | 
							// Proceed to the prevote step.
 | 
				
			||||||
		self.to_step(Step::Prevote(self.new_vote(proposal)));
 | 
							self.to_step(Step::Prevote(self.new_vote(proposal)));
 | 
				
			||||||
@ -154,8 +154,8 @@ impl Tendermint {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	fn prevote_message(&self, sender: Address, message: UntrustedRlp) -> Result<Bytes, Error> {
 | 
						fn prevote_message(&self, sender: Address, message: UntrustedRlp) -> Result<Bytes, Error> {
 | 
				
			||||||
		// Check if message is for correct step.
 | 
							// Check if message is for correct step.
 | 
				
			||||||
		let hash = match *self.s.try_write().unwrap() {
 | 
							let hash = match *self.step.try_write().unwrap() {
 | 
				
			||||||
			Step::Prevote(ref mut vote) => {
 | 
								Step::Prevote => {
 | 
				
			||||||
				// Vote if message is about the right block.
 | 
									// Vote if message is about the right block.
 | 
				
			||||||
				if vote.hash == try!(message.as_val()) {
 | 
									if vote.hash == try!(message.as_val()) {
 | 
				
			||||||
					vote.vote(sender);
 | 
										vote.vote(sender);
 | 
				
			||||||
@ -178,43 +178,39 @@ impl Tendermint {
 | 
				
			|||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn to_precommit(&self, proposal: BlockHash) {
 | 
						fn to_precommit(&self, proposal: BlockHash) {
 | 
				
			||||||
		trace!(target: "tendermint", "step: entering precommit");
 | 
							trace!(target: "poa", "step: entering precommit");
 | 
				
			||||||
		println!("step: entering precommit");
 | 
							println!("step: entering precommit");
 | 
				
			||||||
		self.to_step(Step::Precommit(self.new_vote(proposal), Vec::new()));
 | 
							self.to_step(Step::Precommit(self.new_vote(proposal), Vec::new()));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn precommit_message(&self, sender: Address, signature: H520, message: UntrustedRlp) -> Result<Bytes, Error> {
 | 
					 | 
				
			||||||
		// Check if message is for correct step.
 | 
					 | 
				
			||||||
		match *self.s.try_write().unwrap() {
 | 
					 | 
				
			||||||
			Step::Precommit(ref mut vote, ref mut seal) => {
 | 
					 | 
				
			||||||
				// Vote and accumulate seal if message is about the right block.
 | 
					 | 
				
			||||||
				if vote.hash == try!(message.as_val()) {
 | 
					 | 
				
			||||||
					if vote.vote(sender) { seal.push(encode(&signature).to_vec()); }
 | 
					 | 
				
			||||||
					// Commit if precommit is won.
 | 
					 | 
				
			||||||
					if vote.is_won() { self.to_commit(vote.hash.clone(), seal.clone()); }
 | 
					 | 
				
			||||||
					Ok(message.as_raw().to_vec())
 | 
					 | 
				
			||||||
				} else {
 | 
					 | 
				
			||||||
					try!(Err(EngineError::WrongVote))
 | 
					 | 
				
			||||||
				}
 | 
					 | 
				
			||||||
			},
 | 
					 | 
				
			||||||
			_ => try!(Err(EngineError::WrongStep)),
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	/// Move to commit step, when valid block is known and being distributed.
 | 
						/// Move to commit step, when valid block is known and being distributed.
 | 
				
			||||||
	pub fn to_commit(&self, block_hash: H256, seal: Vec<Bytes>) {
 | 
						pub fn to_commit(&self, block_hash: H256, seal: Vec<Bytes>) {
 | 
				
			||||||
		trace!(target: "tendermint", "step: entering commit");
 | 
							trace!(target: "poa", "step: entering commit");
 | 
				
			||||||
		println!("step: entering commit");
 | 
							println!("step: entering commit");
 | 
				
			||||||
		self.to_step(Step::Commit(block_hash, seal));
 | 
							self.to_step(Step::Commit(block_hash, seal));
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn threshold(&self) -> usize {
 | 
						fn threshold(&self) -> usize {
 | 
				
			||||||
		self.our_params.authority_n*2/3
 | 
							self.our_params.authority_n * 2/3
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn next_timeout(&self) -> u64 {
 | 
						fn next_timeout(&self) -> u64 {
 | 
				
			||||||
		self.timeout.load(AtomicOrdering::Relaxed) as u64
 | 
							self.timeout.load(AtomicOrdering::Relaxed) as u64
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Round proposer switching.
 | 
				
			||||||
 | 
						fn is_proposer(&self, address: &Address) -> bool {
 | 
				
			||||||
 | 
							self.is_nonce_proposer(self.proposer_nonce.load(AtomicOrdering::SeqCst), address)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fn is_current(&self, message: &ConsensusMessage) -> bool {
 | 
				
			||||||
 | 
							message.is_step(self.height.load(AtomicOrdering::SeqCst), self.round.load(AtomicOrdering::SeqCst), self.step.load(AtomicOrdering::SeqCst)) 
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Block hash including the consensus round.
 | 
				
			||||||
 | 
					fn block_hash(header: &Header) -> H256 {
 | 
				
			||||||
 | 
						header.rlp(Seal::WithSome(1)).sha3()
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
impl Engine for Tendermint {
 | 
					impl Engine for Tendermint {
 | 
				
			||||||
@ -253,60 +249,79 @@ impl Engine for Tendermint {
 | 
				
			|||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Set author to proposer and set the correct round in the seal.
 | 
						/// Set the correct round in the seal.
 | 
				
			||||||
	/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
 | 
						/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
 | 
				
			||||||
	fn on_close_block(&self, _block: &mut ExecutedBlock) {
 | 
						fn on_close_block(&self, block: &mut ExecutedBlock) {
 | 
				
			||||||
 | 
							let round = self.round.load(AtomicOrdering::SeqCst);
 | 
				
			||||||
 | 
							vec![::rlp::encode(&round).to_vec()]
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/// Round proposer switching.
 | 
				
			||||||
 | 
						fn is_sealer(&self, address: &Address) -> Option<bool> {
 | 
				
			||||||
 | 
							Some(self.is_proposer(address))
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/// Attempt to seal the block internally using all available signatures.
 | 
						/// Attempt to seal the block internally using all available signatures.
 | 
				
			||||||
	///
 | 
						///
 | 
				
			||||||
	/// None is returned if not enough signatures can be collected.
 | 
						/// None is returned if not enough signatures can be collected.
 | 
				
			||||||
	fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
 | 
						fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
 | 
				
			||||||
		if let (Some(ap), Some(step)) = (accounts, self.s.try_read()) {
 | 
							if let (Some(ap), Some(step)) = (accounts, self.step.try_read()) {
 | 
				
			||||||
			let header = block.header();
 | 
								let header = block.header();
 | 
				
			||||||
			let author = header.author();
 | 
								let author = header.author();
 | 
				
			||||||
			match *step {
 | 
								match *step {
 | 
				
			||||||
				Step::Commit(hash, ref seal) if hash == header.bare_hash() =>
 | 
									Step::Commit => {
 | 
				
			||||||
					// Commit the block using a complete signature set.
 | 
										// Commit the block using a complete signature set.
 | 
				
			||||||
					return Some(seal.clone()),
 | 
										let round = self.round.load(AtomicOrdering::SeqCst);
 | 
				
			||||||
				Step::Propose if self.is_proposer(header.author()) =>
 | 
										if let Some((proposer, votes)) = self.votes.seal_signatures(header.number() as Height, round, block_hash(header)).split_first() {
 | 
				
			||||||
 | 
											if votes.len() + 1 > self.threshold() {
 | 
				
			||||||
 | 
												return Some(vec![
 | 
				
			||||||
 | 
													::rlp::encode(&round).to_vec(),
 | 
				
			||||||
 | 
													::rlp::encode(proposer).to_vec(),
 | 
				
			||||||
 | 
													::rlp::encode(&votes).to_vec()
 | 
				
			||||||
 | 
												]);
 | 
				
			||||||
 | 
											}
 | 
				
			||||||
 | 
										}
 | 
				
			||||||
 | 
									},
 | 
				
			||||||
 | 
									Step::Propose if self.is_proposer(author) =>
 | 
				
			||||||
					// Seal block with propose signature.
 | 
										// Seal block with propose signature.
 | 
				
			||||||
					if let Some(proposal) = Vote::propose(header, &ap) {
 | 
										
 | 
				
			||||||
						return Some(vec![::rlp::encode(&proposal).to_vec(), Vec::new()])
 | 
										if let Ok(signature) = ap.sign(*author, None, block_hash(header)) {
 | 
				
			||||||
 | 
											return Some(vec![
 | 
				
			||||||
 | 
												::rlp::encode(&self.round.load(AtomicOrdering::SeqCst)).to_vec(),
 | 
				
			||||||
 | 
												::rlp::encode(&signature.into()).to_vec(),
 | 
				
			||||||
 | 
												Vec::new()
 | 
				
			||||||
 | 
											])
 | 
				
			||||||
					} else {
 | 
										} else {
 | 
				
			||||||
						trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable");
 | 
											trace!(target: "poa", "generate_seal: FAIL: accounts secret key unavailable");
 | 
				
			||||||
					},
 | 
										},
 | 
				
			||||||
				_ => {},
 | 
									_ => {},
 | 
				
			||||||
			}
 | 
								}
 | 
				
			||||||
		} else {
 | 
							} else {
 | 
				
			||||||
			trace!(target: "basicauthority", "generate_seal: FAIL: accounts not provided");
 | 
								trace!(target: "poa", "generate_seal: FAIL: accounts not provided");
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
		None
 | 
							None
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn handle_message(&self, sender: Address, signature: H520, message: UntrustedRlp) -> Result<Bytes, Error> {
 | 
						fn handle_message(&self, rlp: UntrustedRlp) -> Result<Bytes, Error> {
 | 
				
			||||||
		let message: ConsensusMessage = try!(message.as_val());
 | 
							let message: ConsensusMessage = try!(rlp.as_val());
 | 
				
			||||||
 | 
							let sender = public_to_address(&try!(recover(&message.signature.into(), &try!(rlp.at(1)).as_raw().sha3())));
 | 
				
			||||||
		if self.is_authority(&sender) {
 | 
							// TODO: Do not admit old messages.
 | 
				
			||||||
			//match message {
 | 
							if !self.is_authority(&sender) {
 | 
				
			||||||
			//		ConsensusMessage::Prevote 
 | 
								try!(Err(BlockError::InvalidSeal));
 | 
				
			||||||
			//}
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		try!(Err(EngineError::UnknownStep))
 | 
							// Check if the message affects the current step.
 | 
				
			||||||
 | 
							if self.is_current(message) {
 | 
				
			||||||
		// Check if correct round.
 | 
									match self.step.load(AtomicOrdering::SeqCst) {
 | 
				
			||||||
		//if self.r.load(AtomicOrdering::Relaxed) != try!(message.val_at(0)) {
 | 
										Step::Prevote => {
 | 
				
			||||||
		//	try!(Err(EngineError::WrongRound))
 | 
											let votes = aligned_signatures(message);
 | 
				
			||||||
		//}
 | 
											if votes.len() > self.threshold() {
 | 
				
			||||||
		// Handle according to step.
 | 
											}
 | 
				
			||||||
//		match try!(message.val_at(1)) {
 | 
										},
 | 
				
			||||||
//			0u8 if self.is_proposer(&sender) => self.propose_message(try!(message.at(2))),
 | 
										Step::Precommit => ,
 | 
				
			||||||
//			1 if self.is_authority(&sender) => self.prevote_message(sender, try!(message.at(2))),
 | 
									}
 | 
				
			||||||
//			2 if self.is_authority(&sender) => self.precommit_message(sender, signature, try!(message.at(2))),
 | 
							}
 | 
				
			||||||
//			_ => try!(Err(EngineError::UnknownStep)),
 | 
							self.votes.vote(message, sender);
 | 
				
			||||||
//		}
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
 | 
						fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
 | 
				
			||||||
@ -322,21 +337,28 @@ impl Engine for Tendermint {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
	/// Also transitions to Prevote if verifying Proposal.
 | 
						/// Also transitions to Prevote if verifying Proposal.
 | 
				
			||||||
	fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
 | 
						fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
 | 
				
			||||||
		let to_address = |b: &Vec<u8>| {
 | 
							let proposal_signature: H520 = try!(UntrustedRlp::new(header.seal()[1].as_slice()).as_val());
 | 
				
			||||||
			let sig: H520 = try!(UntrustedRlp::new(b.as_slice()).as_val());
 | 
							let proposer = public_to_address(&try!(recover(&proposal_signature.into(), &block_hash(header))));
 | 
				
			||||||
			Ok(public_to_address(&try!(recover(&sig.into(), &header.bare_hash()))))
 | 
							if !self.is_proposer(&proposer) {
 | 
				
			||||||
		};
 | 
					 | 
				
			||||||
		let authority_set = self.our_params.authorities.iter().cloned().collect();
 | 
					 | 
				
			||||||
		let seal_set = try!(header
 | 
					 | 
				
			||||||
							.seal()
 | 
					 | 
				
			||||||
							.iter()
 | 
					 | 
				
			||||||
							.map(to_address)
 | 
					 | 
				
			||||||
							.collect::<Result<HashSet<_>, Error>>());
 | 
					 | 
				
			||||||
		if seal_set.intersection(&authority_set).count() <= self.threshold() {
 | 
					 | 
				
			||||||
			try!(Err(BlockError::InvalidSeal))
 | 
								try!(Err(BlockError::InvalidSeal))
 | 
				
			||||||
		} else {
 | 
					 | 
				
			||||||
			Ok(())
 | 
					 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							let proposal = ConsensusMessage {
 | 
				
			||||||
 | 
								signature: proposal_signature,
 | 
				
			||||||
 | 
								height: header.number() as usize,
 | 
				
			||||||
 | 
								round: try!(UntrustedRlp::new(header.seal()[0].as_slice()).as_val()),
 | 
				
			||||||
 | 
								step: Step::Propose,
 | 
				
			||||||
 | 
								block_hash: Some(block_hash(header))
 | 
				
			||||||
 | 
							};
 | 
				
			||||||
 | 
							self.votes.vote(proposal, proposer);
 | 
				
			||||||
 | 
							let votes_rlp = UntrustedRlp::new(&header.seal()[2]);
 | 
				
			||||||
 | 
							for rlp in votes_rlp.iter() {
 | 
				
			||||||
 | 
								let sig: H520 = try!(rlp.as_val());
 | 
				
			||||||
 | 
								let address = public_to_address(&try!(recover(&sig.into(), &block_hash(header))));
 | 
				
			||||||
 | 
								if !self.our_params.authorities.contains(a) {
 | 
				
			||||||
 | 
									try!(Err(BlockError::InvalidSeal))
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							Ok(())
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
 | 
						fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
 | 
				
			||||||
@ -368,7 +390,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 {
 | 
				
			||||||
		new_header.seal().get(1).expect("Tendermint seal should have two elements.").len() > best_header.seal().get(1).expect("Tendermint seal should have two elements.").len()
 | 
							let new_signatures = new_header.seal().get(2).expect("Tendermint seal should have three elements.").len();
 | 
				
			||||||
 | 
							let best_signatures = best_header.seal().get(2).expect("Tendermint seal should have three elements.").len();
 | 
				
			||||||
 | 
							new_signatures > best_signatures
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -377,7 +401,7 @@ mod tests {
 | 
				
			|||||||
	use std::thread::sleep;
 | 
						use std::thread::sleep;
 | 
				
			||||||
	use std::time::{Duration};
 | 
						use std::time::{Duration};
 | 
				
			||||||
	use util::*;
 | 
						use util::*;
 | 
				
			||||||
	use rlp::{UntrustedRlp, RlpStream, Stream, View, encode};
 | 
						use rlp::{UntrustedRlp, RlpStream, Stream, View};
 | 
				
			||||||
	use block::*;
 | 
						use block::*;
 | 
				
			||||||
	use error::{Error, BlockError};
 | 
						use error::{Error, BlockError};
 | 
				
			||||||
	use header::Header;
 | 
						use header::Header;
 | 
				
			||||||
@ -416,11 +440,11 @@ mod tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		let v0 = tap.insert_account("0".sha3(), "0").unwrap();
 | 
							let v0 = tap.insert_account("0".sha3(), "0").unwrap();
 | 
				
			||||||
		let sig0 = tap.sign(v0, Some("0".into()), header.bare_hash()).unwrap();
 | 
							let sig0 = tap.sign(v0, Some("0".into()), header.bare_hash()).unwrap();
 | 
				
			||||||
		seal.push(encode(&(&*sig0 as &[u8])).to_vec());
 | 
							seal.push(::rlp::encode(&(&*sig0 as &[u8])).to_vec());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		let v1 = tap.insert_account("1".sha3(), "1").unwrap();
 | 
							let v1 = tap.insert_account("1".sha3(), "1").unwrap();
 | 
				
			||||||
		let sig1 = tap.sign(v1, Some("1".into()), header.bare_hash()).unwrap();
 | 
							let sig1 = tap.sign(v1, Some("1".into()), header.bare_hash()).unwrap();
 | 
				
			||||||
		seal.push(encode(&(&*sig1 as &[u8])).to_vec());
 | 
							seal.push(::rlp::encode(&(&*sig1 as &[u8])).to_vec());
 | 
				
			||||||
		seal
 | 
							seal
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -475,7 +499,7 @@ mod tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		let v1 = tap.insert_account("0".sha3(), "0").unwrap();
 | 
							let v1 = tap.insert_account("0".sha3(), "0").unwrap();
 | 
				
			||||||
		let sig1 = tap.sign(v1, Some("0".into()), header.bare_hash()).unwrap();
 | 
							let sig1 = tap.sign(v1, Some("0".into()), header.bare_hash()).unwrap();
 | 
				
			||||||
		seal.push(encode(&(&*sig1 as &[u8])).to_vec());
 | 
							seal.push(::rlp::encode(&(&*sig1 as &[u8])).to_vec());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		header.set_seal(seal.clone());
 | 
							header.set_seal(seal.clone());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -484,7 +508,7 @@ mod tests {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
		let v2 = tap.insert_account("101".sha3(), "101").unwrap();
 | 
							let v2 = tap.insert_account("101".sha3(), "101").unwrap();
 | 
				
			||||||
		let sig2 = tap.sign(v2, Some("101".into()), header.bare_hash()).unwrap();
 | 
							let sig2 = tap.sign(v2, Some("101".into()), header.bare_hash()).unwrap();
 | 
				
			||||||
		seal.push(encode(&(&*sig2 as &[u8])).to_vec());
 | 
							seal.push(::rlp::encode(&(&*sig2 as &[u8])).to_vec());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		header.set_seal(seal);
 | 
							header.set_seal(seal);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -144,7 +144,7 @@ impl Spec {
 | 
				
			|||||||
			ethjson::spec::Engine::InstantSeal => Arc::new(InstantSeal::new(params, builtins)),
 | 
								ethjson::spec::Engine::InstantSeal => Arc::new(InstantSeal::new(params, builtins)),
 | 
				
			||||||
			ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(params, From::from(ethash.params), builtins)),
 | 
								ethjson::spec::Engine::Ethash(ethash) => Arc::new(ethereum::Ethash::new(params, From::from(ethash.params), builtins)),
 | 
				
			||||||
			ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)),
 | 
								ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(params, From::from(basic_authority.params), builtins)),
 | 
				
			||||||
			ethjson::spec::Engine::Tendermint(tendermint) => Tendermint::new(params, From::from(tendermint.params), builtins),
 | 
								ethjson::spec::Engine::Tendermint(tendermint) => Tendermint::new(params, From::from(tendermint.params), builtins).expect("Failed to start the Tendermint consensus engine."),
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user