2017-01-25 18:51:41 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-08-23 12:58:40 +02:00
// 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.
2017-01-24 22:03:03 +01:00
/// At each blockchain `Height` there can be multiple `View`s of voting.
/// Signatures always sign `Height`, `View`, `Step` and `BlockHash` which is a block hash without seal.
2016-12-08 20:09:30 +01:00
/// First a block with `Seal::Proposal` is issued by the designated proposer.
2017-01-24 22:03:03 +01:00
/// Next the `View` 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 `View`.
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-09-29 16:32:49 +02:00
mod params ;
2016-09-29 15:44:42 +02:00
2017-01-10 12:23:59 +01:00
use std ::sync ::Weak ;
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 ::* ;
2017-01-10 12:23:59 +01:00
use client ::{ Client , EngineClient } ;
2016-11-07 12:34:45 +01:00
use error ::{ Error , BlockError } ;
2017-04-19 14:30:00 +02:00
use header ::{ Header , BlockNumber } ;
2016-11-07 12:34:45 +01:00
use builtin ::Builtin ;
2017-03-22 14:41:46 +01:00
use rlp ::UntrustedRlp ;
2017-01-24 10:03:58 +01:00
use ethkey ::{ recover , public_to_address , Signature } ;
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 } ;
2017-01-05 21:16:13 +01:00
use state ::CleanupMode ;
2017-01-10 12:23:59 +01:00
use io ::IoService ;
2017-01-20 13:25:17 +01:00
use super ::signer ::EngineSigner ;
2017-05-22 08:21:34 +02:00
use super ::validator_set ::ValidatorSet ;
2017-01-24 22:03:03 +01:00
use super ::transition ::TransitionHandler ;
use super ::vote_collector ::VoteCollector ;
2016-11-21 17:02:26 +01:00
use self ::message ::* ;
2016-09-29 16:32:49 +02:00
use self ::params ::TendermintParams ;
2016-08-31 18:18:02 +02:00
2017-01-11 17:56:50 +01:00
#[ derive(Debug, PartialEq, Eq, Clone, Copy, Hash) ]
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 ;
2017-01-24 22:03:03 +01:00
pub type View = usize ;
2016-09-29 15:44:42 +02:00
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 ,
2017-01-10 12:23:59 +01:00
gas_limit_bound_divisor : U256 ,
2016-08-23 12:58:40 +02:00
builtins : BTreeMap < Address , Builtin > ,
2016-11-16 19:01:09 +01:00
step_service : IoService < Step > ,
2017-01-10 12:23:59 +01:00
client : RwLock < Option < Weak < EngineClient > > > ,
block_reward : U256 ,
2017-03-02 12:25:55 +01:00
registrar : Address ,
2016-11-15 11:21:18 +01:00
/// Blockchain height.
height : AtomicUsize ,
2017-01-24 22:03:03 +01:00
/// Consensus view.
view : AtomicUsize ,
2016-09-05 17:51:29 +02:00
/// Consensus step.
2016-11-15 11:21:18 +01:00
step : RwLock < Step > ,
/// Vote accumulator.
2017-01-24 22:03:03 +01:00
votes : VoteCollector < ConsensusMessage > ,
2016-11-18 00:36:24 +01:00
/// Used to sign messages and proposals.
2017-01-20 13:25:17 +01:00
signer : EngineSigner ,
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 > > ,
2017-01-24 22:03:03 +01:00
/// Last lock view.
2016-11-18 13:27:00 +01:00
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 > > ,
2017-03-08 14:41:24 +01:00
/// Hash of the proposal parent block.
proposal_parent : RwLock < H256 > ,
2017-04-10 20:03:18 +02:00
/// Last block proposed by this validator.
last_proposed : RwLock < H256 > ,
2017-01-10 12:23:59 +01:00
/// Set used to determine the current validators.
2017-03-23 13:19:28 +01:00
validators : Box < ValidatorSet > ,
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 ,
2017-01-10 12:23:59 +01:00
gas_limit_bound_divisor : our_params . gas_limit_bound_divisor ,
2016-09-05 17:51:29 +02:00
builtins : builtins ,
2017-01-10 12:23:59 +01:00
client : RwLock ::new ( None ) ,
2016-12-27 12:53:56 +01:00
step_service : IoService ::< Step > ::start ( ) ? ,
2017-01-10 12:23:59 +01:00
block_reward : our_params . block_reward ,
2017-03-02 12:25:55 +01:00
registrar : our_params . registrar ,
2016-11-28 10:42:50 +01:00
height : AtomicUsize ::new ( 1 ) ,
2017-01-24 22:03:03 +01:00
view : AtomicUsize ::new ( 0 ) ,
2016-11-15 11:21:18 +01:00
step : RwLock ::new ( Step ::Propose ) ,
2017-03-08 14:41:24 +01:00
votes : Default ::default ( ) ,
2017-01-20 13:25:17 +01:00
signer : Default ::default ( ) ,
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 ) ,
2017-03-08 14:41:24 +01:00
proposal_parent : Default ::default ( ) ,
2017-04-10 20:03:18 +02:00
last_proposed : Default ::default ( ) ,
2017-05-22 08:21:34 +02:00
validators : our_params . validators ,
2016-09-05 17:51:29 +02:00
} ) ;
2017-01-24 22:03:03 +01:00
let handler = TransitionHandler ::new ( Arc ::downgrade ( & engine ) as Weak < Engine > , Box ::new ( our_params . timeouts ) ) ;
2016-12-27 12:53:56 +01:00
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 ) {
2017-01-10 12:23:59 +01:00
if let Some ( ref weak ) = * self . client . read ( ) {
if let Some ( c ) = weak . upgrade ( ) {
c . update_sealing ( ) ;
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 > ) {
2017-01-10 12:23:59 +01:00
if let Some ( ref weak ) = * self . client . read ( ) {
if let Some ( c ) = weak . upgrade ( ) {
c . submit_seal ( block_hash , seal ) ;
2016-11-16 16:56:16 +01:00
}
}
}
2016-11-28 16:24:22 +01:00
fn broadcast_message ( & self , message : Bytes ) {
2017-01-10 12:23:59 +01:00
if let Some ( ref weak ) = * self . client . read ( ) {
if let Some ( c ) = weak . upgrade ( ) {
c . broadcast_consensus_message ( message ) ;
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 > {
2017-01-18 18:49:50 +01:00
let h = self . height . load ( AtomicOrdering ::SeqCst ) ;
2017-01-24 22:03:03 +01:00
let r = self . view . load ( AtomicOrdering ::SeqCst ) ;
2017-02-24 10:26:56 +01:00
let s = * self . step . read ( ) ;
let vote_info = message_info_rlp ( & VoteStep ::new ( h , r , s ) , block_hash ) ;
2017-01-20 13:25:17 +01:00
match self . signer . sign ( vote_info . sha3 ( ) ) . map ( Into ::into ) {
2017-01-18 18:49:50 +01:00
Ok ( signature ) = > {
let message_rlp = message_full_rlp ( & signature , & vote_info ) ;
2017-02-24 10:26:56 +01:00
let message = ConsensusMessage ::new ( signature , h , r , s , block_hash ) ;
2017-01-20 13:25:17 +01:00
let validator = self . signer . address ( ) ;
self . votes . vote ( message . clone ( ) , & validator ) ;
2017-02-02 19:11:43 +01:00
debug! ( target : " engine " , " Generated {:?} as {}. " , message , validator ) ;
2017-01-18 18:49:50 +01:00
self . handle_valid_message ( & message ) ;
Some ( message_rlp )
} ,
Err ( e ) = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Could not sign the message {} " , e ) ;
2017-01-18 18:49:50 +01:00
None
} ,
2016-11-18 00:36:24 +01:00
}
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 ) {
2017-01-24 22:03:03 +01:00
for m in self . votes . get_up_to ( & VoteStep ::new ( self . height . load ( AtomicOrdering ::SeqCst ) , self . view . load ( AtomicOrdering ::SeqCst ) , Step ::Precommit ) ) . into_iter ( ) {
2016-12-04 20:43:24 +01:00
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 ;
2017-02-02 19:11:43 +01:00
debug! ( target : " engine " , " 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 ) ;
2017-01-24 22:03:03 +01:00
self . view . store ( 0 , AtomicOrdering ::SeqCst ) ;
2016-12-04 20:43:24 +01:00
* self . lock_change . write ( ) = None ;
2017-04-10 20:03:18 +02:00
* self . proposal . write ( ) = None ;
2016-12-04 20:43:24 +01:00
}
/// 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 ) {
2017-02-02 19:11:43 +01:00
warn! ( target : " engine " , " Could not proceed to step {}. " , io_err )
2016-12-10 16:50:23 +01:00
}
2016-11-16 19:01:09 +01:00
* self . step . write ( ) = step ;
match step {
2016-11-17 14:26:57 +01:00
Step ::Propose = > {
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 ( ) {
2017-01-24 22:03:03 +01:00
Some ( ref m ) if ! self . should_unlock ( m . vote_step . view ) = > m . block_hash ,
2016-12-02 21:04:12 +01:00
_ = > 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 = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " to_step: Precommit. " ) ;
2016-11-18 13:27:00 +01:00
let block_hash = match * self . lock_change . read ( ) {
2017-01-24 22:03:03 +01:00
Some ( ref m ) if self . is_view ( m ) & & m . block_hash . is_some ( ) = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Setting last lock: {} " , m . vote_step . view ) ;
2017-01-24 22:03:03 +01:00
self . last_lock . store ( m . vote_step . view , AtomicOrdering ::SeqCst ) ;
2016-11-18 13:27:00 +01:00
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 = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " to_step: Commit. " ) ;
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 {
2017-03-08 14:41:24 +01:00
self . validators . contains ( & * self . proposal_parent . read ( ) , address )
2016-08-26 19:27:50 +02:00
}
2017-04-10 20:03:18 +02:00
fn check_above_threshold ( & self , n : usize ) -> Result < ( ) , EngineError > {
let threshold = self . validators . count ( & * self . proposal_parent . read ( ) ) * 2 / 3 ;
if n > threshold {
Ok ( ( ) )
} else {
Err ( EngineError ::BadSealFieldSize ( OutOfBounds {
min : Some ( threshold ) ,
max : None ,
found : n
} ) )
}
2016-08-24 11:58:49 +02:00
}
2016-09-05 17:51:29 +02:00
2017-01-24 22:03:03 +01:00
/// Find the designated for the given view.
2017-03-08 14:41:24 +01:00
fn view_proposer ( & self , bh : & H256 , height : Height , view : View ) -> Address {
2017-01-24 22:03:03 +01:00
let proposer_nonce = height + view ;
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Proposer nonce: {} " , proposer_nonce ) ;
2017-03-08 14:41:24 +01:00
self . validators . get ( bh , proposer_nonce )
2017-01-20 13:25:17 +01:00
}
2017-01-24 22:03:03 +01:00
/// Check if address is a proposer for given view.
2017-04-10 20:03:18 +02:00
fn check_view_proposer ( & self , bh : & H256 , height : Height , view : View , address : & Address ) -> Result < ( ) , EngineError > {
2017-03-08 14:41:24 +01:00
let proposer = self . view_proposer ( bh , height , view ) ;
2017-01-10 12:23:59 +01:00
if proposer = = * address {
2016-11-24 14:57:54 +01:00
Ok ( ( ) )
} else {
2017-01-10 12:23:59 +01:00
Err ( EngineError ::NotProposer ( Mismatch { expected : proposer , found : address . clone ( ) } ) )
2016-11-24 14:57:54 +01:00
}
2016-11-15 11:21:18 +01:00
}
2017-01-20 13:25:17 +01:00
/// Check if current signer is the current proposer.
2017-03-08 14:41:24 +01:00
fn is_signer_proposer ( & self , bh : & H256 ) -> bool {
let proposer = self . view_proposer ( bh , self . height . load ( AtomicOrdering ::SeqCst ) , self . view . load ( AtomicOrdering ::SeqCst ) ) ;
2017-01-20 13:25:17 +01:00
self . signer . is_address ( & proposer )
2016-12-04 20:43:24 +01:00
}
2016-11-18 14:38:04 +01:00
fn is_height ( & self , message : & ConsensusMessage ) -> bool {
2017-01-30 21:08:36 +01:00
message . vote_step . is_height ( self . height . load ( AtomicOrdering ::SeqCst ) )
2016-11-16 11:29:54 +01:00
}
2017-01-24 22:03:03 +01:00
fn is_view ( & self , message : & ConsensusMessage ) -> bool {
2017-01-30 21:08:36 +01:00
message . vote_step . is_view ( self . height . load ( AtomicOrdering ::SeqCst ) , self . view . load ( AtomicOrdering ::SeqCst ) )
2016-11-18 13:27:00 +01:00
}
2017-01-24 22:03:03 +01:00
fn increment_view ( & self , n : View ) {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " increment_view: New view. " ) ;
2017-01-24 22:03:03 +01:00
self . view . fetch_add ( n , AtomicOrdering ::SeqCst ) ;
2016-11-18 14:38:04 +01:00
}
2017-01-24 22:03:03 +01:00
fn should_unlock ( & self , lock_change_view : View ) -> bool {
self . last_lock . load ( AtomicOrdering ::SeqCst ) < lock_change_view
& & lock_change_view < self . view . load ( AtomicOrdering ::SeqCst )
2016-11-18 14:38:04 +01:00
}
2016-11-16 11:29:54 +01:00
fn has_enough_any_votes ( & self ) -> bool {
2017-01-24 22:03:03 +01:00
let step_votes = self . votes . count_round_votes ( & VoteStep ::new ( self . height . load ( AtomicOrdering ::SeqCst ) , self . view . load ( AtomicOrdering ::SeqCst ) , * self . step . read ( ) ) ) ;
2017-04-10 20:03:18 +02:00
self . check_above_threshold ( step_votes ) . is_ok ( )
2016-11-16 19:01:09 +01:00
}
2017-01-11 17:56:50 +01:00
fn has_enough_future_step_votes ( & self , vote_step : & VoteStep ) -> bool {
2017-01-24 22:03:03 +01:00
if vote_step . view > self . view . load ( AtomicOrdering ::SeqCst ) {
let step_votes = self . votes . count_round_votes ( vote_step ) ;
2017-04-10 20:03:18 +02:00
self . check_above_threshold ( step_votes ) . is_ok ( )
2016-11-22 17:05:27 +01:00
} 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 ) ;
2017-04-10 20:03:18 +02:00
self . check_above_threshold ( aligned_count ) . is_ok ( )
2016-11-15 11:21:18 +01:00
}
2016-12-02 21:04:12 +01:00
fn handle_valid_message ( & self , message : & ConsensusMessage ) {
2017-01-11 17:56:50 +01:00
let ref vote_step = message . vote_step ;
2016-12-02 21:04:12 +01:00
let is_newer_than_lock = match * self . lock_change . read ( ) {
2017-01-11 17:56:50 +01:00
Some ( ref lock ) = > vote_step > & lock . vote_step ,
2016-12-02 21:04:12 +01:00
None = > true ,
} ;
2016-12-12 17:20:20 +01:00
let lock_change = is_newer_than_lock
2017-01-11 17:56:50 +01:00
& & vote_step . step = = Step ::Prevote
2016-12-02 21:04:12 +01:00
& & message . block_hash . is_some ( )
2016-12-12 17:20:20 +01:00
& & self . has_enough_aligned_votes ( message ) ;
if lock_change {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " handle_valid_message: Lock change. " ) ;
2017-04-10 20:03:18 +02:00
* self . lock_change . write ( ) = Some ( message . clone ( ) ) ;
2016-12-02 21:04:12 +01:00
}
// Check if it can affect the step transition.
if self . is_height ( message ) {
let next_step = match * self . step . read ( ) {
2017-04-10 20:03:18 +02:00
Step ::Precommit if message . block_hash . is_none ( ) & & self . has_enough_aligned_votes ( message ) = > {
self . increment_view ( 1 ) ;
Some ( Step ::Propose )
} ,
2016-12-02 21:04:12 +01:00
Step ::Precommit if self . has_enough_aligned_votes ( message ) = > {
2017-04-10 20:03:18 +02:00
let bh = message . block_hash . expect ( " previous guard ensures is_some; qed " ) ;
if * self . last_proposed . read ( ) = = bh {
// Commit the block using a complete signature set.
// Generate seal and remove old votes.
let precommits = self . votes . round_signatures ( vote_step , & bh ) ;
trace! ( target : " engine " , " Collected seal: {:?} " , precommits ) ;
let seal = vec! [
::rlp ::encode ( & vote_step . view ) . to_vec ( ) ,
::rlp ::NULL_RLP . to_vec ( ) ,
::rlp ::encode_list ( & precommits ) . to_vec ( )
] ;
self . submit_seal ( bh , seal ) ;
self . votes . throw_out_old ( & vote_step ) ;
2016-12-02 21:04:12 +01:00
}
2017-04-10 20:03:18 +02:00
self . to_next_height ( self . height . load ( AtomicOrdering ::SeqCst ) ) ;
Some ( Step ::Commit )
2016-12-02 21:04:12 +01:00
} ,
2017-01-11 17:56:50 +01:00
Step ::Precommit if self . has_enough_future_step_votes ( & vote_step ) = > {
2017-01-24 22:03:03 +01:00
self . increment_view ( vote_step . view - self . view . load ( AtomicOrdering ::SeqCst ) ) ;
2016-12-02 21:04:12 +01:00
Some ( Step ::Precommit )
} ,
2017-02-02 19:11:43 +01:00
// Avoid counting votes twice.
2016-12-12 17:20:20 +01:00
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 ) ,
2017-01-11 17:56:50 +01:00
Step ::Prevote if self . has_enough_future_step_votes ( & vote_step ) = > {
2017-01-24 22:03:03 +01:00
self . increment_view ( vote_step . view - self . view . load ( AtomicOrdering ::SeqCst ) ) ;
2016-12-02 21:04:12 +01:00
Some ( Step ::Prevote )
} ,
_ = > None ,
} ;
if let Some ( step ) = next_step {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " 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 " }
2017-03-02 12:25:55 +01:00
2016-08-23 12:58:40 +02:00
fn version ( & self ) -> SemanticVersion { SemanticVersion ::new ( 1 , 0 , 0 ) }
2017-03-02 12:25:55 +01:00
2017-01-24 22:03:03 +01:00
/// (consensus view, proposal signature, authority signatures)
2016-10-05 15:33:07 +02:00
fn seal_fields ( & self ) -> usize { 3 }
2016-08-23 12:58:40 +02:00
fn params ( & self ) -> & CommonParams { & self . params }
2017-03-02 12:25:55 +01:00
fn additional_params ( & self ) -> HashMap < String , String > { hash_map! [ " registrar " . to_owned ( ) = > self . registrar . hex ( ) ] }
2016-08-23 12:58:40 +02:00
fn builtins ( & self ) -> & BTreeMap < Address , Builtin > { & self . builtins }
2016-12-07 09:32:36 +01:00
fn maximum_uncle_count ( & self ) -> usize { 0 }
2017-03-02 12:25:55 +01:00
2016-12-07 09:32:36 +01:00
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 ( ) ,
2017-01-11 17:56:50 +01:00
" height " . into ( ) = > message . vote_step . height . to_string ( ) ,
2017-01-24 22:03:03 +01:00
" view " . into ( ) = > message . vote_step . view . to_string ( ) ,
2016-11-21 17:02:26 +01:00
" 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 populate_from_parent ( & self , header : & mut Header , parent : & Header , gas_floor_target : U256 , _gas_ceil_target : U256 ) {
2017-01-24 22:03:03 +01:00
// Chain scoring: total weight is sqrt(U256::max_value())*height - view
let new_difficulty = U256 ::from ( U128 ::max_value ( ) ) + consensus_view ( parent ) . expect ( " Header has been verified; qed " ) . into ( ) - self . view . load ( AtomicOrdering ::SeqCst ) . into ( ) ;
2017-01-23 15:27:11 +01:00
header . set_difficulty ( new_difficulty ) ;
2016-08-31 18:43:24 +02:00
header . set_gas_limit ( {
let gas_limit = parent . gas_limit ( ) . clone ( ) ;
2017-01-10 12:23:59 +01:00
let bound_divisor = self . gas_limit_bound_divisor ;
2016-08-23 12:58:40 +02:00
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.
2017-02-20 16:35:53 +01:00
fn seals_internally ( & self ) -> Option < bool > {
2017-03-08 14:41:24 +01:00
Some ( self . signer . address ( ) ! = Address ::default ( ) )
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 {
2017-01-18 18:49:50 +01:00
let header = block . header ( ) ;
let author = header . author ( ) ;
// Only proposer can generate seal if None was generated.
2017-03-08 14:41:24 +01:00
if ! self . is_signer_proposer ( header . parent_hash ( ) ) | | self . proposal . read ( ) . is_some ( ) {
2017-01-18 18:49:50 +01:00
return Seal ::None ;
}
2016-12-01 22:56:38 +01:00
2017-01-18 18:49:50 +01:00
let height = header . number ( ) as Height ;
2017-01-24 22:03:03 +01:00
let view = self . view . load ( AtomicOrdering ::SeqCst ) ;
2017-01-18 18:49:50 +01:00
let bh = Some ( header . bare_hash ( ) ) ;
2017-01-24 22:03:03 +01:00
let vote_info = message_info_rlp ( & VoteStep ::new ( height , view , Step ::Propose ) , bh . clone ( ) ) ;
2017-01-20 13:25:17 +01:00
if let Ok ( signature ) = self . signer . sign ( vote_info . sha3 ( ) ) . map ( Into ::into ) {
2017-01-18 18:49:50 +01:00
// Insert Propose vote.
2017-02-02 19:11:43 +01:00
debug! ( target : " engine " , " Submitting proposal {} at height {} view {}. " , header . bare_hash ( ) , height , view ) ;
2017-01-24 22:03:03 +01:00
self . votes . vote ( ConsensusMessage ::new ( signature , height , view , Step ::Propose , bh ) , author ) ;
2017-04-10 20:03:18 +02:00
// Remember the owned block.
* self . last_proposed . write ( ) = header . bare_hash ( ) ;
2017-01-18 18:49:50 +01:00
// Remember proposal for later seal submission.
* self . proposal . write ( ) = bh ;
2017-03-08 14:41:24 +01:00
* self . proposal_parent . write ( ) = header . parent_hash ( ) . clone ( ) ;
2017-01-18 18:49:50 +01:00
Seal ::Proposal ( vec! [
2017-01-24 22:03:03 +01:00
::rlp ::encode ( & view ) . to_vec ( ) ,
2017-01-18 18:49:50 +01:00
::rlp ::encode ( & signature ) . to_vec ( ) ,
::rlp ::EMPTY_LIST_RLP . to_vec ( )
] )
2016-10-05 15:33:07 +02:00
} else {
2017-02-02 19:11:43 +01:00
warn! ( target : " engine " , " 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
}
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-12-27 12:53:56 +01:00
let message : ConsensusMessage = rlp . as_val ( ) ? ;
2016-12-04 20:43:24 +01:00
if ! self . votes . is_old_or_known ( & message ) {
2016-12-27 12:53:56 +01:00
let sender = public_to_address ( & recover ( & message . signature . into ( ) , & rlp . at ( 1 ) ? . as_raw ( ) . sha3 ( ) ) ? ) ;
2016-11-29 11:55:24 +01:00
if ! self . is_authority ( & sender ) {
2017-04-10 20:03:18 +02:00
return Err ( EngineError ::NotAuthorized ( sender ) . into ( ) ) ;
2016-11-29 11:55:24 +01:00
}
2017-01-24 10:03:58 +01:00
self . broadcast_message ( rlp . as_raw ( ) . to_vec ( ) ) ;
2017-05-03 09:01:24 +02:00
if let Some ( double ) = self . votes . vote ( message . clone ( ) , & sender ) {
2017-06-28 13:17:36 +02:00
let height = message . vote_step . height as BlockNumber ;
self . validators . report_malicious ( & sender , height , height , ::rlp ::encode ( & double ) . to_vec ( ) ) ;
2017-04-10 20:03:18 +02:00
return Err ( EngineError ::DoubleVote ( sender ) . into ( ) ) ;
2017-01-11 17:56:50 +01:00
}
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Handling a valid {:?} from {}. " , message , 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
}
2017-01-05 21:16:13 +01:00
/// Apply the block reward on finalisation of the block.
2017-05-30 11:52:33 +02:00
fn on_close_block ( & self , block : & mut ExecutedBlock ) -> Result < ( ) , Error > {
2017-01-05 21:16:13 +01:00
let fields = block . fields_mut ( ) ;
// Bestow block reward
2017-02-26 13:10:50 +01:00
let res = fields . state . add_balance ( fields . header . author ( ) , & self . block_reward , CleanupMode ::NoEmpty )
. map_err ( ::error ::Error ::from )
. and_then ( | _ | fields . state . commit ( ) ) ;
2017-01-05 21:16:13 +01:00
// Commit state so that we can actually figure out the state root.
2017-05-30 11:52:33 +02:00
if let Err ( ref e ) = res {
2017-02-26 13:10:50 +01:00
warn! ( " Encountered error on closing block: {} " , e ) ;
2017-01-05 21:16:13 +01:00
}
2017-05-30 11:52:33 +02:00
res
2017-01-05 21:16:13 +01: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 ( ) {
2017-04-10 20:03:18 +02:00
// Either proposal or commit.
2017-06-28 09:36:42 +02:00
if ( header . seal ( ) [ 1 ] = = ::rlp ::NULL_RLP )
! = ( header . seal ( ) [ 2 ] = = ::rlp ::EMPTY_LIST_RLP ) {
2016-12-02 14:30:43 +01:00
Ok ( ( ) )
} else {
2017-04-10 20:03:18 +02:00
warn! ( target : " engine " , " verify_block_basic: Block is neither a Commit nor Proposal. " ) ;
Err ( BlockError ::InvalidSeal . into ( ) )
2016-12-02 14:30:43 +01:00
}
2016-09-30 13:22:46 +02:00
} else {
2017-04-10 20:03:18 +02:00
Err ( BlockError ::InvalidSealArity (
2016-09-30 13:22:46 +02:00
Mismatch { expected : self . seal_fields ( ) , found : seal_length }
2017-04-10 20:03:18 +02:00
) . into ( ) )
2016-08-23 12:58:40 +02:00
}
}
2017-03-08 14:41:24 +01:00
fn verify_block_unordered ( & self , _header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
Ok ( ( ) )
}
/// Verify validators and gas limit.
fn verify_block_family ( & self , header : & Header , parent : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2017-04-10 20:03:18 +02:00
if header . number ( ) = = 0 {
return Err ( BlockError ::RidiculousNumber ( OutOfBounds { min : Some ( 1 ) , max : None , found : header . number ( ) } ) . into ( ) ) ;
2016-12-01 22:56:38 +01:00
}
2016-12-02 14:30:43 +01:00
2017-04-10 20:03:18 +02:00
if let Ok ( proposal ) = ConsensusMessage ::new_proposal ( header ) {
let proposer = proposal . verify ( ) ? ;
if ! self . is_authority ( & proposer ) {
return Err ( EngineError ::NotAuthorized ( proposer ) . into ( ) ) ;
2016-12-01 22:56:38 +01:00
}
2017-04-10 20:03:18 +02:00
self . check_view_proposer ( header . parent_hash ( ) , proposal . vote_step . height , proposal . vote_step . view , & proposer ) ? ;
} else {
let vote_step = VoteStep ::new ( header . number ( ) as usize , consensus_view ( header ) ? , Step ::Precommit ) ;
let precommit_hash = message_hash ( vote_step . clone ( ) , header . bare_hash ( ) ) ;
let ref signatures_field = header . seal ( ) . get ( 2 ) . expect ( " block went through verify_block_basic; block has .seal_fields() fields; qed " ) ;
let mut origins = HashSet ::new ( ) ;
for rlp in UntrustedRlp ::new ( signatures_field ) . iter ( ) {
let precommit = ConsensusMessage {
signature : rlp . as_val ( ) ? ,
block_hash : Some ( header . bare_hash ( ) ) ,
vote_step : vote_step . clone ( ) ,
} ;
let address = match self . votes . get ( & precommit ) {
Some ( a ) = > a ,
None = > public_to_address ( & recover ( & precommit . signature . into ( ) , & precommit_hash ) ? ) ,
} ;
if ! self . validators . contains ( header . parent_hash ( ) , & address ) {
return Err ( EngineError ::NotAuthorized ( address . to_owned ( ) ) . into ( ) ) ;
}
2016-12-04 20:43:24 +01:00
2017-04-10 20:03:18 +02:00
if ! origins . insert ( address ) {
warn! ( target : " engine " , " verify_block_unordered: Duplicate signature from {} on the seal. " , address ) ;
return Err ( BlockError ::InvalidSeal . into ( ) ) ;
}
2016-12-02 14:30:43 +01:00
}
2016-08-23 12:58:40 +02:00
2017-04-10 20:03:18 +02:00
self . check_above_threshold ( origins . len ( ) ) ?
2016-08-23 12:58:40 +02:00
}
2017-01-10 12:23:59 +01:00
let gas_limit_divisor = self . 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 {
2017-06-28 13:17:36 +02:00
self . validators . report_malicious ( header . author ( ) , header . number ( ) , header . number ( ) , Default ::default ( ) ) ;
2017-04-10 20:03:18 +02:00
return Err ( BlockError ::InvalidGasLimit ( OutOfBounds { min : Some ( min_gas ) , max : Some ( max_gas ) , found : header . gas_limit ( ) . clone ( ) } ) . into ( ) ) ;
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 ( ( ) )
}
2017-01-18 18:49:50 +01:00
fn set_signer ( & self , ap : Arc < AccountProvider > , address : Address , password : String ) {
{
2017-01-20 13:25:17 +01:00
self . signer . set ( ap , address , password ) ;
2017-01-18 18:49:50 +01:00
}
2016-12-10 16:50:23 +01:00
self . to_step ( Step ::Propose ) ;
2016-11-30 13:59:33 +01:00
}
2017-01-24 10:03:58 +01:00
fn sign ( & self , hash : H256 ) -> Result < Signature , Error > {
self . signer . sign ( hash ) . map_err ( Into ::into )
}
2016-12-09 14:52:08 +01:00
fn stop ( & self ) {
self . step_service . stop ( )
}
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.
if signatures_len ! = 1 {
2016-12-08 20:09:30 +01:00
// New Commit received, skip to next height.
2017-04-10 20:03:18 +02:00
trace! ( target : " engine " , " Received a commit: {:?}. " , header . number ( ) ) ;
self . to_next_height ( header . number ( ) as usize ) ;
self . to_step ( Step ::Commit ) ;
2016-12-08 12:03:34 +01:00
return false ;
}
2017-04-10 20:03:18 +02: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
let proposer = proposal . verify ( ) . expect ( " block went through full verification; this Engine tries verify; qed " ) ;
2017-02-02 19:11:43 +01:00
debug! ( target : " engine " , " Received a new proposal {:?} from {}. " , proposal . vote_step , proposer ) ;
2017-01-24 22:03:03 +01:00
if self . is_view ( & proposal ) {
2016-12-08 12:03:34 +01:00
* self . proposal . write ( ) = proposal . block_hash . clone ( ) ;
2017-03-08 14:41:24 +01:00
* self . proposal_parent . write ( ) = header . parent_hash ( ) . clone ( ) ;
2016-12-08 12:03:34 +01:00
}
2017-01-11 17:56:50 +01:00
self . votes . vote ( proposal , & proposer ) ;
2016-12-08 12:03:34 +01:00
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 = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Propose timeout. " ) ;
2017-01-24 10:03:58 +01:00
if self . proposal . read ( ) . is_none ( ) {
// Report the proposer if no proposal was received.
2017-05-03 09:01:24 +02:00
let height = self . height . load ( AtomicOrdering ::SeqCst ) ;
let current_proposer = self . view_proposer ( & * self . proposal_parent . read ( ) , height , self . view . load ( AtomicOrdering ::SeqCst ) ) ;
2017-06-28 13:17:36 +02:00
self . validators . report_benign ( & current_proposer , height as BlockNumber , height as BlockNumber ) ;
2017-01-24 10:03:58 +01:00
}
2016-12-10 16:50:23 +01:00
Step ::Prevote
} ,
Step ::Prevote if self . has_enough_any_votes ( ) = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Prevote timeout. " ) ;
2016-12-10 16:50:23 +01:00
Step ::Precommit
} ,
Step ::Prevote = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " 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 ( ) = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Precommit timeout. " ) ;
2017-01-24 22:03:03 +01:00
self . increment_view ( 1 ) ;
2016-12-10 16:50:23 +01:00
Step ::Propose
} ,
Step ::Precommit = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Precommit timeout without enough votes. " ) ;
2016-12-10 16:50:23 +01:00
self . broadcast_old_messages ( ) ;
Step ::Precommit
} ,
Step ::Commit = > {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " Commit timeout. " ) ;
2016-12-10 16:50:23 +01:00
Step ::Propose
} ,
} ;
self . to_step ( next_step ) ;
}
2017-01-10 12:23:59 +01:00
fn register_client ( & self , client : Weak < Client > ) {
2017-04-10 20:03:18 +02:00
use client ::BlockChainClient ;
if let Some ( c ) = client . upgrade ( ) {
self . height . store ( c . chain_info ( ) . best_block_number as usize + 1 , AtomicOrdering ::SeqCst ) ;
}
2017-01-10 12:23:59 +01:00
* self . client . write ( ) = Some ( client . clone ( ) ) ;
2017-01-24 10:03:58 +01:00
self . validators . register_contract ( client ) ;
2016-11-18 00:36:24 +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-08-23 12:58:40 +02:00
use block ::* ;
2016-11-07 12:34:45 +01:00
use error ::{ Error , BlockError } ;
use header ::Header ;
2017-01-10 12:23:59 +01:00
use client ::chain_notify ::ChainNotify ;
use miner ::MinerService ;
2016-08-23 12:58:40 +02:00
use tests ::helpers ::* ;
use account_provider ::AccountProvider ;
use spec ::Spec ;
2016-12-08 12:03:34 +01:00
use engines ::{ Engine , EngineError , Seal } ;
2017-02-20 17:21:55 +01:00
use super ::* ;
2016-08-23 12:58:40 +02:00
2017-01-10 12:23:59 +01:00
/// Accounts inserted with "0" and "1" are validators. 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 , tap )
}
2017-01-10 12:23:59 +01:00
fn propose_default ( spec : & Spec , proposer : Address ) -> ( ClosedBlock , Vec < Bytes > ) {
2017-04-06 19:26:17 +02:00
let db = get_temp_state_db ( ) ;
let db = spec . ensure_db_good ( db , & Default ::default ( ) ) . unwrap ( ) ;
2016-11-24 20:59:08 +01:00
let genesis_header = spec . genesis_header ( ) ;
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
2017-06-28 13:17:36 +02:00
let b = OpenBlock ::new ( spec . engine . as_ref ( ) , Default ::default ( ) , false , db . boxed_clone ( ) , & genesis_header , last_hashes , proposer , ( 3141562. into ( ) , 31415620. into ( ) ) , vec! [ ] , false ) . unwrap ( ) ;
2017-01-10 12:23:59 +01:00
let b = b . close ( ) ;
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
}
2017-01-30 21:08:36 +01:00
fn vote < F > ( engine : & Engine , signer : F , height : usize , view : usize , step : Step , block_hash : Option < H256 > ) -> Bytes where F : FnOnce ( H256 ) -> Result < H520 , ::account_provider ::SignError > {
2017-01-24 22:03:03 +01:00
let mi = message_info_rlp ( & VoteStep ::new ( height , view , step ) , block_hash ) ;
2016-12-01 21:50:24 +01:00
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
}
2017-01-24 22:03:03 +01:00
fn proposal_seal ( tap : & Arc < AccountProvider > , header : & Header , view : View ) -> Vec < Bytes > {
2016-11-21 19:54:16 +01:00
let author = header . author ( ) ;
2017-01-24 22:03:03 +01:00
let vote_info = message_info_rlp ( & VoteStep ::new ( header . number ( ) as Height , view , Step ::Propose ) , Some ( header . bare_hash ( ) ) ) ;
2016-11-21 19:54:16 +01:00
let signature = tap . sign ( * author , None , vote_info . sha3 ( ) ) . unwrap ( ) ;
vec! [
2017-01-24 22:03:03 +01:00
::rlp ::encode ( & view ) . to_vec ( ) ,
2016-11-21 19:54:16 +01:00
::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-22 17:05:27 +01:00
fn insert_and_unlock ( tap : & Arc < AccountProvider > , acc : & str ) -> Address {
2017-05-19 17:06:36 +02:00
let addr = tap . insert_account ( acc . sha3 ( ) . into ( ) , acc ) . unwrap ( ) ;
2016-11-22 17:05:27 +01:00
tap . unlock_account_permanently ( addr , acc . into ( ) ) . unwrap ( ) ;
addr
}
2017-01-10 12:23:59 +01:00
fn insert_and_register ( tap : & Arc < AccountProvider > , engine : & Engine , acc : & str ) -> Address {
2016-12-05 14:24:22 +01:00
let addr = insert_and_unlock ( tap , acc ) ;
2017-01-18 18:49:50 +01:00
engine . set_signer ( tap . clone ( ) , addr . clone ( ) , acc . into ( ) ) ;
2016-11-30 15:30:21 +01:00
addr
}
2017-01-10 12:23:59 +01:00
#[ derive(Default) ]
struct TestNotify {
messages : RwLock < Vec < Bytes > > ,
2016-11-28 12:47:33 +01:00
}
2017-01-10 12:23:59 +01:00
impl ChainNotify for TestNotify {
fn broadcast ( & self , data : Vec < u8 > ) {
self . messages . write ( ) . push ( data ) ;
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 ;
2017-04-19 14:30:00 +02:00
let schedule = engine . schedule ( 10000000 ) ;
2016-08-23 12:58:40 +02:00
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 ;
2017-03-08 14:41:24 +01:00
let mut parent_header : Header = Header ::default ( ) ;
parent_header . set_gas_limit ( U256 ::from_str ( " 222222 " ) . unwrap ( ) ) ;
2016-11-22 17:05:27 +01:00
let mut header = Header ::default ( ) ;
2017-03-08 14:41:24 +01:00
header . set_number ( 1 ) ;
header . set_gas_limit ( U256 ::from_str ( " 222222 " ) . unwrap ( ) ) ;
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.
2017-03-08 14:41:24 +01:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
2016-11-22 17:05:27 +01:00
2017-03-08 14:41:24 +01:00
let validator = insert_and_unlock ( & tap , " 0 " ) ;
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.
2017-03-08 14:41:24 +01:00
match engine . verify_block_family ( & header , & parent_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.
2017-03-08 14:41:24 +01:00
match engine . verify_block_family ( & header , & parent_header , None ) {
2016-12-02 14:59:54 +01:00
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
2017-03-08 14:41:24 +01:00
let mut parent_header : Header = Header ::default ( ) ;
parent_header . set_gas_limit ( U256 ::from_str ( " 222222 " ) . unwrap ( ) ) ;
2016-11-24 14:57:54 +01:00
let mut header = Header ::default ( ) ;
2017-03-08 14:41:24 +01:00
header . set_number ( 2 ) ;
header . set_gas_limit ( U256 ::from_str ( " 222222 " ) . unwrap ( ) ) ;
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
2017-03-08 14:41:24 +01:00
let vote_info = message_info_rlp ( & VoteStep ::new ( 2 , 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 ( ) ;
2017-04-10 20:03:18 +02:00
seal [ 1 ] = ::rlp ::NULL_RLP . to_vec ( ) ;
2017-03-20 19:14:29 +01:00
seal [ 2 ] = ::rlp ::encode_list ( & vec! [ H520 ::from ( signature1 . clone ( ) ) ] ) . to_vec ( ) ;
2016-12-02 14:30:43 +01:00
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.
2017-03-08 14:41:24 +01:00
match engine . verify_block_family ( & header , & parent_header , None ) {
2016-12-02 14:30:43 +01:00
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 ( ) ;
2017-03-20 19:14:29 +01:00
seal [ 2 ] = ::rlp ::encode_list ( & 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
2017-03-08 14:41:24 +01:00
assert! ( engine . verify_block_family ( & header , & parent_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
2017-03-20 19:14:29 +01:00
seal [ 2 ] = ::rlp ::encode_list ( & 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.
2017-03-08 14:41:24 +01:00
match engine . verify_block_family ( & header , & parent_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
2017-01-10 12:23:59 +01:00
let proposer = insert_and_register ( & tap , spec . engine . as_ref ( ) , " 1 " ) ;
2016-09-07 16:25:42 +02:00
2016-11-24 20:59:08 +01:00
let ( b , seal ) = propose_default ( & spec , proposer ) ;
2017-01-10 12:23:59 +01:00
assert! ( b . lock ( ) . try_seal ( spec . engine . as_ref ( ) , seal ) . is_ok ( ) ) ;
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 ( ) ;
2017-01-10 12:23:59 +01:00
let proposer = insert_and_register ( & tap , spec . engine . as_ref ( ) , " 1 " ) ;
2016-12-09 20:48:05 +01:00
let ( b , seal ) = propose_default ( & spec , proposer ) ;
2017-01-10 12:23:59 +01:00
let sealed = b . lock ( ) . seal ( spec . engine . as_ref ( ) , seal ) . unwrap ( ) ;
2016-12-09 20:48:05 +01:00
assert! ( spec . engine . is_proposal ( sealed . header ( ) ) ) ;
}
#[ test ]
fn relays_messages ( ) {
let ( spec , tap ) = setup ( ) ;
let engine = spec . engine . clone ( ) ;
2017-01-11 12:16:47 +01:00
2017-02-02 19:11:43 +01:00
let v0 = insert_and_unlock ( & tap , " 0 " ) ;
2017-01-10 12:23:59 +01:00
let v1 = insert_and_register ( & tap , engine . as_ref ( ) , " 1 " ) ;
2016-12-09 20:48:05 +01:00
2017-01-18 18:49:50 +01:00
let h = 1 ;
2016-12-09 20:48:05 +01:00
let r = 0 ;
// Propose
let ( b , _ ) = propose_default ( & spec , v1 . clone ( ) ) ;
let proposal = Some ( b . header ( ) . bare_hash ( ) ) ;
2017-01-10 12:23:59 +01:00
let client = generate_dummy_client ( 0 ) ;
let notify = Arc ::new ( TestNotify ::default ( ) ) ;
client . add_notify ( notify . clone ( ) ) ;
engine . register_client ( Arc ::downgrade ( & client ) ) ;
2016-12-09 20:48:05 +01:00
2017-01-10 12:23:59 +01:00
let prevote_current = vote ( engine . as_ref ( ) , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Prevote , proposal ) ;
2016-12-09 20:48:05 +01:00
2017-01-10 12:23:59 +01:00
let precommit_current = vote ( engine . as_ref ( ) , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
2016-12-09 20:48:05 +01:00
2017-01-10 12:23:59 +01:00
let prevote_future = vote ( engine . as_ref ( ) , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h + 1 , r , Step ::Prevote , proposal ) ;
2016-12-09 20:48:05 +01:00
// Relays all valid present and future messages.
2017-01-10 12:23:59 +01:00
assert! ( notify . messages . read ( ) . contains ( & prevote_current ) ) ;
assert! ( notify . messages . read ( ) . contains ( & precommit_current ) ) ;
assert! ( notify . messages . read ( ) . contains ( & prevote_future ) ) ;
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 ( ) {
2017-01-10 12:23:59 +01:00
use ethkey ::{ Generator , Random } ;
use types ::transaction ::{ Transaction , Action } ;
use client ::BlockChainClient ;
2016-09-07 16:25:42 +02:00
2017-01-10 12:23:59 +01:00
let tap = Arc ::new ( AccountProvider ::transient_provider ( ) ) ;
// Accounts for signing votes.
let v0 = insert_and_unlock ( & tap , " 0 " ) ;
let v1 = insert_and_unlock ( & tap , " 1 " ) ;
2017-01-18 18:49:50 +01:00
let client = generate_dummy_client_with_spec_and_accounts ( Spec ::new_test_tendermint , Some ( tap . clone ( ) ) ) ;
let engine = client . engine ( ) ;
client . miner ( ) . set_engine_signer ( v1 . clone ( ) , " 1 " . into ( ) ) . unwrap ( ) ;
2017-01-10 12:23:59 +01:00
let notify = Arc ::new ( TestNotify ::default ( ) ) ;
client . add_notify ( notify . clone ( ) ) ;
engine . register_client ( Arc ::downgrade ( & client ) ) ;
2016-11-28 10:42:50 +01:00
2017-01-10 12:23:59 +01:00
let keypair = Random . generate ( ) . unwrap ( ) ;
let transaction = Transaction {
action : Action ::Create ,
value : U256 ::zero ( ) ,
data : " 3331600055 " . from_hex ( ) . unwrap ( ) ,
gas : U256 ::from ( 100_000 ) ,
gas_price : U256 ::zero ( ) ,
nonce : U256 ::zero ( ) ,
} . sign ( keypair . secret ( ) , None ) ;
client . miner ( ) . import_own_transaction ( client . as_ref ( ) , transaction . into ( ) ) . unwrap ( ) ;
2016-12-12 17:20:20 +01:00
// Propose
2017-01-10 12:23:59 +01:00
let proposal = Some ( client . miner ( ) . pending_block ( ) . unwrap ( ) . header . bare_hash ( ) ) ;
// Propose timeout
2016-12-12 17:20:20 +01:00
engine . step ( ) ;
2017-01-10 12:23:59 +01:00
let h = 1 ;
let r = 0 ;
2016-12-09 20:48:05 +01:00
// Prevote.
2017-01-10 12:23:59 +01:00
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 ) ;
2016-12-09 20:48:05 +01:00
2017-01-10 12:23:59 +01:00
assert_eq! ( client . chain_info ( ) . best_block_number , 0 ) ;
// Last precommit.
vote ( engine , | mh | tap . sign ( v0 , None , mh ) . map ( H520 ::from ) , h , r , Step ::Precommit , proposal ) ;
assert_eq! ( client . chain_info ( ) . best_block_number , 1 ) ;
2016-08-23 12:58:40 +02:00
}
}