2018-06-04 10:19:50 +02:00
// Copyright 2015-2018 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 } ;
2018-04-13 17:34:27 +02:00
use std ::collections ::{ BTreeMap , HashSet , HashMap } ;
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 ansi_term ::Colour ;
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-19 11:52:54 +02:00
use error ::{ Error , ErrorKind , ExecutionError } ;
2018-04-13 17:34:27 +02:00
use ethcore_miner ::gas_pricer ::GasPricer ;
use ethcore_miner ::pool ::{ self , TransactionQueue , VerifiedTransaction , QueueStatus , PrioritizationStrategy } ;
2018-04-10 13:51:29 +02:00
use ethcore_miner ::work_notify ::NotifyWork ;
2018-04-13 17:34:27 +02:00
use ethereum_types ::{ H256 , U256 , Address } ;
use parking_lot ::{ Mutex , RwLock } ;
use rayon ::prelude ::* ;
2018-01-11 17:49:10 +01:00
use transaction ::{
2018-04-13 17:34:27 +02:00
self ,
2018-01-11 17:49:10 +01:00
Action ,
UnverifiedTransaction ,
SignedTransaction ,
2018-04-13 17:34:27 +02:00
PendingTransaction ,
2018-01-11 17:49:10 +01:00
} ;
2017-07-29 17:12:07 +02:00
use using_queue ::{ UsingQueue , GetAction } ;
2018-04-13 17:34:27 +02:00
use account_provider ::{ AccountProvider , SignError as AccountError } ;
use block ::{ ClosedBlock , IsBlock , Block , SealedBlock } ;
2018-03-03 18:42:13 +01:00
use client ::{
2018-04-13 17:34:27 +02:00
BlockChain , ChainInfo , CallContract , BlockProducer , SealedBlockImporter , Nonce
2018-03-03 18:42:13 +01:00
} ;
2018-04-13 17:34:27 +02:00
use client ::BlockId ;
2016-08-17 19:25:02 +02:00
use executive ::contract_address ;
2018-01-11 17:49:10 +01:00
use header ::{ Header , BlockNumber } ;
2018-04-13 17:34:27 +02:00
use miner ;
use miner ::pool_client ::{ PoolClient , CachedNonceClient } ;
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
2018-04-13 17:34:27 +02:00
/// may be empty if the node is not actively mining or has no force_sealing enabled.
2016-06-27 19:06:54 +02:00
AlwaysSealing ,
2018-04-13 17:34:27 +02:00
/// Takes from sealing if mining, from queue otherwise.
2016-06-27 19:06:54 +02:00
SealingOrElseQueue ,
}
2018-04-13 17:34:27 +02:00
/// Transaction queue penalization settings.
///
/// Senders of long-running transactions (above defined threshold)
/// will get lower priority.
2016-10-27 19:28:34 +02:00
#[ derive(Debug, PartialEq, Clone) ]
2018-04-13 17:34:27 +02:00
pub enum Penalization {
/// Penalization in transaction queue is disabled
2016-10-27 19:28:34 +02:00
Disabled ,
2018-04-13 17:34:27 +02:00
/// Penalization in transaction queue is enabled
2016-10-27 19:28:34 +02:00
Enabled {
2018-04-13 17:34:27 +02:00
/// Upper limit of transaction processing time before penalizing.
2016-10-27 19:28:34 +02:00
offend_threshold : Duration ,
} ,
}
2018-04-13 17:34:27 +02:00
/// Initial minimal gas price.
///
/// Gas price should be later overwritten externally
/// for instance by a dynamic gas price mechanism or CLI parameter.
/// This constant controls the initial value.
const DEFAULT_MINIMAL_GAS_PRICE : u64 = 20_000_000_000 ;
/// Allowed number of skipped transactions when constructing pending block.
///
/// When we push transactions to pending block, some of the transactions might
/// get skipped because of block gas limit being reached.
/// This constant controls how many transactions we can skip because of that
/// before stopping attempts to push more transactions to the block.
/// This is an optimization that prevents traversing the entire pool
/// in case we have only a fraction of available block gas limit left.
const MAX_SKIPPED_TRANSACTIONS : usize = 8 ;
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-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 ,
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 ,
2018-04-13 17:34:27 +02:00
/// Strategy to use for prioritizing transactions in the queue.
pub tx_queue_strategy : PrioritizationStrategy ,
/// Simple senders penalization.
pub tx_queue_penalization : Penalization ,
2018-06-18 15:32:18 +02:00
/// Do we want to mark transactions recieved locally (e.g. RPC) as local if we don't have the sending account?
pub tx_queue_no_unfamiliar_locals : bool ,
2018-04-13 17:34:27 +02:00
/// Do we refuse to accept service transactions even if sender is certified.
pub refuse_service_transactions : bool ,
/// Transaction pool limits.
pub pool_limits : pool ::Options ,
/// Initial transaction verification options.
pub pool_verification_options : pool ::verifier ::Options ,
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-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 ) ,
2018-04-13 17:34:27 +02:00
pending_set : PendingSet ::AlwaysQueue ,
2016-06-29 16:26:19 +02:00
work_queue_size : 20 ,
2016-06-30 12:56:58 +02:00
enable_resubmission : true ,
2017-11-03 15:20:20 +01:00
infinite_pending_block : false ,
2018-04-13 17:34:27 +02:00
tx_queue_strategy : PrioritizationStrategy ::GasPriceOnly ,
tx_queue_penalization : Penalization ::Disabled ,
2018-06-18 15:32:18 +02:00
tx_queue_no_unfamiliar_locals : false ,
2018-04-13 17:34:27 +02:00
refuse_service_transactions : false ,
pool_limits : pool ::Options {
max_count : 8_192 ,
max_per_sender : 81 ,
max_mem_usage : 4 * 1024 * 1024 ,
} ,
pool_verification_options : pool ::verifier ::Options {
minimal_gas_price : DEFAULT_MINIMAL_GAS_PRICE . into ( ) ,
block_gas_limit : U256 ::max_value ( ) ,
tx_gas_limit : U256 ::max_value ( ) ,
} ,
2016-06-27 17:23:54 +02:00
}
}
}
2018-04-13 17:34:27 +02:00
/// Configurable parameters of block authoring.
#[ derive(Debug, Default, Clone) ]
pub struct AuthoringParams {
/// Lower and upper bound of block gas limit that we are targeting
pub gas_range_target : ( U256 , U256 ) ,
/// Block author
pub author : Address ,
/// Block extra data
pub extra_data : Bytes ,
2016-07-08 17:26:06 +02:00
}
2016-07-28 21:06:36 +02:00
struct SealingWork {
queue : UsingQueue < ClosedBlock > ,
enabled : bool ,
2018-04-13 17:34:27 +02:00
next_allowed_reseal : Instant ,
next_mandatory_reseal : Instant ,
// block number when sealing work was last requested
2018-06-12 08:21:55 +02:00
last_request : Option < u64 > ,
2018-04-13 17:34:27 +02:00
}
impl SealingWork {
/// Are we allowed to do a non-mandatory reseal?
fn reseal_allowed ( & self ) -> bool {
Instant ::now ( ) > self . next_allowed_reseal
}
2016-07-28 21:06:36 +02:00
}
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!
2018-04-13 17:34:27 +02:00
sealing : Mutex < SealingWork > ,
params : RwLock < AuthoringParams > ,
listeners : RwLock < Vec < Box < NotifyWork > > > ,
nonce_cache : RwLock < HashMap < Address , U256 > > ,
gas_pricer : Mutex < GasPricer > ,
2016-06-27 17:23:54 +02:00
options : MinerOptions ,
2018-04-13 17:34:27 +02:00
// TODO [ToDr] Arc is only required because of price updater
transaction_queue : Arc < TransactionQueue > ,
2017-09-26 14:19:08 +02:00
engine : Arc < EthEngine > ,
2016-05-30 13:10:33 +02:00
accounts : Option < Arc < AccountProvider > > ,
2016-03-08 15:46:44 +01:00
}
2016-06-20 10:28:38 +02:00
impl Miner {
2018-04-13 17:34:27 +02:00
/// Push listener that will handle new jobs
pub fn add_work_listener ( & self , notifier : Box < NotifyWork > ) {
self . listeners . write ( ) . push ( notifier ) ;
self . sealing . lock ( ) . enabled = true ;
2017-01-25 11:03:36 +01:00
}
2018-04-13 17:34:27 +02: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_queue . add_listener ( f ) ;
2017-01-25 11:03:36 +01:00
}
2018-04-13 17:34:27 +02:00
/// Creates new instance of miner Arc.
pub fn new ( options : MinerOptions , gas_pricer : GasPricer , spec : & Spec , accounts : Option < Arc < AccountProvider > > ) -> Self {
let limits = options . pool_limits . clone ( ) ;
let verifier_options = options . pool_verification_options . clone ( ) ;
let tx_queue_strategy = options . tx_queue_strategy ;
2017-01-25 11:03:36 +01:00
2016-09-15 12:12:15 +02:00
Miner {
2018-04-13 17:34:27 +02:00
sealing : Mutex ::new ( SealingWork {
2016-09-15 12:12:15 +02:00
queue : UsingQueue ::new ( options . work_queue_size ) ,
enabled : options . force_sealing
2018-04-13 17:34:27 +02:00
| | spec . engine . seals_internally ( ) . is_some ( ) ,
next_allowed_reseal : Instant ::now ( ) ,
next_mandatory_reseal : Instant ::now ( ) + options . reseal_max_period ,
2018-06-12 08:21:55 +02:00
last_request : None ,
2016-09-15 12:12:15 +02:00
} ) ,
2018-04-13 17:34:27 +02:00
params : RwLock ::new ( AuthoringParams ::default ( ) ) ,
listeners : RwLock ::new ( vec! [ ] ) ,
2016-07-08 17:26:06 +02:00
gas_pricer : Mutex ::new ( gas_pricer ) ,
2018-04-13 17:34:27 +02:00
nonce_cache : RwLock ::new ( HashMap ::with_capacity ( 1024 ) ) ,
options ,
transaction_queue : Arc ::new ( TransactionQueue ::new ( limits , verifier_options , tx_queue_strategy ) ) ,
accounts ,
engine : spec . engine . clone ( ) ,
2016-09-15 12:12:15 +02:00
}
}
2018-04-13 17:34:27 +02:00
/// Creates new instance of miner with given spec and accounts.
///
/// NOTE This should be only used for tests.
pub fn new_for_tests ( spec : & Spec , accounts : Option < Arc < AccountProvider > > ) -> Miner {
let minimal_gas_price = 0. into ( ) ;
Miner ::new ( MinerOptions {
pool_verification_options : pool ::verifier ::Options {
minimal_gas_price ,
block_gas_limit : U256 ::max_value ( ) ,
tx_gas_limit : U256 ::max_value ( ) ,
} ,
reseal_min_period : Duration ::from_secs ( 0 ) ,
.. Default ::default ( )
} , GasPricer ::new_fixed ( minimal_gas_price ) , spec , accounts )
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 ) {
2018-04-13 17:34:27 +02:00
self . sealing . lock ( ) . queue . reset ( ) ;
2016-09-06 15:31:13 +02:00
}
2018-04-13 17:34:27 +02:00
/// Updates transaction queue verification limits.
///
/// Limits consist of current block gas limit and minimal gas price.
pub fn update_transaction_queue_limits ( & self , block_gas_limit : U256 ) {
trace! ( target : " miner " , " minimal_gas_price: recalibrating... " ) ;
let txq = self . transaction_queue . clone ( ) ;
let mut options = self . options . pool_verification_options . clone ( ) ;
self . gas_pricer . lock ( ) . recalibrate ( move | gas_price | {
debug! ( target : " miner " , " minimal_gas_price: Got gas price! {} " , gas_price ) ;
options . minimal_gas_price = gas_price ;
options . block_gas_limit = block_gas_limit ;
txq . set_verifier_options ( options ) ;
} ) ;
2017-08-04 15:58:14 +02:00
}
2018-04-13 17:34:27 +02:00
/// Retrieves an existing pending block iff it's not older than given block number.
///
/// NOTE: This will not prepare a new pending block if it's not existing.
/// See `map_pending_block` for alternative behaviour.
fn map_existing_pending_block < F , T > ( & self , f : F , latest_block_number : BlockNumber ) -> Option < T > where
F : FnOnce ( & ClosedBlock ) -> T ,
{
self . sealing . lock ( ) . queue
. peek_last_ref ( )
2018-06-01 09:38:20 +02:00
. and_then ( | b | {
if b . block ( ) . header ( ) . number ( ) > latest_block_number {
Some ( f ( b ) )
} else {
None
}
2018-04-13 17:34:27 +02:00
} )
2018-02-16 16:51:34 +01:00
}
2018-04-13 17:34:27 +02:00
fn pool_client < ' a , C : ' a > ( & ' a self , chain : & ' a C ) -> PoolClient < ' a , C > where
C : BlockChain + CallContract ,
2017-08-04 15:58:14 +02:00
{
2018-04-13 17:34:27 +02:00
PoolClient ::new (
chain ,
& self . nonce_cache ,
& * self . engine ,
self . accounts . as_ref ( ) . map ( | x | & * * x ) ,
self . options . refuse_service_transactions ,
2017-08-04 15:58:14 +02:00
)
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-04-13 17:34:27 +02:00
fn prepare_block < C > ( & self , chain : & C ) -> ( ClosedBlock , Option < H256 > ) where
C : BlockChain + CallContract + BlockProducer + Nonce + Sync ,
{
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 ( ) ;
2018-04-13 17:34:27 +02:00
// Open block
let ( mut open_block , original_work_hash ) = {
let mut sealing = self . sealing . lock ( ) ;
let last_work_hash = sealing . 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-04-13 17:34:27 +02:00
let mut open_block = match sealing . 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 " ) ;
2018-04-13 17:34:27 +02:00
let params = self . params . read ( ) . clone ( ) ;
2016-06-21 11:26:43 +02:00
chain . prepare_open_block (
2018-04-13 17:34:27 +02:00
params . author ,
params . gas_range_target ,
params . extra_data ,
2016-06-21 11:26:43 +02:00
)
}
} ;
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
}
2018-04-13 17:34:27 +02:00
( 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 ( ) ;
2018-04-13 17:34:27 +02:00
let mut not_allowed_transactions = HashSet ::new ( ) ;
let mut senders_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
2018-04-13 17:34:27 +02:00
let mut tx_count = 0 usize ;
let mut skipped_transactions = 0 usize ;
let client = self . pool_client ( chain ) ;
let engine_params = self . engine . params ( ) ;
2018-06-12 08:22:54 +02:00
let min_tx_gas : U256 = self . engine . schedule ( chain_info . best_block_number ) . tx_gas . into ( ) ;
2018-04-13 17:34:27 +02:00
let nonce_cap : Option < U256 > = if chain_info . best_block_number + 1 > = engine_params . dust_protection_transition {
Some ( ( engine_params . nonce_cap_increment * ( chain_info . best_block_number + 1 ) ) . into ( ) )
} else {
None
} ;
2018-06-12 08:22:54 +02:00
// we will never need more transactions than limit divided by min gas
let max_transactions = if min_tx_gas . is_zero ( ) {
usize ::max_value ( )
} else {
( * open_block . block ( ) . header ( ) . gas_limit ( ) / min_tx_gas ) . as_u64 ( ) as usize
} ;
2018-04-13 17:34:27 +02:00
let pending : Vec < Arc < _ > > = self . transaction_queue . pending (
client . clone ( ) ,
2018-06-12 08:22:54 +02:00
pool ::PendingSettings {
block_number : chain_info . best_block_number ,
current_timestamp : chain_info . best_block_timestamp ,
nonce_cap ,
max_len : max_transactions ,
ordering : miner ::PendingOrdering ::Priority ,
}
2018-04-13 17:34:27 +02:00
) ;
let took_ms = | elapsed : & Duration | {
elapsed . as_secs ( ) * 1000 + elapsed . subsec_nanos ( ) as u64 / 1_000_000
} ;
let block_start = Instant ::now ( ) ;
debug! ( target : " miner " , " Attempting to push {} transactions. " , pending . len ( ) ) ;
for tx in pending {
2016-10-27 19:28:34 +02:00
let start = Instant ::now ( ) ;
2018-04-13 17:34:27 +02:00
let transaction = tx . signed ( ) . clone ( ) ;
let hash = transaction . hash ( ) ;
let sender = transaction . sender ( ) ;
// Re-verify transaction again vs current state.
let result = client . verify_signed ( & transaction )
2018-04-19 11:52:54 +02:00
. map_err ( | e | e . into ( ) )
2018-04-13 17:34:27 +02:00
. and_then ( | _ | {
open_block . push_transaction ( transaction , None )
} ) ;
2016-10-27 19:28:34 +02:00
let took = start . elapsed ( ) ;
// Check for heavy transactions
2018-04-13 17:34:27 +02:00
match self . options . tx_queue_penalization {
Penalization ::Enabled { ref offend_threshold } if & took > offend_threshold = > {
senders_to_penalize . insert ( sender ) ;
debug! ( target : " miner " , " Detected heavy transaction ({} ms). Penalizing sender. " , took_ms ( & took ) ) ;
2016-10-27 19:28:34 +02:00
} ,
_ = > { } ,
}
2018-04-13 17:34:27 +02:00
debug! ( target : " miner " , " Adding tx {:?} took {} ms " , hash , took_ms ( & took ) ) ;
2016-10-27 19:28:34 +02:00
match result {
2018-04-19 11:52:54 +02:00
Err ( Error ( ErrorKind ::Execution ( ExecutionError ::BlockGasLimitReached { gas_limit , gas_used , gas } ) , _ ) ) = > {
2016-07-18 13:50:45 +02:00
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 {
2018-04-13 17:34:27 +02:00
debug! ( target : " txqueue " , " [{:?}] Transaction above block gas limit. " , hash ) ;
invalid_transactions . insert ( hash ) ;
2016-09-23 17:26:36 +02:00
}
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
2018-04-13 17:34:27 +02:00
let gas_left = gas_limit - gas_used ;
if gas_left < min_tx_gas {
debug! ( target : " miner " , " Remaining gas is lower than minimal gas for a transaction. Block is full. " ) ;
break ;
}
// Avoid iterating over the entire queue in case block is almost full.
skipped_transactions + = 1 ;
if skipped_transactions > MAX_SKIPPED_TRANSACTIONS {
debug! ( target : " miner " , " Reached skipped transactions threshold. Assuming block is full. " ) ;
2016-06-06 14:33:12 +02:00
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.
2018-04-19 11:52:54 +02:00
Err ( Error ( ErrorKind ::Execution ( ExecutionError ::InvalidNonce { expected , got } ) , _ ) ) = > {
2016-07-18 13:50:45 +02:00
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
2018-04-19 11:52:54 +02:00
Err ( Error ( ErrorKind ::Transaction ( transaction ::Error ::AlreadyImported ) , _ ) ) = > { } ,
Err ( Error ( ErrorKind ::Transaction ( transaction ::Error ::NotAllowed ) , _ ) ) = > {
2018-04-13 17:34:27 +02:00
not_allowed_transactions . insert ( hash ) ;
debug! ( target : " miner " , " Skipping non-allowed transaction for sender {:?} " , hash ) ;
2017-12-21 21:42:36 +01:00
} ,
2016-06-06 14:33:12 +02:00
Err ( e ) = > {
2018-04-13 17:34:27 +02:00
debug! ( target : " txqueue " , " [{:?}] Marking as invalid: {:?}. " , hash , e ) ;
debug! (
target : " miner " , " Error adding transaction to block: number={}. transaction_hash={:?}, Error: {:?} " , block_number , hash , e
) ;
2016-06-06 14:33:12 +02:00
invalid_transactions . insert ( hash ) ;
} ,
2018-04-13 17:34:27 +02:00
// imported ok
_ = > tx_count + = 1 ,
2016-06-06 14:33:12 +02:00
}
}
2018-04-13 17:34:27 +02:00
let elapsed = block_start . elapsed ( ) ;
debug! ( target : " miner " , " Pushed {} transactions in {} ms " , tx_count , took_ms ( & elapsed ) ) ;
2016-06-06 14:33:12 +02:00
let block = open_block . close ( ) ;
2016-06-21 11:26:43 +02:00
{
2018-04-13 17:34:27 +02:00
self . transaction_queue . remove ( invalid_transactions . iter ( ) , true ) ;
self . transaction_queue . remove ( not_allowed_transactions . iter ( ) , false ) ;
self . transaction_queue . penalize ( senders_to_penalize . iter ( ) ) ;
2016-04-15 07:38:23 +02:00
}
2018-04-13 17:34:27 +02:00
2016-09-13 15:09:07 +02:00
( block , original_work_hash )
}
2018-04-13 17:34:27 +02:00
/// Returns `true` if we should create pending block even if some other conditions are not met.
///
/// In general we always seal iff:
/// 1. --force-sealing CLI parameter is provided
/// 2. There are listeners awaiting new work packages (e.g. remote work notifications or stratum).
fn forced_sealing ( & self ) -> bool {
self . options . force_sealing | | ! self . listeners . read ( ) . is_empty ( )
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 {
2018-04-13 17:34:27 +02:00
let mut sealing = self . sealing . lock ( ) ;
if ! sealing . enabled {
2016-09-15 12:12:15 +02:00
trace! ( target : " miner " , " requires_reseal: sealing is disabled " ) ;
2018-04-13 17:34:27 +02:00
return false
}
if ! sealing . reseal_allowed ( ) {
trace! ( target : " miner " , " requires_reseal: reseal too early " ) ;
return false
}
trace! ( target : " miner " , " requires_reseal: sealing enabled " ) ;
// Disable sealing if there were no requests for SEALING_TIMEOUT_IN_BLOCKS
2018-06-12 08:21:55 +02:00
let had_requests = sealing . last_request . map ( | last_request | {
best_block > last_request
& & best_block - last_request < = SEALING_TIMEOUT_IN_BLOCKS
} ) . unwrap_or ( false ) ;
2018-04-13 17:34:27 +02:00
// keep sealing enabled if any of the conditions is met
let sealing_enabled = self . forced_sealing ( )
| | self . transaction_queue . has_local_pending_transactions ( )
| | self . engine . seals_internally ( ) = = Some ( true )
| | had_requests ;
let should_disable_sealing = ! sealing_enabled ;
trace! ( target : " miner " , " requires_reseal: should_disable_sealing={}; forced={:?}, has_local={:?}, internal={:?}, had_requests={:?} " ,
should_disable_sealing ,
self . forced_sealing ( ) ,
self . transaction_queue . has_local_pending_transactions ( ) ,
self . engine . seals_internally ( ) ,
had_requests ,
) ;
if should_disable_sealing {
2018-06-12 08:21:55 +02:00
trace! ( target : " miner " , " Miner sleeping (current {}, last {}) " , best_block , sealing . last_request . unwrap_or ( 0 ) ) ;
2018-04-13 17:34:27 +02:00
sealing . enabled = false ;
sealing . queue . reset ( ) ;
2016-09-13 15:09:07 +02:00
false
2018-04-13 17:34:27 +02:00
} else {
// sealing enabled and we don't want to sleep.
sealing . next_allowed_reseal = Instant ::now ( ) + self . options . reseal_min_period ;
true
2016-09-13 15:09:07 +02:00
}
}
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-05-09 12:05:56 +02:00
fn seal_and_import_block_internally < C > ( & self , chain : & C , block : ClosedBlock ) -> bool
where C : BlockChain + SealedBlockImporter ,
2018-03-03 18:42:13 +01:00
{
2018-04-13 17:34:27 +02:00
{
let sealing = self . sealing . lock ( ) ;
if block . transactions ( ) . is_empty ( )
& & ! self . forced_sealing ( )
& & Instant ::now ( ) < = sealing . next_mandatory_reseal
{
return false
}
}
2017-12-07 12:17:11 +01:00
2018-04-13 17:34:27 +02:00
trace! ( target : " miner " , " seal_block_internally: attempting internal seal. " ) ;
2017-12-07 12:17:11 +01:00
2018-04-13 17:34:27 +02:00
let parent_header = match chain . block_header ( BlockId ::Hash ( * block . header ( ) . parent_hash ( ) ) ) {
2018-05-09 12:05:56 +02:00
Some ( h ) = > {
match h . decode ( ) {
Ok ( decoded_hdr ) = > decoded_hdr ,
Err ( _ ) = > return false
}
}
2018-04-13 17:34:27 +02:00
None = > return false ,
} ;
match self . engine . generate_seal ( block . block ( ) , & parent_header ) {
// Save proposal for later seal submission and broadcast it.
Seal ::Proposal ( seal ) = > {
trace! ( target : " miner " , " Received a Proposal seal. " ) ;
{
let mut sealing = self . sealing . lock ( ) ;
sealing . next_mandatory_reseal = Instant ::now ( ) + self . options . reseal_max_period ;
sealing . queue . push ( block . clone ( ) ) ;
sealing . queue . use_last_ref ( ) ;
}
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
} )
} ,
// Directly import a regular sealed block.
Seal ::Regular ( seal ) = > {
trace! ( target : " miner " , " Received a Regular seal. " ) ;
{
let mut sealing = self . sealing . lock ( ) ;
sealing . next_mandatory_reseal = Instant ::now ( ) + self . options . reseal_max_period ;
}
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
} )
} ,
Seal ::None = > 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 ) = {
2018-04-13 17:34:27 +02:00
let block_header = block . block ( ) . header ( ) . clone ( ) ;
let block_hash = block_header . hash ( ) ;
let mut sealing = self . sealing . lock ( ) ;
let last_work_hash = sealing . 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_hash
) ;
let ( work , is_new ) = if last_work_hash . map_or ( true , | h | h ! = block_hash ) {
trace! (
target : " miner " ,
" prepare_work: Pushing a new, refreshed or borrowed pending {}... " ,
block_hash
) ;
let is_new = original_work_hash . map_or ( true , | h | h ! = block_hash ) ;
sealing . queue . push ( block ) ;
2016-07-01 20:38:37 +02:00
// If push notifications are enabled we assume all work items are used.
2018-04-13 17:34:27 +02:00
if is_new & & ! self . listeners . read ( ) . is_empty ( ) {
sealing . queue . use_last_ref ( ) ;
2016-07-01 20:38:37 +02:00
}
2018-04-13 17:34:27 +02:00
( Some ( ( block_hash , * block_header . difficulty ( ) , block_header . 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-04-13 17:34:27 +02:00
trace! (
target : " miner " ,
" prepare_work: leaving (last={:?}) " ,
sealing . 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 ) | {
2018-04-13 17:34:27 +02:00
for notifier in self . listeners . read ( ) . iter ( ) {
2017-01-25 11:03:36 +01:00
notifier . notify ( pow_hash , difficulty , number )
}
} ) ;
2016-06-30 22:35:59 +02:00
}
2016-03-18 19:36:32 +01:00
}
2016-09-13 15:09:07 +02:00
/// Returns true if we had to prepare new pending block.
2018-04-13 17:34:27 +02:00
fn prepare_pending_block < C > ( & self , client : & C ) -> bool where
C : BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync ,
{
trace! ( target : " miner " , " prepare_pending_block: entering " ) ;
2016-07-28 21:06:36 +02:00
let prepare_new = {
2018-04-13 17:34:27 +02:00
let mut sealing = self . sealing . lock ( ) ;
let have_work = sealing . queue . peek_last_ref ( ) . is_some ( ) ;
trace! ( target : " miner " , " prepare_pending_block: have_work={} " , have_work ) ;
2016-07-28 21:06:36 +02:00
if ! have_work {
2018-04-13 17:34:27 +02:00
sealing . enabled = true ;
2016-07-28 21:06:36 +02:00
true
} else {
false
}
} ;
2018-04-13 17:34:27 +02:00
2016-07-28 21:06:36 +02:00
if prepare_new {
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
2018-04-13 17:34:27 +02:00
// | NOTE Code below requires sealing locks. |
2016-07-08 17:19:14 +02:00
// | 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
}
2018-04-13 17:34:27 +02:00
2017-01-22 16:15:22 +01:00
let best_number = client . chain_info ( ) . best_block_number ;
2018-04-13 17:34:27 +02:00
let mut sealing = self . sealing . lock ( ) ;
2018-06-12 08:21:55 +02:00
if sealing . last_request ! = Some ( best_number ) {
2018-04-13 17:34:27 +02:00
trace! (
target : " miner " ,
" prepare_pending_block: Miner received request (was {}, now {}) - waking up. " ,
2018-06-12 08:21:55 +02:00
sealing . last_request . unwrap_or ( 0 ) , best_number
2018-04-13 17:34:27 +02:00
) ;
2018-06-12 08:21:55 +02:00
sealing . last_request = Some ( best_number ) ;
2016-04-28 17:36:53 +02:00
}
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
}
2018-06-13 09:58:52 +02:00
/// Prepare pending block, check whether sealing is needed, and then update sealing.
fn prepare_and_update_sealing < C : miner ::BlockChainClient > ( & self , chain : & C ) {
use miner ::MinerService ;
// Make sure to do it after transaction is imported and lock is dropped.
// We need to create pending block and enable sealing.
if self . engine . seals_internally ( ) . unwrap_or ( false ) | | ! self . prepare_pending_block ( chain ) {
// 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.
self . update_sealing ( chain ) ;
}
}
2016-03-09 13:28:37 +01:00
}
2016-03-18 13:59:11 +01:00
const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5 ;
2018-04-13 17:34:27 +02:00
impl miner ::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-04-13 17:34:27 +02:00
fn authoring_params ( & self ) -> AuthoringParams {
self . params . read ( ) . clone ( )
2016-03-09 14:26:28 +01:00
}
2018-04-13 17:34:27 +02:00
fn set_gas_range_target ( & self , gas_range_target : ( U256 , U256 ) ) {
self . params . write ( ) . gas_range_target = gas_range_target ;
2016-03-08 16:23:32 +01:00
}
2018-04-13 17:34:27 +02:00
fn set_extra_data ( & self , extra_data : Bytes ) {
self . params . write ( ) . extra_data = extra_data ;
2016-04-13 00:04:40 +02:00
}
2018-04-13 17:34:27 +02:00
fn set_author ( & self , address : Address , password : Option < String > ) -> Result < ( ) , AccountError > {
self . params . write ( ) . author = address ;
if self . engine . seals_internally ( ) . is_some ( ) & & password . is_some ( ) {
2016-12-05 18:08:16 +01:00
if let Some ( ref ap ) = self . accounts {
2018-04-13 17:34:27 +02:00
let password = password . unwrap_or_default ( ) ;
// Sign test message
2016-12-27 12:53:56 +01:00
ap . sign ( address . clone ( ) , Some ( password . clone ( ) ) , Default ::default ( ) ) ? ;
2018-04-13 17:34:27 +02:00
// Enable sealing
self . sealing . lock ( ) . enabled = true ;
2017-01-18 18:49:50 +01:00
// --------------------------------------------------------------------------
2018-04-13 17:34:27 +02:00
// | NOTE Code below may require author and sealing locks |
// | (some `Engine`s call `EngineClient.update_sealing()`) |
2017-01-18 18:49:50 +01:00
// | 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 {
2018-04-13 17:34:27 +02:00
Ok ( ( ) )
2016-12-05 18:08:16 +01:00
}
}
2016-03-28 18:53:33 +02:00
fn sensible_gas_price ( & self ) -> U256 {
// 10% above our minimum.
2018-04-13 17:34:27 +02:00
self . transaction_queue . current_worst_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 {
2018-04-13 17:34:27 +02:00
self . params . read ( ) . gas_range_target . 0 / 5. into ( )
2016-04-11 21:06:32 +02:00
}
2018-04-13 17:34:27 +02:00
fn import_external_transactions < C : miner ::BlockChainClient > (
2016-07-08 17:26:06 +02:00
& self ,
2018-04-13 17:34:27 +02:00
chain : & C ,
2017-01-13 09:51:36 +01:00
transactions : Vec < UnverifiedTransaction >
2018-04-13 17:34:27 +02:00
) -> Vec < Result < ( ) , transaction ::Error > > {
2016-09-19 10:38:47 +02:00
trace! ( target : " external_tx " , " Importing external transactions " ) ;
2018-04-13 17:34:27 +02:00
let client = self . pool_client ( chain ) ;
let results = self . transaction_queue . import (
client ,
transactions . into_iter ( ) . map ( pool ::verifier ::Transaction ::Unverified ) . collect ( ) ,
) ;
2016-07-06 17:15:59 +02:00
2018-06-13 09:58:52 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2018-04-13 17:34:27 +02:00
if ! results . is_empty ( ) & & self . options . reseal_on_external_tx & & self . sealing . lock ( ) . reseal_allowed ( ) {
2018-06-13 09:58:52 +02:00
self . prepare_and_update_sealing ( chain ) ;
2016-06-21 16:00:34 +02:00
}
2018-04-13 17:34:27 +02:00
2016-06-21 16:00:34 +02:00
results
2016-03-08 15:46:44 +01:00
}
2018-04-13 17:34:27 +02:00
fn import_own_transaction < C : miner ::BlockChainClient > (
2016-06-19 14:51:51 +02:00
& self ,
2018-03-03 18:42:13 +01:00
chain : & C ,
2018-06-18 15:32:18 +02:00
pending : PendingTransaction
2018-04-13 17:34:27 +02:00
) -> Result < ( ) , transaction ::Error > {
2018-06-18 15:32:18 +02:00
// note: you may want to use `import_claimed_local_transaction` instead of this one.
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
2018-04-13 17:34:27 +02:00
let client = self . pool_client ( chain ) ;
let imported = self . transaction_queue . import (
client ,
vec! [ pool ::verifier ::Transaction ::Local ( pending ) ]
) . pop ( ) . expect ( " one result returned per added transaction; one added => one result; qed " ) ;
2016-04-28 17:36:53 +02:00
2016-07-08 17:19:14 +02:00
// --------------------------------------------------------------------------
2018-04-13 17:34:27 +02:00
// | NOTE Code below requires sealing locks. |
2016-07-08 17:19:14 +02:00
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
2018-04-13 17:34:27 +02:00
if imported . is_ok ( ) & & self . options . reseal_on_own_tx & & self . sealing . lock ( ) . reseal_allowed ( ) {
2018-06-13 09:58:52 +02:00
self . prepare_and_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
}
2018-06-18 15:32:18 +02:00
fn import_claimed_local_transaction < C : miner ::BlockChainClient > (
& self ,
chain : & C ,
pending : PendingTransaction ,
trusted : bool
) -> Result < ( ) , transaction ::Error > {
// treat the tx as local if the option is enabled, or if we have the account
let sender = pending . sender ( ) ;
let treat_as_local = trusted
| | ! self . options . tx_queue_no_unfamiliar_locals
| | self . accounts . as_ref ( ) . map ( | accts | accts . has_account ( sender ) ) . unwrap_or ( false ) ;
if treat_as_local {
self . import_own_transaction ( chain , pending )
} else {
// We want to replicate behaviour for external transactions if we're not going to treat
// this as local. This is important with regards to sealing blocks
self . import_external_transactions ( chain , vec! [ pending . transaction . into ( ) ] )
. pop ( ) . expect ( " one result per tx, as in `import_own_transaction` " )
}
}
2018-04-13 17:34:27 +02:00
fn local_transactions ( & self ) -> BTreeMap < H256 , pool ::local_transactions ::Status > {
self . transaction_queue . local_transactions ( )
2016-03-10 16:00:55 +01:00
}
2018-04-13 17:34:27 +02:00
fn queued_transactions ( & self ) -> Vec < Arc < VerifiedTransaction > > {
self . transaction_queue . all_transactions ( )
2016-11-16 17:54:54 +01:00
}
2018-06-12 08:22:54 +02:00
fn ready_transactions < C > ( & self , chain : & C , max_len : usize , ordering : miner ::PendingOrdering )
-> Vec < Arc < VerifiedTransaction > >
where
2018-04-13 17:34:27 +02:00
C : ChainInfo + Nonce + Sync ,
{
let chain_info = chain . chain_info ( ) ;
2016-12-15 18:19:19 +01:00
2018-04-13 17:34:27 +02:00
let from_queue = | | {
2018-06-12 08:22:54 +02:00
// We propagate transactions over the nonce cap.
// The mechanism is only to limit number of transactions in pending block
// those transactions are valid and will just be ready to be included in next block.
let nonce_cap = None ;
2018-04-13 17:34:27 +02:00
self . transaction_queue . pending (
CachedNonceClient ::new ( chain , & self . nonce_cache ) ,
2018-06-12 08:22:54 +02:00
pool ::PendingSettings {
block_number : chain_info . best_block_number ,
current_timestamp : chain_info . best_block_timestamp ,
nonce_cap ,
max_len ,
ordering ,
} ,
2018-04-13 17:34:27 +02:00
)
} ;
let from_pending = | | {
self . map_existing_pending_block ( | sealing | {
sealing . transactions ( )
. iter ( )
. map ( | signed | pool ::VerifiedTransaction ::from_pending_block_transaction ( signed . clone ( ) ) )
. map ( Arc ::new )
2018-06-12 08:22:54 +02:00
. take ( max_len )
2018-04-13 17:34:27 +02:00
. collect ( )
} , chain_info . best_block_number )
} ;
2016-03-27 15:12:21 +02:00
2016-10-07 12:13:15 +02:00
match self . options . pending_set {
2018-04-13 17:34:27 +02:00
PendingSet ::AlwaysQueue = > {
from_queue ( )
2016-10-07 12:13:15 +02:00
} ,
PendingSet ::AlwaysSealing = > {
2018-04-13 17:34:27 +02:00
from_pending ( ) . unwrap_or_default ( )
2016-10-07 12:13:15 +02:00
} ,
PendingSet ::SealingOrElseQueue = > {
2018-04-13 17:34:27 +02:00
from_pending ( ) . unwrap_or_else ( from_queue )
2016-10-07 12:13:15 +02:00
} ,
2016-05-24 21:56:32 +02:00
}
}
2018-04-13 17:34:27 +02:00
fn next_nonce < C > ( & self , chain : & C , address : & Address ) -> U256 where
C : Nonce + Sync ,
{
self . transaction_queue . next_nonce ( CachedNonceClient ::new ( chain , & self . nonce_cache ) , address )
. unwrap_or_else ( | | chain . latest_nonce ( address ) )
2017-03-19 08:46:51 +01:00
}
2018-04-13 17:34:27 +02:00
fn transaction ( & self , hash : & H256 ) -> Option < Arc < VerifiedTransaction > > {
self . transaction_queue . find ( hash )
2016-08-17 19:25:02 +02:00
}
2018-04-13 17:34:27 +02:00
fn remove_transaction ( & self , hash : & H256 ) -> Option < Arc < VerifiedTransaction > > {
self . transaction_queue . remove ( ::std ::iter ::once ( hash ) , false )
. pop ( )
. expect ( " remove() returns one result per hash; one hash passed; qed " )
}
2016-05-24 21:56:32 +02:00
2018-04-13 17:34:27 +02:00
fn queue_status ( & self ) -> QueueStatus {
self . transaction_queue . status ( )
2016-05-24 21:56:32 +02:00
}
2018-04-13 17:34:27 +02:00
fn pending_receipt ( & self , best_block : BlockNumber , hash : & H256 ) -> Option < RichReceipt > {
self . map_existing_pending_block ( | pending | {
let txs = pending . transactions ( ) ;
txs . iter ( )
. map ( | t | t . hash ( ) )
. position ( | t | t = = * hash )
. map ( | index | {
let receipts = pending . receipts ( ) ;
let prev_gas = if index = = 0 { Default ::default ( ) } else { receipts [ index - 1 ] . gas_used } ;
let tx = & txs [ index ] ;
let receipt = & receipts [ index ] ;
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 ,
Action ::Create = > {
let sender = tx . sender ( ) ;
Some ( contract_address ( self . engine . create_address_scheme ( pending . header ( ) . number ( ) ) , & sender , & tx . nonce , & tx . data ) . 0 )
}
} ,
logs : receipt . logs . clone ( ) ,
log_bloom : receipt . log_bloom ,
outcome : receipt . outcome . clone ( ) ,
}
} )
} , best_block ) . and_then ( | x | x )
2016-04-06 12:15:20 +02:00
}
2018-04-13 17:34:27 +02:00
fn pending_receipts ( & self , best_block : BlockNumber ) -> Option < BTreeMap < H256 , Receipt > > {
self . map_existing_pending_block ( | pending | {
let hashes = pending . transactions ( ) . iter ( ) . map ( | t | t . hash ( ) ) ;
let receipts = pending . receipts ( ) . iter ( ) . cloned ( ) ;
hashes . zip ( receipts ) . collect ( )
} , best_block )
2017-07-12 08:52:18 +02:00
}
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-04-13 17:34:27 +02:00
fn update_sealing < C > ( & self , chain : & C ) where
C : BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync ,
2018-03-03 18:42:13 +01:00
{
2016-07-28 21:06:36 +02:00
trace! ( target : " miner " , " update_sealing " ) ;
2016-08-04 18:17:21 +02:00
2018-04-13 17:34:27 +02:00
// Do nothing if reseal is not required,
// but note that `requires_reseal` updates internal state.
if ! self . requires_reseal ( chain . chain_info ( ) . best_block_number ) {
return ;
}
2017-07-31 12:34:29 +02:00
2018-04-13 17:34:27 +02:00
// --------------------------------------------------------------------------
// | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
trace! ( target : " miner " , " update_sealing: preparing a block " ) ;
let ( block , original_work_hash ) = self . prepare_block ( chain ) ;
// refuse to seal the first block of the chain if it contains hard forks
// which should be on by default.
if block . block ( ) . header ( ) . number ( ) = = 1 & & self . engine . params ( ) . contains_bugfix_hard_fork ( ) {
warn! ( " 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 . " );
return ;
}
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 " ) ;
}
} ,
Some ( false ) = > {
trace! ( target : " miner " , " update_sealing: engine is not keen to seal internally right now " ) ;
// anyway, save the block for later use
self . sealing . lock ( ) . queue . push ( block ) ;
} ,
None = > {
trace! ( target : " miner " , " update_sealing: engine does not seal internally, preparing work " ) ;
self . prepare_work ( block , original_work_hash )
} ,
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 {
2018-06-12 08:21:55 +02:00
self . sealing . lock ( ) . enabled
2016-08-02 18:53:32 +02:00
}
2018-04-13 17:34:27 +02:00
fn work_package < C > ( & self , chain : & C ) -> Option < ( H256 , BlockNumber , u64 , U256 ) > where
C : BlockChain + CallContract + BlockProducer + SealedBlockImporter + Nonce + Sync ,
2018-03-03 18:42:13 +01:00
{
2018-04-13 17:34:27 +02:00
if self . engine . seals_internally ( ) . is_some ( ) {
return None ;
}
self . prepare_pending_block ( chain ) ;
self . sealing . lock ( ) . queue . use_last_ref ( ) . map ( | b | {
let header = b . header ( ) ;
( header . hash ( ) , header . number ( ) , header . timestamp ( ) , * header . difficulty ( ) )
} )
2016-03-08 15:46:44 +01:00
}
2018-04-13 17:34:27 +02:00
// Note used for external submission (PoW) and internally by sealing engines.
fn submit_seal ( & self , block_hash : H256 , seal : Vec < Bytes > ) -> Result < SealedBlock , Error > {
2016-09-28 23:31:59 +02:00
let result =
2018-04-13 17:34:27 +02:00
if let Some ( b ) = self . sealing . lock ( ) . queue . get_used_if (
2016-09-28 23:31:59 +02:00
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 ) ;
2018-04-19 11:52:54 +02:00
Err ( ErrorKind ::PowInvalid . into ( ) )
2016-09-28 23:31:59 +02:00
} )
} else {
2016-12-05 18:08:16 +01:00
warn! ( target : " miner " , " Submitted solution rejected: Block unknown or out of date. " ) ;
2018-04-19 11:52:54 +02:00
Err ( ErrorKind ::PowHashInvalid . into ( ) )
2016-09-28 23:31:59 +02:00
} ;
2018-04-13 17:34:27 +02:00
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 ( ) ;
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 ) ) ) ;
2018-04-13 17:34:27 +02:00
Ok ( sealed )
2016-06-29 21:49:12 +02:00
} )
2016-03-08 15:46:44 +01:00
}
2018-04-13 17:34:27 +02:00
fn chain_new_blocks < C > ( & self , chain : & C , imported : & [ H256 ] , _invalid : & [ H256 ] , enacted : & [ H256 ] , retracted : & [ H256 ] , is_internal_import : bool )
where C : miner ::BlockChainClient ,
2018-03-03 18:42:13 +01:00
{
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
2018-04-13 17:34:27 +02:00
// Clear nonce cache
self . nonce_cache . write ( ) . clear ( ) ;
2016-03-17 15:20:33 +01:00
2018-04-13 17:34:27 +02:00
// First update gas limit in transaction queue and minimal gas price.
let gas_limit = * chain . best_block_header ( ) . gas_limit ( ) ;
self . update_transaction_queue_limits ( gas_limit ) ;
2017-01-18 19:44:24 +01:00
2016-03-17 15:20:33 +01:00
// Then import all transactions...
2018-04-13 17:34:27 +02:00
let client = self . pool_client ( chain ) ;
2016-03-08 15:46:44 +01:00
{
2018-04-13 17:34:27 +02:00
retracted
. par_iter ( )
. for_each ( | hash | {
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 ( )
. into_iter ( )
. map ( pool ::verifier ::Transaction ::Retracted )
. collect ( ) ;
let _ = self . transaction_queue . import (
client . clone ( ) ,
txs ,
) ;
} ) ;
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
2018-04-13 17:34:27 +02:00
self . transaction_queue . cull ( client ) ;
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 ) {
2018-04-13 17:34:27 +02:00
// Reset `next_allowed_reseal` in case a block is imported.
// Even if min_period is high, we will always attempt to create
// new pending block.
self . sealing . lock ( ) . next_allowed_reseal = Instant ::now ( ) ;
if ! is_internal_import {
// --------------------------------------------------------------------------
// | NOTE Code below requires sealing locks. |
// | Make sure to release the locks before calling that method. |
// --------------------------------------------------------------------------
self . update_sealing ( chain ) ;
}
2016-07-28 21:06:36 +02:00
}
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 > {
2018-04-13 17:34:27 +02:00
self . map_existing_pending_block ( | b | b . state ( ) . clone ( ) , latest_block_number )
2018-03-03 18:42:13 +01:00
}
fn pending_block_header ( & self , latest_block_number : BlockNumber ) -> Option < Header > {
2018-04-13 17:34:27 +02:00
self . map_existing_pending_block ( | b | b . header ( ) . clone ( ) , latest_block_number )
2018-03-03 18:42:13 +01:00
}
fn pending_block ( & self , latest_block_number : BlockNumber ) -> Option < Block > {
2018-04-13 17:34:27 +02:00
self . map_existing_pending_block ( | b | b . to_base ( ) , latest_block_number )
2018-03-03 18:42:13 +01:00
}
2017-01-22 16:15:22 +01:00
2018-04-13 17:34:27 +02:00
fn pending_transactions ( & self , latest_block_number : BlockNumber ) -> Option < Vec < SignedTransaction > > {
self . map_existing_pending_block ( | b | b . transactions ( ) . into_iter ( ) . cloned ( ) . collect ( ) , latest_block_number )
2017-01-22 16:15:22 +01:00
}
}
2016-03-18 13:59:11 +01:00
#[ cfg(test) ]
mod tests {
2016-07-14 12:16:53 +02:00
use super ::* ;
2016-08-24 18:35:21 +02:00
use ethkey ::{ Generator , Random } ;
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-04-13 17:34:27 +02:00
use client ::{ TestBlockChainClient , EachBlockWith , ChainInfo , ImportSealedBlock } ;
2018-06-12 08:22:54 +02:00
use miner ::{ MinerService , PendingOrdering } ;
2018-04-09 16:14:33 +02:00
use test_helpers ::{ generate_dummy_client , generate_dummy_client_with_spec_and_accounts } ;
2018-04-13 17:34:27 +02:00
use transaction ::{ Transaction } ;
2016-03-18 13:59:11 +01:00
#[ test ]
fn should_prepare_block_to_seal ( ) {
// given
let client = TestBlockChainClient ::default ( ) ;
2018-04-13 17:34:27 +02:00
let miner = Miner ::new_for_tests ( & Spec ::new_test ( ) , None ) ;
2016-03-18 13:59:11 +01:00
// when
2018-04-13 17:34:27 +02:00
let sealing_work = miner . work_package ( & client ) ;
2016-03-25 16:41:01 +01:00
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 ( ) ;
2018-04-13 17:34:27 +02:00
let miner = Miner ::new_for_tests ( & Spec ::new_test ( ) , None ) ;
2016-03-18 13:59:11 +01:00
2018-04-13 17:34:27 +02:00
let res = miner . work_package ( & client ) ;
let hash = res . unwrap ( ) . 0 ;
let block = miner . submit_seal ( hash , vec! [ ] ) . unwrap ( ) ;
client . import_sealed_block ( block ) . unwrap ( ) ;
2016-03-25 16:41:01 +01:00
// two more blocks mined, work requested.
client . add_blocks ( 1 , EachBlockWith ::Uncle ) ;
2018-04-13 17:34:27 +02:00
miner . work_package ( & client ) ;
2016-03-25 16:41:01 +01:00
client . add_blocks ( 1 , EachBlockWith ::Uncle ) ;
2018-04-13 17:34:27 +02:00
miner . work_package ( & client ) ;
2016-03-18 13:59:11 +01:00
2016-03-25 16:41:01 +01:00
// solution to original work submitted.
2018-04-13 17:34:27 +02:00
assert! ( miner . submit_seal ( hash , vec! [ ] ) . is_ok ( ) ) ;
2016-03-18 13:59:11 +01:00
}
2016-07-14 12:16:53 +02:00
fn miner ( ) -> Miner {
2018-04-13 17:34:27 +02:00
Miner ::new (
2016-07-14 12:16:53 +02:00
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
pending_set : PendingSet ::AlwaysSealing ,
work_queue_size : 5 ,
enable_resubmission : true ,
2017-11-03 15:20:20 +01:00
infinite_pending_block : false ,
2018-04-13 17:34:27 +02:00
tx_queue_penalization : Penalization ::Disabled ,
tx_queue_strategy : PrioritizationStrategy ::GasPriceOnly ,
2018-06-18 15:32:18 +02:00
tx_queue_no_unfamiliar_locals : false ,
2018-04-13 17:34:27 +02:00
refuse_service_transactions : false ,
pool_limits : Default ::default ( ) ,
pool_verification_options : pool ::verifier ::Options {
minimal_gas_price : 0. into ( ) ,
block_gas_limit : U256 ::max_value ( ) ,
tx_gas_limit : U256 ::max_value ( ) ,
} ,
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
2018-04-13 17:34:27 +02:00
)
2016-07-14 12:16:53 +02:00
}
2018-06-18 15:32:18 +02:00
const TEST_CHAIN_ID : u64 = 2 ;
2016-09-13 15:09:07 +02:00
fn transaction ( ) -> SignedTransaction {
2018-06-18 15:32:18 +02:00
transaction_with_chain_id ( TEST_CHAIN_ID )
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
2018-04-13 17:34:27 +02:00
assert_eq! ( res . unwrap ( ) , ( ) ) ;
assert_eq! ( miner . pending_transactions ( best_block ) . unwrap ( ) . len ( ) , 1 ) ;
assert_eq! ( miner . pending_receipts ( best_block ) . unwrap ( ) . len ( ) , 1 ) ;
2018-06-12 08:22:54 +02:00
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . 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)
2018-04-13 17:34:27 +02:00
assert! ( ! miner . prepare_pending_block ( & 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
2018-04-13 17:34:27 +02:00
assert_eq! ( res . unwrap ( ) , ( ) ) ;
assert_eq! ( miner . pending_transactions ( best_block ) , None ) ;
assert_eq! ( miner . pending_receipts ( best_block ) , None ) ;
2018-06-12 08:22:54 +02:00
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . len ( ) , 1 ) ;
2016-10-07 12:13:15 +02:00
}
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
2018-04-13 17:34:27 +02:00
assert_eq! ( res . unwrap ( ) , ( ) ) ;
// By default we don't reseal on external transactions
assert_eq! ( miner . pending_transactions ( best_block ) , None ) ;
assert_eq! ( miner . pending_receipts ( best_block ) , None ) ;
// By default we use PendingSet::AlwaysSealing, so no transactions yet.
2018-06-12 08:22:54 +02:00
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . 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)
2018-04-13 17:34:27 +02:00
assert! ( miner . prepare_pending_block ( & client ) ) ;
// After pending block is created we should see a transaction.
2018-06-12 08:22:54 +02:00
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . len ( ) , 1 ) ;
2016-09-15 12:12:15 +02:00
}
2018-06-18 15:32:18 +02:00
#[ test ]
fn should_treat_unfamiliar_locals_selectively ( ) {
// given
let keypair = Random . generate ( ) . unwrap ( ) ;
let client = TestBlockChainClient ::default ( ) ;
let account_provider = AccountProvider ::transient_provider ( ) ;
account_provider . insert_account ( keypair . secret ( ) . clone ( ) , " " ) . expect ( " can add accounts to the provider we just created " ) ;
let miner = Miner ::new (
MinerOptions {
tx_queue_no_unfamiliar_locals : true ,
.. miner ( ) . options
} ,
GasPricer ::new_fixed ( 0 u64 . into ( ) ) ,
& Spec ::new_test ( ) ,
Some ( Arc ::new ( account_provider ) ) ,
) ;
let transaction = transaction ( ) ;
let best_block = 0 ;
// when
// This transaction should not be marked as local because our account_provider doesn't have the sender
let res = miner . import_claimed_local_transaction ( & client , PendingTransaction ::new ( transaction . clone ( ) , None ) , false ) ;
// then
// Check the same conditions as `should_import_external_transaction` first. Behaviour should be identical.
// That is: it's treated as though we added it through `import_external_transactions`
assert_eq! ( res . unwrap ( ) , ( ) ) ;
assert_eq! ( miner . pending_transactions ( best_block ) , None ) ;
assert_eq! ( miner . pending_receipts ( best_block ) , None ) ;
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . len ( ) , 0 ) ;
assert! ( miner . prepare_pending_block ( & client ) ) ;
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . len ( ) , 1 ) ;
// when - 2nd part: create a local transaction from account_provider.
// Borrow the transaction used before & sign with our generated keypair.
let local_transaction = transaction . deconstruct ( ) . 0. as_unsigned ( ) . clone ( ) . sign ( keypair . secret ( ) , Some ( TEST_CHAIN_ID ) ) ;
let res2 = miner . import_claimed_local_transaction ( & client , PendingTransaction ::new ( local_transaction , None ) , false ) ;
// then - 2nd part: we add on the results from the last pending block.
// This is borrowed from `should_make_pending_block_when_importing_own_transaction` and slightly modified.
assert_eq! ( res2 . unwrap ( ) , ( ) ) ;
assert_eq! ( miner . pending_transactions ( best_block ) . unwrap ( ) . len ( ) , 2 ) ;
assert_eq! ( miner . pending_receipts ( best_block ) . unwrap ( ) . len ( ) , 2 ) ;
assert_eq! ( miner . ready_transactions ( & client , 10 , PendingOrdering ::Priority ) . len ( ) , 2 ) ;
assert! ( ! miner . prepare_pending_block ( & client ) ) ;
}
2016-09-15 12:12:15 +02:00
#[ 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 ( ) ;
2018-04-13 17:34:27 +02:00
assert! ( miner . prepare_pending_block ( & client ) ) ;
2016-09-15 12:12:15 +02:00
// 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 ( ) ;
2018-04-13 17:34:27 +02:00
let miner = Miner ::new_for_tests ( & spec , None ) ;
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
2018-04-13 17:34:27 +02:00
let import = miner . import_external_transactions ( & * client , vec! [ transaction_with_chain_id ( spec . chain_id ( ) ) . into ( ) ] ) . pop ( ) . unwrap ( ) ;
assert_eq! ( import . unwrap ( ) , ( ) ) ;
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 ) ;
2018-04-13 17:34:27 +02:00
assert! ( miner . import_own_transaction ( & * client , PendingTransaction ::new ( transaction_with_chain_id ( spec . chain_id ( ) ) . into ( ) , None ) ) . is_ok ( ) ) ;
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_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 ) ;
2018-04-13 17:34:27 +02:00
assert! ( match client . miner ( ) . set_author ( addr , Some ( " " . into ( ) ) ) { Err ( AccountError ::NotFound ) = > true , _ = > false } ) ;
2017-07-12 08:52:18 +02:00
}
2018-06-12 08:21:55 +02:00
#[ test ]
fn should_mine_if_internal_sealing_is_enabled ( ) {
let spec = Spec ::new_instant ( ) ;
let miner = Miner ::new_for_tests ( & spec , None ) ;
let client = generate_dummy_client ( 2 ) ;
miner . update_sealing ( & * client ) ;
assert! ( miner . is_currently_sealing ( ) ) ;
}
#[ test ]
fn should_not_mine_if_internal_sealing_is_disabled ( ) {
let spec = Spec ::new_test_round ( ) ;
let miner = Miner ::new_for_tests ( & spec , None ) ;
let client = generate_dummy_client ( 2 ) ;
miner . update_sealing ( & * client ) ;
assert! ( ! miner . is_currently_sealing ( ) ) ;
}
#[ test ]
fn should_not_mine_if_no_fetch_work_request ( ) {
let spec = Spec ::new_test ( ) ;
let miner = Miner ::new_for_tests ( & spec , None ) ;
let client = generate_dummy_client ( 2 ) ;
miner . update_sealing ( & * client ) ;
assert! ( ! miner . is_currently_sealing ( ) ) ;
}
#[ test ]
fn should_mine_if_fetch_work_request ( ) {
struct DummyNotifyWork ;
impl NotifyWork for DummyNotifyWork {
fn notify ( & self , _pow_hash : H256 , _difficulty : U256 , _number : u64 ) { }
}
let spec = Spec ::new_test ( ) ;
let miner = Miner ::new_for_tests ( & spec , None ) ;
miner . add_work_listener ( Box ::new ( DummyNotifyWork ) ) ;
let client = generate_dummy_client ( 2 ) ;
miner . update_sealing ( & * client ) ;
assert! ( miner . is_currently_sealing ( ) ) ;
}
2016-03-18 13:59:11 +01:00
}