diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 7348db566..a2dab4475 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -48,6 +48,17 @@ pub enum PendingSet { SealingOrElseQueue, } +/// 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), +} + /// Configures the behaviour of the miner. #[derive(Debug, PartialEq)] pub struct MinerOptions { @@ -71,6 +82,8 @@ pub struct MinerOptions { pub work_queue_size: usize, /// Can we submit two different solutions for the same block and expect both to result in an import? pub enable_resubmission: bool, + /// Global gas limit for all transaction in the queue except for local and retracted. + pub tx_queue_gas_limit: GasLimit, } impl Default for MinerOptions { @@ -86,6 +99,7 @@ impl Default for MinerOptions { reseal_min_period: Duration::from_secs(2), work_queue_size: 20, enable_resubmission: true, + tx_queue_gas_limit: GasLimit::Auto, } } } @@ -194,7 +208,11 @@ impl Miner { true => None, false => Some(WorkPoster::new(&options.new_work_notify)) }; - let txq = Arc::new(Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, !U256::zero(), options.tx_gas_limit))); + let gas_limit = match options.tx_queue_gas_limit { + GasLimit::Fixed(ref limit) => *limit, + _ => !U256::zero(), + }; + let txq = Arc::new(Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, gas_limit, options.tx_gas_limit))); Miner { transaction_queue: txq, next_allowed_reseal: Mutex::new(Instant::now()), @@ -443,8 +461,10 @@ impl Miner { let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); let mut queue = self.transaction_queue.lock(); queue.set_gas_limit(gas_limit); - // Set total qx queue gas limit to be 2x the block gas limit. - queue.set_total_gas_limit(gas_limit << 1); + if let GasLimit::Auto = self.options.tx_queue_gas_limit { + // Set total tx queue gas limit to be 2x the block gas limit. + queue.set_total_gas_limit(gas_limit << 1); + } } /// Returns true if we had to prepare new pending block. @@ -1062,6 +1082,7 @@ mod tests { reseal_min_period: Duration::from_secs(5), tx_gas_limit: !U256::zero(), tx_queue_size: 1024, + tx_queue_gas_limit: GasLimit::None, pending_set: PendingSet::AlwaysSealing, work_queue_size: 5, enable_resubmission: true, diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index c6bb00dce..8dfddf483 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -48,7 +48,7 @@ mod work_notify; mod price_info; pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin}; -pub use self::miner::{Miner, MinerOptions, PendingSet, GasPricer, GasPriceCalibratorOptions}; +pub use self::miner::{Miner, MinerOptions, PendingSet, GasPricer, GasPriceCalibratorOptions, GasLimit}; pub use self::external::{ExternalMiner, ExternalMinerService}; pub use client::TransactionImportResult; diff --git a/ethcore/src/miner/transaction_queue.rs b/ethcore/src/miner/transaction_queue.rs index 38923438c..fdb652780 100644 --- a/ethcore/src/miner/transaction_queue.rs +++ b/ethcore/src/miner/transaction_queue.rs @@ -331,7 +331,9 @@ impl TransactionSet { let r = gas.overflowing_add(order.gas); if r.1 { return false } gas = r.0; - count <= self.limit && gas <= self.gas_limit + // Own and retracted transactions are allowed to go above the gas limit, bot not above the count limit. + (gas <= self.gas_limit || order.origin == TransactionOrigin::Local || order.origin == TransactionOrigin::RetractedBlock) && + count <= self.limit }) .map(|order| by_hash.get(&order.hash) .expect("All transactions in `self.by_priority` and `self.by_address` are kept in sync with `by_hash`.")) @@ -1762,13 +1764,27 @@ mod test { #[test] fn should_limit_by_gas() { let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero()); - let (tx1, _) = new_tx_pair_default(U256::from(4), U256::from(1)); - let (tx3, _) = new_tx_pair_default(U256::from(4), U256::from(2)); - txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap(); - txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).unwrap(); + let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); + let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); + txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).ok(); + txq.add(tx2.clone(), &default_account_details, TransactionOrigin::External).ok(); + txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).ok(); + txq.add(tx4.clone(), &default_account_details, TransactionOrigin::External).ok(); assert_eq!(txq.status().pending, 2); } + #[test] + fn should_keep_own_transactions_above_gas_limit() { + let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero()); + let (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1)); + let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2)); + txq.add(tx1.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); + txq.add(tx2.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); + txq.add(tx3.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); + txq.add(tx4.clone(), &default_account_details, TransactionOrigin::Local).unwrap(); + assert_eq!(txq.status().pending, 4); + } + #[test] fn should_drop_transactions_with_old_nonces() { let mut txq = TransactionQueue::new(); diff --git a/parity/cli/config.full.toml b/parity/cli/config.full.toml index 5b47e1184..2363f1740 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -68,6 +68,7 @@ price_update_period = "hourly" gas_floor_target = "4700000" gas_cap = "6283184" tx_queue_size = 2048 +tx_queue_gas = "auto" tx_gas_limit = "6283184" extra_data = "Parity" remove_solved = false diff --git a/parity/cli/config.toml b/parity/cli/config.toml index a5ad55d40..4ab691679 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -41,6 +41,7 @@ reseal_on_txs = "all" reseal_min_period = 4000 price_update_period = "hourly" tx_queue_size = 2048 +tx_queue_gas = "auto" [footprint] tracing = "on" diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index 8044032eb..10348b21b 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -195,6 +195,8 @@ usage! { or |c: &Config| otry!(c.mining).extra_data.clone().map(Some), flag_tx_queue_size: usize = 2048usize, or |c: &Config| otry!(c.mining).tx_queue_size.clone(), + flag_tx_queue_gas: String = "auto", + or |c: &Config| otry!(c.mining).tx_queue_gas.clone(), flag_remove_solved: bool = false, or |c: &Config| otry!(c.mining).remove_solved.clone(), flag_notify_work: Option = None, @@ -348,6 +350,7 @@ struct Mining { gas_cap: Option, extra_data: Option, tx_queue_size: Option, + tx_queue_gas: Option, remove_solved: Option, notify_work: Option>, } @@ -523,6 +526,7 @@ mod tests { flag_gas_cap: "6283184".into(), flag_extra_data: Some("Parity".into()), flag_tx_queue_size: 2048usize, + flag_tx_queue_gas: "auto".into(), flag_remove_solved: false, flag_notify_work: Some("http://localhost:3001".into()), @@ -673,6 +677,7 @@ mod tests { gas_floor_target: None, gas_cap: None, tx_queue_size: Some(2048), + tx_queue_gas: Some("auto".into()), tx_gas_limit: None, extra_data: None, remove_solved: None, diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index 6ad0cec21..ca75c9ee0 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -184,6 +184,10 @@ Sealing/Mining Options: more than 32 characters. (default: {flag_extra_data:?}) --tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting to be included in next block) (default: {flag_tx_queue_size}). + --tx-queue-gas LIMIT Maximum amount of total gas for external transactions in + the queue. LIMIT can be either an amount of gas or + 'auto' or 'off'. 'auto' sets the limit to be 2x + the current block gas limit. (default: {flag_tx_queue_gas}). --remove-solved Move solved blocks from the work package queue instead of cloning them. This gives a slightly faster import speed, but means that extra solutions diff --git a/parity/configuration.rs b/parity/configuration.rs index 4503b0f2f..54a72fab5 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -30,7 +30,7 @@ use rpc::{IpcConfiguration, HttpConfiguration}; use ethcore_rpc::NetworkSettings; use cache::CacheConfig; use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, -geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address}; +geth_ipc_path, parity_ipc_path, to_bootnodes, to_addresses, to_address, to_gas_limit}; use params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType}; use ethcore_logger::Config as LogConfig; use dir::Directories; @@ -348,6 +348,7 @@ impl Configuration { None => U256::max_value(), }, tx_queue_size: self.args.flag_tx_queue_size, + tx_queue_gas_limit: try!(to_gas_limit(&self.args.flag_tx_queue_gas)), pending_set: try!(to_pending_set(&self.args.flag_relay_set)), reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period), work_queue_size: self.args.flag_work_queue_size, diff --git a/parity/helpers.rs b/parity/helpers.rs index cdee9ede0..6f4f90953 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -22,7 +22,7 @@ use std::fs::File; use util::{clean_0x, U256, Uint, Address, path, CompactionProfile}; use util::journaldb::Algorithm; use ethcore::client::{Mode, BlockID, VMType, DatabaseCompactionProfile, ClientConfig}; -use ethcore::miner::PendingSet; +use ethcore::miner::{PendingSet, GasLimit}; use cache::CacheConfig; use dir::DatabaseDirectories; use upgrade::upgrade; @@ -93,6 +93,14 @@ pub fn to_pending_set(s: &str) -> Result { } } +pub fn to_gas_limit(s: &str) -> Result { + match s { + "auto" => Ok(GasLimit::Auto), + "off" => Ok(GasLimit::None), + other => Ok(GasLimit::Fixed(try!(to_u256(other)))), + } +} + pub fn to_address(s: Option) -> Result { match s { Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)), diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 448fa4734..97e4d3bea 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -24,7 +24,7 @@ use ethcore::spec::{Genesis, Spec}; use ethcore::block::Block; use ethcore::views::BlockView; use ethcore::ethereum; -use ethcore::miner::{MinerOptions, GasPricer, MinerService, ExternalMiner, Miner, PendingSet}; +use ethcore::miner::{MinerOptions, GasPricer, MinerService, ExternalMiner, Miner, PendingSet, GasLimit}; use ethcore::account_provider::AccountProvider; use devtools::RandomTempPath; use util::Hashable; @@ -58,6 +58,7 @@ fn miner_service(spec: &Spec, accounts: Arc) -> Arc { reseal_on_own_tx: true, tx_queue_size: 1024, tx_gas_limit: !U256::zero(), + tx_queue_gas_limit: GasLimit::None, pending_set: PendingSet::SealingOrElseQueue, reseal_min_period: Duration::from_secs(0), work_queue_size: 50,