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 1/4] 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()); From ca2cf8e591404245fed40cc1f8d81f8a6e67087e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 10:05:51 +0100 Subject: [PATCH 2/4] Lowering minimal gas price --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index b3a0224d8..4cf52728e 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -108,7 +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]. + --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. --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. From 02b7e7698ad07fccb61aa5f51b31e47ad599c851 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 10 Mar 2016 10:09:55 +0100 Subject: [PATCH 3/4] Breaking couple of lines to keep number of characters below limit --- parity/main.rs | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 4cf52728e..729f6aeed 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -247,12 +247,15 @@ impl Configuration { } fn author(&self) -> Address { - 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)) + 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.")) + 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 { @@ -275,7 +278,9 @@ impl Configuration { "frontier" | "homestead" | "mainnet" => ethereum::new_frontier(), "morden" | "testnet" => ethereum::new_morden(), "olympic" => ethereum::new_olympic(), - f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| die!("{}: Couldn't read chain specification file. Sure it exists?", f)).as_ref()), + f => Spec::from_json_utf8(contents(f).unwrap_or_else(|_| { + die!("{}: Couldn't read chain specification file. Sure it exists?", f) + }).as_ref()), } } @@ -291,7 +296,9 @@ impl Configuration { if self.args.flag_no_bootstrap { Vec::new() } else { match self.args.arg_enode.len() { 0 => spec.nodes().clone(), - _ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s))).collect(), + _ => self.args.arg_enode.iter().map(|s| Self::normalize_enode(s).unwrap_or_else(|| { + die!("{}: Invalid node address format given for a boot node.", s) + })).collect(), } } } @@ -302,17 +309,23 @@ impl Configuration { let mut public_address = None; if let Some(ref a) = self.args.flag_address { - public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --address", a))); + public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| { + die!("{}: Invalid listen/public address given with --address", a) + })); listen_address = public_address; } if listen_address.is_none() { - listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --listen-address", self.args.flag_listen_address))); + listen_address = Some(SocketAddr::from_str(self.args.flag_listen_address.as_ref()).unwrap_or_else(|_| { + die!("{}: Invalid listen/public address given with --listen-address", self.args.flag_listen_address) + })); } if let Some(ref a) = self.args.flag_public_address { if public_address.is_some() { die!("Conflicting flags provided: --address and --public-address"); } - public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| die!("{}: Invalid listen/public address given with --public-address", a))); + public_address = Some(SocketAddr::from_str(a.as_ref()).unwrap_or_else(|_| { + die!("{}: Invalid listen/public address given with --public-address", a) + })); } (listen_address, public_address) } @@ -403,7 +416,7 @@ impl Configuration { self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_addr), self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); - SocketAddr::from_str(&url).unwrap_or_else(|_|die!("{}: Invalid JSONRPC listen host/port given.", url)); + SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); @@ -475,7 +488,11 @@ impl Informant { let report = client.report(); let sync_info = sync.status(); - if let (_, _, &Some(ref last_report)) = (self.chain_info.read().unwrap().deref(), self.cache_info.read().unwrap().deref(), self.report.read().unwrap().deref()) { + if let (_, _, &Some(ref last_report)) = ( + self.chain_info.read().unwrap().deref(), + self.cache_info.read().unwrap().deref(), + self.report.read().unwrap().deref() + ) { println!("[ #{} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {}/{} peers, #{}, {}+{} queued ···// mem: {} db, {} chain, {} queue, {} sync ]", chain_info.best_block_number, chain_info.best_block_hash, From 90ae7500da814df956e7b2fb228c1a15711c5886 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 11:07:10 +0100 Subject: [PATCH 4/4] Update main.rs --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 729f6aeed..745912028 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -108,7 +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: 20000000000]. + --gasprice GAS Minimal gas price a transaction must have to be accepted for mining [default: 20000000000]. --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.