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 ;
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-11-17 18:12:37 +01:00
use engines ::{ Engine , 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-09-29 15:44:42 +02:00
pub type Height = usize ;
pub type Round = usize ;
pub type BlockHash = H256 ;
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-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-11-17 14:26:57 +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-11-17 14:26:57 +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-11-28 16:50:55 +01:00
Ok ( _ ) = > trace! ( target : " poa " , " update_sealing: UpdateSealing message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " update_sealing: 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-11-28 16:50:55 +01:00
Ok ( _ ) = > trace! ( target : " poa " , " submit_seal: SubmitSeal message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " submit_seal: 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 ) {
if let Some ( ref channel ) = * self . message_channel . lock ( ) {
match channel . send ( ClientIoMessage ::BroadcastMessage ( message ) ) {
2016-11-28 16:50:55 +01:00
Ok ( _ ) = > trace! ( target : " poa " , " broadcast_message: BroadcastMessage message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " broadcast_message: Could not send a sealing message {}. " , err ) ,
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-11-21 12:36:07 +01:00
message_full_rlp (
2016-11-30 13:59:33 +01:00
| mh | ap . sign ( * self . authority . read ( ) , self . password . read ( ) . clone ( ) , mh ) . ok ( ) . map ( H520 ::from ) ,
2016-11-18 00:36:24 +01:00
self . height . load ( AtomicOrdering ::SeqCst ) ,
self . round . load ( AtomicOrdering ::SeqCst ) ,
* self . step . read ( ) ,
block_hash
)
} else {
2016-11-25 17:45:32 +01:00
warn! ( target : " poa " , " generate_message: 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-11-16 19:01:09 +01:00
fn to_step ( & self , step : Step ) {
* self . step . write ( ) = step ;
match step {
2016-11-17 14:26:57 +01:00
Step ::Propose = > {
2016-11-25 17:45:32 +01:00
trace! ( target : " poa " , " to_step: Transitioning to 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-25 17:45:32 +01:00
trace! ( target : " poa " , " to_step: Transitioning to Prevote. " ) ;
2016-11-18 13:27:00 +01:00
let block_hash = match * self . lock_change . read ( ) {
2016-11-18 14:38:04 +01:00
Some ( ref m ) if self . should_unlock ( m . round ) = > self . proposal . read ( ) . clone ( ) ,
2016-11-18 13:27:00 +01:00
Some ( ref m ) = > m . block_hash ,
None = > None ,
} ;
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-11-25 17:45:32 +01:00
trace! ( target : " poa " , " to_step: Transitioning to Precommit. " ) ;
2016-11-18 13:27:00 +01:00
let block_hash = match * self . lock_change . read ( ) {
Some ( ref m ) if self . is_round ( m ) = > {
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-11-25 17:45:32 +01:00
trace! ( target : " poa " , " to_step: Transitioning to 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-11-28 19:58:15 +01:00
if let Some ( block_hash ) = * self . proposal . read ( ) {
if let Some ( seal ) = self . votes . seal_signatures ( self . height . load ( AtomicOrdering ::SeqCst ) , round , block_hash ) {
let seal = vec! [
::rlp ::encode ( & round ) . to_vec ( ) ,
::rlp ::encode ( & seal . proposal ) . to_vec ( ) ,
::rlp ::encode ( & seal . votes ) . to_vec ( )
] ;
2016-11-17 18:12:37 +01:00
self . submit_seal ( block_hash , seal ) ;
2016-11-28 19:58:15 +01:00
} else {
warn! ( target : " poa " , " Proposal was not found! " ) ;
2016-11-17 18:12:37 +01:00
}
2016-11-17 13:18:20 +01:00
}
2016-11-18 13:27:00 +01:00
* self . lock_change . write ( ) = None ;
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-11-15 11:21:18 +01:00
/// Round proposer switching.
2016-11-29 13:51:27 +01:00
fn is_proposer ( & self , address : & Address ) -> Result < ( ) , EngineError > {
2016-11-22 17:05:27 +01:00
let ref p = self . our_params ;
2016-11-30 17:02:05 +01:00
let proposer_nonce = self . height . load ( AtomicOrdering ::SeqCst ) + self . round . load ( AtomicOrdering ::SeqCst ) ;
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-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 ) {
self . round . fetch_add ( n , AtomicOrdering ::SeqCst ) ;
}
fn reset_round ( & self ) {
self . last_lock . store ( 0 , AtomicOrdering ::SeqCst ) ;
self . height . fetch_add ( 1 , AtomicOrdering ::SeqCst ) ;
self . round . store ( 0 , 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-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`.
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 {
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 ) {
2016-11-17 18:12:37 +01:00
* self . authority . write ( ) = * block . header ( ) . author ( )
2016-10-05 15:33:07 +02:00
}
2016-11-15 11:21:18 +01:00
/// Round proposer switching.
fn is_sealer ( & self , address : & Address ) -> Option < bool > {
2016-11-24 14:57:54 +01:00
Some ( self . is_proposer ( address ) . is_ok ( ) )
2016-10-11 19:37:31 +02:00
}
2016-08-23 12:58:40 +02:00
/// Attempt to seal the block internally using all available signatures.
2016-11-18 00:36:24 +01:00
fn generate_seal ( & self , block : & ExecutedBlock ) -> Option < Vec < Bytes > > {
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-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 ( ) ) ;
let vote_info = message_info_rlp ( height , round , Step ::Propose , bh ) ;
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-11-28 19:58:15 +01:00
self . votes . vote ( ConsensusMessage { signature : signature , height : height , round : round , step : Step ::Propose , block_hash : bh } , * author ) ;
2016-11-17 18:12:37 +01:00
* self . proposal . write ( ) = Some ( header . bare_hash ( ) ) ;
2016-11-17 13:18:20 +01:00
Some ( vec! [
::rlp ::encode ( & self . round . load ( AtomicOrdering ::SeqCst ) ) . to_vec ( ) ,
2016-11-28 19:58:15 +01:00
::rlp ::encode ( & signature ) . to_vec ( ) ,
2016-11-17 13:18:20 +01:00
Vec ::new ( )
] )
} else {
warn! ( target : " poa " , " generate_seal: FAIL: accounts secret key unavailable " ) ;
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 " ) ;
None
2016-10-05 15:33:07 +02:00
}
2016-08-23 12:58:40 +02:00
}
2016-11-17 13:18:20 +01:00
fn handle_message ( & self , rlp : UntrustedRlp ) -> Result < ( ) , Error > {
2016-11-15 11:21:18 +01:00
let message : ConsensusMessage = try ! ( rlp . as_val ( ) ) ;
2016-11-17 18:12:37 +01:00
// Check if the message is known.
2016-11-29 15:55:54 +01:00
if ! self . votes . is_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-25 17:45:32 +01:00
trace! ( target : " poa " , " handle_message: Processing new authorized message: {:?} " , & message ) ;
2016-11-29 15:55:54 +01:00
self . votes . vote ( message . clone ( ) , sender ) ;
2016-11-28 16:24:22 +01:00
self . broadcast_message ( rlp . as_raw ( ) . to_vec ( ) ) ;
2016-11-18 13:27:00 +01:00
let is_newer_than_lock = match * self . lock_change . read ( ) {
2016-11-18 00:36:24 +01:00
Some ( ref lock ) = > & message > lock ,
None = > true ,
} ;
2016-11-17 18:12:37 +01:00
if is_newer_than_lock
& & message . step = = Step ::Prevote
& & self . has_enough_aligned_votes ( & message ) {
2016-11-25 17:45:32 +01:00
trace! ( target : " poa " , " handle_message: Lock change. " ) ;
2016-11-18 13:27:00 +01:00
* self . lock_change . write ( ) = Some ( message . clone ( ) ) ;
2016-11-17 18:12:37 +01:00
}
2016-11-18 14:38:04 +01:00
// Check if it can affect the step transition.
if self . is_height ( & message ) {
2016-11-17 18:12:37 +01:00
let next_step = match * self . step . read ( ) {
Step ::Precommit if self . has_enough_aligned_votes ( & message ) = > {
if message . block_hash . is_none ( ) {
2016-11-18 14:38:04 +01:00
self . increment_round ( 1 ) ;
2016-11-17 18:12:37 +01:00
Some ( Step ::Propose )
} else {
Some ( Step ::Commit )
}
} ,
2016-11-18 14:38:04 +01:00
Step ::Precommit if self . has_enough_future_step_votes ( & message ) = > {
self . increment_round ( message . round - self . round . load ( AtomicOrdering ::SeqCst ) ) ;
2016-11-17 18:12:37 +01:00
Some ( Step ::Precommit )
} ,
Step ::Prevote if self . has_enough_aligned_votes ( & message ) = > Some ( Step ::Precommit ) ,
2016-11-18 14:38:04 +01:00
Step ::Prevote if self . has_enough_future_step_votes ( & message ) = > {
self . increment_round ( message . round - self . round . load ( AtomicOrdering ::SeqCst ) ) ;
2016-11-17 18:12:37 +01:00
Some ( Step ::Prevote )
} ,
_ = > None ,
} ;
if let Some ( step ) = next_step {
2016-11-28 10:42:50 +01:00
trace! ( target : " poa " , " handle_message: Transition triggered. " ) ;
2016-11-17 18:12:37 +01:00
if let Err ( io_err ) = self . step_service . send_message ( step ) {
warn! ( target : " poa " , " Could not proceed to next step {}. " , io_err )
2016-11-16 19:01:09 +01:00
}
2016-11-15 11:21:18 +01:00
}
2016-11-16 19:01:09 +01:00
}
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 ( ) {
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 > {
2016-11-21 17:02:26 +01:00
let proposal = try ! ( ConsensusMessage ::new_proposal ( header ) ) ;
let proposer = try ! ( proposal . verify ( ) ) ;
2016-11-24 14:57:54 +01:00
try ! ( self . is_proposer ( & proposer ) ) ;
2016-11-15 11:21:18 +01:00
self . votes . vote ( proposal , proposer ) ;
2016-11-21 17:02:26 +01:00
let block_info_hash = try ! ( message_info_rlp_from_header ( header ) ) . sha3 ( ) ;
2016-11-24 14:57:54 +01:00
2016-11-25 17:45:32 +01:00
// TODO: use addresses recovered during precommit vote
2016-11-24 14:57:54 +01:00
let mut signature_count = 0 ;
2016-11-21 17:02:26 +01:00
for rlp in UntrustedRlp ::new ( & header . seal ( ) [ 2 ] ) . iter ( ) {
let signature : H520 = try ! ( rlp . as_val ( ) ) ;
let address = public_to_address ( & try ! ( recover ( & signature . into ( ) , & block_info_hash ) ) ) ;
2016-11-16 11:29:54 +01:00
if ! self . our_params . authorities . contains ( & address ) {
2016-11-29 13:51:27 +01:00
try ! ( Err ( EngineError ::NotAuthorized ( address ) ) )
2016-11-15 11:21:18 +01:00
}
2016-11-24 14:57:54 +01:00
signature_count + = 1 ;
}
if signature_count > self . our_params . authority_n {
try ! ( Err ( BlockError ::InvalidSealArity ( Mismatch { expected : self . our_params . authority_n , found : signature_count } ) ) )
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
// 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
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-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-11-15 11:21:18 +01:00
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
2016-10-05 15:33:07 +02:00
}
2016-11-16 11:29:54 +01:00
fn register_message_channel ( & self , message_channel : IoChannel < ClientIoMessage > ) {
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 rlp ::{ UntrustedRlp , View } ;
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 ;
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 io ::IoService ;
use service ::ClientIoMessage ;
2016-08-23 12:58:40 +02:00
use spec ::Spec ;
2016-09-07 16:25:42 +02:00
use engines ::{ Engine , EngineError } ;
2016-11-21 19:54:16 +01:00
use super ::* ;
use super ::message ::* ;
2016-08-23 12:58:40 +02:00
2016-11-24 14:57:54 +01:00
/// Accounts inserted with "1" and "2" 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-11-24 20:59:08 +01:00
let seal = spec . engine . generate_seal ( b . block ( ) ) . unwrap ( ) ;
( b , seal )
2016-08-26 19:27:50 +02:00
}
2016-11-25 17:45:32 +01:00
fn vote < F > ( engine : & Arc < Engine > , signer : F , height : usize , round : usize , step : Step , block_hash : Option < H256 > ) where F : FnOnce ( H256 ) -> Option < H520 > {
let m = message_full_rlp ( signer , height , round , step , block_hash ) . unwrap ( ) ;
2016-11-21 19:54:16 +01:00
engine . handle_message ( UntrustedRlp ::new ( & m ) ) . unwrap ( ) ;
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 ( ) ,
Vec ::new ( )
]
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 {
let addr = tap . insert_account ( acc . sha3 ( ) , acc ) . unwrap ( ) ;
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-11-30 17:02:05 +01:00
let validator = insert_and_unlock ( & tap , " 1 " ) ;
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.
assert! ( engine . verify_block_unordered ( & header , None ) . is_ok ( ) ) ;
let mut header = Header ::default ( ) ;
let random = insert_and_unlock ( & tap , " 101 " ) ;
header . set_author ( random ) ;
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-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 ( ) ;
let proposer = insert_and_unlock ( & tap , " 0 " ) ;
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 14:57:54 +01:00
let voter = insert_and_unlock ( & tap , " 1 " ) ;
2016-11-24 20:59:08 +01:00
let vote_info = message_info_rlp ( 0 , 0 , Step ::Precommit , Some ( header . bare_hash ( ) ) ) ;
2016-11-24 14:57:54 +01:00
let signature = tap . sign ( voter , None , vote_info . sha3 ( ) ) . unwrap ( ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 20:59:08 +01:00
seal [ 2 ] = ::rlp ::encode ( & vec! [ H520 ::from ( signature . clone ( ) ) ] ) . to_vec ( ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 14:57:54 +01:00
header . set_seal ( seal . clone ( ) ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 14:57:54 +01:00
// One good signature.
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-11-24 20:59:08 +01:00
seal [ 2 ] = ::rlp ::encode ( & vec! [ H520 ::from ( signature ) , 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-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-08-24 15:55:47 +02:00
}
2016-08-23 12:58:40 +02:00
#[ test ]
2016-11-28 10:42:50 +01:00
fn step_transitioning ( ) {
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
let v0 = insert_and_unlock ( & tap , " 0 " ) ;
let v1 = insert_and_unlock ( & tap , " 1 " ) ;
2016-09-07 16:25:42 +02:00
2016-11-28 10:42:50 +01:00
let h = 1 ;
let r = 0 ;
2016-11-21 19:54:16 +01:00
// Propose
2016-11-30 17:02:05 +01:00
let ( b , mut seal ) = propose_default ( & spec , v1 . clone ( ) ) ;
2016-11-25 17:45:32 +01:00
let proposal = Some ( b . header ( ) . bare_hash ( ) ) ;
2016-11-28 12:47:33 +01:00
// Register IoHandler remembers messages.
2016-11-25 17:45:32 +01:00
let io_service = IoService ::< ClientIoMessage > ::start ( ) . unwrap ( ) ;
2016-11-28 12:47:33 +01:00
let test_io = TestIo ::new ( ) ;
io_service . register_handler ( test_io . clone ( ) ) . unwrap ( ) ;
2016-11-25 17:45:32 +01:00
engine . register_message_channel ( io_service . channel ( ) ) ;
2016-09-07 16:25:42 +02:00
// Prevote.
2016-11-25 17:45:32 +01:00
vote ( & engine , | mh | tap . sign ( v1 , None , mh ) . ok ( ) . map ( H520 ::from ) , h , r , Step ::Prevote , proposal ) ;
2016-09-07 16:25:42 +02:00
2016-11-25 17:45:32 +01:00
vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . ok ( ) . map ( H520 ::from ) , h , r , Step ::Prevote , proposal ) ;
2016-11-28 10:42:50 +01:00
vote ( & engine , | mh | tap . sign ( v1 , None , mh ) . ok ( ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
vote ( & engine , | mh | tap . sign ( v0 , None , mh ) . ok ( ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
2016-11-28 12:47:33 +01:00
2016-11-30 13:59:33 +01:00
// Wait a bit for async stuff.
2016-11-28 19:58:15 +01:00
::std ::thread ::sleep ( ::std ::time ::Duration ::from_millis ( 500 ) ) ;
2016-11-30 13:59:33 +01:00
seal [ 2 ] = precommit_signatures ( & tap , h , r , Some ( b . header ( ) . bare_hash ( ) ) , v0 , v1 ) ;
let first = test_io . received . read ( ) [ 5 ] = = ClientIoMessage ::SubmitSeal ( proposal . unwrap ( ) , seal . clone ( ) ) ;
seal [ 2 ] = precommit_signatures ( & tap , h , r , Some ( b . header ( ) . bare_hash ( ) ) , v1 , v0 ) ;
let second = test_io . received . read ( ) [ 5 ] = = ClientIoMessage ::SubmitSeal ( proposal . unwrap ( ) , seal ) ;
assert! ( first ^ second ) ;
2016-08-23 12:58:40 +02:00
}
2016-11-30 17:02:05 +01:00
#[ test ]
fn timeout_transitioning ( ) {
::env_logger ::init ( ) . unwrap ( ) ;
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 v = insert_and_register ( & tap , & engine , " 0 " ) ;
::std ::thread ::sleep ( ::std ::time ::Duration ::from_millis ( 15000 ) ) ;
println! ( " done " ) ;
}
2016-08-23 12:58:40 +02:00
}