2016-08-23 12:58:40 +02:00
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
//! Tendermint BFT consensus engine with round robin proof-of-authority.
2016-09-29 15:44:42 +02:00
mod message ;
mod timeout ;
2016-09-29 16:32:49 +02:00
mod params ;
2016-10-05 15:33:07 +02:00
mod vote ;
2016-10-11 19:37:31 +02:00
mod vote_collector ;
2016-09-29 15:44:42 +02:00
2016-08-25 19:22:10 +02:00
use std ::sync ::atomic ::{ AtomicUsize , Ordering as AtomicOrdering } ;
2016-08-23 12:58:40 +02:00
use common ::* ;
2016-09-05 18:16:09 +02:00
use rlp ::{ UntrustedRlp , View , encode } ;
2016-09-06 12:26:06 +02:00
use ethkey ::{ recover , public_to_address } ;
2016-08-23 12:58:40 +02:00
use account_provider ::AccountProvider ;
use block ::* ;
use spec ::CommonParams ;
2016-08-24 15:55:47 +02:00
use engines ::{ Engine , EngineError , ProposeCollect } ;
2016-10-05 15:33:07 +02:00
use blockchain ::extras ::BlockDetails ;
2016-08-23 12:58:40 +02:00
use evm ::Schedule ;
2016-09-29 15:44:42 +02:00
use io ::IoService ;
use self ::message ::ConsensusMessage ;
2016-09-29 16:32:49 +02:00
use self ::timeout ::{ TimerHandler , NextStep } ;
use self ::params ::TendermintParams ;
2016-10-05 15:33:07 +02:00
use self ::vote ::Vote ;
2016-08-31 18:18:02 +02:00
2016-08-23 12:58:40 +02:00
#[ derive(Debug) ]
enum Step {
Propose ,
Prevote ( ProposeCollect ) ,
2016-08-29 14:32:37 +02:00
/// Precommit step storing the precommit vote and accumulating seal.
2016-10-05 15:33:07 +02:00
Precommit ( ProposeCollect , Signatures ) ,
2016-08-29 14:32:37 +02:00
/// Commit step storing a complete valid seal.
2016-10-05 15:33:07 +02:00
Commit ( BlockHash , Signatures )
2016-08-23 12:58:40 +02:00
}
2016-09-29 15:44:42 +02:00
pub type Height = usize ;
pub type Round = usize ;
pub type BlockHash = H256 ;
pub type AtomicMs = AtomicUsize ;
2016-10-05 15:33:07 +02:00
type Signatures = Vec < Bytes > ;
2016-09-29 15:44:42 +02:00
2016-08-23 12:58:40 +02:00
/// Engine using `Tendermint` consensus algorithm, suitable for EVM chain.
pub struct Tendermint {
params : CommonParams ,
our_params : TendermintParams ,
builtins : BTreeMap < Address , Builtin > ,
2016-09-29 15:44:42 +02:00
timeout_service : IoService < NextStep > ,
2016-10-05 15:33:07 +02:00
/// Address to be used as authority.
authority : RwLock < Address > ,
2016-09-05 17:51:29 +02:00
/// Consensus round.
2016-09-07 16:25:42 +02:00
r : AtomicUsize ,
2016-09-05 17:51:29 +02:00
/// Consensus step.
s : RwLock < Step > ,
/// Current step timeout in ms.
timeout : AtomicMs ,
/// Used to swith proposer.
proposer_nonce : AtomicUsize ,
}
2016-08-23 12:58:40 +02:00
impl Tendermint {
/// Create a new instance of Tendermint engine
2016-09-05 17:51:29 +02:00
pub fn new ( params : CommonParams , our_params : TendermintParams , builtins : BTreeMap < Address , Builtin > ) -> Arc < Self > {
let engine = Arc ::new (
Tendermint {
params : params ,
2016-09-29 17:57:52 +02:00
timeout : AtomicUsize ::new ( our_params . timeouts . propose ) ,
2016-09-05 17:51:29 +02:00
our_params : our_params ,
builtins : builtins ,
2016-09-29 15:44:42 +02:00
timeout_service : IoService ::< NextStep > ::start ( ) . expect ( " Error creating engine timeout service " ) ,
2016-10-05 15:33:07 +02:00
authority : RwLock ::new ( Address ::default ( ) ) ,
2016-09-07 16:25:42 +02:00
r : AtomicUsize ::new ( 0 ) ,
2016-09-05 17:51:29 +02:00
s : RwLock ::new ( Step ::Propose ) ,
proposer_nonce : AtomicUsize ::new ( 0 )
} ) ;
2016-09-29 15:44:42 +02:00
let handler = TimerHandler ::new ( Arc ::downgrade ( & engine ) ) ;
2016-09-05 17:51:29 +02:00
engine . timeout_service . register_handler ( Arc ::new ( handler ) ) . expect ( " Error creating engine timeout service " ) ;
engine
2016-08-23 12:58:40 +02:00
}
2016-10-05 15:33:07 +02:00
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 {
2016-08-23 12:58:40 +02:00
let ref p = self . our_params ;
2016-10-05 15:33:07 +02:00
p . authorities . get ( proposer_nonce % p . authority_n ) . unwrap ( )
2016-08-23 12:58:40 +02:00
}
2016-08-23 17:19:23 +02:00
2016-10-05 15:33:07 +02:00
fn is_nonce_proposer ( & self , proposer_nonce : usize , address : & Address ) -> bool {
self . nonce_proposer ( proposer_nonce ) = = address
2016-08-26 19:27:50 +02:00
}
2016-10-05 15:33:07 +02:00
fn is_authority ( & self , address : & Address ) -> bool {
self . our_params . authorities . contains ( address )
2016-08-26 19:27:50 +02:00
}
2016-09-29 15:44:42 +02:00
fn new_vote ( & self , proposal : BlockHash ) -> ProposeCollect {
2016-08-26 19:27:50 +02:00
ProposeCollect ::new ( proposal ,
2016-10-05 15:33:07 +02:00
self . our_params . authorities . iter ( ) . cloned ( ) . collect ( ) ,
2016-08-26 19:27:50 +02:00
self . threshold ( ) )
}
2016-09-05 17:51:29 +02:00
fn to_step ( & self , step : Step ) {
let mut guard = self . s . try_write ( ) . unwrap ( ) ;
* guard = step ;
}
2016-08-31 18:18:02 +02:00
fn to_propose ( & self ) {
2016-09-05 17:51:29 +02:00
trace! ( target : " tendermint " , " step: entering propose " ) ;
println! ( " step: entering propose " ) ;
self . proposer_nonce . fetch_add ( 1 , AtomicOrdering ::Relaxed ) ;
self . to_step ( Step ::Propose ) ;
2016-08-31 18:18:02 +02:00
}
2016-08-24 15:55:47 +02:00
fn propose_message ( & self , message : UntrustedRlp ) -> Result < Bytes , Error > {
2016-08-26 19:27:50 +02:00
// Check if message is for correct step.
2016-09-05 17:51:29 +02:00
match * self . s . try_read ( ) . unwrap ( ) {
2016-08-24 11:58:49 +02:00
Step ::Propose = > ( ) ,
2016-08-24 15:55:47 +02:00
_ = > try ! ( Err ( EngineError ::WrongStep ) ) ,
2016-08-24 11:58:49 +02:00
}
2016-08-25 19:22:10 +02:00
let proposal = try ! ( message . as_val ( ) ) ;
2016-08-31 18:18:02 +02:00
self . to_prevote ( proposal ) ;
Ok ( message . as_raw ( ) . to_vec ( ) )
}
2016-09-29 15:44:42 +02:00
fn to_prevote ( & self , proposal : BlockHash ) {
2016-09-05 17:51:29 +02:00
trace! ( target : " tendermint " , " step: entering prevote " ) ;
println! ( " step: entering prevote " ) ;
2016-08-26 19:27:50 +02:00
// Proceed to the prevote step.
2016-09-05 17:51:29 +02:00
self . to_step ( Step ::Prevote ( self . new_vote ( proposal ) ) ) ;
2016-08-24 11:58:49 +02:00
}
2016-08-24 15:55:47 +02:00
fn prevote_message ( & self , sender : Address , message : UntrustedRlp ) -> Result < Bytes , Error > {
2016-08-26 19:27:50 +02:00
// Check if message is for correct step.
2016-09-07 16:25:42 +02:00
let hash = match * self . s . try_write ( ) . unwrap ( ) {
2016-08-26 19:27:50 +02:00
Step ::Prevote ( ref mut vote ) = > {
// Vote if message is about the right block.
if vote . hash = = try ! ( message . as_val ( ) ) {
vote . vote ( sender ) ;
// Move to next step is prevote is won.
2016-09-05 17:51:29 +02:00
if vote . is_won ( ) {
2016-09-07 16:25:42 +02:00
// If won assign a hash used for precommit.
vote . hash . clone ( )
} else {
// Just propoagate the message if not won yet.
return Ok ( message . as_raw ( ) . to_vec ( ) ) ;
2016-09-05 17:51:29 +02:00
}
2016-08-26 19:27:50 +02:00
} else {
try ! ( Err ( EngineError ::WrongVote ) )
}
} ,
_ = > try ! ( Err ( EngineError ::WrongStep ) ) ,
2016-09-07 16:25:42 +02:00
} ;
self . to_precommit ( hash ) ;
Ok ( message . as_raw ( ) . to_vec ( ) )
2016-08-26 19:27:50 +02:00
}
2016-09-29 15:44:42 +02:00
fn to_precommit ( & self , proposal : BlockHash ) {
2016-09-05 17:51:29 +02:00
trace! ( target : " tendermint " , " step: entering precommit " ) ;
println! ( " step: entering precommit " ) ;
self . to_step ( Step ::Precommit ( self . new_vote ( proposal ) , Vec ::new ( ) ) ) ;
2016-08-31 18:18:02 +02:00
}
2016-08-29 12:09:51 +02:00
fn precommit_message ( & self , sender : Address , signature : H520 , message : UntrustedRlp ) -> Result < Bytes , Error > {
2016-08-26 19:27:50 +02:00
// Check if message is for correct step.
2016-09-05 17:51:29 +02:00
match * self . s . try_write ( ) . unwrap ( ) {
2016-08-29 12:09:51 +02:00
Step ::Precommit ( ref mut vote , ref mut seal ) = > {
2016-08-26 19:27:50 +02:00
// Vote and accumulate seal if message is about the right block.
if vote . hash = = try ! ( message . as_val ( ) ) {
2016-08-29 12:09:51 +02:00
if vote . vote ( sender ) { seal . push ( encode ( & signature ) . to_vec ( ) ) ; }
2016-08-26 19:27:50 +02:00
// Commit if precommit is won.
2016-09-07 16:25:42 +02:00
if vote . is_won ( ) { self . to_commit ( vote . hash . clone ( ) , seal . clone ( ) ) ; }
2016-08-31 18:18:02 +02:00
Ok ( message . as_raw ( ) . to_vec ( ) )
2016-08-26 19:27:50 +02:00
} else {
try ! ( Err ( EngineError ::WrongVote ) )
}
} ,
2016-08-26 13:16:56 +02:00
_ = > try ! ( Err ( EngineError ::WrongStep ) ) ,
}
2016-08-23 17:19:23 +02:00
}
2016-08-24 11:58:49 +02:00
2016-09-07 16:25:42 +02:00
/// Move to commit step, when valid block is known and being distributed.
pub fn to_commit ( & self , block_hash : H256 , seal : Vec < Bytes > ) {
2016-09-05 17:51:29 +02:00
trace! ( target : " tendermint " , " step: entering commit " ) ;
println! ( " step: entering commit " ) ;
2016-09-07 16:25:42 +02:00
self . to_step ( Step ::Commit ( block_hash , seal ) ) ;
2016-08-31 18:18:02 +02:00
}
2016-08-24 11:58:49 +02:00
fn threshold ( & self ) -> usize {
2016-10-05 15:33:07 +02:00
self . our_params . authority_n * 2 / 3
2016-08-24 11:58:49 +02:00
}
2016-09-05 17:51:29 +02:00
fn next_timeout ( & self ) -> u64 {
self . timeout . load ( AtomicOrdering ::Relaxed ) as u64
}
2016-08-23 12:58:40 +02:00
}
impl Engine for Tendermint {
fn name ( & self ) -> & str { " Tendermint " }
fn version ( & self ) -> SemanticVersion { SemanticVersion ::new ( 1 , 0 , 0 ) }
2016-10-05 15:33:07 +02:00
/// (consensus round, proposal signature, authority signatures)
fn seal_fields ( & self ) -> usize { 3 }
2016-08-23 12:58:40 +02:00
fn params ( & self ) -> & CommonParams { & self . params }
fn builtins ( & self ) -> & BTreeMap < Address , Builtin > { & self . builtins }
/// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info ( & self , _header : & Header ) -> HashMap < String , String > { hash_map! [ " signature " . to_owned ( ) = > " TODO " . to_owned ( ) ] }
fn schedule ( & self , _env_info : & EnvInfo ) -> Schedule {
Schedule ::new_homestead ( )
}
fn populate_from_parent ( & self , header : & mut Header , parent : & Header , gas_floor_target : U256 , _gas_ceil_target : U256 ) {
2016-08-31 18:43:24 +02:00
header . set_difficulty ( parent . difficulty ( ) . clone ( ) ) ;
header . set_gas_limit ( {
let gas_limit = parent . gas_limit ( ) . clone ( ) ;
2016-08-23 12:58:40 +02:00
let bound_divisor = self . our_params . gas_limit_bound_divisor ;
if gas_limit < gas_floor_target {
min ( gas_floor_target , gas_limit + gas_limit / bound_divisor - 1. into ( ) )
} else {
max ( gas_floor_target , gas_limit - gas_limit / bound_divisor + 1. into ( ) )
}
2016-08-31 18:43:24 +02:00
} ) ;
2016-08-23 12:58:40 +02:00
}
2016-10-05 15:33:07 +02:00
/// Get the address to be used as authority.
fn on_new_block ( & self , block : & mut ExecutedBlock ) {
if let Some ( mut authority ) = self . authority . try_write ( ) {
* authority = * block . header ( ) . author ( )
}
}
2016-10-11 19:37:31 +02:00
/// Set author to proposer and set the correct round in the seal.
2016-08-23 12:58:40 +02:00
/// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current).
2016-10-11 19:37:31 +02:00
fn on_close_block ( & self , _block : & mut ExecutedBlock ) {
}
2016-08-23 12:58:40 +02:00
/// Attempt to seal the block internally using all available signatures.
///
/// None is returned if not enough signatures can be collected.
2016-10-05 15:33:07 +02:00
fn generate_seal ( & self , block : & ExecutedBlock , accounts : Option < & AccountProvider > ) -> Option < Vec < Bytes > > {
if let ( Some ( ap ) , Some ( step ) ) = ( accounts , self . s . try_read ( ) ) {
let header = block . header ( ) ;
let author = header . author ( ) ;
match * step {
Step ::Commit ( hash , ref seal ) if hash = = header . bare_hash ( ) = >
// Commit the block using a complete signature set.
return Some ( seal . clone ( ) ) ,
Step ::Propose if self . is_proposer ( header . author ( ) ) = >
// Seal block with propose signature.
if let Some ( proposal ) = Vote ::propose ( header , & ap ) {
return Some ( vec! [ ::rlp ::encode ( & proposal ) . to_vec ( ) , Vec ::new ( ) ] )
} else {
trace! ( target : " basicauthority " , " generate_seal: FAIL: accounts secret key unavailable " ) ;
} ,
_ = > { } ,
}
} else {
trace! ( target : " basicauthority " , " generate_seal: FAIL: accounts not provided " ) ;
}
None
2016-08-23 12:58:40 +02:00
}
2016-08-29 12:09:51 +02:00
fn handle_message ( & self , sender : Address , signature : H520 , message : UntrustedRlp ) -> Result < Bytes , Error > {
2016-10-05 15:33:07 +02:00
let message : ConsensusMessage = try ! ( message . as_val ( ) ) ;
2016-10-11 19:37:31 +02:00
if self . is_authority ( & sender ) {
//match message {
// ConsensusMessage::Prevote
//}
}
try ! ( Err ( EngineError ::UnknownStep ) )
2016-10-05 15:33:07 +02:00
2016-08-26 19:27:50 +02:00
// Check if correct round.
2016-10-05 15:33:07 +02:00
//if self.r.load(AtomicOrdering::Relaxed) != try!(message.val_at(0)) {
// try!(Err(EngineError::WrongRound))
//}
2016-08-26 19:27:50 +02:00
// Handle according to step.
2016-10-05 15:33:07 +02:00
// match try!(message.val_at(1)) {
// 0u8 if self.is_proposer(&sender) => self.propose_message(try!(message.at(2))),
// 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)),
// }
2016-08-23 12:58:40 +02:00
}
2016-09-06 12:26:06 +02:00
fn verify_block_basic ( & self , header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2016-09-30 13:22:46 +02:00
let seal_length = header . seal ( ) . len ( ) ;
if seal_length = = self . seal_fields ( ) {
Ok ( ( ) )
} else {
2016-09-06 12:26:06 +02:00
Err ( From ::from ( BlockError ::InvalidSealArity (
2016-09-30 13:22:46 +02:00
Mismatch { expected : self . seal_fields ( ) , found : seal_length }
2016-09-06 12:26:06 +02:00
) ) )
2016-08-23 12:58:40 +02:00
}
}
2016-10-05 15:33:07 +02:00
/// Also transitions to Prevote if verifying Proposal.
2016-09-06 12:26:06 +02:00
fn verify_block_unordered ( & self , header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
let to_address = | b : & Vec < u8 > | {
let sig : H520 = try ! ( UntrustedRlp ::new ( b . as_slice ( ) ) . as_val ( ) ) ;
Ok ( public_to_address ( & try ! ( recover ( & sig . into ( ) , & header . bare_hash ( ) ) ) ) )
} ;
2016-10-05 15:33:07 +02:00
let authority_set = self . our_params . authorities . iter ( ) . cloned ( ) . collect ( ) ;
2016-09-06 12:26:06 +02:00
let seal_set = try ! ( header
. seal ( )
. iter ( )
. map ( to_address )
. collect ::< Result < HashSet < _ > , Error > > ( ) ) ;
2016-10-05 15:33:07 +02:00
if seal_set . intersection ( & authority_set ) . count ( ) < = self . threshold ( ) {
2016-09-06 12:26:06 +02:00
try ! ( Err ( BlockError ::InvalidSeal ) )
2016-09-07 16:25:42 +02:00
} else {
Ok ( ( ) )
2016-09-06 12:26:06 +02:00
}
2016-08-23 12:58:40 +02:00
}
2016-09-06 12:26:06 +02:00
fn verify_block_family ( & self , header : & Header , parent : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2016-08-23 12:58:40 +02:00
// we should not calculate difficulty for genesis blocks
if header . number ( ) = = 0 {
return Err ( From ::from ( BlockError ::RidiculousNumber ( OutOfBounds { min : Some ( 1 ) , max : None , found : header . number ( ) } ) ) ) ;
}
// Check difficulty is correct given the two timestamps.
if header . difficulty ( ) ! = parent . difficulty ( ) {
return Err ( From ::from ( BlockError ::InvalidDifficulty ( Mismatch { expected : * parent . difficulty ( ) , found : * header . difficulty ( ) } ) ) )
}
let gas_limit_divisor = self . our_params . gas_limit_bound_divisor ;
2016-08-31 18:43:24 +02:00
let min_gas = parent . gas_limit ( ) . clone ( ) - parent . gas_limit ( ) . clone ( ) / gas_limit_divisor ;
let max_gas = parent . gas_limit ( ) . clone ( ) + parent . gas_limit ( ) . clone ( ) / gas_limit_divisor ;
if header . gas_limit ( ) < = & min_gas | | header . gas_limit ( ) > = & max_gas {
return Err ( From ::from ( BlockError ::InvalidGasLimit ( OutOfBounds { min : Some ( min_gas ) , max : Some ( max_gas ) , found : header . gas_limit ( ) . clone ( ) } ) ) ) ;
2016-08-23 12:58:40 +02:00
}
Ok ( ( ) )
}
2016-09-06 12:26:06 +02:00
fn verify_transaction_basic ( & self , t : & SignedTransaction , _header : & Header ) -> Result < ( ) , Error > {
2016-08-23 12:58:40 +02:00
try ! ( t . check_low_s ( ) ) ;
Ok ( ( ) )
}
fn verify_transaction ( & self , t : & SignedTransaction , _header : & Header ) -> Result < ( ) , Error > {
t . sender ( ) . map ( | _ | ( ) ) // Perform EC recovery and cache sender
}
2016-10-05 15:33:07 +02:00
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 ( )
}
2016-08-23 12:58:40 +02:00
}
#[ cfg(test) ]
mod tests {
use common ::* ;
2016-08-31 18:18:02 +02:00
use std ::thread ::sleep ;
2016-09-05 17:51:29 +02:00
use std ::time ::{ Duration } ;
2016-09-07 16:25:42 +02:00
use rlp ::{ UntrustedRlp , RlpStream , Stream , View , encode } ;
2016-08-23 12:58:40 +02:00
use block ::* ;
use tests ::helpers ::* ;
use account_provider ::AccountProvider ;
use spec ::Spec ;
2016-09-07 16:25:42 +02:00
use engines ::{ Engine , EngineError } ;
2016-09-29 17:57:52 +02:00
use super ::Tendermint ;
use super ::params ::TendermintParams ;
2016-08-23 12:58:40 +02:00
2016-09-07 16:25:42 +02:00
fn propose_default ( engine : & Arc < Engine > , round : u8 , proposer : Address ) -> Result < Bytes , Error > {
2016-08-26 19:27:50 +02:00
let mut s = RlpStream ::new_list ( 3 ) ;
let header = Header ::default ( ) ;
2016-09-07 16:25:42 +02:00
s . append ( & round ) . append ( & 0 u8 ) . append ( & header . bare_hash ( ) ) ;
2016-08-26 19:27:50 +02:00
let drain = s . out ( ) ;
let propose_rlp = UntrustedRlp ::new ( & drain ) ;
2016-08-29 12:09:51 +02:00
engine . handle_message ( proposer , H520 ::default ( ) , propose_rlp )
2016-08-26 19:27:50 +02:00
}
2016-09-07 16:25:42 +02:00
fn vote_default ( engine : & Arc < Engine > , round : u8 , voter : Address ) -> Result < Bytes , Error > {
let mut s = RlpStream ::new_list ( 3 ) ;
let header = Header ::default ( ) ;
s . append ( & round ) . append ( & 1 u8 ) . append ( & header . bare_hash ( ) ) ;
let drain = s . out ( ) ;
let vote_rlp = UntrustedRlp ::new ( & drain ) ;
engine . handle_message ( voter , H520 ::default ( ) , vote_rlp )
}
fn good_seal ( header : & Header ) -> Vec < Bytes > {
let tap = AccountProvider ::transient_provider ( ) ;
let mut seal = Vec ::new ( ) ;
let v0 = tap . insert_account ( " 0 " . sha3 ( ) , " 0 " ) . unwrap ( ) ;
let sig0 = tap . sign_with_password ( v0 , " 0 " . into ( ) , header . bare_hash ( ) ) . unwrap ( ) ;
seal . push ( encode ( & ( & * sig0 as & [ u8 ] ) ) . to_vec ( ) ) ;
let v1 = tap . insert_account ( " 1 " . sha3 ( ) , " 1 " ) . unwrap ( ) ;
let sig1 = tap . sign_with_password ( v1 , " 1 " . into ( ) , header . bare_hash ( ) ) . unwrap ( ) ;
seal . push ( encode ( & ( & * sig1 as & [ u8 ] ) ) . to_vec ( ) ) ;
seal
}
2016-09-05 17:51:29 +02:00
fn default_block ( ) -> Vec < u8 > {
vec! [ 160 , 39 , 191 , 179 , 126 , 80 , 124 , 233 , 13 , 161 , 65 , 48 , 114 , 4 , 177 , 198 , 186 , 36 , 25 , 67 , 128 , 97 , 53 , 144 , 172 , 80 , 202 , 75 , 29 , 113 , 152 , 255 , 101 ]
}
2016-08-23 12:58:40 +02:00
#[ test ]
fn has_valid_metadata ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-08-23 12:58:40 +02:00
assert! ( ! engine . name ( ) . is_empty ( ) ) ;
assert! ( engine . version ( ) . major > = 1 ) ;
}
#[ test ]
fn can_return_schedule ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-08-23 12:58:40 +02:00
let schedule = engine . schedule ( & EnvInfo {
number : 10000000 ,
author : 0. into ( ) ,
timestamp : 0 ,
difficulty : 0. into ( ) ,
last_hashes : Arc ::new ( vec! [ ] ) ,
gas_used : 0. into ( ) ,
gas_limit : 0. into ( ) ,
} ) ;
assert! ( schedule . stack_limit > 0 ) ;
}
#[ test ]
2016-09-07 16:25:42 +02:00
fn verification_fails_on_short_seal ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-08-23 12:58:40 +02:00
let header : Header = Header ::default ( ) ;
let verify_result = engine . verify_block_basic ( & header , None ) ;
match verify_result {
Err ( Error ::Block ( BlockError ::InvalidSealArity ( _ ) ) ) = > { } ,
Err ( _ ) = > { panic! ( " should be block seal-arity mismatch error (got {:?} ) " , verify_result ) ; } ,
_ = > { panic! ( " Should be error, got Ok " ) ; } ,
}
}
#[ test ]
2016-09-07 16:25:42 +02:00
fn verification_fails_on_wrong_signatures ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-09-07 16:25:42 +02:00
let mut header = Header ::default ( ) ;
2016-08-23 12:58:40 +02:00
let tap = AccountProvider ::transient_provider ( ) ;
2016-09-07 16:25:42 +02:00
let mut seal = Vec ::new ( ) ;
let v1 = tap . insert_account ( " 0 " . sha3 ( ) , " 0 " ) . unwrap ( ) ;
let sig1 = tap . sign_with_password ( v1 , " 0 " . into ( ) , header . bare_hash ( ) ) . unwrap ( ) ;
seal . push ( encode ( & ( & * sig1 as & [ u8 ] ) ) . to_vec ( ) ) ;
header . set_seal ( seal . clone ( ) ) ;
// Not enough signatures.
assert! ( engine . verify_block_basic ( & header , None ) . is_err ( ) ) ;
let v2 = tap . insert_account ( " 101 " . sha3 ( ) , " 101 " ) . unwrap ( ) ;
let sig2 = tap . sign_with_password ( v2 , " 101 " . into ( ) , header . bare_hash ( ) ) . unwrap ( ) ;
seal . push ( encode ( & ( & * sig2 as & [ u8 ] ) ) . to_vec ( ) ) ;
header . set_seal ( seal ) ;
// Enough signatures.
assert! ( engine . verify_block_basic ( & header , None ) . is_ok ( ) ) ;
let verify_result = engine . verify_block_unordered ( & header , None ) ;
// But wrong signatures.
match verify_result {
Err ( Error ::Block ( BlockError ::InvalidSeal ) ) = > ( ) ,
Err ( _ ) = > panic! ( " should be block seal-arity mismatch error (got {:?} ) " , verify_result ) ,
_ = > panic! ( " Should be error, got Ok " ) ,
}
}
#[ test ]
fn seal_with_enough_signatures_is_ok ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-09-07 16:25:42 +02:00
let mut header = Header ::default ( ) ;
let seal = good_seal ( & header ) ;
header . set_seal ( seal ) ;
// Enough signatures.
assert! ( engine . verify_block_basic ( & header , None ) . is_ok ( ) ) ;
// And they are ok.
assert! ( engine . verify_block_unordered ( & header , None ) . is_ok ( ) ) ;
}
#[ test ]
fn can_generate_seal ( ) {
2016-09-29 17:57:52 +02:00
let spec = Spec ::new_test_tendermint ( ) ;
2016-09-07 16:25:42 +02:00
let ref engine = * spec . engine ;
let tender = Tendermint ::new ( engine . params ( ) . clone ( ) , TendermintParams ::default ( ) , BTreeMap ::new ( ) ) ;
2016-08-23 12:58:40 +02:00
let genesis_header = spec . genesis_header ( ) ;
2016-10-05 15:33:07 +02:00
let mut db_result = get_temp_state_db ( ) ;
2016-08-23 12:58:40 +02:00
let mut db = db_result . take ( ) ;
2016-10-05 15:33:07 +02:00
spec . ensure_db_good ( & mut db ) . unwrap ( ) ;
2016-08-23 12:58:40 +02:00
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
2016-09-07 16:25:42 +02:00
let b = OpenBlock ::new ( engine , Default ::default ( ) , false , db , & genesis_header , last_hashes , Address ::default ( ) , ( 3141562. into ( ) , 31415620. into ( ) ) , vec! [ ] ) . unwrap ( ) ;
2016-08-23 12:58:40 +02:00
let b = b . close_and_lock ( ) ;
2016-09-07 16:25:42 +02:00
tender . to_commit ( b . hash ( ) , good_seal ( & b . header ( ) ) ) ;
let seal = tender . generate_seal ( b . block ( ) , None ) . unwrap ( ) ;
2016-08-23 12:58:40 +02:00
assert! ( b . try_seal ( engine , seal ) . is_ok ( ) ) ;
}
2016-08-24 15:55:47 +02:00
#[ test ]
2016-08-25 19:22:10 +02:00
fn propose_step ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-08-24 15:55:47 +02:00
let tap = AccountProvider ::transient_provider ( ) ;
2016-09-07 16:25:42 +02:00
let r = 0 ;
2016-08-25 19:22:10 +02:00
2016-10-05 15:33:07 +02:00
let not_authority_addr = tap . insert_account ( " 101 " . sha3 ( ) , " 101 " ) . unwrap ( ) ;
assert! ( propose_default ( & engine , r , not_authority_addr ) . is_err ( ) ) ;
2016-08-25 19:22:10 +02:00
let not_proposer_addr = tap . insert_account ( " 0 " . sha3 ( ) , " 0 " ) . unwrap ( ) ;
2016-09-07 16:25:42 +02:00
assert! ( propose_default ( & engine , r , not_proposer_addr ) . is_err ( ) ) ;
2016-08-25 19:22:10 +02:00
let proposer_addr = tap . insert_account ( " 1 " . sha3 ( ) , " 1 " ) . unwrap ( ) ;
2016-09-07 16:25:42 +02:00
assert_eq! ( default_block ( ) , propose_default ( & engine , r , proposer_addr ) . unwrap ( ) ) ;
2016-08-26 19:27:50 +02:00
2016-09-07 16:25:42 +02:00
assert! ( propose_default ( & engine , r , proposer_addr ) . is_err ( ) ) ;
assert! ( propose_default ( & engine , r , not_proposer_addr ) . is_err ( ) ) ;
2016-08-26 19:27:50 +02:00
}
2016-08-25 19:22:10 +02:00
2016-08-26 19:27:50 +02:00
#[ test ]
2016-09-05 17:51:29 +02:00
fn proposer_switching ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-09-05 17:51:29 +02:00
let tap = AccountProvider ::transient_provider ( ) ;
2016-09-07 16:25:42 +02:00
// Currently not a proposer.
2016-09-05 17:51:29 +02:00
let not_proposer_addr = tap . insert_account ( " 0 " . sha3 ( ) , " 0 " ) . unwrap ( ) ;
2016-09-07 16:25:42 +02:00
assert! ( propose_default ( & engine , 0 , not_proposer_addr ) . is_err ( ) ) ;
2016-09-05 17:51:29 +02:00
2016-09-07 16:25:42 +02:00
sleep ( Duration ::from_millis ( TendermintParams ::default ( ) . timeouts . propose as u64 ) ) ;
2016-09-05 17:51:29 +02:00
2016-09-07 16:25:42 +02:00
// Becomes proposer after timeout.
assert_eq! ( default_block ( ) , propose_default ( & engine , 0 , not_proposer_addr ) . unwrap ( ) ) ;
2016-08-24 15:55:47 +02:00
}
2016-08-23 12:58:40 +02:00
#[ test ]
2016-09-05 17:51:29 +02:00
fn prevote_step ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-09-07 16:25:42 +02:00
let tap = AccountProvider ::transient_provider ( ) ;
let r = 0 ;
let v0 = tap . insert_account ( " 0 " . sha3 ( ) , " 0 " ) . unwrap ( ) ;
let v1 = tap . insert_account ( " 1 " . sha3 ( ) , " 1 " ) . unwrap ( ) ;
// Propose.
assert! ( propose_default ( & engine , r , v1 . clone ( ) ) . is_ok ( ) ) ;
// Prevote.
assert_eq! ( default_block ( ) , vote_default ( & engine , r , v0 . clone ( ) ) . unwrap ( ) ) ;
assert! ( vote_default ( & engine , r , v0 ) . is_err ( ) ) ;
assert! ( vote_default ( & engine , r , v1 ) . is_err ( ) ) ;
}
#[ test ]
fn precommit_step ( ) {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-09-07 16:25:42 +02:00
let tap = AccountProvider ::transient_provider ( ) ;
let r = 0 ;
let v0 = tap . insert_account ( " 0 " . sha3 ( ) , " 0 " ) . unwrap ( ) ;
let v1 = tap . insert_account ( " 1 " . sha3 ( ) , " 1 " ) . unwrap ( ) ;
// Propose.
assert! ( propose_default ( & engine , r , v1 . clone ( ) ) . is_ok ( ) ) ;
// Prevote.
assert_eq! ( default_block ( ) , vote_default ( & engine , r , v0 . clone ( ) ) . unwrap ( ) ) ;
assert! ( vote_default ( & engine , r , v0 ) . is_err ( ) ) ;
assert! ( vote_default ( & engine , r , v1 ) . is_err ( ) ) ;
2016-08-23 12:58:40 +02:00
}
2016-08-31 18:18:02 +02:00
#[ test ]
fn timeout_switching ( ) {
2016-09-07 16:25:42 +02:00
let tender = {
2016-09-29 17:57:52 +02:00
let engine = Spec ::new_test_tendermint ( ) . engine ;
2016-09-07 16:25:42 +02:00
Tendermint ::new ( engine . params ( ) . clone ( ) , TendermintParams ::default ( ) , BTreeMap ::new ( ) )
} ;
2016-08-31 18:18:02 +02:00
println! ( " Waiting for timeout " ) ;
2016-09-07 16:25:42 +02:00
sleep ( Duration ::from_secs ( 10 ) ) ;
}
#[ test ]
fn increments_round ( ) {
2016-09-29 17:57:52 +02:00
let spec = Spec ::new_test_tendermint ( ) ;
2016-09-07 16:25:42 +02:00
let ref engine = * spec . engine ;
let def_params = TendermintParams ::default ( ) ;
let tender = Tendermint ::new ( engine . params ( ) . clone ( ) , def_params . clone ( ) , BTreeMap ::new ( ) ) ;
let header = Header ::default ( ) ;
tender . to_commit ( header . bare_hash ( ) , good_seal ( & header ) ) ;
2016-08-31 18:18:02 +02:00
2016-09-07 16:25:42 +02:00
sleep ( Duration ::from_millis ( def_params . timeouts . commit as u64 ) ) ;
match propose_default ( & ( tender as Arc < Engine > ) , 0 , Address ::default ( ) ) {
Err ( Error ::Engine ( EngineError ::WrongRound ) ) = > { } ,
_ = > panic! ( " Should be EngineError::WrongRound " ) ,
}
2016-08-31 18:18:02 +02:00
}
2016-08-23 12:58:40 +02:00
}