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/>.
2016-12-08 20:09:30 +01:00
/// Tendermint BFT consensus engine with round robin proof-of-authority.
/// At each blockchain `Height` there can be multiple `Round`s of voting.
/// 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.
2016-12-09 10:53:38 +01:00
/// Next the `Round` proceeds through `Prevote` and `Precommit` `Step`s.
/// Block is issued when there is enough `Precommit` votes collected on a particular block at the end of a `Round`.
2016-12-08 20:09:30 +01:00
/// Once enough votes have been gathered the proposer issues that block in the `Commit` step.
2016-08-23 12:58:40 +02:00
2016-09-29 15:44:42 +02:00
mod message ;
2016-11-18 14:38:04 +01:00
mod transition ;
2016-09-29 16:32:49 +02:00
mod params ;
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-11-07 12:34:45 +01:00
use util ::* ;
use error ::{ Error , BlockError } ;
use header ::Header ;
use builtin ::Builtin ;
use env_info ::EnvInfo ;
use transaction ::SignedTransaction ;
2016-11-18 14:38:04 +01:00
use rlp ::{ UntrustedRlp , View } ;
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-12-08 12:03:34 +01:00
use engines ::{ Engine , Seal , EngineError } ;
2016-10-05 15:33:07 +02:00
use blockchain ::extras ::BlockDetails ;
2016-11-07 12:34:45 +01:00
use views ::HeaderView ;
2016-08-23 12:58:40 +02:00
use evm ::Schedule ;
2016-11-16 13:43:21 +01:00
use io ::{ IoService , IoChannel } ;
use service ::ClientIoMessage ;
2016-11-21 17:02:26 +01:00
use self ::message ::* ;
2016-11-18 14:38:04 +01:00
use self ::transition ::TransitionHandler ;
2016-09-29 16:32:49 +02:00
use self ::params ::TendermintParams ;
2016-11-15 11:21:18 +01:00
use self ::vote_collector ::VoteCollector ;
2016-08-31 18:18:02 +02:00
2016-11-16 19:01:09 +01:00
#[ derive(Debug, PartialEq, Eq, Clone, Copy) ]
2016-11-15 11:21:18 +01:00
pub enum Step {
2016-08-23 12:58:40 +02:00
Propose ,
2016-11-15 11:21:18 +01:00
Prevote ,
Precommit ,
Commit
2016-08-23 12:58:40 +02:00
}
2016-12-07 16:42:58 +01:00
impl Step {
pub fn is_pre ( self ) -> bool {
match self {
Step ::Prevote | Step ::Precommit = > true ,
_ = > false ,
}
}
}
2016-09-29 15:44:42 +02:00
pub type Height = usize ;
pub type Round = usize ;
pub type BlockHash = H256 ;
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-11-16 19:01:09 +01:00
step_service : IoService < Step > ,
2016-10-05 15:33:07 +02:00
/// Address to be used as authority.
authority : RwLock < Address > ,
2016-11-30 13:59:33 +01:00
/// Password used for signing messages.
password : RwLock < Option < String > > ,
2016-11-15 11:21:18 +01:00
/// Blockchain height.
height : AtomicUsize ,
2016-09-05 17:51:29 +02:00
/// Consensus round.
2016-11-15 11:21:18 +01:00
round : AtomicUsize ,
2016-09-05 17:51:29 +02:00
/// Consensus step.
2016-11-15 11:21:18 +01:00
step : RwLock < Step > ,
/// Vote accumulator.
2016-11-16 11:29:54 +01:00
votes : VoteCollector ,
/// Channel for updating the sealing.
2016-11-17 14:26:57 +01:00
message_channel : Mutex < Option < IoChannel < ClientIoMessage > > > ,
2016-11-18 00:36:24 +01:00
/// Used to sign messages and proposals.
account_provider : Mutex < Option < Arc < AccountProvider > > > ,
2016-11-17 18:12:37 +01:00
/// Message for the last PoLC.
2016-11-18 13:27:00 +01:00
lock_change : RwLock < Option < ConsensusMessage > > ,
/// Last lock round.
last_lock : AtomicUsize ,
2016-11-17 18:12:37 +01:00
/// Bare hash of the proposed block, used for seal submission.
2016-12-09 10:53:38 +01:00
proposal : RwLock < Option < H256 > > ,
2016-09-05 17:51:29 +02:00
}
2016-08-23 12:58:40 +02:00
impl Tendermint {
/// Create a new instance of Tendermint engine
2016-11-15 11:21:18 +01:00
pub fn new ( params : CommonParams , our_params : TendermintParams , builtins : BTreeMap < Address , Builtin > ) -> Result < Arc < Self > , Error > {
2016-09-05 17:51:29 +02:00
let engine = Arc ::new (
Tendermint {
params : params ,
our_params : our_params ,
builtins : builtins ,
2016-11-16 19:01:09 +01:00
step_service : try ! ( IoService ::< Step > ::start ( ) ) ,
2016-10-05 15:33:07 +02:00
authority : RwLock ::new ( Address ::default ( ) ) ,
2016-11-30 13:59:33 +01:00
password : RwLock ::new ( None ) ,
2016-11-28 10:42:50 +01:00
height : AtomicUsize ::new ( 1 ) ,
2016-11-15 11:21:18 +01:00
round : AtomicUsize ::new ( 0 ) ,
step : RwLock ::new ( Step ::Propose ) ,
2016-11-16 11:29:54 +01:00
votes : VoteCollector ::new ( ) ,
2016-11-17 14:26:57 +01:00
message_channel : Mutex ::new ( None ) ,
2016-11-18 00:36:24 +01:00
account_provider : Mutex ::new ( None ) ,
2016-11-18 13:27:00 +01:00
lock_change : RwLock ::new ( None ) ,
last_lock : AtomicUsize ::new ( 0 ) ,
2016-12-09 10:53:38 +01:00
proposal : RwLock ::new ( None ) ,
2016-09-05 17:51:29 +02:00
} ) ;
2016-11-16 14:13:21 +01:00
let handler = TransitionHandler { engine : Arc ::downgrade ( & engine ) } ;
2016-11-16 13:43:21 +01:00
try ! ( engine . step_service . register_handler ( Arc ::new ( handler ) ) ) ;
2016-11-15 11:21:18 +01:00
Ok ( engine )
2016-10-05 15:33:07 +02:00
}
2016-11-16 13:43:21 +01:00
fn update_sealing ( & self ) {
if let Some ( ref channel ) = * self . message_channel . lock ( ) {
match channel . send ( ClientIoMessage ::UpdateSealing ) {
2016-12-12 17:20:20 +01:00
Ok ( _ ) = > trace! ( target : " poa " , " UpdateSealing message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " Could not send a sealing message {}. " , err ) ,
2016-11-16 13:43:21 +01:00
}
}
}
2016-11-16 16:56:16 +01:00
fn submit_seal ( & self , block_hash : H256 , seal : Vec < Bytes > ) {
if let Some ( ref channel ) = * self . message_channel . lock ( ) {
match channel . send ( ClientIoMessage ::SubmitSeal ( block_hash , seal ) ) {
2016-12-12 17:20:20 +01:00
Ok ( _ ) = > trace! ( target : " poa " , " SubmitSeal message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " Could not send a sealing message {}. " , err ) ,
2016-11-16 16:56:16 +01:00
}
}
}
2016-11-28 16:24:22 +01:00
fn broadcast_message ( & self , message : Bytes ) {
2016-12-11 12:32:01 +01:00
let channel = self . message_channel . lock ( ) . clone ( ) ;
if let Some ( ref channel ) = channel {
2016-11-28 16:24:22 +01:00
match channel . send ( ClientIoMessage ::BroadcastMessage ( message ) ) {
2016-12-12 17:20:20 +01:00
Ok ( _ ) = > trace! ( target : " poa " , " BroadcastMessage message sent. " ) ,
2016-11-28 16:50:55 +01:00
Err ( err ) = > warn! ( target : " poa " , " broadcast_message: Could not send a sealing message {}. " , err ) ,
2016-11-17 13:18:20 +01:00
}
2016-12-01 15:10:42 +01:00
} else {
warn! ( target : " poa " , " broadcast_message: No IoChannel available. " ) ;
2016-11-17 13:18:20 +01:00
}
}
2016-11-18 00:36:24 +01:00
fn generate_message ( & self , block_hash : Option < BlockHash > ) -> Option < Bytes > {
if let Some ( ref ap ) = * self . account_provider . lock ( ) {
2016-12-01 21:50:24 +01:00
let h = self . height . load ( AtomicOrdering ::SeqCst ) ;
let r = self . round . load ( AtomicOrdering ::SeqCst ) ;
let s = self . step . read ( ) ;
let vote_info = message_info_rlp ( h , r , * s , block_hash ) ;
let authority = self . authority . read ( ) ;
match ap . sign ( * authority , self . password . read ( ) . clone ( ) , vote_info . sha3 ( ) ) . map ( Into ::into ) {
Ok ( signature ) = > {
let message_rlp = message_full_rlp ( & signature , & vote_info ) ;
2016-12-02 21:04:12 +01:00
let message = ConsensusMessage ::new ( signature , h , r , * s , block_hash ) ;
self . votes . vote ( message . clone ( ) , * authority ) ;
2016-12-11 22:54:48 +01:00
debug! ( target : " poa " , " Generated {:?} as {}. " , message , * authority ) ;
2016-12-02 21:04:12 +01:00
self . handle_valid_message ( & message ) ;
2016-12-01 21:50:24 +01:00
Some ( message_rlp )
} ,
2016-12-01 15:10:42 +01:00
Err ( e ) = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Could not sign the message {} " , e ) ;
2016-12-01 15:10:42 +01:00
None
} ,
}
2016-11-18 00:36:24 +01:00
} else {
2016-12-12 17:20:20 +01:00
warn! ( target : " poa " , " No AccountProvider available. " ) ;
2016-11-18 00:36:24 +01:00
None
}
2016-11-17 18:12:37 +01:00
}
2016-11-28 16:24:22 +01:00
fn generate_and_broadcast_message ( & self , block_hash : Option < BlockHash > ) {
if let Some ( message ) = self . generate_message ( block_hash ) {
self . broadcast_message ( message ) ;
}
}
2016-12-09 14:52:08 +01:00
/// Broadcast all messages since last issued block to get the peers up to speed.
2016-12-02 14:30:43 +01:00
fn broadcast_old_messages ( & self ) {
2016-12-04 20:43:24 +01:00
for m in self . votes . get_up_to ( self . height . load ( AtomicOrdering ::SeqCst ) ) . into_iter ( ) {
self . broadcast_message ( m ) ;
2016-12-02 14:30:43 +01:00
}
}
2016-12-08 20:09:30 +01:00
fn to_next_height ( & self , height : Height ) {
let new_height = height + 1 ;
debug! ( target : " poa " , " Received a Commit, transitioning to height {}. " , new_height ) ;
2016-12-04 20:43:24 +01:00
self . last_lock . store ( 0 , AtomicOrdering ::SeqCst ) ;
2016-12-08 20:09:30 +01:00
self . height . store ( new_height , AtomicOrdering ::SeqCst ) ;
2016-12-04 20:43:24 +01:00
self . round . store ( 0 , AtomicOrdering ::SeqCst ) ;
* self . lock_change . write ( ) = None ;
}
/// Use via step_service to transition steps.
2016-11-16 19:01:09 +01:00
fn to_step ( & self , step : Step ) {
2016-12-10 16:50:23 +01:00
if let Err ( io_err ) = self . step_service . send_message ( step ) {
warn! ( target : " poa " , " Could not proceed to step {}. " , io_err )
}
2016-11-16 19:01:09 +01:00
* self . step . write ( ) = step ;
match step {
2016-11-17 14:26:57 +01:00
Step ::Propose = > {
2016-11-17 18:12:37 +01:00
* self . proposal . write ( ) = None ;
2016-11-17 14:26:57 +01:00
self . update_sealing ( )
} ,
2016-11-17 13:18:20 +01:00
Step ::Prevote = > {
2016-11-18 13:27:00 +01:00
let block_hash = match * self . lock_change . read ( ) {
2016-12-02 21:04:12 +01:00
Some ( ref m ) if ! self . should_unlock ( m . round ) = > m . block_hash ,
_ = > self . proposal . read ( ) . clone ( ) ,
2016-11-18 13:27:00 +01:00
} ;
2016-11-30 17:02:05 +01:00
self . generate_and_broadcast_message ( block_hash ) ;
2016-11-17 13:18:20 +01:00
} ,
Step ::Precommit = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " to_step: Precommit. " ) ;
2016-11-18 13:27:00 +01:00
let block_hash = match * self . lock_change . read ( ) {
2016-12-02 21:04:12 +01:00
Some ( ref m ) if self . is_round ( m ) & & m . block_hash . is_some ( ) = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Setting last lock: {} " , m . round ) ;
2016-11-18 13:27:00 +01:00
self . last_lock . store ( m . round , AtomicOrdering ::SeqCst ) ;
m . block_hash
} ,
_ = > None ,
2016-11-18 00:36:24 +01:00
} ;
2016-11-28 16:24:22 +01:00
self . generate_and_broadcast_message ( block_hash ) ;
2016-11-17 13:18:20 +01:00
} ,
Step ::Commit = > {
2016-12-04 20:43:24 +01:00
trace! ( target : " poa " , " to_step: Commit. " ) ;
2016-11-17 13:18:20 +01:00
// Commit the block using a complete signature set.
let round = self . round . load ( AtomicOrdering ::SeqCst ) ;
2016-12-04 20:43:24 +01:00
let height = self . height . load ( AtomicOrdering ::SeqCst ) ;
2016-11-28 19:58:15 +01:00
if let Some ( block_hash ) = * self . proposal . read ( ) {
2016-12-04 20:43:24 +01:00
// Generate seal and remove old votes.
2016-12-08 20:09:30 +01:00
if self . is_proposer ( & * self . authority . read ( ) ) . is_ok ( ) {
if let Some ( seal ) = self . votes . seal_signatures ( height , round , block_hash ) {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Collected seal: {:?} " , seal ) ;
2016-12-04 20:43:24 +01:00
let seal = vec! [
::rlp ::encode ( & round ) . to_vec ( ) ,
::rlp ::encode ( & seal . proposal ) . to_vec ( ) ,
::rlp ::encode ( & seal . votes ) . to_vec ( )
] ;
self . submit_seal ( block_hash , seal ) ;
2016-12-08 20:09:30 +01:00
self . to_next_height ( height ) ;
} else {
2016-12-09 20:48:05 +01:00
warn! ( target : " poa " , " Not enough votes found! " ) ;
2016-12-04 20:43:24 +01:00
}
2016-11-17 18:12:37 +01:00
}
2016-11-17 13:18:20 +01:00
}
} ,
2016-11-16 19:01:09 +01: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-11-22 17:05:27 +01:00
fn is_above_threshold ( & self , n : usize ) -> bool {
n > self . our_params . authority_n * 2 / 3
2016-08-24 11:58:49 +02:00
}
2016-09-05 17:51:29 +02:00
2016-12-04 20:43:24 +01:00
/// Check if address is a proposer for given round.
fn is_round_proposer ( & self , height : Height , round : Round , address : & Address ) -> Result < ( ) , EngineError > {
2016-11-22 17:05:27 +01:00
let ref p = self . our_params ;
2016-12-04 20:43:24 +01:00
let proposer_nonce = height + round ;
trace! ( target : " poa " , " is_proposer: Proposer nonce: {} " , proposer_nonce ) ;
2016-11-22 17:05:27 +01:00
let proposer = p . authorities . get ( proposer_nonce % p . authority_n ) . expect ( " There are authority_n authorities; taking number modulo authority_n gives number in authority_n range; qed " ) ;
2016-11-24 14:57:54 +01:00
if proposer = = address {
Ok ( ( ) )
} else {
2016-11-29 13:51:27 +01:00
Err ( EngineError ::NotProposer ( Mismatch { expected : proposer . clone ( ) , found : address . clone ( ) } ) )
2016-11-24 14:57:54 +01:00
}
2016-11-15 11:21:18 +01:00
}
2016-12-04 20:43:24 +01:00
/// Check if address is the current proposer.
fn is_proposer ( & self , address : & Address ) -> Result < ( ) , EngineError > {
self . is_round_proposer ( self . height . load ( AtomicOrdering ::SeqCst ) , self . round . load ( AtomicOrdering ::SeqCst ) , address )
}
2016-11-18 14:38:04 +01:00
fn is_height ( & self , message : & ConsensusMessage ) -> bool {
2016-11-16 19:01:09 +01:00
message . is_height ( self . height . load ( AtomicOrdering ::SeqCst ) )
2016-11-16 11:29:54 +01:00
}
2016-11-18 13:27:00 +01:00
fn is_round ( & self , message : & ConsensusMessage ) -> bool {
message . is_round ( self . height . load ( AtomicOrdering ::SeqCst ) , self . round . load ( AtomicOrdering ::SeqCst ) )
}
2016-11-18 14:38:04 +01:00
fn increment_round ( & self , n : Round ) {
2016-12-04 20:43:24 +01:00
trace! ( target : " poa " , " increment_round: New round. " ) ;
2016-11-18 14:38:04 +01:00
self . round . fetch_add ( n , AtomicOrdering ::SeqCst ) ;
}
fn should_unlock ( & self , lock_change_round : Round ) -> bool {
self . last_lock . load ( AtomicOrdering ::SeqCst ) < lock_change_round
& & lock_change_round < self . round . load ( AtomicOrdering ::SeqCst )
}
2016-11-16 11:29:54 +01:00
fn has_enough_any_votes ( & self ) -> bool {
2016-11-22 17:05:27 +01:00
let step_votes = self . votes . count_step_votes ( self . height . load ( AtomicOrdering ::SeqCst ) , self . round . load ( AtomicOrdering ::SeqCst ) , * self . step . read ( ) ) ;
self . is_above_threshold ( step_votes )
2016-11-16 19:01:09 +01:00
}
2016-11-18 14:38:04 +01:00
fn has_enough_future_step_votes ( & self , message : & ConsensusMessage ) -> bool {
2016-11-22 17:05:27 +01:00
if message . round > self . round . load ( AtomicOrdering ::SeqCst ) {
let step_votes = self . votes . count_step_votes ( message . height , message . round , message . step ) ;
self . is_above_threshold ( step_votes )
} else {
false
}
2016-11-16 19:01:09 +01:00
}
fn has_enough_aligned_votes ( & self , message : & ConsensusMessage ) -> bool {
2016-11-28 15:08:38 +01:00
let aligned_count = self . votes . count_aligned_votes ( & message ) ;
self . is_above_threshold ( aligned_count )
2016-11-15 11:21:18 +01:00
}
2016-12-02 21:04:12 +01:00
fn handle_valid_message ( & self , message : & ConsensusMessage ) {
let is_newer_than_lock = match * self . lock_change . read ( ) {
Some ( ref lock ) = > message > lock ,
None = > true ,
} ;
2016-12-12 17:20:20 +01:00
let lock_change = is_newer_than_lock
2016-12-02 21:04:12 +01:00
& & message . step = = Step ::Prevote
& & message . block_hash . is_some ( )
2016-12-12 17:20:20 +01:00
& & self . has_enough_aligned_votes ( message ) ;
if lock_change {
2016-12-04 20:43:24 +01:00
trace! ( target : " poa " , " handle_valid_message: Lock change. " ) ;
2016-12-02 21:04:12 +01:00
* self . lock_change . write ( ) = Some ( message . clone ( ) ) ;
}
// Check if it can affect the step transition.
if self . is_height ( message ) {
let next_step = match * self . step . read ( ) {
Step ::Precommit if self . has_enough_aligned_votes ( message ) = > {
if message . block_hash . is_none ( ) {
self . increment_round ( 1 ) ;
Some ( Step ::Propose )
} else {
Some ( Step ::Commit )
}
} ,
Step ::Precommit if self . has_enough_future_step_votes ( message ) = > {
self . increment_round ( message . round - self . round . load ( AtomicOrdering ::SeqCst ) ) ;
Some ( Step ::Precommit )
} ,
2016-12-12 17:20:20 +01:00
// Avoid counting twice.
Step ::Prevote if lock_change = > Some ( Step ::Precommit ) ,
2016-12-02 21:04:12 +01:00
Step ::Prevote if self . has_enough_aligned_votes ( message ) = > Some ( Step ::Precommit ) ,
Step ::Prevote if self . has_enough_future_step_votes ( message ) = > {
self . increment_round ( message . round - self . round . load ( AtomicOrdering ::SeqCst ) ) ;
Some ( Step ::Prevote )
} ,
_ = > None ,
} ;
if let Some ( step ) = next_step {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Transition to {:?} triggered. " , step ) ;
2016-12-10 16:50:23 +01:00
self . to_step ( step ) ;
2016-12-02 21:04:12 +01:00
}
}
}
2016-11-15 11:21:18 +01:00
}
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 }
2016-12-07 09:32:36 +01:00
fn maximum_uncle_count ( & self ) -> usize { 0 }
fn maximum_uncle_age ( & self ) -> usize { 0 }
2016-08-23 12:58:40 +02:00
/// Additional engine-specific information for the user/developer concerning `header`.
2016-11-15 12:27:09 +01:00
fn extra_info ( & self , header : & Header ) -> BTreeMap < String , String > {
2016-11-21 17:02:26 +01:00
let message = ConsensusMessage ::new_proposal ( header ) . expect ( " Invalid header. " ) ;
2016-11-15 12:27:09 +01:00
map! [
2016-11-21 17:02:26 +01:00
" signature " . into ( ) = > message . signature . to_string ( ) ,
" height " . into ( ) = > message . height . to_string ( ) ,
" round " . into ( ) = > message . round . to_string ( ) ,
" block_hash " . into ( ) = > message . block_hash . as_ref ( ) . map ( ToString ::to_string ) . unwrap_or ( " " . into ( ) )
2016-11-15 12:27:09 +01:00
]
}
2016-08-23 12:58:40 +02:00
fn schedule ( & self , _env_info : & EnvInfo ) -> Schedule {
2016-12-09 10:53:38 +01:00
Schedule ::new_post_eip150 ( usize ::max_value ( ) , true , true , true )
2016-08-23 12:58:40 +02:00
}
fn populate_from_parent ( & self , header : & mut Header , parent : & Header , gas_floor_target : U256 , _gas_ceil_target : U256 ) {
2016-12-07 14:39:37 +01:00
header . set_difficulty ( parent . difficulty ( ) . clone ( ) ) ;
2016-08-31 18:43:24 +02:00
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-12-01 18:21:51 +01:00
/// Should this node participate.
2016-11-15 11:21:18 +01:00
fn is_sealer ( & self , address : & Address ) -> Option < bool > {
2016-12-01 18:21:51 +01:00
Some ( self . is_authority ( address ) )
2016-10-11 19:37:31 +02:00
}
2016-08-23 12:58:40 +02:00
2016-12-08 12:03:34 +01:00
/// Attempt to seal generate a proposal seal.
fn generate_seal ( & self , block : & ExecutedBlock ) -> Seal {
2016-11-18 00:36:24 +01:00
if let Some ( ref ap ) = * self . account_provider . lock ( ) {
2016-10-05 15:33:07 +02:00
let header = block . header ( ) ;
let author = header . author ( ) ;
2016-12-01 22:56:38 +01:00
// Only proposer can generate seal if None was generated.
2016-12-08 20:09:30 +01:00
if self . is_proposer ( author ) . is_err ( ) | | self . proposal . read ( ) . is_some ( ) {
2016-12-08 12:03:34 +01:00
return Seal ::None ;
2016-12-01 22:56:38 +01:00
}
2016-11-28 19:58:15 +01:00
let height = header . number ( ) as Height ;
let round = self . round . load ( AtomicOrdering ::SeqCst ) ;
let bh = Some ( header . bare_hash ( ) ) ;
2016-12-04 20:43:24 +01:00
let vote_info = message_info_rlp ( height , round , Step ::Propose , bh . clone ( ) ) ;
2016-11-30 13:59:33 +01:00
if let Ok ( signature ) = ap . sign ( * author , self . password . read ( ) . clone ( ) , vote_info . sha3 ( ) ) . map ( H520 ::from ) {
2016-12-01 18:21:51 +01:00
// Insert Propose vote.
2016-12-04 20:43:24 +01:00
debug! ( target : " poa " , " Submitting proposal {} at height {} round {}. " , header . bare_hash ( ) , height , round ) ;
2016-12-01 21:50:24 +01:00
self . votes . vote ( ConsensusMessage ::new ( signature , height , round , Step ::Propose , bh ) , * author ) ;
2016-12-01 18:21:51 +01:00
// Remember proposal for later seal submission.
2016-12-04 20:43:24 +01:00
* self . proposal . write ( ) = bh ;
2016-12-08 12:03:34 +01:00
Seal ::Proposal ( vec! [
2016-12-04 20:43:24 +01:00
::rlp ::encode ( & round ) . to_vec ( ) ,
2016-11-28 19:58:15 +01:00
::rlp ::encode ( & signature ) . to_vec ( ) ,
2016-12-01 18:21:51 +01:00
::rlp ::EMPTY_LIST_RLP . to_vec ( )
2016-11-17 13:18:20 +01:00
] )
} else {
warn! ( target : " poa " , " generate_seal: FAIL: accounts secret key unavailable " ) ;
2016-12-08 12:03:34 +01:00
Seal ::None
2016-10-05 15:33:07 +02:00
}
} else {
2016-11-17 13:18:20 +01:00
warn! ( target : " poa " , " generate_seal: FAIL: accounts not provided " ) ;
2016-12-08 12:03:34 +01:00
Seal ::None
2016-10-05 15:33:07 +02:00
}
2016-08-23 12:58:40 +02:00
}
2016-12-11 12:32:01 +01:00
fn handle_message ( & self , rlp : & [ u8 ] ) -> Result < ( ) , Error > {
let rlp = UntrustedRlp ::new ( rlp ) ;
2016-11-15 11:21:18 +01:00
let message : ConsensusMessage = try ! ( rlp . as_val ( ) ) ;
2016-12-04 20:43:24 +01:00
if ! self . votes . is_old_or_known ( & message ) {
2016-11-29 11:55:24 +01:00
let sender = public_to_address ( & try ! ( recover ( & message . signature . into ( ) , & try ! ( rlp . at ( 1 ) ) . as_raw ( ) . sha3 ( ) ) ) ) ;
if ! self . is_authority ( & sender ) {
2016-11-29 13:51:27 +01:00
try ! ( Err ( EngineError ::NotAuthorized ( sender ) ) ) ;
2016-11-29 11:55:24 +01:00
}
2016-11-28 16:24:22 +01:00
self . broadcast_message ( rlp . as_raw ( ) . to_vec ( ) ) ;
2016-12-11 22:54:48 +01:00
trace! ( target : " poa " , " Handling a valid {:?} from {}. " , message , sender ) ;
self . votes . vote ( message . clone ( ) , sender ) ;
2016-12-02 21:04:12 +01:00
self . handle_valid_message ( & message ) ;
2016-11-15 11:21:18 +01:00
}
2016-11-17 13:18:20 +01:00
Ok ( ( ) )
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 ( ) {
2016-12-02 14:30:43 +01:00
let signatures_len = header . seal ( ) [ 2 ] . len ( ) ;
if signatures_len > = 1 {
Ok ( ( ) )
} else {
Err ( From ::from ( EngineError ::BadSealFieldSize ( OutOfBounds {
min : Some ( 1 ) ,
max : None ,
found : signatures_len
} ) ) )
}
2016-09-30 13:22:46 +02:00
} 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-12-02 14:30:43 +01:00
2016-08-23 12:58:40 +02:00
}
2016-09-06 12:26:06 +02:00
fn verify_block_unordered ( & self , header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2016-11-21 17:02:26 +01:00
let proposal = try ! ( ConsensusMessage ::new_proposal ( header ) ) ;
let proposer = try ! ( proposal . verify ( ) ) ;
2016-12-01 22:56:38 +01:00
if ! self . is_authority ( & proposer ) {
try ! ( Err ( EngineError ::NotAuthorized ( proposer ) ) )
}
2016-12-02 14:30:43 +01:00
2016-12-01 22:56:38 +01:00
let precommit_hash = proposal . precommit_hash ( ) ;
2016-12-02 14:30:43 +01:00
let ref signatures_field = header . seal ( ) [ 2 ] ;
2016-11-24 14:57:54 +01:00
let mut signature_count = 0 ;
2016-12-01 22:56:38 +01:00
let mut origins = HashSet ::new ( ) ;
2016-12-02 14:30:43 +01:00
for rlp in UntrustedRlp ::new ( signatures_field ) . iter ( ) {
2016-12-11 17:50:12 +01:00
let precommit : ConsensusMessage = ConsensusMessage ::new_commit ( & proposal , try ! ( rlp . as_val ( ) ) ) ;
let address = match self . votes . get ( & precommit ) {
Some ( a ) = > a ,
None = > public_to_address ( & try ! ( recover ( & precommit . signature . into ( ) , & precommit_hash ) ) ) ,
} ;
2016-11-16 11:29:54 +01:00
if ! self . our_params . authorities . contains ( & address ) {
2016-12-11 17:50:12 +01:00
try ! ( Err ( EngineError ::NotAuthorized ( address . to_owned ( ) ) ) )
2016-11-15 11:21:18 +01:00
}
2016-11-24 14:57:54 +01:00
2016-12-01 22:56:38 +01:00
if origins . insert ( address ) {
signature_count + = 1 ;
} else {
2016-12-02 14:30:43 +01:00
warn! ( target : " poa " , " verify_block_unordered: Duplicate signature from {} on the seal. " , address ) ;
try ! ( Err ( BlockError ::InvalidSeal ) ) ;
2016-12-01 22:56:38 +01:00
}
2016-11-24 14:57:54 +01:00
}
2016-12-04 20:43:24 +01:00
2016-12-02 14:30:43 +01:00
// Check if its a proposal if there is not enough precommits.
2016-12-08 20:09:30 +01:00
if ! self . is_above_threshold ( signature_count ) {
2016-12-02 14:30:43 +01:00
let signatures_len = signatures_field . len ( ) ;
// Proposal has to have an empty signature list.
if signatures_len ! = 1 {
try ! ( Err ( EngineError ::BadSealFieldSize ( OutOfBounds {
min : Some ( 1 ) ,
max : Some ( 1 ) ,
found : signatures_len
} ) ) ) ;
}
2016-12-04 20:43:24 +01:00
try ! ( self . is_round_proposer ( proposal . height , proposal . round , & proposer ) ) ;
2016-11-15 11:21:18 +01:00
}
Ok ( ( ) )
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
if header . number ( ) = = 0 {
2016-12-02 14:30:43 +01:00
try ! ( Err ( BlockError ::RidiculousNumber ( OutOfBounds { min : Some ( 1 ) , max : None , found : header . number ( ) } ) ) ) ;
2016-08-23 12:58:40 +02:00
}
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 {
2016-12-02 14:30:43 +01:00
try ! ( Err ( BlockError ::InvalidGasLimit ( OutOfBounds { min : Some ( min_gas ) , max : Some ( max_gas ) , found : header . gas_limit ( ) . clone ( ) } ) ) ) ;
2016-08-23 12:58:40 +02:00
}
2016-12-02 14:30:43 +01:00
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
2016-11-30 13:59:33 +01:00
fn set_signer ( & self , address : Address , password : String ) {
* self . authority . write ( ) = address ;
* self . password . write ( ) = Some ( password ) ;
2016-12-10 16:50:23 +01:00
self . to_step ( Step ::Propose ) ;
2016-11-30 13:59:33 +01:00
}
2016-12-09 14:52:08 +01:00
fn stop ( & self ) {
self . step_service . stop ( )
}
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 {
2016-12-04 20:43:24 +01:00
let new_number = new_header . number ( ) ;
let best_number = best_header . number ( ) ;
2016-12-08 20:09:30 +01:00
trace! ( target : " poa " , " new_header: {}, best_header: {} " , new_number , best_number ) ;
2016-12-04 20:43:24 +01:00
if new_number ! = best_number {
new_number > best_number
2016-12-01 21:50:24 +01:00
} else {
2016-12-04 20:43:24 +01:00
let new_seal = new_header . seal ( ) ;
let best_seal = best_header . seal ( ) ;
let new_signatures = new_seal . get ( 2 ) . expect ( " Tendermint seal should have three elements. " ) . len ( ) ;
let best_signatures = best_seal . get ( 2 ) . expect ( " Tendermint seal should have three elements. " ) . len ( ) ;
if new_signatures > best_signatures {
true
} else {
let new_round : Round = ::rlp ::Rlp ::new ( & new_seal . get ( 0 ) . expect ( " Tendermint seal should have three elements. " ) ) . as_val ( ) ;
let best_round : Round = ::rlp ::Rlp ::new ( & best_seal . get ( 0 ) . expect ( " Tendermint seal should have three elements. " ) ) . as_val ( ) ;
new_round > best_round
}
2016-12-01 21:50:24 +01:00
}
2016-10-05 15:33:07 +02:00
}
2016-11-16 11:29:54 +01:00
2016-12-08 12:03:34 +01:00
fn is_proposal ( & self , header : & Header ) -> bool {
let signatures_len = header . seal ( ) [ 2 ] . len ( ) ;
// Signatures have to be an empty list rlp.
2016-12-08 20:09:30 +01:00
let proposal = ConsensusMessage ::new_proposal ( header ) . expect ( " block went through full verification; this Engine verifies new_proposal creation; qed " ) ;
2016-12-08 12:03:34 +01:00
if signatures_len ! = 1 {
2016-12-08 20:09:30 +01:00
// New Commit received, skip to next height.
2016-12-12 19:44:24 +01:00
trace! ( target : " poa " , " Received a commit for height {}, round {}. " , proposal . height , proposal . round ) ;
2016-12-08 20:09:30 +01:00
self . to_next_height ( proposal . height ) ;
2016-12-08 12:03:34 +01:00
return false ;
}
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 ) ;
if self . is_round ( & proposal ) {
* self . proposal . write ( ) = proposal . block_hash . clone ( ) ;
}
self . votes . vote ( proposal , proposer ) ;
true
}
2016-12-10 16:50:23 +01:00
/// Equivalent to a timeout: to be used for tests.
fn step ( & self ) {
let next_step = match * self . step . read ( ) {
Step ::Propose = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Propose timeout. " ) ;
2016-12-10 16:50:23 +01:00
Step ::Prevote
} ,
Step ::Prevote if self . has_enough_any_votes ( ) = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Prevote timeout. " ) ;
2016-12-10 16:50:23 +01:00
Step ::Precommit
} ,
Step ::Prevote = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Prevote timeout without enough votes. " ) ;
2016-12-10 16:50:23 +01:00
self . broadcast_old_messages ( ) ;
Step ::Prevote
} ,
Step ::Precommit if self . has_enough_any_votes ( ) = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Precommit timeout. " ) ;
2016-12-10 16:50:23 +01:00
self . increment_round ( 1 ) ;
Step ::Propose
} ,
Step ::Precommit = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Precommit timeout without enough votes. " ) ;
2016-12-10 16:50:23 +01:00
self . broadcast_old_messages ( ) ;
Step ::Precommit
} ,
Step ::Commit = > {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Commit timeout. " ) ;
2016-12-10 16:50:23 +01:00
Step ::Propose
} ,
} ;
self . to_step ( next_step ) ;
}
2016-11-16 11:29:54 +01:00
fn register_message_channel ( & self , message_channel : IoChannel < ClientIoMessage > ) {
2016-12-12 17:20:20 +01:00
trace! ( target : " poa " , " Register the IoChannel. " ) ;
2016-11-18 00:36:24 +01:00
* self . message_channel . lock ( ) = Some ( message_channel ) ;
}
fn register_account_provider ( & self , account_provider : Arc < AccountProvider > ) {
* self . account_provider . lock ( ) = Some ( account_provider ) ;
2016-11-16 11:29:54 +01:00
}
2016-08-23 12:58:40 +02:00
}
#[ cfg(test) ]
mod tests {
2016-11-07 12:34:45 +01:00
use util ::* ;
2016-11-30 15:30:21 +01:00
use util ::trie ::TrieSpec ;
2016-11-24 20:59:08 +01:00
use io ::{ IoContext , IoHandler } ;
2016-08-23 12:58:40 +02:00
use block ::* ;
2016-11-07 12:34:45 +01:00
use error ::{ Error , BlockError } ;
use header ::Header ;
2016-12-15 16:52:39 +01:00
use io ::{ IoService , IoChannel } ;
2016-11-07 12:34:45 +01:00
use env_info ::EnvInfo ;
2016-08-23 12:58:40 +02:00
use tests ::helpers ::* ;
use account_provider ::AccountProvider ;
2016-11-24 20:59:08 +01:00
use service ::ClientIoMessage ;
2016-08-23 12:58:40 +02:00
use spec ::Spec ;
2016-12-08 12:03:34 +01:00
use engines ::{ Engine , EngineError , Seal } ;
2016-11-21 19:54:16 +01:00
use super ::* ;
use super ::message ::* ;
2016-08-23 12:58:40 +02:00
2016-12-10 17:40:20 +01:00
/// Accounts inserted with "0" and "1" are authorities. First proposer is "0".
2016-11-22 17:05:27 +01:00
fn setup ( ) -> ( Spec , Arc < AccountProvider > ) {
let tap = Arc ::new ( AccountProvider ::transient_provider ( ) ) ;
let spec = Spec ::new_test_tendermint ( ) ;
spec . engine . register_account_provider ( tap . clone ( ) ) ;
( spec , tap )
}
2016-11-24 20:59:08 +01:00
fn propose_default ( spec : & Spec , proposer : Address ) -> ( LockedBlock , Vec < Bytes > ) {
let mut db_result = get_temp_state_db ( ) ;
let mut db = db_result . take ( ) ;
2016-11-30 15:30:21 +01:00
spec . ensure_db_good ( & mut db , & TrieFactory ::new ( TrieSpec ::Secure ) ) . unwrap ( ) ;
2016-11-24 20:59:08 +01:00
let genesis_header = spec . genesis_header ( ) ;
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
let b = OpenBlock ::new ( spec . engine . as_ref ( ) , Default ::default ( ) , false , db . boxed_clone ( ) , & genesis_header , last_hashes , proposer , ( 3141562. into ( ) , 31415620. into ( ) ) , vec! [ ] ) . unwrap ( ) ;
2016-11-21 19:54:16 +01:00
let b = b . close_and_lock ( ) ;
2016-12-08 12:03:34 +01:00
if let Seal ::Proposal ( seal ) = spec . engine . generate_seal ( b . block ( ) ) {
( b , seal )
} else {
panic! ( )
}
2016-08-26 19:27:50 +02:00
}
2016-12-09 20:48:05 +01:00
fn vote < F > ( engine : & Arc < Engine > , signer : F , height : usize , round : usize , step : Step , block_hash : Option < H256 > ) -> Bytes where F : FnOnce ( H256 ) -> Result < H520 , ::account_provider ::Error > {
2016-12-01 21:50:24 +01:00
let mi = message_info_rlp ( height , round , step , block_hash ) ;
let m = message_full_rlp ( & signer ( mi . sha3 ( ) ) . unwrap ( ) . into ( ) , & mi ) ;
2016-12-11 18:23:54 +01:00
engine . handle_message ( & m ) . unwrap ( ) ;
2016-12-09 20:48:05 +01:00
m
2016-09-07 16:25:42 +02:00
}
2016-11-22 17:05:27 +01:00
fn proposal_seal ( tap : & Arc < AccountProvider > , header : & Header , round : Round ) -> Vec < Bytes > {
2016-11-21 19:54:16 +01:00
let author = header . author ( ) ;
let vote_info = message_info_rlp ( header . number ( ) as Height , round , Step ::Propose , Some ( header . bare_hash ( ) ) ) ;
let signature = tap . sign ( * author , None , vote_info . sha3 ( ) ) . unwrap ( ) ;
vec! [
::rlp ::encode ( & round ) . to_vec ( ) ,
::rlp ::encode ( & H520 ::from ( signature ) ) . to_vec ( ) ,
2016-12-02 14:30:43 +01:00
::rlp ::EMPTY_LIST_RLP . to_vec ( )
2016-11-21 19:54:16 +01:00
]
2016-09-07 16:25:42 +02:00
}
2016-11-28 12:47:33 +01:00
fn precommit_signatures ( tap : & Arc < AccountProvider > , height : Height , round : Round , bare_hash : Option < H256 > , v1 : H160 , v2 : H160 ) -> Bytes {
2016-11-28 10:42:50 +01:00
let vote_info = message_info_rlp ( height , round , Step ::Precommit , bare_hash ) ;
::rlp ::encode ( & vec! [
2016-11-28 12:47:33 +01:00
H520 ::from ( tap . sign ( v1 , None , vote_info . sha3 ( ) ) . unwrap ( ) ) ,
H520 ::from ( tap . sign ( v2 , None , vote_info . sha3 ( ) ) . unwrap ( ) )
2016-11-28 10:42:50 +01:00
] ) . to_vec ( )
}
2016-11-22 17:05:27 +01:00
fn insert_and_unlock ( tap : & Arc < AccountProvider > , acc : & str ) -> Address {
let addr = tap . insert_account ( acc . sha3 ( ) , acc ) . unwrap ( ) ;
tap . unlock_account_permanently ( addr , acc . into ( ) ) . unwrap ( ) ;
addr
}
2016-11-30 15:30:21 +01:00
fn insert_and_register ( tap : & Arc < AccountProvider > , engine : & Arc < Engine > , acc : & str ) -> Address {
2016-12-05 14:24:22 +01:00
let addr = insert_and_unlock ( tap , acc ) ;
2016-11-30 15:30:21 +01:00
engine . set_signer ( addr . clone ( ) , acc . into ( ) ) ;
addr
}
2016-11-28 12:47:33 +01:00
struct TestIo {
2016-11-28 19:58:15 +01:00
received : RwLock < Vec < ClientIoMessage > >
2016-11-28 12:47:33 +01:00
}
impl TestIo {
2016-11-28 19:58:15 +01:00
fn new ( ) -> Arc < Self > { Arc ::new ( TestIo { received : RwLock ::new ( Vec ::new ( ) ) } ) }
2016-11-28 12:47:33 +01:00
}
2016-11-24 20:59:08 +01:00
impl IoHandler < ClientIoMessage > for TestIo {
fn message ( & self , _io : & IoContext < ClientIoMessage > , net_message : & ClientIoMessage ) {
2016-11-28 19:58:15 +01:00
self . received . write ( ) . push ( net_message . clone ( ) ) ;
2016-11-24 20:59:08 +01:00
}
2016-09-05 17:51:29 +02:00
}
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-11-24 14:57:54 +01:00
let header = Header ::default ( ) ;
2016-08-23 12:58:40 +02:00
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 " ) ; } ,
}
}
2016-11-22 17:05:27 +01:00
#[ test ]
fn allows_correct_proposer ( ) {
let ( spec , tap ) = setup ( ) ;
let engine = spec . engine ;
let mut header = Header ::default ( ) ;
2016-12-05 14:24:22 +01:00
let validator = insert_and_unlock ( & tap , " 0 " ) ;
2016-11-22 17:05:27 +01:00
header . set_author ( validator ) ;
let seal = proposal_seal ( & tap , & header , 0 ) ;
header . set_seal ( seal ) ;
// Good proposer.
2016-12-02 14:59:54 +01:00
assert! ( engine . verify_block_unordered ( & header . clone ( ) , None ) . is_ok ( ) ) ;
2016-11-22 17:05:27 +01:00
2016-12-05 14:24:22 +01:00
let validator = insert_and_unlock ( & tap , " 1 " ) ;
2016-12-02 14:59:54 +01:00
header . set_author ( validator ) ;
2016-11-22 17:05:27 +01:00
let seal = proposal_seal ( & tap , & header , 0 ) ;
header . set_seal ( seal ) ;
// Bad proposer.
2016-11-24 14:57:54 +01:00
match engine . verify_block_unordered ( & header , None ) {
2016-11-29 13:51:27 +01:00
Err ( Error ::Engine ( EngineError ::NotProposer ( _ ) ) ) = > { } ,
2016-11-24 14:57:54 +01:00
_ = > panic! ( ) ,
}
2016-12-02 14:59:54 +01:00
let random = insert_and_unlock ( & tap , " 101 " ) ;
header . set_author ( random ) ;
let seal = proposal_seal ( & tap , & header , 0 ) ;
header . set_seal ( seal ) ;
// Not authority.
match engine . verify_block_unordered ( & header , None ) {
Err ( Error ::Engine ( EngineError ::NotAuthorized ( _ ) ) ) = > { } ,
_ = > panic! ( ) ,
2016-12-09 14:52:08 +01:00
} ;
engine . stop ( ) ;
2016-11-22 17:05:27 +01:00
}
2016-08-23 12:58:40 +02:00
#[ test ]
2016-11-24 14:57:54 +01:00
fn seal_signatures_checking ( ) {
2016-11-22 17:05:27 +01:00
let ( spec , tap ) = setup ( ) ;
let engine = spec . engine ;
2016-09-07 16:25:42 +02:00
2016-11-24 14:57:54 +01:00
let mut header = Header ::default ( ) ;
2016-11-30 17:40:16 +01:00
let proposer = insert_and_unlock ( & tap , " 1 " ) ;
2016-11-24 14:57:54 +01:00
header . set_author ( proposer ) ;
2016-11-22 17:05:27 +01:00
let mut seal = proposal_seal ( & tap , & header , 0 ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 20:59:08 +01:00
let vote_info = message_info_rlp ( 0 , 0 , Step ::Precommit , Some ( header . bare_hash ( ) ) ) ;
2016-12-02 14:30:43 +01:00
let signature1 = tap . sign ( proposer , None , vote_info . sha3 ( ) ) . unwrap ( ) ;
seal [ 2 ] = ::rlp ::encode ( & vec! [ H520 ::from ( signature1 . clone ( ) ) ] ) . to_vec ( ) ;
header . set_seal ( seal . clone ( ) ) ;
2016-09-07 16:25:42 +02:00
2016-12-02 14:30:43 +01:00
// One good signature is not enough.
match engine . verify_block_unordered ( & header , None ) {
Err ( Error ::Engine ( EngineError ::BadSealFieldSize ( _ ) ) ) = > { } ,
_ = > panic! ( ) ,
}
2016-09-07 16:25:42 +02:00
2016-12-02 14:30:43 +01:00
let voter = insert_and_unlock ( & tap , " 0 " ) ;
let signature0 = tap . sign ( voter , None , vote_info . sha3 ( ) ) . unwrap ( ) ;
seal [ 2 ] = ::rlp ::encode ( & vec! [ H520 ::from ( signature1 . clone ( ) ) , H520 ::from ( signature0 . clone ( ) ) ] ) . to_vec ( ) ;
2016-11-24 14:57:54 +01:00
header . set_seal ( seal . clone ( ) ) ;
2016-09-07 16:25:42 +02:00
2016-11-22 17:05:27 +01:00
assert! ( engine . verify_block_unordered ( & header , None ) . is_ok ( ) ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 14:57:54 +01:00
let bad_voter = insert_and_unlock ( & tap , " 101 " ) ;
let bad_signature = tap . sign ( bad_voter , None , vote_info . sha3 ( ) ) . unwrap ( ) ;
2016-09-07 16:25:42 +02:00
2016-12-02 14:30:43 +01:00
seal [ 2 ] = ::rlp ::encode ( & vec! [ H520 ::from ( signature1 ) , H520 ::from ( bad_signature ) ] ) . to_vec ( ) ;
2016-09-07 16:25:42 +02:00
header . set_seal ( seal ) ;
2016-11-24 14:57:54 +01:00
// One good and one bad signature.
match engine . verify_block_unordered ( & header , None ) {
2016-11-29 13:51:27 +01:00
Err ( Error ::Engine ( EngineError ::NotAuthorized ( _ ) ) ) = > { } ,
2016-11-24 14:57:54 +01:00
_ = > panic! ( ) ,
2016-12-09 14:52:08 +01:00
} ;
engine . stop ( ) ;
2016-09-07 16:25:42 +02:00
}
#[ test ]
fn can_generate_seal ( ) {
2016-11-24 14:57:54 +01:00
let ( spec , tap ) = setup ( ) ;
2016-11-30 15:30:21 +01:00
2016-11-30 17:02:05 +01:00
let proposer = insert_and_register ( & tap , & spec . engine , " 1 " ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 20:59:08 +01:00
let ( b , seal ) = propose_default ( & spec , proposer ) ;
assert! ( b . try_seal ( spec . engine . as_ref ( ) , seal ) . is_ok ( ) ) ;
2016-12-09 14:52:08 +01:00
spec . engine . stop ( ) ;
2016-08-24 15:55:47 +02:00
}
2016-12-09 20:48:05 +01:00
#[ test ]
fn can_recognize_proposal ( ) {
let ( spec , tap ) = setup ( ) ;
let proposer = insert_and_register ( & tap , & spec . engine , " 1 " ) ;
let ( b , seal ) = propose_default ( & spec , proposer ) ;
let sealed = b . seal ( spec . engine . as_ref ( ) , seal ) . unwrap ( ) ;
assert! ( spec . engine . is_proposal ( sealed . header ( ) ) ) ;
spec . engine . stop ( ) ;
}
#[ test ]
fn relays_messages ( ) {
let ( spec , tap ) = setup ( ) ;
let engine = spec . engine . clone ( ) ;
let mut db_result = get_temp_state_db ( ) ;
let mut db = db_result . take ( ) ;
spec . ensure_db_good ( & mut db , & TrieFactory ::new ( TrieSpec ::Secure ) ) . unwrap ( ) ;
let v0 = insert_and_register ( & tap , & engine , " 0 " ) ;
let v1 = insert_and_register ( & tap , & engine , " 1 " ) ;
let h = 0 ;
let r = 0 ;
// Propose
let ( b , _ ) = propose_default ( & spec , v1 . clone ( ) ) ;
let proposal = Some ( b . header ( ) . bare_hash ( ) ) ;
// Register IoHandler remembers messages.
let test_io = TestIo ::new ( ) ;
2016-12-15 16:52:39 +01:00
let channel = IoChannel ::to_handler ( Arc ::downgrade ( & ( test_io . clone ( ) as Arc < IoHandler < ClientIoMessage > > ) ) ) ;
engine . register_message_channel ( channel ) ;
2016-12-09 20:48:05 +01:00
let prevote_current = vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Prevote , proposal ) ;
let precommit_current = vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
let prevote_future = vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h + 1 , r , Step ::Prevote , proposal ) ;
// Relays all valid present and future messages.
assert! ( test_io . received . read ( ) . contains ( & ClientIoMessage ::BroadcastMessage ( prevote_current ) ) ) ;
assert! ( test_io . received . read ( ) . contains ( & ClientIoMessage ::BroadcastMessage ( precommit_current ) ) ) ;
assert! ( test_io . received . read ( ) . contains ( & ClientIoMessage ::BroadcastMessage ( prevote_future ) ) ) ;
2016-12-10 16:50:23 +01:00
engine . stop ( ) ;
2016-12-09 20:48:05 +01:00
}
2016-08-23 12:58:40 +02:00
#[ test ]
2016-12-09 20:48:05 +01:00
fn seal_submission ( ) {
2016-11-24 20:59:08 +01:00
let ( spec , tap ) = setup ( ) ;
let engine = spec . engine . clone ( ) ;
2016-11-21 19:54:16 +01:00
let mut db_result = get_temp_state_db ( ) ;
let mut db = db_result . take ( ) ;
2016-11-30 15:30:21 +01:00
spec . ensure_db_good ( & mut db , & TrieFactory ::new ( TrieSpec ::Secure ) ) . unwrap ( ) ;
2016-11-24 20:59:08 +01:00
2016-12-05 14:24:22 +01:00
let v0 = insert_and_register ( & tap , & engine , " 0 " ) ;
let v1 = insert_and_register ( & tap , & engine , " 1 " ) ;
2016-09-07 16:25:42 +02:00
2016-11-28 10:42:50 +01:00
let h = 1 ;
let r = 0 ;
2016-12-09 20:48:05 +01:00
// Register IoHandler remembers messages.
2016-12-12 17:20:20 +01:00
let test_io = TestIo ::new ( ) ;
2016-12-15 16:52:39 +01:00
let channel = IoChannel ::to_handler ( Arc ::downgrade ( & ( test_io . clone ( ) as Arc < IoHandler < ClientIoMessage > > ) ) ) ;
engine . register_message_channel ( channel ) ;
2016-12-09 20:48:05 +01:00
2016-12-12 17:20:20 +01:00
// Propose
let ( b , mut seal ) = propose_default ( & spec , v1 . clone ( ) ) ;
let proposal = Some ( b . header ( ) . bare_hash ( ) ) ;
engine . step ( ) ;
2016-12-09 20:48:05 +01:00
// Prevote.
vote ( & engine , | mh | tap . sign ( v1 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Prevote , proposal ) ;
vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Prevote , proposal ) ;
vote ( & engine , | mh | tap . sign ( v1 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
2016-12-10 16:50:23 +01:00
seal [ 2 ] = precommit_signatures ( & tap , h , r , Some ( b . header ( ) . bare_hash ( ) ) , v1 , v0 ) ;
2016-12-15 16:52:39 +01:00
let first = test_io . received . read ( ) . contains ( & ClientIoMessage ::SubmitSeal ( proposal . unwrap ( ) , seal . clone ( ) ) ) ;
seal [ 2 ] = precommit_signatures ( & tap , h , r , Some ( b . header ( ) . bare_hash ( ) ) , v0 , v1 ) ;
let second = test_io . received . read ( ) . contains ( & ClientIoMessage ::SubmitSeal ( proposal . unwrap ( ) , seal ) ) ;
assert! ( first ^ second ) ;
2016-12-10 16:50:23 +01:00
engine . stop ( ) ;
2016-08-23 12:58:40 +02:00
}
}