diff --git a/Cargo.lock b/Cargo.lock index bfae7a5dc..b95500540 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -266,7 +266,7 @@ dependencies = [ "log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", "rayon 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "syntex 0.33.0 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", @@ -399,7 +399,7 @@ dependencies = [ "nix 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rocksdb 0.4.5 (git+https://github.com/ethcore/rust-rocksdb)", - "rust-crypto 0.2.35 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (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.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -637,11 +637,6 @@ name = "lazy_static" version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -[[package]] -name = "libc" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" - [[package]] name = "libc" version = "0.2.10" @@ -1140,11 +1135,11 @@ dependencies = [ [[package]] name = "rust-crypto" -version = "0.2.35" +version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "gcc 0.3.28 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)", "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/README.md b/README.md index f807be3a4..acd873b74 100644 --- a/README.md +++ b/README.md @@ -43,20 +43,19 @@ Parity is fully compatible with Stable Rust. We recommend installing Rust through [rustup](https://www.rustup.rs/). If you don't already have rustup, you can install it like this: - Linux and OSX: -```bash -$ curl https://sh.rustup.rs -sSf | sh -``` + ```bash + $ curl https://sh.rustup.rs -sSf | sh + ``` - Windows -Make sure you have Visual Studio 2015 with C++ support installed, download and run [rustup](https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe) and use the following command to setup msvc toolchain: + Make sure you have Visual Studio 2015 with C++ support installed. Next, download and run the rustup installer from + https://static.rust-lang.org/rustup/dist/x86_64-pc-windows-msvc/rustup-init.exe and use the following command to install and set up the msvc toolchain: + ``` + $ rustup default stable-x86_64-pc-windows-msvc + ``` -``` -rustup default stable-x86_64-pc-windows-msvc -``` - - -Then, download and build Parity: +Once you have rustup, download and build parity: ```bash # download Parity code @@ -67,12 +66,11 @@ $ cd parity $ cargo build --release ``` -This will produce an executable in the `target/release` subdirectory. -Either run `cd target/release`, or copy `target/release/parity` to another location. +This will produce an executable in the `./target/release` subdirectory. To get started, just run ```bash -$ parity +$ ./target/release/parity ``` -and parity will begin syncing the Ethereum blockchain. +and parity will begin syncing the Ethereum blockchain. \ No newline at end of file diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 746da9069..c8b8d7b31 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -255,12 +255,21 @@ impl Ethash { /// Convert an Ethash boundary to its original difficulty. Basically just `f(x) = 2^256 / x`. pub fn boundary_to_difficulty(boundary: &H256) -> U256 { - U256::from((U512::one() << 256) / U256::from(boundary.as_slice()).into()) + let d = U256::from(*boundary); + if d <= U256::one() { + U256::max_value() + } else { + ((U256::one() << 255) / d) << 1 + } } /// Convert an Ethash difficulty to the target boundary. Basically just `f(x) = 2^256 / x`. pub fn difficulty_to_boundary(difficulty: &U256) -> H256 { - U256::from((U512::one() << 256) / difficulty.into()).into() + if *difficulty <= U256::one() { + U256::max_value().into() + } else { + (((U256::one() << 255) / *difficulty) << 1).into() + } } fn to_ethash(hash: H256) -> EH256 { @@ -291,12 +300,11 @@ impl Header { #[cfg(test)] mod tests { - extern crate ethash; - use common::*; use block::*; use tests::helpers::*; use super::super::new_morden; + use super::Ethash; #[test] fn on_close_block() { @@ -509,5 +517,15 @@ mod tests { } } + #[test] + fn test_difficulty_to_boundary() { + // result of f(0) is undefined, so do not assert the result + let _ = Ethash::difficulty_to_boundary(&U256::from(0)); + assert_eq!(Ethash::difficulty_to_boundary(&U256::from(1)), H256::from(U256::max_value())); + assert_eq!(Ethash::difficulty_to_boundary(&U256::from(2)), H256::from_str("8000000000000000000000000000000000000000000000000000000000000000").unwrap()); + assert_eq!(Ethash::difficulty_to_boundary(&U256::from(4)), H256::from_str("4000000000000000000000000000000000000000000000000000000000000000").unwrap()); + assert_eq!(Ethash::difficulty_to_boundary(&U256::from(32)), H256::from_str("0800000000000000000000000000000000000000000000000000000000000000").unwrap()); + } + // TODO: difficulty test } diff --git a/parity/configuration.rs b/parity/configuration.rs index 1e14cd1de..3aff2ee27 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -362,14 +362,12 @@ impl Configuration { } fn ipc_path(&self) -> String { - if self.args.flag_geth { self.geth_ipc_path() } - else { - if cfg!(windows) { - r"\\.\pipe\parity.jsonrpc".to_owned() - } - else { - Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) - } + if self.args.flag_geth { + self.geth_ipc_path() + } else if cfg!(windows) { + r"\\.\pipe\parity.jsonrpc".to_owned() + } else { + Configuration::replace_home(&self.args.flag_ipcpath.clone().unwrap_or(self.args.flag_ipc_path.clone())) } } diff --git a/parity/signer.rs b/parity/signer.rs index f8ff699df..3c8dceb6b 100644 --- a/parity/signer.rs +++ b/parity/signer.rs @@ -18,7 +18,7 @@ use std::io; use std::path::PathBuf; use std::sync::Arc; use util::panics::{PanicHandler, ForwardPanic}; -use util::keys::directory::restrict_permissions_owner; +use util::path::restrict_permissions_owner; use die::*; use rpc_apis; diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 5c205c087..28ba1a7de 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -212,6 +212,7 @@ fn from_params_default_third(params: Params) -> Result<(F1, F2, BlockNum // must be in range [-32099, -32000] const UNSUPPORTED_REQUEST_CODE: i64 = -32000; +const NO_WORK_CODE: i64 = -32001; fn make_unsupported_err() -> Error { Error { @@ -221,6 +222,14 @@ fn make_unsupported_err() -> Error { } } +fn no_work_err() -> Error { + Error { + code: ErrorCode::ServerError(NO_WORK_CODE), + message: "Still syncing.".into(), + data: None + } +} + impl Eth for EthClient where C: MiningBlockChainClient + 'static, S: SyncProvider + 'static, @@ -460,7 +469,7 @@ impl Eth for EthClient where //let sync = take_weak!(self.sync); if /*sync.status().state != SyncState::Idle ||*/ client.queue_info().total_queue_size() > MAX_QUEUE_SIZE_TO_MINE_ON { trace!(target: "miner", "Syncing. Cannot give any work."); - return to_value(&(String::new(), String::new(), String::new())); + return Err(no_work_err()); } } diff --git a/rpc/src/v1/tests/mocked/eth.rs b/rpc/src/v1/tests/mocked/eth.rs index 34708e232..45f8bd366 100644 --- a/rpc/src/v1/tests/mocked/eth.rs +++ b/rpc/src/v1/tests/mocked/eth.rs @@ -732,7 +732,7 @@ fn returns_no_work_if_cant_mine() { eth_tester.client.set_queue_size(10); let request = r#"{"jsonrpc": "2.0", "method": "eth_getWork", "params": [], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":["","",""],"id":1}"#; + let response = r#"{"jsonrpc":"2.0","error":{"code":-32001,"message":"Still syncing.","data":null},"id":1}"#; assert_eq!(eth_tester.io.handle_request(request), Some(response.to_owned())); } diff --git a/signer/src/ws_server/session.rs b/signer/src/ws_server/session.rs index 8cc3f5d07..b635f1524 100644 --- a/signer/src/ws_server/session.rs +++ b/signer/src/ws_server/session.rs @@ -75,7 +75,7 @@ impl ws::Handler for Session { let host = req.header("host").or_else(|| req.header("Host")); // Check request origin and host header. - if !origin_is_allowed(&self.self_origin, origin) && !origin_is_allowed(&self.self_origin, host) { + if !origin_is_allowed(&self.self_origin, origin) && !(origin.is_none() && origin_is_allowed(&self.self_origin, host)) { warn!(target: "signer", "Blocked connection to Signer API from untrusted origin."); return Ok(ws::Response::forbidden(format!("You are not allowed to access system ui. Use: http://{}", self.self_origin))); } diff --git a/util/bigint/src/uint.rs b/util/bigint/src/uint.rs index 286f6a43f..efb9d63d9 100644 --- a/util/bigint/src/uint.rs +++ b/util/bigint/src/uint.rs @@ -50,6 +50,12 @@ use std::cmp::*; use serde; use rustc_serialize::hex::{FromHex, FromHexError, ToHex}; +/// Conversion from decimal string error +#[derive(Debug, PartialEq)] +pub enum FromDecStrErr { + /// Value does not fit into type + InvalidLength +} macro_rules! impl_map_from { ($thing:ident, $from:ty, $to:ty) => { @@ -493,10 +499,8 @@ pub trait Uint: Sized + Default + FromStr + From + fmt::Debug + fmt::Displa /// Returns the largest value that can be represented by this integer type. fn max_value() -> Self; - /// Error type for converting from a decimal string. - type FromDecStrErr; /// Convert from a decimal string. - fn from_dec_str(value: &str) -> Result; + fn from_dec_str(value: &str) -> Result; /// Conversion to u32 fn low_u32(&self) -> u32; @@ -553,17 +557,22 @@ macro_rules! construct_uint { pub struct $name(pub [u64; $n_words]); impl Uint for $name { - type FromDecStrErr = FromHexError; /// TODO: optimize, throw appropriate err - fn from_dec_str(value: &str) -> Result { - Ok(value.bytes() - .map(|b| b - 48) - .fold($name::from(0u64), | acc, c | - // fast multiplication by 10 - // (acc << 3) + (acc << 1) => acc * 10 - (acc << 3) + (acc << 1) + $name::from(c) - )) + fn from_dec_str(value: &str) -> Result { + let mut res = Self::default(); + for b in value.bytes().map(|b| b - 48) { + let (r, overflow) = res.overflowing_mul_u32(10); + if overflow { + return Err(FromDecStrErr::InvalidLength); + } + let (r, overflow) = r.overflowing_add(b.into()); + if overflow { + return Err(FromDecStrErr::InvalidLength); + } + res = r; + } + Ok(res) } #[inline] @@ -1433,6 +1442,7 @@ known_heap_size!(0, U128, U256); mod tests { use uint::{Uint, U128, U256, U512}; use std::str::FromStr; + use super::FromDecStrErr; #[test] pub fn uint256_from() { @@ -1802,6 +1812,7 @@ mod tests { fn uint256_from_dec_str() { assert_eq!(U256::from_dec_str("10").unwrap(), U256::from(10u64)); assert_eq!(U256::from_dec_str("1024").unwrap(), U256::from(1024u64)); + assert_eq!(U256::from_dec_str("115792089237316195423570985008687907853269984665640564039457584007913129639936"), Err(FromDecStrErr::InvalidLength)); } #[test] diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index d9d453409..32ac14b55 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -18,6 +18,7 @@ use common::*; use std::path::{PathBuf}; +use path::restrict_permissions_owner; const CURRENT_DECLARED_VERSION: u64 = 3; const MAX_KEY_FILE_LEN: u64 = 1024 * 80; @@ -465,23 +466,6 @@ pub struct KeyDirectory { cache_usage: RwLock>, } -/// Restricts the permissions of given path only to the owner. -#[cfg(not(windows))] -pub fn restrict_permissions_owner(file_path: &Path) -> Result<(), i32> { - let cstr = ::std::ffi::CString::new(file_path.to_str().unwrap()).unwrap(); - match unsafe { ::libc::chmod(cstr.as_ptr(), ::libc::S_IWUSR | ::libc::S_IRUSR) } { - 0 => Ok(()), - x => Err(x), - } -} - -/// Restricts the permissions of given path only to the owner. -#[cfg(windows)] -pub fn restrict_permissions_owner(_file_path: &Path) -> Result<(), i32> { - //TODO: implement me - Ok(()) -} - impl KeyDirectory { /// Initializes new cache directory context with a given `path` pub fn new(path: &Path) -> KeyDirectory { diff --git a/util/src/network/host.rs b/util/src/network/host.rs index abace1983..b37538c9c 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -41,6 +41,7 @@ use network::stats::NetworkStats; use network::error::{NetworkError, DisconnectReason}; use network::discovery::{Discovery, TableUpdates, NodeEntry}; use network::ip_utils::{map_external_address, select_public_address}; +use path::restrict_permissions_owner; type Slab = ::slab::Slab; @@ -946,13 +947,17 @@ fn save_key(path: &Path, key: &Secret) { return; }; path_buf.push("key"); - let mut file = match fs::File::create(path_buf.as_path()) { + let path = path_buf.as_path(); + let mut file = match fs::File::create(&path) { Ok(file) => file, Err(e) => { warn!("Error creating key file: {:?}", e); return; } }; + if let Err(e) = restrict_permissions_owner(&path) { + warn!(target: "network", "Failed to modify permissions of the file (chmod: {})", e); + } if let Err(e) = file.write(&key.hex().into_bytes()) { warn!("Error writing key file: {:?}", e); } diff --git a/util/src/path.rs b/util/src/path.rs index 899650149..023269a69 100644 --- a/util/src/path.rs +++ b/util/src/path.rs @@ -15,6 +15,7 @@ // along with Parity. If not, see . //! Path utilities +use std::path::Path; /// Default ethereum paths pub mod ethereum { @@ -62,3 +63,21 @@ pub mod ethereum { pth } } + +/// Restricts the permissions of given path only to the owner. +#[cfg(not(windows))] +pub fn restrict_permissions_owner(file_path: &Path) -> Result<(), i32> { + let cstr = ::std::ffi::CString::new(file_path.to_str().unwrap()).unwrap(); + match unsafe { ::libc::chmod(cstr.as_ptr(), ::libc::S_IWUSR | ::libc::S_IRUSR) } { + 0 => Ok(()), + x => Err(x), + } +} + +/// Restricts the permissions of given path only to the owner. +#[cfg(windows)] +pub fn restrict_permissions_owner(_file_path: &Path) -> Result<(), i32> { + //TODO: implement me + Ok(()) +} + diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index a92dd5c4a..3df2f2d97 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -429,3 +429,10 @@ fn test_rlp_nested_empty_list_encode() { assert_eq!(stream.drain()[..], [0xc2u8, 0xc0u8, 40u8][..]); } +#[test] +fn test_rlp_list_length_overflow() { + let data: Vec = vec![0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00]; + let rlp = UntrustedRlp::new(&data); + let as_val: Result = rlp.val_at(0); + assert_eq!(Err(DecoderError::RlpIsTooShort), as_val); +} diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 6109a643b..8e9b6d70e 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -334,9 +334,9 @@ impl<'a> BasicDecoder<'a> { /// Return first item info. fn payload_info(bytes: &[u8]) -> Result { let item = try!(PayloadInfo::from(bytes)); - match item.header_len + item.value_len <= bytes.len() { - true => Ok(item), - false => Err(DecoderError::RlpIsTooShort), + match item.header_len.checked_add(item.value_len) { + Some(x) if x <= bytes.len() => Ok(item), + _ => Err(DecoderError::RlpIsTooShort), } } }