From 493c61f09d9a2e8b12579c8a27cdc9ef22766651 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 9 Mar 2016 15:22:06 +0100 Subject: [PATCH] Minimal gas price threshold. Closes: #636 --- miner/src/miner.rs | 32 ++++++++++++++++---------------- miner/src/transaction_queue.rs | 34 ++++++++++++++++++++++++++++++++++ parity/main.rs | 8 ++++++++ 3 files changed, 58 insertions(+), 16 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index f5ad32d2d..2c18f3a79 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -24,7 +24,7 @@ use ethcore::error::*; use ethcore::transaction::SignedTransaction; use transaction_queue::{TransactionQueue}; -/// Miner external API +/// Miner client API pub trait MinerService { /// Returns miner's status. @@ -34,12 +34,6 @@ pub trait MinerService { fn import_transactions(&self, transactions: Vec, fetch_nonce: T) where T: Fn(&Address) -> U256; - /// Set the author that we will seal blocks as. - fn set_author(&self, author: Address); - - /// Set the extra_data that we will seal blocks with. - fn set_extra_data(&self, extra_data: Bytes); - /// Removes all transactions from the queue and restart mining operation. fn clear_and_reset(&self, chain: &BlockChainClient); @@ -103,6 +97,21 @@ impl Miner { fn extra_data(&self) -> Bytes { self.extra_data.read().unwrap().clone() } + + /// Set the author that we will seal blocks as. + pub fn set_author(&self, author: Address) { + *self.author.write().unwrap() = author; + } + + /// Set the extra_data that we will seal blocks with. + pub fn set_extra_data(&self, extra_data: Bytes) { + *self.extra_data.write().unwrap() = extra_data; + } + + /// Set minimal gas price of transaction to be accepted for mining. + pub fn set_minimal_gas_price(&self, min_gas_price: U256) { + self.transaction_queue.lock().unwrap().set_minimal_gas_price(min_gas_price); + } } impl MinerService for Miner { @@ -126,15 +135,6 @@ impl MinerService for Miner { transaction_queue.add_all(transactions, fetch_nonce); } - fn set_author(&self, author: Address) { - *self.author.write().unwrap() = author; - } - - - fn set_extra_data(&self, extra_data: Bytes) { - *self.extra_data.write().unwrap() = extra_data; - } - fn prepare_sealing(&self, chain: &BlockChainClient) { let no_of_transactions = 128; let transactions = self.transaction_queue.lock().unwrap().top_transactions(no_of_transactions); diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 3e0d931b5..ed8cf801e 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -159,6 +159,8 @@ pub struct TransactionQueueStatus { /// TransactionQueue implementation pub struct TransactionQueue { + /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) + minimal_gas_price: U256, /// Priority queue for transactions that can go to block current: TransactionSet, /// Priority queue for transactions that has been received but are not yet valid to go to block @@ -189,6 +191,7 @@ impl TransactionQueue { }; TransactionQueue { + minimal_gas_price: U256::zero(), current: current, future: future, by_hash: HashMap::new(), @@ -196,6 +199,12 @@ impl TransactionQueue { } } + /// Sets new gas price threshold for incoming transactions. + /// Any transactions already imported to the queue are not affected. + pub fn set_minimal_gas_price(&mut self, min_gas_price: U256) { + self.minimal_gas_price = min_gas_price; + } + /// Returns current status for this queue pub fn status(&self) -> TransactionQueueStatus { TransactionQueueStatus { @@ -215,6 +224,15 @@ impl TransactionQueue { /// Add signed transaction to queue to be verified and imported pub fn add(&mut self, tx: SignedTransaction, fetch_nonce: &T) where T: Fn(&Address) -> U256 { + + if tx.gas_price < self.minimal_gas_price { + trace!(target: "sync", + "Dropping transaction below minimal gas price threshold: {:?} (gp: {} < {})", + tx.hash(), tx.gas_price, self.minimal_gas_price + ); + return; + } + // Everything ok - import transaction self.import_tx(VerifiedTransaction::new(tx), fetch_nonce); } @@ -503,6 +521,22 @@ mod test { assert_eq!(stats.pending, 1); } + #[test] + fn should_not_import_transaction_below_min_gas_price_threshold() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + txq.set_minimal_gas_price(tx.gas_price + U256::one()); + + // when + txq.add(tx, &default_nonce); + + // then + let stats = txq.status(); + assert_eq!(stats.pending, 0); + assert_eq!(stats.future, 0); + } + #[test] fn should_import_txs_from_same_sender() { // given diff --git a/parity/main.rs b/parity/main.rs index d75bdcb57..b3a0224d8 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -108,6 +108,7 @@ API and Console Options: --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: + --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 50000000000]. --author ADDRESS Specify the block author (aka "coinbase") address for sending block rewards from sealed blocks [default: 0037a6b811ffeb6e072da21179d11b1406371c63]. --extradata STRING Specify a custom extra-data for authored blocks, no more than 32 characters. @@ -161,6 +162,7 @@ struct Args { flag_rpcapi: Option, flag_logging: Option, flag_version: bool, + flag_gasprice: String, flag_author: String, flag_extra_data: Option, } @@ -248,6 +250,11 @@ impl Configuration { Address::from_str(&self.args.flag_author).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) } + fn gasprice(&self) -> U256 { + U256::from_dec_str(self.args.flag_gasprice).unwrap_or_else(|_| die("{}: Invalid gasprice given. Must be a + decimal unsigned 256-bit number.")) + } + fn extra_data(&self) -> Bytes { match self.args.flag_extra_data { Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), @@ -385,6 +392,7 @@ impl Configuration { let miner = Miner::new(); miner.set_author(self.author()); miner.set_extra_data(self.extra_data()); + miner.set_minimal_gas_price(self.gasprice()); // Sync let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone());