From c8076b2f9d9ac45e1a431366eaa5710cedfdcccc Mon Sep 17 00:00:00 2001 From: arkpar Date: Sun, 21 Feb 2016 19:46:29 +0100 Subject: [PATCH 01/27] Threading performance optimizations --- Cargo.lock | 3 +- Cargo.toml | 3 + ethcore/src/block_queue.rs | 146 +++++++++++++++++++----------------- ethcore/src/client.rs | 30 ++++---- ethcore/src/verification.rs | 14 +--- util/sha3/build.rs | 2 +- util/src/lib.rs | 2 + util/src/thread.rs | 43 +++++++++++ 8 files changed, 148 insertions(+), 95 deletions(-) create mode 100644 util/src/thread.rs diff --git a/Cargo.lock b/Cargo.lock index cf747f3cc..50274857f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,7 +151,6 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" -source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -223,7 +222,7 @@ dependencies = [ "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", + "eth-secp256k1 0.5.4", "ethcore-devtools 0.9.99", "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 7fdfc2bee..f28829180 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,3 +30,6 @@ travis-nightly = ["ethcore/json-tests", "dev"] [[bin]] path = "parity/main.rs" name = "parity" + +[profile.release] +debug = true diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index c39f158f0..a51a1e900 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -63,7 +63,7 @@ pub struct BlockQueue { panic_handler: Arc, engine: Arc>, more_to_verify: Arc, - verification: Arc>, + verification: Arc, verifiers: Vec>, deleting: Arc, ready_signal: Arc, @@ -98,12 +98,11 @@ impl QueueSignal { } } -#[derive(Default)] struct Verification { - unverified: VecDeque, - verified: VecDeque, - verifying: VecDeque, - bad: HashSet, + unverified: Mutex>, + verified: Mutex>, + verifying: Mutex>, + bad: Mutex>, } const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000; @@ -111,7 +110,12 @@ const MAX_UNVERIFIED_QUEUE_SIZE: usize = 50000; impl BlockQueue { /// Creates a new queue instance. pub fn new(engine: Arc>, message_channel: IoChannel) -> BlockQueue { - let verification = Arc::new(Mutex::new(Verification::default())); + let verification = Arc::new(Verification { + unverified: Mutex::new(VecDeque::new()), + verified: Mutex::new(VecDeque::new()), + verifying: Mutex::new(VecDeque::new()), + bad: Mutex::new(HashSet::new()), + }); let more_to_verify = Arc::new(Condvar::new()); let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); let deleting = Arc::new(AtomicBool::new(false)); @@ -119,7 +123,7 @@ impl BlockQueue { let panic_handler = PanicHandler::new_in_arc(); let mut verifiers: Vec> = Vec::new(); - let thread_count = max(::num_cpus::get(), 3) - 2; + let thread_count = max(::num_cpus::get(), 5) - 0; for i in 0..thread_count { let verification = verification.clone(); let engine = engine.clone(); @@ -133,7 +137,8 @@ impl BlockQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) + lower_thread_priority(); + BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) }).unwrap() }) .expect("Error starting block verification thread") @@ -152,17 +157,17 @@ impl BlockQueue { } } - fn verify(verification: Arc>, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { + fn verify(verification: Arc, engine: Arc>, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { while !deleting.load(AtomicOrdering::Acquire) { { - let mut lock = verification.lock().unwrap(); + let mut unverified = verification.unverified.lock().unwrap(); - if lock.unverified.is_empty() && lock.verifying.is_empty() { + if unverified.is_empty() && verification.verifying.lock().unwrap().is_empty() { empty.notify_all(); } - while lock.unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) { - lock = wait.wait(lock).unwrap(); + while unverified.is_empty() && !deleting.load(AtomicOrdering::Acquire) { + unverified = wait.wait(unverified).unwrap(); } if deleting.load(AtomicOrdering::Acquire) { @@ -171,39 +176,42 @@ impl BlockQueue { } let block = { - let mut v = verification.lock().unwrap(); - if v.unverified.is_empty() { + let mut unverified = verification.unverified.lock().unwrap(); + if unverified.is_empty() { continue; } - let block = v.unverified.pop_front().unwrap(); - v.verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); + let mut verifying = verification.verifying.lock().unwrap(); + let block = unverified.pop_front().unwrap(); + verifying.push_back(VerifyingBlock{ hash: block.header.hash(), block: None }); block }; let block_hash = block.header.hash(); match verify_block_unordered(block.header, block.bytes, engine.deref().deref()) { Ok(verified) => { - let mut v = verification.lock().unwrap(); - for e in &mut v.verifying { + let mut verifying = verification.verifying.lock().unwrap(); + for e in verifying.iter_mut() { if e.hash == block_hash { e.block = Some(verified); break; } } - if !v.verifying.is_empty() && v.verifying.front().unwrap().hash == block_hash { + if !verifying.is_empty() && verifying.front().unwrap().hash == block_hash { // we're next! - let mut vref = v.deref_mut(); - BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad); + let mut verified = verification.verified.lock().unwrap(); + let mut bad = verification.bad.lock().unwrap(); + BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad); ready.set(); } }, Err(err) => { - let mut v = verification.lock().unwrap(); + let mut verifying = verification.verifying.lock().unwrap(); + let mut verified = verification.verified.lock().unwrap(); + let mut bad = verification.bad.lock().unwrap(); warn!(target: "client", "Stage 2 block verification failed for {}\nError: {:?}", block_hash, err); - v.bad.insert(block_hash.clone()); - v.verifying.retain(|e| e.hash != block_hash); - let mut vref = v.deref_mut(); - BlockQueue::drain_verifying(&mut vref.verifying, &mut vref.verified, &mut vref.bad); + bad.insert(block_hash.clone()); + verifying.retain(|e| e.hash != block_hash); + BlockQueue::drain_verifying(&mut verifying, &mut verified, &mut bad); ready.set(); } } @@ -223,19 +231,21 @@ impl BlockQueue { } /// Clear the queue and stop verification activity. - pub fn clear(&mut self) { - let mut verification = self.verification.lock().unwrap(); - verification.unverified.clear(); - verification.verifying.clear(); - verification.verified.clear(); + pub fn clear(&self) { + let mut unverified = self.verification.unverified.lock().unwrap(); + let mut verifying = self.verification.verifying.lock().unwrap(); + let mut verified = self.verification.verified.lock().unwrap(); + unverified.clear(); + verifying.clear(); + verified.clear(); self.processing.write().unwrap().clear(); } - /// Wait for queue to be empty - pub fn flush(&mut self) { - let mut verification = self.verification.lock().unwrap(); - while !verification.unverified.is_empty() || !verification.verifying.is_empty() { - verification = self.empty.wait(verification).unwrap(); + /// Wait for unverified queue to be empty + pub fn flush(&self) { + let mut unverified = self.verification.unverified.lock().unwrap(); + while !unverified.is_empty() || !self.verification.verifying.lock().unwrap().is_empty() { + unverified = self.empty.wait(unverified).unwrap(); } } @@ -244,27 +254,29 @@ impl BlockQueue { if self.processing.read().unwrap().contains(&hash) { return BlockStatus::Queued; } - if self.verification.lock().unwrap().bad.contains(&hash) { + if self.verification.bad.lock().unwrap().contains(&hash) { return BlockStatus::Bad; } BlockStatus::Unknown } /// Add a block to the queue. - pub fn import_block(&mut self, bytes: Bytes) -> ImportResult { + pub fn import_block(&self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); let h = header.hash(); - if self.processing.read().unwrap().contains(&h) { - return Err(ImportError::AlreadyQueued); - } { - let mut verification = self.verification.lock().unwrap(); - if verification.bad.contains(&h) { + if self.processing.read().unwrap().contains(&h) { + return Err(ImportError::AlreadyQueued); + } + } + { + let mut bad = self.verification.bad.lock().unwrap(); + if bad.contains(&h) { return Err(ImportError::Bad(None)); } - if verification.bad.contains(&header.parent_hash) { - verification.bad.insert(h.clone()); + if bad.contains(&header.parent_hash) { + bad.insert(h.clone()); return Err(ImportError::Bad(None)); } } @@ -272,39 +284,40 @@ impl BlockQueue { match verify_block_basic(&header, &bytes, self.engine.deref().deref()) { Ok(()) => { self.processing.write().unwrap().insert(h.clone()); - self.verification.lock().unwrap().unverified.push_back(UnVerifiedBlock { header: header, bytes: bytes }); + self.verification.unverified.lock().unwrap().push_back(UnVerifiedBlock { header: header, bytes: bytes }); self.more_to_verify.notify_all(); Ok(h) }, Err(err) => { warn!(target: "client", "Stage 1 block verification failed for {}\nError: {:?}", BlockView::new(&bytes).header_view().sha3(), err); - self.verification.lock().unwrap().bad.insert(h.clone()); + self.verification.bad.lock().unwrap().insert(h.clone()); Err(From::from(err)) } } } /// Mark given block and all its children as bad. Stops verification. - pub fn mark_as_bad(&mut self, hash: &H256) { - let mut verification_lock = self.verification.lock().unwrap(); - let mut verification = verification_lock.deref_mut(); - verification.bad.insert(hash.clone()); + pub fn mark_as_bad(&self, hash: &H256) { + let mut verified_lock = self.verification.verified.lock().unwrap(); + let mut verified = verified_lock.deref_mut(); + let mut bad = self.verification.bad.lock().unwrap(); + bad.insert(hash.clone()); self.processing.write().unwrap().remove(&hash); let mut new_verified = VecDeque::new(); - for block in verification.verified.drain(..) { - if verification.bad.contains(&block.header.parent_hash) { - verification.bad.insert(block.header.hash()); + for block in verified.drain(..) { + if bad.contains(&block.header.parent_hash) { + bad.insert(block.header.hash()); self.processing.write().unwrap().remove(&block.header.hash()); } else { new_verified.push_back(block); } } - verification.verified = new_verified; + *verified = new_verified; } /// Mark given block as processed - pub fn mark_as_good(&mut self, hashes: &[H256]) { + pub fn mark_as_good(&self, hashes: &[H256]) { let mut processing = self.processing.write().unwrap(); for h in hashes { processing.remove(&h); @@ -312,16 +325,16 @@ impl BlockQueue { } /// Removes up to `max` verified blocks from the queue - pub fn drain(&mut self, max: usize) -> Vec { - let mut verification = self.verification.lock().unwrap(); - let count = min(max, verification.verified.len()); + pub fn drain(&self, max: usize) -> Vec { + let mut verified = self.verification.verified.lock().unwrap(); + let count = min(max, verified.len()); let mut result = Vec::with_capacity(count); for _ in 0..count { - let block = verification.verified.pop_front().unwrap(); + let block = verified.pop_front().unwrap(); result.push(block); } self.ready_signal.reset(); - if !verification.verified.is_empty() { + if !verified.is_empty() { self.ready_signal.set(); } result @@ -329,11 +342,10 @@ impl BlockQueue { /// Get queue status. pub fn queue_info(&self) -> BlockQueueInfo { - let verification = self.verification.lock().unwrap(); BlockQueueInfo { - verified_queue_size: verification.verified.len(), - unverified_queue_size: verification.unverified.len(), - verifying_queue_size: verification.verifying.len(), + unverified_queue_size: self.verification.unverified.lock().unwrap().len(), + verifying_queue_size: self.verification.verifying.lock().unwrap().len(), + verified_queue_size: self.verification.verified.lock().unwrap().len(), } } } diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index c3ec4b4d0..0c8580117 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -172,7 +172,7 @@ pub struct Client { chain: Arc>, engine: Arc>, state_db: Mutex, - block_queue: RwLock, + block_queue: BlockQueue, report: RwLock, import_lock: Mutex<()>, panic_handler: Arc, @@ -231,7 +231,7 @@ impl Client { chain: chain, engine: engine, state_db: Mutex::new(state_db), - block_queue: RwLock::new(block_queue), + block_queue: block_queue, report: RwLock::new(Default::default()), import_lock: Mutex::new(()), panic_handler: panic_handler @@ -240,7 +240,7 @@ impl Client { /// Flush the block import queue. pub fn flush_queue(&self) { - self.block_queue.write().unwrap().flush(); + self.block_queue.flush(); } /// This is triggered by a message coming from a block queue when the block is ready for insertion @@ -248,11 +248,11 @@ impl Client { let mut ret = 0; let mut bad = HashSet::new(); let _import_lock = self.import_lock.lock(); - let blocks = self.block_queue.write().unwrap().drain(128); + let blocks = self.block_queue.drain(128); let mut good_blocks = Vec::with_capacity(128); for block in blocks { if bad.contains(&block.header.parent_hash) { - self.block_queue.write().unwrap().mark_as_bad(&block.header.hash()); + self.block_queue.mark_as_bad(&block.header.hash()); bad.insert(block.header.hash()); continue; } @@ -260,7 +260,7 @@ impl Client { let header = &block.header; if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); bad.insert(block.header.hash()); break; }; @@ -268,7 +268,7 @@ impl Client { Some(p) => p, None => { warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); bad.insert(block.header.hash()); break; }, @@ -292,13 +292,13 @@ impl Client { Err(e) => { warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); bad.insert(block.header.hash()); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); break; } }; if let Err(e) = verify_block_final(&header, result.block().header()) { warn!(target: "client", "Stage 4 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); - self.block_queue.write().unwrap().mark_as_bad(&header.hash()); + self.block_queue.mark_as_bad(&header.hash()); break; } @@ -317,8 +317,8 @@ impl Client { trace!(target: "client", "Imported #{} ({})", header.number(), header.hash()); ret += 1; } - self.block_queue.write().unwrap().mark_as_good(&good_blocks); - if !good_blocks.is_empty() && self.block_queue.read().unwrap().queue_info().is_empty() { + self.block_queue.mark_as_good(&good_blocks); + if !good_blocks.is_empty() && self.block_queue.queue_info().is_empty() { io.send(NetworkIoMessage::User(SyncMessage::BlockVerified)).unwrap(); } ret @@ -389,7 +389,7 @@ impl BlockChainClient for Client { let chain = self.chain.read().unwrap(); match Self::block_hash(&chain, id) { Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, - Some(hash) => self.block_queue.read().unwrap().block_status(&hash), + Some(hash) => self.block_queue.block_status(&hash), None => BlockStatus::Unknown } } @@ -434,15 +434,15 @@ impl BlockChainClient for Client { if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { return Err(ImportError::UnknownParent); } - self.block_queue.write().unwrap().import_block(bytes) + self.block_queue.import_block(bytes) } fn queue_info(&self) -> BlockQueueInfo { - self.block_queue.read().unwrap().queue_info() + self.block_queue.queue_info() } fn clear_queue(&self) { - self.block_queue.write().unwrap().clear(); + self.block_queue.clear(); } fn chain_info(&self) -> BlockChainInfo { diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index c7d5e265f..fa9467e95 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -57,18 +57,12 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Still operates on a individual block /// Returns a PreVerifiedBlock structure populated with transactions pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { - try!(engine.verify_block_unordered(&header, Some(&bytes))); - for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { - try!(engine.verify_block_unordered(&u, None)); - } // Verify transactions. let mut transactions = Vec::new(); - { - let v = BlockView::new(&bytes); - for t in v.transactions() { - try!(engine.verify_transaction(&t, &header)); - transactions.push(t); - } + let v = BlockView::new(&bytes); + for t in v.transactions() { + try!(engine.verify_transaction(&t, &header)); + transactions.push(t); } Ok(PreVerifiedBlock { header: header, diff --git a/util/sha3/build.rs b/util/sha3/build.rs index bbe16d720..9eb36fdb9 100644 --- a/util/sha3/build.rs +++ b/util/sha3/build.rs @@ -21,6 +21,6 @@ extern crate gcc; fn main() { - gcc::compile_library("libtinykeccak.a", &["src/tinykeccak.c"]); + gcc::Config::new().file("src/tinykeccak.c").flag("-O3").compile("libtinykeccak.a"); } diff --git a/util/src/lib.rs b/util/src/lib.rs index 2b7438cf3..5c8bd4fb0 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -143,6 +143,7 @@ pub mod network; pub mod log; pub mod panics; pub mod keys; +mod thread; pub use common::*; pub use misc::*; @@ -163,4 +164,5 @@ pub use semantic_version::*; pub use network::*; pub use io::*; pub use log::*; +pub use thread::*; diff --git a/util/src/thread.rs b/util/src/thread.rs new file mode 100644 index 000000000..b86ca3e86 --- /dev/null +++ b/util/src/thread.rs @@ -0,0 +1,43 @@ +// 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 . + +//! Thread management helpers + +use libc::{c_int, pthread_self, pthread_t}; + +#[repr(C)] +struct sched_param { + priority: c_int, + padding: c_int, +} + +extern { + fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int; + fn pthread_setschedparam(thread: pthread_t, policy: c_int, param: *const sched_param) -> c_int; +} +const PRIO_DARWIN_THREAD: c_int = 3; +const PRIO_DARWIN_BG: c_int = 0x1000; +const SCHED_RR: c_int = 2; + +/// Lower thread priority and put it into background mode +#[cfg(target_os="macos")] +pub fn lower_thread_priority() { + let sp = sched_param { priority: 0, padding: 0 }; + if unsafe { pthread_setschedparam(pthread_self(), SCHED_RR, &sp) } == -1 { + trace!("Could not decrease thread piority"); + } + //unsafe { setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); } +} From 778fa92ebe82bcf7c739b4750a5443f2ed575802 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 22 Feb 2016 00:36:59 +0100 Subject: [PATCH 02/27] Remove locks from the block chain --- Cargo.lock | 3 +- Cargo.toml | 2 +- ethcore/src/block_queue.rs | 12 +++---- ethcore/src/blockchain.rs | 48 ++++++++++++++++------------ ethcore/src/client.rs | 63 +++++++++++++++++-------------------- ethcore/src/verification.rs | 14 ++++++--- util/src/lib.rs | 2 -- util/src/thread.rs | 43 ------------------------- 8 files changed, 75 insertions(+), 112 deletions(-) delete mode 100644 util/src/thread.rs diff --git a/Cargo.lock b/Cargo.lock index 50274857f..cf747f3cc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -151,6 +151,7 @@ dependencies = [ [[package]] name = "eth-secp256k1" version = "0.5.4" +source = "git+https://github.com/arkpar/rust-secp256k1.git#45503e1de68d909b1862e3f2bdb9e1cdfdff3f1e" dependencies = [ "arrayvec 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", "gcc 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)", @@ -222,7 +223,7 @@ dependencies = [ "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", - "eth-secp256k1 0.5.4", + "eth-secp256k1 0.5.4 (git+https://github.com/arkpar/rust-secp256k1.git)", "ethcore-devtools 0.9.99", "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "igd 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f28829180..8bc94a3a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,4 +32,4 @@ path = "parity/main.rs" name = "parity" [profile.release] -debug = true +debug = false diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index a51a1e900..ba9867966 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -99,6 +99,7 @@ impl QueueSignal { } struct Verification { + // All locks must be captured in the order declared here. unverified: Mutex>, verified: Mutex>, verifying: Mutex>, @@ -123,7 +124,7 @@ impl BlockQueue { let panic_handler = PanicHandler::new_in_arc(); let mut verifiers: Vec> = Vec::new(); - let thread_count = max(::num_cpus::get(), 5) - 0; + let thread_count = max(::num_cpus::get(), 3) - 2; for i in 0..thread_count { let verification = verification.clone(); let engine = engine.clone(); @@ -137,7 +138,6 @@ impl BlockQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - lower_thread_priority(); BlockQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) }).unwrap() }) @@ -392,7 +392,7 @@ mod tests { #[test] fn can_import_blocks() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that is valid by definition({:?})", e); } @@ -400,7 +400,7 @@ mod tests { #[test] fn returns_error_for_duplicates() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); if let Err(e) = queue.import_block(get_good_dummy_block()) { panic!("error importing block that is valid by definition({:?})", e); } @@ -419,7 +419,7 @@ mod tests { #[test] fn returns_ok_for_drained_duplicates() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); let block = get_good_dummy_block(); let hash = BlockView::new(&block).header().hash().clone(); if let Err(e) = queue.import_block(block) { @@ -436,7 +436,7 @@ mod tests { #[test] fn returns_empty_once_finished() { - let mut queue = get_test_queue(); + let queue = get_test_queue(); queue.import_block(get_good_dummy_block()).expect("error importing block that is valid by definition"); queue.flush(); queue.drain(1); diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index cc9ff56fd..22d409e8e 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -16,6 +16,7 @@ //! Blockchain database. +use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrder}; use util::*; use rocksdb::{DB, WriteBatch, Writable}; use header::*; @@ -147,8 +148,9 @@ struct CacheManager { /// /// **Does not do input data verification.** pub struct BlockChain { - pref_cache_size: usize, - max_cache_size: usize, + // All locks must be captured in the order declared here. + pref_cache_size: AtomicUsize, + max_cache_size: AtomicUsize, best_block: RwLock, @@ -166,6 +168,7 @@ pub struct BlockChain { blocks_db: DB, cache_man: RwLock, + insert_lock: Mutex<()> } impl BlockProvider for BlockChain { @@ -261,8 +264,8 @@ impl BlockChain { (0..COLLECTION_QUEUE_SIZE).foreach(|_| cache_man.cache_usage.push_back(HashSet::new())); let bc = BlockChain { - pref_cache_size: 1 << 14, - max_cache_size: 1 << 20, + pref_cache_size: AtomicUsize::new(1 << 14), + max_cache_size: AtomicUsize::new(1 << 20), best_block: RwLock::new(BestBlock::new()), blocks: RwLock::new(HashMap::new()), block_details: RwLock::new(HashMap::new()), @@ -273,6 +276,7 @@ impl BlockChain { extras_db: extras_db, blocks_db: blocks_db, cache_man: RwLock::new(cache_man), + insert_lock: Mutex::new(()), }; // load best block @@ -315,9 +319,9 @@ impl BlockChain { } /// Set the cache configuration. - pub fn configure_cache(&mut self, pref_cache_size: usize, max_cache_size: usize) { - self.pref_cache_size = pref_cache_size; - self.max_cache_size = max_cache_size; + pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { + self.pref_cache_size.store(pref_cache_size, AtomicOrder::Relaxed); + self.max_cache_size.store(max_cache_size, AtomicOrder::Relaxed); } /// Returns a tree route between `from` and `to`, which is a tuple of: @@ -435,22 +439,26 @@ impl BlockChain { return; } + let _lock = self.insert_lock.lock(); // store block in db self.blocks_db.put(&hash, &bytes).unwrap(); let (batch, new_best, details) = self.block_to_extras_insert_batch(bytes); - // update best block - let mut best_block = self.best_block.write().unwrap(); - if let Some(b) = new_best { - *best_block = b; + { + // update best block + let mut best_block = self.best_block.write().unwrap(); + if let Some(b) = new_best { + *best_block = b; + } } - // update caches - let mut write = self.block_details.write().unwrap(); - write.remove(&header.parent_hash()); - write.insert(hash.clone(), details); - self.note_used(CacheID::Block(hash)); - + { + // update caches + let mut write = self.block_details.write().unwrap(); + write.remove(&header.parent_hash()); + write.insert(hash.clone(), details); + self.note_used(CacheID::Block(hash)); + } // update extras database self.extras_db.write(batch).unwrap(); } @@ -622,17 +630,17 @@ impl BlockChain { /// Ticks our cache system and throws out any old data. pub fn collect_garbage(&self) { - if self.cache_size().total() < self.pref_cache_size { return; } + if self.cache_size().total() < self.pref_cache_size.load(AtomicOrder::Relaxed) { return; } for _ in 0..COLLECTION_QUEUE_SIZE { { - let mut cache_man = self.cache_man.write().unwrap(); let mut blocks = self.blocks.write().unwrap(); let mut block_details = self.block_details.write().unwrap(); let mut block_hashes = self.block_hashes.write().unwrap(); let mut transaction_addresses = self.transaction_addresses.write().unwrap(); let mut block_logs = self.block_logs.write().unwrap(); let mut blocks_blooms = self.blocks_blooms.write().unwrap(); + let mut cache_man = self.cache_man.write().unwrap(); for id in cache_man.cache_usage.pop_back().unwrap().into_iter() { cache_man.in_use.remove(&id); @@ -650,7 +658,7 @@ impl BlockChain { // TODO: handle block_hashes properly. block_hashes.clear(); } - if self.cache_size().total() < self.max_cache_size { break; } + if self.cache_size().total() < self.max_cache_size.load(AtomicOrder::Relaxed) { break; } } // TODO: m_lastCollection = chrono::system_clock::now(); diff --git a/ethcore/src/client.rs b/ethcore/src/client.rs index 0c8580117..68801520c 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client.rs @@ -169,7 +169,7 @@ impl ClientReport { /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue. /// Call `import_block()` to import a block asynchronously; `flush_queue()` flushes the queue. pub struct Client { - chain: Arc>, + chain: Arc, engine: Arc>, state_db: Mutex, block_queue: BlockQueue, @@ -190,7 +190,7 @@ impl Client { dir.push(format!("v{}-sec-pruned", CLIENT_DB_VER_STR)); let path = dir.as_path(); let gb = spec.genesis_block(); - let chain = Arc::new(RwLock::new(BlockChain::new(&gb, path))); + let chain = Arc::new(BlockChain::new(&gb, path)); let mut opts = Options::new(); opts.set_max_open_files(256); opts.create_if_missing(true); @@ -258,13 +258,13 @@ impl Client { } let header = &block.header; - if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.read().unwrap().deref()) { + if let Err(e) = verify_block_family(&header, &block.bytes, self.engine.deref().deref(), self.chain.deref()) { warn!(target: "client", "Stage 3 block verification failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); self.block_queue.mark_as_bad(&header.hash()); bad.insert(block.header.hash()); break; }; - let parent = match self.chain.read().unwrap().block_header(&header.parent_hash) { + let parent = match self.chain.block_header(&header.parent_hash) { Some(p) => p, None => { warn!(target: "client", "Block import failed for #{} ({}): Parent not found ({}) ", header.number(), header.hash(), header.parent_hash); @@ -278,7 +278,7 @@ impl Client { last_hashes.resize(256, H256::new()); last_hashes[0] = header.parent_hash.clone(); for i in 0..255 { - match self.chain.read().unwrap().block_details(&last_hashes[i]) { + match self.chain.block_details(&last_hashes[i]) { Some(details) => { last_hashes[i + 1] = details.parent.clone(); }, @@ -304,9 +304,9 @@ impl Client { good_blocks.push(header.hash().clone()); - self.chain.write().unwrap().insert_block(&block.bytes); //TODO: err here? + self.chain.insert_block(&block.bytes); //TODO: err here? let ancient = if header.number() >= HISTORY { Some(header.number() - HISTORY) } else { None }; - match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.read().unwrap().block_hash(n).unwrap()))) { + match result.drain().commit(header.number(), &header.hash(), ancient.map(|n|(n, self.chain.block_hash(n).unwrap()))) { Ok(_) => (), Err(e) => { warn!(target: "client", "State DB commit failed: {:?}", e); @@ -331,7 +331,7 @@ impl Client { /// Get info on the cache. pub fn cache_info(&self) -> CacheSize { - self.chain.read().unwrap().cache_size() + self.chain.cache_size() } /// Get the report. @@ -341,12 +341,12 @@ impl Client { /// Tick the client. pub fn tick(&self) { - self.chain.read().unwrap().collect_garbage(); + self.chain.collect_garbage(); } /// Set up the cache behaviour. pub fn configure_cache(&self, pref_cache_size: usize, max_cache_size: usize) { - self.chain.write().unwrap().configure_cache(pref_cache_size, max_cache_size); + self.chain.configure_cache(pref_cache_size, max_cache_size); } fn block_hash(chain: &BlockChain, id: BlockId) -> Option { @@ -361,14 +361,12 @@ impl Client { impl BlockChainClient for Client { fn block_header(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) + Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block(&hash).map(|bytes| BlockView::new(&bytes).rlp().at(0).as_raw().to_vec())) } fn block_body(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash).map(|bytes| { + Self::block_hash(&self.chain, id).and_then(|hash| { + self.chain.block(&hash).map(|bytes| { let rlp = Rlp::new(&bytes); let mut body = RlpStream::new_list(2); body.append_raw(rlp.at(1).as_raw(), 1); @@ -379,24 +377,21 @@ impl BlockChainClient for Client { } fn block(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| { - chain.block(&hash) + Self::block_hash(&self.chain, id).and_then(|hash| { + self.chain.block(&hash) }) } fn block_status(&self, id: BlockId) -> BlockStatus { - let chain = self.chain.read().unwrap(); - match Self::block_hash(&chain, id) { - Some(ref hash) if chain.is_known(hash) => BlockStatus::InChain, + match Self::block_hash(&self.chain, id) { + Some(ref hash) if self.chain.is_known(hash) => BlockStatus::InChain, Some(hash) => self.block_queue.block_status(&hash), None => BlockStatus::Unknown } } fn block_total_difficulty(&self, id: BlockId) -> Option { - let chain = self.chain.read().unwrap(); - Self::block_hash(&chain, id).and_then(|hash| chain.block_details(&hash)).map(|d| d.total_difficulty) + Self::block_hash(&self.chain, id).and_then(|hash| self.chain.block_details(&hash)).map(|d| d.total_difficulty) } fn code(&self, address: &Address) -> Option { @@ -404,18 +399,17 @@ impl BlockChainClient for Client { } fn transaction(&self, id: TransactionId) -> Option { - let chain = self.chain.read().unwrap(); match id { - TransactionId::Hash(ref hash) => chain.transaction_address(hash), - TransactionId::Location(id, index) => Self::block_hash(&chain, id).map(|hash| TransactionAddress { + TransactionId::Hash(ref hash) => self.chain.transaction_address(hash), + TransactionId::Location(id, index) => Self::block_hash(&self.chain, id).map(|hash| TransactionAddress { block_hash: hash, index: index }) - }.and_then(|address| chain.transaction(&address)) + }.and_then(|address| self.chain.transaction(&address)) } fn tree_route(&self, from: &H256, to: &H256) -> Option { - self.chain.read().unwrap().tree_route(from.clone(), to.clone()) + self.chain.tree_route(from.clone(), to.clone()) } fn state_data(&self, _hash: &H256) -> Option { @@ -428,7 +422,7 @@ impl BlockChainClient for Client { fn import_block(&self, bytes: Bytes) -> ImportResult { let header = BlockView::new(&bytes).header(); - if self.chain.read().unwrap().is_known(&header.hash()) { + if self.chain.is_known(&header.hash()) { return Err(ImportError::AlreadyInChain); } if self.block_status(BlockId::Hash(header.parent_hash)) == BlockStatus::Unknown { @@ -446,13 +440,12 @@ impl BlockChainClient for Client { } fn chain_info(&self) -> BlockChainInfo { - let chain = self.chain.read().unwrap(); BlockChainInfo { - total_difficulty: chain.best_block_total_difficulty(), - pending_total_difficulty: chain.best_block_total_difficulty(), - genesis_hash: chain.genesis_hash(), - best_block_hash: chain.best_block_hash(), - best_block_number: From::from(chain.best_block_number()) + total_difficulty: self.chain.best_block_total_difficulty(), + pending_total_difficulty: self.chain.best_block_total_difficulty(), + genesis_hash: self.chain.genesis_hash(), + best_block_hash: self.chain.best_block_hash(), + best_block_number: From::from(self.chain.best_block_number()) } } } diff --git a/ethcore/src/verification.rs b/ethcore/src/verification.rs index fa9467e95..c7d5e265f 100644 --- a/ethcore/src/verification.rs +++ b/ethcore/src/verification.rs @@ -57,12 +57,18 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Still operates on a individual block /// Returns a PreVerifiedBlock structure populated with transactions pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { + try!(engine.verify_block_unordered(&header, Some(&bytes))); + for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { + try!(engine.verify_block_unordered(&u, None)); + } // Verify transactions. let mut transactions = Vec::new(); - let v = BlockView::new(&bytes); - for t in v.transactions() { - try!(engine.verify_transaction(&t, &header)); - transactions.push(t); + { + let v = BlockView::new(&bytes); + for t in v.transactions() { + try!(engine.verify_transaction(&t, &header)); + transactions.push(t); + } } Ok(PreVerifiedBlock { header: header, diff --git a/util/src/lib.rs b/util/src/lib.rs index 5c8bd4fb0..2b7438cf3 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -143,7 +143,6 @@ pub mod network; pub mod log; pub mod panics; pub mod keys; -mod thread; pub use common::*; pub use misc::*; @@ -164,5 +163,4 @@ pub use semantic_version::*; pub use network::*; pub use io::*; pub use log::*; -pub use thread::*; diff --git a/util/src/thread.rs b/util/src/thread.rs deleted file mode 100644 index b86ca3e86..000000000 --- a/util/src/thread.rs +++ /dev/null @@ -1,43 +0,0 @@ -// 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 . - -//! Thread management helpers - -use libc::{c_int, pthread_self, pthread_t}; - -#[repr(C)] -struct sched_param { - priority: c_int, - padding: c_int, -} - -extern { - fn setpriority(which: c_int, who: c_int, prio: c_int) -> c_int; - fn pthread_setschedparam(thread: pthread_t, policy: c_int, param: *const sched_param) -> c_int; -} -const PRIO_DARWIN_THREAD: c_int = 3; -const PRIO_DARWIN_BG: c_int = 0x1000; -const SCHED_RR: c_int = 2; - -/// Lower thread priority and put it into background mode -#[cfg(target_os="macos")] -pub fn lower_thread_priority() { - let sp = sched_param { priority: 0, padding: 0 }; - if unsafe { pthread_setschedparam(pthread_self(), SCHED_RR, &sp) } == -1 { - trace!("Could not decrease thread piority"); - } - //unsafe { setpriority(PRIO_DARWIN_THREAD, 0, PRIO_DARWIN_BG); } -} From cb4d17825bc6353461549a4a9c03424cda525cae Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 29 Feb 2016 19:49:29 +0100 Subject: [PATCH 03/27] Fixed lock order --- Cargo.toml | 1 + ethcore/src/blockchain/blockchain.rs | 78 +++++++++++++++------------- 2 files changed, 44 insertions(+), 35 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 25b7caa85..df3beef49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,3 +35,4 @@ name = "parity" [profile.release] debug = false +lto = false diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 7339f3a1a..f30a674e6 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -433,48 +433,56 @@ impl BlockChain { batch.put(b"best", &update.info.hash).unwrap(); // These cached values must be updated atomically - let mut best_block = self.best_block.write().unwrap(); - let mut write_hashes = self.block_hashes.write().unwrap(); - let mut write_txs = self.transaction_addresses.write().unwrap(); + { + let mut best_block = self.best_block.write().unwrap(); + let mut write_hashes = self.block_hashes.write().unwrap(); + let mut write_txs = self.transaction_addresses.write().unwrap(); - // update best block - match update.info.location { - BlockLocation::Branch => (), - _ => { - *best_block = BestBlock { - hash: update.info.hash, - number: update.info.number, - total_difficulty: update.info.total_difficulty - }; + // update best block + match update.info.location { + BlockLocation::Branch => (), + _ => { + *best_block = BestBlock { + hash: update.info.hash, + number: update.info.number, + total_difficulty: update.info.total_difficulty + }; + } + } + + for (number, hash) in &update.block_hashes { + batch.put_extras(number, hash); + write_hashes.remove(number); + } + + for (hash, tx_address) in &update.transactions_addresses { + batch.put_extras(hash, tx_address); + write_txs.remove(hash); } } - for (number, hash) in &update.block_hashes { - batch.put_extras(number, hash); - write_hashes.remove(number); + { + let mut write_details = self.block_details.write().unwrap(); + for (hash, details) in update.block_details.into_iter() { + batch.put_extras(&hash, &details); + write_details.insert(hash, details); + } } - let mut write_details = self.block_details.write().unwrap(); - for (hash, details) in update.block_details.into_iter() { - batch.put_extras(&hash, &details); - write_details.insert(hash, details); + { + let mut write_receipts = self.block_receipts.write().unwrap(); + for (hash, receipt) in &update.block_receipts { + batch.put_extras(hash, receipt); + write_receipts.remove(hash); + } } - let mut write_receipts = self.block_receipts.write().unwrap(); - for (hash, receipt) in &update.block_receipts { - batch.put_extras(hash, receipt); - write_receipts.remove(hash); - } - - for (hash, tx_address) in &update.transactions_addresses { - batch.put_extras(hash, tx_address); - write_txs.remove(hash); - } - - let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); - for (bloom_hash, blocks_bloom) in &update.blocks_blooms { - batch.put_extras(bloom_hash, blocks_bloom); - write_blocks_blooms.remove(bloom_hash); + { + let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); + for (bloom_hash, blocks_bloom) in &update.blocks_blooms { + batch.put_extras(bloom_hash, blocks_bloom); + write_blocks_blooms.remove(bloom_hash); + } } // update extras database @@ -580,7 +588,7 @@ impl BlockChain { /// This function returns modified transaction addresses. fn prepare_transaction_addresses_update(&self, block_bytes: &[u8], info: &BlockInfo) -> HashMap { let block = BlockView::new(block_bytes); - let transaction_hashes = block.transaction_hashes(); + let transaction_hashes = block.transaction_hashes(); transaction_hashes.into_iter() .enumerate() From d0129ff67b5e69436df88a6758e81d880e924a23 Mon Sep 17 00:00:00 2001 From: arkpar Date: Mon, 29 Feb 2016 21:15:39 +0100 Subject: [PATCH 04/27] Fixed cache memory leak --- ethcore/src/blockchain/blockchain.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index f30a674e6..23e9aaac9 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -465,6 +465,7 @@ impl BlockChain { let mut write_details = self.block_details.write().unwrap(); for (hash, details) in update.block_details.into_iter() { batch.put_extras(&hash, &details); + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); write_details.insert(hash, details); } } @@ -769,6 +770,14 @@ impl BlockChain { // TODO: handle block_hashes properly. block_hashes.clear(); + + blocks.shrink_to_fit(); + block_details.shrink_to_fit(); + block_hashes.shrink_to_fit(); + transaction_addresses.shrink_to_fit(); + block_logs.shrink_to_fit(); + blocks_blooms.shrink_to_fit(); + block_receipts.shrink_to_fit(); } if self.cache_size().total() < self.max_cache_size.load(AtomicOrder::Relaxed) { break; } } From c889d9b3eb21c1b54989d741c6b34bed4bfc30ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 25 Feb 2016 16:58:18 +0100 Subject: [PATCH 05/27] Exposing transaction queue pending in RPC --- rpc/src/v1/impls/eth.rs | 13 ++++++++++++- rpc/src/v1/traits/eth.rs | 13 ++++++++----- sync/src/chain.rs | 3 +++ 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 00bce5437..6d66a2c6d 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -152,7 +152,7 @@ impl Eth for EthClient { } } - fn block_transaction_count(&self, params: Params) -> Result { + fn block_transaction_count_by_hash(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), @@ -160,6 +160,17 @@ impl Eth for EthClient { }) } + fn block_transaction_count_by_number(&self, params: Params) -> Result { + from_params::<(BlockNumber,)>(params) + .and_then(|(block_number,)| match block_number { + BlockNumber::Pending => to_value(&take_weak!(self.sync).status().transaction_queue_pending), + _ => match take_weak!(self.client).block(block_number.into()) { + Some(bytes) => to_value(&BlockView::new(&bytes).transactions_count()), + None => Ok(Value::Null) + } + }) + } + fn block_uncles_count(&self, params: Params) -> Result { from_params::<(H256,)>(params) .and_then(|(hash,)| match take_weak!(self.client).block(BlockId::Hash(hash)) { diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index d2aeb0f9e..8c24dd38c 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -55,12 +55,15 @@ pub trait Eth: Sized + Send + Sync + 'static { /// Returns block with given number. fn block_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } - + /// Returns the number of transactions sent from given address at given time (block number). fn transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns the number of transactions in a block. - fn block_transaction_count(&self, _: Params) -> Result { rpc_unimplemented!() } + /// Returns the number of transactions in a block given block hash. + fn block_transaction_count_by_hash(&self, _: Params) -> Result { rpc_unimplemented!() } + + /// Returns the number of transactions in a block given block number. + fn block_transaction_count_by_number(&self, _: Params) -> Result { rpc_unimplemented!() } /// Returns the number of uncles in a given block. fn block_uncles_count(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -130,8 +133,8 @@ pub trait Eth: Sized + Send + Sync + 'static { delegate.add_method("eth_balance", Eth::balance); delegate.add_method("eth_getStorageAt", Eth::storage_at); delegate.add_method("eth_getTransactionCount", Eth::transaction_count); - delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count); - delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count); + delegate.add_method("eth_getBlockTransactionCountByHash", Eth::block_transaction_count_by_hash); + delegate.add_method("eth_getBlockTransactionCountByNumber", Eth::block_transaction_count_by_number); delegate.add_method("eth_getUncleCountByBlockHash", Eth::block_uncles_count); delegate.add_method("eth_getUncleCountByBlockNumber", Eth::block_uncles_count); delegate.add_method("eth_code", Eth::code_at); diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 9edab791a..90f7b0d2a 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -140,6 +140,8 @@ pub struct SyncStatus { pub num_active_peers: usize, /// Heap memory used in bytes pub mem_used: usize, + /// Number of pending transactions in queue + pub transaction_queue_pending: usize, } #[derive(PartialEq, Eq, Debug, Clone)] @@ -255,6 +257,7 @@ impl ChainSync { blocks_total: match self.highest_block { Some(x) if x > self.starting_block => x - self.starting_block, _ => 0 }, num_peers: self.peers.len(), num_active_peers: self.peers.values().filter(|p| p.asking != PeerAsking::Nothing).count(), + transaction_queue_pending: self.transaction_queue.lock().unwrap().status().pending, mem_used: // TODO: https://github.com/servo/heapsize/pull/50 // self.downloading_hashes.heap_size_of_children() From 324e070581305ded5b9c40942f86837756f2116d Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 2 Mar 2016 01:24:06 +0100 Subject: [PATCH 06/27] Reverted some changes --- ethcore/src/block_queue.rs | 3 +-- util/sha3/build.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index f61eb565d..de411c6e2 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -302,8 +302,7 @@ impl BlockQueue { if self.processing.read().unwrap().contains(&h) { return Err(ImportError::AlreadyQueued); } - } - { + let mut bad = self.verification.bad.lock().unwrap(); if bad.contains(&h) { return Err(ImportError::Bad(None)); diff --git a/util/sha3/build.rs b/util/sha3/build.rs index 9eb36fdb9..bbe16d720 100644 --- a/util/sha3/build.rs +++ b/util/sha3/build.rs @@ -21,6 +21,6 @@ extern crate gcc; fn main() { - gcc::Config::new().file("src/tinykeccak.c").flag("-O3").compile("libtinykeccak.a"); + gcc::compile_library("libtinykeccak.a", &["src/tinykeccak.c"]); } From af5ed8b5f7af5b576fed3181dc03c45fdee50f1b Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Fri, 4 Mar 2016 20:10:07 +0300 Subject: [PATCH 07/27] rpc-signing-extend --- parity/main.rs | 1 + rpc/src/v1/impls/eth.rs | 17 ++++++++++++++++- rpc/src/v1/impls/personal.rs | 21 ++++++++++----------- rpc/src/v1/types/bytes.rs | 32 ++++++++++++++++++++++++++++++-- rpc/src/v1/types/mod.rs.in | 2 ++ rpc/src/v1/types/transaction.rs | 13 +++++++++++++ 6 files changed, 72 insertions(+), 14 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index b991f36cd..91a884beb 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -157,6 +157,7 @@ fn setup_rpc_server(client: Arc, sync: Arc, url: &str, cors_dom server.add_delegate(EthClient::new(&client, &sync).to_delegate()); server.add_delegate(EthFilterClient::new(&client).to_delegate()); server.add_delegate(NetClient::new(&sync).to_delegate()); + server.add_delegate(PersonalClient::new(&client).to_delegate()); server.start_async(url, cors_domain); } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 2313d5114..16b68f90f 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -29,7 +29,7 @@ use ethcore::views::*; use ethcore::ethereum::Ethash; use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; -use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, OptionalValue, Index, Filter, Log}; +use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; use v1::helpers::{PollFilter, PollManager}; /// Eth rpc implementation. @@ -253,6 +253,21 @@ impl Eth for EthClient { to_value(&true) }) } + + fn send_transaction(&self, params: Params) -> Result { + from_params::<(TransactionRequest, )>(params) + .and_then(|(transaction_request, )| { + let client = take_weak!(self.client); + let store = client.secret_store().read().unwrap(); + match store.account_secret(&transaction_request.from) { + Ok(_) => { + // todo: actually sign and push to queue transaction here + Ok(Value::Bool(true)) + }, + Err(_) => { Ok(Value::Bool(false ))} + } + }) + } } /// Eth filter rpc implementation. diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 48e1b1c6a..a2788b9d9 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -18,28 +18,27 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use v1::traits::Personal; -use util::keys::store::*; use util::Address; -use std::sync::RwLock; +use ethcore::client::Client; /// Account management (personal) rpc implementation. pub struct PersonalClient { - secret_store: Weak>, + client: Weak, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(store: &Arc>) -> Self { + pub fn new(client: &Arc) -> Self { PersonalClient { - secret_store: Arc::downgrade(store), + client: Arc::downgrade(client), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let client = take_weak!(self.client); + let store = client.secret_store().read().unwrap(); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() @@ -54,8 +53,8 @@ impl Personal for PersonalClient { fn new_account(&self, params: Params) -> Result { from_params::<(String, )>(params).and_then( |(pass, )| { - let store_wk = take_weak!(self.secret_store); - let mut store = store_wk.write().unwrap(); + let client = take_weak!(self.client); + let mut store = client.secret_store().write().unwrap(); match store.new_account(&pass) { Ok(address) => Ok(Value::String(format!("{:?}", address))), Err(_) => Err(Error::internal_error()) @@ -67,8 +66,8 @@ impl Personal for PersonalClient { fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let client = take_weak!(self.client); + let store = client.secret_store().read().unwrap(); match store.unlock_account(&account, &account_pass) { Ok(_) => Ok(Value::Bool(true)), Err(_) => Ok(Value::Bool(false)), diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index f09f24e4d..44809ac70 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -15,7 +15,9 @@ // along with Parity. If not, see . use rustc_serialize::hex::ToHex; -use serde::{Serialize, Serializer}; +use serde::{Serialize, Serializer, Deserialize, Deserializer, Error}; +use serde::de::Visitor; +use util::common::FromHex; /// Wrapper structure around vector of bytes. #[derive(Debug)] @@ -36,7 +38,7 @@ impl Default for Bytes { } impl Serialize for Bytes { - fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> + fn serialize(&self, serializer: &mut S) -> Result<(), S::Error> where S: Serializer { let mut serialized = "0x".to_owned(); serialized.push_str(self.0.to_hex().as_ref()); @@ -44,6 +46,32 @@ impl Serialize for Bytes { } } +impl Deserialize for Bytes { + fn deserialize(deserializer: &mut D) -> Result + where D: Deserializer { + deserializer.deserialize(BytesVisitor) + } +} + +struct BytesVisitor; + +impl Visitor for BytesVisitor { + type Value = Bytes; + + fn visit_str(&mut self, value: &str) -> Result where E: Error { + if value.len() >= 2 && &value[0..2] == "0x" { + Ok(Bytes::new(FromHex::from_hex(&value[2..]).unwrap_or_else(|_| vec![]))) + } else { + Err(Error::custom("invalid hex")) + } + } + + fn visit_string(&mut self, value: String) -> Result where E: Error { + self.visit_str(value.as_ref()) + } +} + + #[cfg(test)] mod tests { use super::*; diff --git a/rpc/src/v1/types/mod.rs.in b/rpc/src/v1/types/mod.rs.in index 34c1f1cff..2b2390ecb 100644 --- a/rpc/src/v1/types/mod.rs.in +++ b/rpc/src/v1/types/mod.rs.in @@ -33,3 +33,5 @@ pub use self::log::Log; pub use self::optionals::OptionalValue; pub use self::sync::{SyncStatus, SyncInfo}; pub use self::transaction::Transaction; +pub use self::transaction::TransactionRequest; + diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 232cf0bf3..7d40d8a49 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -17,6 +17,7 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; +use serde::{Deserializer, Error}; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -37,6 +38,18 @@ pub struct Transaction { pub input: Bytes } +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct TransactionRequest { + pub from: Address, + pub to: Option
, + #[serde(rename="gasPrice")] + pub gas_price: Option, + pub gas: Option, + pub value: Option, + pub data: Bytes, + pub nonce: Option, +} + impl From for Transaction { fn from(t: LocalizedTransaction) -> Transaction { Transaction { From 1aaae7b55333625c572fc77cc722ea98c2517825 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 16:42:02 +0300 Subject: [PATCH 08/27] [ci skip] codegen bug --- rpc/src/v1/types/transaction.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index 7d40d8a49..c24bcd08f 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -18,6 +18,8 @@ use util::numbers::*; use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; use serde::{Deserializer, Error}; +use ethcore; +use util; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -50,6 +52,22 @@ pub struct TransactionRequest { pub nonce: Option, } +impl TransactionRequest { + fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { + (ethcore::transaction::Transaction { + nonce: self.nonce.unwrap_or(U256::zero()), + action: match self.to { + None => ethcore::transaction::Action::Create, + Some(addr) => ethcore::transaction::Action::Call(addr) + }, + gas: self.gas.unwrap_or(U256::zero()), + gas_price: self.gas_price.unwrap_or(U256::zero()), + value: self.value.unwrap_or(U256::zero()), + data: { let (ref x) = self.data; x } + }, self.from) + } +} + impl From for Transaction { fn from(t: LocalizedTransaction) -> Transaction { Transaction { From bb8a79f18c44575d59ce68d4a9b5c03009679585 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Sat, 5 Mar 2016 18:29:01 +0300 Subject: [PATCH 09/27] finalizing --- rpc/src/v1/impls/eth.rs | 12 ++++++++---- rpc/src/v1/types/bytes.rs | 1 + rpc/src/v1/types/transaction.rs | 6 +++--- 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 16b68f90f..91ccaa05a 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -260,11 +260,15 @@ impl Eth for EthClient { let client = take_weak!(self.client); let store = client.secret_store().read().unwrap(); match store.account_secret(&transaction_request.from) { - Ok(_) => { - // todo: actually sign and push to queue transaction here - Ok(Value::Bool(true)) + Ok(secret) => { + let sync = take_weak!(self.sync); + let (transaction, _) = transaction_request.to_eth(); + let signed_transaction = transaction.sign(&secret); + let hash = signed_transaction.hash(); + sync.insert_transaction(signed_transaction); + to_value(&hash) }, - Err(_) => { Ok(Value::Bool(false ))} + Err(_) => { to_value(&U256::zero()) } } }) } diff --git a/rpc/src/v1/types/bytes.rs b/rpc/src/v1/types/bytes.rs index 44809ac70..466fbebde 100644 --- a/rpc/src/v1/types/bytes.rs +++ b/rpc/src/v1/types/bytes.rs @@ -28,6 +28,7 @@ impl Bytes { pub fn new(bytes: Vec) -> Bytes { Bytes(bytes) } + pub fn to_vec(self) -> Vec { let Bytes(x) = self; x } } impl Default for Bytes { diff --git a/rpc/src/v1/types/transaction.rs b/rpc/src/v1/types/transaction.rs index c24bcd08f..17b42cfcf 100644 --- a/rpc/src/v1/types/transaction.rs +++ b/rpc/src/v1/types/transaction.rs @@ -19,7 +19,6 @@ use ethcore::transaction::{LocalizedTransaction, Action}; use v1::types::{Bytes, OptionalValue}; use serde::{Deserializer, Error}; use ethcore; -use util; #[derive(Debug, Default, Serialize)] pub struct Transaction { @@ -53,7 +52,8 @@ pub struct TransactionRequest { } impl TransactionRequest { - fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { + /// maps transaction request to the transaction that can be signed and inserted + pub fn to_eth(self) -> (ethcore::transaction::Transaction, Address) { (ethcore::transaction::Transaction { nonce: self.nonce.unwrap_or(U256::zero()), action: match self.to { @@ -63,7 +63,7 @@ impl TransactionRequest { gas: self.gas.unwrap_or(U256::zero()), gas_price: self.gas_price.unwrap_or(U256::zero()), value: self.value.unwrap_or(U256::zero()), - data: { let (ref x) = self.data; x } + data: self.data.to_vec() }, self.from) } } From ae1c1b918faea16a81d2fe582446a148fdea3c84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Sat, 5 Mar 2016 16:51:01 +0100 Subject: [PATCH 10/27] Fixing compilation --- sync/src/transaction_queue.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/sync/src/transaction_queue.rs b/sync/src/transaction_queue.rs index 8b38c64ad..24bb772d7 100644 --- a/sync/src/transaction_queue.rs +++ b/sync/src/transaction_queue.rs @@ -297,12 +297,6 @@ impl TransactionQueue { } } self.future.enforce_limit(&mut self.by_hash); - - // And now lets check if there is some chain of transactions in future - // that should be placed in current - if let Some(new_current_top) = self.move_future_txs(sender.clone(), current_nonce, current_nonce) { - self.last_nonces.insert(sender, new_current_top); - } } From 6681aaf76af521a4c67bfa4d85fbaedaa4029915 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 10 Mar 2016 11:32:10 +0100 Subject: [PATCH 11/27] split client into few submodules --- ethcore/src/{ => client}/client.rs | 123 ++--------------------------- ethcore/src/client/config.rs | 31 ++++++++ ethcore/src/client/ids.rs | 44 +++++++++++ ethcore/src/client/mod.rs | 102 ++++++++++++++++++++++++ 4 files changed, 183 insertions(+), 117 deletions(-) rename ethcore/src/{ => client}/client.rs (85%) create mode 100644 ethcore/src/client/config.rs create mode 100644 ethcore/src/client/ids.rs create mode 100644 ethcore/src/client/mod.rs diff --git a/ethcore/src/client.rs b/ethcore/src/client/client.rs similarity index 85% rename from ethcore/src/client.rs rename to ethcore/src/client/client.rs index b342cef15..2f9536b2e 100644 --- a/ethcore/src/client.rs +++ b/ethcore/src/client/client.rs @@ -20,7 +20,6 @@ use std::marker::PhantomData; use std::sync::atomic::AtomicBool; use util::*; use util::panics::*; -use blockchain::{BlockChain, BlockProvider}; use views::BlockView; use error::*; use header::{BlockNumber}; @@ -28,7 +27,6 @@ use state::State; use spec::Spec; use engine::Engine; use views::HeaderView; -use block_queue::BlockQueue; use service::{NetSyncMessage, SyncMessage}; use env_info::LastHashes; use verification::*; @@ -38,32 +36,9 @@ use extras::TransactionAddress; use filter::Filter; use log_entry::LocalizedLogEntry; use util::keys::store::SecretStore; -pub use block_queue::{BlockQueueConfig, BlockQueueInfo}; -pub use blockchain::{TreeRoute, BlockChainConfig, CacheSize as BlockChainCacheSize}; - -/// Uniquely identifies block. -#[derive(Debug, PartialEq, Clone)] -pub enum BlockId { - /// Block's sha3. - /// Querying by hash is always faster. - Hash(H256), - /// Block number within canon blockchain. - Number(BlockNumber), - /// Earliest block (genesis). - Earliest, - /// Latest mined block. - Latest -} - -/// Uniquely identifies transaction. -#[derive(Debug, PartialEq, Clone)] -pub enum TransactionId { - /// Transaction's sha3. - Hash(H256), - /// Block id and transaction index within this block. - /// Querying by block position is always faster. - Location(BlockId, usize) -} +use block_queue::{BlockQueue, BlockQueueInfo}; +use blockchain::{BlockChain, BlockProvider, TreeRoute, CacheSize as BlockChainCacheSize}; +use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; /// General block status #[derive(Debug, Eq, PartialEq)] @@ -78,30 +53,6 @@ pub enum BlockStatus { Unknown, } -/// Client configuration. Includes configs for all sub-systems. -#[derive(Debug)] -pub struct ClientConfig { - /// Block queue configuration. - pub queue: BlockQueueConfig, - /// Blockchain configuration. - pub blockchain: BlockChainConfig, - /// Prefer journal rather than archive. - pub prefer_journal: bool, - /// The name of the client instance. - pub name: String, -} - -impl Default for ClientConfig { - fn default() -> ClientConfig { - ClientConfig { - queue: Default::default(), - blockchain: Default::default(), - prefer_journal: false, - name: Default::default(), - } - } -} - /// Information about the blockchain gathered together. #[derive(Debug)] pub struct BlockChainInfo { @@ -123,72 +74,8 @@ impl fmt::Display for BlockChainInfo { } } -/// Blockchain database client. Owns and manages a blockchain and a block queue. -pub trait BlockChainClient : Sync + Send { - /// Get raw block header data by block id. - fn block_header(&self, id: BlockId) -> Option; - - /// Get raw block body data by block id. - /// Block body is an RLP list of two items: uncles and transactions. - fn block_body(&self, id: BlockId) -> Option; - - /// Get raw block data by block header hash. - fn block(&self, id: BlockId) -> Option; - - /// Get block status by block header hash. - fn block_status(&self, id: BlockId) -> BlockStatus; - - /// Get block total difficulty. - fn block_total_difficulty(&self, id: BlockId) -> Option; - - /// Get address nonce. - fn nonce(&self, address: &Address) -> U256; - - /// Get block hash. - fn block_hash(&self, id: BlockId) -> Option; - - /// Get address code. - fn code(&self, address: &Address) -> Option; - - /// Get transaction with given hash. - fn transaction(&self, id: TransactionId) -> Option; - - /// Get a tree route between `from` and `to`. - /// See `BlockChain::tree_route`. - fn tree_route(&self, from: &H256, to: &H256) -> Option; - - /// Get latest state node - fn state_data(&self, hash: &H256) -> Option; - - /// Get raw block receipts data by block header hash. - fn block_receipts(&self, hash: &H256) -> Option; - - /// Import a block into the blockchain. - fn import_block(&self, bytes: Bytes) -> ImportResult; - - /// Get block queue information. - fn queue_info(&self) -> BlockQueueInfo; - - /// Clear block queue and abort all import activity. - fn clear_queue(&self); - - /// Get blockchain information. - fn chain_info(&self) -> BlockChainInfo; - - /// Get the best block header. - fn best_block_header(&self) -> Bytes { - self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() - } - - /// Returns numbers of blocks containing given bloom. - fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; - - /// Returns logs matching given filter. - fn logs(&self, filter: Filter) -> Vec; -} - -#[derive(Default, Clone, Debug, Eq, PartialEq)] /// Report on the status of a client. +#[derive(Default, Clone, Debug, Eq, PartialEq)] pub struct ClientReport { /// How many blocks have been imported so far. pub blocks_imported: usize, @@ -679,6 +566,8 @@ impl BlockChainClient for Client where V: Verifier { } fn logs(&self, filter: Filter) -> Vec { + // TODO: lock blockchain only once + let mut blocks = filter.bloom_possibilities().iter() .filter_map(|bloom| self.blocks_with_bloom(bloom, filter.from_block.clone(), filter.to_block.clone())) .flat_map(|m| m) diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs new file mode 100644 index 000000000..484c8d0c6 --- /dev/null +++ b/ethcore/src/client/config.rs @@ -0,0 +1,31 @@ +// 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 . + +pub use block_queue::BlockQueueConfig; +pub use blockchain::BlockChainConfig; + +/// Client configuration. Includes configs for all sub-systems. +#[derive(Debug, Default)] +pub struct ClientConfig { + /// Block queue configuration. + pub queue: BlockQueueConfig, + /// Blockchain configuration. + pub blockchain: BlockChainConfig, + /// Prefer journal rather than archive. + pub prefer_journal: bool, + /// The name of the client instance. + pub name: String, +} diff --git a/ethcore/src/client/ids.rs b/ethcore/src/client/ids.rs new file mode 100644 index 000000000..303657a76 --- /dev/null +++ b/ethcore/src/client/ids.rs @@ -0,0 +1,44 @@ +// 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 . + +//! Unique identifiers. + +use util::hash::H256; +use header::BlockNumber; + +/// Uniquely identifies block. +#[derive(Debug, PartialEq, Clone)] +pub enum BlockId { + /// Block's sha3. + /// Querying by hash is always faster. + Hash(H256), + /// Block number within canon blockchain. + Number(BlockNumber), + /// Earliest block (genesis). + Earliest, + /// Latest mined block. + Latest +} + +/// Uniquely identifies transaction. +#[derive(Debug, PartialEq, Clone)] +pub enum TransactionId { + /// Transaction's sha3. + Hash(H256), + /// Block id and transaction index within this block. + /// Querying by block position is always faster. + Location(BlockId, usize) +} diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs new file mode 100644 index 000000000..0daa17553 --- /dev/null +++ b/ethcore/src/client/mod.rs @@ -0,0 +1,102 @@ +// 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 . + +//! Blockchain database client. + +mod client; +mod config; +mod ids; + +pub use self::client::*; +pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; +pub use self::ids::{BlockId, TransactionId}; + +use util::bytes::Bytes; +use util::hash::{Address, H256, H2048}; +use util::numbers::U256; +use blockchain::TreeRoute; +use block_queue::BlockQueueInfo; +use header::BlockNumber; +use transaction::LocalizedTransaction; +use log_entry::LocalizedLogEntry; +use filter::Filter; +use error::ImportResult; + +/// Blockchain database client. Owns and manages a blockchain and a block queue. +pub trait BlockChainClient : Sync + Send { + /// Get raw block header data by block id. + fn block_header(&self, id: BlockId) -> Option; + + /// Get raw block body data by block id. + /// Block body is an RLP list of two items: uncles and transactions. + fn block_body(&self, id: BlockId) -> Option; + + /// Get raw block data by block header hash. + fn block(&self, id: BlockId) -> Option; + + /// Get block status by block header hash. + fn block_status(&self, id: BlockId) -> BlockStatus; + + /// Get block total difficulty. + fn block_total_difficulty(&self, id: BlockId) -> Option; + + /// Get address nonce. + fn nonce(&self, address: &Address) -> U256; + + /// Get block hash. + fn block_hash(&self, id: BlockId) -> Option; + + /// Get address code. + fn code(&self, address: &Address) -> Option; + + /// Get transaction with given hash. + fn transaction(&self, id: TransactionId) -> Option; + + /// Get a tree route between `from` and `to`. + /// See `BlockChain::tree_route`. + fn tree_route(&self, from: &H256, to: &H256) -> Option; + + /// Get latest state node + fn state_data(&self, hash: &H256) -> Option; + + /// Get raw block receipts data by block header hash. + fn block_receipts(&self, hash: &H256) -> Option; + + /// Import a block into the blockchain. + fn import_block(&self, bytes: Bytes) -> ImportResult; + + /// Get block queue information. + fn queue_info(&self) -> BlockQueueInfo; + + /// Clear block queue and abort all import activity. + fn clear_queue(&self); + + /// Get blockchain information. + fn chain_info(&self) -> BlockChainInfo; + + /// Get the best block header. + fn best_block_header(&self) -> Bytes { + // TODO: lock blockchain only once + self.block_header(BlockId::Hash(self.chain_info().best_block_hash)).unwrap() + } + + /// Returns numbers of blocks containing given bloom. + fn blocks_with_bloom(&self, bloom: &H2048, from_block: BlockId, to_block: BlockId) -> Option>; + + /// Returns logs matching given filter. + fn logs(&self, filter: Filter) -> Vec; +} + From 094ae4e9f9a77708c15751afa17c4835e1fb16a0 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 19:15:10 +0400 Subject: [PATCH 12/27] personal is back to the master ver --- rpc/src/v1/impls/personal.rs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index a2788b9d9..48e1b1c6a 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -18,27 +18,28 @@ use std::sync::{Arc, Weak}; use jsonrpc_core::*; use v1::traits::Personal; +use util::keys::store::*; use util::Address; -use ethcore::client::Client; +use std::sync::RwLock; /// Account management (personal) rpc implementation. pub struct PersonalClient { - client: Weak, + secret_store: Weak>, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(client: &Arc) -> Self { + pub fn new(store: &Arc>) -> Self { PersonalClient { - client: Arc::downgrade(client), + secret_store: Arc::downgrade(store), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let client = take_weak!(self.client); - let store = client.secret_store().read().unwrap(); + let store_wk = take_weak!(self.secret_store); + let store = store_wk.read().unwrap(); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() @@ -53,8 +54,8 @@ impl Personal for PersonalClient { fn new_account(&self, params: Params) -> Result { from_params::<(String, )>(params).and_then( |(pass, )| { - let client = take_weak!(self.client); - let mut store = client.secret_store().write().unwrap(); + let store_wk = take_weak!(self.secret_store); + let mut store = store_wk.write().unwrap(); match store.new_account(&pass) { Ok(address) => Ok(Value::String(format!("{:?}", address))), Err(_) => Err(Error::internal_error()) @@ -66,8 +67,8 @@ impl Personal for PersonalClient { fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let client = take_weak!(self.client); - let store = client.secret_store().read().unwrap(); + let store_wk = take_weak!(self.secret_store); + let store = store_wk.read().unwrap(); match store.unlock_account(&account, &account_pass) { Ok(_) => Ok(Value::Bool(true)), Err(_) => Ok(Value::Bool(false)), From 5571503c224b5d1b185243d7f5e6f1f1bc3a6856 Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 20:18:01 +0400 Subject: [PATCH 13/27] traitified secret store --- rpc/src/v1/impls/eth.rs | 16 +++++++++------- util/src/keys/store.rs | 22 ++++++++++++++++++---- 2 files changed, 27 insertions(+), 11 deletions(-) diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 4a8461c45..97d248ef6 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -30,20 +30,23 @@ use ethcore::ethereum::denominations::shannon; use v1::traits::{Eth, EthFilter}; use v1::types::{Block, BlockTransactions, BlockNumber, Bytes, SyncStatus, SyncInfo, Transaction, TransactionRequest, OptionalValue, Index, Filter, Log}; use v1::helpers::{PollFilter, PollManager}; +use util::keys::store::AccountProvider; /// Eth rpc implementation. -pub struct EthClient where C: BlockChainClient, S: SyncStatusProvider { +pub struct EthClient where C: BlockChainClient, S: SyncStatusProvider, A: AccountProvider { client: Weak, sync: Weak, + accounts: Weak, hashrates: RwLock>, } -impl EthClient where C: BlockChainClient, S: SyncStatusProvider { +impl EthClient where C: BlockChainClient, S: SyncStatusProvider, A: AccountProvider { /// Creates new EthClient. - pub fn new(client: &Arc, sync: &Arc) -> Self { + pub fn new(client: &Arc, sync: &Arc, accounts: &Arc) -> Self { EthClient { client: Arc::downgrade(client), sync: Arc::downgrade(sync), + accounts: Arc::downgrade(accounts), hashrates: RwLock::new(HashMap::new()), } } @@ -94,7 +97,7 @@ impl EthClient where C: BlockChainClient, S: SyncStatusProvider { } } -impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncStatusProvider + 'static { +impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncStatusProvider + 'static, A: AccountProvider + 'static { fn protocol_version(&self, params: Params) -> Result { match params { Params::None => to_value(&U256::from(take_weak!(self.sync).status().protocol_version)), @@ -256,9 +259,8 @@ impl Eth for EthClient where C: BlockChainClient + 'static, S: SyncS fn send_transaction(&self, params: Params) -> Result { from_params::<(TransactionRequest, )>(params) .and_then(|(transaction_request, )| { - let client = take_weak!(self.client); - let store = client.secret_store().read().unwrap(); - match store.account_secret(&transaction_request.from) { + let accounts = take_weak!(self.accounts); + match accounts.account_secret(&transaction_request.from) { Ok(secret) => { let sync = take_weak!(self.sync); let (transaction, _) = transaction_request.to_eth(); diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index dcc165259..9ea00cbba 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -78,6 +78,18 @@ struct AccountUnlock { expires: DateTime, } +/// Basic account management trait +pub trait AccountProvider : Send + Sync { + /// Unlocks account with the password provided + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError>; + /// Creates account + fn new_account(&mut self, pass: &str) -> Result; + /// Returns secret for unlocked account + fn account_secret(&self, account: &Address) -> Result; + /// Returns secret for unlocked account + fn sign(&self, account: &Address, message: &H256) -> Result; +} + impl SecretStore { /// new instance of Secret Store in default home directory pub fn new() -> SecretStore { @@ -144,9 +156,11 @@ impl SecretStore { unlocks: RwLock::new(HashMap::new()), } } +} +impl AccountProvider for SecretStore { /// Unlocks account for use - pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); let secret = try!(self.get(&secret_id, pass)); { @@ -160,7 +174,7 @@ impl SecretStore { } /// Creates new account - pub fn new_account(&mut self, pass: &str) -> Result { + fn new_account(&mut self, pass: &str) -> Result { let secret = H256::random(); let key_id = H128::random(); self.insert(key_id.clone(), secret, pass); @@ -173,7 +187,7 @@ impl SecretStore { } /// Signs message with unlocked account - pub fn sign(&self, account: &Address, message: &H256) -> Result { + fn sign(&self, account: &Address, message: &H256) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); match crypto::KeyPair::from_secret(unlock.secret) { @@ -186,7 +200,7 @@ impl SecretStore { } /// Returns secret for unlocked account - pub fn account_secret(&self, account: &Address) -> Result { + fn account_secret(&self, account: &Address) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); Ok(unlock.secret as crypto::Secret) From 84a48142defadd8b48654299c5d4d532f992261d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 19:50:04 +0100 Subject: [PATCH 14/27] Add more geth options. --- parity/main.rs | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 68d45bc04..cced0ed0f 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -70,9 +70,9 @@ Parity. Ethereum Client. Copyright 2015, 2016 Ethcore (UK) Limited Usage: - parity daemon [options] [ --no-bootstrap | ... ] + parity daemon [options] parity account (new | list) - parity [options] [ --no-bootstrap | ... ] + parity [options] Protocol Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file @@ -85,13 +85,13 @@ Protocol Options: --identity NAME Specify your node's name. Networking Options: - --no-bootstrap Don't bother trying to connect to any nodes initially. - --listen-address URL Specify the IP/port on which to listen for peers [default: 0.0.0.0:30304]. - --public-address URL Specify the IP/port on which peers may connect. - --address URL Equivalent to --listen-address URL --public-address URL. - --peers NUM Try to maintain that many peers [default: 25]. + --no-bootstrap Don't bother trying to connect to standard bootnodes. + --bootnodes NODES Specify additional comma-separated bootnodes. --no-discovery Disable new peer discovery. - --no-upnp Disable trying to figure out the correct public adderss over UPnP. + --peers NUM Try to maintain that many peers [default: 25]. + --port PORT Override the port for the node to listen on, supercedes --address. + --nat METHOD Specify method to use for determining public address. Must be one of: any, none, + upnp, extip:(IP) [default: upnp]. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. API and Console Options: @@ -101,16 +101,11 @@ API and Console Options: --jsonrpc-cors URL Specify CORS header for JSON-RPC API responses [default: null]. --jsonrpc-apis APIS Specify the APIs available through the JSONRPC interface. APIS is a comma-delimited list of API name. Possible name are web3, eth and net. [default: web3,eth,net]. - --rpc Equivalent to --jsonrpc (geth-compatible). - --rpcaddr HOST Equivalent to --jsonrpc-addr HOST (geth-compatible). - --rpcport PORT Equivalent to --jsonrpc-port PORT (geth-compatible). - --rpcapi APIS Equivalent to --jsonrpc-apis APIS (geth-compatible). - --rpccorsdomain URL Equivalent to --jsonrpc-cors URL (geth-compatible). Sealing/Mining Options: --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. + --extra-data STRING Specify a custom extra-data for authored blocks, no more than 32 characters. Memory Footprint Options: --cache-pref-size BYTES Specify the prefered size of the blockchain cache in bytes [default: 16384]. @@ -119,6 +114,18 @@ Memory Footprint Options: --cache MEGABYTES Set total amount of cache to use for the entire system, mutually exclusive with other cache options (geth-compatible). +Geth-Compatibility Options + --rpc Equivalent to --jsonrpc. + --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. + --rpcport PORT Equivalent to --jsonrpc-port PORT. + --rpcapi APIS Equivalent to --jsonrpc-apis APIS. + --rpccorsdomain URL Equivalent to --jsonrpc-cors URL. + --maxpeers COUNT Equivalent to --peers COUNT. + --nodekey KEY Equivalent to --node-key KEY. + --nodiscover Equivalent to --no-discovery. + --etherbase ADDRESS Equivalent to --author ADDRESS. + --extradata STRING Equivalent to --extra-data STRING. + Miscellaneous Options: -l --logging LOGGING Specify the logging level. -v --version Show information about version. @@ -145,7 +152,7 @@ struct Args { flag_listen_address: String, flag_public_address: Option, flag_address: Option, - flag_peers: usize, + flag_maxpeers: usize, flag_no_discovery: bool, flag_no_upnp: bool, flag_node_key: Option, @@ -323,7 +330,7 @@ impl Configuration { ret.public_address = public; ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); ret.discovery_enabled = !self.args.flag_no_discovery; - ret.ideal_peers = self.args.flag_peers as u32; + ret.ideal_peers = self.args.flag_maxpeers as u32; let mut net_path = PathBuf::from(&self.path()); net_path.push("network"); ret.config_path = Some(net_path.to_str().unwrap().to_owned()); From a2dea3885b393da47dad0127f22773b7fcae00bc Mon Sep 17 00:00:00 2001 From: Nikolay Volf Date: Thu, 10 Mar 2016 23:09:45 +0400 Subject: [PATCH 15/27] refactoring to AccountService --- parity/main.rs | 10 ++----- rpc/src/v1/impls/personal.rs | 18 +++++------- util/src/keys/store.rs | 53 +++++++++++++++++++++++++++++++----- 3 files changed, 56 insertions(+), 25 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 6d1c08162..b6ed5cba3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -196,7 +196,7 @@ fn setup_log(init: &Option) { } #[cfg(feature = "rpc")] -fn setup_rpc_server(client: Arc, sync: Arc, secret_store: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option> { +fn setup_rpc_server(client: Arc, sync: Arc, secret_store: Arc, url: &str, cors_domain: &str, apis: Vec<&str>) -> Option> { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -416,11 +416,7 @@ impl Configuration { let sync = EthSync::register(service.network(), sync_config, client); // Secret Store - let secret_store = Arc::new(SecretStore::new()); - { - let import_ref = Arc::make_mut(&mut secret_store); - import_ref.try_import_existing(); - } + let account_service = Arc::new(AccountService::new()); // Setup rpc if self.args.flag_jsonrpc || self.args.flag_rpc { @@ -432,7 +428,7 @@ impl Configuration { 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); - let server_handler = setup_rpc_server(service.client(), sync.clone(), secret_store.clone(), &url, cors, apis.split(",").collect()); + let server_handler = setup_rpc_server(service.client(), sync.clone(), account_service.clone(), &url, cors, apis.split(",").collect()); if let Some(handler) = server_handler { panic_handler.forward_from(handler.deref()); } diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 48e1b1c6a..7b79ceae7 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -20,30 +20,28 @@ use jsonrpc_core::*; use v1::traits::Personal; use util::keys::store::*; use util::Address; -use std::sync::RwLock; /// Account management (personal) rpc implementation. pub struct PersonalClient { - secret_store: Weak>, + accounts: Weak, } impl PersonalClient { /// Creates new PersonalClient - pub fn new(store: &Arc>) -> Self { + pub fn new(store: &Arc) -> Self { PersonalClient { - secret_store: Arc::downgrade(store), + accounts: Arc::downgrade(store), } } } impl Personal for PersonalClient { fn accounts(&self, _: Params) -> Result { - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let store = take_weak!(self.accounts); match store.accounts() { Ok(account_list) => { Ok(Value::Array(account_list.iter() - .map(|&(account, _)| Value::String(format!("{:?}", account))) + .map(|&account| Value::String(format!("{:?}", account))) .collect::>()) ) } @@ -54,8 +52,7 @@ impl Personal for PersonalClient { fn new_account(&self, params: Params) -> Result { from_params::<(String, )>(params).and_then( |(pass, )| { - let store_wk = take_weak!(self.secret_store); - let mut store = store_wk.write().unwrap(); + let store = take_weak!(self.accounts); match store.new_account(&pass) { Ok(address) => Ok(Value::String(format!("{:?}", address))), Err(_) => Err(Error::internal_error()) @@ -67,8 +64,7 @@ impl Personal for PersonalClient { fn unlock_account(&self, params: Params) -> Result { from_params::<(Address, String, u64)>(params).and_then( |(account, account_pass, _)|{ - let store_wk = take_weak!(self.secret_store); - let store = store_wk.read().unwrap(); + let store = take_weak!(self.accounts); match store.unlock_account(&account, &account_pass) { Ok(_) => Ok(Value::Bool(true)), Err(_) => Ok(Value::Bool(false)), diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index 9ea00cbba..ea97cc80e 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -80,16 +80,57 @@ struct AccountUnlock { /// Basic account management trait pub trait AccountProvider : Send + Sync { + /// Lists all accounts + fn accounts(&self) -> Result, ::std::io::Error>; /// Unlocks account with the password provided fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError>; /// Creates account - fn new_account(&mut self, pass: &str) -> Result; + fn new_account(&self, pass: &str) -> Result; /// Returns secret for unlocked account fn account_secret(&self, account: &Address) -> Result; /// Returns secret for unlocked account fn sign(&self, account: &Address, message: &H256) -> Result; } +/// Thread-safe accounts management +pub struct AccountService { + secret_store: RwLock, +} + +impl AccountProvider for AccountService { + /// Lists all accounts + fn accounts(&self) -> Result, ::std::io::Error> { + Ok(try!(self.secret_store.read().unwrap().accounts()).iter().map(|&(addr, _)| addr).collect::>()) + } + /// Unlocks account with the password provided + fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + self.secret_store.read().unwrap().unlock_account(account, pass) + } + /// Creates account + fn new_account(&self, pass: &str) -> Result { + self.secret_store.write().unwrap().new_account(pass) + } + /// Returns secret for unlocked account + fn account_secret(&self, account: &Address) -> Result { + self.secret_store.read().unwrap().account_secret(account) + } + /// Returns secret for unlocked account + fn sign(&self, account: &Address, message: &H256) -> Result { + self.secret_store.read().unwrap().sign(account, message) + } +} + +impl AccountService { + /// New account service with the default location + pub fn new() -> AccountService { + let secret_store = RwLock::new(SecretStore::new()); + secret_store.write().unwrap().try_import_existing(); + AccountService { + secret_store: secret_store + } + } +} + impl SecretStore { /// new instance of Secret Store in default home directory pub fn new() -> SecretStore { @@ -156,11 +197,9 @@ impl SecretStore { unlocks: RwLock::new(HashMap::new()), } } -} -impl AccountProvider for SecretStore { /// Unlocks account for use - fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { + pub fn unlock_account(&self, account: &Address, pass: &str) -> Result<(), EncryptedHashMapError> { let secret_id = try!(self.account(&account).ok_or(EncryptedHashMapError::UnknownIdentifier)); let secret = try!(self.get(&secret_id, pass)); { @@ -174,7 +213,7 @@ impl AccountProvider for SecretStore { } /// Creates new account - fn new_account(&mut self, pass: &str) -> Result { + pub fn new_account(&mut self, pass: &str) -> Result { let secret = H256::random(); let key_id = H128::random(); self.insert(key_id.clone(), secret, pass); @@ -187,7 +226,7 @@ impl AccountProvider for SecretStore { } /// Signs message with unlocked account - fn sign(&self, account: &Address, message: &H256) -> Result { + pub fn sign(&self, account: &Address, message: &H256) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); match crypto::KeyPair::from_secret(unlock.secret) { @@ -200,7 +239,7 @@ impl AccountProvider for SecretStore { } /// Returns secret for unlocked account - fn account_secret(&self, account: &Address) -> Result { + pub fn account_secret(&self, account: &Address) -> Result { let read_lock = self.unlocks.read().unwrap(); let unlock = try!(read_lock.get(account).ok_or(SigningError::AccountNotUnlocked)); Ok(unlock.secret as crypto::Secret) From c5c8851b5097e27ccadc43b579dd8f605b9c9733 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 10 Mar 2016 20:27:50 +0100 Subject: [PATCH 16/27] moved TestBlockChainClient to ethcore --- ethcore/src/client/mod.rs | 2 + ethcore/src/client/test_client.rs | 322 ++++++++++++++++++++++++++++++ ethcore/src/lib.rs | 2 +- sync/src/tests/chain.rs | 2 +- sync/src/tests/helpers.rs | 292 +-------------------------- 5 files changed, 327 insertions(+), 293 deletions(-) create mode 100644 ethcore/src/client/test_client.rs diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 0daa17553..58a21f151 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -19,10 +19,12 @@ mod client; mod config; mod ids; +mod test_client; pub use self::client::*; pub use self::config::{ClientConfig, BlockQueueConfig, BlockChainConfig}; pub use self::ids::{BlockId, TransactionId}; +pub use self::test_client::{TestBlockChainClient, EachBlockWith}; use util::bytes::Bytes; use util::hash::{Address, H256, H2048}; diff --git a/ethcore/src/client/test_client.rs b/ethcore/src/client/test_client.rs new file mode 100644 index 000000000..4ca30dcd5 --- /dev/null +++ b/ethcore/src/client/test_client.rs @@ -0,0 +1,322 @@ +// 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 . + +//use std::mem; +//use std::ops::{Deref, DerefMut}; +//use std::collections::HashMap; +//use rustc_serialize::hex::FromHex; +//use util::rlp; +//use util::rlp::*; +//use util::bytes::Bytes; +//use util::hash::{FixedHash, Address, H256, H2048}; +//use util::numbers::{Uint, U256}; +//use util::crypto::KeyPair; +//use util::sha3::Hashable; +use util::*; +//use std::sync::RwLock; +use transaction::{Transaction, LocalizedTransaction, Action}; +use blockchain::TreeRoute; +use client::{BlockChainClient, BlockChainInfo, BlockStatus, BlockId, TransactionId}; +use header::{Header as BlockHeader, BlockNumber}; +use filter::Filter; +use log_entry::LocalizedLogEntry; +use receipt::Receipt; +use error::ImportResult; +use block_queue::BlockQueueInfo; + +pub struct TestBlockChainClient { + pub blocks: RwLock>, + pub numbers: RwLock>, + pub genesis_hash: H256, + pub last_hash: RwLock, + pub difficulty: RwLock, +} + +#[derive(Clone)] +pub enum EachBlockWith { + Nothing, + Uncle, + Transaction, + UncleAndTransaction +} + +impl TestBlockChainClient { + pub fn new() -> TestBlockChainClient { + + let mut client = TestBlockChainClient { + blocks: RwLock::new(HashMap::new()), + numbers: RwLock::new(HashMap::new()), + genesis_hash: H256::new(), + last_hash: RwLock::new(H256::new()), + difficulty: RwLock::new(From::from(0)), + }; + client.add_blocks(1, EachBlockWith::Nothing); // add genesis block + client.genesis_hash = client.last_hash.read().unwrap().clone(); + client + } + + pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { + let len = self.numbers.read().unwrap().len(); + for n in len..(len + count) { + let mut header = BlockHeader::new(); + header.difficulty = From::from(n); + header.parent_hash = self.last_hash.read().unwrap().clone(); + header.number = n as BlockNumber; + let uncles = match with { + EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { + let mut uncles = RlpStream::new_list(1); + let mut uncle_header = BlockHeader::new(); + uncle_header.difficulty = From::from(n); + uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); + uncle_header.number = n as BlockNumber; + uncles.append(&uncle_header); + header.uncles_hash = uncles.as_raw().sha3(); + uncles + }, + _ => RlpStream::new_list(0) + }; + let txs = match with { + EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { + let mut txs = RlpStream::new_list(1); + let keypair = KeyPair::create().unwrap(); + let tx = Transaction { + action: Action::Create, + value: U256::from(100), + data: "3331600055".from_hex().unwrap(), + gas: U256::from(100_000), + gas_price: U256::one(), + nonce: U256::zero() + }; + let signed_tx = tx.sign(&keypair.secret()); + txs.append(&signed_tx); + txs.out() + }, + _ => rlp::NULL_RLP.to_vec() + }; + + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&txs, 1); + rlp.append_raw(uncles.as_raw(), 1); + self.import_block(rlp.as_raw().to_vec()).unwrap(); + } + } + + pub fn corrupt_block(&mut self, n: BlockNumber) { + let hash = self.block_hash(BlockId::Number(n)).unwrap(); + let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); + header.parent_hash = H256::new(); + let mut rlp = RlpStream::new_list(3); + rlp.append(&header); + rlp.append_raw(&rlp::NULL_RLP, 1); + rlp.append_raw(&rlp::NULL_RLP, 1); + self.blocks.write().unwrap().insert(hash, rlp.out()); + } + + pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { + let blocks_read = self.numbers.read().unwrap(); + let index = blocks_read.len() - delta; + blocks_read[&index].clone() + } + + fn block_hash(&self, id: BlockId) -> Option { + match id { + BlockId::Hash(hash) => Some(hash), + BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), + BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), + BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() + } + } +} + +impl BlockChainClient for TestBlockChainClient { + fn block_total_difficulty(&self, _id: BlockId) -> Option { + Some(U256::zero()) + } + + fn block_hash(&self, _id: BlockId) -> Option { + unimplemented!(); + } + + fn nonce(&self, _address: &Address) -> U256 { + U256::zero() + } + + fn code(&self, _address: &Address) -> Option { + unimplemented!(); + } + + fn transaction(&self, _id: TransactionId) -> Option { + unimplemented!(); + } + + fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { + unimplemented!(); + } + + fn logs(&self, _filter: Filter) -> Vec { + unimplemented!(); + } + + fn block_header(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) + } + + fn block_body(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { + let mut stream = RlpStream::new_list(2); + stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); + stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); + stream.out() + })) + } + + fn block(&self, id: BlockId) -> Option { + self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) + } + + fn block_status(&self, id: BlockId) -> BlockStatus { + match id { + BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, + BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, + _ => BlockStatus::Unknown + } + } + + // works only if blocks are one after another 1 -> 2 -> 3 + fn tree_route(&self, from: &H256, to: &H256) -> Option { + Some(TreeRoute { + ancestor: H256::new(), + index: 0, + blocks: { + let numbers_read = self.numbers.read().unwrap(); + let mut adding = false; + + let mut blocks = Vec::new(); + for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { + if hash == to { + if adding { + blocks.push(hash.clone()); + } + adding = false; + break; + } + if hash == from { + adding = true; + } + if adding { + blocks.push(hash.clone()); + } + } + if adding { Vec::new() } else { blocks } + } + }) + } + + // TODO: returns just hashes instead of node state rlp(?) + fn state_data(&self, hash: &H256) -> Option { + // starts with 'f' ? + if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { + let mut rlp = RlpStream::new(); + rlp.append(&hash.clone()); + return Some(rlp.out()); + } + None + } + + fn block_receipts(&self, hash: &H256) -> Option { + // starts with 'f' ? + if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { + let receipt = Receipt::new( + H256::zero(), + U256::zero(), + vec![]); + let mut rlp = RlpStream::new(); + rlp.append(&receipt); + return Some(rlp.out()); + } + None + } + + fn import_block(&self, b: Bytes) -> ImportResult { + let header = Rlp::new(&b).val_at::(0); + let h = header.hash(); + let number: usize = header.number as usize; + if number > self.blocks.read().unwrap().len() { + panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); + } + if number > 0 { + match self.blocks.read().unwrap().get(&header.parent_hash) { + Some(parent) => { + let parent = Rlp::new(parent).val_at::(0); + if parent.number != (header.number - 1) { + panic!("Unexpected block parent"); + } + }, + None => { + panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); + } + } + } + let len = self.numbers.read().unwrap().len(); + if number == len { + { + let mut difficulty = self.difficulty.write().unwrap(); + *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; + } + mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); + self.blocks.write().unwrap().insert(h.clone(), b); + self.numbers.write().unwrap().insert(number, h.clone()); + let mut parent_hash = header.parent_hash; + if number > 0 { + let mut n = number - 1; + while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { + *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); + n -= 1; + parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; + } + } + } + else { + self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); + } + Ok(h) + } + + fn queue_info(&self) -> BlockQueueInfo { + BlockQueueInfo { + verified_queue_size: 0, + unverified_queue_size: 0, + verifying_queue_size: 0, + max_queue_size: 0, + max_mem_use: 0, + mem_used: 0, + } + } + + fn clear_queue(&self) { + } + + fn chain_info(&self) -> BlockChainInfo { + BlockChainInfo { + total_difficulty: *self.difficulty.read().unwrap(), + pending_total_difficulty: *self.difficulty.read().unwrap(), + genesis_hash: self.genesis_hash.clone(), + best_block_hash: self.last_hash.read().unwrap().clone(), + best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, + } + } +} diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 469364eb3..0ff5c1903 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -86,6 +86,7 @@ extern crate crossbeam; #[cfg(feature = "jit" )] extern crate evmjit; pub mod block; +pub mod block_queue; pub mod client; pub mod error; pub mod ethereum; @@ -119,7 +120,6 @@ mod substate; mod executive; mod externalities; mod verification; -mod block_queue; mod blockchain; #[cfg(test)] diff --git a/sync/src/tests/chain.rs b/sync/src/tests/chain.rs index 855aa79a6..eebbdb164 100644 --- a/sync/src/tests/chain.rs +++ b/sync/src/tests/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockId}; +use ethcore::client::{BlockChainClient, BlockId, EachBlockWith}; use io::SyncIo; use chain::{SyncState}; use super::helpers::*; diff --git a/sync/src/tests/helpers.rs b/sync/src/tests/helpers.rs index d01dba0b2..ca4ae5158 100644 --- a/sync/src/tests/helpers.rs +++ b/sync/src/tests/helpers.rs @@ -15,300 +15,10 @@ // along with Parity. If not, see . use util::*; -use ethcore::client::{BlockChainClient, BlockStatus, TreeRoute, BlockChainInfo, TransactionId, BlockId, BlockQueueInfo}; -use ethcore::header::{Header as BlockHeader, BlockNumber}; -use ethcore::error::*; +use ethcore::client::{TestBlockChainClient, BlockChainClient}; use io::SyncIo; use chain::ChainSync; use ::SyncConfig; -use ethcore::receipt::Receipt; -use ethcore::transaction::{LocalizedTransaction, Transaction, Action}; -use ethcore::filter::Filter; -use ethcore::log_entry::LocalizedLogEntry; - -pub struct TestBlockChainClient { - pub blocks: RwLock>, - pub numbers: RwLock>, - pub genesis_hash: H256, - pub last_hash: RwLock, - pub difficulty: RwLock, -} - -#[derive(Clone)] -pub enum EachBlockWith { - Nothing, - Uncle, - Transaction, - UncleAndTransaction -} - -impl TestBlockChainClient { - pub fn new() -> TestBlockChainClient { - - let mut client = TestBlockChainClient { - blocks: RwLock::new(HashMap::new()), - numbers: RwLock::new(HashMap::new()), - genesis_hash: H256::new(), - last_hash: RwLock::new(H256::new()), - difficulty: RwLock::new(From::from(0)), - }; - client.add_blocks(1, EachBlockWith::Nothing); // add genesis block - client.genesis_hash = client.last_hash.read().unwrap().clone(); - client - } - - pub fn add_blocks(&mut self, count: usize, with: EachBlockWith) { - let len = self.numbers.read().unwrap().len(); - for n in len..(len + count) { - let mut header = BlockHeader::new(); - header.difficulty = From::from(n); - header.parent_hash = self.last_hash.read().unwrap().clone(); - header.number = n as BlockNumber; - let uncles = match with { - EachBlockWith::Uncle | EachBlockWith::UncleAndTransaction => { - let mut uncles = RlpStream::new_list(1); - let mut uncle_header = BlockHeader::new(); - uncle_header.difficulty = From::from(n); - uncle_header.parent_hash = self.last_hash.read().unwrap().clone(); - uncle_header.number = n as BlockNumber; - uncles.append(&uncle_header); - header.uncles_hash = uncles.as_raw().sha3(); - uncles - }, - _ => RlpStream::new_list(0) - }; - let txs = match with { - EachBlockWith::Transaction | EachBlockWith::UncleAndTransaction => { - let mut txs = RlpStream::new_list(1); - let keypair = KeyPair::create().unwrap(); - let tx = Transaction { - action: Action::Create, - value: U256::from(100), - data: "3331600055".from_hex().unwrap(), - gas: U256::from(100_000), - gas_price: U256::one(), - nonce: U256::zero() - }; - let signed_tx = tx.sign(&keypair.secret()); - txs.append(&signed_tx); - txs.out() - }, - _ => rlp::NULL_RLP.to_vec() - }; - - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&txs, 1); - rlp.append_raw(uncles.as_raw(), 1); - self.import_block(rlp.as_raw().to_vec()).unwrap(); - } - } - - pub fn corrupt_block(&mut self, n: BlockNumber) { - let hash = self.block_hash(BlockId::Number(n)).unwrap(); - let mut header: BlockHeader = decode(&self.block_header(BlockId::Number(n)).unwrap()); - header.parent_hash = H256::new(); - let mut rlp = RlpStream::new_list(3); - rlp.append(&header); - rlp.append_raw(&rlp::NULL_RLP, 1); - rlp.append_raw(&rlp::NULL_RLP, 1); - self.blocks.write().unwrap().insert(hash, rlp.out()); - } - - pub fn block_hash_delta_minus(&mut self, delta: usize) -> H256 { - let blocks_read = self.numbers.read().unwrap(); - let index = blocks_read.len() - delta; - blocks_read[&index].clone() - } - - fn block_hash(&self, id: BlockId) -> Option { - match id { - BlockId::Hash(hash) => Some(hash), - BlockId::Number(n) => self.numbers.read().unwrap().get(&(n as usize)).cloned(), - BlockId::Earliest => self.numbers.read().unwrap().get(&0).cloned(), - BlockId::Latest => self.numbers.read().unwrap().get(&(self.numbers.read().unwrap().len() - 1)).cloned() - } - } -} - -impl BlockChainClient for TestBlockChainClient { - fn block_total_difficulty(&self, _id: BlockId) -> Option { - Some(U256::zero()) - } - - fn block_hash(&self, _id: BlockId) -> Option { - unimplemented!(); - } - - fn nonce(&self, _address: &Address) -> U256 { - U256::zero() - } - - fn code(&self, _address: &Address) -> Option { - unimplemented!(); - } - - fn transaction(&self, _id: TransactionId) -> Option { - unimplemented!(); - } - - fn blocks_with_bloom(&self, _bloom: &H2048, _from_block: BlockId, _to_block: BlockId) -> Option> { - unimplemented!(); - } - - fn logs(&self, _filter: Filter) -> Vec { - unimplemented!(); - } - - fn block_header(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| Rlp::new(r).at(0).as_raw().to_vec())) - } - - fn block_body(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).map(|r| { - let mut stream = RlpStream::new_list(2); - stream.append_raw(Rlp::new(&r).at(1).as_raw(), 1); - stream.append_raw(Rlp::new(&r).at(2).as_raw(), 1); - stream.out() - })) - } - - fn block(&self, id: BlockId) -> Option { - self.block_hash(id).and_then(|hash| self.blocks.read().unwrap().get(&hash).cloned()) - } - - fn block_status(&self, id: BlockId) -> BlockStatus { - match id { - BlockId::Number(number) if (number as usize) < self.blocks.read().unwrap().len() => BlockStatus::InChain, - BlockId::Hash(ref hash) if self.blocks.read().unwrap().get(hash).is_some() => BlockStatus::InChain, - _ => BlockStatus::Unknown - } - } - - // works only if blocks are one after another 1 -> 2 -> 3 - fn tree_route(&self, from: &H256, to: &H256) -> Option { - Some(TreeRoute { - ancestor: H256::new(), - index: 0, - blocks: { - let numbers_read = self.numbers.read().unwrap(); - let mut adding = false; - - let mut blocks = Vec::new(); - for (_, hash) in numbers_read.iter().sort_by(|tuple1, tuple2| tuple1.0.cmp(tuple2.0)) { - if hash == to { - if adding { - blocks.push(hash.clone()); - } - adding = false; - break; - } - if hash == from { - adding = true; - } - if adding { - blocks.push(hash.clone()); - } - } - if adding { Vec::new() } else { blocks } - } - }) - } - - // TODO: returns just hashes instead of node state rlp(?) - fn state_data(&self, hash: &H256) -> Option { - // starts with 'f' ? - if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let mut rlp = RlpStream::new(); - rlp.append(&hash.clone()); - return Some(rlp.out()); - } - None - } - - fn block_receipts(&self, hash: &H256) -> Option { - // starts with 'f' ? - if *hash > H256::from("f000000000000000000000000000000000000000000000000000000000000000") { - let receipt = Receipt::new( - H256::zero(), - U256::zero(), - vec![]); - let mut rlp = RlpStream::new(); - rlp.append(&receipt); - return Some(rlp.out()); - } - None - } - - fn import_block(&self, b: Bytes) -> ImportResult { - let header = Rlp::new(&b).val_at::(0); - let h = header.hash(); - let number: usize = header.number as usize; - if number > self.blocks.read().unwrap().len() { - panic!("Unexpected block number. Expected {}, got {}", self.blocks.read().unwrap().len(), number); - } - if number > 0 { - match self.blocks.read().unwrap().get(&header.parent_hash) { - Some(parent) => { - let parent = Rlp::new(parent).val_at::(0); - if parent.number != (header.number - 1) { - panic!("Unexpected block parent"); - } - }, - None => { - panic!("Unknown block parent {:?} for block {}", header.parent_hash, number); - } - } - } - let len = self.numbers.read().unwrap().len(); - if number == len { - { - let mut difficulty = self.difficulty.write().unwrap(); - *difficulty.deref_mut() = *difficulty.deref() + header.difficulty; - } - mem::replace(self.last_hash.write().unwrap().deref_mut(), h.clone()); - self.blocks.write().unwrap().insert(h.clone(), b); - self.numbers.write().unwrap().insert(number, h.clone()); - let mut parent_hash = header.parent_hash; - if number > 0 { - let mut n = number - 1; - while n > 0 && self.numbers.read().unwrap()[&n] != parent_hash { - *self.numbers.write().unwrap().get_mut(&n).unwrap() = parent_hash.clone(); - n -= 1; - parent_hash = Rlp::new(&self.blocks.read().unwrap()[&parent_hash]).val_at::(0).parent_hash; - } - } - } - else { - self.blocks.write().unwrap().insert(h.clone(), b.to_vec()); - } - Ok(h) - } - - fn queue_info(&self) -> BlockQueueInfo { - BlockQueueInfo { - verified_queue_size: 0, - unverified_queue_size: 0, - verifying_queue_size: 0, - max_queue_size: 0, - max_mem_use: 0, - mem_used: 0, - } - } - - fn clear_queue(&self) { - } - - fn chain_info(&self) -> BlockChainInfo { - BlockChainInfo { - total_difficulty: *self.difficulty.read().unwrap(), - pending_total_difficulty: *self.difficulty.read().unwrap(), - genesis_hash: self.genesis_hash.clone(), - best_block_hash: self.last_hash.read().unwrap().clone(), - best_block_number: self.blocks.read().unwrap().len() as BlockNumber - 1, - } - } -} pub struct TestIo<'p> { pub chain: &'p mut TestBlockChainClient, From 5f37f6edb442aa41097f7c014d2a0a08b20cb1f0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 10 Mar 2016 21:01:17 +0100 Subject: [PATCH 17/27] Correct cache update order --- ethcore/src/blockchain/blockchain.rs | 52 ++++++++++++++-------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8e56cdc5f..4ebd111d9 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -452,7 +452,32 @@ impl BlockChain { let batch = DBTransaction::new(); batch.put(b"best", &update.info.hash).unwrap(); - // These cached values must be updated atomically + { + let mut write_details = self.block_details.write().unwrap(); + for (hash, details) in update.block_details.into_iter() { + batch.put_extras(&hash, &details); + self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); + write_details.insert(hash, details); + } + } + + { + let mut write_receipts = self.block_receipts.write().unwrap(); + for (hash, receipt) in &update.block_receipts { + batch.put_extras(hash, receipt); + write_receipts.remove(hash); + } + } + + { + let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); + for (bloom_hash, blocks_bloom) in &update.blocks_blooms { + batch.put_extras(bloom_hash, blocks_bloom); + write_blocks_blooms.remove(bloom_hash); + } + } + + // These cached values must be updated last and togeterh { let mut best_block = self.best_block.write().unwrap(); let mut write_hashes = self.block_hashes.write().unwrap(); @@ -481,31 +506,6 @@ impl BlockChain { } } - { - let mut write_details = self.block_details.write().unwrap(); - for (hash, details) in update.block_details.into_iter() { - batch.put_extras(&hash, &details); - self.note_used(CacheID::Extras(ExtrasIndex::BlockDetails, hash.clone())); - write_details.insert(hash, details); - } - } - - { - let mut write_receipts = self.block_receipts.write().unwrap(); - for (hash, receipt) in &update.block_receipts { - batch.put_extras(hash, receipt); - write_receipts.remove(hash); - } - } - - { - let mut write_blocks_blooms = self.blocks_blooms.write().unwrap(); - for (bloom_hash, blocks_bloom) in &update.blocks_blooms { - batch.put_extras(bloom_hash, blocks_bloom); - write_blocks_blooms.remove(bloom_hash); - } - } - // update extras database self.extras_db.write(batch).unwrap(); } From 29916edb91092d95a5a08c10075bea2bb7098a3f Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Thu, 10 Mar 2016 21:36:45 +0100 Subject: [PATCH 18/27] More geth compatibility. --- parity/main.rs | 101 +++++++++++++++++++++++++------------------------ 1 file changed, 52 insertions(+), 49 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index cced0ed0f..402017f3c 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -37,7 +37,7 @@ extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; -use std::net::{SocketAddr}; +use std::net::{SocketAddr, IpAddr}; use std::env; use std::process::exit; use std::path::PathBuf; @@ -77,21 +77,19 @@ Usage: Protocol Options: --chain CHAIN Specify the blockchain type. CHAIN may be either a JSON chain specification file or olympic, frontier, homestead, mainnet, morden, or testnet [default: homestead]. - --testnet Equivalent to --chain testnet (geth-compatible). - --networkid INDEX Override the network identifier from the chain we are on. - --archive Client should not prune the state/storage trie. - -d --datadir PATH Specify the database & configuration directory path [default: $HOME/.parity] + --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity] --keys-path PATH Specify the path for JSON key files to be found [default: $HOME/.web3/keys] --identity NAME Specify your node's name. + --archive Client should not prune the state/storage trie. Networking Options: - --no-bootstrap Don't bother trying to connect to standard bootnodes. - --bootnodes NODES Specify additional comma-separated bootnodes. - --no-discovery Disable new peer discovery. + --port PORT Override the port on which the node should listen [default: 30303]. --peers NUM Try to maintain that many peers [default: 25]. - --port PORT Override the port for the node to listen on, supercedes --address. --nat METHOD Specify method to use for determining public address. Must be one of: any, none, - upnp, extip:(IP) [default: upnp]. + upnp, extip:(IP) [default: any]. + --bootnodes NODES Specify additional comma-separated bootnodes. + --no-bootstrap Don't bother trying to connect to standard bootnodes. + --no-discovery Disable new peer discovery. --node-key KEY Specify node secret key, either as 64-character hex string or input to SHA3 operation. API and Console Options: @@ -115,6 +113,9 @@ Memory Footprint Options: other cache options (geth-compatible). Geth-Compatibility Options + --datadir PATH Equivalent to --db-path PATH. + --testnet Equivalent to --chain testnet. + --networkid INDEX Override the network identifier from the chain we are on. --rpc Equivalent to --jsonrpc. --rpcaddr HOST Equivalent to --jsonrpc-addr HOST. --rpcport PORT Equivalent to --jsonrpc-port PORT. @@ -139,22 +140,18 @@ struct Args { cmd_new: bool, cmd_list: bool, arg_pid_file: String, - arg_enode: Vec, flag_chain: String, - flag_testnet: bool, - flag_datadir: String, - flag_networkid: Option, + flag_db_path: String, flag_identity: String, flag_cache: Option, flag_keys_path: String, flag_archive: bool, + flag_bootnodes: Option, flag_no_bootstrap: bool, - flag_listen_address: String, - flag_public_address: Option, - flag_address: Option, - flag_maxpeers: usize, + flag_port: u16, + flag_peers: usize, flag_no_discovery: bool, - flag_no_upnp: bool, + flag_nat: String, flag_node_key: Option, flag_cache_pref_size: usize, flag_cache_max_size: usize, @@ -164,15 +161,24 @@ struct Args { flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, + flag_logging: Option, + flag_version: bool, + // geth-compatibility... + flag_nodekey: Option, + flag_nodiscover: bool, + flag_maxpeers: Option, + flag_author: String, + flag_extra_data: Option, + flag_datadir: Option, + flag_extradata: Option, + flag_etherbase: Option, flag_rpc: bool, flag_rpcaddr: Option, flag_rpcport: Option, flag_rpccorsdomain: Option, flag_rpcapi: Option, - flag_logging: Option, - flag_version: bool, - flag_author: String, - flag_extra_data: Option, + flag_testnet: bool, + flag_networkid: Option, } fn setup_log(init: &Option) { @@ -252,15 +258,17 @@ impl Configuration { } fn path(&self) -> String { - self.args.flag_datadir.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) + let d = self.args.flag_datadir.as_ref().unwrap_or(&self.args.flag_db_path); + d.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } 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)) + let d = self.args.flag_etherbase.as_ref().unwrap_or(&self.args.flag_author); + Address::from_str(d).unwrap_or_else(|_| die!("{}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning.", self.args.flag_author)) } fn extra_data(&self) -> Bytes { - match self.args.flag_extra_data { + match self.args.flag_extradata.as_ref().or(self.args.flag_extra_data.as_ref()) { Some(ref x) if x.len() <= 32 => x.as_bytes().to_owned(), None => version_data(), Some(ref x) => { die!("{}: Extra data must be at most 32 characters.", x); } @@ -292,45 +300,40 @@ impl Configuration { } fn init_nodes(&self, spec: &Spec) -> Vec { - 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(), - } + let mut r = if self.args.flag_no_bootstrap { Vec::new() } else { spec.nodes().clone() }; + if let Some(ref x) = self.args.flag_bootnodes { + r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s)))); } + r } #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { - let mut listen_address = None; - let mut public_address = None; + let listen_address = Some(SocketAddr::new(IpAddr::from_str("127.0.0.1").unwrap(), self.args.flag_port)); + + let host = if self.args.flag_nat.starts_with("extip:") { + &self.args.flag_nat[6..] + } else { + "127.0.0.1" + }; + let public_address = Some(SocketAddr::new( + IpAddr::from_str(&host).unwrap_or_else(|_| die!("{}: Invalid host given with --net extip:", host)), + self.args.flag_port + )); - 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))); - 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))); - } - 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))); - } (listen_address, public_address) } fn net_settings(&self, spec: &Spec) -> NetworkConfiguration { let mut ret = NetworkConfiguration::new(); - ret.nat_enabled = !self.args.flag_no_upnp; + ret.nat_enabled = self.args.flag_nat == "any" || self.args.flag_nat == "upnp"; ret.boot_nodes = self.init_nodes(spec); let (listen, public) = self.net_addresses(); ret.listen_address = listen; ret.public_address = public; ret.use_secret = self.args.flag_node_key.as_ref().map(|s| Secret::from_str(&s).unwrap_or_else(|_| s.sha3())); - ret.discovery_enabled = !self.args.flag_no_discovery; - ret.ideal_peers = self.args.flag_maxpeers as u32; + ret.discovery_enabled = !self.args.flag_no_discovery && !self.args.flag_nodiscover; + ret.ideal_peers = self.args.flag_maxpeers.unwrap_or(self.args.flag_peers) as u32; let mut net_path = PathBuf::from(&self.path()); net_path.push("network"); ret.config_path = Some(net_path.to_str().unwrap().to_owned()); From d9c462a3d3bd5a15b5c8dc6c8424b85b4179349c Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Fri, 11 Mar 2016 10:05:27 +0100 Subject: [PATCH 19/27] Use proper listen address. Tidyups. --- parity/main.rs | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index d6c3516d0..732e94f02 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -302,25 +302,21 @@ impl Configuration { fn init_nodes(&self, spec: &Spec) -> Vec { let mut r = if self.args.flag_no_bootstrap { Vec::new() } else { spec.nodes().clone() }; if let Some(ref x) = self.args.flag_bootnodes { - r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(||die!("{}: Invalid node address format given for a boot node.", s)))); + r.extend(x.split(",").map(|s| Self::normalize_enode(s).unwrap_or_else(|| die!("{}: Invalid node address format given for a boot node.", s)))); } r } #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { - let listen_address = Some(SocketAddr::new(IpAddr::from_str("127.0.0.1").unwrap(), self.args.flag_port)); - - let host = if self.args.flag_nat.starts_with("extip:") { - &self.args.flag_nat[6..] + let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port)); + let public_address = if self.args.flag_nat.starts_with("extip:") { + let host = &self.args.flag_nat[6..]; + let host = IpAddr::from_str(host).unwrap_or_else(|_| die!("Invalid host given with `--nat extip:{}`", host)); + Some(SocketAddr::new(host, self.args.flag_port)) } else { - "127.0.0.1" + listen_address.clone() }; - let public_address = Some(SocketAddr::new( - IpAddr::from_str(&host).unwrap_or_else(|_| die!("{}: Invalid host given with --net extip:", host)), - self.args.flag_port - )); - (listen_address, public_address) } From 34a120e1270288ffafc3518f8a4fb681ee5cfdf2 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 10:17:20 +0100 Subject: [PATCH 20/27] net tests --- rpc/src/v1/impls/net.rs | 4 +- rpc/src/v1/mod.rs | 3 +- rpc/src/v1/tests/helpers/mod.rs | 19 ++++++++ rpc/src/v1/tests/helpers/sync_provider.rs | 57 +++++++++++++++++++++++ rpc/src/v1/tests/mod.rs | 21 ++++++++- rpc/src/v1/tests/net.rs | 52 +++++++++++++++++++++ sync/src/chain.rs | 1 + 7 files changed, 153 insertions(+), 4 deletions(-) create mode 100644 rpc/src/v1/tests/helpers/mod.rs create mode 100644 rpc/src/v1/tests/helpers/sync_provider.rs create mode 100644 rpc/src/v1/tests/net.rs diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 5e67bf252..1918073e3 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -36,10 +36,10 @@ impl NetClient where S: SyncProvider { impl Net for NetClient where S: SyncProvider + 'static { fn version(&self, _: Params) -> Result { - Ok(Value::U64(take_weak!(self.sync).status().protocol_version as u64)) + Ok(Value::String(format!("{}", take_weak!(self.sync).status().protocol_version).to_owned())) } fn peer_count(&self, _params: Params) -> Result { - Ok(Value::U64(take_weak!(self.sync).status().num_peers as u64)) + Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())) } } diff --git a/rpc/src/v1/mod.rs b/rpc/src/v1/mod.rs index 104a8b3f0..b82a20e89 100644 --- a/rpc/src/v1/mod.rs +++ b/rpc/src/v1/mod.rs @@ -21,9 +21,10 @@ pub mod traits; mod impls; mod types; +mod helpers; + #[cfg(test)] mod tests; -mod helpers; pub use self::traits::{Web3, Eth, EthFilter, Personal, Net}; pub use self::impls::*; diff --git a/rpc/src/v1/tests/helpers/mod.rs b/rpc/src/v1/tests/helpers/mod.rs new file mode 100644 index 000000000..501bfb2d3 --- /dev/null +++ b/rpc/src/v1/tests/helpers/mod.rs @@ -0,0 +1,19 @@ +// 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 . + +mod sync_provider; + +pub use self::sync_provider::{Config, TestSyncProvider}; diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs new file mode 100644 index 000000000..b6d9241dd --- /dev/null +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -0,0 +1,57 @@ +// 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 . + +use ethcore::transaction::SignedTransaction; +use ethsync::{SyncProvider, SyncStatus, SyncState}; + +pub struct Config { + pub protocol_version: u8, + pub num_peers: usize, +} + +pub struct TestSyncProvider { + status: SyncStatus, +} + +impl TestSyncProvider { + pub fn new(config: Config) -> Self { + TestSyncProvider { + status: SyncStatus { + state: SyncState::NotSynced, + protocol_version: config.protocol_version, + start_block_number: 0, + last_imported_block_number: None, + highest_block_number: None, + blocks_total: 0, + blocks_received: 0, + num_peers: config.num_peers, + num_active_peers: 0, + mem_used: 0, + }, + } + } +} + +impl SyncProvider for TestSyncProvider { + fn status(&self) -> SyncStatus { + self.status.clone() + } + + fn insert_transaction(&self, _transaction: SignedTransaction) { + unimplemented!() + } +} + diff --git a/rpc/src/v1/tests/mod.rs b/rpc/src/v1/tests/mod.rs index bdf4567b6..5ef74987c 100644 --- a/rpc/src/v1/tests/mod.rs +++ b/rpc/src/v1/tests/mod.rs @@ -1 +1,20 @@ -//TODO: load custom blockchain state and test +// 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 . + +//!TODO: load custom blockchain state and test + +mod net; +mod helpers; diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs new file mode 100644 index 000000000..f6c4ae2e9 --- /dev/null +++ b/rpc/src/v1/tests/net.rs @@ -0,0 +1,52 @@ +// 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 . + +use std::sync::Arc; +use jsonrpc_core::IoHandler; +use v1::{Net, NetClient}; +use v1::tests::helpers::{Config, TestSyncProvider}; + +#[test] +fn rpc_net_version() { + let sync = Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_version", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"65","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_string())); +} + +#[test] +fn rpc_net_peer_count() { + let sync = Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_peerCount", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":"0x78","id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_string())); +} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index da3908a1e..da25c72de 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -120,6 +120,7 @@ pub enum SyncState { } /// Syncing status and statistics +#[derive(Clone)] pub struct SyncStatus { /// State pub state: SyncState, From 8e52510dbb45642105f3fb4dab5e6fc166225fff Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 10:21:25 +0100 Subject: [PATCH 21/27] implemented net_listening method --- rpc/src/v1/impls/net.rs | 5 +++++ rpc/src/v1/tests/net.rs | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/rpc/src/v1/impls/net.rs b/rpc/src/v1/impls/net.rs index 1918073e3..e52fc0bd4 100644 --- a/rpc/src/v1/impls/net.rs +++ b/rpc/src/v1/impls/net.rs @@ -42,4 +42,9 @@ impl Net for NetClient where S: SyncProvider + 'static { fn peer_count(&self, _params: Params) -> Result { Ok(Value::String(format!("0x{:x}", take_weak!(self.sync).status().num_peers as u64).to_owned())) } + + fn is_listening(&self, _: Params) -> Result { + // right now (11 march 2016), we are always listening for incoming connections + Ok(Value::Bool(true)) + } } diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs index f6c4ae2e9..9cb0bd189 100644 --- a/rpc/src/v1/tests/net.rs +++ b/rpc/src/v1/tests/net.rs @@ -50,3 +50,19 @@ fn rpc_net_peer_count() { assert_eq!(io.handle_request(request), Some(response.to_string())); } + +#[test] +fn rpc_net_listening() { + let sync = Arc::new(TestSyncProvider::new(Config { + protocol_version: 65, + num_peers: 120, + })); + let net = NetClient::new(&sync).to_delegate(); + let io = IoHandler::new(); + io.add_delegate(net); + + let request = r#"{"jsonrpc": "2.0", "method": "net_listening", "params": [], "id": 1}"#; + let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request(request), Some(response.to_string())); +} From a6d268db1618dea7bb2c6189a443777cb0760438 Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 10:30:13 +0100 Subject: [PATCH 22/27] fixed missing reexport --- ethcore/src/blockchain/mod.rs | 2 +- ethcore/src/client/client.rs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/ethcore/src/blockchain/mod.rs b/ethcore/src/blockchain/mod.rs index 6559d8364..29a4ee684 100644 --- a/ethcore/src/blockchain/mod.rs +++ b/ethcore/src/blockchain/mod.rs @@ -23,9 +23,9 @@ mod bloom_indexer; mod cache; mod tree_route; mod update; +mod import_route; #[cfg(test)] mod generator; -mod import_route; pub use self::blockchain::{BlockProvider, BlockChain, BlockChainConfig}; pub use self::cache::CacheSize; diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index 4ef8bb029..40f86f7a2 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -37,8 +37,9 @@ use filter::Filter; use log_entry::LocalizedLogEntry; use util::keys::store::SecretStore; use block_queue::{BlockQueue, BlockQueueInfo}; -use blockchain::{BlockChain, BlockProvider, TreeRoute, CacheSize as BlockChainCacheSize}; +use blockchain::{BlockChain, BlockProvider, TreeRoute}; use client::{BlockId, TransactionId, ClientConfig, BlockChainClient}; +pub use blockchain::CacheSize as BlockChainCacheSize; /// General block status #[derive(Debug, Eq, PartialEq)] From 18939462c392a3c175b69dc6002454c7baeb55ca Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 11:03:43 +0100 Subject: [PATCH 23/27] sync_provider function --- rpc/src/v1/tests/net.rs | 22 ++++++++++------------ 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/rpc/src/v1/tests/net.rs b/rpc/src/v1/tests/net.rs index 9cb0bd189..792e469d8 100644 --- a/rpc/src/v1/tests/net.rs +++ b/rpc/src/v1/tests/net.rs @@ -19,12 +19,16 @@ use jsonrpc_core::IoHandler; use v1::{Net, NetClient}; use v1::tests::helpers::{Config, TestSyncProvider}; -#[test] -fn rpc_net_version() { - let sync = Arc::new(TestSyncProvider::new(Config { +fn sync_provider() -> Arc { + Arc::new(TestSyncProvider::new(Config { protocol_version: 65, num_peers: 120, - })); + })) +} + +#[test] +fn rpc_net_version() { + let sync = sync_provider(); let net = NetClient::new(&sync).to_delegate(); let io = IoHandler::new(); io.add_delegate(net); @@ -37,10 +41,7 @@ fn rpc_net_version() { #[test] fn rpc_net_peer_count() { - let sync = Arc::new(TestSyncProvider::new(Config { - protocol_version: 65, - num_peers: 120, - })); + let sync = sync_provider(); let net = NetClient::new(&sync).to_delegate(); let io = IoHandler::new(); io.add_delegate(net); @@ -53,10 +54,7 @@ fn rpc_net_peer_count() { #[test] fn rpc_net_listening() { - let sync = Arc::new(TestSyncProvider::new(Config { - protocol_version: 65, - num_peers: 120, - })); + let sync = sync_provider(); let net = NetClient::new(&sync).to_delegate(); let io = IoHandler::new(); io.add_delegate(net); From a8a21da9ba7942615a6bbf031fc0ac78e9bc83f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:05:20 +0100 Subject: [PATCH 24/27] Updating hook and removing running clippy from dev-dependencies --- Cargo.toml | 6 ------ hook.sh | 13 +++++++++++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 22d0f9288..563dd2a69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -27,12 +27,6 @@ ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } rpassword = "0.1" -[dev-dependencies] -ethcore = { path = "ethcore", features = ["dev"] } -ethcore-util = { path = "util", features = ["dev"] } -ethsync = { path = "sync", features = ["dev"] } -ethcore-rpc = { path = "rpc", features = ["dev"] } - [features] default = ["rpc"] rpc = ["ethcore-rpc"] diff --git a/hook.sh b/hook.sh index 354fddd5d..aa6ed7415 100755 --- a/hook.sh +++ b/hook.sh @@ -1,3 +1,12 @@ #!/bin/sh -echo "#!/bin/sh\ncargo test -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity --features dev-clippy" > ./.git/hooks/pre-push -chmod +x ./.git/hooks/pre-push +FILE=./.git/hooks/pre-push +echo "#!/bin/sh\n" > $FILE +# Exit on any error +echo "set -e" >> $FILE +# Run release build +echo "cargo build --release --features dev-clippy" >> $FILE +# Build tests +echo "cargo test --no-run --features dev-clippy \\" >> $FILE +echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" >> $FILE +echo "" >> $FILE +chmod +x $FILE From d84e008e00b23d64d6bee1920cc545b434f5348d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:16:49 +0100 Subject: [PATCH 25/27] Removing superflous check for nightly --- Cargo.toml | 5 ++--- cargo.sh | 2 -- ethcore/Cargo.toml | 6 +----- ethcore/build.rs | 25 ------------------------- ethcore/src/basic_types.rs | 2 +- ethcore/src/block.rs | 2 +- ethcore/src/block_queue.rs | 2 +- ethcore/src/blockchain/blockchain.rs | 4 ++-- ethcore/src/ethereum/ethash.rs | 2 +- ethcore/src/evm/interpreter.rs | 6 +++--- ethcore/src/externalities.rs | 2 +- ethcore/src/lib.rs | 10 +++++----- ethcore/src/service.rs | 2 +- ethcore/src/spec.rs | 2 +- ethcore/src/state.rs | 2 +- ethcore/src/transaction.rs | 2 +- hook.sh | 4 ++-- parity/main.rs | 6 +++--- rpc/Cargo.toml | 3 +-- rpc/build.rs | 7 ------- sync/Cargo.toml | 6 +----- sync/build.rs | 25 ------------------------- sync/src/chain.rs | 6 +++--- sync/src/lib.rs | 6 +++--- sync/src/range_collection.rs | 4 ++-- util/Cargo.toml | 3 +-- util/bigint/src/uint.rs | 6 +++--- util/build.rs | 5 ----- util/src/hash.rs | 4 ++-- util/src/lib.rs | 12 ++++++------ util/src/network/discovery.rs | 2 +- util/src/network/host.rs | 4 ++-- util/src/panics.rs | 2 +- util/src/trie/triedb.rs | 2 +- util/src/trie/triedbmut.rs | 4 ++-- 35 files changed, 56 insertions(+), 131 deletions(-) delete mode 100755 cargo.sh delete mode 100644 ethcore/build.rs delete mode 100644 sync/build.rs diff --git a/Cargo.toml b/Cargo.toml index 563dd2a69..4daabf669 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,10 +30,9 @@ rpassword = "0.1" [features] default = ["rpc"] rpc = ["ethcore-rpc"] -dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] -dev-clippy = ["clippy", "ethcore/clippy", "ethcore-util/clippy", "ethsync/clippy", "ethcore-rpc/clippy"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev"] travis-beta = ["ethcore/json-tests"] -travis-nightly = ["ethcore/json-tests", "dev-clippy", "dev"] +travis-nightly = ["ethcore/json-tests", "dev"] [[bin]] path = "parity/main.rs" diff --git a/cargo.sh b/cargo.sh deleted file mode 100755 index 6870ab385..000000000 --- a/cargo.sh +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -cargo "$@" --features dev-clippy diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index fbfe175d7..c3a3d32dc 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -5,10 +5,6 @@ license = "GPL-3.0" name = "ethcore" version = "0.9.99" authors = ["Ethcore "] -build = "build.rs" - -[build-dependencies] -rustc_version = "0.1" [dependencies] log = "0.3" @@ -31,5 +27,5 @@ jit = ["evmjit"] evm-debug = [] json-tests = [] test-heavy = [] -dev = [] +dev = ["clippy"] default = [] diff --git a/ethcore/build.rs b/ethcore/build.rs deleted file mode 100644 index 41b9a1b3e..000000000 --- a/ethcore/build.rs +++ /dev/null @@ -1,25 +0,0 @@ -// 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 . - -extern crate rustc_version; - -use rustc_version::{version_meta, Channel}; - -fn main() { - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/ethcore/src/basic_types.rs b/ethcore/src/basic_types.rs index 9cba8b3a0..5f6515c0d 100644 --- a/ethcore/src/basic_types.rs +++ b/ethcore/src/basic_types.rs @@ -24,7 +24,7 @@ pub type LogBloom = H2048; /// Constant 2048-bit datum for 0. Often used as a default. pub static ZERO_LOGBLOOM: LogBloom = H2048([0x00; 256]); -#[cfg_attr(all(nightly, feature="dev"), allow(enum_variant_names))] +#[cfg_attr(feature="dev", allow(enum_variant_names))] /// Semantic boolean for when a seal/signature is included. pub enum Seal { /// The seal/signature is included. diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index b3894db94..9ecd58e0a 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -16,7 +16,7 @@ //! Blockchain block. -#![cfg_attr(all(nightly, feature="dev"), allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> +#![cfg_attr(feature="dev", allow(ptr_arg))] // Because of &LastHashes -> &Vec<_> use common::*; use engine::*; diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 3dfb98e8a..c83542f12 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -121,7 +121,7 @@ struct QueueSignal { } impl QueueSignal { - #[cfg_attr(all(nightly, feature="dev"), allow(bool_comparison))] + #[cfg_attr(feature="dev", allow(bool_comparison))] fn set(&self) { if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message"); diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 8c21532c8..d67c1b7f1 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -891,7 +891,7 @@ mod tests { } #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_find_uncles() { let mut canon_chain = ChainGenerator::default(); let mut finalizer = BlockFinalizer::default(); @@ -929,7 +929,7 @@ mod tests { } #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { let mut canon_chain = ChainGenerator::default(); let mut finalizer = BlockFinalizer::default(); diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index b0c0e4a9f..f9810b964 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -202,7 +202,7 @@ impl Engine for Ethash { } } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] // to_ethash should take self +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // to_ethash should take self impl Ethash { fn calculate_difficuty(&self, header: &Header, parent: &Header) -> U256 { const EXP_DIFF_PERIOD: u64 = 100000; diff --git a/ethcore/src/evm/interpreter.rs b/ethcore/src/evm/interpreter.rs index fb8d19357..7491321cb 100644 --- a/ethcore/src/evm/interpreter.rs +++ b/ethcore/src/evm/interpreter.rs @@ -243,7 +243,7 @@ struct CodeReader<'a> { code: &'a Bytes } -#[cfg_attr(all(nightly, feature="dev"), allow(len_without_is_empty))] +#[cfg_attr(feature="dev", allow(len_without_is_empty))] impl<'a> CodeReader<'a> { /// Get `no_of_bytes` from code and convert to U256. Move PC fn read(&mut self, no_of_bytes: usize) -> U256 { @@ -258,7 +258,7 @@ impl<'a> CodeReader<'a> { } } -#[cfg_attr(all(nightly, feature="dev"), allow(enum_variant_names))] +#[cfg_attr(feature="dev", allow(enum_variant_names))] enum InstructionCost { Gas(U256), GasMem(U256, U256), @@ -347,7 +347,7 @@ impl evm::Evm for Interpreter { } impl Interpreter { - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn get_gas_cost_mem(&self, ext: &evm::Ext, instruction: Instruction, diff --git a/ethcore/src/externalities.rs b/ethcore/src/externalities.rs index a1f5763ea..598921580 100644 --- a/ethcore/src/externalities.rs +++ b/ethcore/src/externalities.rs @@ -188,7 +188,7 @@ impl<'a> Ext for Externalities<'a> { self.state.code(address).unwrap_or_else(|| vec![]) } - #[cfg_attr(all(nightly, feature="dev"), allow(match_ref_pats))] + #[cfg_attr(feature="dev", allow(match_ref_pats))] fn ret(&mut self, gas: &U256, data: &[u8]) -> Result { match &mut self.output { &mut OutputPolicy::Return(BytesRef::Fixed(ref mut slice)) => unsafe { diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 469364eb3..938da02a0 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -15,16 +15,16 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Clippy config // TODO [todr] not really sure -#![cfg_attr(all(nightly, feature="dev"), allow(needless_range_loop))] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] +#![cfg_attr(feature="dev", allow(match_bool))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Ethcore library //! diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index bd15ee501..6daf0d7b6 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -117,7 +117,7 @@ impl IoHandler for ClientIoHandler { } } - #[cfg_attr(all(nightly, feature="dev"), allow(single_match))] + #[cfg_attr(feature="dev", allow(single_match))] fn message(&self, io: &IoContext, net_message: &NetSyncMessage) { if let UserMessage(ref message) = *net_message { match *message { diff --git a/ethcore/src/spec.rs b/ethcore/src/spec.rs index 774024351..2208350cc 100644 --- a/ethcore/src/spec.rs +++ b/ethcore/src/spec.rs @@ -99,7 +99,7 @@ pub struct Spec { genesis_state: PodState, } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) +#[cfg_attr(feature="dev", allow(wrong_self_convention))] // because to_engine(self) should be to_engine(&self) impl Spec { /// Convert this object into a boxed Engine of the right underlying type. // TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead. diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index 7c1064abf..c13678c38 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -224,7 +224,7 @@ impl State { /// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit. /// `accounts` is mutable because we may need to commit the code or storage and record that. - #[cfg_attr(all(nightly, feature="dev"), allow(match_ref_pats))] + #[cfg_attr(feature="dev", allow(match_ref_pats))] pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap>) { // first, commit the sub trees. // TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? diff --git a/ethcore/src/transaction.rs b/ethcore/src/transaction.rs index 733e5ac6b..a51824494 100644 --- a/ethcore/src/transaction.rs +++ b/ethcore/src/transaction.rs @@ -80,7 +80,7 @@ impl Transaction { } impl FromJson for SignedTransaction { - #[cfg_attr(all(nightly, feature="dev"), allow(single_char_pattern))] + #[cfg_attr(feature="dev", allow(single_char_pattern))] fn from_json(json: &Json) -> SignedTransaction { let t = Transaction { nonce: xjson!(&json["nonce"]), diff --git a/hook.sh b/hook.sh index aa6ed7415..9780541fe 100755 --- a/hook.sh +++ b/hook.sh @@ -4,9 +4,9 @@ echo "#!/bin/sh\n" > $FILE # Exit on any error echo "set -e" >> $FILE # Run release build -echo "cargo build --release --features dev-clippy" >> $FILE +echo "cargo build --release --features dev" >> $FILE # Build tests -echo "cargo test --no-run --features dev-clippy \\" >> $FILE +echo "cargo test --no-run --features dev \\" >> $FILE echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity" >> $FILE echo "" >> $FILE chmod +x $FILE diff --git a/parity/main.rs b/parity/main.rs index efff52e4e..c38c2d515 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -17,8 +17,8 @@ //! Ethcore client application. #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] extern crate docopt; extern crate rustc_serialize; extern crate ethcore_util as util; @@ -293,7 +293,7 @@ impl Configuration { } } - #[cfg_attr(all(nightly, feature="dev"), allow(useless_format))] + #[cfg_attr(feature="dev", allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { let mut listen_address = None; let mut public_address = None; diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 2ce430e51..f324aba10 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -26,9 +26,8 @@ serde_macros = { version = "0.7.0", optional = true } [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } syntex = "0.29.0" -rustc_version = "0.1" [features] default = ["serde_codegen"] nightly = ["serde_macros"] -dev = ["ethcore/dev", "ethcore-util/dev", "ethsync/dev"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev"] diff --git a/rpc/build.rs b/rpc/build.rs index 3806f6fe5..659bc35eb 100644 --- a/rpc/build.rs +++ b/rpc/build.rs @@ -14,10 +14,6 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate rustc_version; - -use rustc_version::{version_meta, Channel}; - #[cfg(not(feature = "serde_macros"))] mod inner { extern crate syntex; @@ -46,7 +42,4 @@ mod inner { fn main() { inner::main(); - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 46baa8a83..0097cd47e 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -4,13 +4,9 @@ name = "ethsync" version = "0.9.99" license = "GPL-3.0" authors = ["Ethcore . - -extern crate rustc_version; - -use rustc_version::{version_meta, Channel}; - -fn main() { - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } -} diff --git a/sync/src/chain.rs b/sync/src/chain.rs index da3908a1e..7789fb004 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -275,7 +275,7 @@ impl ChainSync { } - #[cfg_attr(all(nightly, feature="dev"), allow(for_kv_map))] // Because it's not possible to get `values_mut()` + #[cfg_attr(feature="dev", allow(for_kv_map))] // Because it's not possible to get `values_mut()` /// Rest sync. Clear all downloaded data but keep the queue fn reset(&mut self) { self.downloading_headers.clear(); @@ -343,7 +343,7 @@ impl ChainSync { Ok(()) } - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Called by peer once it has new block headers during sync fn on_peer_block_headers(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { self.reset_peer_asking(peer_id, PeerAsking::BlockHeaders); @@ -470,7 +470,7 @@ impl ChainSync { } /// Called by peer once it has new block bodies - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn on_peer_new_block(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { let block_rlp = try!(r.at(0)); let header_rlp = try!(block_rlp.at(0)); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index 3b79e5614..3ef4b4150 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -15,11 +15,11 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Blockchain sync module //! Implements ethereum protocol version 63 as specified here: diff --git a/sync/src/range_collection.rs b/sync/src/range_collection.rs index 826a67121..664d7c7a3 100644 --- a/sync/src/range_collection.rs +++ b/sync/src/range_collection.rs @@ -42,7 +42,7 @@ pub trait RangeCollection { fn remove_head(&mut self, start: &K); /// Remove all elements >= `start` in the range that contains `start` fn remove_tail(&mut self, start: &K); - /// Remove all elements >= `start` + /// Remove all elements >= `start` fn remove_from(&mut self, start: &K); /// Remove all elements >= `tail` fn insert_item(&mut self, key: K, value: V); @@ -231,7 +231,7 @@ impl RangeCollection for Vec<(K, Vec)> where K: Ord + PartialEq + } #[test] -#[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] +#[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_range() { use std::cmp::{Ordering}; diff --git a/util/Cargo.toml b/util/Cargo.toml index 0ce27ec2b..74e4d7226 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -40,8 +40,7 @@ chrono = "0.2" [features] default = [] -dev = [] +dev = ["clippy"] [build-dependencies] vergen = "*" -rustc_version = "0.1" diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 959df0944..32abdb5d5 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -1103,7 +1103,7 @@ macro_rules! construct_uint { } } - #[cfg_attr(all(nightly, feature="dev"), allow(derive_hash_xor_eq))] // We are pretty sure it's ok. + #[cfg_attr(feature="dev", allow(derive_hash_xor_eq))] // We are pretty sure it's ok. impl Hash for $name { fn hash(&self, state: &mut H) where H: Hasher { unsafe { state.write(::std::slice::from_raw_parts(self.0.as_ptr() as *mut u8, self.0.len() * 8)); } @@ -1485,7 +1485,7 @@ mod tests { } #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(eq_op))] + #[cfg_attr(feature="dev", allow(eq_op))] pub fn uint256_comp_test() { let small = U256([10u64, 0, 0, 0]); let big = U256([0x8C8C3EE70C644118u64, 0x0209E7378231E632, 0, 0]); @@ -2032,7 +2032,7 @@ mod tests { #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn u256_multi_full_mul() { let result = U256([0, 0, 0, 0]).full_mul(U256([0, 0, 0, 0])); assert_eq!(U512([0, 0, 0, 0, 0, 0, 0, 0]), result); diff --git a/util/build.rs b/util/build.rs index 0b9b233e0..b0b64a380 100644 --- a/util/build.rs +++ b/util/build.rs @@ -14,15 +14,10 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -extern crate rustc_version; extern crate vergen; use vergen::*; -use rustc_version::{version_meta, Channel}; fn main() { vergen(OutputFns::all()).unwrap(); - if let Channel::Nightly = version_meta().channel { - println!("cargo:rustc-cfg=nightly"); - } } diff --git a/util/src/hash.rs b/util/src/hash.rs index 4eb96b53e..73fa33b47 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -305,7 +305,7 @@ macro_rules! impl_hash { } impl Copy for $from {} - #[cfg_attr(all(nightly, feature="dev"), allow(expl_impl_clone_on_copy))] + #[cfg_attr(feature="dev", allow(expl_impl_clone_on_copy))] impl Clone for $from { fn clone(&self) -> $from { unsafe { @@ -637,7 +637,7 @@ mod tests { use std::str::FromStr; #[test] - #[cfg_attr(all(nightly, feature="dev"), allow(eq_op))] + #[cfg_attr(feature="dev", allow(eq_op))] fn hash() { let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); diff --git a/util/src/lib.rs b/util/src/lib.rs index 59d66a325..a50ba8da4 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -15,18 +15,18 @@ // along with Parity. If not, see . #![warn(missing_docs)] -#![cfg_attr(all(nightly, feature="dev"), feature(plugin))] -#![cfg_attr(all(nightly, feature="dev"), plugin(clippy))] +#![cfg_attr(feature="dev", feature(plugin))] +#![cfg_attr(feature="dev", plugin(clippy))] // Clippy settings // TODO [todr] not really sure -#![cfg_attr(all(nightly, feature="dev"), allow(needless_range_loop))] +#![cfg_attr(feature="dev", allow(needless_range_loop))] // Shorter than if-else -#![cfg_attr(all(nightly, feature="dev"), allow(match_bool))] +#![cfg_attr(feature="dev", allow(match_bool))] // We use that to be more explicit about handled cases -#![cfg_attr(all(nightly, feature="dev"), allow(match_same_arms))] +#![cfg_attr(feature="dev", allow(match_same_arms))] // Keeps consistency (all lines with `.clone()`) and helpful when changing ref to non-ref. -#![cfg_attr(all(nightly, feature="dev"), allow(clone_on_copy))] +#![cfg_attr(feature="dev", allow(clone_on_copy))] //! Ethcore-util library //! diff --git a/util/src/network/discovery.rs b/util/src/network/discovery.rs index 644af22af..4f3384894 100644 --- a/util/src/network/discovery.rs +++ b/util/src/network/discovery.rs @@ -243,7 +243,7 @@ impl Discovery { self.send_to(packet, address.clone()); } - #[cfg_attr(all(nightly, feature="dev"), allow(map_clone))] + #[cfg_attr(feature="dev", allow(map_clone))] fn nearest_node_entries(target: &NodeId, buckets: &[NodeBucket]) -> Vec { let mut found: BTreeMap> = BTreeMap::new(); let mut count = 0; diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 2d1af55ba..ece24a1d1 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -507,7 +507,7 @@ impl Host where Message: Send + Sync + Clone { debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } - #[cfg_attr(all(nightly, feature="dev"), allow(single_match))] + #[cfg_attr(feature="dev", allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { @@ -542,7 +542,7 @@ impl Host where Message: Send + Sync + Clone { self.create_connection(socket, Some(id), io); } - #[cfg_attr(all(nightly, feature="dev"), allow(block_in_if_condition_stmt))] + #[cfg_attr(feature="dev", allow(block_in_if_condition_stmt))] fn create_connection(&self, socket: TcpStream, id: Option<&NodeId>, io: &IoContext>) { let nonce = self.info.write().unwrap().next_nonce(); let mut handshakes = self.handshakes.write().unwrap(); diff --git a/util/src/panics.rs b/util/src/panics.rs index 70ce0bc33..05d266b8b 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -71,7 +71,7 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. - #[cfg_attr(all(nightly, feature="dev"), allow(deprecated))] + #[cfg_attr(feature="dev", allow(deprecated))] pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { let _guard = PanicGuard { handler: self }; let result = g(); diff --git a/util/src/trie/triedb.rs b/util/src/trie/triedb.rs index 182b87063..06076d273 100644 --- a/util/src/trie/triedb.rs +++ b/util/src/trie/triedb.rs @@ -54,7 +54,7 @@ pub struct TrieDB<'db> { pub hash_count: usize, } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDB<'db> { /// Create a new trie with the backing database `db` and `root` /// Panics, if `root` does not exist diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 3d5c366e5..3d75fa3e1 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -66,7 +66,7 @@ enum MaybeChanged<'a> { Changed(Bytes), } -#[cfg_attr(all(nightly, feature="dev"), allow(wrong_self_convention))] +#[cfg_attr(feature="dev", allow(wrong_self_convention))] impl<'db> TrieDBMut<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. @@ -350,7 +350,7 @@ impl<'db> TrieDBMut<'db> { } } - #[cfg_attr(all(nightly, feature="dev"), allow(cyclomatic_complexity))] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] /// Determine the RLP of the node, assuming we're inserting `partial` into the /// node currently of data `old`. This will *not* delete any hash of `old` from the database; /// it will just return the new RLP that includes the new node. From eb8e92c37f7ffca670c2c9790f3a585141ab6c40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 11 Mar 2016 11:18:38 +0100 Subject: [PATCH 26/27] Cargo.lock --- Cargo.lock | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f583a8747..627fbfa69 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -219,7 +219,6 @@ dependencies = [ "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.34 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -243,7 +242,6 @@ dependencies = [ "jsonrpc-http-server 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_codegen 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -299,7 +297,6 @@ dependencies = [ "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", - "rustc_version 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] From 68a13973a4c9e6151c77465d7798b68ed3fec75f Mon Sep 17 00:00:00 2001 From: debris Date: Fri, 11 Mar 2016 11:42:24 +0100 Subject: [PATCH 27/27] fixed ethcore-rpc tests build after merge --- rpc/src/v1/tests/helpers/sync_provider.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index b6d9241dd..a3711d949 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -40,6 +40,7 @@ impl TestSyncProvider { num_peers: config.num_peers, num_active_peers: 0, mem_used: 0, + transaction_queue_pending: 0, }, } }