2017-01-25 18:51:41 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-03-08 15:46:44 +01: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-06-29 16:26:19 +02:00
use std ::time ::{ Instant , Duration } ;
2017-07-29 17:12:07 +02:00
use std ::collections ::{ BTreeMap , HashSet } ;
2017-07-29 21:56:42 +02:00
use std ::sync ::Arc ;
2016-03-11 14:48:30 +01:00
2018-01-11 17:49:10 +01:00
use account_provider ::{ AccountProvider , SignError as AccountError } ;
use ansi_term ::Colour ;
2018-01-10 13:35:18 +01:00
use ethereum_types ::{ H256 , U256 , Address } ;
2017-09-02 20:09:13 +02:00
use parking_lot ::{ Mutex , RwLock } ;
2017-09-06 20:47:45 +02:00
use bytes ::Bytes ;
2018-01-11 17:49:10 +01:00
use engines ::{ EthEngine , Seal } ;
2018-04-09 16:14:33 +02:00
use error ::{ ExecutionError , Error } ;
2018-01-11 17:49:10 +01:00
use ethcore_miner ::banning_queue ::{ BanningTransactionQueue , Threshold } ;
use ethcore_miner ::local_transactions ::{ Status as LocalTransactionStatus } ;
use ethcore_miner ::transaction_queue ::{
TransactionQueue ,
RemovalReason ,
TransactionDetailsProvider as TransactionQueueDetailsProvider ,
PrioritizationStrategy ,
AccountDetails ,
TransactionOrigin ,
} ;
2018-03-14 13:40:54 +01:00
use futures_cpupool ::CpuPool ;
2018-04-10 13:51:29 +02:00
use ethcore_miner ::work_notify ::NotifyWork ;
2018-03-03 18:42:13 +01:00
use miner ::service_transaction_checker ::ServiceTransactionChecker ;
2018-01-11 17:49:10 +01:00
use miner ::{ MinerService , MinerStatus } ;
use price_info ::fetch ::Client as FetchClient ;
use price_info ::{ Client as PriceInfoClient , PriceInfo } ;
use transaction ::{
Action ,
UnverifiedTransaction ,
PendingTransaction ,
SignedTransaction ,
Condition as TransactionCondition ,
ImportResult as TransactionImportResult ,
Error as TransactionError ,
} ;
2017-07-29 17:12:07 +02:00
use using_queue ::{ UsingQueue , GetAction } ;
2018-01-11 17:49:10 +01:00
use block ::{ ClosedBlock , IsBlock , Block } ;
2018-03-03 18:42:13 +01:00
use client ::{
AccountData , BlockChain , RegistryInfo , ScheduleInfo , CallContract , BlockProducer , SealedBlockImporter
} ;
use client ::{ BlockId , TransactionId , MiningBlockChainClient } ;
2016-08-17 19:25:02 +02:00
use executive ::contract_address ;
2018-01-11 17:49:10 +01:00
use header ::{ Header , BlockNumber } ;
2016-08-17 19:25:02 +02:00
use receipt ::{ Receipt , RichReceipt } ;
2016-05-31 19:52:53 +02:00
use spec ::Spec ;
2018-01-11 17:49:10 +01:00
use state ::State ;
2016-07-01 21:13:56 +02:00
2016-06-27 19:06:54 +02:00
/// Different possible definitions for pending transaction set.
2016-07-25 16:09:47 +02:00
#[ derive(Debug, PartialEq) ]
2016-06-27 19:06:54 +02:00
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-10-10 23:04:43 +02:00
/// Type of the gas limit to apply to the transaction queue.
#[ derive(Debug, PartialEq) ]
pub enum GasLimit {
/// Depends on the block gas limit and is updated with every block.
Auto ,
/// No limit.
None ,
/// Set to a fixed gas value.
Fixed ( U256 ) ,
}
2016-10-27 19:28:34 +02:00
/// Transaction queue banning settings.
#[ derive(Debug, PartialEq, Clone) ]
pub enum Banning {
/// Banning in transaction queue is disabled
Disabled ,
/// Banning in transaction queue is enabled
Enabled {
/// Upper limit of transaction processing time before banning.
offend_threshold : Duration ,
/// Number of similar offending transactions before banning.
min_offends : u16 ,
/// Number of seconds the offender is banned for.
ban_duration : Duration ,
} ,
}
2016-06-27 17:23:54 +02:00
/// Configures the behaviour of the miner.
2016-07-25 16:09:47 +02:00
#[ derive(Debug, PartialEq) ]
2016-06-27 17:23:54 +02:00
pub struct MinerOptions {
/// 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 ,
2017-07-10 13:36:42 +02:00
/// Reseal when new uncle block has been imported.
pub reseal_on_uncle : bool ,
2016-06-29 16:26:19 +02:00
/// Minimum period between transaction-inspired reseals.
pub reseal_min_period : Duration ,
2017-03-15 14:04:42 +01:00
/// Maximum period between blocks (enables force sealing after that).
pub reseal_max_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 ,
2017-07-13 15:12:25 +02:00
/// Maximum memory usage of transactions in the queue (current / future).
pub tx_queue_memory_limit : Option < usize > ,
2016-10-15 14:46:33 +02:00
/// Strategy to use for prioritizing transactions in the queue.
pub tx_queue_strategy : PrioritizationStrategy ,
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-10-10 23:04:43 +02:00
/// Global gas limit for all transaction in the queue except for local and retracted.
pub tx_queue_gas_limit : GasLimit ,
2017-01-22 16:15:22 +01:00
/// Banning settings.
2016-10-27 19:28:34 +02:00
pub tx_queue_banning : Banning ,
2017-01-22 16:15:22 +01:00
/// Do we refuse to accept service transactions even if sender is certified.
pub refuse_service_transactions : bool ,
2017-11-03 15:20:20 +01:00
/// Create a pending block with maximal possible gas limit.
/// NOTE: Such block will contain all pending transactions but
/// will be invalid if mined.
pub infinite_pending_block : bool ,
2016-06-27 17:23:54 +02:00
}
impl Default for MinerOptions {
fn default ( ) -> Self {
MinerOptions {
force_sealing : false ,
2016-07-25 16:09:47 +02:00
reseal_on_external_tx : false ,
2016-06-27 17:23:54 +02:00
reseal_on_own_tx : true ,
2017-07-10 13:36:42 +02:00
reseal_on_uncle : false ,
2016-06-28 10:40:35 +02:00
tx_gas_limit : ! U256 ::zero ( ) ,
2017-07-13 15:12:25 +02:00
tx_queue_size : 8192 ,
tx_queue_memory_limit : Some ( 2 * 1024 * 1024 ) ,
tx_queue_gas_limit : GasLimit ::None ,
2016-10-27 19:27:08 +02:00
tx_queue_strategy : PrioritizationStrategy ::GasPriceOnly ,
2016-06-27 19:06:54 +02:00
pending_set : PendingSet ::AlwaysQueue ,
2016-07-25 16:09:47 +02:00
reseal_min_period : Duration ::from_secs ( 2 ) ,
2017-03-15 14:04:42 +01:00
reseal_max_period : Duration ::from_secs ( 120 ) ,
2016-06-29 16:26:19 +02:00
work_queue_size : 20 ,
2016-06-30 12:56:58 +02:00
enable_resubmission : true ,
2016-10-27 19:28:34 +02:00
tx_queue_banning : Banning ::Disabled ,
2017-01-22 16:15:22 +01:00
refuse_service_transactions : false ,
2017-11-03 15:20:20 +01:00
infinite_pending_block : false ,
2016-06-27 17:23:54 +02:00
}
}
}
2016-07-08 17:26:06 +02:00
/// Options for the dynamic gas price recalibrator.
2016-07-25 16:09:47 +02:00
#[ derive(Debug, PartialEq) ]
2016-07-08 17:26:06 +02:00
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-25 16:09:47 +02:00
#[ derive(Debug, PartialEq) ]
2016-07-08 17:26:06 +02:00
pub struct GasPriceCalibrator {
options : GasPriceCalibratorOptions ,
next_calibration : Instant ,
2017-07-16 18:22:45 +02:00
price_info : PriceInfoClient ,
2016-07-08 17:26:06 +02:00
}
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 " ) ;
2017-01-18 17:56:21 +01:00
2017-07-16 18:22:45 +02:00
self . price_info . get ( move | price : PriceInfo | {
2016-07-08 17:26:06 +02:00
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 ;
2017-04-19 22:59:02 +02:00
info! ( target : " miner " , " Updated conversion rate to Ξ1 = {} ({} wei/gas) " , Colour ::White . bold ( ) . paint ( format! ( " US$ {:.2} " , usd_per_eth ) ) , Colour ::Yellow . bold ( ) . paint ( format! ( " {} " , wei_per_gas ) ) ) ;
2016-10-20 23:41:15 +02:00
set_price ( U256 ::from ( wei_per_gas as u64 ) ) ;
2016-11-28 13:20:49 +01:00
} ) ;
2017-01-18 17:56:21 +01:00
self . next_calibration = Instant ::now ( ) + self . options . recalibration_period ;
2016-07-08 17:26:06 +02:00
}
}
}
/// Struct to look after updating the acceptable gas price of a miner.
2016-07-25 16:09:47 +02:00
#[ derive(Debug, PartialEq) ]
2016-07-08 17:26:06 +02:00
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`.
2018-03-14 13:40:54 +01:00
pub fn new_calibrated ( options : GasPriceCalibratorOptions , fetch : FetchClient , p : CpuPool ) -> GasPricer {
2016-07-08 17:26:06 +02:00
GasPricer ::Calibrated ( GasPriceCalibrator {
options : options ,
next_calibration : Instant ::now ( ) ,
2018-03-14 13:40:54 +01:00
price_info : PriceInfoClient ::new ( fetch , p ) ,
2016-07-08 17:26:06 +02:00
} )
}
/// 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-07-28 21:06:36 +02:00
struct SealingWork {
queue : UsingQueue < ClosedBlock > ,
enabled : bool ,
}
2016-03-09 14:26:28 +01:00
/// Keeps track of transactions using priority queue and holds currently mined block.
2016-09-13 15:09:07 +02:00
/// Handles preparing work for "work sealing" or seals "internally" if Engine does not require work.
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!
2017-03-20 19:15:02 +01:00
transaction_queue : Arc < RwLock < BanningTransactionQueue > > ,
2018-02-16 16:51:34 +01:00
transaction_listener : RwLock < Vec < Box < Fn ( & [ H256 ] ) + Send + Sync > > > ,
2016-07-28 21:06:36 +02:00
sealing_work : Mutex < SealingWork > ,
2016-08-09 11:45:07 +02:00
next_allowed_reseal : Mutex < Instant > ,
2017-03-15 14:04:42 +01:00
next_mandatory_reseal : RwLock < Instant > ,
2016-08-09 11:45:07 +02:00
sealing_block_last_request : Mutex < u64 > ,
2016-03-08 15:46:44 +01:00
// for sealing...
2016-06-27 17:23:54 +02:00
options : MinerOptions ,
2016-08-04 18:17:21 +02:00
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 > ,
2017-09-26 14:19:08 +02:00
engine : Arc < EthEngine > ,
2016-05-03 17:23:53 +02:00
2016-05-30 13:10:33 +02:00
accounts : Option < Arc < AccountProvider > > ,
2017-01-25 11:03:36 +01:00
notifiers : RwLock < Vec < Box < NotifyWork > > > ,
2016-07-08 17:26:06 +02:00
gas_pricer : Mutex < GasPricer > ,
2017-01-22 16:15:22 +01:00
service_transaction_action : ServiceTransactionAction ,
2016-03-08 15:46:44 +01:00
}
2016-06-20 10:28:38 +02:00
impl Miner {
2017-01-25 11:03:36 +01:00
/// Push notifier that will handle new jobs
pub fn push_notifier ( & self , notifier : Box < NotifyWork > ) {
2017-03-16 01:37:50 +01:00
self . notifiers . write ( ) . push ( notifier ) ;
self . sealing_work . lock ( ) . enabled = true ;
2017-01-25 11:03:36 +01:00
}
/// Creates new instance of miner Arc.
pub fn new ( options : MinerOptions , gas_pricer : GasPricer , spec : & Spec , accounts : Option < Arc < AccountProvider > > ) -> Arc < Miner > {
Arc ::new ( Miner ::new_raw ( options , gas_pricer , spec , accounts ) )
}
2016-09-15 12:12:15 +02:00
/// Creates new instance of miner.
fn new_raw ( options : MinerOptions , gas_pricer : GasPricer , spec : & Spec , accounts : Option < Arc < AccountProvider > > ) -> Miner {
2016-10-10 23:04:43 +02:00
let gas_limit = match options . tx_queue_gas_limit {
GasLimit ::Fixed ( ref limit ) = > * limit ,
_ = > ! U256 ::zero ( ) ,
} ;
2017-07-13 15:12:25 +02:00
let mem_limit = options . tx_queue_memory_limit . unwrap_or_else ( usize ::max_value ) ;
let txq = TransactionQueue ::with_limits (
options . tx_queue_strategy ,
options . tx_queue_size ,
mem_limit ,
gas_limit ,
options . tx_gas_limit
) ;
2016-10-27 19:28:34 +02:00
let txq = match options . tx_queue_banning {
Banning ::Disabled = > BanningTransactionQueue ::new ( txq , Threshold ::NeverBan , Duration ::from_secs ( 180 ) ) ,
Banning ::Enabled { ban_duration , min_offends , .. } = > BanningTransactionQueue ::new (
txq ,
Threshold ::BanAfter ( min_offends ) ,
ban_duration ,
) ,
} ;
2017-01-25 11:03:36 +01:00
2018-04-10 13:51:29 +02:00
let notifiers : Vec < Box < NotifyWork > > = Vec ::new ( ) ;
2017-01-25 11:03:36 +01:00
2017-01-22 16:15:22 +01:00
let service_transaction_action = match options . refuse_service_transactions {
true = > ServiceTransactionAction ::Refuse ,
false = > ServiceTransactionAction ::Check ( ServiceTransactionChecker ::default ( ) ) ,
} ;
2017-01-25 11:03:36 +01:00
2016-09-15 12:12:15 +02:00
Miner {
2017-03-20 19:15:02 +01:00
transaction_queue : Arc ::new ( RwLock ::new ( txq ) ) ,
2018-02-16 16:51:34 +01:00
transaction_listener : RwLock ::new ( vec! [ ] ) ,
2016-06-29 16:26:19 +02:00
next_allowed_reseal : Mutex ::new ( Instant ::now ( ) ) ,
2017-03-15 14:04:42 +01:00
next_mandatory_reseal : RwLock ::new ( Instant ::now ( ) + options . reseal_max_period ) ,
2016-05-03 17:23:53 +02:00
sealing_block_last_request : Mutex ::new ( 0 ) ,
2016-09-15 12:12:15 +02:00
sealing_work : Mutex ::new ( SealingWork {
queue : UsingQueue ::new ( options . work_queue_size ) ,
enabled : options . force_sealing
2017-02-20 16:35:53 +01:00
| | spec . engine . seals_internally ( ) . is_some ( )
2016-09-15 12:12:15 +02:00
} ) ,
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-08-05 23:33:55 +02:00
engine : spec . engine . clone ( ) ,
2017-01-25 11:03:36 +01:00
notifiers : RwLock ::new ( notifiers ) ,
2016-07-08 17:26:06 +02:00
gas_pricer : Mutex ::new ( gas_pricer ) ,
2017-01-22 16:15:22 +01:00
service_transaction_action : service_transaction_action ,
2016-09-15 12:12:15 +02:00
}
}
2016-09-14 17:29:35 +02:00
/// Creates new instance of miner with accounts and with given spec.
pub fn with_spec_and_accounts ( spec : & Spec , accounts : Option < Arc < AccountProvider > > ) -> Miner {
Miner ::new_raw ( Default ::default ( ) , GasPricer ::new_fixed ( 20_000_000_000 u64 . into ( ) ) , spec , accounts )
}
2016-09-15 12:12:15 +02:00
/// Creates new instance of miner without accounts, but with given spec.
pub fn with_spec ( spec : & Spec ) -> Miner {
Miner ::new_raw ( Default ::default ( ) , GasPricer ::new_fixed ( 20_000_000_000 u64 . into ( ) ) , spec , None )
}
2016-06-29 20:04:52 +02:00
fn forced_sealing ( & self ) -> bool {
2017-03-20 19:14:49 +01:00
self . options . force_sealing | | ! self . notifiers . read ( ) . is_empty ( )
2016-06-29 20:04:52 +02:00
}
2016-09-06 15:31:13 +02:00
/// Clear all pending block states
pub fn clear ( & self ) {
self . sealing_work . lock ( ) . queue . reset ( ) ;
}
2016-07-14 15:24:12 +02:00
/// Get `Some` `clone()` of the current pending block's state or `None` if we're not sealing.
2017-08-04 15:58:14 +02:00
pub fn pending_state ( & self , latest_block_number : BlockNumber ) -> Option < State < ::state_db ::StateDB > > {
self . map_pending_block ( | b | b . state ( ) . clone ( ) , latest_block_number )
2016-07-14 15:24:12 +02:00
}
2017-01-13 09:51:36 +01:00
/// Get `Some` `clone()` of the current pending block or `None` if we're not sealing.
2017-08-04 15:58:14 +02:00
pub fn pending_block ( & self , latest_block_number : BlockNumber ) -> Option < Block > {
self . map_pending_block ( | b | b . to_base ( ) , latest_block_number )
}
/// Get `Some` `clone()` of the current pending block header or `None` if we're not sealing.
pub fn pending_block_header ( & self , latest_block_number : BlockNumber ) -> Option < Header > {
self . map_pending_block ( | b | b . header ( ) . clone ( ) , latest_block_number )
}
2018-02-16 16:51:34 +01:00
/// Set a callback to be notified about imported transactions' hashes.
pub fn add_transactions_listener ( & self , f : Box < Fn ( & [ H256 ] ) + Send + Sync > ) {
self . transaction_listener . write ( ) . push ( f ) ;
}
2017-08-04 15:58:14 +02:00
fn map_pending_block < F , T > ( & self , f : F , latest_block_number : BlockNumber ) -> Option < T > where
F : FnOnce ( & ClosedBlock ) -> T ,
{
self . from_pending_block (
latest_block_number ,
| | None ,
| block | Some ( f ( block ) ) ,
)
2016-07-14 15:24:12 +02:00
}
2016-03-17 12:47:31 +01:00
/// Prepares new block for sealing including top transactions from queue.
2018-03-03 18:42:13 +01:00
fn prepare_block < C : AccountData + BlockChain + BlockProducer + CallContract > ( & self , chain : & C ) -> ( ClosedBlock , Option < H256 > ) {
2018-02-23 19:49:08 +01:00
trace_time! ( " prepare_block " ) ;
2016-12-15 18:19:19 +01:00
let chain_info = chain . chain_info ( ) ;
2016-06-30 22:35:59 +02:00
let ( transactions , mut open_block , original_work_hash ) = {
2017-06-28 09:10:57 +02:00
let nonce_cap = if chain_info . best_block_number + 1 > = self . engine . params ( ) . dust_protection_transition {
Some ( ( self . engine . params ( ) . nonce_cap_increment * ( chain_info . best_block_number + 1 ) ) . into ( ) )
} else { None } ;
let transactions = { self . transaction_queue . read ( ) . top_transactions_at ( chain_info . best_block_number , chain_info . best_block_timestamp , nonce_cap ) } ;
2016-07-13 19:59:59 +02:00
let mut sealing_work = self . sealing_work . lock ( ) ;
2018-02-27 18:22:56 +01:00
let last_work_hash = sealing_work . queue . peek_last_ref ( ) . map ( | pb | pb . block ( ) . header ( ) . hash ( ) ) ;
2016-12-15 18:19:19 +01:00
let best_hash = chain_info . best_block_hash ;
2017-11-03 15:20:20 +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.
2018-02-27 18:22:56 +01:00
let mut open_block = match sealing_work . queue . pop_if ( | b | b . block ( ) . header ( ) . parent_hash ( ) = = & best_hash ) {
2016-06-21 11:26:43 +02:00
Some ( old_block ) = > {
2016-09-13 15:09:07 +02:00
trace! ( target : " miner " , " prepare_block: Already have previous work; updating and returning " ) ;
2016-06-21 11:26:43 +02:00
// add transactions to old_block
2017-07-10 13:36:42 +02:00
chain . reopen_block ( old_block )
2016-06-21 11:26:43 +02:00
}
None = > {
// block not found - create it.
2016-09-13 15:09:07 +02:00
trace! ( target : " miner " , " prepare_block: No existing work - making new block " ) ;
2016-06-21 11:26:43 +02:00
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 ( )
)
}
} ;
2017-11-03 15:20:20 +01:00
if self . options . infinite_pending_block {
2018-03-04 19:31:26 +01:00
open_block . remove_gas_limit ( ) ;
2017-11-03 15:20:20 +01:00
}
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 ( ) ;
2017-12-21 21:42:36 +01:00
let mut non_allowed_transactions = HashSet ::new ( ) ;
2016-09-23 17:26:36 +02:00
let mut transactions_to_penalize = HashSet ::new ( ) ;
2018-02-27 18:22:56 +01:00
let block_number = open_block . block ( ) . header ( ) . number ( ) ;
2016-10-27 19:28:34 +02:00
2016-12-07 23:13:53 +01:00
let mut tx_count : usize = 0 ;
let tx_total = transactions . len ( ) ;
2016-06-06 14:33:12 +02:00
for tx in transactions {
let hash = tx . hash ( ) ;
2016-10-27 19:28:34 +02:00
let start = Instant ::now ( ) ;
2017-12-21 21:42:36 +01:00
// Check whether transaction type is allowed for sender
2018-03-03 18:42:13 +01:00
let result = match self . engine . machine ( ) . verify_transaction ( & tx , open_block . header ( ) , chain ) {
2017-12-21 21:42:36 +01:00
Err ( Error ::Transaction ( TransactionError ::NotAllowed ) ) = > {
2017-12-22 21:48:37 +01:00
Err ( TransactionError ::NotAllowed . into ( ) )
2017-12-21 21:42:36 +01:00
}
_ = > {
open_block . push_transaction ( tx , None )
}
} ;
2016-10-27 19:28:34 +02:00
let took = start . elapsed ( ) ;
// Check for heavy transactions
match self . options . tx_queue_banning {
Banning ::Enabled { ref offend_threshold , .. } if & took > offend_threshold = > {
2017-03-20 19:15:02 +01:00
match self . transaction_queue . write ( ) . ban_transaction ( & hash ) {
2016-10-27 19:28:34 +02:00
true = > {
warn! ( target : " miner " , " Detected heavy transaction. Banning the sender and recipient/code. " ) ;
} ,
false = > {
transactions_to_penalize . insert ( hash ) ;
debug! ( target : " miner " , " Detected heavy transaction. Penalizing sender. " )
}
}
} ,
_ = > { } ,
}
2016-12-07 23:13:53 +01:00
trace! ( target : " miner " , " Adding tx {:?} took {:?} " , hash , took ) ;
2016-10-27 19:28:34 +02:00
match result {
2016-07-18 13:50:45 +02:00
Err ( Error ::Execution ( ExecutionError ::BlockGasLimitReached { gas_limit , gas_used , gas } ) ) = > {
debug! ( target : " miner " , " Skipping adding transaction to block because of gas limit: {:?} (limit: {:?}, used: {:?}, gas: {:?}) " , hash , gas_limit , gas_used , gas ) ;
2016-09-23 17:26:36 +02:00
// Penalize transaction if it's above current gas limit
if gas > gas_limit {
transactions_to_penalize . insert ( hash ) ;
}
2016-09-23 16:24:11 +02:00
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.
2016-07-18 13:50:45 +02:00
Err ( Error ::Execution ( ExecutionError ::InvalidNonce { expected , got } ) ) = > {
debug! ( target : " miner " , " Skipping adding transaction to block because of invalid nonce: {:?} (expected: {:?}, got: {:?}) " , hash , expected , got ) ;
2016-07-05 17:51:41 +02:00
} ,
// already have transaction - ignore
Err ( Error ::Transaction ( TransactionError ::AlreadyImported ) ) = > { } ,
2017-12-21 21:42:36 +01:00
Err ( Error ::Transaction ( TransactionError ::NotAllowed ) ) = > {
non_allowed_transactions . insert ( hash ) ;
debug! ( target : " miner " ,
" Skipping non-allowed transaction for sender {:?} " ,
hash ) ;
} ,
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 ) ;
} ,
2016-12-07 23:13:53 +01:00
_ = > {
tx_count + = 1 ;
} // imported ok
2016-06-06 14:33:12 +02:00
}
}
2016-12-07 23:13:53 +01:00
trace! ( target : " miner " , " Pushed {}/{} transactions " , tx_count , tx_total ) ;
2016-06-06 14:33:12 +02:00
let block = open_block . close ( ) ;
2017-01-05 21:16:52 +01:00
let fetch_nonce = | a : & Address | chain . latest_nonce ( a ) ;
2016-06-06 14:33:12 +02:00
2016-06-21 11:26:43 +02:00
{
2017-03-20 19:15:02 +01:00
let mut queue = self . transaction_queue . write ( ) ;
2016-10-27 08:28:12 +02:00
for hash in invalid_transactions {
2017-03-29 14:43:55 +02:00
queue . remove ( & hash , & fetch_nonce , RemovalReason ::Invalid ) ;
2016-06-21 11:26:43 +02:00
}
2017-12-21 21:42:36 +01:00
for hash in non_allowed_transactions {
queue . remove ( & hash , & fetch_nonce , RemovalReason ::NotAllowed ) ;
}
2016-09-23 17:26:36 +02:00
for hash in transactions_to_penalize {
2016-09-23 16:24:11 +02:00
queue . penalize ( & hash ) ;
}
2016-04-15 07:38:23 +02:00
}
2016-09-13 15:09:07 +02:00
( block , original_work_hash )
}
2017-01-18 19:44:24 +01:00
/// Asynchronously updates minimal gas price for transaction queue
pub fn recalibrate_minimal_gas_price ( & self ) {
debug! ( target : " miner " , " minimal_gas_price: recalibrating... " ) ;
let txq = self . transaction_queue . clone ( ) ;
self . gas_pricer . lock ( ) . recalibrate ( move | price | {
debug! ( target : " miner " , " minimal_gas_price: Got gas price! {} " , price ) ;
2017-03-20 19:15:02 +01:00
txq . write ( ) . set_minimal_gas_price ( price ) ;
2017-01-18 19:44:24 +01:00
} ) ;
}
2016-09-13 15:09:07 +02:00
/// Check is reseal is allowed and necessary.
fn requires_reseal ( & self , best_block : BlockNumber ) -> bool {
2017-03-20 19:15:02 +01:00
let has_local_transactions = self . transaction_queue . read ( ) . has_local_pending_transactions ( ) ;
2016-09-13 15:09:07 +02:00
let mut sealing_work = self . sealing_work . lock ( ) ;
if sealing_work . enabled {
trace! ( target : " miner " , " requires_reseal: sealing enabled " ) ;
let last_request = * self . sealing_block_last_request . lock ( ) ;
let should_disable_sealing = ! self . forced_sealing ( )
& & ! has_local_transactions
2017-02-20 16:35:53 +01:00
& & self . engine . seals_internally ( ) . is_none ( )
2016-09-13 15:09:07 +02:00
& & best_block > last_request
& & best_block - last_request > SEALING_TIMEOUT_IN_BLOCKS ;
trace! ( target : " miner " , " requires_reseal: should_disable_sealing={}; best_block={}, last_request={} " , should_disable_sealing , best_block , last_request ) ;
if should_disable_sealing {
trace! ( target : " miner " , " Miner sleeping (current {}, last {}) " , best_block , last_request ) ;
sealing_work . enabled = false ;
sealing_work . queue . reset ( ) ;
false
} else {
// sealing enabled and we don't want to sleep.
* self . next_allowed_reseal . lock ( ) = Instant ::now ( ) + self . options . reseal_min_period ;
true
}
} else {
2016-09-15 12:12:15 +02:00
trace! ( target : " miner " , " requires_reseal: sealing is disabled " ) ;
2016-09-13 15:09:07 +02:00
false
}
}
2016-12-08 12:03:34 +01:00
/// Attempts to perform internal sealing (one that does not require work) and handles the result depending on the type of Seal.
2018-03-03 18:42:13 +01:00
fn seal_and_import_block_internally < C > ( & self , chain : & C , block : ClosedBlock ) -> bool
where C : BlockChain + SealedBlockImporter
{
2017-03-20 19:14:49 +01:00
if ! block . transactions ( ) . is_empty ( ) | | self . forced_sealing ( ) | | Instant ::now ( ) > * self . next_mandatory_reseal . read ( ) {
2016-12-08 12:03:34 +01:00
trace! ( target : " miner " , " seal_block_internally: attempting internal seal. " ) ;
2017-12-07 12:17:11 +01:00
let parent_header = match chain . block_header ( BlockId ::Hash ( * block . header ( ) . parent_hash ( ) ) ) {
Some ( hdr ) = > hdr . decode ( ) ,
None = > return false ,
} ;
match self . engine . generate_seal ( block . block ( ) , & parent_header ) {
2016-12-08 12:03:34 +01:00
// Save proposal for later seal submission and broadcast it.
Seal ::Proposal ( seal ) = > {
trace! ( target : " miner " , " Received a Proposal seal. " ) ;
2017-03-15 14:04:42 +01:00
* self . next_mandatory_reseal . write ( ) = Instant ::now ( ) + self . options . reseal_max_period ;
2016-12-08 20:09:30 +01:00
{
let mut sealing_work = self . sealing_work . lock ( ) ;
sealing_work . queue . push ( block . clone ( ) ) ;
sealing_work . queue . use_last_ref ( ) ;
}
2016-12-08 12:03:34 +01:00
block
. lock ( )
. seal ( & * self . engine , seal )
. map ( | sealed | { chain . broadcast_proposal_block ( sealed ) ; true } )
. unwrap_or_else ( | e | {
warn! ( " ERROR: seal failed when given internally generated seal: {} " , e ) ;
false
} )
} ,
2016-12-08 21:49:55 +01:00
// Directly import a regular sealed block.
2017-03-15 14:04:42 +01:00
Seal ::Regular ( seal ) = > {
* self . next_mandatory_reseal . write ( ) = Instant ::now ( ) + self . options . reseal_max_period ;
2016-12-08 12:03:34 +01:00
block
. lock ( )
. seal ( & * self . engine , seal )
. map ( | sealed | chain . import_sealed_block ( sealed ) . is_ok ( ) )
. unwrap_or_else ( | e | {
warn! ( " ERROR: seal failed when given internally generated seal: {} " , e ) ;
false
2017-03-15 14:04:42 +01:00
} )
} ,
2016-12-08 12:03:34 +01:00
Seal ::None = > false ,
2016-03-26 20:36:03 +01:00
}
2016-12-08 12:03:34 +01:00
} else {
false
2016-03-22 13:05:18 +01:00
}
2016-09-13 15:09:07 +02:00
}
2016-06-21 11:26:43 +02:00
2016-09-13 15:09:07 +02:00
/// Prepares work which has to be done to seal.
fn prepare_work ( & self , block : ClosedBlock , original_work_hash : Option < H256 > ) {
2016-06-30 22:35:59 +02:00
let ( work , is_new ) = {
2016-07-13 19:59:59 +02:00
let mut sealing_work = self . sealing_work . lock ( ) ;
2018-02-27 18:22:56 +01:00
let last_work_hash = sealing_work . queue . peek_last_ref ( ) . map ( | pb | pb . block ( ) . header ( ) . hash ( ) ) ;
trace! ( target : " miner " , " prepare_work: Checking whether we need to reseal: orig={:?} last={:?}, this={:?} " , original_work_hash , last_work_hash , block . block ( ) . header ( ) . hash ( ) ) ;
let ( work , is_new ) = if last_work_hash . map_or ( true , | h | h ! = block . block ( ) . header ( ) . hash ( ) ) {
trace! ( target : " miner " , " prepare_work: Pushing a new, refreshed or borrowed pending {}... " , block . block ( ) . header ( ) . hash ( ) ) ;
let pow_hash = block . block ( ) . header ( ) . hash ( ) ;
let number = block . block ( ) . header ( ) . number ( ) ;
let difficulty = * block . block ( ) . header ( ) . difficulty ( ) ;
let is_new = original_work_hash . map_or ( true , | h | block . block ( ) . header ( ) . hash ( ) ! = h ) ;
2016-07-28 21:06:36 +02:00
sealing_work . queue . push ( block ) ;
2016-07-01 20:38:37 +02:00
// If push notifications are enabled we assume all work items are used.
2017-01-25 11:03:36 +01:00
if ! self . notifiers . read ( ) . is_empty ( ) & & is_new {
2016-07-28 21:06:36 +02:00
sealing_work . queue . use_last_ref ( ) ;
2016-07-01 20:38:37 +02:00
}
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
} ;
2018-02-27 18:22:56 +01:00
trace! ( target : " miner " , " prepare_work: leaving (last={:?}) " , sealing_work . queue . peek_last_ref ( ) . map ( | b | b . block ( ) . 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 {
2017-01-25 11:03:36 +01:00
work . map ( | ( pow_hash , difficulty , number ) | {
for notifier in self . notifiers . read ( ) . iter ( ) {
notifier . notify ( pow_hash , difficulty , number )
}
} ) ;
2016-06-30 22:35:59 +02:00
}
2016-03-18 19:36:32 +01:00
}
2018-03-03 18:42:13 +01:00
fn update_gas_limit < C : BlockChain > ( & self , client : & C ) {
2018-04-03 10:01:28 +02:00
let gas_limit = * client . best_block_header ( ) . gas_limit ( ) ;
2017-03-20 19:15:02 +01:00
let mut queue = self . transaction_queue . write ( ) ;
2016-03-17 15:20:33 +01:00
queue . set_gas_limit ( gas_limit ) ;
2016-10-10 23:04:43 +02:00
if let GasLimit ::Auto = self . options . tx_queue_gas_limit {
2016-10-14 13:56:00 +02:00
// Set total tx queue gas limit to be 20x the block gas limit.
2018-02-09 09:32:06 +01:00
queue . set_total_gas_limit ( gas_limit * 20 u32 ) ;
2016-10-10 23:04:43 +02:00
}
2016-03-17 12:47:31 +01:00
}
2016-04-28 17:36:53 +02:00
2016-09-13 15:09:07 +02:00
/// Returns true if we had to prepare new pending block.
2018-03-03 18:42:13 +01:00
fn prepare_work_sealing < C : AccountData + BlockChain + BlockProducer + CallContract > ( & self , client : & C ) -> bool {
2016-09-13 15:09:07 +02:00
trace! ( target : " miner " , " prepare_work_sealing: entering " ) ;
2016-07-28 21:06:36 +02:00
let prepare_new = {
let mut sealing_work = self . sealing_work . lock ( ) ;
let have_work = sealing_work . queue . peek_last_ref ( ) . is_some ( ) ;
2016-09-13 15:09:07 +02:00
trace! ( target : " miner " , " prepare_work_sealing: have_work={} " , have_work ) ;
2016-07-28 21:06:36 +02:00
if ! have_work {
sealing_work . enabled = true ;
true
} else {
false
}
} ;
if prepare_new {
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. |
// --------------------------------------------------------------------------
2017-01-22 16:15:22 +01:00
let ( block , original_work_hash ) = self . prepare_block ( client ) ;
2016-09-13 15:09:07 +02:00
self . prepare_work ( block , original_work_hash ) ;
2016-04-28 17:36:53 +02:00
}
2016-07-13 19:59:59 +02:00
let mut sealing_block_last_request = self . sealing_block_last_request . lock ( ) ;
2017-01-22 16:15:22 +01:00
let best_number = client . chain_info ( ) . best_block_number ;
2016-04-28 17:36:53 +02:00
if * sealing_block_last_request ! = best_number {
2016-09-13 15:09:07 +02:00
trace! ( target : " miner " , " prepare_work_sealing: Miner received request (was {}, now {}) - waking up. " , * sealing_block_last_request , best_number ) ;
2016-04-28 17:36:53 +02:00
* sealing_block_last_request = best_number ;
}
2016-08-04 18:17:21 +02:00
// Return if we restarted
2016-07-28 21:06:36 +02:00
prepare_new
2016-04-28 17:36:53 +02:00
}
2016-06-29 16:26:19 +02:00
2018-03-03 18:42:13 +01:00
fn add_transactions_to_queue < C : AccountData + BlockChain + CallContract + RegistryInfo + ScheduleInfo > (
2016-12-15 18:19:19 +01:00
& self ,
2018-03-03 18:42:13 +01:00
client : & C ,
2017-01-13 09:51:36 +01:00
transactions : Vec < UnverifiedTransaction > ,
2016-12-15 18:19:19 +01:00
default_origin : TransactionOrigin ,
2017-02-03 19:32:10 +01:00
condition : Option < TransactionCondition > ,
2017-01-13 09:51:36 +01:00
transaction_queue : & mut BanningTransactionQueue ,
) -> Vec < Result < TransactionImportResult , Error > > {
2018-04-03 10:01:28 +02:00
let best_block_header = client . best_block_header ( ) ;
2017-01-22 16:15:22 +01:00
let insertion_time = client . chain_info ( ) . best_block_number ;
2018-02-16 16:51:34 +01:00
let mut inserted = Vec ::with_capacity ( transactions . len ( ) ) ;
2017-01-05 21:16:52 +01:00
2018-02-16 16:51:34 +01:00
let results = transactions . into_iter ( )
2016-11-23 08:46:55 +01:00
. map ( | tx | {
2017-01-13 09:51:36 +01:00
let hash = tx . hash ( ) ;
2017-01-22 16:15:22 +01:00
if client . transaction_block ( TransactionId ::Hash ( hash ) ) . is_some ( ) {
2017-01-13 09:51:36 +01:00
debug! ( target : " miner " , " Rejected tx {:?}: already in the blockchain " , hash ) ;
2016-12-07 23:13:53 +01:00
return Err ( Error ::Transaction ( TransactionError ::AlreadyImported ) ) ;
}
2017-01-13 09:51:36 +01:00
match self . engine . verify_transaction_basic ( & tx , & best_block_header )
2017-09-26 14:19:08 +02:00
. and_then ( | _ | self . engine . verify_transaction_unordered ( tx , & best_block_header ) )
2017-01-13 09:51:36 +01:00
{
2016-11-18 17:45:19 +01:00
Err ( e ) = > {
2017-01-13 09:51:36 +01:00
debug! ( target : " miner " , " Rejected tx {:?} with invalid signature: {:?} " , hash , e ) ;
2016-11-23 08:46:55 +01:00
Err ( e )
} ,
2017-01-13 09:51:36 +01:00
Ok ( transaction ) = > {
2017-12-22 21:50:09 +01:00
// This check goes here because verify_transaction takes SignedTransaction parameter
2018-03-03 18:42:13 +01:00
self . engine . machine ( ) . verify_transaction ( & transaction , & best_block_header , client ) ? ;
2017-12-22 21:50:09 +01:00
2017-10-20 20:20:41 +02:00
let origin = self . accounts . as_ref ( ) . and_then ( | accounts | {
match accounts . has_account ( transaction . sender ( ) ) . unwrap_or ( false ) {
2016-11-23 08:46:55 +01:00
true = > Some ( TransactionOrigin ::Local ) ,
false = > None ,
2017-01-13 09:51:36 +01:00
}
2016-11-23 08:46:55 +01:00
} ) . unwrap_or ( default_origin ) ;
2017-01-22 16:15:22 +01:00
let details_provider = TransactionDetailsProvider ::new ( client , & self . service_transaction_action ) ;
2018-02-16 16:51:34 +01:00
let hash = transaction . hash ( ) ;
let result = match origin {
2016-11-23 08:46:55 +01:00
TransactionOrigin ::Local | TransactionOrigin ::RetractedBlock = > {
2018-02-16 16:51:34 +01:00
transaction_queue . add ( transaction , origin , insertion_time , condition . clone ( ) , & details_provider ) ?
2016-11-23 08:46:55 +01:00
} ,
TransactionOrigin ::External = > {
2018-02-16 16:51:34 +01:00
transaction_queue . add_with_banlist ( transaction , insertion_time , & details_provider ) ?
2017-01-22 16:15:22 +01:00
} ,
2018-02-16 16:51:34 +01:00
} ;
inserted . push ( hash ) ;
Ok ( result )
2016-11-17 11:01:21 +01:00
} ,
2016-10-27 19:28:34 +02:00
}
} )
2018-02-16 16:51:34 +01:00
. collect ( ) ;
for listener in & * self . transaction_listener . read ( ) {
listener ( & inserted ) ;
}
results
2016-07-06 17:15:59 +02:00
}
2016-06-29 16:26:19 +02:00
/// Are we allowed to do a non-mandatory reseal?
2016-07-13 19:59:59 +02:00
fn tx_reseal_allowed ( & self ) -> bool { Instant ::now ( ) > * self . next_allowed_reseal . lock ( ) }
2016-10-07 12:13:15 +02:00
fn from_pending_block < H , F , G > ( & self , latest_block_number : BlockNumber , from_chain : F , map_block : G ) -> H
2017-08-04 15:58:14 +02:00
where F : Fn ( ) -> H , G : FnOnce ( & ClosedBlock ) -> H {
2016-10-07 12:13:15 +02:00
let sealing_work = self . sealing_work . lock ( ) ;
sealing_work . queue . peek_last_ref ( ) . map_or_else (
| | from_chain ( ) ,
| b | {
if b . block ( ) . header ( ) . number ( ) > latest_block_number {
map_block ( b )
} else {
from_chain ( )
}
}
)
}
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 {
2018-03-03 18:42:13 +01:00
type State = State < ::state_db ::StateDB > ;
2016-03-09 13:28:37 +01:00
2018-03-03 18:42:13 +01:00
fn clear_and_reset < C : MiningBlockChainClient > ( & self , chain : & C ) {
2017-03-20 19:15:02 +01:00
self . transaction_queue . write ( ) . 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 {
2017-03-20 19:15:02 +01:00
let status = self . transaction_queue . read ( ) . status ( ) ;
2016-07-13 19:59:59 +02:00
let sealing_work = self . sealing_work . lock ( ) ;
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-07-28 21:06:36 +02:00
transactions_in_pending_block : sealing_work . queue . peek_last_ref ( ) . map_or ( 0 , | b | b . transactions ( ) . len ( ) ) ,
2016-03-08 16:23:32 +01:00
}
}
2016-04-13 00:04:40 +02:00
fn set_author ( & self , author : Address ) {
2017-02-20 16:35:53 +01:00
if self . engine . seals_internally ( ) . is_some ( ) {
2016-09-15 12:12:15 +02:00
let mut sealing_work = self . sealing_work . lock ( ) ;
2017-02-20 16:35:53 +01:00
sealing_work . enabled = true ;
2016-09-15 12:12:15 +02:00
}
2016-07-13 19:59:59 +02:00
* self . author . write ( ) = author ;
2016-04-13 00:04:40 +02:00
}
2016-12-05 22:31:38 +01:00
fn set_engine_signer ( & self , address : Address , password : String ) -> Result < ( ) , AccountError > {
2017-02-20 16:35:53 +01:00
if self . engine . seals_internally ( ) . is_some ( ) {
2016-12-05 18:08:16 +01:00
if let Some ( ref ap ) = self . accounts {
2016-12-27 12:53:56 +01:00
ap . sign ( address . clone ( ) , Some ( password . clone ( ) ) , Default ::default ( ) ) ? ;
2017-01-18 18:49:50 +01:00
// Limit the scope of the locks.
{
let mut sealing_work = self . sealing_work . lock ( ) ;
2017-02-20 16:35:53 +01:00
sealing_work . enabled = true ;
2017-01-18 18:49:50 +01:00
* self . author . write ( ) = address ;
}
// --------------------------------------------------------------------------
// | NOTE Code below may require author and sealing_work locks |
// | (some `Engine`s call `EngineClient.update_sealing()`) |.
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self . engine . set_signer ( ap . clone ( ) , address , password ) ;
2017-07-12 08:52:18 +02:00
Ok ( ( ) )
} else {
warn! ( target : " miner " , " No account provider " ) ;
Err ( AccountError ::NotFound )
2016-12-05 18:08:16 +01:00
}
2017-07-12 08:52:18 +02:00
} else {
warn! ( target : " miner " , " Cannot set engine signer on a PoW chain. " ) ;
Err ( AccountError ::InappropriateChain )
2016-12-05 18:08:16 +01:00
}
}
2016-04-13 00:04:40 +02:00
fn set_extra_data ( & self , extra_data : Bytes ) {
2016-07-13 19:59:59 +02:00
* self . extra_data . 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-13 19:59:59 +02:00
self . gas_range_target . write ( ) . 0 = target ;
2016-06-23 14:29:16 +02:00
}
fn set_gas_ceil_target ( & self , target : U256 ) {
2016-07-13 19:59:59 +02:00
self . gas_range_target . write ( ) . 1 = target ;
2016-04-13 00:04:40 +02:00
}
fn set_minimal_gas_price ( & self , min_gas_price : U256 ) {
2017-03-20 19:15:02 +01:00
self . transaction_queue . write ( ) . set_minimal_gas_price ( min_gas_price ) ;
2016-04-13 00:04:40 +02:00
}
fn minimal_gas_price ( & self ) -> U256 {
2017-03-20 19:15:02 +01:00
* self . transaction_queue . read ( ) . 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.
2018-02-09 09:32:06 +01:00
* self . transaction_queue . read ( ) . minimal_gas_price ( ) * 110 u32 / 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-13 19:59:59 +02:00
self . gas_range_target . 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 {
2017-03-20 19:15:02 +01:00
self . transaction_queue . read ( ) . limit ( )
2016-04-18 23:03:41 +02:00
}
fn set_transactions_limit ( & self , limit : usize ) {
2017-03-20 19:15:02 +01:00
self . transaction_queue . write ( ) . 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 ) {
2017-03-20 19:15:02 +01:00
self . transaction_queue . write ( ) . 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-13 19:59:59 +02:00
* self . author . 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-13 19:59:59 +02:00
self . extra_data . 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-13 19:59:59 +02:00
self . gas_range_target . 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-13 19:59:59 +02:00
self . gas_range_target . read ( ) . 1
2016-04-11 21:06:32 +02:00
}
2018-03-03 18:42:13 +01:00
fn import_external_transactions < C : MiningBlockChainClient > (
2016-07-08 17:26:06 +02:00
& self ,
2018-03-03 18:42:13 +01:00
client : & C ,
2017-01-13 09:51:36 +01:00
transactions : Vec < UnverifiedTransaction >
2016-07-08 17:26:06 +02:00
) -> Vec < Result < TransactionImportResult , Error > > {
2016-09-19 10:38:47 +02:00
trace! ( target : " external_tx " , " Importing external transactions " ) ;
2016-07-08 17:26:06 +02:00
let results = {
2017-03-20 19:15:02 +01:00
let mut transaction_queue = self . transaction_queue . write ( ) ;
2016-07-08 17:19:14 +02:00
self . add_transactions_to_queue (
2018-03-03 18:42:13 +01:00
client , transactions , TransactionOrigin ::External , None , & mut transaction_queue
2016-07-08 17:19:14 +02:00
)
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. |
// --------------------------------------------------------------------------
2018-03-03 18:42:13 +01:00
self . update_sealing ( client ) ;
2016-06-21 16:00:34 +02:00
}
results
2016-03-08 15:46:44 +01:00
}
2018-03-03 18:42:13 +01:00
fn import_own_transaction < C : MiningBlockChainClient > (
2016-06-19 14:51:51 +02:00
& self ,
2018-03-03 18:42:13 +01:00
chain : & C ,
2016-12-15 18:19:19 +01:00
pending : PendingTransaction ,
2016-07-06 17:15:59 +02:00
) -> Result < TransactionImportResult , Error > {
2016-06-19 14:51:51 +02:00
2016-12-15 18:19:19 +01:00
trace! ( target : " own_tx " , " Importing transaction: {:?} " , pending ) ;
2016-04-17 20:36:37 +02:00
2016-04-28 17:36:53 +02:00
let imported = {
2016-09-13 15:09:07 +02:00
// Be sure to release the lock before we call prepare_work_sealing
2017-03-20 19:15:02 +01:00
let mut transaction_queue = self . transaction_queue . write ( ) ;
2017-01-13 09:51:36 +01:00
// We need to re-validate transactions
2016-07-14 12:16:53 +02:00
let import = self . add_transactions_to_queue (
2017-02-03 19:32:10 +01:00
chain , vec! [ pending . transaction . into ( ) ] , TransactionOrigin ::Local , pending . condition , & mut transaction_queue
2016-10-20 23:41:15 +02:00
) . pop ( ) . expect ( " one result returned per added transaction; one added => one result; qed " ) ;
2016-04-28 17:36:53 +02:00
match import {
2017-01-24 20:18:52 +01:00
Ok ( _ ) = > {
2016-04-28 17:36:53 +02:00
trace! ( target : " own_tx " , " Status: {:?} " , transaction_queue . status ( ) ) ;
} ,
Err ( ref e ) = > {
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.
2016-09-13 15:09:07 +02:00
// We need to create pending block and enable sealing.
2017-02-20 16:35:53 +01:00
if self . engine . seals_internally ( ) . unwrap_or ( false ) | | ! self . prepare_work_sealing ( chain ) {
2016-09-13 15:09:07 +02:00
// If new block has not been prepared (means we already had one)
// or Engine might be able to seal internally,
// we need to update sealing.
2016-04-28 17:36:53 +02:00
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-12-16 14:54:26 +01:00
fn pending_transactions ( & self ) -> Vec < PendingTransaction > {
2017-03-20 19:15:02 +01:00
let queue = self . transaction_queue . read ( ) ;
2017-02-03 19:32:10 +01:00
queue . pending_transactions ( BlockNumber ::max_value ( ) , u64 ::max_value ( ) )
2016-03-10 16:00:55 +01:00
}
2016-11-16 17:54:54 +01:00
fn local_transactions ( & self ) -> BTreeMap < H256 , LocalTransactionStatus > {
2017-03-20 19:15:02 +01:00
let queue = self . transaction_queue . read ( ) ;
2016-11-16 17:54:54 +01:00
queue . local_transactions ( )
. iter ( )
. map ( | ( hash , status ) | ( * hash , status . clone ( ) ) )
. collect ( )
}
2016-12-15 18:19:19 +01:00
fn future_transactions ( & self ) -> Vec < PendingTransaction > {
2017-03-20 19:15:02 +01:00
self . transaction_queue . read ( ) . future_transactions ( )
2016-12-15 18:19:19 +01:00
}
2017-02-03 19:32:10 +01:00
fn ready_transactions ( & self , best_block : BlockNumber , best_block_timestamp : u64 ) -> Vec < PendingTransaction > {
2017-03-20 19:15:02 +01:00
let queue = self . transaction_queue . read ( ) ;
2016-10-07 12:13:15 +02:00
match self . options . pending_set {
2017-02-03 19:32:10 +01:00
PendingSet ::AlwaysQueue = > queue . pending_transactions ( best_block , best_block_timestamp ) ,
2016-10-07 12:13:15 +02:00
PendingSet ::SealingOrElseQueue = > {
self . from_pending_block (
best_block ,
2017-02-03 19:32:10 +01:00
| | queue . pending_transactions ( best_block , best_block_timestamp ) ,
2016-12-15 18:19:19 +01:00
| sealing | sealing . transactions ( ) . iter ( ) . map ( | t | t . clone ( ) . into ( ) ) . collect ( )
2016-10-07 12:13:15 +02:00
)
} ,
PendingSet ::AlwaysSealing = > {
self . from_pending_block (
best_block ,
| | vec! [ ] ,
2016-12-15 18:19:19 +01:00
| sealing | sealing . transactions ( ) . iter ( ) . map ( | t | t . clone ( ) . into ( ) ) . collect ( )
2016-10-07 12:13:15 +02:00
)
} ,
2016-05-24 21:56:32 +02:00
}
2016-03-27 15:12:21 +02:00
}
2016-10-07 12:13:15 +02:00
fn pending_transactions_hashes ( & self , best_block : BlockNumber ) -> Vec < H256 > {
2017-03-20 19:15:02 +01:00
let queue = self . transaction_queue . read ( ) ;
2016-10-07 12:13:15 +02:00
match self . options . pending_set {
PendingSet ::AlwaysQueue = > queue . pending_hashes ( ) ,
PendingSet ::SealingOrElseQueue = > {
self . from_pending_block (
best_block ,
| | queue . pending_hashes ( ) ,
| sealing | sealing . transactions ( ) . iter ( ) . map ( | t | t . hash ( ) ) . collect ( )
)
} ,
PendingSet ::AlwaysSealing = > {
self . from_pending_block (
best_block ,
| | vec! [ ] ,
| sealing | sealing . transactions ( ) . iter ( ) . map ( | t | t . hash ( ) ) . collect ( )
)
} ,
2016-06-27 19:06:54 +02:00
}
2016-04-06 23:03:07 +02:00
}
2017-02-20 16:19:43 +01:00
fn transaction ( & self , best_block : BlockNumber , hash : & H256 ) -> Option < PendingTransaction > {
2017-03-20 19:15:02 +01:00
let queue = self . transaction_queue . read ( ) ;
2016-10-07 12:13:15 +02:00
match self . options . pending_set {
PendingSet ::AlwaysQueue = > queue . find ( hash ) ,
PendingSet ::SealingOrElseQueue = > {
self . from_pending_block (
best_block ,
| | queue . find ( hash ) ,
2017-02-20 16:19:43 +01:00
| sealing | sealing . transactions ( ) . iter ( ) . find ( | t | & t . hash ( ) = = hash ) . cloned ( ) . map ( Into ::into )
2016-10-07 12:13:15 +02:00
)
} ,
PendingSet ::AlwaysSealing = > {
self . from_pending_block (
best_block ,
| | None ,
2017-02-20 16:19:43 +01:00
| sealing | sealing . transactions ( ) . iter ( ) . find ( | t | & t . hash ( ) = = hash ) . cloned ( ) . map ( Into ::into )
2016-10-07 12:13:15 +02:00
)
} ,
2016-05-24 21:56:32 +02:00
}
}
2018-03-03 18:42:13 +01:00
fn remove_pending_transaction < C : AccountData > ( & self , chain : & C , hash : & H256 ) -> Option < PendingTransaction > {
2017-03-20 19:15:02 +01:00
let mut queue = self . transaction_queue . write ( ) ;
2017-03-19 08:46:51 +01:00
let tx = queue . find ( hash ) ;
if tx . is_some ( ) {
let fetch_nonce = | a : & Address | chain . latest_nonce ( a ) ;
2017-03-29 14:43:55 +02:00
queue . remove ( hash , & fetch_nonce , RemovalReason ::Canceled ) ;
2017-03-19 08:46:51 +01:00
}
tx
}
2016-10-07 12:13:15 +02:00
fn pending_receipt ( & self , best_block : BlockNumber , hash : & H256 ) -> Option < RichReceipt > {
self . from_pending_block (
best_block ,
| | None ,
| pending | {
2016-08-17 19:25:02 +02:00
let txs = pending . transactions ( ) ;
txs . iter ( )
. map ( | t | t . hash ( ) )
. position ( | t | t = = * hash )
. map ( | index | {
let prev_gas = if index = = 0 { Default ::default ( ) } else { pending . receipts ( ) [ index - 1 ] . gas_used } ;
2016-08-23 19:28:21 +02:00
let tx = & txs [ index ] ;
let receipt = & pending . receipts ( ) [ index ] ;
2016-08-17 19:25:02 +02:00
RichReceipt {
transaction_hash : hash . clone ( ) ,
transaction_index : index ,
cumulative_gas_used : receipt . gas_used ,
gas_used : receipt . gas_used - prev_gas ,
contract_address : match tx . action {
Action ::Call ( _ ) = > None ,
2016-10-20 23:41:15 +02:00
Action ::Create = > {
2017-01-13 09:51:36 +01:00
let sender = tx . sender ( ) ;
2017-06-30 11:30:32 +02:00
Some ( contract_address ( self . engine . create_address_scheme ( pending . header ( ) . number ( ) ) , & sender , & tx . nonce , & tx . data ) . 0 )
2016-10-20 23:41:15 +02:00
}
2016-08-17 19:25:02 +02:00
} ,
logs : receipt . logs . clone ( ) ,
2016-11-04 12:33:13 +01:00
log_bloom : receipt . log_bloom ,
2017-09-21 10:11:53 +02:00
outcome : receipt . outcome . clone ( ) ,
2016-08-17 19:25:02 +02:00
}
} )
2016-10-07 12:13:15 +02:00
}
)
2016-08-17 19:25:02 +02:00
}
2016-10-07 12:13:15 +02:00
fn pending_receipts ( & self , best_block : BlockNumber ) -> BTreeMap < H256 , Receipt > {
self . from_pending_block (
best_block ,
2016-10-27 08:28:12 +02:00
BTreeMap ::new ,
2016-10-07 12:13:15 +02:00
| pending | {
2016-05-24 21:56:32 +02:00
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 ( )
2016-10-07 12:13:15 +02:00
}
)
2016-05-24 21:56:32 +02:00
}
2016-04-06 12:15:20 +02:00
fn last_nonce ( & self , address : & Address ) -> Option < U256 > {
2017-03-20 19:15:02 +01:00
self . transaction_queue . read ( ) . last_nonce ( address )
2016-04-06 12:15:20 +02:00
}
2017-07-12 08:52:18 +02:00
fn can_produce_work_package ( & self ) -> bool {
self . engine . seals_internally ( ) . is_none ( )
}
2016-09-13 15:09:07 +02:00
/// Update sealing if required.
/// Prepare the block and work if the Engine does not seal internally.
2018-03-03 18:42:13 +01:00
fn update_sealing < C > ( & self , chain : & C )
where C : AccountData + BlockChain + RegistryInfo
+ CallContract + BlockProducer + SealedBlockImporter
{
2016-07-28 21:06:36 +02:00
trace! ( target : " miner " , " update_sealing " ) ;
2017-07-31 12:34:29 +02:00
const NO_NEW_CHAIN_WITH_FORKS : & str = " Your chain specification contains one or more hard forks which are required to be \
on by default . Please remove these forks and start your chain again . " ;
2016-08-04 18:17:21 +02:00
2016-09-13 15:09:07 +02:00
if self . requires_reseal ( chain . chain_info ( ) . best_block_number ) {
2016-07-28 21:06:36 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2016-09-13 15:09:07 +02:00
trace! ( target : " miner " , " update_sealing: preparing a block " ) ;
let ( block , original_work_hash ) = self . prepare_block ( chain ) ;
2017-07-31 12:34:29 +02:00
// refuse to seal the first block of the chain if it contains hard forks
// which should be on by default.
2018-02-27 18:22:56 +01:00
if block . block ( ) . header ( ) . number ( ) = = 1 & & self . engine . params ( ) . contains_bugfix_hard_fork ( ) {
2017-07-31 12:34:29 +02:00
warn! ( " {} " , NO_NEW_CHAIN_WITH_FORKS ) ;
return ;
}
2017-02-20 16:35:53 +01:00
match self . engine . seals_internally ( ) {
Some ( true ) = > {
trace! ( target : " miner " , " update_sealing: engine indicates internal sealing " ) ;
if self . seal_and_import_block_internally ( chain , block ) {
trace! ( target : " miner " , " update_sealing: imported internally sealed block " ) ;
}
} ,
2017-07-31 12:34:29 +02:00
Some ( false ) = > trace! ( target : " miner " , " update_sealing: engine is not keen to seal internally right now " ) ,
2017-02-20 16:35:53 +01:00
None = > {
trace! ( target : " miner " , " update_sealing: engine does not seal internally, preparing work " ) ;
self . prepare_work ( block , original_work_hash )
} ,
2016-09-13 15:09:07 +02:00
}
2016-03-17 12:47:31 +01:00
}
2016-03-08 15:46:44 +01:00
}
2017-07-12 08:52:18 +02:00
fn is_currently_sealing ( & self ) -> bool {
2016-08-02 18:53:32 +02:00
self . sealing_work . lock ( ) . queue . is_in_use ( )
}
2018-03-03 18:42:13 +01:00
fn map_sealing_work < C , F , T > ( & self , client : & C , f : F ) -> Option < T >
where C : AccountData + BlockChain + BlockProducer + CallContract ,
F : FnOnce ( & ClosedBlock ) -> T
{
2016-03-26 20:36:03 +01:00
trace! ( target : " miner " , " map_sealing_work: entering " ) ;
2018-03-03 18:42:13 +01:00
self . prepare_work_sealing ( client ) ;
2016-04-28 17:36:53 +02:00
trace! ( target : " miner " , " map_sealing_work: sealing prepared " ) ;
2016-07-13 19:59:59 +02:00
let mut sealing_work = self . sealing_work . lock ( ) ;
2016-07-28 21:06:36 +02:00
let ret = sealing_work . queue . use_last_ref ( ) ;
2018-02-27 18:22:56 +01:00
trace! ( target : " miner " , " map_sealing_work: leaving use_last_ref={:?} " , ret . as_ref ( ) . map ( | b | b . block ( ) . header ( ) . hash ( ) ) ) ;
2016-03-26 20:36:03 +01:00
ret . map ( f )
2016-03-08 15:46:44 +01:00
}
2018-03-03 18:42:13 +01:00
fn submit_seal < C : SealedBlockImporter > ( & self , chain : & C , block_hash : H256 , seal : Vec < Bytes > ) -> Result < ( ) , Error > {
2016-09-28 23:31:59 +02:00
let result =
if let Some ( b ) = self . sealing_work . lock ( ) . queue . get_used_if (
if self . options . enable_resubmission {
GetAction ::Clone
} else {
GetAction ::Take
} ,
2016-12-05 18:08:16 +01:00
| b | & b . hash ( ) = = & block_hash
2016-09-28 23:31:59 +02:00
) {
2016-12-05 18:08:16 +01:00
trace! ( target : " miner " , " Submitted block {}={}={} with seal {:?} " , block_hash , b . hash ( ) , b . header ( ) . bare_hash ( ) , seal ) ;
2016-09-28 23:31:59 +02:00
b . lock ( ) . try_seal ( & * self . engine , seal ) . or_else ( | ( e , _ ) | {
warn! ( target : " miner " , " Mined solution rejected: {} " , e ) ;
Err ( Error ::PowInvalid )
} )
} else {
2016-12-05 18:08:16 +01:00
warn! ( target : " miner " , " Submitted solution rejected: Block unknown or out of date. " ) ;
2016-09-28 23:31:59 +02: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-12-27 12:53:56 +01:00
chain . import_sealed_block ( sealed ) ? ;
2018-02-09 09:32:06 +01:00
info! ( target : " miner " , " Submitted block imported OK. #{}: {} " , Colour ::White . bold ( ) . paint ( format! ( " {} " , n ) ) , Colour ::White . bold ( ) . paint ( format! ( " {:x} " , h ) ) ) ;
2016-06-29 21:49:12 +02:00
Ok ( ( ) )
} )
2016-03-08 15:46:44 +01:00
}
2018-03-03 18:42:13 +01:00
fn chain_new_blocks < C > ( & self , chain : & C , imported : & [ H256 ] , _invalid : & [ H256 ] , enacted : & [ H256 ] , retracted : & [ H256 ] )
where C : AccountData + BlockChain + CallContract + RegistryInfo
+ BlockProducer + ScheduleInfo + SealedBlockImporter
{
2016-07-28 21:06:36 +02:00
trace! ( target : " miner " , " chain_new_blocks " ) ;
2017-07-10 13:36:42 +02:00
// 1. We ignore blocks that were `imported` unless resealing on new uncles is enabled.
2016-04-15 07:38:23 +02:00
// 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 ) ;
2017-01-18 19:44:24 +01:00
// Update minimal gas price
self . recalibrate_minimal_gas_price ( ) ;
2016-03-17 15:20:33 +01:00
// Then import all transactions...
2016-03-08 15:46:44 +01:00
{
2017-01-13 09:51:36 +01:00
2017-03-20 19:15:02 +01:00
let mut transaction_queue = self . transaction_queue . write ( ) ;
2017-01-13 09:51:36 +01:00
for hash in retracted {
let block = chain . block ( BlockId ::Hash ( * hash ) )
. expect ( " Client is sending message after commit to db and inserting to chain; the block is available; qed " ) ;
let txs = block . transactions ( ) ;
let _ = self . add_transactions_to_queue (
chain , txs , TransactionOrigin ::RetractedBlock , None , & mut transaction_queue
) ;
}
2016-03-08 15:46:44 +01:00
}
2016-03-17 15:20:33 +01:00
2016-12-09 15:54:13 +01:00
// ...and at the end remove the old ones
2016-03-15 23:01:36 +01:00
{
2017-01-05 21:16:52 +01:00
let fetch_account = | a : & Address | AccountDetails {
nonce : chain . latest_nonce ( a ) ,
balance : chain . latest_balance ( a ) ,
} ;
let time = chain . chain_info ( ) . best_block_number ;
2017-03-20 19:15:02 +01:00
let mut transaction_queue = self . transaction_queue . write ( ) ;
2017-01-05 21:16:52 +01:00
transaction_queue . remove_old ( & fetch_account , time ) ;
2016-03-08 15:46:44 +01:00
}
2017-07-10 13:36:42 +02:00
if enacted . len ( ) > 0 | | ( imported . len ( ) > 0 & & self . options . reseal_on_uncle ) {
2016-07-28 21:06:36 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires transaction_queue and sealing_work locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self . update_sealing ( chain ) ;
}
2016-03-08 15:46:44 +01:00
}
2018-03-03 18:42:13 +01:00
fn pending_state ( & self , latest_block_number : BlockNumber ) -> Option < Self ::State > {
Miner ::pending_state ( self , latest_block_number )
}
fn pending_block_header ( & self , latest_block_number : BlockNumber ) -> Option < Header > {
Miner ::pending_block_header ( self , latest_block_number )
}
fn pending_block ( & self , latest_block_number : BlockNumber ) -> Option < Block > {
Miner ::pending_block ( self , latest_block_number )
}
2016-03-08 15:46:44 +01:00
}
2016-03-18 13:59:11 +01:00
2017-01-22 16:15:22 +01:00
/// Action when service transaction is received
enum ServiceTransactionAction {
/// Refuse service transaction immediately
Refuse ,
/// Accept if sender is certified to send service transactions
Check ( ServiceTransactionChecker ) ,
}
impl ServiceTransactionAction {
2018-03-03 18:42:13 +01:00
pub fn check < C : CallContract + RegistryInfo > ( & self , client : & C , tx : & SignedTransaction ) -> Result < bool , String >
{
2017-01-22 16:15:22 +01:00
match * self {
ServiceTransactionAction ::Refuse = > Err ( " configured to refuse service transactions " . to_owned ( ) ) ,
2018-03-03 18:42:13 +01:00
ServiceTransactionAction ::Check ( ref checker ) = > checker . check ( client , tx ) ,
2017-01-22 16:15:22 +01:00
}
}
}
2018-03-03 18:42:13 +01:00
struct TransactionDetailsProvider < ' a , C : ' a > {
client : & ' a C ,
2017-01-22 16:15:22 +01:00
service_transaction_action : & ' a ServiceTransactionAction ,
}
2018-03-03 18:42:13 +01:00
impl < ' a , C > TransactionDetailsProvider < ' a , C > {
pub fn new ( client : & ' a C , service_transaction_action : & ' a ServiceTransactionAction ) -> Self {
2017-01-22 16:15:22 +01:00
TransactionDetailsProvider {
client : client ,
service_transaction_action : service_transaction_action ,
}
}
}
2018-03-03 18:42:13 +01:00
impl < ' a , C > TransactionQueueDetailsProvider for TransactionDetailsProvider < ' a , C >
where C : AccountData + CallContract + RegistryInfo + ScheduleInfo
{
2017-01-22 16:15:22 +01:00
fn fetch_account ( & self , address : & Address ) -> AccountDetails {
AccountDetails {
nonce : self . client . latest_nonce ( address ) ,
balance : self . client . latest_balance ( address ) ,
}
}
fn estimate_gas_required ( & self , tx : & SignedTransaction ) -> U256 {
tx . gas_required ( & self . client . latest_schedule ( ) ) . into ( )
}
fn is_service_transaction_acceptable ( & self , tx : & SignedTransaction ) -> Result < bool , String > {
self . service_transaction_action . check ( self . client , tx )
}
}
2016-03-18 13:59:11 +01:00
#[ cfg(test) ]
mod tests {
2016-07-14 12:16:53 +02:00
use super ::* ;
2018-01-11 17:49:10 +01:00
use ethcore_miner ::transaction_queue ::PrioritizationStrategy ;
2018-01-10 13:35:18 +01:00
use ethereum_types ::U256 ;
2016-08-24 18:35:21 +02:00
use ethkey ::{ Generator , Random } ;
2018-03-03 18:42:13 +01:00
use client ::{ TestBlockChainClient , EachBlockWith , ChainInfo } ;
2018-01-11 17:49:10 +01:00
use hash ::keccak ;
2018-03-03 18:42:13 +01:00
use header ::BlockNumber ;
2018-01-11 17:49:10 +01:00
use rustc_hex ::FromHex ;
2018-03-03 18:42:13 +01:00
use spec ::Spec ;
use transaction ::{ SignedTransaction , Transaction , PendingTransaction , Action } ;
2018-01-11 17:49:10 +01:00
use miner ::MinerService ;
2018-04-09 16:14:33 +02:00
use test_helpers ::{ generate_dummy_client , generate_dummy_client_with_spec_and_accounts } ;
2016-03-18 13:59:11 +01:00
#[ test ]
fn should_prepare_block_to_seal ( ) {
// given
let client = TestBlockChainClient ::default ( ) ;
2016-08-05 23:33:55 +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-08-05 23:33:55 +02:00
let miner = Miner ::with_spec ( & Spec ::new_test ( ) ) ;
2016-03-18 13:59:11 +01:00
2018-02-27 18:22:56 +01:00
let res = miner . map_sealing_work ( & client , | b | b . block ( ) . header ( ) . hash ( ) ) ;
2016-03-25 16:41:01 +01:00
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 ) ;
2018-02-27 18:22:56 +01:00
miner . map_sealing_work ( & client , | b | b . block ( ) . header ( ) . hash ( ) ) ;
2016-03-25 16:41:01 +01:00
client . add_blocks ( 1 , EachBlockWith ::Uncle ) ;
2018-02-27 18:22:56 +01:00
miner . map_sealing_work ( & client , | b | b . block ( ) . 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
}
2016-07-14 12:16:53 +02:00
fn miner ( ) -> Miner {
Arc ::try_unwrap ( Miner ::new (
MinerOptions {
force_sealing : false ,
reseal_on_external_tx : false ,
reseal_on_own_tx : true ,
2017-07-10 13:36:42 +02:00
reseal_on_uncle : false ,
2016-07-14 12:16:53 +02:00
reseal_min_period : Duration ::from_secs ( 5 ) ,
2017-03-15 14:04:42 +01:00
reseal_max_period : Duration ::from_secs ( 120 ) ,
2016-07-14 12:16:53 +02:00
tx_gas_limit : ! U256 ::zero ( ) ,
tx_queue_size : 1024 ,
2017-07-13 15:12:25 +02:00
tx_queue_memory_limit : None ,
2016-10-10 23:04:43 +02:00
tx_queue_gas_limit : GasLimit ::None ,
2016-10-15 14:46:33 +02:00
tx_queue_strategy : PrioritizationStrategy ::GasFactorAndGasPrice ,
2016-07-14 12:16:53 +02:00
pending_set : PendingSet ::AlwaysSealing ,
work_queue_size : 5 ,
enable_resubmission : true ,
2016-10-27 19:28:34 +02:00
tx_queue_banning : Banning ::Disabled ,
2017-01-22 16:15:22 +01:00
refuse_service_transactions : false ,
2017-11-03 15:20:20 +01:00
infinite_pending_block : false ,
2016-07-14 12:16:53 +02:00
} ,
GasPricer ::new_fixed ( 0 u64 . into ( ) ) ,
2016-08-05 23:33:55 +02:00
& Spec ::new_test ( ) ,
2016-07-14 12:16:53 +02:00
None , // accounts provider
) ) . ok ( ) . expect ( " Miner was just created. " )
}
2016-09-13 15:09:07 +02:00
fn transaction ( ) -> SignedTransaction {
2017-08-21 13:46:58 +02:00
transaction_with_chain_id ( 2 )
2017-04-19 14:30:00 +02:00
}
2017-08-21 13:46:58 +02:00
fn transaction_with_chain_id ( chain_id : u64 ) -> SignedTransaction {
2016-09-13 15:09:07 +02:00
let keypair = Random . generate ( ) . unwrap ( ) ;
Transaction {
action : Action ::Create ,
value : U256 ::zero ( ) ,
data : " 3331600055 " . from_hex ( ) . unwrap ( ) ,
gas : U256 ::from ( 100_000 ) ,
gas_price : U256 ::zero ( ) ,
nonce : U256 ::zero ( ) ,
2017-08-21 13:46:58 +02:00
} . sign ( keypair . secret ( ) , Some ( chain_id ) )
2016-09-13 15:09:07 +02:00
}
2016-07-14 12:16:53 +02:00
#[ test ]
fn should_make_pending_block_when_importing_own_transaction ( ) {
// given
let client = TestBlockChainClient ::default ( ) ;
let miner = miner ( ) ;
2016-09-13 15:09:07 +02:00
let transaction = transaction ( ) ;
2016-10-07 12:13:15 +02:00
let best_block = 0 ;
2016-07-14 12:16:53 +02:00
// when
2016-12-15 18:19:19 +01:00
let res = miner . import_own_transaction ( & client , PendingTransaction ::new ( transaction , None ) ) ;
2016-07-14 12:16:53 +02:00
// then
assert_eq! ( res . unwrap ( ) , TransactionImportResult ::Current ) ;
2016-12-16 14:54:26 +01:00
assert_eq! ( miner . pending_transactions ( ) . len ( ) , 1 ) ;
2017-02-03 19:32:10 +01:00
assert_eq! ( miner . ready_transactions ( best_block , 0 ) . len ( ) , 1 ) ;
2016-10-07 12:13:15 +02:00
assert_eq! ( miner . pending_transactions_hashes ( best_block ) . len ( ) , 1 ) ;
assert_eq! ( miner . pending_receipts ( best_block ) . len ( ) , 1 ) ;
2016-07-14 12:16:53 +02:00
// This method will let us know if pending block was created (before calling that method)
2016-09-15 12:12:15 +02:00
assert! ( ! miner . prepare_work_sealing ( & client ) ) ;
2016-07-14 12:16:53 +02:00
}
2016-10-07 12:13:15 +02:00
#[ test ]
fn should_not_use_pending_block_if_best_block_is_higher ( ) {
// given
let client = TestBlockChainClient ::default ( ) ;
let miner = miner ( ) ;
let transaction = transaction ( ) ;
let best_block = 10 ;
// when
2016-12-15 18:19:19 +01:00
let res = miner . import_own_transaction ( & client , PendingTransaction ::new ( transaction , None ) ) ;
2016-10-07 12:13:15 +02:00
// then
assert_eq! ( res . unwrap ( ) , TransactionImportResult ::Current ) ;
2016-12-16 14:54:26 +01:00
assert_eq! ( miner . pending_transactions ( ) . len ( ) , 1 ) ;
2017-02-03 19:32:10 +01:00
assert_eq! ( miner . ready_transactions ( best_block , 0 ) . len ( ) , 0 ) ;
2016-10-07 12:13:15 +02:00
assert_eq! ( miner . pending_transactions_hashes ( best_block ) . len ( ) , 0 ) ;
assert_eq! ( miner . pending_receipts ( best_block ) . len ( ) , 0 ) ;
}
2016-07-14 12:16:53 +02:00
#[ test ]
fn should_import_external_transaction ( ) {
// given
let client = TestBlockChainClient ::default ( ) ;
let miner = miner ( ) ;
2017-01-13 09:51:36 +01:00
let transaction = transaction ( ) . into ( ) ;
2016-10-07 12:13:15 +02:00
let best_block = 0 ;
2016-07-14 12:16:53 +02:00
// when
let res = miner . import_external_transactions ( & client , vec! [ transaction ] ) . pop ( ) . unwrap ( ) ;
// then
assert_eq! ( res . unwrap ( ) , TransactionImportResult ::Current ) ;
2016-12-16 14:54:26 +01:00
assert_eq! ( miner . pending_transactions ( ) . len ( ) , 1 ) ;
2016-10-07 12:13:15 +02:00
assert_eq! ( miner . pending_transactions_hashes ( best_block ) . len ( ) , 0 ) ;
2017-02-03 19:32:10 +01:00
assert_eq! ( miner . ready_transactions ( best_block , 0 ) . len ( ) , 0 ) ;
2016-10-07 12:13:15 +02:00
assert_eq! ( miner . pending_receipts ( best_block ) . len ( ) , 0 ) ;
2016-07-14 12:16:53 +02:00
// This method will let us know if pending block was created (before calling that method)
2016-09-15 12:12:15 +02:00
assert! ( miner . prepare_work_sealing ( & client ) ) ;
}
#[ test ]
fn should_not_seal_unless_enabled ( ) {
let miner = miner ( ) ;
let client = TestBlockChainClient ::default ( ) ;
// By default resealing is not required.
assert! ( ! miner . requires_reseal ( 1 u8 . into ( ) ) ) ;
2017-01-13 09:51:36 +01:00
miner . import_external_transactions ( & client , vec! [ transaction ( ) . into ( ) ] ) . pop ( ) . unwrap ( ) . unwrap ( ) ;
2016-09-15 12:12:15 +02:00
assert! ( miner . prepare_work_sealing ( & client ) ) ;
// Unless asked to prepare work.
assert! ( miner . requires_reseal ( 1 u8 . into ( ) ) ) ;
2016-09-13 15:09:07 +02:00
}
#[ test ]
fn internal_seals_without_work ( ) {
2017-04-19 14:30:00 +02:00
let spec = Spec ::new_instant ( ) ;
let miner = Miner ::with_spec ( & spec ) ;
2016-09-15 12:12:15 +02:00
2017-04-06 19:26:17 +02:00
let client = generate_dummy_client ( 2 ) ;
2016-09-13 15:09:07 +02:00
2017-08-21 13:46:58 +02:00
assert_eq! ( miner . import_external_transactions ( & * client , vec! [ transaction_with_chain_id ( spec . chain_id ( ) ) . into ( ) ] ) . pop ( ) . unwrap ( ) . unwrap ( ) , TransactionImportResult ::Current ) ;
2016-09-13 15:09:07 +02:00
2017-04-06 19:26:17 +02:00
miner . update_sealing ( & * client ) ;
2016-09-13 15:09:07 +02:00
client . flush_queue ( ) ;
2017-08-04 15:58:14 +02:00
assert! ( miner . pending_block ( 0 ) . is_none ( ) ) ;
2016-09-13 15:09:07 +02:00
assert_eq! ( client . chain_info ( ) . best_block_number , 3 as BlockNumber ) ;
2017-08-21 13:46:58 +02:00
assert_eq! ( miner . import_own_transaction ( & * client , PendingTransaction ::new ( transaction_with_chain_id ( spec . chain_id ( ) ) . into ( ) , None ) ) . unwrap ( ) , TransactionImportResult ::Current ) ;
2016-09-13 15:09:07 +02:00
2017-04-06 19:26:17 +02:00
miner . update_sealing ( & * client ) ;
2016-09-13 15:09:07 +02:00
client . flush_queue ( ) ;
2017-08-04 15:58:14 +02:00
assert! ( miner . pending_block ( 0 ) . is_none ( ) ) ;
2016-09-13 15:09:07 +02:00
assert_eq! ( client . chain_info ( ) . best_block_number , 4 as BlockNumber ) ;
2016-07-14 12:16:53 +02:00
}
2017-07-12 08:52:18 +02:00
#[ test ]
fn should_fail_setting_engine_signer_on_pow ( ) {
let spec = Spec ::new_pow_test_spec ;
let tap = Arc ::new ( AccountProvider ::transient_provider ( ) ) ;
2017-08-30 19:18:28 +02:00
let addr = tap . insert_account ( keccak ( " 1 " ) . into ( ) , " " ) . unwrap ( ) ;
2017-07-12 08:52:18 +02:00
let client = generate_dummy_client_with_spec_and_accounts ( spec , Some ( tap . clone ( ) ) ) ;
assert! ( match client . miner ( ) . set_engine_signer ( addr , " " . into ( ) ) { Err ( AccountError ::InappropriateChain ) = > true , _ = > false } )
}
#[ test ]
fn should_fail_setting_engine_signer_without_account_provider ( ) {
let spec = Spec ::new_instant ;
let tap = Arc ::new ( AccountProvider ::transient_provider ( ) ) ;
2017-08-30 19:18:28 +02:00
let addr = tap . insert_account ( keccak ( " 1 " ) . into ( ) , " " ) . unwrap ( ) ;
2017-07-12 08:52:18 +02:00
let client = generate_dummy_client_with_spec_and_accounts ( spec , None ) ;
assert! ( match client . miner ( ) . set_engine_signer ( addr , " " . into ( ) ) { Err ( AccountError ::NotFound ) = > true , _ = > false } ) ;
}
2016-03-18 13:59:11 +01:00
}