diff --git a/Cargo.lock b/Cargo.lock index ea41e41c7..8d46fff53 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,13 +8,13 @@ dependencies = [ "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 0.9.99", + "ethcore-devtools 0.9.99", "ethcore-rpc 0.9.99", "ethcore-util 0.9.99", "ethsync 0.9.99", "fdlimit 0.1.0", "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)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -52,6 +52,11 @@ name = "bitflags" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "blastfig" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "bytes" version = "0.3.0" @@ -173,6 +178,7 @@ dependencies = [ "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 0.9.99", + "ethcore-devtools 0.9.99", "ethcore-util 0.9.99", "heapsize 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -183,6 +189,13 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-devtools" +version = "0.9.99" +dependencies = [ + "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethcore-rpc" version = "0.9.99" @@ -198,7 +211,6 @@ dependencies = [ "serde_codegen 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.29.0 (registry+https://github.com/rust-lang/crates.io-index)", - "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -211,6 +223,7 @@ dependencies = [ "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)", + "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)", "itertools 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -223,12 +236,14 @@ dependencies = [ "rocksdb 0.3.0 (git+https://github.com/arkpar/rust-rocksdb.git)", "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)", "serde 0.6.14 (registry+https://github.com/rust-lang/crates.io-index)", "sha3 0.1.0", "slab 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "target_info 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", "tiny-keccak 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -793,6 +808,15 @@ dependencies = [ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vergen" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "blastfig 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.5" diff --git a/Cargo.toml b/Cargo.toml index 5b59b26f1..7fdfc2bee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,8 +17,8 @@ ethcore = { path = "ethcore" } ethsync = { path = "sync" } ethcore-rpc = { path = "rpc", optional = true } fdlimit = { path = "util/fdlimit" } -target_info = "0.1" daemonize = "0.2" +ethcore-devtools = { path = "devtools" } [features] default = ["rpc"] diff --git a/devtools/Cargo.toml b/devtools/Cargo.toml new file mode 100644 index 000000000..ce0260936 --- /dev/null +++ b/devtools/Cargo.toml @@ -0,0 +1,16 @@ +[package] +description = "Ethcore development/test/build tools" +homepage = "http://ethcore.io" +license = "GPL-3.0" +name = "ethcore-devtools" +version = "0.9.99" +authors = ["Ethcore "] + +[dependencies] +rand = "0.3" + +[features] + +[lib] +path = "src/lib.rs" +test = true diff --git a/devtools/README.md b/devtools/README.md new file mode 100644 index 000000000..5d5144689 --- /dev/null +++ b/devtools/README.md @@ -0,0 +1 @@ +# ethcore dev tools diff --git a/devtools/src/lib.rs b/devtools/src/lib.rs new file mode 100644 index 000000000..f310cca30 --- /dev/null +++ b/devtools/src/lib.rs @@ -0,0 +1,24 @@ +// 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 . + +//! dev-tools + + +extern crate rand; + +pub mod random_path; + +pub use random_path::*; diff --git a/devtools/src/random_path.rs b/devtools/src/random_path.rs new file mode 100644 index 000000000..b037867fa --- /dev/null +++ b/devtools/src/random_path.rs @@ -0,0 +1,89 @@ +// 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 . + +//! Random path + +use std::path::*; +use std::fs; +use std::env; +use rand::random; + +pub struct RandomTempPath { + path: PathBuf +} + +pub fn random_filename() -> String { + (0..8).map(|_| ((random::() * 26.0) as u8 + 97) as char).collect() +} + +impl RandomTempPath { + pub fn new() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(random_filename()); + RandomTempPath { + path: dir.clone() + } + } + + pub fn create_dir() -> RandomTempPath { + let mut dir = env::temp_dir(); + dir.push(random_filename()); + fs::create_dir_all(dir.as_path()).unwrap(); + RandomTempPath { + path: dir.clone() + } + } + + pub fn as_path(&self) -> &PathBuf { + &self.path + } + + pub fn as_str(&self) -> &str { + self.path.to_str().unwrap() + } +} + +impl Drop for RandomTempPath { + fn drop(&mut self) { + if let Err(e) = fs::remove_dir_all(self.as_path()) { + panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); + } + } +} + +#[test] +fn creates_dir() { + let temp = RandomTempPath::create_dir(); + assert!(fs::metadata(temp.as_path()).unwrap().is_dir()); +} + +#[test] +fn destroys_dir() { + let path_buf = { + let temp = RandomTempPath::create_dir(); + assert!(fs::metadata(temp.as_path()).unwrap().is_dir()); + let path_buf = temp.as_path().to_path_buf(); + path_buf + }; + + assert!(fs::metadata(&path_buf).is_err()); +} + +#[test] +fn provides_random() { + let temp = RandomTempPath::create_dir(); + assert!(temp.as_path().to_str().is_some()); +} diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index edb87ef2c..1dfb66c7c 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -20,6 +20,7 @@ num_cpus = "0.2" clippy = { version = "0.0.42", optional = true } crossbeam = "0.1.5" lazy_static = "0.1" +ethcore-devtools = { path = "../devtools" } [features] jit = ["evmjit"] diff --git a/ethcore/res/ethereum/tests b/ethcore/res/ethereum/tests index 3116f85a4..f32954b3d 160000 --- a/ethcore/res/ethereum/tests +++ b/ethcore/res/ethereum/tests @@ -1 +1 @@ -Subproject commit 3116f85a499ceaf4dfdc46726060fc056e2d7829 +Subproject commit f32954b3ddb5af2dc3dc9ec6d9a28bee848fdf70 diff --git a/ethcore/src/blockchain.rs b/ethcore/src/blockchain.rs index 8518ef121..88edc9ff0 100644 --- a/ethcore/src/blockchain.rs +++ b/ethcore/src/blockchain.rs @@ -663,6 +663,7 @@ mod tests { use util::hash::*; use blockchain::*; use tests::helpers::*; + use devtools::*; #[test] fn valid_tests_extra32() { @@ -678,7 +679,7 @@ mod tests { assert_eq!(bc.best_block_hash(), genesis_hash.clone()); assert_eq!(bc.block_hash(0), Some(genesis_hash.clone())); assert_eq!(bc.block_hash(1), None); - + let first = "f90285f90219a03caa2203f3d7c136c0295ed128a7d31cea520b1ca5e27afe17d0853331798942a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0bac6177a79e910c98d86ec31a09ae37ac2de15b754fd7bed1ba52362c49416bfa0d45893a296c1490a978e0bd321b5f2635d8280365c1fe9f693d65f233e791344a0c7778a7376099ee2e5c455791c1885b5c361b95713fddcbe32d97fd01334d296b90100000000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000400000000000000000000000000000000000000000000000000000008302000001832fefd882560b845627cb99a00102030405060708091011121314151617181920212223242526272829303132a08ccb2837fb2923bd97e8f2d08ea32012d6e34be018c73e49a0f98843e8f47d5d88e53be49fec01012ef866f864800a82c35094095e7baea6a6c7c4c2dfeb977efac326af552d8785012a05f200801ba0cb088b8d2ff76a7b2c6616c9d02fb6b7a501afbf8b69d7180b09928a1b80b5e4a06448fe7476c606582039bb72a9f6f4b4fad18507b8dfbd00eebbe151cc573cd2c0".from_hex().unwrap(); bc.insert_block(&first); @@ -695,7 +696,7 @@ mod tests { } #[test] - #[allow(cyclomatic_complexity)] + #[cfg_attr(feature="dev", allow(cyclomatic_complexity))] fn test_small_fork() { let genesis = "f901fcf901f7a00000000000000000000000000000000000000000000000000000000000000000a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a07dba07d6b448a186e9612e5f737d1c909dce473e53199901a302c00646d523c1a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000080832fefd8808454c98c8142a059262c330941f3fe2a34d16d6e3c7b30d2ceb37c6a0e9a994c494ee1a61d2410885aa4c8bf8e56e264c0c0".from_hex().unwrap(); let b1 = "f90261f901f9a05716670833ec874362d65fea27a7cd35af5897d275b31a44944113111e4e96d2a01dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347948888f1f195afa192cfee860698584c030f4c9db1a0cb52de543653d86ccd13ba3ddf8b052525b04231c6884a4db3188a184681d878a0e78628dd45a1f8dc495594d83b76c588a3ee67463260f8b7d4a42f574aeab29aa0e9244cf7503b79c03d3a099e07a80d2dbc77bb0b502d8a89d51ac0d68dd31313b90100000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008302000001832fefd882520884562791e580a051b3ecba4e3f2b49c11d42dd0851ec514b1be3138080f72a2b6e83868275d98f8877671f479c414b47f862f86080018304cb2f94095e7baea6a6c7c4c2dfeb977efac326af552d870a801ca09e2709d7ec9bbe6b1bbbf0b2088828d14cd5e8642a1fee22dc74bfa89761a7f9a04bd8813dee4be989accdb708b1c2e325a7e9c695a8024e30e89d6c644e424747c0".from_hex().unwrap(); @@ -854,7 +855,7 @@ mod tests { let temp = RandomTempPath::new(); let bc = BlockChain::new(&genesis, temp.as_path()); bc.insert_block(&b1); - + let transactions = bc.transactions(&b1_hash).unwrap(); assert_eq!(transactions.len(), 7); for t in transactions { diff --git a/ethcore/src/evm/tests.rs b/ethcore/src/evm/tests.rs index 02f929192..9d4dd3bc4 100644 --- a/ethcore/src/evm/tests.rs +++ b/ethcore/src/evm/tests.rs @@ -25,7 +25,7 @@ struct FakeLogEntry { } #[derive(PartialEq, Eq, Hash, Debug)] -#[allow(enum_variant_names)] // Common prefix is C ;) +#[cfg_attr(feature="dev", allow(enum_variant_names))] // Common prefix is C ;) enum FakeCallType { CALL, CREATE } diff --git a/ethcore/src/json_tests/chain.rs b/ethcore/src/json_tests/chain.rs index 6a9f84073..a386e2854 100644 --- a/ethcore/src/json_tests/chain.rs +++ b/ethcore/src/json_tests/chain.rs @@ -20,6 +20,7 @@ use pod_state::*; use block::Block; use ethereum; use tests::helpers::*; +use devtools::*; pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec { init_log(); diff --git a/ethcore/src/lib.rs b/ethcore/src/lib.rs index 72f0aeaa6..3a5449ad6 100644 --- a/ethcore/src/lib.rs +++ b/ethcore/src/lib.rs @@ -91,6 +91,7 @@ extern crate env_logger; extern crate num_cpus; extern crate crossbeam; +#[cfg(test)] extern crate ethcore_devtools as devtools; #[cfg(feature = "jit" )] extern crate evmjit; pub mod block; diff --git a/ethcore/src/service.rs b/ethcore/src/service.rs index db0260b06..534aab49d 100644 --- a/ethcore/src/service.rs +++ b/ethcore/src/service.rs @@ -129,6 +129,7 @@ mod tests { use super::*; use tests::helpers::*; use util::network::*; + use devtools::*; #[test] fn it_can_be_started() { diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index bbec8cd37..8bbf317c1 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -163,7 +163,7 @@ impl State { /// Mutate storage of account `address` so that it is `value` for `key`. pub fn storage_at(&self, address: &Address, key: &H256) -> H256 { - self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(&self.db, address), key)) + self.get(address, false).as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::new(&self.db, address), key)) } /// Mutate storage of account `a` so that it is `value` for `key`. @@ -341,6 +341,7 @@ use util::rlp::*; use util::uint::*; use account::*; use tests::helpers::*; +use devtools::*; #[test] fn code_from_database() { diff --git a/ethcore/src/tests/client.rs b/ethcore/src/tests/client.rs index d025b4b78..af25d1b72 100644 --- a/ethcore/src/tests/client.rs +++ b/ethcore/src/tests/client.rs @@ -17,6 +17,7 @@ use client::{BlockChainClient, Client, BlockId}; use tests::helpers::*; use common::*; +use devtools::*; #[test] fn created() { diff --git a/ethcore/src/tests/helpers.rs b/ethcore/src/tests/helpers.rs index 550fc8937..ebe4d1d66 100644 --- a/ethcore/src/tests/helpers.rs +++ b/ethcore/src/tests/helpers.rs @@ -15,16 +15,14 @@ // along with Parity. If not, see . use client::{BlockChainClient, Client}; -use std::env; use common::*; -use std::path::PathBuf; use spec::*; -use std::fs::{remove_dir_all}; use blockchain::{BlockChain}; use state::*; use evm::{Schedule, Factory}; use engine::*; use ethereum; +use devtools::*; #[cfg(feature = "json-tests")] pub enum ChainEra { @@ -32,36 +30,6 @@ pub enum ChainEra { Homestead, } -pub struct RandomTempPath { - path: PathBuf -} - -impl RandomTempPath { - pub fn new() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } - - pub fn as_str(&self) -> &str { - self.path.to_str().unwrap() - } -} - -impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } -} - #[cfg(test)] pub struct GuardedTempResult { result: Option, diff --git a/install-deps.sh b/install-deps.sh index 214b6748c..f5e1e44cf 100755 --- a/install-deps.sh +++ b/install-deps.sh @@ -425,7 +425,7 @@ function run_installer() depFound=$((depFound+1)) check "multirust" isMultirust=true - if [[ $(multirust show-default 2>/dev/null | grep beta | wc -l) == 4 ]]; then + if [[ $(multirust show-default 2>/dev/null | grep beta | wc -l) == 3 ]]; then depFound=$((depFound+1)) check "rust beta" isMultirustBeta=true diff --git a/parity/main.rs b/parity/main.rs index 58d3a6f4c..f4b7880ab 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -29,7 +29,6 @@ extern crate log as rlog; extern crate env_logger; extern crate ctrlc; extern crate fdlimit; -extern crate target_info; extern crate daemonize; #[cfg(feature = "rpc")] @@ -51,7 +50,6 @@ use ethcore::ethereum; use ethcore::blockchain::CacheSize; use ethsync::EthSync; use docopt::Docopt; -use target_info::Target; use daemonize::Daemonize; const USAGE: &'static str = " @@ -146,14 +144,15 @@ fn setup_rpc_server(_client: Arc, _sync: Arc, _url: &str) { fn print_version() { println!("\ -Parity version {} ({}-{}-{}) +Parity + version {} Copyright 2015, 2016 Ethcore (UK) Limited License GPLv3+: GNU GPL version 3 or later . This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law. By Wood/Paronyan/Kotewicz/Drwięga/Volf.\ -", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()); +", version()); } fn die_with_message(msg: &str) -> ! { diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 0b7c17383..be06316a4 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -17,7 +17,6 @@ ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethsync = { path = "../sync" } clippy = { version = "0.0.42", optional = true } -target_info = "0.1.0" rustc-serialize = "0.3" serde_macros = { version = "0.6.13", optional = true } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index c9542ade7..d7b5bdc3b 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -20,7 +20,6 @@ #![cfg_attr(nightly, plugin(serde_macros, clippy))] extern crate rustc_serialize; -extern crate target_info; extern crate serde; extern crate serde_json; extern crate jsonrpc_core; diff --git a/rpc/src/v1/impls/web3.rs b/rpc/src/v1/impls/web3.rs index f10150a30..0a237d56b 100644 --- a/rpc/src/v1/impls/web3.rs +++ b/rpc/src/v1/impls/web3.rs @@ -15,8 +15,8 @@ // along with Parity. If not, see . //! Web3 rpc implementation. -use target_info::Target; use jsonrpc_core::*; +use util::version; use v1::traits::Web3; /// Web3 rpc implementation. @@ -30,7 +30,9 @@ impl Web3Client { impl Web3 for Web3Client { fn client_version(&self, params: Params) -> Result { match params { - Params::None => Ok(Value::String(format!("Parity/-/{}/{}-{}-{}/rust1.8-nightly", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()))), + Params::None => { + Ok(Value::String(version())), + } _ => Err(Error::invalid_params()) } } diff --git a/util/Cargo.toml b/util/Cargo.toml index 5290adbe7..e7318bac2 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -5,6 +5,7 @@ license = "GPL-3.0" name = "ethcore-util" version = "0.9.99" authors = ["Ethcore "] +build = "build.rs" [dependencies] log = "0.3" @@ -28,10 +29,16 @@ sha3 = { path = "sha3" } serde = "0.6.7" clippy = { version = "0.0.42", optional = true } json-tests = { path = "json-tests" } -target_info = "0.1.0" +rustc_version = "0.1.0" igd = "0.4.2" +ethcore-devtools = { path = "../devtools" } libc = "0.2.7" +vergen = "0.1" +target_info = "0.1" [features] default = [] dev = ["clippy"] + +[build-dependencies] +vergen = "*" diff --git a/util/build.rs b/util/build.rs new file mode 100644 index 000000000..32ee30472 --- /dev/null +++ b/util/build.rs @@ -0,0 +1,6 @@ +extern crate vergen; +use vergen::*; + +fn main() { + vergen(OutputFns::all()).unwrap(); +} \ No newline at end of file diff --git a/util/src/hash.rs b/util/src/hash.rs index d436c2d81..71c690ef6 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -635,7 +635,7 @@ mod tests { use std::str::FromStr; #[test] - #[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/keys/directory.rs b/util/src/keys/directory.rs index 23c483482..bc875db3f 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -1030,7 +1030,7 @@ mod file_tests { mod directory_tests { use super::{KeyDirectory, new_uuid, uuid_to_string, KeyFileContent, KeyFileCrypto, MAX_CACHE_USAGE_TRACK}; use common::*; - use tests::helpers::*; + use devtools::*; #[test] fn key_directory_locates_keys() { @@ -1110,7 +1110,7 @@ mod directory_tests { mod specs { use super::*; use common::*; - use tests::helpers::*; + use devtools::*; #[test] fn can_initiate_key_directory() { diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index b8b0b0a47..ae44d567a 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -70,7 +70,7 @@ impl SecretStore { } #[cfg(test)] - fn new_test(path: &::tests::helpers::RandomTempPath) -> SecretStore { + fn new_test(path: &::devtools::RandomTempPath) -> SecretStore { SecretStore { directory: KeyDirectory::new(path.as_path()) } @@ -203,7 +203,7 @@ mod vector_tests { #[cfg(test)] mod tests { use super::*; - use tests::helpers::*; + use devtools::*; use common::*; #[test] diff --git a/util/src/lib.rs b/util/src/lib.rs index 397b2b1a9..74d08eb7e 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -82,7 +82,6 @@ //! cargo build --release //! ``` -extern crate target_info; extern crate slab; extern crate rustc_serialize; extern crate mio; @@ -106,7 +105,11 @@ extern crate serde; #[macro_use] extern crate log as rlog; extern crate igd; +extern crate ethcore_devtools as devtools; extern crate libc; +extern crate rustc_version; +extern crate target_info; +extern crate vergen; pub mod standard; #[macro_use] @@ -163,5 +166,3 @@ pub use io::*; pub use log::*; pub use kvdb::*; -#[cfg(test)] -mod tests; diff --git a/util/src/misc.rs b/util/src/misc.rs index ae3dbc5bf..289f1c50c 100644 --- a/util/src/misc.rs +++ b/util/src/misc.rs @@ -18,6 +18,10 @@ use std::fs::File; use common::*; +use target_info::Target; +use rustc_version; + +include!(concat!(env!("OUT_DIR"), "/version.rs")); #[derive(Debug,Clone,PartialEq,Eq)] /// Diff type for specifying a change (or not). @@ -62,3 +66,8 @@ pub fn contents(name: &str) -> Result { try!(file.read_to_end(&mut ret)); Ok(ret) } + +/// Get the standard version string for this software. +pub fn version() -> String { + format!("Parity//{}-{}-{}/{}-{}-{}/rustc{}", env!("CARGO_PKG_VERSION"), short_sha(), commit_date().replace("-", ""), Target::arch(), Target::os(), Target::env(), rustc_version::version()) +} \ No newline at end of file diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 9e9304ca6..a7396ff33 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -175,13 +175,26 @@ impl Connection { self.socket.peer_addr() } + /// Clone this connection. Clears the receiving buffer of the returned connection. + pub fn try_clone(&self) -> io::Result { + Ok(Connection { + token: self.token, + socket: try!(self.socket.try_clone()), + rec_buf: Vec::new(), + rec_size: 0, + send_queue: self.send_queue.clone(), + interest: EventSet::hup() | EventSet::readable(), + stats: self.stats.clone(), + }) + } + /// Register this connection with the IO event loop. pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> io::Result<()> { trace!(target: "net", "connection register; token={:?}", reg); - event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()).or_else(|e| { + if let Err(e) = event_loop.register(&self.socket, reg, self.interest, PollOpt::edge() | PollOpt::oneshot()) { debug!("Failed to register {:?}, {:?}", reg, e); - Ok(()) - }) + } + Ok(()) } /// Update connection registration. Should be called at the end of the IO handler. @@ -265,7 +278,7 @@ impl EncryptedConnection { } /// Create an encrypted connection out of the handshake. Consumes a handshake object. - pub fn new(mut handshake: Handshake) -> Result { + pub fn new(handshake: &mut Handshake) -> Result { let shared = try!(crypto::ecdh::agree(handshake.ecdhe.secret(), &handshake.remote_public)); let mut nonce_material = H512::new(); if handshake.originated { @@ -300,9 +313,8 @@ impl EncryptedConnection { ingress_mac.update(&mac_material); ingress_mac.update(if handshake.originated { &handshake.ack_cipher } else { &handshake.auth_cipher }); - handshake.connection.expect(ENCRYPTED_HEADER_LEN); - Ok(EncryptedConnection { - connection: handshake.connection, + let mut enc = EncryptedConnection { + connection: try!(handshake.connection.try_clone()), encoder: encoder, decoder: decoder, mac_encoder: mac_encoder, @@ -311,7 +323,9 @@ impl EncryptedConnection { read_state: EncryptedConnectionState::Header, protocol_id: 0, payload_len: 0 - }) + }; + enc.connection.expect(ENCRYPTED_HEADER_LEN); + Ok(enc) } /// Send a packet @@ -440,6 +454,12 @@ impl EncryptedConnection { Ok(()) } + /// Register socket with the event lpop. This should be called at the end of the event loop. + pub fn register_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + try!(self.connection.register_socket(reg, event_loop)); + Ok(()) + } + /// Update connection registration. This should be called at the end of the event loop. pub fn update_socket(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { try!(self.connection.update_socket(reg, event_loop)); diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index 5d43decd7..087de63b3 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -63,7 +63,9 @@ pub struct Handshake { /// A copy of received encryped auth packet pub auth_cipher: Bytes, /// A copy of received encryped ack packet - pub ack_cipher: Bytes + pub ack_cipher: Bytes, + /// This Handshake is marked for deleteion flag + pub expired: bool, } const AUTH_PACKET_SIZE: usize = 307; @@ -84,6 +86,7 @@ impl Handshake { remote_nonce: H256::new(), auth_cipher: Bytes::new(), ack_cipher: Bytes::new(), + expired: false, }) } @@ -97,6 +100,16 @@ impl Handshake { self.connection.token() } + /// Mark this handshake as inactive to be deleted lated. + pub fn set_expired(&mut self) { + self.expired = true; + } + + /// Check if this handshake is expired. + pub fn expired(&self) -> bool { + self.expired + } + /// Start a handhsake pub fn start(&mut self, io: &IoContext, host: &HostInfo, originated: bool) -> Result<(), UtilError> where Message: Send + Clone{ self.originated = originated; @@ -118,47 +131,56 @@ impl Handshake { /// Readable IO handler. Drives the state change. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { - io.clear_timer(self.connection.token).unwrap(); - match self.state { - HandshakeState::ReadingAuth => { - if let Some(data) = try!(self.connection.readable()) { - try!(self.read_auth(host, &data)); - try!(self.write_ack()); - }; - }, - HandshakeState::ReadingAck => { - if let Some(data) = try!(self.connection.readable()) { - try!(self.read_ack(host, &data)); - self.state = HandshakeState::StartSession; - }; - }, - HandshakeState::StartSession => {}, - _ => { panic!("Unexpected state"); } - } - if self.state != HandshakeState::StartSession { - try!(io.update_registration(self.connection.token)); + if !self.expired() { + io.clear_timer(self.connection.token).unwrap(); + match self.state { + HandshakeState::ReadingAuth => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_auth(host, &data)); + try!(self.write_ack()); + }; + }, + HandshakeState::ReadingAck => { + if let Some(data) = try!(self.connection.readable()) { + try!(self.read_ack(host, &data)); + self.state = HandshakeState::StartSession; + }; + }, + HandshakeState::StartSession => {}, + _ => { panic!("Unexpected state"); } + } + if self.state != HandshakeState::StartSession { + try!(io.update_registration(self.connection.token)); + } } Ok(()) } /// Writabe IO handler. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Clone { - io.clear_timer(self.connection.token).unwrap(); - try!(self.connection.writable()); - if self.state != HandshakeState::StartSession { - io.update_registration(self.connection.token).unwrap(); + if !self.expired() { + io.clear_timer(self.connection.token).unwrap(); + try!(self.connection.writable()); + if self.state != HandshakeState::StartSession { + io.update_registration(self.connection.token).unwrap(); + } } Ok(()) } /// Register the socket with the event loop pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.register_socket(reg, event_loop)); + if !self.expired() { + try!(self.connection.register_socket(reg, event_loop)); + } Ok(()) } + /// Update socket registration with the event loop. pub fn update_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { - try!(self.connection.update_socket(reg, event_loop)); + if !self.expired() { + try!(self.connection.update_socket(reg, event_loop)); + } Ok(()) } diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 78fb274fa..fb3150ad3 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -26,8 +26,8 @@ use std::io::{Read, Write}; use std::fs; use mio::*; use mio::tcp::*; -use target_info::Target; use hash::*; +use misc::version; use crypto::*; use sha3::Hashable; use rlp::*; @@ -174,8 +174,8 @@ pub struct NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'sta impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone + 'static, { /// Create a new network IO access point. Takes references to all the data that can be updated within the IO handler. - fn new(io: &'s IoContext>, - protocol: ProtocolId, + fn new(io: &'s IoContext>, + protocol: ProtocolId, session: Option, sessions: Arc>>) -> NetworkContext<'s, Message> { NetworkContext { io: io, @@ -190,11 +190,11 @@ impl<'s, Message> NetworkContext<'s, Message> where Message: Send + Sync + Clone let session = { self.sessions.read().unwrap().get(peer).cloned() }; if let Some(session) = session { session.lock().unwrap().deref_mut().send_packet(self.protocol, packet_id as u8, &data).unwrap_or_else(|e| { - warn!(target: "net", "Send error: {:?}", e); + warn!(target: "network", "Send error: {:?}", e); }); //TODO: don't copy vector data try!(self.io.update_registration(peer)); } else { - trace!(target: "net", "Send: Peer no longer exist") + trace!(target: "network", "Send: Peer no longer exist") } Ok(()) } @@ -337,9 +337,9 @@ impl Host where Message: Send + Sync + Clone { // Setup the server socket let tcp_listener = TcpListener::bind(&listen_address).unwrap(); - let keys = if let Some(ref secret) = config.use_secret { - KeyPair::from_secret(secret.clone()).unwrap() - } else { + let keys = if let Some(ref secret) = config.use_secret { + KeyPair::from_secret(secret.clone()).unwrap() + } else { config.config_path.clone().and_then(|ref p| load_key(&Path::new(&p))) .map_or_else(|| { let key = KeyPair::create().unwrap(); @@ -351,7 +351,7 @@ impl Host where Message: Send + Sync + Clone { |s| KeyPair::from_secret(s).expect("Error creating node secret key")) }; let discovery = if config.discovery_enabled && !config.pin { - Some(Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY)) + Some(Discovery::new(&keys, listen_address.clone(), public_endpoint.clone(), DISCOVERY)) } else { None }; let path = config.config_path.clone(); let mut host = Host:: { @@ -360,7 +360,7 @@ impl Host where Message: Send + Sync + Clone { config: config, nonce: H256::random(), protocol_version: PROTOCOL_VERSION, - client_version: format!("Parity/{}/{}-{}-{}", env!("CARGO_PKG_VERSION"), Target::arch(), Target::env(), Target::os()), + client_version: version(), listen_port: 0, capabilities: Vec::new(), }), @@ -470,18 +470,18 @@ impl Host where Message: Send + Sync + Clone { .take(min(MAX_HANDSHAKES_PER_ROUND, handshake_limit - handshake_count)) { self.connect_peer(&id, io); } - debug!(target: "net", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); + debug!(target: "network", "Connecting peers: {} sessions, {} pending", self.session_count(), self.handshake_count()); } #[cfg_attr(feature="dev", allow(single_match))] fn connect_peer(&self, id: &NodeId, io: &IoContext>) { if self.have_session(id) { - trace!("Aborted connect. Node already connected."); + trace!(target: "network", "Aborted connect. Node already connected."); return; } if self.connecting_to(id) { - trace!("Aborted connect. Node already connecting."); + trace!(target: "network", "Aborted connect. Node already connecting."); return; } @@ -493,7 +493,7 @@ impl Host where Message: Send + Sync + Clone { node.endpoint.address } else { - debug!("Connection to expired node aborted"); + debug!(target: "network", "Connection to expired node aborted"); return; } }; @@ -515,16 +515,16 @@ impl Host where Message: Send + Sync + Clone { if handshakes.insert_with(|token| { let mut handshake = Handshake::new(token, id, socket, &nonce, self.stats.clone()).expect("Can't create handshake"); handshake.start(io, &self.info.read().unwrap(), id.is_some()).and_then(|_| io.register_stream(token)).unwrap_or_else (|e| { - debug!(target: "net", "Handshake create error: {:?}", e); + debug!(target: "network", "Handshake create error: {:?}", e); }); Arc::new(Mutex::new(handshake)) }).is_none() { - debug!("Max handshakes reached"); + debug!(target: "network", "Max handshakes reached"); } } fn accept(&self, io: &IoContext>) { - trace!(target: "net", "accept"); + trace!(target: "network", "Accepting incoming connection"); loop { let socket = match self.tcp_listener.lock().unwrap().accept() { Ok(None) => break, @@ -544,9 +544,9 @@ impl Host where Message: Send + Sync + Clone { if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.writable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake write error: {}:{:?}", token, e); + trace!(target: "network", "Handshake write error: {}: {:?}", token, e); } - } + } } fn session_writable(&self, token: StreamToken, io: &IoContext>) { @@ -554,10 +554,10 @@ impl Host where Message: Send + Sync + Clone { if let Some(session) = session { let mut s = session.lock().unwrap(); if let Err(e) = s.writable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Session write error: {}:{:?}", token, e); + trace!(target: "network", "Session write error: {}: {:?}", token, e); } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); - } + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Session registration error: {:?}", e)); + } } fn connection_closed(&self, token: TimerToken, io: &IoContext>) { @@ -571,7 +571,7 @@ impl Host where Message: Send + Sync + Clone { if let Some(handshake) = handshake { let mut h = handshake.lock().unwrap(); if let Err(e) = h.readable(io, &self.info.read().unwrap()) { - debug!(target: "net", "Handshake read error: {}:{:?}", token, e); + debug!(target: "network", "Handshake read error: {}: {:?}", token, e); kill = true; } if h.done() { @@ -583,9 +583,9 @@ impl Host where Message: Send + Sync + Clone { return; } else if create_session { self.start_session(token, io); - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Session registration error: {:?}", e)); + return; } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } fn session_readable(&self, token: StreamToken, io: &IoContext>) { @@ -597,7 +597,7 @@ impl Host where Message: Send + Sync + Clone { let mut s = session.lock().unwrap(); match s.readable(io, &self.info.read().unwrap()) { Err(e) => { - debug!(target: "net", "Session read error: {}:{:?}", token, e); + debug!(target: "network", "Session read error: {}: {:?}", token, e); kill = true; }, Ok(SessionData::Ready) => { @@ -613,13 +613,13 @@ impl Host where Message: Send + Sync + Clone { packet_id, }) => { match self.handlers.read().unwrap().get(protocol) { - None => { warn!(target: "net", "No handler found for protocol: {:?}", protocol) }, + None => { warn!(target: "network", "No handler found for protocol: {:?}", protocol) }, Some(_) => packet_data = Some((protocol, packet_id, data)), } }, Ok(SessionData::None) => {}, } - } + } if kill { self.kill_connection(token, io, true); //TODO: mark connection as dead an check in kill_connection } @@ -631,7 +631,7 @@ impl Host where Message: Send + Sync + Clone { let h = self.handlers.read().unwrap().get(p).unwrap().clone(); h.read(&NetworkContext::new(io, p, Some(token), self.sessions.clone()), &token, packet_id, &data[1..]); } - io.update_registration(token).unwrap_or_else(|e| debug!(target: "net", "Token registration error: {:?}", e)); + io.update_registration(token).unwrap_or_else(|e| debug!(target: "network", "Token registration error: {:?}", e)); } fn start_session(&self, token: StreamToken, io: &IoContext>) { @@ -639,29 +639,28 @@ impl Host where Message: Send + Sync + Clone { if handshakes.get(token).is_none() { return; } - + // turn a handshake into a session let mut sessions = self.sessions.write().unwrap(); - let mut h = handshakes.remove(token).unwrap(); - // wait for other threads to stop using it - { - while Arc::get_mut(&mut h).is_none() { - h.lock().ok(); - } + let mut h = handshakes.get_mut(token).unwrap().lock().unwrap(); + if h.expired { + return; } - let h = Arc::try_unwrap(h).ok().unwrap().into_inner().unwrap(); let originated = h.originated; - let mut session = match Session::new(h, &self.info.read().unwrap()) { + let mut session = match Session::new(&mut h, &self.info.read().unwrap()) { Ok(s) => s, Err(e) => { - debug!("Session creation error: {:?}", e); + debug!(target: "network", "Session creation error: {:?}", e); return; } }; let result = sessions.insert_with(move |session_token| { session.set_token(session_token); - io.update_registration(session_token).expect("Error updating session registration"); + io.deregister_stream(token).expect("Error deleting handshake registration"); + h.set_expired(); + io.register_stream(session_token).expect("Error creating session registration"); self.stats.inc_sessions(); + trace!(target: "network", "Creating session {} -> {}", token, session_token); if !originated { // Add it no node table if let Ok(address) = session.remote_addr() { @@ -690,26 +689,34 @@ impl Host where Message: Send + Sync + Clone { FIRST_HANDSHAKE ... LAST_HANDSHAKE => { let handshakes = self.handshakes.write().unwrap(); if let Some(handshake) = handshakes.get(token).cloned() { - failure_id = Some(handshake.lock().unwrap().id().clone()); + let mut handshake = handshake.lock().unwrap(); + if !handshake.expired() { + handshake.set_expired(); + failure_id = Some(handshake.id().clone()); + io.deregister_stream(token).expect("Error deregistering stream"); + } } }, FIRST_SESSION ... LAST_SESSION => { let sessions = self.sessions.write().unwrap(); if let Some(session) = sessions.get(token).cloned() { - let s = session.lock().unwrap(); - if s.is_ready() { - for (p, _) in self.handlers.read().unwrap().iter() { - if s.have_capability(p) { - to_disconnect.push(p); + let mut s = session.lock().unwrap(); + if !s.expired() { + if s.is_ready() { + for (p, _) in self.handlers.read().unwrap().iter() { + if s.have_capability(p) { + to_disconnect.push(p); + } } } + s.set_expired(); + failure_id = Some(s.id().clone()); + io.deregister_stream(token).expect("Error deregistering stream"); } - failure_id = Some(s.id().clone()); } }, _ => {}, } - io.deregister_stream(token).expect("Error deregistering stream"); if let Some(id) = failure_id { if remote { self.nodes.write().unwrap().note_failure(&id); @@ -764,11 +771,11 @@ impl IoHandler> for Host where Messa } fn stream_hup(&self, io: &IoContext>, stream: StreamToken) { - trace!(target: "net", "Hup: {}", stream); + trace!(target: "network", "Hup: {}", stream); match stream { FIRST_SESSION ... LAST_SESSION => self.connection_closed(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.connection_closed(stream, io), - _ => warn!(target: "net", "Unexpected hup"), + _ => warn!(target: "network", "Unexpected hup"), }; } @@ -777,12 +784,13 @@ impl IoHandler> for Host where Messa FIRST_SESSION ... LAST_SESSION => self.session_readable(stream, io), FIRST_HANDSHAKE ... LAST_HANDSHAKE => self.handshake_readable(stream, io), DISCOVERY => { - if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().readable() { + let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().readable() }; + if let Some(node_changes) = node_changes { self.update_nodes(io, node_changes); } io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, - TCP_ACCEPT => self.accept(io), + TCP_ACCEPT => self.accept(io), _ => panic!("Received unknown readable token"), } } @@ -809,14 +817,15 @@ impl IoHandler> for Host where Messa io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, DISCOVERY_ROUND => { - if let Some(node_changes) = self.discovery.as_ref().unwrap().lock().unwrap().round() { + let node_changes = { self.discovery.as_ref().unwrap().lock().unwrap().round() }; + if let Some(node_changes) = node_changes { self.update_nodes(io, node_changes); } io.update_registration(DISCOVERY).expect("Error updating discovery registration"); }, _ => match self.timers.read().unwrap().get(&token).cloned() { Some(timer) => match self.handlers.read().unwrap().get(timer.protocol).cloned() { - None => { warn!(target: "net", "No handler found for protocol: {:?}", timer.protocol) }, + None => { warn!(target: "network", "No handler found for protocol: {:?}", timer.protocol) }, Some(h) => { h.timeout(&NetworkContext::new(io, timer.protocol, None, self.sessions.clone()), timer.token); } }, None => { warn!("Unknown timer token: {}", token); } // timer is not registerd through us @@ -858,7 +867,7 @@ impl IoHandler> for Host where Messa let session = { self.sessions.read().unwrap().get(*peer).cloned() }; if let Some(session) = session { session.lock().unwrap().disconnect(DisconnectReason::DisconnectRequested); - } + } self.kill_connection(*peer, io, false); }, NetworkIoMessage::User(ref message) => { @@ -872,7 +881,10 @@ impl IoHandler> for Host where Messa fn register_stream(&self, stream: StreamToken, reg: Token, event_loop: &mut EventLoop>>) { match stream { FIRST_SESSION ... LAST_SESSION => { - warn!("Unexpected session stream registration"); + let session = { self.sessions.read().unwrap().get(stream).cloned() }; + if let Some(session) = session { + session.lock().unwrap().register_socket(reg, event_loop).expect("Error registering socket"); + } } FIRST_HANDSHAKE ... LAST_HANDSHAKE => { let connection = { self.handshakes.read().unwrap().get(stream).cloned() }; @@ -961,14 +973,14 @@ fn load_key(path: &Path) -> Option { let mut buf = String::new(); match file.read_to_string(&mut buf) { Ok(_) => {}, - Err(e) => { + Err(e) => { warn!("Error reading key file: {:?}", e); return None; } } match Secret::from_str(&buf) { Ok(key) => Some(key), - Err(e) => { + Err(e) => { warn!("Error parsing key file: {:?}", e); None } @@ -977,7 +989,7 @@ fn load_key(path: &Path) -> Option { #[test] fn key_save_load() { - use tests::helpers::RandomTempPath; + use ::devtools::RandomTempPath; let temp_path = RandomTempPath::create_dir(); let key = H256::random(); save_key(temp_path.as_path(), &key); diff --git a/util/src/network/node_table.rs b/util/src/network/node_table.rs index 7ca060f75..ec6bad2aa 100644 --- a/util/src/network/node_table.rs +++ b/util/src/network/node_table.rs @@ -159,7 +159,7 @@ impl Display for Node { Ok(()) } } - + impl FromStr for Node { type Err = UtilError; fn from_str(s: &str) -> Result { @@ -265,7 +265,7 @@ impl NodeTable { let node_ids = self.nodes(); for i in 0 .. node_ids.len() { let node = self.nodes.get(&node_ids[i]).unwrap(); - json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) + json.push_str(&format!("\t{{ \"url\": \"{}\", \"failures\": {} }}{}\n", node, node.failures, if i == node_ids.len() - 1 {""} else {","})) } json.push_str("]\n"); json.push_str("}"); @@ -297,14 +297,14 @@ impl NodeTable { let mut buf = String::new(); match file.read_to_string(&mut buf) { Ok(_) => {}, - Err(e) => { + Err(e) => { warn!("Error reading node table file: {:?}", e); return nodes; } } let json = match Json::from_str(&buf) { Ok(json) => json, - Err(e) => { + Err(e) => { warn!("Error parsing node table file: {:?}", e); return nodes; } @@ -344,7 +344,7 @@ mod tests { use std::str::FromStr; use std::net::*; use hash::*; - use tests::helpers::*; + use devtools::*; #[test] fn endpoint_parse() { diff --git a/util/src/network/session.rs b/util/src/network/session.rs index b0db5f7ef..edf929a9a 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -41,6 +41,8 @@ pub struct Session { connection: EncryptedConnection, /// Session ready flag. Set after successfull Hello packet exchange had_hello: bool, + /// Session is no longer active flag. + expired: bool, ping_time_ns: u64, pong_time_ns: Option, } @@ -109,8 +111,9 @@ const PACKET_USER: u8 = 0x10; const PACKET_LAST: u8 = 0x7f; impl Session { - /// Create a new session out of comepleted handshake. Consumes handshake object. - pub fn new(h: Handshake, host: &HostInfo) -> Result { + /// Create a new session out of comepleted handshake. This clones the handshake connection object + /// and leaves the handhsake in limbo to be deregistered from the event loop. + pub fn new(h: &mut Handshake, host: &HostInfo) -> Result { let id = h.id.clone(); let connection = try!(EncryptedConnection::new(h)); let mut session = Session { @@ -125,6 +128,7 @@ impl Session { }, ping_time_ns: 0, pong_time_ns: None, + expired: false, }; try!(session.write_hello(host)); try!(session.send_ping()); @@ -141,6 +145,16 @@ impl Session { self.had_hello } + /// Mark this session as inactive to be deleted lated. + pub fn set_expired(&mut self) { + self.expired = true; + } + + /// Check if this session is expired. + pub fn expired(&self) -> bool { + self.expired + } + /// Replace socket token pub fn set_token(&mut self, token: StreamToken) { self.connection.set_token(token); @@ -153,6 +167,9 @@ impl Session { /// Readable IO handler. Returns packet data if available. pub fn readable(&mut self, io: &IoContext, host: &HostInfo) -> Result where Message: Send + Sync + Clone { + if self.expired() { + return Ok(SessionData::None) + } match try!(self.connection.readable(io)) { Some(data) => Ok(try!(self.read_packet(data, host))), None => Ok(SessionData::None) @@ -161,6 +178,9 @@ impl Session { /// Writable IO handler. Sends pending packets. pub fn writable(&mut self, io: &IoContext, _host: &HostInfo) -> Result<(), UtilError> where Message: Send + Sync + Clone { + if self.expired() { + return Ok(()) + } self.connection.writable(io) } @@ -169,8 +189,20 @@ impl Session { self.info.capabilities.iter().any(|c| c.protocol == protocol) } + /// Register the session socket with the event loop + pub fn register_socket>(&self, reg: Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + if self.expired() { + return Ok(()); + } + try!(self.connection.register_socket(reg, event_loop)); + Ok(()) + } + /// Update registration with the event loop. Should be called at the end of the IO handler. pub fn update_socket(&self, reg:Token, event_loop: &mut EventLoop) -> Result<(), UtilError> { + if self.expired() { + return Ok(()); + } self.connection.update_socket(reg, event_loop) } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 44d53bdbe..f8ef588f6 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -74,7 +74,7 @@ impl NetworkProtocolHandler for TestProtocol { } fn connected(&self, io: &NetworkContext, peer: &PeerId) { - assert!(io.peer_info(*peer).contains("parity")); + assert!(io.peer_info(*peer).contains("Parity")); if self.drop_session { io.disconnect_peer(*peer) } else { diff --git a/util/src/panics.rs b/util/src/panics.rs index 18ed9ecb1..05d266b8b 100644 --- a/util/src/panics.rs +++ b/util/src/panics.rs @@ -18,7 +18,6 @@ use std::thread; use std::ops::DerefMut; -use std::any::Any; use std::sync::{Arc, Mutex}; /// Thread-safe closure for handling possible panics @@ -73,9 +72,8 @@ impl PanicHandler { /// Invoke closure and catch any possible panics. /// In case of panic notifies all listeners about it. #[cfg_attr(feature="dev", allow(deprecated))] - // TODO [todr] catch_panic is deprecated but panic::recover has different bounds (not allowing mutex) pub fn catch_panic(&self, g: G) -> thread::Result where G: FnOnce() -> R + Send + 'static { - let guard = PanicGuard { handler: self }; + let _guard = PanicGuard { handler: self }; let result = g(); Ok(result) } @@ -108,13 +106,6 @@ impl OnPanicListener for F } } -fn convert_to_string(t: &Box) -> Option { - let as_str = t.downcast_ref::<&'static str>().cloned().map(|t| t.to_owned()); - let as_string = t.downcast_ref::().cloned(); - - as_str.or(as_string) -} - #[test] #[ignore] // panic forwarding doesnt work on the same thread in beta fn should_notify_listeners_about_panic () { diff --git a/util/src/tests/helpers.rs b/util/src/tests/helpers.rs deleted file mode 100644 index fee3d2cbb..000000000 --- a/util/src/tests/helpers.rs +++ /dev/null @@ -1,31 +0,0 @@ -use common::*; -use std::path::PathBuf; -use std::fs::{remove_dir_all}; -use std::env; - -pub struct RandomTempPath { - path: PathBuf -} - -impl RandomTempPath { - pub fn create_dir() -> RandomTempPath { - let mut dir = env::temp_dir(); - dir.push(H32::random().hex()); - fs::create_dir_all(dir.as_path()).unwrap(); - RandomTempPath { - path: dir.clone() - } - } - - pub fn as_path(&self) -> &PathBuf { - &self.path - } -} - -impl Drop for RandomTempPath { - fn drop(&mut self) { - if let Err(e) = remove_dir_all(self.as_path()) { - panic!("failed to remove temp directory, probably something failed to destroyed ({})", e); - } - } -} diff --git a/util/src/tests/mod.rs b/util/src/tests/mod.rs deleted file mode 100644 index 1630fabcd..000000000 --- a/util/src/tests/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod helpers; diff --git a/util/src/uint.rs b/util/src/uint.rs index 912088fb9..7206a521e 100644 --- a/util/src/uint.rs +++ b/util/src/uint.rs @@ -991,7 +991,7 @@ mod tests { } #[test] - #[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]);