diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 803706c56..4518e416a 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -16,6 +16,7 @@ use rayon::prelude::*; use std::sync::atomic::AtomicBool; +use std::time::{Instant, Duration}; use util::*; use account_provider::AccountProvider; @@ -50,12 +51,16 @@ pub struct MinerOptions { pub reseal_on_external_tx: bool, /// Reseal on receipt of new local transactions. pub reseal_on_own_tx: bool, + /// Minimum period between transaction-inspired reseals. + pub reseal_min_period: Duration, /// Maximum amount of gas to bother considering for block insertion. pub tx_gas_limit: U256, /// Maximum size of the transaction queue. pub tx_queue_size: usize, /// Whether we should fallback to providing all the queue's transactions or just pending. pub pending_set: PendingSet, + /// How many historical work packages can we store before running out? + pub work_queue_size: usize, } impl Default for MinerOptions { @@ -67,6 +72,8 @@ impl Default for MinerOptions { tx_gas_limit: !U256::zero(), tx_queue_size: 1024, pending_set: PendingSet::AlwaysQueue, + reseal_min_period: Duration::from_secs(0), + work_queue_size: 20, } } } @@ -80,6 +87,7 @@ pub struct Miner { // for sealing... options: MinerOptions, sealing_enabled: AtomicBool, + next_allowed_reseal: Mutex, sealing_block_last_request: Mutex, gas_range_target: RwLock<(U256, U256)>, author: RwLock
, @@ -96,8 +104,9 @@ impl Miner { transaction_queue: Mutex::new(TransactionQueue::new()), options: Default::default(), sealing_enabled: AtomicBool::new(false), + next_allowed_reseal: Mutex::new(Instant::now()), sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(UsingQueue::new(5)), + sealing_work: Mutex::new(UsingQueue::new(20)), gas_range_target: RwLock::new((U256::zero(), U256::zero())), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), @@ -111,13 +120,14 @@ impl Miner { Arc::new(Miner { transaction_queue: Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, options.tx_gas_limit)), sealing_enabled: AtomicBool::new(options.force_sealing), - options: options, + next_allowed_reseal: Mutex::new(Instant::now()), sealing_block_last_request: Mutex::new(0), - sealing_work: Mutex::new(UsingQueue::new(5)), + sealing_work: Mutex::new(UsingQueue::new(options.work_queue_size)), gas_range_target: RwLock::new((U256::zero(), U256::zero())), author: RwLock::new(Address::default()), extra_data: RwLock::new(Vec::new()), accounts: accounts, + options: options, spec: spec, }) } @@ -261,6 +271,9 @@ impl Miner { // Return if !have_work } + + /// Are we allowed to do a non-mandatory reseal? + fn tx_reseal_allowed(&self) -> bool { Instant::now() > *self.next_allowed_reseal.lock().unwrap() } } const SEALING_TIMEOUT_IN_BLOCKS : u64 = 5; @@ -431,7 +444,7 @@ impl MinerService for Miner { .map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External)) .collect() }; - if !results.is_empty() && self.options.reseal_on_external_tx { + if !results.is_empty() && self.options.reseal_on_external_tx && self.tx_reseal_allowed() { self.update_sealing(chain); } results @@ -466,7 +479,7 @@ impl MinerService for Miner { import }; - if imported.is_ok() && self.options.reseal_on_own_tx { + if imported.is_ok() && self.options.reseal_on_own_tx && self.tx_reseal_allowed() { // Make sure to do it after transaction is imported and lock is droped. // We need to create pending block and enable sealing let prepared = self.enable_and_prepare_sealing(chain); @@ -559,6 +572,7 @@ impl MinerService for Miner { self.sealing_enabled.store(false, atomic::Ordering::Relaxed); self.sealing_work.lock().unwrap().reset(); } else { + *self.next_allowed_reseal.lock().unwrap() = Instant::now() + self.options.reseal_min_period; self.prepare_sealing(chain); } } diff --git a/parity/cli.rs b/parity/cli.rs index 27578df73..a48ce3aa7 100644 --- a/parity/cli.rs +++ b/parity/cli.rs @@ -137,6 +137,13 @@ Sealing/Mining Options: own - reseal only on a new local transaction; ext - reseal only on a new external transaction; all - reseal on all new transactions [default: all]. + --reseal-min-period MS Specify the minimum time between reseals from + incoming transactions. MS is time measured in + milliseconds [default: 2000]. + --work-queue-size ITEMS Specify the number of historical work packages + which are kept cached lest a solution is found for + them later. High values take more memory but result + in fewer unusable solutions [default: 20]. --tx-gas-limit GAS Apply a limit of GAS as the maximum amount of gas a single transaction may have for it to be mined. --relay-set SET Set of transactions to relay. SET may be: @@ -302,6 +309,8 @@ pub struct Args { pub flag_no_token: bool, pub flag_force_sealing: bool, pub flag_reseal_on_txs: String, + pub flag_reseal_min_period: u64, + pub flag_work_queue_size: usize, pub flag_tx_gas_limit: Option, pub flag_relay_set: String, pub flag_author: Option, diff --git a/parity/configuration.rs b/parity/configuration.rs index 121d40e6e..e95ef4233 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -16,6 +16,7 @@ use std::env; use std::fs::File; +use std::time::Duration; use std::io::{BufRead, BufReader}; use std::net::{SocketAddr, IpAddr}; use std::path::PathBuf; @@ -103,6 +104,8 @@ impl Configuration { "lenient" => PendingSet::SealingOrElseQueue, x => die!("{}: Invalid value for --relay-set option. Use --help for more information.", x) }, + reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period), + work_queue_size: self.args.flag_work_queue_size, } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 88a12a74f..59d06e84a 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -17,6 +17,7 @@ //! rpc integration tests. use std::sync::Arc; use std::str::FromStr; +use std::time::Duration; use ethcore::client::{BlockChainClient, Client, ClientConfig}; use ethcore::ids::BlockID; @@ -57,6 +58,8 @@ fn miner_service(spec: Spec, accounts: Arc) -> Arc { tx_queue_size: 1024, tx_gas_limit: !U256::zero(), pending_set: PendingSet::SealingOrElseQueue, + reseal_min_period: Duration::from_secs(0), + work_queue_size: 50, }, spec, Some(accounts)