From c48374dbc649d302cf6c3d025ceae215f84c0f4e Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 11 Apr 2016 11:52:33 -0700 Subject: [PATCH] Parameter to allow user to force the sealing mechanism (#918) * Allow block sealing mechanism to be forced, even when not mining. * Fix deadlock in dispatch_transaction. Fix tests. * Horrible workaround for transaction importing. * Reduce tracing. Cleanups. * Remove logging. * Remove broken code inherited from dodgy implementation. * pre-query tx queue nonce also if any * remove outside nonce queries * remove queue nonces --- miner/src/miner.rs | 17 ++++++++++++++--- miner/src/transaction_queue.rs | 15 ++++++++------- parity/main.rs | 5 ++++- rpc/src/v1/impls/eth.rs | 12 +++++++++--- sync/src/chain.rs | 2 +- sync/src/lib.rs | 2 +- sync/src/tests/helpers.rs | 2 +- 7 files changed, 38 insertions(+), 17 deletions(-) diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 3b4d1f32d..8b3e7f4e4 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -30,6 +30,7 @@ pub struct Miner { transaction_queue: Mutex, // for sealing... + force_sealing: bool, sealing_enabled: AtomicBool, sealing_block_last_request: Mutex, sealing_work: Mutex>, @@ -42,6 +43,7 @@ impl Default for Miner { fn default() -> Miner { Miner { transaction_queue: Mutex::new(TransactionQueue::new()), + force_sealing: false, sealing_enabled: AtomicBool::new(false), sealing_block_last_request: Mutex::new(0), sealing_work: Mutex::new(UsingQueue::new(5)), @@ -54,8 +56,17 @@ impl Default for Miner { impl Miner { /// Creates new instance of miner - pub fn new() -> Arc { - Arc::new(Miner::default()) + pub fn new(force_sealing: bool) -> Arc { + Arc::new(Miner { + transaction_queue: Mutex::new(TransactionQueue::new()), + force_sealing: force_sealing, + sealing_enabled: AtomicBool::new(force_sealing), + sealing_block_last_request: Mutex::new(0), + sealing_work: Mutex::new(UsingQueue::new(5)), + gas_floor_target: RwLock::new(U256::zero()), + author: RwLock::new(Address::default()), + extra_data: RwLock::new(Vec::new()), + }) } /// Get the author that we will seal blocks as. @@ -241,7 +252,7 @@ impl MinerService for Miner { if self.sealing_enabled.load(atomic::Ordering::Relaxed) { let current_no = chain.chain_info().best_block_number; let last_request = *self.sealing_block_last_request.lock().unwrap(); - let should_disable_sealing = current_no > last_request && current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS; + let should_disable_sealing = !self.force_sealing && current_no > last_request && current_no - last_request > SEALING_TIMEOUT_IN_BLOCKS; if should_disable_sealing { trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request); diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 5e7beb5fe..fad864a5a 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -383,19 +383,19 @@ impl TransactionQueue { } let vtx = try!(VerifiedTransaction::new(tx)); - let account = fetch_account(&vtx.sender()); + let client_account = fetch_account(&vtx.sender()); let cost = vtx.transaction.value + vtx.transaction.gas_price * vtx.transaction.gas; - if account.balance < cost { + if client_account.balance < cost { trace!(target: "miner", "Dropping transaction without sufficient balance: {:?} ({} < {})", - vtx.hash(), account.balance, cost); + vtx.hash(), client_account.balance, cost); return Err(Error::Transaction(TransactionError::InsufficientBalance { cost: cost, - balance: account.balance + balance: client_account.balance })); } - self.import_tx(vtx, account.nonce).map_err(Error::Transaction) + self.import_tx(vtx, client_account.nonce).map_err(Error::Transaction) } /// Removes all transactions identified by hashes given in slice @@ -1188,6 +1188,7 @@ mod test { #[test] fn should_replace_same_transaction_when_has_higher_fee() { + init_log(); // given let mut txq = TransactionQueue::new(); let keypair = KeyPair::create().unwrap(); @@ -1264,7 +1265,7 @@ mod test { #[test] fn should_return_none_when_transaction_from_given_address_does_not_exist() { // given - let mut txq = TransactionQueue::new(); + let txq = TransactionQueue::new(); // then assert_eq!(txq.last_nonce(&Address::default()), None); @@ -1277,7 +1278,7 @@ mod test { let tx = new_tx(); let from = tx.sender().unwrap(); let nonce = tx.nonce; - let details = |a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() }; + let details = |_a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() }; // when txq.add(tx, &details).unwrap(); diff --git a/parity/main.rs b/parity/main.rs index 287392d4e..6fa0c5f00 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -152,6 +152,8 @@ API and Console Options: conjunction with --webapp-user. Sealing/Mining Options: + --force-sealing Force the node to author new blocks as if it were + always sealing/mining. --usd-per-tx USD Amount of USD to be paid for a basic transaction [default: 0.005]. The minimum gas price is set accordingly. @@ -239,6 +241,7 @@ struct Args { flag_webapp_interface: String, flag_webapp_user: Option, flag_webapp_pass: Option, + flag_force_sealing: bool, flag_author: String, flag_usd_per_tx: String, flag_usd_per_eth: String, @@ -657,7 +660,7 @@ impl Configuration { let client = service.client(); // Miner - let miner = Miner::new(); + let miner = Miner::new(self.args.flag_force_sealing); miner.set_author(self.author()); miner.set_gas_floor_target(self.gas_floor_target()); miner.set_extra_data(self.extra_data()); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index f8d591756..c885407cc 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -26,6 +26,7 @@ use ethminer::{MinerService, AccountDetails}; use jsonrpc_core::*; use util::numbers::*; use util::sha3::*; +use util::bytes::{ToPretty}; use util::rlp::{encode, UntrustedRlp, View}; use ethcore::client::*; use ethcore::block::IsBlock; @@ -191,9 +192,13 @@ impl EthClient let import = { let client = take_weak!(self.client); - take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { - nonce: client.nonce(a), - balance: client.balance(a), + let miner = take_weak!(self.miner); + + miner.import_transactions(vec![signed_transaction], |a: &Address| { + AccountDetails { + nonce: client.nonce(&a), + balance: client.balance(&a), + } }) }; @@ -499,6 +504,7 @@ impl Eth for EthClient data: request.data.map_or_else(Vec::new, |d| d.to_vec()), }.sign(&secret) }; + trace!(target: "miner", "send_transaction: dispatching tx: {}", encode(&signed_transaction).to_vec().pretty()); self.dispatch_transaction(signed_transaction) }, Err(_) => { to_value(&H256::zero()) } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 74bcb8d38..e2c11af1a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -1476,7 +1476,7 @@ mod tests { } fn dummy_sync_with_peer(peer_latest_hash: H256) -> ChainSync { - let mut sync = ChainSync::new(SyncConfig::default(), Miner::new()); + let mut sync = ChainSync::new(SyncConfig::default(), Miner::new(false)); sync.peers.insert(0, PeerInfo { protocol_version: 0, diff --git a/sync/src/lib.rs b/sync/src/lib.rs index a4f6eff38..6e900e97e 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -45,7 +45,7 @@ //! let mut service = NetworkService::start(NetworkConfiguration::new()).unwrap(); //! let dir = env::temp_dir(); //! let client = Client::new(ClientConfig::default(), ethereum::new_frontier(), &dir, service.io().channel()).unwrap(); -//! let miner = Miner::new(); +//! let miner = Miner::new(false); //! EthSync::register(&mut service, SyncConfig::default(), client, miner); //! } //! ``` diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index b3e62ccc6..269362064 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -93,7 +93,7 @@ impl TestNet { for _ in 0..n { net.peers.push(TestPeer { chain: TestBlockChainClient::new(), - sync: ChainSync::new(SyncConfig::default(), Miner::new()), + sync: ChainSync::new(SyncConfig::default(), Miner::new(false)), queue: VecDeque::new(), }); }