diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs index b2230af7b..893cdae03 100644 --- a/ethcore/src/client/test_client.rs +++ b/ethcore/src/client/test_client.rs @@ -16,6 +16,7 @@ //! Test client. +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; use util::*; use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action}; use blockchain::TreeRoute; @@ -54,6 +55,8 @@ pub struct TestBlockChainClient { pub execution_result: RwLock>, /// Transaction receipts. pub receipts: RwLock>, + /// Block queue size. + pub queue_size: AtomicUsize, } #[derive(Clone)] @@ -90,6 +93,7 @@ impl TestBlockChainClient { code: RwLock::new(HashMap::new()), execution_result: RwLock::new(None), receipts: RwLock::new(HashMap::new()), + queue_size: AtomicUsize::new(0), }; client.add_blocks(1, EachBlockWith::Nothing); // add genesis block client.genesis_hash = client.last_hash.read().unwrap().clone(); @@ -121,6 +125,11 @@ impl TestBlockChainClient { self.storage.write().unwrap().insert((address, position), value); } + /// Set block queue size for testing + pub fn set_queue_size(&self, size: usize) { + self.queue_size.store(size, AtomicOrder::Relaxed); + } + /// Add blocks to test client. pub fn add_blocks(&self, count: usize, with: EachBlockWith) { let len = self.numbers.read().unwrap().len(); @@ -383,7 +392,7 @@ impl BlockChainClient for TestBlockChainClient { fn queue_info(&self) -> BlockQueueInfo { BlockQueueInfo { - verified_queue_size: 0, + verified_queue_size: self.queue_size.load(AtomicOrder::Relaxed), unverified_queue_size: 0, verifying_queue_size: 0, max_queue_size: 0, diff --git a/ethcore/src/evm/instructions.rs b/ethcore/src/evm/instructions.rs index 623868618..6a1a06ba9 100644 --- a/ethcore/src/evm/instructions.rs +++ b/ethcore/src/evm/instructions.rs @@ -137,6 +137,7 @@ impl InstructionInfo { } } +#[cfg_attr(rustfmt, rustfmt_skip)] /// Return details about specific instruction pub fn get_info (instruction: Instruction) -> InstructionInfo { match instruction { @@ -301,7 +302,7 @@ pub const EXP: Instruction = 0x0a; pub const SIGNEXTEND: Instruction = 0x0b; /// less-than comparision -pub const LT: Instruction = 0x10; +pub const LT: Instruction = 0x10; /// greater-than comparision pub const GT: Instruction = 0x11; /// signed less-than comparision @@ -324,10 +325,10 @@ pub const NOT: Instruction = 0x19; pub const BYTE: Instruction = 0x1a; /// compute SHA3-256 hash -pub const SHA3: Instruction = 0x20; +pub const SHA3: Instruction = 0x20; /// get address of currently executing account -pub const ADDRESS: Instruction = 0x30; +pub const ADDRESS: Instruction = 0x30; /// get balance of the given account pub const BALANCE: Instruction = 0x31; /// get execution origination address @@ -367,7 +368,7 @@ pub const DIFFICULTY: Instruction = 0x44; pub const GASLIMIT: Instruction = 0x45; /// remove item from stack -pub const POP: Instruction = 0x50; +pub const POP: Instruction = 0x50; /// load word from memory pub const MLOAD: Instruction = 0x51; /// save word to memory @@ -392,7 +393,7 @@ pub const GAS: Instruction = 0x5a; pub const JUMPDEST: Instruction = 0x5b; /// place 1 byte item on stack -pub const PUSH1: Instruction = 0x60; +pub const PUSH1: Instruction = 0x60; /// place 2 byte item on stack pub const PUSH2: Instruction = 0x61; /// place 3 byte item on stack @@ -457,7 +458,7 @@ pub const PUSH31: Instruction = 0x7e; pub const PUSH32: Instruction = 0x7f; /// copies the highest item in the stack to the top of the stack -pub const DUP1: Instruction = 0x80; +pub const DUP1: Instruction = 0x80; /// copies the second highest item in the stack to the top of the stack pub const DUP2: Instruction = 0x81; /// copies the third highest item in the stack to the top of the stack @@ -490,7 +491,7 @@ pub const DUP15: Instruction = 0x8e; pub const DUP16: Instruction = 0x8f; /// swaps the highest and second highest value on the stack -pub const SWAP1: Instruction = 0x90; +pub const SWAP1: Instruction = 0x90; /// swaps the highest and third highest value on the stack pub const SWAP2: Instruction = 0x91; /// swaps the highest and 4th highest value on the stack @@ -523,7 +524,7 @@ pub const SWAP15: Instruction = 0x9e; pub const SWAP16: Instruction = 0x9f; /// Makes a log entry; no topics. -pub const LOG0: Instruction = 0xa0; +pub const LOG0: Instruction = 0xa0; /// Makes a log entry; 1 topic. pub const LOG1: Instruction = 0xa1; /// Makes a log entry; 2 topics. @@ -536,7 +537,7 @@ pub const LOG4: Instruction = 0xa4; pub const MAX_NO_OF_TOPICS : usize = 4; /// create a new account with associated code -pub const CREATE: Instruction = 0xf0; +pub const CREATE: Instruction = 0xf0; /// message-call into an account pub const CALL: Instruction = 0xf1; /// message-call with another account's code only @@ -546,5 +547,5 @@ pub const RETURN: Instruction = 0xf3; /// like CALLCODE but keeps caller's value and sender pub const DELEGATECALL: Instruction = 0xf4; /// halt execution and register account for later deletion -pub const SUICIDE: Instruction = 0xff; +pub const SUICIDE: Instruction = 0xff; diff --git a/fmt.sh b/fmt.sh new file mode 100755 index 000000000..a16d5ac1f --- /dev/null +++ b/fmt.sh @@ -0,0 +1,14 @@ +#!/bin/sh + +RUSTFMT="rustfmt --write-mode overwrite" + +$RUSTFMT ./ethash/src/lib.rs +$RUSTFMT ./ethcore/src/lib.rs +$RUSTFMT ./evmjit/src/lib.rs +$RUSTFMT ./json/src/lib.rs +$RUSTFMT ./miner/src/lib.rs +$RUSTFMT ./parity/main.rs +$RUSTFMT ./rpc/src/lib.rs +$RUSTFMT ./sync/src/lib.rs +$RUSTFMT ./util/src/lib.rs + diff --git a/install-parity.sh b/install-parity.sh index 74387ca7f..dec7f00ec 100755 --- a/install-parity.sh +++ b/install-parity.sh @@ -1,6 +1,6 @@ #!/usr/bin/env bash -PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/v1.0.0-rc1/parity_linux_1.0.0.rc1-0_amd64.deb +PARITY_DEB_URL=https://github.com/ethcore/parity/releases/download/v1.0.0/parity_linux_1.0.0-0_amd64.deb function run_installer() @@ -435,13 +435,8 @@ function run_installer() echo info "Installing parity" - if [[ $isEth == true ]] - then - brew reinstall parity - else - brew install parity - brew linkapps parity - fi + brew reinstall parity + brew linkapps parity echo } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index d4f6c8a00..e989fa495 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -39,7 +39,6 @@ pub struct Miner { gas_floor_target: RwLock, author: RwLock
, extra_data: RwLock, - } impl Default for Miner { @@ -166,28 +165,32 @@ impl MinerService for Miner { } fn update_sealing(&self, chain: &BlockChainClient) { - let should_disable_sealing = { + 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 is_greater = current_no > *last_request; - is_greater && current_no - *last_request > SEALING_TIMEOUT_IN_BLOCKS - }; + 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; - if should_disable_sealing { - self.sealing_enabled.store(false, atomic::Ordering::Relaxed); - *self.sealing_block.lock().unwrap() = None; - } else if self.sealing_enabled.load(atomic::Ordering::Relaxed) { - self.prepare_sealing(chain); + if should_disable_sealing { + trace!(target: "miner", "Miner sleeping (current {}, last {})", current_no, last_request); + self.sealing_enabled.store(false, atomic::Ordering::Relaxed); + *self.sealing_block.lock().unwrap() = None; + } else { + self.prepare_sealing(chain); + } } } fn sealing_block(&self, chain: &BlockChainClient) -> &Mutex> { if self.sealing_block.lock().unwrap().is_none() { self.sealing_enabled.store(true, atomic::Ordering::Relaxed); - self.prepare_sealing(chain); } - *self.sealing_block_last_request.lock().unwrap() = chain.chain_info().best_block_number; + let mut sealing_block_last_request = self.sealing_block_last_request.lock().unwrap(); + let best_number = chain.chain_info().best_block_number; + if *sealing_block_last_request != best_number { + trace!(target: "miner", "Miner received request (was {}, now {}) - waking up.", *sealing_block_last_request, best_number); + *sealing_block_last_request = best_number; + } &self.sealing_block } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index a065392d5..99f6eda3e 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -197,6 +197,8 @@ impl EthClient } } +const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6. + impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncProvider + 'static, @@ -398,10 +400,12 @@ impl Eth for EthClient match params { Params::None => { let client = take_weak!(self.client); - // check if we're still syncing and return empty strings int that case + // check if we're still syncing and return empty strings in that case { - let sync = take_weak!(self.sync); - if sync.status().state != SyncState::Idle && client.queue_info().is_empty() { + //TODO: check if initial sync is complete here + //let sync = take_weak!(self.sync); + if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON { + trace!(target: "miner", "Syncing. Cannot give any work."); return to_value(&(String::new(), String::new(), String::new())); } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 4564076eb..209b95ded 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -476,7 +476,8 @@ fn rpc_eth_compile_serpent() { #[test] fn returns_no_work_if_cant_mine() { - let eth_tester = EthTester::default(); + let mut eth_tester = EthTester::default(); + eth_tester.client.set_queue_size(10); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["","",""],"id":1}"#; diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 000000000..0b377a371 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,14 @@ +verbose=false +max_width=150 +ideal_width=120 +tabs_spaces=4 +fn_call_width=100 +single_line_if_else=true +where_indent="Visual" +where_trailing_comma=true +chain_base_indent="Inherit" +chain_indent="Tabbed" +reorder_imports=true +format_strings=false +hard_tabs=true +wrap_match_arms=false diff --git a/util/rustfmt.toml b/util/rustfmt.toml deleted file mode 100644 index 218e20321..000000000 --- a/util/rustfmt.toml +++ /dev/null @@ -1 +0,0 @@ -hard_tabs = true diff --git a/util/src/crypto.rs b/util/src/crypto.rs index e5096a317..e9b3116fd 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -208,7 +208,7 @@ pub mod ec { match context.verify(&try!(Message::from_slice(&message)), &sig, &publ) { Ok(_) => Ok(true), Err(Error::IncorrectSignature) => Ok(false), - Err(x) => Err(>::from(x)) + Err(x) => Err(CryptoError::from(x)) } } diff --git a/util/src/lib.rs b/util/src/lib.rs index 6abf6485d..dfdb300f6 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -124,6 +124,7 @@ pub mod hash; pub mod bytes; pub mod rlp; pub mod misc; +pub mod using_queue; mod json_aid; pub mod vector; pub mod sha3; @@ -149,6 +150,7 @@ pub mod table; pub use common::*; pub use misc::*; +pub use using_queue::*; pub use json_aid::*; pub use rlp::*; pub use hashdb::*; diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index 9d3fcb2fa..945ae9b24 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -153,7 +153,7 @@ impl<'a, 'view> Iterator for RlpIterator<'a, 'view> { fn next(&mut self) -> Option> { let index = self.index; - let result = self.rlp.rlp.at(index).ok().map(| iter | { From::from(iter) }); + let result = self.rlp.rlp.at(index).ok().map(From::from); self.index += 1; result } diff --git a/util/src/using_queue.rs b/util/src/using_queue.rs new file mode 100644 index 000000000..0371d3efe --- /dev/null +++ b/util/src/using_queue.rs @@ -0,0 +1,207 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . +//! Queue-like datastructure including notion of usage. + +/// Special queue-like datastructure that includes the notion of +/// usage to avoid items that were queued but never used from making it into +/// the queue. +pub struct UsingQueue where T: Clone { + /// Not yet being sealed by a miner, but if one asks for work, we'd prefer they do this. + pending: Option, + /// Currently being sealed by miners. + in_use: Vec, + /// The maximum allowable number of items in_use. + max_size: usize, +} + +impl UsingQueue where T: Clone { + /// Create a new struct with a maximum size of `max_size`. + pub fn new(max_size: usize) -> UsingQueue { + UsingQueue { + pending: None, + in_use: vec![], + max_size: max_size, + } + } + + /// Return a reference to the item at the top of the queue (or `None` if the queue is empty); + /// it doesn't constitute noting that the item is used. + pub fn peek_last_ref(&self) -> Option<&T> { + self.pending.as_ref().or(self.in_use.last()) + } + + /// Return a reference to the item at the top of the queue (or `None` if the queue is empty); + /// this constitutes using the item and will remain in the queue for at least another + /// `max_size` invocations of `push()`. + pub fn use_last_ref(&mut self) -> Option<&T> { + if let Some(x) = self.pending.take() { + self.in_use.push(x); + if self.in_use.len() > self.max_size { + self.in_use.remove(0); + } + } + self.in_use.last() + } + + /// Place an item on the end of the queue. The previously `push()`ed item will be removed + /// if `use_last_ref()` since it was `push()`ed. + pub fn push(&mut self, b: T) { + self.pending = Some(b); + } + + /// Clears everything; the queue is entirely reset. + pub fn reset(&mut self) { + self.pending = None; + self.in_use.clear(); + } + + /// Returns `Some` reference to first block that `f` returns `true` with it as a parameter + /// or `None` if no such block exists in the queue. + pub fn find_if

(&self, predicate: P) -> Option<&T> where P: Fn(&T) -> bool { + if self.pending.as_ref().map(|r| predicate(r)).unwrap_or(false) { + self.pending.as_ref() + } else { + self.in_use.iter().find(|r| predicate(r)) + } + } + + /// Returns the most recently pushed block if `f` returns `true` with a reference to it as + /// a parameter, otherwise `None`. + /// Will not destroy a block if a reference to it has previously been returned by `use_last_ref`, + /// but rather clone it. + pub fn pop_if

(&mut self, predicate: P) -> Option where P: Fn(&T) -> bool { + // a bit clumsy - TODO: think about a nicer way of expressing this. + if let Some(x) = self.pending.take() { + if predicate(&x) { + Some(x) + } else { + self.pending = Some(x); + None + } + } else { + self.in_use.last().into_iter().filter(|x| predicate(x)).next().cloned() + } + } +} + +#[test] +fn should_find_when_pushed() { + let mut q = UsingQueue::new(2); + q.push(1); + assert!(q.find_if(|i| i == &1).is_some()); +} + +#[test] +fn should_find_when_pushed_and_used() { + let mut q = UsingQueue::new(2); + q.push(1); + q.use_last_ref(); + assert!(q.find_if(|i| i == &1).is_some()); +} + +#[test] +fn should_find_when_others_used() { + let mut q = UsingQueue::new(2); + q.push(1); + q.use_last_ref(); + q.push(2); + q.use_last_ref(); + assert!(q.find_if(|i| i == &1).is_some()); +} + +#[test] +fn should_not_find_when_too_many_used() { + let mut q = UsingQueue::new(1); + q.push(1); + q.use_last_ref(); + q.push(2); + q.use_last_ref(); + assert!(q.find_if(|i| i == &1).is_none()); +} + +#[test] +fn should_not_find_when_not_used_and_then_pushed() { + let mut q = UsingQueue::new(3); + q.push(1); + q.push(2); + q.use_last_ref(); + assert!(q.find_if(|i| i == &1).is_none()); +} + +#[test] +fn should_peek_correctly_after_push() { + let mut q = UsingQueue::new(3); + q.push(1); + assert_eq!(q.peek_last_ref(), Some(&1)); + q.push(2); + assert_eq!(q.peek_last_ref(), Some(&2)); +} + +#[test] +fn should_inspect_correctly() { + let mut q = UsingQueue::new(3); + q.push(1); + assert_eq!(q.use_last_ref(), Some(&1)); + assert_eq!(q.peek_last_ref(), Some(&1)); + q.push(2); + assert_eq!(q.use_last_ref(), Some(&2)); + assert_eq!(q.peek_last_ref(), Some(&2)); +} + +#[test] +fn should_not_find_when_not_used_peeked_and_then_pushed() { + let mut q = UsingQueue::new(3); + q.push(1); + q.peek_last_ref(); + q.push(2); + q.use_last_ref(); + assert!(q.find_if(|i| i == &1).is_none()); +} + +#[test] +fn should_pop_used() { + let mut q = UsingQueue::new(3); + q.push(1); + q.use_last_ref(); + let popped = q.pop_if(|i| i == &1); + assert_eq!(popped, Some(1)); +} + +#[test] +fn should_pop_unused() { + let mut q = UsingQueue::new(3); + q.push(1); + assert_eq!(q.pop_if(|i| i == &1), Some(1)); + assert_eq!(q.pop_if(|i| i == &1), None); +} + +#[test] +fn should_not_pop_unused_before_used() { + let mut q = UsingQueue::new(3); + q.push(1); + q.push(2); + let popped = q.pop_if(|i| i == &1); + assert_eq!(popped, None); +} + +#[test] +fn should_not_remove_used_popped() { + let mut q = UsingQueue::new(3); + q.push(1); + q.use_last_ref(); + assert_eq!(q.pop_if(|i| i == &1), Some(1)); + assert_eq!(q.pop_if(|i| i == &1), Some(1)); +}