TX queue gas limit config and allow local transactions over the gas limit (#2553)

* Gas limit config; Allow local transactions over the limit

* Fix typo

[ci:skip]
This commit is contained in:
Arkadiy Paronyan 2016-10-10 23:04:43 +02:00 committed by Gav Wood
parent 64f6f836ab
commit 26d7712d30
10 changed files with 70 additions and 12 deletions

View File

@ -48,6 +48,17 @@ pub enum PendingSet {
SealingOrElseQueue, 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. /// Configures the behaviour of the miner.
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
pub struct MinerOptions { pub struct MinerOptions {
@ -71,6 +82,8 @@ pub struct MinerOptions {
pub work_queue_size: usize, pub work_queue_size: usize,
/// Can we submit two different solutions for the same block and expect both to result in an import? /// Can we submit two different solutions for the same block and expect both to result in an import?
pub enable_resubmission: bool, 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 { impl Default for MinerOptions {
@ -86,6 +99,7 @@ impl Default for MinerOptions {
reseal_min_period: Duration::from_secs(2), reseal_min_period: Duration::from_secs(2),
work_queue_size: 20, work_queue_size: 20,
enable_resubmission: true, enable_resubmission: true,
tx_queue_gas_limit: GasLimit::Auto,
} }
} }
} }
@ -194,7 +208,11 @@ impl Miner {
true => None, true => None,
false => Some(WorkPoster::new(&options.new_work_notify)) 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 { Miner {
transaction_queue: txq, transaction_queue: txq,
next_allowed_reseal: Mutex::new(Instant::now()), next_allowed_reseal: Mutex::new(Instant::now()),
@ -443,9 +461,11 @@ impl Miner {
let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit(); let gas_limit = HeaderView::new(&chain.best_block_header()).gas_limit();
let mut queue = self.transaction_queue.lock(); let mut queue = self.transaction_queue.lock();
queue.set_gas_limit(gas_limit); queue.set_gas_limit(gas_limit);
// Set total qx queue gas limit to be 2x the block gas limit. 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); queue.set_total_gas_limit(gas_limit << 1);
} }
}
/// Returns true if we had to prepare new pending block. /// Returns true if we had to prepare new pending block.
fn prepare_work_sealing(&self, chain: &MiningBlockChainClient) -> bool { fn prepare_work_sealing(&self, chain: &MiningBlockChainClient) -> bool {
@ -1062,6 +1082,7 @@ mod tests {
reseal_min_period: Duration::from_secs(5), reseal_min_period: Duration::from_secs(5),
tx_gas_limit: !U256::zero(), tx_gas_limit: !U256::zero(),
tx_queue_size: 1024, tx_queue_size: 1024,
tx_queue_gas_limit: GasLimit::None,
pending_set: PendingSet::AlwaysSealing, pending_set: PendingSet::AlwaysSealing,
work_queue_size: 5, work_queue_size: 5,
enable_resubmission: true, enable_resubmission: true,

View File

@ -48,7 +48,7 @@ mod work_notify;
mod price_info; mod price_info;
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin}; 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 self::external::{ExternalMiner, ExternalMinerService};
pub use client::TransactionImportResult; pub use client::TransactionImportResult;

View File

@ -331,7 +331,9 @@ impl TransactionSet {
let r = gas.overflowing_add(order.gas); let r = gas.overflowing_add(order.gas);
if r.1 { return false } if r.1 { return false }
gas = r.0; 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) .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`.")) .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] #[test]
fn should_limit_by_gas() { fn should_limit_by_gas() {
let mut txq = TransactionQueue::with_limits(100, default_gas_val() * U256::from(2), !U256::zero()); 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 (tx1, tx2) = new_tx_pair_default(U256::from(1), U256::from(1));
let (tx3, _) = new_tx_pair_default(U256::from(4), U256::from(2)); let (tx3, tx4) = new_tx_pair_default(U256::from(1), U256::from(2));
txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).unwrap(); txq.add(tx1.clone(), &default_account_details, TransactionOrigin::External).ok();
txq.add(tx3.clone(), &default_account_details, TransactionOrigin::External).unwrap(); 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); 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] #[test]
fn should_drop_transactions_with_old_nonces() { fn should_drop_transactions_with_old_nonces() {
let mut txq = TransactionQueue::new(); let mut txq = TransactionQueue::new();

View File

@ -68,6 +68,7 @@ price_update_period = "hourly"
gas_floor_target = "4700000" gas_floor_target = "4700000"
gas_cap = "6283184" gas_cap = "6283184"
tx_queue_size = 2048 tx_queue_size = 2048
tx_queue_gas = "auto"
tx_gas_limit = "6283184" tx_gas_limit = "6283184"
extra_data = "Parity" extra_data = "Parity"
remove_solved = false remove_solved = false

View File

@ -41,6 +41,7 @@ reseal_on_txs = "all"
reseal_min_period = 4000 reseal_min_period = 4000
price_update_period = "hourly" price_update_period = "hourly"
tx_queue_size = 2048 tx_queue_size = 2048
tx_queue_gas = "auto"
[footprint] [footprint]
tracing = "on" tracing = "on"

View File

@ -195,6 +195,8 @@ usage! {
or |c: &Config| otry!(c.mining).extra_data.clone().map(Some), or |c: &Config| otry!(c.mining).extra_data.clone().map(Some),
flag_tx_queue_size: usize = 2048usize, flag_tx_queue_size: usize = 2048usize,
or |c: &Config| otry!(c.mining).tx_queue_size.clone(), 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, flag_remove_solved: bool = false,
or |c: &Config| otry!(c.mining).remove_solved.clone(), or |c: &Config| otry!(c.mining).remove_solved.clone(),
flag_notify_work: Option<String> = None, flag_notify_work: Option<String> = None,
@ -348,6 +350,7 @@ struct Mining {
gas_cap: Option<String>, gas_cap: Option<String>,
extra_data: Option<String>, extra_data: Option<String>,
tx_queue_size: Option<usize>, tx_queue_size: Option<usize>,
tx_queue_gas: Option<String>,
remove_solved: Option<bool>, remove_solved: Option<bool>,
notify_work: Option<Vec<String>>, notify_work: Option<Vec<String>>,
} }
@ -523,6 +526,7 @@ mod tests {
flag_gas_cap: "6283184".into(), flag_gas_cap: "6283184".into(),
flag_extra_data: Some("Parity".into()), flag_extra_data: Some("Parity".into()),
flag_tx_queue_size: 2048usize, flag_tx_queue_size: 2048usize,
flag_tx_queue_gas: "auto".into(),
flag_remove_solved: false, flag_remove_solved: false,
flag_notify_work: Some("http://localhost:3001".into()), flag_notify_work: Some("http://localhost:3001".into()),
@ -673,6 +677,7 @@ mod tests {
gas_floor_target: None, gas_floor_target: None,
gas_cap: None, gas_cap: None,
tx_queue_size: Some(2048), tx_queue_size: Some(2048),
tx_queue_gas: Some("auto".into()),
tx_gas_limit: None, tx_gas_limit: None,
extra_data: None, extra_data: None,
remove_solved: None, remove_solved: None,

View File

@ -184,6 +184,10 @@ Sealing/Mining Options:
more than 32 characters. (default: {flag_extra_data:?}) more than 32 characters. (default: {flag_extra_data:?})
--tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting --tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
to be included in next block) (default: {flag_tx_queue_size}). 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 --remove-solved Move solved blocks from the work package queue
instead of cloning them. This gives a slightly instead of cloning them. This gives a slightly
faster import speed, but means that extra solutions faster import speed, but means that extra solutions

View File

@ -30,7 +30,7 @@ use rpc::{IpcConfiguration, HttpConfiguration};
use ethcore_rpc::NetworkSettings; use ethcore_rpc::NetworkSettings;
use cache::CacheConfig; use cache::CacheConfig;
use helpers::{to_duration, to_mode, to_block_id, to_u256, to_pending_set, to_price, replace_home, 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 params::{ResealPolicy, AccountsConfig, GasPricerConfig, MinerExtras, SpecType};
use ethcore_logger::Config as LogConfig; use ethcore_logger::Config as LogConfig;
use dir::Directories; use dir::Directories;
@ -348,6 +348,7 @@ impl Configuration {
None => U256::max_value(), None => U256::max_value(),
}, },
tx_queue_size: self.args.flag_tx_queue_size, 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)), pending_set: try!(to_pending_set(&self.args.flag_relay_set)),
reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period), reseal_min_period: Duration::from_millis(self.args.flag_reseal_min_period),
work_queue_size: self.args.flag_work_queue_size, work_queue_size: self.args.flag_work_queue_size,

View File

@ -22,7 +22,7 @@ use std::fs::File;
use util::{clean_0x, U256, Uint, Address, path, CompactionProfile}; use util::{clean_0x, U256, Uint, Address, path, CompactionProfile};
use util::journaldb::Algorithm; use util::journaldb::Algorithm;
use ethcore::client::{Mode, BlockID, VMType, DatabaseCompactionProfile, ClientConfig}; use ethcore::client::{Mode, BlockID, VMType, DatabaseCompactionProfile, ClientConfig};
use ethcore::miner::PendingSet; use ethcore::miner::{PendingSet, GasLimit};
use cache::CacheConfig; use cache::CacheConfig;
use dir::DatabaseDirectories; use dir::DatabaseDirectories;
use upgrade::upgrade; use upgrade::upgrade;
@ -93,6 +93,14 @@ pub fn to_pending_set(s: &str) -> Result<PendingSet, String> {
} }
} }
pub fn to_gas_limit(s: &str) -> Result<GasLimit, String> {
match s {
"auto" => Ok(GasLimit::Auto),
"off" => Ok(GasLimit::None),
other => Ok(GasLimit::Fixed(try!(to_u256(other)))),
}
}
pub fn to_address(s: Option<String>) -> Result<Address, String> { pub fn to_address(s: Option<String>) -> Result<Address, String> {
match s { match s {
Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)), Some(ref a) => clean_0x(a).parse().map_err(|_| format!("Invalid address: {:?}", a)),

View File

@ -24,7 +24,7 @@ use ethcore::spec::{Genesis, Spec};
use ethcore::block::Block; use ethcore::block::Block;
use ethcore::views::BlockView; use ethcore::views::BlockView;
use ethcore::ethereum; 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 ethcore::account_provider::AccountProvider;
use devtools::RandomTempPath; use devtools::RandomTempPath;
use util::Hashable; use util::Hashable;
@ -58,6 +58,7 @@ fn miner_service(spec: &Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
reseal_on_own_tx: true, reseal_on_own_tx: true,
tx_queue_size: 1024, tx_queue_size: 1024,
tx_gas_limit: !U256::zero(), tx_gas_limit: !U256::zero(),
tx_queue_gas_limit: GasLimit::None,
pending_set: PendingSet::SealingOrElseQueue, pending_set: PendingSet::SealingOrElseQueue,
reseal_min_period: Duration::from_secs(0), reseal_min_period: Duration::from_secs(0),
work_queue_size: 50, work_queue_size: 50,