Merge pull request #1460 from ethcore/miner-improvements

Allow configuration of when to reseal blocks.
This commit is contained in:
Arkadiy Paronyan 2016-06-28 13:11:24 +02:00 committed by GitHub
commit 39307b2bea
16 changed files with 244 additions and 67 deletions

View File

@ -158,7 +158,8 @@ impl<V> Client<V> where V: Verifier {
let mut state_db = journaldb::new( let mut state_db = journaldb::new(
&append_path(&path, "state"), &append_path(&path, "state"),
config.pruning, config.pruning,
state_db_config); state_db_config
);
if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) { if state_db.is_empty() && spec.ensure_db_good(state_db.as_hashdb_mut()) {
state_db.commit(0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB"); state_db.commit(0, &spec.genesis_header().hash(), None).expect("Error commiting genesis state to state DB");
@ -800,8 +801,8 @@ impl<V> BlockChainClient for Client<V> where V: Verifier {
} }
} }
fn all_transactions(&self) -> Vec<SignedTransaction> { fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.all_transactions() self.miner.pending_transactions()
} }
} }

View File

@ -197,7 +197,7 @@ pub trait BlockChainClient : Sync + Send {
fn queue_transactions(&self, transactions: Vec<Bytes>); fn queue_transactions(&self, transactions: Vec<Bytes>);
/// list all transactions /// list all transactions
fn all_transactions(&self) -> Vec<SignedTransaction>; fn pending_transactions(&self) -> Vec<SignedTransaction>;
/// Get the gas price distribution. /// Get the gas price distribution.
fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result<Vec<U256>, ()> { fn gas_price_statistics(&self, sample_size: usize, distribution_size: usize) -> Result<Vec<U256>, ()> {

View File

@ -500,7 +500,7 @@ impl BlockChainClient for TestBlockChainClient {
self.import_transactions(tx); self.import_transactions(tx);
} }
fn all_transactions(&self) -> Vec<SignedTransaction> { fn pending_transactions(&self) -> Vec<SignedTransaction> {
self.miner.all_transactions() self.miner.pending_transactions()
} }
} }

View File

@ -29,6 +29,48 @@ use spec::Spec;
use engine::Engine; use engine::Engine;
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
/// Different possible definitions for pending transaction set.
#[derive(Debug)]
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
/// may be empty if the node is not actively mining or has force_sealing enabled.
AlwaysSealing,
/// Try the sealing block, but if it is not currently sealing, fallback to the queue.
SealingOrElseQueue,
}
/// Configures the behaviour of the miner.
#[derive(Debug)]
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,
/// 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,
}
impl Default for MinerOptions {
fn default() -> Self {
MinerOptions {
force_sealing: false,
reseal_on_external_tx: true,
reseal_on_own_tx: true,
tx_gas_limit: !U256::zero(),
tx_queue_size: 1024,
pending_set: PendingSet::AlwaysQueue,
}
}
}
/// Keeps track of transactions using priority queue and holds currently mined block. /// Keeps track of transactions using priority queue and holds currently mined block.
pub struct Miner { pub struct Miner {
// NOTE [ToDr] When locking always lock in this order! // NOTE [ToDr] When locking always lock in this order!
@ -36,7 +78,7 @@ pub struct Miner {
sealing_work: Mutex<UsingQueue<ClosedBlock>>, sealing_work: Mutex<UsingQueue<ClosedBlock>>,
// for sealing... // for sealing...
force_sealing: bool, options: MinerOptions,
sealing_enabled: AtomicBool, sealing_enabled: AtomicBool,
sealing_block_last_request: Mutex<u64>, sealing_block_last_request: Mutex<u64>,
gas_range_target: RwLock<(U256, U256)>, gas_range_target: RwLock<(U256, U256)>,
@ -52,7 +94,7 @@ impl Miner {
pub fn with_spec(spec: Spec) -> Miner { pub fn with_spec(spec: Spec) -> Miner {
Miner { Miner {
transaction_queue: Mutex::new(TransactionQueue::new()), transaction_queue: Mutex::new(TransactionQueue::new()),
force_sealing: false, options: Default::default(),
sealing_enabled: AtomicBool::new(false), sealing_enabled: AtomicBool::new(false),
sealing_block_last_request: Mutex::new(0), sealing_block_last_request: Mutex::new(0),
sealing_work: Mutex::new(UsingQueue::new(5)), sealing_work: Mutex::new(UsingQueue::new(5)),
@ -65,11 +107,11 @@ impl Miner {
} }
/// Creates new instance of miner /// Creates new instance of miner
pub fn new(force_sealing: bool, spec: Spec, accounts: Option<Arc<AccountProvider>>) -> Arc<Miner> { pub fn new(options: MinerOptions, spec: Spec, accounts: Option<Arc<AccountProvider>>) -> Arc<Miner> {
Arc::new(Miner { Arc::new(Miner {
transaction_queue: Mutex::new(TransactionQueue::new()), transaction_queue: Mutex::new(TransactionQueue::with_limits(options.tx_queue_size, options.tx_gas_limit)),
force_sealing: force_sealing, sealing_enabled: AtomicBool::new(options.force_sealing),
sealing_enabled: AtomicBool::new(force_sealing), options: options,
sealing_block_last_request: Mutex::new(0), sealing_block_last_request: Mutex::new(0),
sealing_work: Mutex::new(UsingQueue::new(5)), sealing_work: Mutex::new(UsingQueue::new(5)),
gas_range_target: RwLock::new((U256::zero(), U256::zero())), gas_range_target: RwLock::new((U256::zero(), U256::zero())),
@ -356,6 +398,10 @@ impl MinerService for Miner {
self.transaction_queue.lock().unwrap().set_limit(limit) self.transaction_queue.lock().unwrap().set_limit(limit)
} }
fn set_tx_gas_limit(&self, limit: U256) {
self.transaction_queue.lock().unwrap().set_tx_gas_limit(limit)
}
/// Get the author that we will seal blocks as. /// Get the author that we will seal blocks as.
fn author(&self) -> Address { fn author(&self) -> Address {
*self.author.read().unwrap() *self.author.read().unwrap()
@ -385,7 +431,7 @@ impl MinerService for Miner {
.map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External)) .map(|tx| transaction_queue.add(tx, &fetch_account, TransactionOrigin::External))
.collect() .collect()
}; };
if !results.is_empty() { if !results.is_empty() && self.options.reseal_on_external_tx {
self.update_sealing(chain); self.update_sealing(chain);
} }
results results
@ -420,7 +466,7 @@ impl MinerService for Miner {
import import
}; };
if imported.is_ok() { if imported.is_ok() && self.options.reseal_on_own_tx {
// Make sure to do it after transaction is imported and lock is droped. // Make sure to do it after transaction is imported and lock is droped.
// We need to create pending block and enable sealing // We need to create pending block and enable sealing
let prepared = self.enable_and_prepare_sealing(chain); let prepared = self.enable_and_prepare_sealing(chain);
@ -434,26 +480,6 @@ impl MinerService for Miner {
imported imported
} }
fn pending_transactions_hashes(&self) -> Vec<H256> {
let queue = self.transaction_queue.lock().unwrap();
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
(true, Some(pending)) => pending.transactions().iter().map(|t| t.hash()).collect(),
_ => {
queue.pending_hashes()
}
}
}
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap();
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) {
(true, Some(pending)) => pending.transactions().iter().find(|t| &t.hash() == hash).cloned(),
_ => {
queue.find(hash)
}
}
}
fn all_transactions(&self) -> Vec<SignedTransaction> { fn all_transactions(&self) -> Vec<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap(); let queue = self.transaction_queue.lock().unwrap();
queue.top_transactions() queue.top_transactions()
@ -461,13 +487,42 @@ impl MinerService for Miner {
fn pending_transactions(&self) -> Vec<SignedTransaction> { fn pending_transactions(&self) -> Vec<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap(); let queue = self.transaction_queue.lock().unwrap();
let sw = self.sealing_work.lock().unwrap();
// TODO: should only use the sealing_work when it's current (it could be an old block) // TODO: should only use the sealing_work when it's current (it could be an old block)
match (self.sealing_enabled.load(atomic::Ordering::Relaxed), self.sealing_work.lock().unwrap().peek_last_ref()) { let sealing_set = match self.sealing_enabled.load(atomic::Ordering::Relaxed) {
(true, Some(pending)) => pending.transactions().clone(), true => sw.peek_last_ref(),
_ => { false => None,
queue.top_transactions() };
match (&self.options.pending_set, sealing_set) {
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.top_transactions(),
(_, sealing) => sealing.map_or_else(Vec::new, |s| s.transactions().clone()),
} }
} }
fn pending_transactions_hashes(&self) -> Vec<H256> {
let queue = self.transaction_queue.lock().unwrap();
let sw = self.sealing_work.lock().unwrap();
let sealing_set = match self.sealing_enabled.load(atomic::Ordering::Relaxed) {
true => sw.peek_last_ref(),
false => None,
};
match (&self.options.pending_set, sealing_set) {
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.pending_hashes(),
(_, sealing) => sealing.map_or_else(Vec::new, |s| s.transactions().iter().map(|t| t.hash()).collect()),
}
}
fn transaction(&self, hash: &H256) -> Option<SignedTransaction> {
let queue = self.transaction_queue.lock().unwrap();
let sw = self.sealing_work.lock().unwrap();
let sealing_set = match self.sealing_enabled.load(atomic::Ordering::Relaxed) {
true => sw.peek_last_ref(),
false => None,
};
match (&self.options.pending_set, sealing_set) {
(&PendingSet::AlwaysQueue, _) | (&PendingSet::SealingOrElseQueue, None) => queue.find(hash),
(_, sealing) => sealing.and_then(|s| s.transactions().iter().find(|t| &t.hash() == hash).cloned()),
}
} }
fn pending_receipts(&self) -> BTreeMap<H256, Receipt> { fn pending_receipts(&self) -> BTreeMap<H256, Receipt> {
@ -494,7 +549,7 @@ impl MinerService for Miner {
let current_no = chain.chain_info().best_block_number; let current_no = chain.chain_info().best_block_number;
let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions(); let has_local_transactions = self.transaction_queue.lock().unwrap().has_local_pending_transactions();
let last_request = *self.sealing_block_last_request.lock().unwrap(); let last_request = *self.sealing_block_last_request.lock().unwrap();
let should_disable_sealing = !self.force_sealing let should_disable_sealing = !self.options.force_sealing
&& !has_local_transactions && !has_local_transactions
&& current_no > last_request && current_no > last_request
&& current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS; && current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS;

View File

@ -47,7 +47,7 @@ mod external;
mod transaction_queue; mod transaction_queue;
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin}; pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
pub use self::miner::{Miner}; pub use self::miner::{Miner, MinerOptions, PendingSet};
pub use self::external::{ExternalMiner, ExternalMinerService}; pub use self::external::{ExternalMiner, ExternalMinerService};
use std::collections::BTreeMap; use std::collections::BTreeMap;
@ -101,6 +101,9 @@ pub trait MinerService : Send + Sync {
/// Set maximal number of transactions kept in the queue (both current and future). /// Set maximal number of transactions kept in the queue (both current and future).
fn set_transactions_limit(&self, limit: usize); fn set_transactions_limit(&self, limit: usize);
/// Set maximum amount of gas allowed for any single transaction to mine.
fn set_tx_gas_limit(&self, limit: U256);
/// Imports transactions to transaction queue. /// Imports transactions to transaction queue.
fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) -> fn import_transactions<T>(&self, chain: &MiningBlockChainClient, transactions: Vec<SignedTransaction>, fetch_account: T) ->
Vec<Result<TransactionImportResult, Error>> Vec<Result<TransactionImportResult, Error>>

View File

@ -334,6 +334,8 @@ const GAS_LIMIT_HYSTERESIS: usize = 10; // %
pub struct TransactionQueue { pub struct TransactionQueue {
/// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0)
minimal_gas_price: U256, minimal_gas_price: U256,
/// The maximum amount of gas any individual transaction may use.
tx_gas_limit: U256,
/// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0) /// Current gas limit (block gas limit * factor). Transactions above the limit will not be accepted (default to !0)
gas_limit: U256, gas_limit: U256,
/// Priority queue for transactions that can go to block /// Priority queue for transactions that can go to block
@ -355,11 +357,11 @@ impl Default for TransactionQueue {
impl TransactionQueue { impl TransactionQueue {
/// Creates new instance of this Queue /// Creates new instance of this Queue
pub fn new() -> Self { pub fn new() -> Self {
Self::with_limit(1024) Self::with_limits(1024, !U256::zero())
} }
/// Create new instance of this Queue with specified limits /// Create new instance of this Queue with specified limits
pub fn with_limit(limit: usize) -> Self { pub fn with_limits(limit: usize, tx_gas_limit: U256) -> Self {
let current = TransactionSet { let current = TransactionSet {
by_priority: BTreeSet::new(), by_priority: BTreeSet::new(),
by_address: Table::new(), by_address: Table::new(),
@ -374,6 +376,7 @@ impl TransactionQueue {
TransactionQueue { TransactionQueue {
minimal_gas_price: U256::zero(), minimal_gas_price: U256::zero(),
tx_gas_limit: tx_gas_limit,
gas_limit: !U256::zero(), gas_limit: !U256::zero(),
current: current, current: current,
future: future, future: future,
@ -418,6 +421,12 @@ impl TransactionQueue {
}; };
} }
/// Set the new limit for the amount of gas any individual transaction may have.
/// Any transaction already imported to the queue is not affected.
pub fn set_tx_gas_limit(&mut self, limit: U256) {
self.tx_gas_limit = limit;
}
/// Returns current status for this queue /// Returns current status for this queue
pub fn status(&self) -> TransactionQueueStatus { pub fn status(&self) -> TransactionQueueStatus {
TransactionQueueStatus { TransactionQueueStatus {
@ -435,7 +444,9 @@ impl TransactionQueue {
if tx.gas_price < self.minimal_gas_price { if tx.gas_price < self.minimal_gas_price {
trace!(target: "miner", trace!(target: "miner",
"Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})",
tx.hash(), tx.gas_price, self.minimal_gas_price tx.hash(),
tx.gas_price,
self.minimal_gas_price
); );
return Err(Error::Transaction(TransactionError::InsufficientGasPrice { return Err(Error::Transaction(TransactionError::InsufficientGasPrice {
@ -446,10 +457,13 @@ impl TransactionQueue {
try!(tx.check_low_s()); try!(tx.check_low_s());
if tx.gas > self.gas_limit { if tx.gas > self.gas_limit || tx.gas > self.tx_gas_limit {
trace!(target: "miner", trace!(target: "miner",
"Dropping transaction above gas limit: {:?} ({} > {})", "Dropping transaction above gas limit: {:?} ({} > min({}, {}))",
tx.hash(), tx.gas, self.gas_limit tx.hash(),
tx.gas,
self.gas_limit,
self.tx_gas_limit
); );
return Err(Error::Transaction(TransactionError::GasLimitExceeded { return Err(Error::Transaction(TransactionError::GasLimitExceeded {
@ -463,8 +477,13 @@ impl TransactionQueue {
let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas; let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas;
if client_account.balance < cost { if client_account.balance < cost {
trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})", trace!(target: "miner",
vtx.hash(), client_account.balance, cost); "Dropping transaction without sufficient balance: {:?} ({} < {})",
vtx.hash(),
client_account.balance,
cost
);
return Err(Error::Transaction(TransactionError::InsufficientBalance { return Err(Error::Transaction(TransactionError::InsufficientBalance {
cost: cost, cost: cost,
balance: client_account.balance balance: client_account.balance
@ -1288,7 +1307,7 @@ mod test {
#[test] #[test]
fn should_drop_old_transactions_when_hitting_the_limit() { fn should_drop_old_transactions_when_hitting_the_limit() {
// given // given
let mut txq = TransactionQueue::with_limit(1); let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let (tx, tx2) = new_txs(U256::one()); let (tx, tx2) = new_txs(U256::one());
let sender = tx.sender().unwrap(); let sender = tx.sender().unwrap();
let nonce = tx.nonce; let nonce = tx.nonce;
@ -1310,7 +1329,7 @@ mod test {
#[test] #[test]
fn should_return_correct_nonces_when_dropped_because_of_limit() { fn should_return_correct_nonces_when_dropped_because_of_limit() {
// given // given
let mut txq = TransactionQueue::with_limit(2); let mut txq = TransactionQueue::with_limits(2, !U256::zero());
let tx = new_tx(); let tx = new_tx();
let (tx1, tx2) = new_txs(U256::one()); let (tx1, tx2) = new_txs(U256::one());
let sender = tx1.sender().unwrap(); let sender = tx1.sender().unwrap();
@ -1331,7 +1350,7 @@ mod test {
#[test] #[test]
fn should_limit_future_transactions() { fn should_limit_future_transactions() {
let mut txq = TransactionQueue::with_limit(1); let mut txq = TransactionQueue::with_limits(1, !U256::zero());
txq.current.set_limit(10); txq.current.set_limit(10);
let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(4), U256::from(1)); let (tx1, tx2) = new_txs_with_gas_price_diff(U256::from(4), U256::from(1));
let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(4), U256::from(2)); let (tx3, tx4) = new_txs_with_gas_price_diff(U256::from(4), U256::from(2));
@ -1591,7 +1610,7 @@ mod test {
#[test] #[test]
fn should_keep_right_order_in_future() { fn should_keep_right_order_in_future() {
// given // given
let mut txq = TransactionQueue::with_limit(1); let mut txq = TransactionQueue::with_limits(1, !U256::zero());
let (tx1, tx2) = new_txs(U256::from(1)); let (tx1, tx2) = new_txs(U256::from(1));
let prev_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce - U256::one(), balance: let prev_nonce = |a: &Address| AccountDetails { nonce: default_nonce(a).nonce - U256::one(), balance:
default_nonce(a).balance }; default_nonce(a).balance };

View File

@ -133,6 +133,22 @@ Sealing/Mining Options:
NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION. NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION.
--force-sealing Force the node to author new blocks as if it were --force-sealing Force the node to author new blocks as if it were
always sealing/mining. always sealing/mining.
--reseal-on-txs SET Specify which transactions should force the node
to reseal a block. SET is one of:
none - never reseal on new transactions;
own - reseal only on a new local transaction;
ext - reseal only on a new external transaction;
all - reseal on all new transactions [default: all].
--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:
cheap - Relay any transaction in the queue (this
may include invalid transactions);
strict - Relay only executed transactions (this
guarantees we don't relay invalid transactions, but
means we relay nothing if not mining);
lenient - Same as strict when mining, and cheap
when not [default: cheap].
--usd-per-tx USD Amount of USD to be paid for a basic transaction --usd-per-tx USD Amount of USD to be paid for a basic transaction
[default: 0.005]. The minimum gas price is set [default: 0.005]. The minimum gas price is set
accordingly. accordingly.
@ -146,8 +162,8 @@ Sealing/Mining Options:
block due to transaction volume [default: 3141592]. block due to transaction volume [default: 3141592].
--extra-data STRING Specify a custom extra-data for authored blocks, no --extra-data STRING Specify a custom extra-data for authored blocks, no
more than 32 characters. more than 32 characters.
--tx-limit LIMIT Limit of transactions kept in the queue (waiting to --tx-queue-size LIMIT Maximum amount of transactions in the queue (waiting
be included in next block) [default: 1024]. to be included in next block) [default: 1024].
Footprint Options: Footprint Options:
--tracing BOOL Indicates if full transaction tracing should be --tracing BOOL Indicates if full transaction tracing should be
@ -288,13 +304,16 @@ pub struct Args {
pub flag_signer_path: String, pub flag_signer_path: String,
pub flag_no_token: bool, pub flag_no_token: bool,
pub flag_force_sealing: bool, pub flag_force_sealing: bool,
pub flag_reseal_on_txs: String,
pub flag_tx_gas_limit: Option<String>,
pub flag_relay_set: String,
pub flag_author: Option<String>, pub flag_author: Option<String>,
pub flag_usd_per_tx: String, pub flag_usd_per_tx: String,
pub flag_usd_per_eth: String, pub flag_usd_per_eth: String,
pub flag_gas_floor_target: String, pub flag_gas_floor_target: String,
pub flag_gas_cap: String, pub flag_gas_cap: String,
pub flag_extra_data: Option<String>, pub flag_extra_data: Option<String>,
pub flag_tx_limit: usize, pub flag_tx_queue_size: usize,
pub flag_logging: Option<String>, pub flag_logging: Option<String>,
pub flag_version: bool, pub flag_version: bool,
pub flag_from: String, pub flag_from: String,

View File

@ -27,6 +27,7 @@ use util::*;
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use util::network_settings::NetworkSettings; use util::network_settings::NetworkSettings;
use ethcore::client::{append_path, get_db_path, ClientConfig, DatabaseCompactionProfile, Switch, VMType}; use ethcore::client::{append_path, get_db_path, ClientConfig, DatabaseCompactionProfile, Switch, VMType};
use ethcore::miner::{MinerOptions, PendingSet};
use ethcore::ethereum; use ethcore::ethereum;
use ethcore::spec::Spec; use ethcore::spec::Spec;
use ethsync::SyncConfig; use ethsync::SyncConfig;
@ -67,6 +68,37 @@ impl Configuration {
self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32 self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32
} }
fn decode_u256(d: &str, argument: &str) -> U256 {
U256::from_dec_str(d).unwrap_or_else(|_|
U256::from_str(clean_0x(d)).unwrap_or_else(|_|
die!("{}: Invalid numeric value for {}. Must be either a decimal or a hex number.", d, argument)
)
)
}
pub fn miner_options(&self) -> MinerOptions {
let (own, ext) = match self.args.flag_reseal_on_txs.as_str() {
"none" => (false, false),
"own" => (true, false),
"ext" => (false, true),
"all" => (true, true),
x => die!("{}: Invalid value for --reseal option. Use --help for more information.", x)
};
MinerOptions {
force_sealing: self.args.flag_force_sealing,
reseal_on_external_tx: ext,
reseal_on_own_tx: own,
tx_gas_limit: self.args.flag_tx_gas_limit.as_ref().map_or(!U256::zero(), |d| Self::decode_u256(d, "--tx-gas-limit")),
tx_queue_size: self.args.flag_tx_queue_size,
pending_set: match self.args.flag_relay_set.as_str() {
"cheap" => PendingSet::AlwaysQueue,
"strict" => PendingSet::AlwaysSealing,
"lenient" => PendingSet::SealingOrElseQueue,
x => die!("{}: Invalid value for --relay-set option. Use --help for more information.", x)
},
}
}
pub fn author(&self) -> Option<Address> { pub fn author(&self) -> Option<Address> {
self.args.flag_etherbase.as_ref() self.args.flag_etherbase.as_ref()
.or(self.args.flag_author.as_ref()) .or(self.args.flag_author.as_ref())

View File

@ -208,13 +208,13 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig)
let account_service = Arc::new(conf.account_service()); let account_service = Arc::new(conf.account_service());
// Miner // Miner
let miner = Miner::new(conf.args.flag_force_sealing, conf.spec(), Some(account_service.clone())); let miner = Miner::new(conf.miner_options(), conf.spec(), Some(account_service.clone()));
miner.set_author(conf.author().unwrap_or_default()); miner.set_author(conf.author().unwrap_or_default());
miner.set_gas_floor_target(conf.gas_floor_target()); miner.set_gas_floor_target(conf.gas_floor_target());
miner.set_gas_ceil_target(conf.gas_ceil_target()); miner.set_gas_ceil_target(conf.gas_ceil_target());
miner.set_extra_data(conf.extra_data()); miner.set_extra_data(conf.extra_data());
miner.set_minimal_gas_price(conf.gas_price()); miner.set_minimal_gas_price(conf.gas_price());
miner.set_transactions_limit(conf.args.flag_tx_limit); miner.set_transactions_limit(conf.args.flag_tx_queue_size);
// Build client // Build client
let mut service = ClientService::start( let mut service = ClientService::start(

View File

@ -22,7 +22,7 @@ use jsonrpc_core::*;
use ethcore::miner::MinerService; use ethcore::miner::MinerService;
use ethcore::service::SyncMessage; use ethcore::service::SyncMessage;
use v1::traits::EthcoreSet; use v1::traits::EthcoreSet;
use v1::types::{Bytes}; use v1::types::Bytes;
/// Ethcore-specific rpc interface for operations altering the settings. /// Ethcore-specific rpc interface for operations altering the settings.
pub struct EthcoreSetClient<M> where pub struct EthcoreSetClient<M> where
@ -86,6 +86,13 @@ impl<M> EthcoreSet for EthcoreSetClient<M> where M: MinerService + 'static {
}) })
} }
fn set_tx_gas_limit(&self, params: Params) -> Result<Value, Error> {
from_params::<(U256,)>(params).and_then(|(limit,)| {
take_weak!(self.miner).set_tx_gas_limit(limit.into());
to_value(&true)
})
}
fn add_reserved_peer(&self, params: Params) -> Result<Value, Error> { fn add_reserved_peer(&self, params: Params) -> Result<Value, Error> {
from_params::<(String,)>(params).and_then(|(peer,)| { from_params::<(String,)>(params).and_then(|(peer,)| {
match take_weak!(self.net).add_reserved_peer(&peer) { match take_weak!(self.net).add_reserved_peer(&peer) {

View File

@ -24,12 +24,12 @@ 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::{MinerService, ExternalMiner, Miner}; use ethcore::miner::{MinerOptions, MinerService, ExternalMiner, Miner, PendingSet};
use ethcore::account_provider::AccountProvider; use ethcore::account_provider::AccountProvider;
use devtools::RandomTempPath; use devtools::RandomTempPath;
use util::Hashable; use util::Hashable;
use util::io::IoChannel; use util::io::IoChannel;
use util::{U256, H256}; use util::{U256, H256, Uint};
use jsonrpc_core::IoHandler; use jsonrpc_core::IoHandler;
use ethjson::blockchain::BlockChain; use ethjson::blockchain::BlockChain;
@ -49,7 +49,18 @@ fn sync_provider() -> Arc<TestSyncProvider> {
} }
fn miner_service(spec: Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> { fn miner_service(spec: Spec, accounts: Arc<AccountProvider>) -> Arc<Miner> {
Miner::new(true, spec, Some(accounts)) Miner::new(
MinerOptions {
force_sealing: true,
reseal_on_external_tx: true,
reseal_on_own_tx: true,
tx_queue_size: 1024,
tx_gas_limit: !U256::zero(),
pending_set: PendingSet::SealingOrElseQueue,
},
spec,
Some(accounts)
)
} }
fn make_spec(chain: &BlockChain) -> Spec { fn make_spec(chain: &BlockChain) -> Spec {

View File

@ -43,6 +43,7 @@ pub struct TestMinerService {
author: RwLock<Address>, author: RwLock<Address>,
extra_data: RwLock<Bytes>, extra_data: RwLock<Bytes>,
limit: RwLock<usize>, limit: RwLock<usize>,
tx_gas_limit: RwLock<U256>,
} }
impl Default for TestMinerService { impl Default for TestMinerService {
@ -58,6 +59,7 @@ impl Default for TestMinerService {
author: RwLock::new(Address::zero()), author: RwLock::new(Address::zero()),
extra_data: RwLock::new(vec![1, 2, 3, 4]), extra_data: RwLock::new(vec![1, 2, 3, 4]),
limit: RwLock::new(1024), limit: RwLock::new(1024),
tx_gas_limit: RwLock::new(!U256::zero()),
} }
} }
} }
@ -99,6 +101,10 @@ impl MinerService for TestMinerService {
*self.limit.write().unwrap() = limit; *self.limit.write().unwrap() = limit;
} }
fn set_tx_gas_limit(&self, limit: U256) {
*self.tx_gas_limit.write().unwrap() = limit;
}
fn transactions_limit(&self) -> usize { fn transactions_limit(&self) -> usize {
*self.limit.read().unwrap() *self.limit.read().unwrap()
} }

View File

@ -40,6 +40,9 @@ pub trait EthcoreSet: Sized + Send + Sync + 'static {
/// Sets the limits for transaction queue. /// Sets the limits for transaction queue.
fn set_transactions_limit(&self, _: Params) -> Result<Value, Error>; fn set_transactions_limit(&self, _: Params) -> Result<Value, Error>;
/// Sets the maximum amount of gas a single transaction may consume.
fn set_tx_gas_limit(&self, _: Params) -> Result<Value, Error>;
/// Add a reserved peer. /// Add a reserved peer.
fn add_reserved_peer(&self, _: Params) -> Result<Value, Error>; fn add_reserved_peer(&self, _: Params) -> Result<Value, Error>;
@ -60,6 +63,7 @@ pub trait EthcoreSet: Sized + Send + Sync + 'static {
delegate.add_method("ethcore_setGasCeilTarget", EthcoreSet::set_gas_ceil_target); delegate.add_method("ethcore_setGasCeilTarget", EthcoreSet::set_gas_ceil_target);
delegate.add_method("ethcore_setExtraData", EthcoreSet::set_extra_data); delegate.add_method("ethcore_setExtraData", EthcoreSet::set_extra_data);
delegate.add_method("ethcore_setAuthor", EthcoreSet::set_author); delegate.add_method("ethcore_setAuthor", EthcoreSet::set_author);
delegate.add_method("ethcore_setMaxTransactionGas", EthcoreSet::set_tx_gas_limit);
delegate.add_method("ethcore_setTransactionsLimit", EthcoreSet::set_transactions_limit); delegate.add_method("ethcore_setTransactionsLimit", EthcoreSet::set_transactions_limit);
delegate.add_method("ethcore_addReservedPeer", EthcoreSet::add_reserved_peer); delegate.add_method("ethcore_addReservedPeer", EthcoreSet::add_reserved_peer);
delegate.add_method("ethcore_removeReservedPeer", EthcoreSet::remove_reserved_peer); delegate.add_method("ethcore_removeReservedPeer", EthcoreSet::remove_reserved_peer);

View File

@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License // You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>. // along with Parity. If not, see <http://www.gnu.org/licenses/>.
use serde::{Serialize, Serializer}; use serde::{Serialize, Serializer, Deserialize, Deserializer};
use serde_json::Value; use serde_json::Value;
/// Optional value /// Optional value
@ -26,13 +26,22 @@ pub enum OptionalValue<T> where T: Serialize {
Null Null
} }
impl<T> Default for OptionalValue<T> where T: Serialize { impl<T> Default for OptionalValue<T> where T: Serialize + Deserialize {
fn default() -> Self { fn default() -> Self {
OptionalValue::Null OptionalValue::Null
} }
} }
impl<T> Serialize for OptionalValue<T> where T: Serialize { impl<T> Into<Option<T>> for OptionalValue<T> where T: Serialize + Deserialize {
fn into(self) -> Option<T> {
match self {
OptionalValue::Null => None,
OptionalValue::Value(t) => Some(t),
}
}
}
impl<T> Serialize for OptionalValue<T> where T: Serialize + Deserialize {
fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error> fn serialize<S>(&self, serializer: &mut S) -> Result<(), S::Error>
where S: Serializer { where S: Serializer {
match *self { match *self {
@ -42,6 +51,17 @@ impl<T> Serialize for OptionalValue<T> where T: Serialize {
} }
} }
impl<T> Deserialize for OptionalValue<T> where T: Serialize + Deserialize {
fn deserialize<D>(deserializer: &mut D) -> Result<OptionalValue<T>, D::Error>
where D: Deserializer {
let deser_result: Result<T, D::Error> = Deserialize::deserialize(deserializer);
match deser_result {
Ok(t) => Ok(OptionalValue::Value(t)),
Err(_) => Ok(OptionalValue::Null),
}
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use serde_json; use serde_json;

View File

@ -1314,7 +1314,7 @@ impl ChainSync {
return 0; return 0;
} }
let mut transactions = io.chain().all_transactions(); let mut transactions = io.chain().pending_transactions();
if transactions.is_empty() { if transactions.is_empty() {
return 0; return 0;
} }

View File

@ -44,7 +44,7 @@
//! let mut service = NetworkService::new(NetworkConfiguration::new()).unwrap(); //! let mut service = NetworkService::new(NetworkConfiguration::new()).unwrap();
//! service.start().unwrap(); //! service.start().unwrap();
//! let dir = env::temp_dir(); //! let dir = env::temp_dir();
//! let miner = Miner::new(false, ethereum::new_frontier(true), None); //! let miner = Miner::new(Default::default(), ethereum::new_frontier(true), None);
//! let client = Client::new( //! let client = Client::new(
//! ClientConfig::default(), //! ClientConfig::default(),
//! ethereum::new_frontier(true), //! ethereum::new_frontier(true),