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,
}
/// 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,9 +461,11 @@ 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.
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.
fn prepare_work_sealing(&self, chain: &MiningBlockChainClient) -> bool {
@ -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,

View File

@ -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;

View File

@ -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();

View File

@ -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

View File

@ -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"

View File

@ -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<String> = None,
@ -348,6 +350,7 @@ struct Mining {
gas_cap: Option<String>,
extra_data: Option<String>,
tx_queue_size: Option<usize>,
tx_queue_gas: Option<String>,
remove_solved: Option<bool>,
notify_work: Option<Vec<String>>,
}
@ -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,

View File

@ -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

View File

@ -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,

View File

@ -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<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> {
match s {
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::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<AccountProvider>) -> Arc<Miner> {
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,