2016-03-08 15:46:44 +01:00
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use rayon ::prelude ::* ;
2016-03-11 14:48:30 +01:00
use std ::sync ::atomic ::AtomicBool ;
2016-06-29 16:26:19 +02:00
use std ::time ::{ Instant , Duration } ;
2016-03-11 14:48:30 +01:00
2016-03-27 15:39:45 +02:00
use util ::* ;
2016-07-06 11:23:29 +02:00
use util ::using_queue ::{ UsingQueue , GetAction } ;
2016-06-20 00:10:34 +02:00
use account_provider ::AccountProvider ;
2016-05-31 19:52:53 +02:00
use views ::{ BlockView , HeaderView } ;
2016-06-06 12:17:30 +02:00
use client ::{ MiningBlockChainClient , Executive , Executed , EnvInfo , TransactOptions , BlockID , CallAnalytics } ;
2016-05-31 19:52:53 +02:00
use block ::{ ClosedBlock , IsBlock } ;
use error ::* ;
use transaction ::SignedTransaction ;
use receipt ::{ Receipt } ;
use spec ::Spec ;
use engine ::Engine ;
2016-07-01 21:13:56 +02:00
use miner ::{ MinerService , MinerStatus , TransactionQueue , AccountDetails , TransactionOrigin } ;
2016-06-29 20:04:52 +02:00
use miner ::work_notify ::WorkPoster ;
2016-07-01 21:13:56 +02:00
use client ::TransactionImportResult ;
2016-07-08 17:26:06 +02:00
use miner ::price_info ::PriceInfo ;
2016-07-01 21:13:56 +02:00
2016-03-08 15:46:44 +01:00
2016-06-27 19:06:54 +02:00
/// Different possible definitions for pending transaction set.
#[ derive(Debug) ]
pub enum PendingSet {
/// Always just the transactions in the queue. These have had only cheap checks.
AlwaysQueue ,
/// Always just the transactions in the sealing block. These have had full checks but
/// may be empty if the node is not actively mining or has force_sealing enabled.
AlwaysSealing ,
/// Try the sealing block, but if it is not currently sealing, fallback to the queue.
SealingOrElseQueue ,
}
2016-06-27 17:23:54 +02:00
/// Configures the behaviour of the miner.
#[ derive(Debug) ]
pub struct MinerOptions {
2016-06-29 15:37:11 +02:00
/// URLs to notify when there is new work.
pub new_work_notify : Vec < String > ,
2016-06-27 17:23:54 +02:00
/// Force the miner to reseal, even when nobody has asked for work.
pub force_sealing : bool ,
/// Reseal on receipt of new external transactions.
pub reseal_on_external_tx : bool ,
/// Reseal on receipt of new local transactions.
pub reseal_on_own_tx : bool ,
2016-06-29 16:26:19 +02:00
/// Minimum period between transaction-inspired reseals.
pub reseal_min_period : Duration ,
2016-06-28 10:21:29 +02:00
/// Maximum amount of gas to bother considering for block insertion.
2016-06-28 10:40:35 +02:00
pub tx_gas_limit : U256 ,
2016-06-27 20:19:01 +02:00
/// Maximum size of the transaction queue.
pub tx_queue_size : usize ,
2016-06-27 18:27:06 +02:00
/// Whether we should fallback to providing all the queue's transactions or just pending.
2016-06-27 19:06:54 +02:00
pub pending_set : PendingSet ,
2016-06-29 16:26:19 +02:00
/// How many historical work packages can we store before running out?
pub work_queue_size : usize ,
2016-06-30 12:56:58 +02:00
/// Can we submit two different solutions for the same block and expect both to result in an import?
pub enable_resubmission : bool ,
2016-06-27 17:23:54 +02:00
}
impl Default for MinerOptions {
fn default ( ) -> Self {
MinerOptions {
2016-06-29 15:37:11 +02:00
new_work_notify : vec ! [ ] ,
2016-06-27 17:23:54 +02:00
force_sealing : false ,
reseal_on_external_tx : true ,
reseal_on_own_tx : true ,
2016-06-28 10:40:35 +02:00
tx_gas_limit : ! U256 ::zero ( ) ,
2016-06-27 20:19:01 +02:00
tx_queue_size : 1024 ,
2016-06-27 19:06:54 +02:00
pending_set : PendingSet ::AlwaysQueue ,
2016-06-29 16:26:19 +02:00
reseal_min_period : Duration ::from_secs ( 0 ) ,
work_queue_size : 20 ,
2016-06-30 12:56:58 +02:00
enable_resubmission : true ,
2016-06-27 17:23:54 +02:00
}
}
}
2016-07-08 17:26:06 +02:00
/// Options for the dynamic gas price recalibrator.
pub struct GasPriceCalibratorOptions {
/// Base transaction price to match against.
pub usd_per_tx : f32 ,
2016-07-10 13:18:33 +02:00
/// How frequently we should recalibrate.
2016-07-08 17:26:06 +02:00
pub recalibration_period : Duration ,
}
2016-07-10 13:18:33 +02:00
/// The gas price validator variant for a `GasPricer`.
2016-07-08 17:26:06 +02:00
pub struct GasPriceCalibrator {
options : GasPriceCalibratorOptions ,
next_calibration : Instant ,
}
impl GasPriceCalibrator {
fn recalibrate < F : Fn ( U256 ) + Sync + Send + 'static > ( & mut self , set_price : F ) {
trace! ( target : " miner " , " Recalibrating {:?} versus {:?} " , Instant ::now ( ) , self . next_calibration ) ;
if Instant ::now ( ) > = self . next_calibration {
let usd_per_tx = self . options . usd_per_tx ;
trace! ( target : " miner " , " Getting price info " ) ;
if let Ok ( _ ) = PriceInfo ::get ( move | price : PriceInfo | {
trace! ( target : " miner " , " Price info arrived: {:?} " , price ) ;
let usd_per_eth = price . ethusd ;
let wei_per_usd : f32 = 1.0e18 / usd_per_eth ;
let gas_per_tx : f32 = 21000.0 ;
let wei_per_gas : f32 = wei_per_usd * usd_per_tx / gas_per_tx ;
info! ( target : " miner " , " Updated conversion rate to Ξ1 = {} ({} wei/gas) " , format! ( " US$ {} " , usd_per_eth ) . apply ( Colour ::White . bold ( ) ) , format! ( " {} " , wei_per_gas ) . apply ( Colour ::Yellow . bold ( ) ) ) ;
set_price ( U256 ::from_dec_str ( & format! ( " {:.0} " , wei_per_gas ) ) . unwrap ( ) ) ;
} ) {
self . next_calibration = Instant ::now ( ) + self . options . recalibration_period ;
} else {
warn! ( target : " miner " , " Unable to update Ether price. " ) ;
}
}
}
}
/// Struct to look after updating the acceptable gas price of a miner.
pub enum GasPricer {
/// A fixed gas price in terms of Wei - always the argument given.
Fixed ( U256 ) ,
/// Gas price is calibrated according to a fixed amount of USD.
Calibrated ( GasPriceCalibrator ) ,
}
impl GasPricer {
/// Create a new Calibrated `GasPricer`.
pub fn new_calibrated ( options : GasPriceCalibratorOptions ) -> GasPricer {
GasPricer ::Calibrated ( GasPriceCalibrator {
options : options ,
next_calibration : Instant ::now ( ) ,
} )
}
/// Create a new Fixed `GasPricer`.
pub fn new_fixed ( gas_price : U256 ) -> GasPricer {
GasPricer ::Fixed ( gas_price )
}
fn recalibrate < F : Fn ( U256 ) + Sync + Send + 'static > ( & mut self , set_price : F ) {
match * self {
GasPricer ::Fixed ( ref max ) = > set_price ( max . clone ( ) ) ,
GasPricer ::Calibrated ( ref mut cal ) = > cal . recalibrate ( set_price ) ,
}
}
}
2016-03-09 14:26:28 +01:00
/// Keeps track of transactions using priority queue and holds currently mined block.
2016-03-08 15:46:44 +01:00
pub struct Miner {
2016-06-19 12:33:50 +02:00
// NOTE [ToDr] When locking always lock in this order!
2016-07-08 17:26:06 +02:00
transaction_queue : Arc < Mutex < TransactionQueue > > ,
2016-06-19 12:33:50 +02:00
sealing_work : Mutex < UsingQueue < ClosedBlock > > ,
2016-03-08 15:46:44 +01:00
// for sealing...
2016-06-27 17:23:54 +02:00
options : MinerOptions ,
2016-03-08 15:46:44 +01:00
sealing_enabled : AtomicBool ,
2016-06-29 16:26:19 +02:00
next_allowed_reseal : Mutex < Instant > ,
2016-03-18 13:59:11 +01:00
sealing_block_last_request : Mutex < u64 > ,
2016-06-23 14:29:16 +02:00
gas_range_target : RwLock < ( U256 , U256 ) > ,
2016-03-08 15:46:44 +01:00
author : RwLock < Address > ,
extra_data : RwLock < Bytes > ,
2016-05-16 18:16:56 +02:00
spec : Spec ,
2016-05-03 17:23:53 +02:00
2016-05-30 13:10:33 +02:00
accounts : Option < Arc < AccountProvider > > ,
2016-06-29 20:04:52 +02:00
work_poster : Option < WorkPoster > ,
2016-07-08 17:26:06 +02:00
gas_pricer : Mutex < GasPricer > ,
2016-03-08 15:46:44 +01:00
}
2016-06-20 10:28:38 +02:00
impl Miner {
/// Creates new instance of miner without accounts, but with given spec.
pub fn with_spec ( spec : Spec ) -> Miner {
2016-03-08 15:46:44 +01:00
Miner {
2016-07-08 17:26:06 +02:00
transaction_queue : Arc ::new ( Mutex ::new ( TransactionQueue ::new ( ) ) ) ,
2016-06-27 17:23:54 +02:00
options : Default ::default ( ) ,
2016-03-08 15:46:44 +01:00
sealing_enabled : AtomicBool ::new ( false ) ,
2016-06-29 16:26:19 +02:00
next_allowed_reseal : Mutex ::new ( Instant ::now ( ) ) ,
2016-03-18 13:59:11 +01:00
sealing_block_last_request : Mutex ::new ( 0 ) ,
2016-06-29 16:26:19 +02:00
sealing_work : Mutex ::new ( UsingQueue ::new ( 20 ) ) ,
2016-06-23 14:29:16 +02:00
gas_range_target : RwLock ::new ( ( U256 ::zero ( ) , U256 ::zero ( ) ) ) ,
2016-03-11 14:48:30 +01:00
author : RwLock ::new ( Address ::default ( ) ) ,
2016-03-08 15:46:44 +01:00
extra_data : RwLock ::new ( Vec ::new ( ) ) ,
2016-05-30 13:10:33 +02:00
accounts : None ,
2016-05-16 18:16:56 +02:00
spec : spec ,
2016-06-29 20:04:52 +02:00
work_poster : None ,
2016-07-08 17:26:06 +02:00
gas_pricer : Mutex ::new ( GasPricer ::new_fixed ( 20_000_000_000 u64 . into ( ) ) ) ,
2016-06-20 10:28:38 +02:00
}
2016-05-03 17:23:53 +02:00
}
/// Creates new instance of miner
2016-07-08 17:26:06 +02:00
pub fn new ( options : MinerOptions , gas_pricer : GasPricer , spec : Spec , accounts : Option < Arc < AccountProvider > > ) -> Arc < Miner > {
2016-06-29 20:04:52 +02:00
let work_poster = if ! options . new_work_notify . is_empty ( ) { Some ( WorkPoster ::new ( & options . new_work_notify ) ) } else { None } ;
2016-07-08 17:26:06 +02:00
let txq = Arc ::new ( Mutex ::new ( TransactionQueue ::with_limits ( options . tx_queue_size , options . tx_gas_limit ) ) ) ;
2016-05-03 17:23:53 +02:00
Arc ::new ( Miner {
2016-07-08 17:26:06 +02:00
transaction_queue : txq ,
2016-06-29 20:04:52 +02:00
sealing_enabled : AtomicBool ::new ( options . force_sealing | | ! options . new_work_notify . is_empty ( ) ) ,
2016-06-29 16:26:19 +02:00
next_allowed_reseal : Mutex ::new ( Instant ::now ( ) ) ,
2016-05-03 17:23:53 +02:00
sealing_block_last_request : Mutex ::new ( 0 ) ,
2016-06-29 16:26:19 +02:00
sealing_work : Mutex ::new ( UsingQueue ::new ( options . work_queue_size ) ) ,
2016-06-23 14:29:16 +02:00
gas_range_target : RwLock ::new ( ( U256 ::zero ( ) , U256 ::zero ( ) ) ) ,
2016-05-03 17:23:53 +02:00
author : RwLock ::new ( Address ::default ( ) ) ,
extra_data : RwLock ::new ( Vec ::new ( ) ) ,
2016-06-29 16:26:19 +02:00
options : options ,
2016-06-20 10:28:38 +02:00
accounts : accounts ,
2016-05-16 18:16:56 +02:00
spec : spec ,
2016-06-29 20:04:52 +02:00
work_poster : work_poster ,
2016-07-08 17:26:06 +02:00
gas_pricer : Mutex ::new ( gas_pricer ) ,
2016-04-11 20:52:33 +02:00
} )
2016-03-09 14:26:28 +01:00
}
2016-03-08 15:46:44 +01:00
2016-05-16 18:16:56 +02:00
fn engine ( & self ) -> & Engine {
self . spec . engine . deref ( )
}
2016-06-29 20:04:52 +02:00
fn forced_sealing ( & self ) -> bool {
self . options . force_sealing | | ! self . options . new_work_notify . is_empty ( )
}
2016-03-17 12:47:31 +01:00
/// Prepares new block for sealing including top transactions from queue.
2016-04-06 10:07:24 +02:00
#[ cfg_attr(feature= " dev " , allow(match_same_arms)) ]
2016-05-25 17:03:58 +02:00
#[ cfg_attr(feature= " dev " , allow(cyclomatic_complexity)) ]
2016-05-31 20:33:26 +02:00
fn prepare_sealing ( & self , chain : & MiningBlockChainClient ) {
2016-03-26 20:36:03 +01:00
trace! ( target : " miner " , " prepare_sealing: entering " ) ;
2016-03-23 17:28:02 +01:00
2016-07-08 17:26:06 +02:00
{
trace! ( target : " miner " , " recalibrating... " ) ;
let txq = self . transaction_queue . clone ( ) ;
self . gas_pricer . lock ( ) . unwrap ( ) . recalibrate ( move | price | {
trace! ( target : " miner " , " Got gas price! {} " , price ) ;
txq . lock ( ) . unwrap ( ) . set_minimal_gas_price ( price ) ;
} ) ;
trace! ( target : " miner " , " done recalibration. " ) ;
}
2016-06-30 22:35:59 +02:00
let ( transactions , mut open_block , original_work_hash ) = {
2016-07-06 19:52:34 +02:00
let transactions = { self . transaction_queue . locked ( ) . top_transactions ( ) } ;
let mut sealing_work = self . sealing_work . locked ( ) ;
2016-06-30 13:12:15 +02:00
let last_work_hash = sealing_work . peek_last_ref ( ) . map ( | pb | pb . block ( ) . fields ( ) . header . hash ( ) ) ;
2016-06-21 11:26:43 +02:00
let best_hash = chain . best_block_header ( ) . sha3 ( ) ;
2016-03-23 17:28:02 +01:00
/*
2016-06-21 11:26:43 +02:00
// check to see if last ClosedBlock in would_seals is actually same parent block.
// if so
// duplicate, re-open and push any new transactions.
// if at least one was pushed successfully, close and enqueue new ClosedBlock;
// otherwise, leave everything alone.
// otherwise, author a fresh block.
2016-03-23 17:28:02 +01:00
* /
2016-06-21 11:26:43 +02:00
let open_block = match sealing_work . pop_if ( | b | b . block ( ) . fields ( ) . header . parent_hash ( ) = = & best_hash ) {
Some ( old_block ) = > {
trace! ( target : " miner " , " Already have previous work; updating and returning " ) ;
// add transactions to old_block
let e = self . engine ( ) ;
old_block . reopen ( e , chain . vm_factory ( ) )
}
None = > {
// block not found - create it.
trace! ( target : " miner " , " No existing work - making new block " ) ;
chain . prepare_open_block (
self . author ( ) ,
2016-06-23 14:29:16 +02:00
( self . gas_floor_target ( ) , self . gas_ceil_target ( ) ) ,
2016-06-21 11:26:43 +02:00
self . extra_data ( )
)
}
} ;
2016-06-30 13:12:15 +02:00
( transactions , open_block , last_work_hash )
2016-03-24 23:03:22 +01:00
} ;
2016-06-06 14:33:12 +02:00
let mut invalid_transactions = HashSet ::new ( ) ;
let block_number = open_block . block ( ) . fields ( ) . header . number ( ) ;
// TODO: push new uncles, too.
for tx in transactions {
let hash = tx . hash ( ) ;
match open_block . push_transaction ( tx , None ) {
Err ( Error ::Execution ( ExecutionError ::BlockGasLimitReached { gas_limit , gas_used , .. } ) ) = > {
2016-07-05 17:51:41 +02:00
debug! ( target : " miner " , " Skipping adding transaction to block because of gas limit: {:?} " , hash ) ;
2016-06-06 14:33:12 +02:00
// Exit early if gas left is smaller then min_tx_gas
let min_tx_gas : U256 = 21000. into ( ) ; // TODO: figure this out properly.
if gas_limit - gas_used < min_tx_gas {
break ;
}
} ,
2016-07-05 17:51:41 +02:00
// Invalid nonce error can happen only if previous transaction is skipped because of gas limit.
// If there is errornous state of transaction queue it will be fixed when next block is imported.
Err ( Error ::Execution ( ExecutionError ::InvalidNonce { .. } ) ) = > {
debug! ( target : " miner " , " Skipping adding transaction to block because of invalid nonce: {:?} " , hash ) ;
} ,
// already have transaction - ignore
Err ( Error ::Transaction ( TransactionError ::AlreadyImported ) ) = > { } ,
2016-06-06 14:33:12 +02:00
Err ( e ) = > {
invalid_transactions . insert ( hash ) ;
2016-07-05 17:51:41 +02:00
debug! ( target : " miner " ,
2016-06-06 14:33:12 +02:00
" Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?} " ,
block_number , hash , e ) ;
} ,
_ = > { } // imported ok
}
}
let block = open_block . close ( ) ;
2016-04-15 07:38:23 +02:00
let fetch_account = | a : & Address | AccountDetails {
2016-05-26 22:17:55 +02:00
nonce : chain . latest_nonce ( a ) ,
balance : chain . latest_balance ( a ) ,
2016-04-15 07:38:23 +02:00
} ;
2016-06-06 14:33:12 +02:00
2016-06-21 11:26:43 +02:00
{
2016-07-06 19:52:34 +02:00
let mut queue = self . transaction_queue . locked ( ) ;
2016-06-21 11:26:43 +02:00
for hash in invalid_transactions . into_iter ( ) {
queue . remove_invalid ( & hash , & fetch_account ) ;
}
2016-04-15 07:38:23 +02:00
}
2016-06-06 14:33:12 +02:00
if ! block . transactions ( ) . is_empty ( ) {
trace! ( target : " miner " , " prepare_sealing: block has transaction - attempting internal seal. " ) ;
// block with transactions - see if we can seal immediately.
let s = self . engine ( ) . generate_seal ( block . block ( ) , match self . accounts {
Some ( ref x ) = > Some ( & * * x ) ,
None = > None ,
} ) ;
if let Some ( seal ) = s {
trace! ( target : " miner " , " prepare_sealing: managed internal seal. importing... " ) ;
2016-06-13 18:51:14 +02:00
if let Ok ( sealed ) = block . lock ( ) . try_seal ( self . engine ( ) , seal ) {
2016-06-06 14:33:12 +02:00
if let Ok ( _ ) = chain . import_block ( sealed . rlp_bytes ( ) ) {
trace! ( target : " miner " , " prepare_sealing: sealed internally and imported. leaving. " ) ;
2016-05-03 17:23:53 +02:00
} else {
2016-06-06 14:33:12 +02:00
warn! ( " prepare_sealing: ERROR: could not import internally sealed block. WTF? " ) ;
2016-05-03 17:23:53 +02:00
}
} else {
2016-06-06 14:33:12 +02:00
warn! ( " prepare_sealing: ERROR: try_seal failed when given internally generated seal. WTF? " ) ;
2016-05-03 17:23:53 +02:00
}
2016-06-06 14:33:12 +02:00
return ;
} else {
trace! ( target : " miner " , " prepare_sealing: unable to generate seal internally " ) ;
2016-03-26 20:36:03 +01:00
}
2016-03-22 13:05:18 +01:00
}
2016-06-21 11:26:43 +02:00
2016-06-30 22:35:59 +02:00
let ( work , is_new ) = {
2016-07-06 19:52:34 +02:00
let mut sealing_work = self . sealing_work . locked ( ) ;
2016-06-30 22:35:59 +02:00
let last_work_hash = sealing_work . peek_last_ref ( ) . map ( | pb | pb . block ( ) . fields ( ) . header . hash ( ) ) ;
trace! ( target : " miner " , " Checking whether we need to reseal: orig={:?} last={:?}, this={:?} " , original_work_hash , last_work_hash , block . block ( ) . fields ( ) . header . hash ( ) ) ;
let ( work , is_new ) = if last_work_hash . map_or ( true , | h | h ! = block . block ( ) . fields ( ) . header . hash ( ) ) {
2016-06-29 20:04:52 +02:00
trace! ( target : " miner " , " Pushing a new, refreshed or borrowed pending {}... " , block . block ( ) . fields ( ) . header . hash ( ) ) ;
let pow_hash = block . block ( ) . fields ( ) . header . hash ( ) ;
let number = block . block ( ) . fields ( ) . header . number ( ) ;
let difficulty = * block . block ( ) . fields ( ) . header . difficulty ( ) ;
2016-06-30 23:14:54 +02:00
let is_new = original_work_hash . map_or ( true , | h | block . block ( ) . fields ( ) . header . hash ( ) ! = h ) ;
2016-06-29 20:04:52 +02:00
sealing_work . push ( block ) ;
2016-07-01 20:38:37 +02:00
// If push notifications are enabled we assume all work items are used.
if self . work_poster . is_some ( ) & & is_new {
sealing_work . use_last_ref ( ) ;
}
2016-06-30 22:35:59 +02:00
( Some ( ( pow_hash , difficulty , number ) ) , is_new )
2016-06-29 20:04:52 +02:00
} else {
2016-06-30 22:35:59 +02:00
( None , false )
2016-06-29 20:04:52 +02:00
} ;
trace! ( target : " miner " , " prepare_sealing: leaving (last={:?}) " , sealing_work . peek_last_ref ( ) . map ( | b | b . block ( ) . fields ( ) . header . hash ( ) ) ) ;
2016-06-30 22:35:59 +02:00
( work , is_new )
2016-06-29 20:04:52 +02:00
} ;
2016-06-30 22:35:59 +02:00
if is_new {
work . map ( | ( pow_hash , difficulty , number ) | self . work_poster . as_ref ( ) . map ( | ref p | p . notify ( pow_hash , difficulty , number ) ) ) ;
}
2016-03-18 19:36:32 +01:00
}
2016-05-31 20:33:26 +02:00
fn update_gas_limit ( & self , chain : & MiningBlockChainClient ) {
2016-03-17 15:20:33 +01:00
let gas_limit = HeaderView ::new ( & chain . best_block_header ( ) ) . gas_limit ( ) ;
2016-07-06 19:52:34 +02:00
let mut queue = self . transaction_queue . locked ( ) ;
2016-03-17 15:20:33 +01:00
queue . set_gas_limit ( gas_limit ) ;
2016-03-17 12:47:31 +01:00
}
2016-04-28 17:36:53 +02:00
/// Returns true if we had to prepare new pending block
2016-05-31 20:33:26 +02:00
fn enable_and_prepare_sealing ( & self , chain : & MiningBlockChainClient ) -> bool {
2016-04-28 17:36:53 +02:00
trace! ( target : " miner " , " enable_and_prepare_sealing: entering " ) ;
2016-07-06 19:52:34 +02:00
let have_work = self . sealing_work . locked ( ) . peek_last_ref ( ) . is_some ( ) ;
2016-04-28 17:36:53 +02:00
trace! ( target : " miner " , " enable_and_prepare_sealing: have_work={} " , have_work ) ;
if ! have_work {
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-04-28 17:36:53 +02:00
self . sealing_enabled . store ( true , atomic ::Ordering ::Relaxed ) ;
self . prepare_sealing ( chain ) ;
}
2016-07-06 19:52:34 +02:00
let mut sealing_block_last_request = self . sealing_block_last_request . locked ( ) ;
2016-04-28 17:36:53 +02:00
let best_number = chain . chain_info ( ) . best_block_number ;
if * sealing_block_last_request ! = best_number {
trace! ( target : " miner " , " enable_and_prepare_sealing: Miner received request (was {}, now {}) - waking up. " , * sealing_block_last_request , best_number ) ;
* sealing_block_last_request = best_number ;
}
// Return if
! have_work
}
2016-06-29 16:26:19 +02:00
2016-07-06 17:15:59 +02:00
fn add_transactions_to_queue ( & self , chain : & MiningBlockChainClient , transactions : Vec < SignedTransaction > , origin : TransactionOrigin , transaction_queue : & mut TransactionQueue ) ->
Vec < Result < TransactionImportResult , Error > > {
let fetch_account = | a : & Address | AccountDetails {
nonce : chain . latest_nonce ( a ) ,
balance : chain . latest_balance ( a ) ,
} ;
transactions . into_iter ( )
. map ( | tx | transaction_queue . add ( tx , & fetch_account , origin ) )
. collect ( )
}
2016-06-29 16:26:19 +02:00
/// Are we allowed to do a non-mandatory reseal?
2016-07-06 19:52:34 +02:00
fn tx_reseal_allowed ( & self ) -> bool { Instant ::now ( ) > * self . next_allowed_reseal . locked ( ) }
2016-03-09 13:28:37 +01:00
}
2016-03-18 13:59:11 +01:00
const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5 ;
2016-03-09 13:28:37 +01:00
impl MinerService for Miner {
2016-05-31 20:33:26 +02:00
fn clear_and_reset ( & self , chain : & MiningBlockChainClient ) {
2016-07-06 19:52:34 +02:00
self . transaction_queue . locked ( ) . clear ( ) ;
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-03-17 12:47:31 +01:00
self . update_sealing ( chain ) ;
2016-03-09 14:26:28 +01:00
}
2016-03-09 13:28:37 +01:00
fn status ( & self ) -> MinerStatus {
2016-07-06 19:52:34 +02:00
let status = self . transaction_queue . locked ( ) . status ( ) ;
let sealing_work = self . sealing_work . locked ( ) ;
2016-03-08 16:23:32 +01:00
MinerStatus {
2016-03-17 11:19:12 +01:00
transactions_in_pending_queue : status . pending ,
transactions_in_future_queue : status . future ,
2016-03-24 23:03:22 +01:00
transactions_in_pending_block : sealing_work . peek_last_ref ( ) . map_or ( 0 , | b | b . transactions ( ) . len ( ) ) ,
2016-03-08 16:23:32 +01:00
}
}
2016-06-02 12:28:09 +02:00
fn call ( & self , chain : & MiningBlockChainClient , t : & SignedTransaction , analytics : CallAnalytics ) -> Result < Executed , ExecutionError > {
2016-07-06 19:52:34 +02:00
let sealing_work = self . sealing_work . locked ( ) ;
2016-04-28 21:47:44 +02:00
match sealing_work . peek_last_ref ( ) {
Some ( work ) = > {
let block = work . block ( ) ;
2016-06-05 17:23:27 +02:00
// TODO: merge this code with client.rs's fn call somwhow.
2016-04-28 21:47:44 +02:00
let header = block . header ( ) ;
let last_hashes = chain . last_hashes ( ) ;
let env_info = EnvInfo {
number : header . number ( ) ,
2016-05-02 13:13:12 +02:00
author : * header . author ( ) ,
2016-04-28 21:47:44 +02:00
timestamp : header . timestamp ( ) ,
2016-05-02 13:13:12 +02:00
difficulty : * header . difficulty ( ) ,
2016-04-28 21:47:44 +02:00
last_hashes : last_hashes ,
gas_used : U256 ::zero ( ) ,
gas_limit : U256 ::max_value ( ) ,
} ;
// that's just a copy of the state.
let mut state = block . state ( ) . clone ( ) ;
2016-05-14 14:28:44 +02:00
let sender = try ! ( t . sender ( ) . map_err ( | e | {
let message = format! ( " Transaction malformed: {:?} " , e ) ;
ExecutionError ::TransactionMalformed ( message )
} ) ) ;
2016-04-28 21:47:44 +02:00
let balance = state . balance ( & sender ) ;
2016-06-05 17:23:27 +02:00
let needed_balance = t . value + t . gas * t . gas_price ;
if balance < needed_balance {
// give the sender a sufficient balance
state . add_balance ( & sender , & ( needed_balance - balance ) ) ;
}
2016-06-02 13:50:50 +02:00
let options = TransactOptions { tracing : analytics . transaction_tracing , vm_tracing : analytics . vm_tracing , check_nonce : false } ;
2016-05-31 21:03:44 +02:00
let mut ret = Executive ::new ( & mut state , & env_info , self . engine ( ) , chain . vm_factory ( ) ) . transact ( t , options ) ;
2016-06-06 14:33:12 +02:00
2016-05-31 21:03:44 +02:00
// TODO gav move this into Executive.
2016-06-02 12:39:25 +02:00
if analytics . state_diffing {
2016-05-31 21:03:44 +02:00
if let Ok ( ref mut x ) = ret {
2016-06-02 12:39:25 +02:00
x . state_diff = Some ( state . diff_from ( block . state ( ) . clone ( ) ) ) ;
2016-05-31 21:03:44 +02:00
}
}
ret
2016-04-28 21:47:44 +02:00
} ,
None = > {
2016-05-31 21:03:44 +02:00
chain . call ( t , analytics )
2016-04-28 21:47:44 +02:00
}
}
}
2016-05-31 20:33:26 +02:00
fn balance ( & self , chain : & MiningBlockChainClient , address : & Address ) -> U256 {
2016-07-06 19:52:34 +02:00
let sealing_work = self . sealing_work . locked ( ) ;
2016-05-26 11:46:45 +02:00
sealing_work . peek_last_ref ( ) . map_or_else (
2016-05-26 22:17:55 +02:00
| | chain . latest_balance ( address ) ,
2016-05-26 11:46:45 +02:00
| b | b . block ( ) . fields ( ) . state . balance ( address )
)
2016-04-28 21:47:44 +02:00
}
2016-05-31 20:33:26 +02:00
fn storage_at ( & self , chain : & MiningBlockChainClient , address : & Address , position : & H256 ) -> H256 {
2016-07-06 19:52:34 +02:00
let sealing_work = self . sealing_work . locked ( ) ;
2016-05-26 11:46:45 +02:00
sealing_work . peek_last_ref ( ) . map_or_else (
2016-05-26 22:17:55 +02:00
| | chain . latest_storage_at ( address , position ) ,
2016-05-26 11:46:45 +02:00
| b | b . block ( ) . fields ( ) . state . storage_at ( address , position )
)
2016-04-28 21:47:44 +02:00
}
2016-05-31 20:33:26 +02:00
fn nonce ( & self , chain : & MiningBlockChainClient , address : & Address ) -> U256 {
2016-07-06 19:52:34 +02:00
let sealing_work = self . sealing_work . locked ( ) ;
2016-05-26 22:17:55 +02:00
sealing_work . peek_last_ref ( ) . map_or_else ( | | chain . latest_nonce ( address ) , | b | b . block ( ) . fields ( ) . state . nonce ( address ) )
2016-04-28 21:47:44 +02:00
}
2016-05-31 20:33:26 +02:00
fn code ( & self , chain : & MiningBlockChainClient , address : & Address ) -> Option < Bytes > {
2016-07-06 19:52:34 +02:00
let sealing_work = self . sealing_work . locked ( ) ;
2016-04-28 21:47:44 +02:00
sealing_work . peek_last_ref ( ) . map_or_else ( | | chain . code ( address ) , | b | b . block ( ) . fields ( ) . state . code ( address ) )
}
2016-04-13 00:04:40 +02:00
fn set_author ( & self , author : Address ) {
2016-07-07 09:37:31 +02:00
* self . author . unwrapped_write ( ) = author ;
2016-04-13 00:04:40 +02:00
}
fn set_extra_data ( & self , extra_data : Bytes ) {
2016-07-07 09:37:31 +02:00
* self . extra_data . unwrapped_write ( ) = extra_data ;
2016-04-13 00:04:40 +02:00
}
/// Set the gas limit we wish to target when sealing a new block.
fn set_gas_floor_target ( & self , target : U256 ) {
2016-07-07 09:37:31 +02:00
self . gas_range_target . unwrapped_write ( ) . 0 = target ;
2016-06-23 14:29:16 +02:00
}
fn set_gas_ceil_target ( & self , target : U256 ) {
2016-07-07 09:37:31 +02:00
self . gas_range_target . unwrapped_write ( ) . 1 = target ;
2016-04-13 00:04:40 +02:00
}
fn set_minimal_gas_price ( & self , min_gas_price : U256 ) {
2016-07-06 19:52:34 +02:00
self . transaction_queue . locked ( ) . set_minimal_gas_price ( min_gas_price ) ;
2016-04-13 00:04:40 +02:00
}
fn minimal_gas_price ( & self ) -> U256 {
2016-07-06 19:52:34 +02:00
* self . transaction_queue . locked ( ) . minimal_gas_price ( )
2016-04-13 00:04:40 +02:00
}
2016-03-28 18:53:33 +02:00
fn sensible_gas_price ( & self ) -> U256 {
// 10% above our minimum.
2016-07-06 19:52:34 +02:00
* self . transaction_queue . locked ( ) . minimal_gas_price ( ) * 110. into ( ) / 100. into ( )
2016-03-28 18:53:33 +02:00
}
2016-04-14 21:01:12 +02:00
fn sensible_gas_limit ( & self ) -> U256 {
2016-07-07 09:37:31 +02:00
self . gas_range_target . unwrapped_read ( ) . 0 / 5. into ( )
2016-04-14 21:01:12 +02:00
}
2016-04-18 23:03:41 +02:00
fn transactions_limit ( & self ) -> usize {
2016-07-06 19:52:34 +02:00
self . transaction_queue . locked ( ) . limit ( )
2016-04-18 23:03:41 +02:00
}
fn set_transactions_limit ( & self , limit : usize ) {
2016-07-06 19:52:34 +02:00
self . transaction_queue . locked ( ) . set_limit ( limit )
2016-04-18 23:03:41 +02:00
}
2016-06-28 10:21:29 +02:00
fn set_tx_gas_limit ( & self , limit : U256 ) {
2016-07-06 19:52:34 +02:00
self . transaction_queue . locked ( ) . set_tx_gas_limit ( limit )
2016-06-27 20:19:01 +02:00
}
2016-04-11 21:06:32 +02:00
/// Get the author that we will seal blocks as.
2016-03-22 19:12:17 +01:00
fn author ( & self ) -> Address {
2016-07-07 09:37:31 +02:00
* self . author . unwrapped_read ( )
2016-03-22 19:12:17 +01:00
}
2016-04-11 21:06:32 +02:00
/// Get the extra_data that we will seal blocks with.
2016-03-22 19:12:17 +01:00
fn extra_data ( & self ) -> Bytes {
2016-07-07 09:37:31 +02:00
self . extra_data . unwrapped_read ( ) . clone ( )
2016-03-22 19:12:17 +01:00
}
2016-04-11 21:06:32 +02:00
/// Get the gas limit we wish to target when sealing a new block.
fn gas_floor_target ( & self ) -> U256 {
2016-07-07 09:37:31 +02:00
self . gas_range_target . unwrapped_read ( ) . 0
2016-06-23 14:29:16 +02:00
}
/// Get the gas limit we wish to target when sealing a new block.
fn gas_ceil_target ( & self ) -> U256 {
2016-07-07 09:37:31 +02:00
self . gas_range_target . unwrapped_read ( ) . 1
2016-04-11 21:06:32 +02:00
}
2016-07-08 17:26:06 +02:00
fn import_external_transactions (
& self ,
chain : & MiningBlockChainClient ,
transactions : Vec < SignedTransaction >
) -> Vec < Result < TransactionImportResult , Error > > {
2016-07-06 17:15:59 +02:00
2016-07-08 17:26:06 +02:00
let results = {
2016-07-08 20:42:11 +02:00
let mut transaction_queue = self . transaction_queue . locked ( ) ;
2016-07-08 17:19:14 +02:00
self . add_transactions_to_queue (
chain , transactions , TransactionOrigin ::External , & mut transaction_queue
)
2016-07-08 17:26:06 +02:00
} ;
2016-07-06 17:15:59 +02:00
if ! results . is_empty ( ) & & self . options . reseal_on_external_tx & & self . tx_reseal_allowed ( ) {
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-06-21 16:00:34 +02:00
self . update_sealing ( chain ) ;
}
results
2016-03-08 15:46:44 +01:00
}
2016-07-06 17:15:59 +02:00
fn import_own_transaction (
2016-06-19 14:51:51 +02:00
& self ,
chain : & MiningBlockChainClient ,
transaction : SignedTransaction ,
2016-07-06 17:15:59 +02:00
) -> Result < TransactionImportResult , Error > {
2016-06-19 14:51:51 +02:00
2016-04-17 20:36:37 +02:00
let hash = transaction . hash ( ) ;
trace! ( target : " own_tx " , " Importing transaction: {:?} " , transaction ) ;
2016-04-28 17:36:53 +02:00
let imported = {
// Be sure to release the lock before we call enable_and_prepare_sealing
2016-07-06 19:52:34 +02:00
let mut transaction_queue = self . transaction_queue . locked ( ) ;
2016-07-06 17:15:59 +02:00
let import = self . add_transactions_to_queue ( chain , vec! [ transaction ] , TransactionOrigin ::Local , & mut transaction_queue ) . pop ( ) . unwrap ( ) ;
2016-04-28 17:36:53 +02:00
match import {
Ok ( ref res ) = > {
trace! ( target : " own_tx " , " Imported transaction to {:?} (hash: {:?}) " , res , hash ) ;
trace! ( target : " own_tx " , " Status: {:?} " , transaction_queue . status ( ) ) ;
} ,
Err ( ref e ) = > {
trace! ( target : " own_tx " , " Failed to import transaction {:?} (hash: {:?}) " , e , hash ) ;
trace! ( target : " own_tx " , " Status: {:?} " , transaction_queue . status ( ) ) ;
2016-05-30 13:13:48 +02:00
warn! ( target : " own_tx " , " Error importing transaction: {:?} " , e ) ;
2016-04-28 17:36:53 +02:00
} ,
}
import
} ;
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-06-29 16:26:19 +02:00
if imported . is_ok ( ) & & self . options . reseal_on_own_tx & & self . tx_reseal_allowed ( ) {
2016-04-28 17:36:53 +02:00
// Make sure to do it after transaction is imported and lock is droped.
// We need to create pending block and enable sealing
let prepared = self . enable_and_prepare_sealing ( chain ) ;
// If new block has not been prepared (means we already had one)
// we need to update sealing
if ! prepared {
self . update_sealing ( chain ) ;
}
2016-04-17 20:36:37 +02:00
}
2016-04-28 17:36:53 +02:00
imported
2016-04-17 18:26:15 +02:00
}
2016-06-27 19:06:54 +02:00
fn all_transactions ( & self ) -> Vec < SignedTransaction > {
2016-07-06 19:52:34 +02:00
let queue = self . transaction_queue . locked ( ) ;
2016-06-27 19:06:54 +02:00
queue . top_transactions ( )
2016-03-10 16:00:55 +01:00
}
2016-06-27 19:06:54 +02:00
fn pending_transactions ( & self ) -> Vec < SignedTransaction > {
2016-07-06 19:52:34 +02:00
let queue = self . transaction_queue . locked ( ) ;
let sw = self . sealing_work . locked ( ) ;
2016-06-27 19:06:54 +02:00
// TODO: should only use the sealing_work when it's current (it could be an old block)
let sealing_set = match self . sealing_enabled . load ( atomic ::Ordering ::Relaxed ) {
true = > sw . peek_last_ref ( ) ,
false = > None ,
} ;
match ( & self . options . pending_set , sealing_set ) {
( & PendingSet ::AlwaysQueue , _ ) | ( & PendingSet ::SealingOrElseQueue , None ) = > queue . top_transactions ( ) ,
2016-07-12 10:28:35 +02:00
( _ , sealing ) = > sealing . map_or_else ( Vec ::new , | s | s . transactions ( ) . to_owned ( ) ) ,
2016-05-24 21:56:32 +02:00
}
2016-03-27 15:12:21 +02:00
}
2016-06-27 19:06:54 +02:00
fn pending_transactions_hashes ( & self ) -> Vec < H256 > {
2016-07-06 19:52:34 +02:00
let queue = self . transaction_queue . locked ( ) ;
let sw = self . sealing_work . locked ( ) ;
2016-06-27 19:06:54 +02:00
let sealing_set = match self . sealing_enabled . load ( atomic ::Ordering ::Relaxed ) {
true = > sw . peek_last_ref ( ) ,
false = > None ,
} ;
match ( & self . options . pending_set , sealing_set ) {
( & PendingSet ::AlwaysQueue , _ ) | ( & PendingSet ::SealingOrElseQueue , None ) = > queue . pending_hashes ( ) ,
2016-06-28 10:00:28 +02:00
( _ , sealing ) = > sealing . map_or_else ( Vec ::new , | s | s . transactions ( ) . iter ( ) . map ( | t | t . hash ( ) ) . collect ( ) ) ,
2016-06-27 19:06:54 +02:00
}
2016-04-06 23:03:07 +02:00
}
2016-06-27 19:06:54 +02:00
fn transaction ( & self , hash : & H256 ) -> Option < SignedTransaction > {
2016-07-06 19:52:34 +02:00
let queue = self . transaction_queue . locked ( ) ;
let sw = self . sealing_work . locked ( ) ;
2016-06-27 19:06:54 +02:00
let sealing_set = match self . sealing_enabled . load ( atomic ::Ordering ::Relaxed ) {
true = > sw . peek_last_ref ( ) ,
false = > None ,
} ;
match ( & self . options . pending_set , sealing_set ) {
( & PendingSet ::AlwaysQueue , _ ) | ( & PendingSet ::SealingOrElseQueue , None ) = > queue . find ( hash ) ,
( _ , sealing ) = > sealing . and_then ( | s | s . transactions ( ) . iter ( ) . find ( | t | & t . hash ( ) = = hash ) . cloned ( ) ) ,
2016-05-24 21:56:32 +02:00
}
}
fn pending_receipts ( & self ) -> BTreeMap < H256 , Receipt > {
2016-07-06 19:52:34 +02:00
match ( self . sealing_enabled . load ( atomic ::Ordering ::Relaxed ) , self . sealing_work . locked ( ) . peek_last_ref ( ) ) {
2016-05-24 21:56:32 +02:00
( true , Some ( pending ) ) = > {
let hashes = pending . transactions ( )
. iter ( )
. map ( | t | t . hash ( ) ) ;
2016-07-12 10:28:35 +02:00
let receipts = pending . receipts ( ) . iter ( ) . cloned ( ) ;
2016-05-24 21:56:32 +02:00
hashes . zip ( receipts ) . collect ( )
} ,
_ = > BTreeMap ::new ( )
}
}
2016-04-06 12:15:20 +02:00
fn last_nonce ( & self , address : & Address ) -> Option < U256 > {
2016-07-06 19:52:34 +02:00
self . transaction_queue . locked ( ) . last_nonce ( address )
2016-04-06 12:15:20 +02:00
}
2016-05-31 20:33:26 +02:00
fn update_sealing ( & self , chain : & MiningBlockChainClient ) {
2016-03-24 14:51:51 +01:00
if self . sealing_enabled . load ( atomic ::Ordering ::Relaxed ) {
2016-03-18 13:59:11 +01:00
let current_no = chain . chain_info ( ) . best_block_number ;
2016-07-06 19:52:34 +02:00
let has_local_transactions = self . transaction_queue . locked ( ) . has_local_pending_transactions ( ) ;
let last_request = * self . sealing_block_last_request . locked ( ) ;
2016-06-29 20:04:52 +02:00
let should_disable_sealing = ! self . forced_sealing ( )
2016-04-28 17:36:53 +02:00
& & ! has_local_transactions
& & current_no > last_request
& & current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS ;
2016-03-24 14:51:51 +01:00
if should_disable_sealing {
trace! ( target : " miner " , " Miner sleeping (current {}, last {}) " , current_no , last_request ) ;
self . sealing_enabled . store ( false , atomic ::Ordering ::Relaxed ) ;
2016-07-06 19:52:34 +02:00
self . sealing_work . locked ( ) . reset ( ) ;
2016-06-14 03:04:06 +02:00
} else {
2016-07-06 19:52:34 +02:00
* self . next_allowed_reseal . locked ( ) = Instant ::now ( ) + self . options . reseal_min_period ;
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-03-24 14:51:51 +01:00
self . prepare_sealing ( chain ) ;
}
2016-03-17 12:47:31 +01:00
}
2016-03-08 15:46:44 +01:00
}
2016-05-31 20:33:26 +02:00
fn map_sealing_work < F , T > ( & self , chain : & MiningBlockChainClient , f : F ) -> Option < T > where F : FnOnce ( & ClosedBlock ) -> T {
2016-03-26 20:36:03 +01:00
trace! ( target : " miner " , " map_sealing_work: entering " ) ;
2016-04-28 17:36:53 +02:00
self . enable_and_prepare_sealing ( chain ) ;
trace! ( target : " miner " , " map_sealing_work: sealing prepared " ) ;
2016-07-06 19:52:34 +02:00
let mut sealing_work = self . sealing_work . locked ( ) ;
2016-03-26 20:36:03 +01:00
let ret = sealing_work . use_last_ref ( ) ;
trace! ( target : " miner " , " map_sealing_work: leaving use_last_ref={:?} " , ret . as_ref ( ) . map ( | b | b . block ( ) . fields ( ) . header . hash ( ) ) ) ;
ret . map ( f )
2016-03-08 15:46:44 +01:00
}
2016-05-31 20:33:26 +02:00
fn submit_seal ( & self , chain : & MiningBlockChainClient , pow_hash : H256 , seal : Vec < Bytes > ) -> Result < ( ) , Error > {
2016-07-06 19:52:34 +02:00
let result = if let Some ( b ) = self . sealing_work . locked ( ) . get_used_if ( if self . options . enable_resubmission { GetAction ::Clone } else { GetAction ::Take } , | b | & b . hash ( ) = = & pow_hash ) {
2016-06-29 19:19:45 +02:00
b . lock ( ) . try_seal ( self . engine ( ) , seal ) . or_else ( | _ | {
warn! ( target : " miner " , " Mined solution rejected: Invalid. " ) ;
Err ( Error ::PowInvalid )
} )
2016-03-22 13:05:18 +01:00
} else {
2016-06-29 19:19:45 +02:00
warn! ( target : " miner " , " Mined solution rejected: Block unknown or out of date. " ) ;
2016-03-22 13:05:18 +01:00
Err ( Error ::PowHashInvalid )
2016-06-29 21:49:12 +02:00
} ;
result . and_then ( | sealed | {
2016-06-29 16:45:17 +02:00
let n = sealed . header ( ) . number ( ) ;
let h = sealed . header ( ) . hash ( ) ;
2016-06-29 21:49:12 +02:00
try ! ( chain . import_sealed_block ( sealed ) ) ;
2016-07-06 18:28:11 +02:00
info! ( target : " miner " , " Mined block imported OK. #{}: {} " , format! ( " {} " , n ) . apply ( Colour ::White . bold ( ) ) , h . hex ( ) . apply ( Colour ::White . bold ( ) ) ) ;
2016-06-29 21:49:12 +02:00
Ok ( ( ) )
} )
2016-03-08 15:46:44 +01:00
}
2016-05-31 20:33:26 +02:00
fn chain_new_blocks ( & self , chain : & MiningBlockChainClient , _imported : & [ H256 ] , _invalid : & [ H256 ] , enacted : & [ H256 ] , retracted : & [ H256 ] ) {
fn fetch_transactions ( chain : & MiningBlockChainClient , hash : & H256 ) -> Vec < SignedTransaction > {
2016-03-08 15:46:44 +01:00
let block = chain
2016-05-19 11:00:32 +02:00
. block ( BlockID ::Hash ( * hash ) )
2016-03-08 15:46:44 +01:00
// Client should send message after commit to db and inserting to chain.
. expect ( " Expected in-chain blocks. " ) ;
let block = BlockView ::new ( & block ) ;
2016-07-06 17:15:59 +02:00
let txs = block . transactions ( ) ;
// populate sender
for tx in & txs {
let _sender = tx . sender ( ) ;
}
txs
2016-03-08 15:46:44 +01:00
}
2016-03-17 15:20:33 +01:00
2016-04-15 07:38:23 +02:00
// 1. We ignore blocks that were `imported` (because it means that they are not in canon-chain, and transactions
// should be still available in the queue.
// 2. We ignore blocks that are `invalid` because it doesn't have any meaning in terms of the transactions that
// are in those blocks
2016-03-17 15:20:33 +01:00
// First update gas limit in transaction queue
self . update_gas_limit ( chain ) ;
// Then import all transactions...
2016-03-08 15:46:44 +01:00
{
2016-03-13 15:29:55 +01:00
let out_of_chain = retracted
. par_iter ( )
2016-03-13 15:36:03 +01:00
. map ( | h | fetch_transactions ( chain , h ) ) ;
2016-03-13 15:29:55 +01:00
out_of_chain . for_each ( | txs | {
2016-07-06 19:52:34 +02:00
let mut transaction_queue = self . transaction_queue . locked ( ) ;
2016-07-06 17:42:01 +02:00
let _ = self . add_transactions_to_queue (
chain , txs , TransactionOrigin ::External , & mut transaction_queue
) ;
2016-03-08 15:46:44 +01:00
} ) ;
}
2016-03-17 15:20:33 +01:00
2016-04-15 07:38:23 +02:00
// ...and at the end remove old ones
2016-03-15 23:01:36 +01:00
{
2016-04-15 07:38:23 +02:00
let in_chain = enacted
2016-03-15 23:01:36 +01:00
. par_iter ( )
. map ( | h : & H256 | fetch_transactions ( chain , h ) ) ;
2016-04-15 07:38:23 +02:00
in_chain . for_each ( | mut txs | {
2016-07-06 19:52:34 +02:00
let mut transaction_queue = self . transaction_queue . locked ( ) ;
2016-04-15 07:38:23 +02:00
let to_remove = txs . drain ( .. )
. map ( | tx | {
tx . sender ( ) . expect ( " Transaction is in block, so sender has to be defined. " )
} )
. collect ::< HashSet < Address > > ( ) ;
for sender in to_remove . into_iter ( ) {
2016-05-26 22:17:55 +02:00
transaction_queue . remove_all ( sender , chain . latest_nonce ( & sender ) ) ;
2016-04-15 07:38:23 +02:00
}
2016-03-08 15:46:44 +01:00
} ) ;
}
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-03-17 12:47:31 +01:00
self . update_sealing ( chain ) ;
2016-03-08 15:46:44 +01:00
}
}
2016-03-18 13:59:11 +01:00
#[ cfg(test) ]
mod tests {
2016-05-31 22:24:32 +02:00
use super ::super ::MinerService ;
use super ::Miner ;
2016-03-25 16:41:01 +01:00
use util ::* ;
2016-05-31 22:24:32 +02:00
use client ::{ TestBlockChainClient , EachBlockWith } ;
use block ::* ;
2016-06-23 21:04:23 +02:00
use spec ::Spec ;
2016-03-18 13:59:11 +01:00
#[ test ]
fn should_prepare_block_to_seal ( ) {
// given
let client = TestBlockChainClient ::default ( ) ;
2016-06-20 10:28:38 +02:00
let miner = Miner ::with_spec ( Spec ::new_test ( ) ) ;
2016-03-18 13:59:11 +01:00
// when
2016-03-25 16:41:01 +01:00
let sealing_work = miner . map_sealing_work ( & client , | _ | ( ) ) ;
assert! ( sealing_work . is_some ( ) , " Expected closed block " ) ;
2016-03-18 13:59:11 +01:00
}
#[ test ]
2016-03-25 16:41:01 +01:00
fn should_still_work_after_a_couple_of_blocks ( ) {
2016-03-18 13:59:11 +01:00
// given
let client = TestBlockChainClient ::default ( ) ;
2016-06-20 10:28:38 +02:00
let miner = Miner ::with_spec ( Spec ::new_test ( ) ) ;
2016-03-18 13:59:11 +01:00
2016-03-25 16:41:01 +01:00
let res = miner . map_sealing_work ( & client , | b | b . block ( ) . fields ( ) . header . hash ( ) ) ;
assert! ( res . is_some ( ) ) ;
assert! ( miner . submit_seal ( & client , res . unwrap ( ) , vec! [ ] ) . is_ok ( ) ) ;
// two more blocks mined, work requested.
client . add_blocks ( 1 , EachBlockWith ::Uncle ) ;
miner . map_sealing_work ( & client , | b | b . block ( ) . fields ( ) . header . hash ( ) ) ;
client . add_blocks ( 1 , EachBlockWith ::Uncle ) ;
miner . map_sealing_work ( & client , | b | b . block ( ) . fields ( ) . header . hash ( ) ) ;
2016-03-18 13:59:11 +01:00
2016-03-25 16:41:01 +01:00
// solution to original work submitted.
assert! ( miner . submit_seal ( & client , res . unwrap ( ) , vec! [ ] ) . is_ok ( ) ) ;
2016-03-18 13:59:11 +01:00
}
}