2017-01-25 18:51:41 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-09-08 12:12:24 +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-11-02 18:42:56 +01:00
//! A blockchain engine that supports a non-instant BFT proof-of-authority.
2016-09-08 12:12:24 +02:00
2016-11-14 14:35:45 +01:00
use std ::sync ::atomic ::{ AtomicUsize , AtomicBool , Ordering as AtomicOrdering } ;
2017-07-29 21:56:42 +02:00
use std ::sync ::{ Weak , Arc } ;
2016-10-15 14:55:10 +02:00
use std ::time ::{ UNIX_EPOCH , Duration } ;
2017-07-29 17:12:07 +02:00
use std ::collections ::{ BTreeMap , HashSet , HashMap } ;
use std ::cmp ;
2017-06-28 13:17:36 +02:00
2016-09-08 12:12:24 +02:00
use account_provider ::AccountProvider ;
use block ::* ;
2016-10-26 18:50:04 +02:00
use builtin ::Builtin ;
2017-01-10 12:23:59 +01:00
use client ::{ Client , EngineClient } ;
2017-06-28 13:17:36 +02:00
use engines ::{ Call , Engine , Seal , EngineError , ConstructedVerifier } ;
use error ::{ Error , TransactionError , BlockError } ;
use ethjson ;
use header ::{ Header , BlockNumber } ;
use spec ::CommonParams ;
use transaction ::UnverifiedTransaction ;
2017-01-20 13:25:17 +01:00
use super ::signer ::EngineSigner ;
2017-04-13 20:24:21 +02:00
use super ::validator_set ::{ ValidatorSet , SimpleList , new_validator_set } ;
2016-09-08 12:12:24 +02:00
2017-06-28 13:17:36 +02:00
use self ::finality ::RollingFinality ;
use ethkey ::{ verify_address , Signature } ;
use io ::{ IoContext , IoHandler , TimerToken , IoService } ;
use itertools ::{ self , Itertools } ;
use rlp ::{ UntrustedRlp , encode } ;
use util ::* ;
mod finality ;
2016-09-08 12:12:24 +02:00
/// `AuthorityRound` params.
pub struct AuthorityRoundParams {
/// Time to wait before next block or authority switching.
2016-10-15 14:55:10 +02:00
pub step_duration : Duration ,
2016-12-06 19:23:15 +01:00
/// Starting step,
pub start_step : Option < u64 > ,
2017-01-10 12:23:59 +01:00
/// Valid validators.
2017-05-22 08:21:34 +02:00
pub validators : Box < ValidatorSet > ,
2017-03-28 10:46:52 +02:00
/// Chain score validation transition block.
pub validate_score_transition : u64 ,
2017-05-15 22:34:01 +02:00
/// Monotonic step validation transition block.
pub validate_step_transition : u64 ,
2017-06-28 13:17:36 +02:00
/// Immediate transitions.
pub immediate_transitions : bool ,
2016-09-08 12:12:24 +02:00
}
impl From < ethjson ::spec ::AuthorityRoundParams > for AuthorityRoundParams {
fn from ( p : ethjson ::spec ::AuthorityRoundParams ) -> Self {
AuthorityRoundParams {
2016-10-15 14:55:10 +02:00
step_duration : Duration ::from_secs ( p . step_duration . into ( ) ) ,
2017-05-22 08:21:34 +02:00
validators : new_validator_set ( p . validators ) ,
2016-12-06 19:23:15 +01:00
start_step : p . start_step . map ( Into ::into ) ,
2017-03-28 10:46:52 +02:00
validate_score_transition : p . validate_score_transition . map_or ( 0 , Into ::into ) ,
2017-05-15 22:34:01 +02:00
validate_step_transition : p . validate_step_transition . map_or ( 0 , Into ::into ) ,
2017-06-28 13:17:36 +02:00
immediate_transitions : p . immediate_transitions . unwrap_or ( false ) ,
2016-09-08 12:12:24 +02:00
}
}
}
2017-04-13 20:24:21 +02:00
// Helper for managing the step.
#[ derive(Debug) ]
struct Step {
calibrate : bool , // whether calibration is enabled.
inner : AtomicUsize ,
duration : Duration ,
}
impl Step {
fn load ( & self ) -> usize { self . inner . load ( AtomicOrdering ::SeqCst ) }
fn duration_remaining ( & self ) -> Duration {
let now = unix_now ( ) ;
let step_end = self . duration * ( self . load ( ) as u32 + 1 ) ;
if step_end > now {
step_end - now
} else {
Duration ::from_secs ( 0 )
}
}
fn increment ( & self ) {
self . inner . fetch_add ( 1 , AtomicOrdering ::SeqCst ) ;
}
fn calibrate ( & self ) {
if self . calibrate {
let new_step = unix_now ( ) . as_secs ( ) / self . duration . as_secs ( ) ;
self . inner . store ( new_step as usize , AtomicOrdering ::SeqCst ) ;
}
}
fn is_future ( & self , given : usize ) -> bool {
if given > self . load ( ) + 1 {
// Make absolutely sure that the given step is correct.
self . calibrate ( ) ;
given > self . load ( ) + 1
} else {
false
}
}
}
2017-06-28 13:17:36 +02:00
struct EpochManager {
epoch_transition_hash : H256 ,
epoch_transition_number : BlockNumber ,
finality_checker : RollingFinality ,
force : bool ,
}
impl EpochManager {
fn blank ( ) -> Self {
EpochManager {
epoch_transition_hash : H256 ::default ( ) ,
epoch_transition_number : 0 ,
finality_checker : RollingFinality ::blank ( Vec ::new ( ) ) ,
force : true ,
}
}
// zoom to epoch for given header. returns true if succeeded, false otherwise.
fn zoom_to ( & mut self , client : & EngineClient , engine : & Engine , validators : & ValidatorSet , header : & Header ) -> bool {
let last_was_parent = self . finality_checker . subchain_head ( ) = = Some ( header . parent_hash ( ) . clone ( ) ) ;
// early exit for current target == chain head, but only if the epochs are
// the same.
if last_was_parent & & ! self . force {
return true ;
}
self . force = false ;
debug! ( target : " engine " , " Zooming to epoch for block {} " , header . hash ( ) ) ;
// epoch_transition_for can be an expensive call, but in the absence of
// forks it will only need to be called for the block directly after
// epoch transition, in which case it will be O(1) and require a single
// DB lookup.
let last_transition = match client . epoch_transition_for ( * header . parent_hash ( ) ) {
Some ( t ) = > t ,
None = > {
// this really should never happen unless the block passed
// hasn't got a parent in the database.
debug! ( target : " engine " , " No genesis transition found. " ) ;
return false ;
}
} ;
// extract other epoch set if it's not the same as the last.
if last_transition . block_hash ! = self . epoch_transition_hash {
let ( signal_number , set_proof , _ ) = destructure_proofs ( & last_transition . proof )
. expect ( " proof produced by this engine; therefore it is valid; qed " ) ;
trace! ( target : " engine " , " extracting epoch set for epoch ({}, {}) signalled at #{} " ,
last_transition . block_number , last_transition . block_hash , signal_number ) ;
let first = signal_number = = 0 ;
let epoch_set = validators . epoch_set (
first ,
engine ,
signal_number , // use signal number so multi-set first calculation is correct.
set_proof ,
)
. ok ( )
. map ( | ( list , _ ) | list . into_inner ( ) )
. expect ( " proof produced by this engine; therefore it is valid; qed " ) ;
self . finality_checker = RollingFinality ::blank ( epoch_set ) ;
}
self . epoch_transition_hash = last_transition . block_hash ;
self . epoch_transition_number = last_transition . block_number ;
true
}
// note new epoch hash. this will force the next block to re-load
// the epoch set
// TODO: optimize and don't require re-loading after epoch change.
fn note_new_epoch ( & mut self ) {
self . force = true ;
}
/// Get validator set. Zoom to the correct epoch first.
fn validators ( & self ) -> & SimpleList {
self . finality_checker . validators ( )
}
}
2017-04-13 20:24:21 +02:00
/// Engine using `AuthorityRound` proof-of-authority BFT consensus.
2016-09-08 12:12:24 +02:00
pub struct AuthorityRound {
params : CommonParams ,
builtins : BTreeMap < Address , Builtin > ,
2016-12-07 14:49:07 +01:00
transition_service : IoService < ( ) > ,
2017-04-13 20:24:21 +02:00
step : Arc < Step > ,
2017-07-13 09:48:00 +02:00
can_propose : AtomicBool ,
2017-01-10 12:23:59 +01:00
client : RwLock < Option < Weak < EngineClient > > > ,
2017-07-13 09:48:00 +02:00
signer : RwLock < EngineSigner > ,
2017-03-23 13:19:28 +01:00
validators : Box < ValidatorSet > ,
2017-03-28 10:46:52 +02:00
validate_score_transition : u64 ,
2017-05-15 22:34:01 +02:00
validate_step_transition : u64 ,
2017-06-28 13:17:36 +02:00
epoch_manager : Mutex < EpochManager > ,
immediate_transitions : bool ,
2016-10-15 14:55:10 +02:00
}
2017-04-13 20:24:21 +02:00
// header-chain validator.
2017-04-18 14:19:10 +02:00
struct EpochVerifier {
2017-04-13 20:24:21 +02:00
step : Arc < Step > ,
subchain_validators : SimpleList ,
}
2017-04-18 14:19:10 +02:00
impl super ::EpochVerifier for EpochVerifier {
2017-04-13 20:24:21 +02:00
fn verify_light ( & self , header : & Header ) -> Result < ( ) , Error > {
// always check the seal since it's fast.
// nothing heavier to do.
2017-06-28 13:17:36 +02:00
verify_external ( header , & self . subchain_validators , & * self . step , | _ | { } )
}
fn check_finality_proof ( & self , proof : & [ u8 ] ) -> Option < Vec < H256 > > {
macro_rules ! otry {
( $e : expr ) = > {
match $e {
Some ( x ) = > x ,
None = > return None ,
}
}
}
let mut finality_checker = RollingFinality ::blank ( self . subchain_validators . clone ( ) . into_inner ( ) ) ;
let mut finalized = Vec ::new ( ) ;
let headers : Vec < Header > = otry! ( UntrustedRlp ::new ( proof ) . as_list ( ) . ok ( ) ) ;
for header in & headers {
// ensure all headers have correct number of seal fields so we can `verify_external`
// without panic.
//
// `verify_external` checks that signature is correct and author == signer.
if header . seal ( ) . len ( ) ! = 2 { return None }
otry! ( verify_external ( header , & self . subchain_validators , & * self . step , | _ | { } ) . ok ( ) ) ;
let newly_finalized = otry! ( finality_checker . push_hash ( header . hash ( ) , header . author ( ) . clone ( ) ) . ok ( ) ) ;
finalized . extend ( newly_finalized ) ;
}
if finalized . is_empty ( ) { None } else { Some ( finalized ) }
2017-04-13 20:24:21 +02:00
}
}
2017-06-28 13:17:36 +02:00
// Report misbehavior
#[ derive(Debug) ]
#[ allow(dead_code) ]
enum Report {
// Malicious behavior
Malicious ( Address , BlockNumber , Bytes ) ,
// benign misbehavior
Benign ( Address , BlockNumber ) ,
}
2016-11-14 18:42:56 +01:00
fn header_step ( header : & Header ) -> Result < usize , ::rlp ::DecoderError > {
2016-12-07 10:34:06 +01:00
UntrustedRlp ::new ( & header . seal ( ) . get ( 0 ) . expect ( " was either checked with verify_block_basic or is genesis; has 2 fields; qed (Make sure the spec file has a correct genesis seal) " ) ) . as_val ( )
2016-11-02 18:42:56 +01:00
}
2016-11-14 18:42:56 +01:00
fn header_signature ( header : & Header ) -> Result < Signature , ::rlp ::DecoderError > {
2016-12-07 10:34:06 +01:00
UntrustedRlp ::new ( & header . seal ( ) . get ( 1 ) . expect ( " was checked with verify_block_basic; has 2 fields; qed " ) ) . as_val ::< H520 > ( ) . map ( Into ::into )
2016-11-14 16:56:19 +01:00
}
2016-11-02 18:42:56 +01:00
2017-06-28 13:17:36 +02:00
fn step_proposer ( validators : & ValidatorSet , bh : & H256 , step : usize ) -> Address {
let proposer = validators . get ( bh , step ) ;
trace! ( target : " engine " , " Fetched proposer for step {}: {} " , step , proposer ) ;
proposer
}
fn is_step_proposer ( validators : & ValidatorSet , bh : & H256 , step : usize , address : & Address ) -> bool {
step_proposer ( validators , bh , step ) = = * address
}
fn verify_external < F : Fn ( Report ) > ( header : & Header , validators : & ValidatorSet , step : & Step , report : F )
-> Result < ( ) , Error >
{
2017-04-13 20:24:21 +02:00
let header_step = header_step ( header ) ? ;
// Give one step slack if step is lagging, double vote is still not possible.
if step . is_future ( header_step ) {
2017-07-13 09:48:00 +02:00
trace! ( target : " engine " , " verify_block_external: block from the future " ) ;
2017-06-28 13:17:36 +02:00
report ( Report ::Benign ( * header . author ( ) , header . number ( ) ) ) ;
2017-04-13 20:24:21 +02:00
Err ( BlockError ::InvalidSeal ) ?
} else {
let proposer_signature = header_signature ( header ) ? ;
let correct_proposer = validators . get ( header . parent_hash ( ) , header_step ) ;
2017-06-12 11:54:34 +02:00
let is_invalid_proposer = * header . author ( ) ! = correct_proposer | |
! verify_address ( & correct_proposer , & proposer_signature , & header . bare_hash ( ) ) ? ;
if is_invalid_proposer {
2017-07-13 09:48:00 +02:00
trace! ( target : " engine " , " verify_block_external: bad proposer for step: {} " , header_step ) ;
2017-04-13 20:24:21 +02:00
Err ( EngineError ::NotProposer ( Mismatch { expected : correct_proposer , found : header . author ( ) . clone ( ) } ) ) ?
} else {
Ok ( ( ) )
}
}
}
2017-06-28 13:17:36 +02:00
fn combine_proofs ( signal_number : BlockNumber , set_proof : & [ u8 ] , finality_proof : & [ u8 ] ) -> Vec < u8 > {
let mut stream = ::rlp ::RlpStream ::new_list ( 3 ) ;
stream . append ( & signal_number ) . append ( & set_proof ) . append ( & finality_proof ) ;
stream . out ( )
}
fn destructure_proofs ( combined : & [ u8 ] ) -> Result < ( BlockNumber , & [ u8 ] , & [ u8 ] ) , Error > {
let rlp = UntrustedRlp ::new ( combined ) ;
Ok ( (
rlp . at ( 0 ) ? . as_val ( ) ? ,
rlp . at ( 1 ) ? . data ( ) ? ,
rlp . at ( 2 ) ? . data ( ) ? ,
) )
}
2016-10-15 14:55:10 +02:00
trait AsMillis {
fn as_millis ( & self ) -> u64 ;
}
impl AsMillis for Duration {
fn as_millis ( & self ) -> u64 {
self . as_secs ( ) * 1_000 + ( self . subsec_nanos ( ) / 1_000_000 ) as u64
}
2016-09-08 12:12:24 +02:00
}
impl AuthorityRound {
2016-10-15 14:55:10 +02:00
/// Create a new instance of AuthorityRound engine.
2016-11-14 18:42:56 +01:00
pub fn new ( params : CommonParams , our_params : AuthorityRoundParams , builtins : BTreeMap < Address , Builtin > ) -> Result < Arc < Self > , Error > {
2016-12-15 23:36:06 +01:00
let should_timeout = our_params . start_step . is_none ( ) ;
2016-12-06 19:23:15 +01:00
let initial_step = our_params . start_step . unwrap_or_else ( | | ( unix_now ( ) . as_secs ( ) / our_params . step_duration . as_secs ( ) ) ) as usize ;
2016-09-08 12:12:24 +02:00
let engine = Arc ::new (
AuthorityRound {
params : params ,
builtins : builtins ,
2016-12-27 12:53:56 +01:00
transition_service : IoService ::< ( ) > ::start ( ) ? ,
2017-04-13 20:24:21 +02:00
step : Arc ::new ( Step {
inner : AtomicUsize ::new ( initial_step ) ,
calibrate : our_params . start_step . is_none ( ) ,
duration : our_params . step_duration ,
} ) ,
2017-07-13 09:48:00 +02:00
can_propose : AtomicBool ::new ( true ) ,
2017-01-10 12:23:59 +01:00
client : RwLock ::new ( None ) ,
2017-01-20 13:25:17 +01:00
signer : Default ::default ( ) ,
2017-05-22 08:21:34 +02:00
validators : our_params . validators ,
2017-03-28 10:46:52 +02:00
validate_score_transition : our_params . validate_score_transition ,
2017-05-15 22:34:01 +02:00
validate_step_transition : our_params . validate_step_transition ,
2017-06-28 13:17:36 +02:00
epoch_manager : Mutex ::new ( EpochManager ::blank ( ) ) ,
immediate_transitions : our_params . immediate_transitions ,
2016-09-08 12:12:24 +02:00
} ) ;
2017-06-28 13:17:36 +02:00
2016-12-15 23:36:06 +01:00
// Do not initialize timeouts for tests.
if should_timeout {
let handler = TransitionHandler { engine : Arc ::downgrade ( & engine ) } ;
2016-12-27 12:53:56 +01:00
engine . transition_service . register_handler ( Arc ::new ( handler ) ) ? ;
2016-12-15 23:36:06 +01:00
}
2016-11-14 18:42:56 +01:00
Ok ( engine )
2016-09-08 12:12:24 +02:00
}
}
2016-10-15 14:55:10 +02:00
fn unix_now ( ) -> Duration {
UNIX_EPOCH . elapsed ( ) . expect ( " Valid time has to be set in your system. " )
}
2016-09-08 12:12:24 +02:00
struct TransitionHandler {
engine : Weak < AuthorityRound > ,
}
2016-11-01 19:12:06 +01:00
const ENGINE_TIMEOUT_TOKEN : TimerToken = 23 ;
2016-09-08 12:12:24 +02:00
2016-12-07 14:49:07 +01:00
impl IoHandler < ( ) > for TransitionHandler {
fn initialize ( & self , io : & IoContext < ( ) > ) {
2016-09-08 12:12:24 +02:00
if let Some ( engine ) = self . engine . upgrade ( ) {
2017-04-13 20:24:21 +02:00
let remaining = engine . step . duration_remaining ( ) ;
io . register_timer_once ( ENGINE_TIMEOUT_TOKEN , remaining . as_millis ( ) )
2017-02-02 19:11:43 +01:00
. unwrap_or_else ( | e | warn! ( target : " engine " , " Failed to start consensus step timer: {}. " , e ) )
2016-09-08 12:12:24 +02:00
}
}
2016-12-07 14:49:07 +01:00
fn timeout ( & self , io : & IoContext < ( ) > , timer : TimerToken ) {
2016-09-08 12:12:24 +02:00
if timer = = ENGINE_TIMEOUT_TOKEN {
if let Some ( engine ) = self . engine . upgrade ( ) {
2016-12-06 19:23:15 +01:00
engine . step ( ) ;
2017-04-13 20:24:21 +02:00
let remaining = engine . step . duration_remaining ( ) ;
io . register_timer_once ( ENGINE_TIMEOUT_TOKEN , remaining . as_millis ( ) )
2017-02-02 19:11:43 +01:00
. unwrap_or_else ( | e | warn! ( target : " engine " , " Failed to restart consensus step timer: {}. " , e ) )
2016-09-08 12:12:24 +02:00
}
}
}
}
impl Engine for AuthorityRound {
fn name ( & self ) -> & str { " AuthorityRound " }
2017-03-02 12:25:55 +01:00
2016-09-08 12:12:24 +02:00
fn version ( & self ) -> SemanticVersion { SemanticVersion ::new ( 1 , 0 , 0 ) }
2017-03-02 12:25:55 +01:00
2016-10-15 14:55:10 +02:00
/// Two fields - consensus step and the corresponding proposer signature.
2016-09-19 18:00:39 +02:00
fn seal_fields ( & self ) -> usize { 2 }
2016-09-08 12:12:24 +02:00
fn params ( & self ) -> & CommonParams { & self . params }
2017-03-02 12:25:55 +01:00
2017-07-31 12:34:29 +02:00
fn additional_params ( & self ) -> HashMap < String , String > {
hash_map! [ " registrar " . to_owned ( ) = > self . params ( ) . registrar . hex ( ) ]
}
2017-03-02 12:25:55 +01:00
2016-09-08 12:12:24 +02:00
fn builtins ( & self ) -> & BTreeMap < Address , Builtin > { & self . builtins }
2016-12-06 19:23:15 +01:00
fn step ( & self ) {
2017-04-13 20:24:21 +02:00
self . step . increment ( ) ;
2017-07-13 09:48:00 +02:00
self . can_propose . store ( true , AtomicOrdering ::SeqCst ) ;
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-12-06 19:23:15 +01:00
}
}
}
2016-09-08 12:12:24 +02:00
/// Additional engine-specific information for the user/developer concerning `header`.
2016-11-15 12:10:32 +01:00
fn extra_info ( & self , header : & Header ) -> BTreeMap < String , String > {
map! [
" step " . into ( ) = > header_step ( header ) . as_ref ( ) . map ( ToString ::to_string ) . unwrap_or ( " " . into ( ) ) ,
" signature " . into ( ) = > header_signature ( header ) . as_ref ( ) . map ( ToString ::to_string ) . unwrap_or ( " " . into ( ) )
]
}
2016-09-08 12:12:24 +02:00
fn populate_from_parent ( & self , header : & mut Header , parent : & Header , gas_floor_target : U256 , _gas_ceil_target : U256 ) {
2017-01-23 15:27:11 +01:00
// Chain scoring: total weight is sqrt(U256::max_value())*height - step
2017-04-13 20:24:21 +02:00
let new_difficulty = U256 ::from ( U128 ::max_value ( ) ) + header_step ( parent ) . expect ( " Header has been verified; qed " ) . into ( ) - self . step . load ( ) . into ( ) ;
2017-01-23 15:27:11 +01:00
header . set_difficulty ( new_difficulty ) ;
2016-09-08 12:12:24 +02:00
header . set_gas_limit ( {
let gas_limit = parent . gas_limit ( ) . clone ( ) ;
2017-07-31 12:34:29 +02:00
let bound_divisor = self . params ( ) . gas_limit_bound_divisor ;
2016-09-08 12:12:24 +02:00
if gas_limit < gas_floor_target {
2017-07-29 17:12:07 +02:00
cmp ::min ( gas_floor_target , gas_limit + gas_limit / bound_divisor - 1. into ( ) )
2016-09-08 12:12:24 +02:00
} else {
2017-07-29 17:12:07 +02:00
cmp ::max ( gas_floor_target , gas_limit - gas_limit / bound_divisor + 1. into ( ) )
2016-09-08 12:12:24 +02:00
}
} ) ;
}
2017-02-20 16:35:53 +01:00
fn seals_internally ( & self ) -> Option < bool > {
2017-07-13 09:48:00 +02:00
Some ( self . signer . read ( ) . is_some ( ) )
2016-09-14 17:28:15 +02:00
}
2016-09-08 12:12:24 +02:00
/// Attempt to seal the block internally.
///
2017-07-26 17:25:32 +02:00
/// This operation is synchronous and may (quite reasonably) not be available, in which case
/// `Seal::None` will be returned.
2016-12-08 12:03:34 +01:00
fn generate_seal ( & self , block : & ExecutedBlock ) -> Seal {
2017-06-22 20:44:04 +02:00
// first check to avoid generating signature most of the time
// (but there's still a race to the `compare_and_swap`)
2017-07-13 09:48:00 +02:00
if ! self . can_propose . load ( AtomicOrdering ::SeqCst ) { return Seal ::None ; }
2017-06-22 20:44:04 +02:00
2016-09-08 16:27:54 +02:00
let header = block . header ( ) ;
2017-04-13 20:24:21 +02:00
let step = self . step . load ( ) ;
2017-06-28 13:17:36 +02:00
// fetch correct validator set for current epoch, taking into account
// finality of previous transitions.
let active_set ;
let validators = if self . immediate_transitions {
& * self . validators
} else {
let mut epoch_manager = self . epoch_manager . lock ( ) ;
let client = match self . client . read ( ) . as_ref ( ) . and_then ( | weak | weak . upgrade ( ) ) {
Some ( client ) = > client ,
None = > {
warn! ( target : " engine " , " Unable to generate seal: missing client ref. " ) ;
return Seal ::None ;
}
} ;
if ! epoch_manager . zoom_to ( & * client , self , & * self . validators , header ) {
debug! ( target : " engine " , " Unable to zoom to epoch. " ) ;
return Seal ::None ;
}
active_set = epoch_manager . validators ( ) . clone ( ) ;
& active_set as & _
} ;
if is_step_proposer ( validators , header . parent_hash ( ) , step , header . author ( ) ) {
2017-07-13 09:48:00 +02:00
if let Ok ( signature ) = self . sign ( header . bare_hash ( ) ) {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " generate_seal: Issuing a block for step {}. " , step ) ;
2017-06-22 20:44:04 +02:00
// only issue the seal if we were the first to reach the compare_and_swap.
2017-07-13 09:48:00 +02:00
if self . can_propose . compare_and_swap ( true , false , AtomicOrdering ::SeqCst ) {
2017-06-28 14:16:53 +02:00
return Seal ::Regular ( vec! [ encode ( & step ) . into_vec ( ) , encode ( & ( & H520 ::from ( signature ) as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-06-22 20:44:04 +02:00
}
2016-09-08 12:12:24 +02:00
} else {
2017-02-02 19:11:43 +01:00
warn! ( target : " engine " , " generate_seal: FAIL: Accounts secret key unavailable. " ) ;
2016-09-08 12:12:24 +02:00
}
2016-12-06 19:23:15 +01:00
} else {
2017-06-28 13:17:36 +02:00
trace! ( target : " engine " , " generate_seal: {} not a proposer for step {}. " ,
header . author ( ) , step ) ;
2016-09-08 12:12:24 +02:00
}
2016-12-08 12:03:34 +01:00
Seal ::None
2016-09-08 12:12:24 +02:00
}
2017-06-28 13:17:36 +02:00
fn on_new_block (
& self ,
block : & mut ExecutedBlock ,
2017-08-01 12:37:57 +02:00
last_hashes : Arc < ::vm ::LastHashes > ,
2017-06-28 13:17:36 +02:00
epoch_begin : bool ,
) -> Result < ( ) , Error > {
let parent_hash = block . fields ( ) . header . parent_hash ( ) . clone ( ) ;
::engines ::common ::push_last_hash ( block , last_hashes . clone ( ) , self , & parent_hash ) ? ;
2017-08-29 15:16:24 +02:00
// with immediate transitions, we don't use the epoch mechanism anyway.
// the genesis is always considered an epoch, but we ignore it intentionally.
if self . immediate_transitions | | ! epoch_begin { return Ok ( ( ) ) }
2017-06-28 13:17:36 +02:00
// genesis is never a new block, but might as well check.
let header = block . fields ( ) . header . clone ( ) ;
let first = header . number ( ) = = 0 ;
let mut call = | to , data | {
let result = ::engines ::common ::execute_as_system (
block ,
last_hashes . clone ( ) ,
self ,
to ,
U256 ::max_value ( ) , // unbounded gas? maybe make configurable.
Some ( data ) ,
) ;
result . map_err ( | e | format! ( " {} " , e ) )
} ;
self . validators . on_epoch_begin ( first , & header , & mut call )
}
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-08-04 11:28:26 +02:00
::engines ::common ::bestow_block_reward ( block , self )
2017-01-05 21:16:13 +01:00
}
2016-09-08 12:12:24 +02:00
/// Check the number of seal fields.
2016-09-08 16:27:54 +02:00
fn verify_block_basic ( & self , header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2016-09-08 12:12:24 +02:00
if header . seal ( ) . len ( ) ! = self . seal_fields ( ) {
2017-02-02 19:11:43 +01:00
trace! ( target : " engine " , " verify_block_basic: wrong number of seal fields " ) ;
2016-09-19 18:00:39 +02:00
Err ( From ::from ( BlockError ::InvalidSealArity (
2016-09-08 12:12:24 +02:00
Mismatch { expected : self . seal_fields ( ) , found : header . seal ( ) . len ( ) }
2016-09-19 18:00:39 +02:00
) ) )
2017-03-28 10:46:52 +02:00
} else if header . number ( ) > = self . validate_score_transition & & * header . difficulty ( ) > = U256 ::from ( U128 ::max_value ( ) ) {
Err ( From ::from ( BlockError ::DifficultyOutOfBounds (
OutOfBounds { min : None , max : Some ( U256 ::from ( U128 ::max_value ( ) ) ) , found : * header . difficulty ( ) }
) ) )
2016-09-19 18:00:39 +02:00
} else {
Ok ( ( ) )
2016-09-08 12:12:24 +02:00
}
}
2017-03-08 14:41:24 +01:00
fn verify_block_unordered ( & self , _header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2017-03-28 10:46:52 +02:00
Ok ( ( ) )
2017-03-08 14:41:24 +01:00
}
2017-04-13 20:24:21 +02:00
/// Do the step and gas limit validation.
2017-03-08 14:41:24 +01:00
fn verify_block_family ( & self , header : & Header , parent : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
let step = header_step ( header ) ? ;
2016-09-08 12:12:24 +02:00
2017-03-08 14:41:24 +01:00
// Do not calculate difficulty for genesis blocks.
2016-09-08 12:12:24 +02:00
if header . number ( ) = = 0 {
return Err ( From ::from ( BlockError ::RidiculousNumber ( OutOfBounds { min : Some ( 1 ) , max : None , found : header . number ( ) } ) ) ) ;
}
2017-03-28 10:46:52 +02:00
let parent_step = header_step ( parent ) ? ;
2017-06-28 13:17:36 +02:00
2017-05-22 08:21:34 +02:00
// Ensure header is from the step after parent.
2017-05-15 22:34:01 +02:00
if step = = parent_step
| | ( header . number ( ) > = self . validate_step_transition & & step < = parent_step ) {
2017-04-13 20:24:21 +02:00
trace! ( target : " engine " , " Multiple blocks proposed for step {}. " , parent_step ) ;
2017-06-28 13:17:36 +02:00
self . validators . report_malicious ( header . author ( ) , header . number ( ) , header . number ( ) , Default ::default ( ) ) ;
2016-12-27 12:53:56 +01:00
Err ( EngineError ::DoubleVote ( header . author ( ) . clone ( ) ) ) ? ;
2016-11-01 19:12:06 +01:00
}
2017-05-22 08:21:34 +02:00
// Report skipped primaries.
2017-07-13 09:48:00 +02:00
if let ( true , Some ( me ) ) = ( step > parent_step + 1 , self . signer . read ( ) . address ( ) ) {
debug! ( target : " engine " , " Author {} built block with step gap. current step: {}, parent step: {} " ,
2017-06-28 13:17:36 +02:00
header . author ( ) , step , parent_step ) ;
2017-07-13 09:48:00 +02:00
let mut reported = HashSet ::new ( ) ;
2017-05-22 08:21:34 +02:00
for s in parent_step + 1 .. step {
2017-06-28 13:17:36 +02:00
let skipped_primary = step_proposer ( & * self . validators , & parent . hash ( ) , s ) ;
2017-07-13 09:48:00 +02:00
// Do not report this signer.
if skipped_primary ! = me {
self . validators . report_benign ( & skipped_primary , header . number ( ) , header . number ( ) ) ;
}
// Stop reporting once validators start repeating.
if ! reported . insert ( skipped_primary ) { break ; }
2017-05-22 08:21:34 +02:00
}
}
2016-11-01 19:12:06 +01:00
2017-07-31 12:34:29 +02:00
let gas_limit_divisor = self . params ( ) . gas_limit_bound_divisor ;
2016-09-08 12:12: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 ( ) } ) ) ) ;
}
Ok ( ( ) )
}
2017-04-13 20:24:21 +02:00
// Check the validators.
fn verify_block_external ( & self , header : & Header , _block : Option < & [ u8 ] > ) -> Result < ( ) , Error > {
2017-06-28 13:17:36 +02:00
// fetch correct validator set for current epoch, taking into account
// finality of previous transitions.
let active_set ;
let ( validators , set_number ) = if self . immediate_transitions {
( & * self . validators , header . number ( ) )
} else {
// get correct validator set for epoch.
let client = match self . client . read ( ) . as_ref ( ) . and_then ( | weak | weak . upgrade ( ) ) {
Some ( client ) = > client ,
None = > {
debug! ( target : " engine " , " Unable to verify sig: missing client ref. " ) ;
return Err ( EngineError ::RequiresClient . into ( ) )
}
} ;
let mut epoch_manager = self . epoch_manager . lock ( ) ;
if ! epoch_manager . zoom_to ( & * client , self , & * self . validators , header ) {
debug! ( target : " engine " , " Unable to zoom to epoch. " ) ;
return Err ( EngineError ::RequiresClient . into ( ) )
}
active_set = epoch_manager . validators ( ) . clone ( ) ;
( & active_set as & _ , epoch_manager . epoch_transition_number )
} ;
let report = | report | match report {
Report ::Benign ( address , block_number ) = >
self . validators . report_benign ( & address , set_number , block_number ) ,
Report ::Malicious ( address , block_number , proof ) = >
self . validators . report_malicious ( & address , set_number , block_number , proof ) ,
} ;
// verify signature against fixed list, but reports should go to the
// contract itself.
verify_external ( header , validators , & * self . step , report )
2017-04-13 20:24:21 +02:00
}
2017-06-28 13:17:36 +02:00
fn genesis_epoch_data ( & self , header : & Header , call : & Call ) -> Result < Vec < u8 > , String > {
self . validators . genesis_epoch_data ( header , call )
. map ( | set_proof | combine_proofs ( 0 , & set_proof , & [ ] ) )
2017-04-12 18:55:38 +02:00
}
2017-06-28 13:17:36 +02:00
fn signals_epoch_end ( & self , header : & Header , block : Option < & [ u8 ] > , receipts : Option < & [ ::receipt ::Receipt ] > )
2017-04-18 14:19:10 +02:00
-> super ::EpochChange
2017-04-12 18:55:38 +02:00
{
2017-06-28 13:17:36 +02:00
if self . immediate_transitions { return super ::EpochChange ::No }
let first = header . number ( ) = = 0 ;
self . validators . signals_epoch_end ( first , header , block , receipts )
2017-04-12 18:55:38 +02:00
}
2017-06-28 13:17:36 +02:00
fn is_epoch_end (
& self ,
chain_head : & Header ,
chain : & super ::Headers ,
transition_store : & super ::PendingTransitionStore ,
) -> Option < Vec < u8 > > {
// epochs only matter if we want to support light clients.
if self . immediate_transitions { return None }
let first = chain_head . number ( ) = = 0 ;
2017-04-13 20:24:21 +02:00
2017-06-28 13:17:36 +02:00
// apply immediate transitions.
if let Some ( change ) = self . validators . is_epoch_end ( first , chain_head ) {
2017-08-04 21:43:31 +02:00
let change = combine_proofs ( chain_head . number ( ) , & change , & [ ] ) ;
2017-06-28 13:17:36 +02:00
return Some ( change )
}
let client = match self . client . read ( ) . as_ref ( ) . and_then ( | weak | weak . upgrade ( ) ) {
Some ( client ) = > client ,
None = > {
warn! ( target : " engine " , " Unable to check for epoch end: missing client ref. " ) ;
return None ;
}
} ;
// find most recently finalized blocks, then check transition store for pending transitions.
let mut epoch_manager = self . epoch_manager . lock ( ) ;
if ! epoch_manager . zoom_to ( & * client , self , & * self . validators , chain_head ) {
return None ;
}
if epoch_manager . finality_checker . subchain_head ( ) ! = Some ( * chain_head . parent_hash ( ) ) {
// build new finality checker from ancestry of chain head,
// not including chain head itself yet.
2017-07-13 09:48:00 +02:00
trace! ( target : " finality " , " Building finality up to parent of {} ({}) " ,
chain_head . hash ( ) , chain_head . parent_hash ( ) ) ;
2017-06-28 13:17:36 +02:00
let mut hash = chain_head . parent_hash ( ) . clone ( ) ;
let epoch_transition_hash = epoch_manager . epoch_transition_hash ;
// walk the chain within current epoch backwards.
// author == ec_recover(sig) known since
// the blocks are in the DB.
let ancestry_iter = itertools ::repeat_call ( move | | {
chain ( hash ) . and_then ( | header | {
if header . number ( ) = = 0 { return None }
let res = ( hash , header . author ( ) . clone ( ) ) ;
2017-07-13 09:48:00 +02:00
trace! ( target : " finality " , " Ancestry iteration: yielding {:?} " , res ) ;
2017-06-28 13:17:36 +02:00
hash = header . parent_hash ( ) . clone ( ) ;
Some ( res )
} )
} )
. while_some ( )
. take_while ( | & ( h , _ ) | h ! = epoch_transition_hash ) ;
if let Err ( _ ) = epoch_manager . finality_checker . build_ancestry_subchain ( ancestry_iter ) {
debug! ( target : " engine " , " inconsistent validator set within epoch " ) ;
return None ;
}
}
{
if let Ok ( finalized ) = epoch_manager . finality_checker . push_hash ( chain_head . hash ( ) , * chain_head . author ( ) ) {
let mut finalized = finalized . into_iter ( ) ;
while let Some ( hash ) = finalized . next ( ) {
if let Some ( pending ) = transition_store ( hash ) {
let finality_proof = ::std ::iter ::once ( hash )
. chain ( finalized )
. chain ( epoch_manager . finality_checker . unfinalized_hashes ( ) )
. map ( | hash | chain ( hash )
. expect ( " these headers fetched before when constructing finality checker; qed " ) )
. collect ::< Vec < Header > > ( ) ;
// this gives us the block number for `hash`, assuming it's ancestry.
let signal_number = chain_head . number ( )
- finality_proof . len ( ) as BlockNumber
+ 1 ;
let finality_proof = ::rlp ::encode_list ( & finality_proof ) ;
epoch_manager . note_new_epoch ( ) ;
2017-07-13 09:48:00 +02:00
info! ( target : " engine " , " Applying validator set change signalled at block {} " , signal_number ) ;
// We turn off can_propose here because upon validator set change there can
// be two valid proposers for a single step: one from the old set and
// one from the new.
//
// This way, upon encountering an epoch change, the proposer from the
// new set will be forced to wait until the next step to avoid sealing a
// block that breaks the invariant that the parent's step < the block's step.
self . can_propose . store ( false , AtomicOrdering ::SeqCst ) ;
2017-06-28 13:17:36 +02:00
return Some ( combine_proofs ( signal_number , & pending . proof , & * finality_proof ) ) ;
}
}
}
}
None
}
fn epoch_verifier < ' a > ( & self , _header : & Header , proof : & ' a [ u8 ] ) -> ConstructedVerifier < ' a > {
let ( signal_number , set_proof , finality_proof ) = match destructure_proofs ( proof ) {
Ok ( x ) = > x ,
Err ( e ) = > return ConstructedVerifier ::Err ( e ) ,
} ;
let first = signal_number = = 0 ;
match self . validators . epoch_set ( first , self , signal_number , set_proof ) {
Ok ( ( list , finalize ) ) = > {
let verifier = Box ::new ( EpochVerifier {
step : self . step . clone ( ) ,
subchain_validators : list ,
} ) ;
match finalize {
Some ( finalize ) = > ConstructedVerifier ::Unconfirmed ( verifier , finality_proof , finalize ) ,
None = > ConstructedVerifier ::Trusted ( verifier ) ,
}
}
Err ( e ) = > ConstructedVerifier ::Err ( e ) ,
}
2017-04-13 20:24:21 +02:00
}
2017-07-29 17:12:07 +02:00
fn verify_transaction_basic ( & self , t : & UnverifiedTransaction , header : & Header ) -> Result < ( ) , Error > {
2017-04-01 13:21:22 +02:00
t . check_low_s ( ) ? ;
2017-08-21 13:46:58 +02:00
if let Some ( n ) = t . chain_id ( ) {
2017-07-31 12:34:29 +02:00
if header . number ( ) > = self . params ( ) . eip155_transition & & n ! = self . params ( ) . chain_id {
2017-08-21 13:46:58 +02:00
return Err ( TransactionError ::InvalidChainId . into ( ) ) ;
2017-04-01 13:21:22 +02:00
}
}
Ok ( ( ) )
}
2017-01-10 12:23:59 +01:00
fn register_client ( & self , client : Weak < Client > ) {
* self . client . write ( ) = Some ( client . clone ( ) ) ;
2017-01-24 10:03:58 +01:00
self . validators . register_contract ( client ) ;
2016-11-17 19:32:12 +01:00
}
2016-12-07 10:34:06 +01:00
2017-01-18 18:49:50 +01:00
fn set_signer ( & self , ap : Arc < AccountProvider > , address : Address , password : String ) {
2017-07-13 09:48:00 +02:00
self . signer . write ( ) . set ( ap , address , password ) ;
2016-09-27 12:12:18 +02:00
}
2017-01-24 10:03:58 +01:00
fn sign ( & self , hash : H256 ) -> Result < Signature , Error > {
2017-07-13 09:48:00 +02:00
self . signer . read ( ) . sign ( hash ) . map_err ( Into ::into )
2017-01-24 10:03:58 +01:00
}
2017-05-17 12:41:33 +02:00
fn snapshot_components ( & self ) -> Option < Box < ::snapshot ::SnapshotComponents > > {
2017-06-28 13:17:36 +02:00
if self . immediate_transitions {
None
} else {
Some ( Box ::new ( ::snapshot ::PoaSnapshot ) )
}
2017-05-17 12:41:33 +02:00
}
2016-09-08 12:12:24 +02:00
}
#[ cfg(test) ]
mod tests {
2017-07-29 21:56:42 +02:00
use std ::sync ::Arc ;
2017-05-22 08:21:34 +02:00
use std ::sync ::atomic ::{ AtomicUsize , Ordering as AtomicOrdering } ;
2017-08-30 19:18:28 +02:00
use hash ::keccak ;
2016-11-14 12:09:57 +01:00
use util ::* ;
use header ::Header ;
use error ::{ Error , BlockError } ;
2016-09-08 12:28:59 +02:00
use rlp ::encode ;
2016-09-08 12:12:24 +02:00
use block ::* ;
use tests ::helpers ::* ;
use account_provider ::AccountProvider ;
use spec ::Spec ;
2017-05-22 08:21:34 +02:00
use engines ::{ Seal , Engine } ;
use engines ::validator_set ::TestSet ;
use super ::{ AuthorityRoundParams , AuthorityRound } ;
2016-09-08 12:12:24 +02:00
#[ test ]
fn has_valid_metadata ( ) {
2016-09-14 11:20:22 +02:00
let engine = Spec ::new_test_round ( ) . engine ;
2016-09-08 12:12:24 +02:00
assert! ( ! engine . name ( ) . is_empty ( ) ) ;
assert! ( engine . version ( ) . major > = 1 ) ;
}
#[ test ]
fn can_return_schedule ( ) {
2016-09-14 11:20:22 +02:00
let engine = Spec ::new_test_round ( ) . engine ;
2017-04-19 14:30:00 +02:00
let schedule = engine . schedule ( 10000000 ) ;
2016-09-08 12:12:24 +02:00
assert! ( schedule . stack_limit > 0 ) ;
}
#[ test ]
2016-09-08 16:27:54 +02:00
fn verification_fails_on_short_seal ( ) {
2016-09-14 11:20:22 +02:00
let engine = Spec ::new_test_round ( ) . engine ;
2016-09-08 12:12:24 +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 ]
fn can_do_signature_verification_fail ( ) {
2016-09-14 11:20:22 +02:00
let engine = Spec ::new_test_round ( ) . engine ;
2016-09-08 12:12:24 +02:00
let mut header : Header = Header ::default ( ) ;
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & H520 ::default ( ) ) . into_vec ( ) ] ) ;
2016-09-08 12:12:24 +02:00
2017-04-13 20:24:21 +02:00
let verify_result = engine . verify_block_external ( & header , None ) ;
2016-09-08 12:12:24 +02:00
assert! ( verify_result . is_err ( ) ) ;
}
#[ test ]
2016-11-14 15:15:31 +01:00
fn generates_seal_and_does_not_double_propose ( ) {
2017-01-18 18:49:50 +01:00
let tap = Arc ::new ( AccountProvider ::transient_provider ( ) ) ;
2017-08-30 19:18:28 +02:00
let addr1 = tap . insert_account ( keccak ( " 1 " ) . into ( ) , " 1 " ) . unwrap ( ) ;
let addr2 = tap . insert_account ( keccak ( " 2 " ) . into ( ) , " 2 " ) . unwrap ( ) ;
2016-09-08 12:12:24 +02:00
2016-09-14 11:20:22 +02:00
let spec = Spec ::new_test_round ( ) ;
2016-09-08 12:12:24 +02:00
let engine = & * spec . engine ;
let genesis_header = spec . genesis_header ( ) ;
2017-04-06 19:26:17 +02:00
let db1 = spec . ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) ) . unwrap ( ) ;
let db2 = spec . ensure_db_good ( get_temp_state_db ( ) , & Default ::default ( ) ) . unwrap ( ) ;
2016-09-08 12:12:24 +02:00
let last_hashes = Arc ::new ( vec! [ genesis_header . hash ( ) ] ) ;
2017-06-28 13:17:36 +02:00
let b1 = OpenBlock ::new ( engine , Default ::default ( ) , false , db1 , & genesis_header , last_hashes . clone ( ) , addr1 , ( 3141562. into ( ) , 31415620. into ( ) ) , vec! [ ] , false ) . unwrap ( ) ;
2016-11-14 20:03:02 +01:00
let b1 = b1 . close_and_lock ( ) ;
2017-06-28 13:17:36 +02:00
let b2 = OpenBlock ::new ( engine , Default ::default ( ) , false , db2 , & genesis_header , last_hashes , addr2 , ( 3141562. into ( ) , 31415620. into ( ) ) , vec! [ ] , false ) . unwrap ( ) ;
2016-11-14 20:03:02 +01:00
let b2 = b2 . close_and_lock ( ) ;
2017-01-18 18:49:50 +01:00
engine . set_signer ( tap . clone ( ) , addr1 , " 1 " . into ( ) ) ;
2016-12-08 12:03:34 +01:00
if let Seal ::Regular ( seal ) = engine . generate_seal ( b1 . block ( ) ) {
2017-04-12 14:41:19 +02:00
assert! ( b1 . clone ( ) . try_seal ( engine , seal ) . is_ok ( ) ) ;
2016-11-14 20:03:02 +01:00
// Second proposal is forbidden.
2016-12-08 12:03:34 +01:00
assert! ( engine . generate_seal ( b1 . block ( ) ) = = Seal ::None ) ;
2016-11-14 20:03:02 +01:00
}
2017-01-18 18:49:50 +01:00
engine . set_signer ( tap , addr2 , " 2 " . into ( ) ) ;
2016-12-08 12:03:34 +01:00
if let Seal ::Regular ( seal ) = engine . generate_seal ( b2 . block ( ) ) {
2017-04-12 14:41:19 +02:00
assert! ( b2 . clone ( ) . try_seal ( engine , seal ) . is_ok ( ) ) ;
2016-11-14 20:03:02 +01:00
// Second proposal is forbidden.
2016-12-08 12:03:34 +01:00
assert! ( engine . generate_seal ( b2 . block ( ) ) = = Seal ::None ) ;
2016-11-14 20:03:02 +01:00
}
2016-09-08 12:12:24 +02:00
}
2016-09-08 16:27:54 +02:00
#[ test ]
fn proposer_switching ( ) {
let tap = AccountProvider ::transient_provider ( ) ;
2017-08-30 19:18:28 +02:00
let addr = tap . insert_account ( keccak ( " 0 " ) . into ( ) , " 0 " ) . unwrap ( ) ;
2017-03-08 14:41:24 +01:00
let mut parent_header : Header = Header ::default ( ) ;
2017-06-28 14:16:53 +02:00
parent_header . set_seal ( vec! [ encode ( & 0 usize ) . into_vec ( ) ] ) ;
2017-07-29 21:56:42 +02:00
parent_header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2017-03-08 14:41:24 +01:00
let mut header : Header = Header ::default ( ) ;
header . set_number ( 1 ) ;
2017-07-29 21:56:42 +02:00
header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2016-09-08 16:27:54 +02:00
header . set_author ( addr ) ;
2016-09-19 18:00:39 +02:00
let engine = Spec ::new_test_round ( ) . engine ;
2016-09-08 16:27:54 +02:00
2016-11-14 12:34:54 +01:00
let signature = tap . sign ( addr , Some ( " 0 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
2017-01-10 12:23:59 +01:00
// Two validators.
2016-12-10 10:38:10 +01:00
// Spec starts with step 2.
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 2 usize ) . into_vec ( ) , encode ( & ( & * signature as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-04-13 20:24:21 +02:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
assert! ( engine . verify_block_external ( & header , None ) . is_err ( ) ) ;
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 1 usize ) . into_vec ( ) , encode ( & ( & * signature as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-03-08 14:41:24 +01:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
2017-04-13 20:24:21 +02:00
assert! ( engine . verify_block_external ( & header , None ) . is_ok ( ) ) ;
2016-09-08 16:27:54 +02:00
}
2016-12-10 10:38:10 +01:00
#[ test ]
fn rejects_future_block ( ) {
let tap = AccountProvider ::transient_provider ( ) ;
2017-08-30 19:18:28 +02:00
let addr = tap . insert_account ( keccak ( " 0 " ) . into ( ) , " 0 " ) . unwrap ( ) ;
2016-12-10 10:38:10 +01:00
2017-03-08 14:41:24 +01:00
let mut parent_header : Header = Header ::default ( ) ;
2017-06-28 14:16:53 +02:00
parent_header . set_seal ( vec! [ encode ( & 0 usize ) . into_vec ( ) ] ) ;
2017-07-29 21:56:42 +02:00
parent_header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2017-03-08 14:41:24 +01:00
let mut header : Header = Header ::default ( ) ;
header . set_number ( 1 ) ;
2017-07-29 21:56:42 +02:00
header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2016-12-10 10:38:10 +01:00
header . set_author ( addr ) ;
let engine = Spec ::new_test_round ( ) . engine ;
let signature = tap . sign ( addr , Some ( " 0 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
2017-01-10 12:23:59 +01:00
// Two validators.
2016-12-10 10:38:10 +01:00
// Spec starts with step 2.
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 1 usize ) . into_vec ( ) , encode ( & ( & * signature as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-03-08 14:41:24 +01:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
2017-04-13 20:24:21 +02:00
assert! ( engine . verify_block_external ( & header , None ) . is_ok ( ) ) ;
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 5 usize ) . into_vec ( ) , encode ( & ( & * signature as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-04-13 20:24:21 +02:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
assert! ( engine . verify_block_external ( & header , None ) . is_err ( ) ) ;
}
#[ test ]
fn rejects_step_backwards ( ) {
2017-04-19 20:44:11 +02:00
let tap = AccountProvider ::transient_provider ( ) ;
2017-08-30 19:18:28 +02:00
let addr = tap . insert_account ( keccak ( " 0 " ) . into ( ) , " 0 " ) . unwrap ( ) ;
2017-04-13 20:24:21 +02:00
let mut parent_header : Header = Header ::default ( ) ;
2017-06-28 14:16:53 +02:00
parent_header . set_seal ( vec! [ encode ( & 4 usize ) . into_vec ( ) ] ) ;
2017-07-29 21:56:42 +02:00
parent_header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2017-04-13 20:24:21 +02:00
let mut header : Header = Header ::default ( ) ;
header . set_number ( 1 ) ;
2017-07-29 21:56:42 +02:00
header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2017-04-13 20:24:21 +02:00
header . set_author ( addr ) ;
let engine = Spec ::new_test_round ( ) . engine ;
let signature = tap . sign ( addr , Some ( " 0 " . into ( ) ) , header . bare_hash ( ) ) . unwrap ( ) ;
// Two validators.
// Spec starts with step 2.
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 5 usize ) . into_vec ( ) , encode ( & ( & * signature as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-04-13 20:24:21 +02:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 3 usize ) . into_vec ( ) , encode ( & ( & * signature as & [ u8 ] ) ) . into_vec ( ) ] ) ;
2017-03-08 14:41:24 +01:00
assert! ( engine . verify_block_family ( & header , & parent_header , None ) . is_err ( ) ) ;
2016-12-10 10:38:10 +01:00
}
2017-05-22 08:21:34 +02:00
#[ test ]
fn reports_skipped ( ) {
let last_benign = Arc ::new ( AtomicUsize ::new ( 0 ) ) ;
let params = AuthorityRoundParams {
step_duration : Default ::default ( ) ,
start_step : Some ( 1 ) ,
validators : Box ::new ( TestSet ::new ( Default ::default ( ) , last_benign . clone ( ) ) ) ,
validate_score_transition : 0 ,
validate_step_transition : 0 ,
2017-06-28 13:17:36 +02:00
immediate_transitions : true ,
2017-05-22 08:21:34 +02:00
} ;
2017-07-31 12:34:29 +02:00
let aura = {
let mut c_params = ::spec ::CommonParams ::default ( ) ;
c_params . gas_limit_bound_divisor = 5. into ( ) ;
AuthorityRound ::new ( c_params , params , Default ::default ( ) ) . unwrap ( )
} ;
2017-05-22 08:21:34 +02:00
let mut parent_header : Header = Header ::default ( ) ;
2017-06-28 14:16:53 +02:00
parent_header . set_seal ( vec! [ encode ( & 1 usize ) . into_vec ( ) ] ) ;
2017-07-29 21:56:42 +02:00
parent_header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2017-05-22 08:21:34 +02:00
let mut header : Header = Header ::default ( ) ;
header . set_number ( 1 ) ;
2017-07-29 21:56:42 +02:00
header . set_gas_limit ( " 222222 " . parse ::< U256 > ( ) . unwrap ( ) ) ;
2017-06-28 14:16:53 +02:00
header . set_seal ( vec! [ encode ( & 3 usize ) . into_vec ( ) ] ) ;
2017-05-22 08:21:34 +02:00
2017-07-13 09:48:00 +02:00
// Do not report when signer not present.
assert! ( aura . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
assert_eq! ( last_benign . load ( AtomicOrdering ::SeqCst ) , 0 ) ;
aura . set_signer ( Arc ::new ( AccountProvider ::transient_provider ( ) ) , Default ::default ( ) , Default ::default ( ) ) ;
2017-05-22 08:21:34 +02:00
assert! ( aura . verify_block_family ( & header , & parent_header , None ) . is_ok ( ) ) ;
assert_eq! ( last_benign . load ( AtomicOrdering ::SeqCst ) , 1 ) ;
}
2016-09-08 12:12:24 +02:00
}