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 ::* ;
2016-11-15 11:21:18 +01:00
use basic_types ::Seal ;
2016-11-07 12:34:45 +01:00
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-09-29 15:44:42 +02:00
use self ::message ::ConsensusMessage ;
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-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 > ,
2016-09-05 17:51:29 +02:00
/// Used to swith proposer.
proposer_nonce : AtomicUsize ,
2016-11-15 11:21:18 +01:00
/// 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-15 11:21:18 +01:00
height : AtomicUsize ::new ( 0 ) ,
round : AtomicUsize ::new ( 0 ) ,
step : RwLock ::new ( Step ::Propose ) ,
proposer_nonce : AtomicUsize ::new ( 0 ) ,
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 ) {
Ok ( _ ) = > trace! ( target : " poa " , " timeout: UpdateSealing message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " timeout: Could not send a sealing message {}. " , err ) ,
}
}
}
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 ) ) {
Ok ( _ ) = > trace! ( target : " poa " , " timeout: SubmitSeal message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " timeout: Could not send a sealing message {}. " , err ) ,
}
}
}
2016-11-18 00:36:24 +01:00
fn broadcast_message ( & self , block_hash : Option < BlockHash > ) {
if let Some ( message ) = self . generate_message ( block_hash ) {
if let Some ( ref channel ) = * self . message_channel . lock ( ) {
match channel . send ( ClientIoMessage ::BroadcastMessage ( message ) ) {
Ok ( _ ) = > trace! ( target : " poa " , " timeout: BroadcastMessage message sent. " ) ,
Err ( err ) = > warn! ( target : " poa " , " timeout: Could not send a sealing message {}. " , err ) ,
}
2016-11-17 13:18:20 +01:00
}
2016-11-18 00:36:24 +01:00
} else {
warn! ( target : " poa " , " broadcast_message: Message could not be generated. " ) ;
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 ( ) {
ConsensusMessage ::new_rlp (
| mh | ap . sign ( * self . authority . read ( ) , None , mh ) . ok ( ) . map ( H520 ::from ) ,
self . height . load ( AtomicOrdering ::SeqCst ) ,
self . round . load ( AtomicOrdering ::SeqCst ) ,
* self . step . read ( ) ,
block_hash
)
} else {
None
}
2016-11-17 18:12:37 +01:00
}
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-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-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 ,
} ;
self . broadcast_message ( block_hash )
2016-11-17 13:18:20 +01:00
} ,
Step ::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
} ;
self . broadcast_message ( block_hash ) ;
2016-11-17 13:18:20 +01:00
} ,
Step ::Commit = > {
// Commit the block using a complete signature set.
let round = self . round . load ( AtomicOrdering ::SeqCst ) ;
2016-11-18 13:27:00 +01:00
if let Some ( seal ) = self . votes . seal_signatures ( self . height . load ( AtomicOrdering ::SeqCst ) , round , * self . proposal . read ( ) ) {
2016-11-17 13:18:20 +01:00
let seal = vec! [
::rlp ::encode ( & round ) . to_vec ( ) ,
2016-11-18 13:27:00 +01:00
::rlp ::encode ( & seal . proposal ) . to_vec ( ) ,
::rlp ::encode ( & seal . votes ) . to_vec ( )
2016-11-17 13:18:20 +01:00
] ;
2016-11-17 18:12:37 +01:00
if let Some ( block_hash ) = * self . proposal . read ( ) {
self . submit_seal ( block_hash , seal ) ;
}
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 nonce_proposer ( & self , proposer_nonce : usize ) -> & Address {
2016-08-23 12:58:40 +02:00
let ref p = self . our_params ;
2016-11-18 14:38:04 +01:00
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-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-08-24 11:58:49 +02:00
fn threshold ( & self ) -> usize {
2016-11-15 11:21:18 +01:00
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.
fn is_proposer ( & self , address : & Address ) -> bool {
self . is_nonce_proposer ( self . proposer_nonce . 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 ) {
self . proposer_nonce . fetch_add ( n , AtomicOrdering ::SeqCst ) ;
self . round . fetch_add ( n , AtomicOrdering ::SeqCst ) ;
}
fn reset_round ( & self ) {
self . last_lock . store ( 0 , AtomicOrdering ::SeqCst ) ;
self . proposer_nonce . fetch_add ( 1 , 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-16 19:01:09 +01:00
self . votes . count_step_votes ( self . height . load ( AtomicOrdering ::SeqCst ) , self . round . load ( AtomicOrdering ::SeqCst ) , * self . step . read ( ) ) > self . threshold ( )
}
2016-11-18 14:38:04 +01:00
fn has_enough_future_step_votes ( & self , message : & ConsensusMessage ) -> bool {
message . round > self . round . load ( AtomicOrdering ::SeqCst )
& & self . votes . count_step_votes ( message . height , message . round , message . step ) > self . threshold ( )
2016-11-16 19:01:09 +01:00
}
fn has_enough_aligned_votes ( & self , message : & ConsensusMessage ) -> bool {
2016-11-17 18:12:37 +01:00
self . votes . aligned_votes ( & message ) . len ( ) > self . threshold ( )
2016-11-15 11:21:18 +01:00
}
}
2016-11-17 14:26:57 +01:00
/// Block hash including the consensus round, gets signed and included in the seal.
2016-11-15 11:21:18 +01:00
fn block_hash ( header : & Header ) -> H256 {
header . rlp ( Seal ::WithSome ( 1 ) ) . sha3 ( )
2016-08-23 12:58:40 +02:00
}
2016-11-16 11:29:54 +01:00
fn proposer_signature ( header : & Header ) -> Result < H520 , ::rlp ::DecoderError > {
UntrustedRlp ::new ( header . seal ( ) [ 1 ] . as_slice ( ) ) . as_val ( )
2016-11-15 12:27:09 +01:00
}
2016-11-16 11:29:54 +01:00
fn consensus_round ( header : & Header ) -> Result < Round , ::rlp ::DecoderError > {
UntrustedRlp ::new ( header . seal ( ) [ 0 ] . as_slice ( ) ) . as_val ( )
2016-11-15 12:27:09 +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 > {
map! [
2016-11-16 11:29:54 +01:00
" signature " . into ( ) = > proposer_signature ( header ) . as_ref ( ) . map ( ToString ::to_string ) . unwrap_or ( " " . into ( ) ) ,
2016-11-15 12:27:09 +01:00
" height " . into ( ) = > header . number ( ) . to_string ( ) ,
2016-11-16 11:29:54 +01:00
" round " . into ( ) = > consensus_round ( header ) . as_ref ( ) . map ( ToString ::to_string ) . unwrap_or ( " " . into ( ) ) ,
" block_hash " . into ( ) = > block_hash ( header ) . to_string ( )
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
/// Set the correct round in the seal.
fn on_close_block ( & self , block : & mut ExecutedBlock ) {
let round = self . round . load ( AtomicOrdering ::SeqCst ) ;
2016-11-15 14:33:11 +01:00
block . fields_mut ( ) . header . set_seal ( vec! [ ::rlp ::encode ( & round ) . to_vec ( ) , Vec ::new ( ) , Vec ::new ( ) ] ) ;
2016-11-15 11:21:18 +01:00
}
/// Round proposer switching.
fn is_sealer ( & self , address : & Address ) -> Option < bool > {
Some ( self . is_proposer ( address ) )
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-17 13:18:20 +01:00
if let Ok ( signature ) = ap . sign ( * author , None , block_hash ( header ) ) {
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 ( ) ,
::rlp ::encode ( & H520 ::from ( signature ) ) . to_vec ( ) ,
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 ( ) ) ;
let sender = public_to_address ( & try ! ( recover ( & message . signature . into ( ) , & try ! ( rlp . at ( 1 ) ) . as_raw ( ) . sha3 ( ) ) ) ) ;
// TODO: Do not admit old messages.
if ! self . is_authority ( & sender ) {
try ! ( Err ( BlockError ::InvalidSeal ) ) ;
2016-10-11 19:37:31 +02:00
}
2016-11-17 18:12:37 +01:00
// Check if the message is known.
if self . votes . vote ( message . clone ( ) , sender ) . is_none ( ) {
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-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 {
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-16 11:29:54 +01:00
let signature = try ! ( proposer_signature ( header ) ) ;
let proposer = public_to_address ( & try ! ( recover ( & signature . into ( ) , & block_hash ( header ) ) ) ) ;
2016-11-15 11:21:18 +01:00
if ! self . is_proposer ( & proposer ) {
2016-09-06 12:26:06 +02:00
try ! ( Err ( BlockError ::InvalidSeal ) )
}
2016-11-15 11:21:18 +01:00
let proposal = ConsensusMessage {
2016-11-16 11:29:54 +01:00
signature : signature ,
2016-11-15 12:27:09 +01:00
height : header . number ( ) as Height ,
2016-11-16 11:29:54 +01:00
round : try ! ( consensus_round ( header ) ) ,
2016-11-15 11:21:18 +01:00
step : Step ::Propose ,
block_hash : Some ( block_hash ( header ) )
} ;
self . votes . vote ( proposal , proposer ) ;
let votes_rlp = UntrustedRlp ::new ( & header . seal ( ) [ 2 ] ) ;
for rlp in votes_rlp . iter ( ) {
let sig : H520 = try ! ( rlp . as_val ( ) ) ;
let address = public_to_address ( & try ! ( recover ( & sig . into ( ) , & block_hash ( header ) ) ) ) ;
2016-11-16 11:29:54 +01:00
if ! self . our_params . authorities . contains ( & address ) {
2016-11-15 11:21:18 +01:00
try ! ( Err ( BlockError ::InvalidSeal ) )
}
}
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
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-08-31 18:18:02 +02:00
use std ::thread ::sleep ;
2016-09-05 17:51:29 +02:00
use std ::time ::{ Duration } ;
2016-11-07 12:34:45 +01:00
use util ::* ;
2016-11-15 11:21:18 +01:00
use rlp ::{ UntrustedRlp , RlpStream , Stream , View } ;
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 ;
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 ( ) ;
2016-11-07 12:34:45 +01:00
let sig0 = tap . sign ( v0 , Some ( " 0 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
2016-11-15 11:21:18 +01:00
seal . push ( ::rlp ::encode ( & ( & * sig0 as & [ u8 ] ) ) . to_vec ( ) ) ;
2016-09-07 16:25:42 +02:00
let v1 = tap . insert_account ( " 1 " . sha3 ( ) , " 1 " ) . unwrap ( ) ;
2016-11-07 12:34:45 +01:00
let sig1 = tap . sign ( v1 , Some ( " 1 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
2016-11-15 11:21:18 +01:00
seal . push ( ::rlp ::encode ( & ( & * sig1 as & [ u8 ] ) ) . to_vec ( ) ) ;
2016-09-07 16:25:42 +02:00
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 ( ) ;
2016-11-07 12:34:45 +01:00
let sig1 = tap . sign ( v1 , Some ( " 0 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
2016-11-15 11:21:18 +01:00
seal . push ( ::rlp ::encode ( & ( & * sig1 as & [ u8 ] ) ) . to_vec ( ) ) ;
2016-09-07 16:25:42 +02:00
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 ( ) ;
2016-11-07 12:34:45 +01:00
let sig2 = tap . sign ( v2 , Some ( " 101 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
2016-11-15 11:21:18 +01:00
seal . push ( ::rlp ::encode ( & ( & * sig2 as & [ u8 ] ) ) . to_vec ( ) ) ;
2016-09-07 16:25:42 +02:00
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
}