diff --git a/Cargo.lock b/Cargo.lock index 74bedf9a8..d0f3c2803 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -257,7 +257,7 @@ dependencies = [ name = "common-types" version = "0.1.0" dependencies = [ - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethjson 0.1.0", "rlp 0.2.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -459,7 +459,7 @@ dependencies = [ "ethcore-ipc-nano 1.7.0", "ethcore-logger 1.7.0", "ethcore-stratum 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethjson 0.1.0", "ethkey 0.2.0", "ethstore 0.1.0", @@ -527,7 +527,7 @@ name = "ethcore-ipc" version = "1.7.0" dependencies = [ "ethcore-devtools 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -576,7 +576,7 @@ dependencies = [ "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", "ethcore-ipc-nano 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "nanomsg 0.5.1 (git+https://github.com/paritytech/nanomsg.rs.git?branch=parity-1.7)", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -593,7 +593,7 @@ dependencies = [ "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", "ethcore-network 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "evm 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -632,7 +632,7 @@ dependencies = [ "ethcore-devtools 1.7.0", "ethcore-io 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethcrypto 0.1.0", "ethkey 0.2.0", "igd 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -663,7 +663,7 @@ dependencies = [ "ethcore-ipc-codegen 1.7.0", "ethcore-ipc-nano 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethcrypto 0.1.0", "ethkey 0.2.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", @@ -693,7 +693,7 @@ dependencies = [ "ethcore-ipc-codegen 1.7.0", "ethcore-ipc-nano 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-macros 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -706,7 +706,7 @@ dependencies = [ [[package]] name = "ethcore-util" -version = "1.7.0" +version = "1.7.1" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", @@ -756,7 +756,7 @@ name = "ethjson" version = "0.1.0" dependencies = [ "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -837,7 +837,7 @@ dependencies = [ "ethcore-ipc-nano 1.7.0", "ethcore-light 1.7.0", "ethcore-network 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethkey 0.2.0", "heapsize 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -856,7 +856,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "common-types 0.1.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethjson 0.1.0", "evmjit 1.7.0", "lazy_static 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", @@ -873,7 +873,7 @@ version = "0.1.0" dependencies = [ "docopt 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "evm 0.1.0", "rustc-hex 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "serde 1.0.9 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1118,7 +1118,7 @@ version = "1.7.0" dependencies = [ "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "semver 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1148,7 +1148,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "jsonrpc-core" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1160,7 +1160,7 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "hyper 0.10.0-a.0 (git+https://github.com/paritytech/hyper)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1173,7 +1173,7 @@ dependencies = [ [[package]] name = "jsonrpc-ipc-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1186,7 +1186,7 @@ dependencies = [ [[package]] name = "jsonrpc-macros" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-pubsub 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1196,7 +1196,7 @@ dependencies = [ [[package]] name = "jsonrpc-minihttp-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1211,7 +1211,7 @@ dependencies = [ [[package]] name = "jsonrpc-pubsub" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1221,7 +1221,7 @@ dependencies = [ [[package]] name = "jsonrpc-server-utils" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "globset 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1234,7 +1234,7 @@ dependencies = [ [[package]] name = "jsonrpc-tcp-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "bytes 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1248,7 +1248,7 @@ dependencies = [ [[package]] name = "jsonrpc-ws-server" version = "7.0.0" -source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#5e79be8a098cdda221713992f4a46b41a1d4d8f0" +source = "git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7#b5490782884218c5ccf74cd61e54904cb3a3aeed" dependencies = [ "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-server-utils 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1512,7 +1512,7 @@ version = "0.1.0" dependencies = [ "byteorder 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "native-contract-generator 0.1.0", ] @@ -1702,7 +1702,7 @@ dependencies = [ [[package]] name = "parity" -version = "1.7.0" +version = "1.7.1" dependencies = [ "ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", "app_dirs 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1722,7 +1722,7 @@ dependencies = [ "ethcore-logger 1.7.0", "ethcore-secretstore 1.0.0", "ethcore-stratum 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethkey 0.2.0", "ethsync 1.7.0", "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1767,7 +1767,7 @@ dependencies = [ "clippy 0.0.103 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore-devtools 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "futures-cpupool 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1812,7 +1812,7 @@ name = "parity-hash-fetch" version = "1.7.0" dependencies = [ "ethabi 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "fetch 0.1.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1830,7 +1830,7 @@ version = "1.7.0" dependencies = [ "cid 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "jsonrpc-http-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "mime 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "multihash 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1843,7 +1843,7 @@ version = "0.1.0" dependencies = [ "ethcore 1.7.0", "ethcore-io 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethkey 0.2.0", "log 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)", "rlp 0.2.0", @@ -1873,7 +1873,7 @@ dependencies = [ "ethcore-ipc 1.7.0", "ethcore-light 1.7.0", "ethcore-logger 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethcrypto 0.1.0", "ethjson 0.1.0", "ethkey 0.2.0", @@ -1914,7 +1914,7 @@ dependencies = [ name = "parity-rpc-client" version = "1.4.0" dependencies = [ - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", "jsonrpc-ws-server 7.0.0 (git+https://github.com/paritytech/jsonrpc.git?branch=parity-1.7)", @@ -1977,7 +1977,7 @@ dependencies = [ "ethcore 1.7.0", "ethcore-ipc 1.7.0", "ethcore-ipc-codegen 1.7.0", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "ethsync 1.7.0", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "ipc-common-types 1.7.0", @@ -2324,7 +2324,7 @@ name = "rpc-cli" version = "1.4.0" dependencies = [ "bigint 3.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "ethcore-util 1.7.0", + "ethcore-util 1.7.1", "futures 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)", "parity-rpc 1.7.0", "parity-rpc-client 1.4.0", diff --git a/Cargo.toml b/Cargo.toml index 93341b564..26688fa86 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,7 +1,7 @@ [package] description = "Parity Ethereum client" name = "parity" -version = "1.7.0" +version = "1.7.1" license = "GPL-3.0" authors = ["Parity Technologies "] build = "build.rs" diff --git a/dapps/src/api/api.rs b/dapps/src/api/api.rs index 7d38e288f..3452669b6 100644 --- a/dapps/src/api/api.rs +++ b/dapps/src/api/api.rs @@ -21,7 +21,7 @@ use hyper::method::Method; use hyper::status::StatusCode; use api::{response, types}; -use api::time::TimeChecker; +use api::time::{TimeChecker, MAX_DRIFT}; use apps::fetcher::Fetcher; use handlers::{self, extract_url}; use endpoint::{Endpoint, Handler, EndpointPath}; @@ -122,7 +122,6 @@ impl RestApiRouter { // Check time let time = { - const MAX_DRIFT: i64 = 500; let (status, message, details) = match time { Ok(Ok(diff)) if diff < MAX_DRIFT && diff > -MAX_DRIFT => { (HealthStatus::Ok, "".into(), diff) diff --git a/dapps/src/api/time.rs b/dapps/src/api/time.rs index b81b4a844..8ce79f6ad 100644 --- a/dapps/src/api/time.rs +++ b/dapps/src/api/time.rs @@ -33,10 +33,12 @@ use std::io; use std::{fmt, mem, time}; +use std::sync::atomic::{self, AtomicUsize}; use std::collections::VecDeque; use futures::{self, Future, BoxFuture}; -use futures_cpupool::CpuPool; +use futures::future::{self, IntoFuture}; +use futures_cpupool::{CpuPool, CpuFuture}; use ntp; use time::{Duration, Timespec}; use util::{Arc, RwLock}; @@ -44,6 +46,8 @@ use util::{Arc, RwLock}; /// Time checker error. #[derive(Debug, Clone, PartialEq)] pub enum Error { + /// No servers are currently available for a query. + NoServersAvailable, /// There was an error when trying to reach the NTP server. Ntp(String), /// IO error when reading NTP response. @@ -55,6 +59,7 @@ impl fmt::Display for Error { use self::Error::*; match *self { + NoServersAvailable => write!(fmt, "No NTP servers available"), Ntp(ref err) => write!(fmt, "NTP error: {}", err), Io(ref err) => write!(fmt, "Connection Error: {}", err), } @@ -71,58 +76,123 @@ impl From for Error { /// NTP time drift checker. pub trait Ntp { + /// Returned Future. + type Future: IntoFuture; + /// Returns the current time drift. - fn drift(&self) -> BoxFuture; + fn drift(&self) -> Self::Future; +} + +const SERVER_MAX_POLL_INTERVAL_SECS: u64 = 60; +#[derive(Debug)] +struct Server { + pub address: String, + next_call: RwLock, + failures: AtomicUsize, +} + +impl Server { + pub fn is_available(&self) -> bool { + *self.next_call.read() < time::Instant::now() + } + + pub fn report_success(&self) { + self.failures.store(0, atomic::Ordering::SeqCst); + self.update_next_call(1) + } + + pub fn report_failure(&self) { + let errors = self.failures.fetch_add(1, atomic::Ordering::SeqCst); + self.update_next_call(1 << errors) + } + + fn update_next_call(&self, delay: usize) { + *self.next_call.write() = time::Instant::now() + time::Duration::from_secs(delay as u64 * SERVER_MAX_POLL_INTERVAL_SECS); + } +} + +impl> From for Server { + fn from(t: T) -> Self { + Server { + address: t.as_ref().to_owned(), + next_call: RwLock::new(time::Instant::now()), + failures: Default::default(), + } + } } /// NTP client using the SNTP algorithm for calculating drift. #[derive(Clone)] pub struct SimpleNtp { - address: Arc, + addresses: Vec>, pool: CpuPool, } impl fmt::Debug for SimpleNtp { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "Ntp {{ address: {} }}", self.address) + f + .debug_struct("SimpleNtp") + .field("addresses", &self.addresses) + .finish() } } impl SimpleNtp { - fn new(address: &str, pool: CpuPool) -> SimpleNtp { + fn new>(addresses: &[T], pool: CpuPool) -> SimpleNtp { SimpleNtp { - address: Arc::new(address.to_owned()), + addresses: addresses.iter().map(Server::from).map(Arc::new).collect(), pool: pool, } } } impl Ntp for SimpleNtp { - fn drift(&self) -> BoxFuture { - let address = self.address.clone(); - if &*address == "none" { - return futures::future::err(Error::Ntp("NTP server is not provided.".into())).boxed(); - } + type Future = future::Either< + CpuFuture, + future::FutureResult, + >; - self.pool.spawn_fn(move || { - let packet = ntp::request(&*address)?; - let dest_time = ::time::now_utc().to_timespec(); - let orig_time = Timespec::from(packet.orig_time); - let recv_time = Timespec::from(packet.recv_time); - let transmit_time = Timespec::from(packet.transmit_time); + fn drift(&self) -> Self::Future { + use self::future::Either::{A, B}; - let drift = ((recv_time - orig_time) + (transmit_time - dest_time)) / 2; + let server = self.addresses.iter().find(|server| server.is_available()); + server.map(|server| { + let server = server.clone(); + A(self.pool.spawn_fn(move || { + debug!(target: "dapps", "Fetching time from {}.", server.address); - Ok(drift) - }).boxed() + match ntp::request(&server.address) { + Ok(packet) => { + let dest_time = ::time::now_utc().to_timespec(); + let orig_time = Timespec::from(packet.orig_time); + let recv_time = Timespec::from(packet.recv_time); + let transmit_time = Timespec::from(packet.transmit_time); + + let drift = ((recv_time - orig_time) + (transmit_time - dest_time)) / 2; + + server.report_success(); + Ok(drift) + }, + Err(err) => { + server.report_failure(); + Err(err.into()) + }, + } + })) + }).unwrap_or_else(|| B(future::err(Error::NoServersAvailable))) } } // NOTE In a positive scenario first results will be seen after: -// MAX_RESULTS * UPDATE_TIMEOUT_OK_SECS seconds. -const MAX_RESULTS: usize = 7; -const UPDATE_TIMEOUT_OK_SECS: u64 = 30; -const UPDATE_TIMEOUT_ERR_SECS: u64 = 2; +// MAX_RESULTS * UPDATE_TIMEOUT_INCOMPLETE_SECS seconds. +const MAX_RESULTS: usize = 4; +const UPDATE_TIMEOUT_OK_SECS: u64 = 6 * 60 * 60; +const UPDATE_TIMEOUT_WARN_SECS: u64 = 15 * 60; +const UPDATE_TIMEOUT_ERR_SECS: u64 = 60; +const UPDATE_TIMEOUT_INCOMPLETE_SECS: u64 = 10; + +/// Maximal valid time drift. +pub const MAX_DRIFT: i64 = 500; #[derive(Debug, Clone)] /// A time checker. @@ -133,13 +203,13 @@ pub struct TimeChecker { impl TimeChecker { /// Creates new time checker given the NTP server address. - pub fn new(ntp_address: String, pool: CpuPool) -> Self { + pub fn new>(ntp_addresses: &[T], pool: CpuPool) -> Self { let last_result = Arc::new(RwLock::new( // Assume everything is ok at the very beginning. (time::Instant::now(), vec![Ok(0)].into()) )); - let ntp = SimpleNtp::new(&ntp_address, pool); + let ntp = SimpleNtp::new(ntp_addresses, pool); TimeChecker { ntp, @@ -148,22 +218,34 @@ impl TimeChecker { } } -impl TimeChecker { +impl TimeChecker where ::Future: Send + 'static { /// Updates the time pub fn update(&self) -> BoxFuture { + trace!(target: "dapps", "Updating time from NTP."); let last_result = self.last_result.clone(); - self.ntp.drift().then(move |res| { + self.ntp.drift().into_future().then(move |res| { + let res = res.map(|d| d.num_milliseconds()); + + if let Err(Error::NoServersAvailable) = res { + debug!(target: "dapps", "No NTP servers available. Selecting an older result."); + return select_result(last_result.read().1.iter()); + } + + // Update the results. let mut results = mem::replace(&mut last_result.write().1, VecDeque::new()); + let has_all_results = results.len() >= MAX_RESULTS; let valid_till = time::Instant::now() + time::Duration::from_secs( - if res.is_ok() && results.len() == MAX_RESULTS { - UPDATE_TIMEOUT_OK_SECS - } else { - UPDATE_TIMEOUT_ERR_SECS + match res { + Ok(time) if has_all_results && time < MAX_DRIFT => UPDATE_TIMEOUT_OK_SECS, + Ok(_) if has_all_results => UPDATE_TIMEOUT_WARN_SECS, + Err(_) if has_all_results => UPDATE_TIMEOUT_ERR_SECS, + _ => UPDATE_TIMEOUT_INCOMPLETE_SECS, } ); + trace!(target: "dapps", "New time drift received: {:?}", res); // Push the result. - results.push_back(res.map(|d| d.num_milliseconds())); + results.push_back(res); while results.len() > MAX_RESULTS { results.pop_front(); } @@ -208,7 +290,7 @@ mod tests { use std::cell::{Cell, RefCell}; use std::time::Instant; use time::Duration; - use futures::{self, BoxFuture, Future}; + use futures::{future, Future}; use super::{Ntp, TimeChecker, Error}; use util::RwLock; @@ -223,9 +305,11 @@ mod tests { } impl Ntp for FakeNtp { - fn drift(&self) -> BoxFuture { + type Future = future::FutureResult; + + fn drift(&self) -> Self::Future { self.1.set(self.1.get() + 1); - futures::future::ok(self.0.borrow_mut().pop().expect("Unexpected call to drift().")).boxed() + future::ok(self.0.borrow_mut().pop().expect("Unexpected call to drift().")) } } diff --git a/dapps/src/handlers/mod.rs b/dapps/src/handlers/mod.rs index 7937ce667..65c2cbe27 100644 --- a/dapps/src/handlers/mod.rs +++ b/dapps/src/handlers/mod.rs @@ -67,10 +67,20 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd // Allow fonts from data: and HTTPS. b"font-src 'self' data: https:;".to_vec(), // Allow inline scripts and scripts eval (webpack/jsconsole) - b"script-src 'self' 'unsafe-inline' 'unsafe-eval';".to_vec(), - // Same restrictions as script-src (fallback) with additional + { + let script_src = embeddable_on.as_ref() + .map(|e| e.extra_script_src.iter() + .map(|&(ref host, port)| address(host, port)) + .join(" ") + ).unwrap_or_default(); + format!( + "script-src 'self' 'unsafe-inline' 'unsafe-eval' {};", + script_src + ).into_bytes() + }, + // Same restrictions as script-src with additional // blob: that is required for camera access (worker) - b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' blob: ;".to_vec(), + b"worker-src 'self' 'unsafe-inline' 'unsafe-eval' https: blob:;".to_vec(), // Restrict everything else to the same origin. b"default-src 'self';".to_vec(), // Run in sandbox mode (although it's not fully safe since we allow same-origin and script) @@ -90,7 +100,7 @@ pub fn add_security_headers(headers: &mut header::Headers, embeddable_on: Embedd .into_iter() .chain(embed.extra_embed_on .iter() - .map(|&(ref host, port)| format!("{}:{}", host, port)) + .map(|&(ref host, port)| address(host, port)) ); let ancestors = if embed.host == "127.0.0.1" { diff --git a/dapps/src/lib.rs b/dapps/src/lib.rs index 0cb7024cc..daa415edb 100644 --- a/dapps/src/lib.rs +++ b/dapps/src/lib.rs @@ -130,7 +130,7 @@ impl Middleware { /// Creates new middleware for UI server. pub fn ui( - ntp_server: &str, + ntp_servers: &[String], pool: CpuPool, remote: Remote, dapps_domain: &str, @@ -146,7 +146,7 @@ impl Middleware { ).embeddable_on(None).allow_dapps(false)); let special = { let mut special = special_endpoints( - ntp_server, + ntp_servers, pool, content_fetcher.clone(), remote.clone(), @@ -171,11 +171,12 @@ impl Middleware { /// Creates new Dapps server middleware. pub fn dapps( - ntp_server: &str, + ntp_servers: &[String], pool: CpuPool, remote: Remote, ui_address: Option<(String, u16)>, extra_embed_on: Vec<(String, u16)>, + extra_script_src: Vec<(String, u16)>, dapps_path: PathBuf, extra_dapps: Vec, dapps_domain: &str, @@ -184,7 +185,7 @@ impl Middleware { web_proxy_tokens: Arc, fetch: F, ) -> Self { - let embeddable = as_embeddable(ui_address, extra_embed_on, dapps_domain); + let embeddable = as_embeddable(ui_address, extra_embed_on, extra_script_src, dapps_domain); let content_fetcher = Arc::new(apps::fetcher::ContentFetcher::new( hash_fetch::urlhint::URLHintContract::new(registrar), sync_status.clone(), @@ -203,7 +204,7 @@ impl Middleware { let special = { let mut special = special_endpoints( - ntp_server, + ntp_servers, pool, content_fetcher.clone(), remote.clone(), @@ -237,8 +238,8 @@ impl http::RequestMiddleware for Middleware { } } -fn special_endpoints( - ntp_server: &str, +fn special_endpoints>( + ntp_servers: &[T], pool: CpuPool, content_fetcher: Arc, remote: Remote, @@ -250,7 +251,7 @@ fn special_endpoints( special.insert(router::SpecialEndpoint::Api, Some(api::RestApi::new( content_fetcher, sync_status, - api::TimeChecker::new(ntp_server.into(), pool), + api::TimeChecker::new(ntp_servers, pool), remote, ))); special @@ -263,12 +264,14 @@ fn address(host: &str, port: u16) -> String { fn as_embeddable( ui_address: Option<(String, u16)>, extra_embed_on: Vec<(String, u16)>, + extra_script_src: Vec<(String, u16)>, dapps_domain: &str, ) -> Option { ui_address.map(|(host, port)| ParentFrameSettings { host, port, extra_embed_on, + extra_script_src, dapps_domain: dapps_domain.to_owned(), }) } @@ -289,8 +292,10 @@ pub struct ParentFrameSettings { pub host: String, /// Port pub port: u16, - /// Additional pages the pages can be embedded on. + /// Additional URLs the dapps can be embedded on. pub extra_embed_on: Vec<(String, u16)>, + /// Additional URLs the dapp scripts can be loaded from. + pub extra_script_src: Vec<(String, u16)>, /// Dapps Domain (web3.site) pub dapps_domain: String, } diff --git a/dapps/src/tests/helpers/mod.rs b/dapps/src/tests/helpers/mod.rs index 2d9d5f341..30d3ba8f9 100644 --- a/dapps/src/tests/helpers/mod.rs +++ b/dapps/src/tests/helpers/mod.rs @@ -255,11 +255,12 @@ impl Server { fetch: F, ) -> Result { let middleware = Middleware::dapps( - "pool.ntp.org:123", + &["0.pool.ntp.org:123".into(), "1.pool.ntp.org:123".into()], CpuPool::new(4), remote, signer_address, vec![], + vec![], dapps_path, extra_dapps, DAPPS_DOMAIN.into(), diff --git a/ethcore/src/engines/authority_round/mod.rs b/ethcore/src/engines/authority_round/mod.rs index 018489f26..8f0170526 100644 --- a/ethcore/src/engines/authority_round/mod.rs +++ b/ethcore/src/engines/authority_round/mod.rs @@ -705,6 +705,7 @@ impl Engine for AuthorityRound { // apply immediate transitions. if let Some(change) = self.validators.is_epoch_end(first, chain_head) { + let change = combine_proofs(chain_head.number(), &change, &[]); return Some(change) } diff --git a/ethcore/src/miner/stratum.rs b/ethcore/src/miner/stratum.rs index e419247f0..0031bb715 100644 --- a/ethcore/src/miner/stratum.rs +++ b/ethcore/src/miner/stratum.rs @@ -32,7 +32,6 @@ use util::Mutex; use miner::{self, Miner, MinerService}; use client::Client; use block::IsBlock; -use std::str::FromStr; use rlp::encode; /// Configures stratum server options. @@ -60,7 +59,7 @@ impl SubmitPayload { return Err(PayloadError::ArgumentsAmountUnexpected(payload.len())); } - let nonce = match H64::from_str(clean_0x(&payload[0])) { + let nonce = match clean_0x(&payload[0]).parse::() { Ok(nonce) => nonce, Err(e) => { warn!(target: "stratum", "submit_work ({}): invalid nonce ({:?})", &payload[0], e); @@ -68,7 +67,7 @@ impl SubmitPayload { } }; - let pow_hash = match H256::from_str(clean_0x(&payload[1])) { + let pow_hash = match clean_0x(&payload[1]).parse::() { Ok(pow_hash) => pow_hash, Err(e) => { warn!(target: "stratum", "submit_work ({}): invalid hash ({:?})", &payload[1], e); @@ -76,7 +75,7 @@ impl SubmitPayload { } }; - let mix_hash = match H256::from_str(clean_0x(&payload[2])) { + let mix_hash = match clean_0x(&payload[2]).parse::() { Ok(mix_hash) => mix_hash, Err(e) => { warn!(target: "stratum", "submit_work ({}): invalid mix-hash ({:?})", &payload[2], e); @@ -133,7 +132,7 @@ impl JobDispatcher for StratumJobDispatcher { fn submit(&self, payload: Vec) -> Result<(), StratumServiceError> { let payload = SubmitPayload::from_args(payload).map_err(|e| - StratumServiceError::Dispatch(format!("{}", e)) + StratumServiceError::Dispatch(e.to_string()) )?; trace!( @@ -144,14 +143,16 @@ impl JobDispatcher for StratumJobDispatcher { payload.mix_hash, ); - self.with_core_void(|client, miner| { + self.with_core_result(|client, miner| { let seal = vec![encode(&payload.mix_hash).into_vec(), encode(&payload.nonce).into_vec()]; - if let Err(e) = miner.submit_seal(&*client, payload.pow_hash, seal) { - warn!(target: "stratum", "submit_seal error: {:?}", e); - }; - }); - - Ok(()) + match miner.submit_seal(&*client, payload.pow_hash, seal) { + Ok(_) => Ok(()), + Err(e) => { + warn!(target: "stratum", "submit_seal error: {:?}", e); + Err(StratumServiceError::Dispatch(e.to_string())) + } + } + }) } } @@ -181,8 +182,11 @@ impl StratumJobDispatcher { self.client.upgrade().and_then(|client| self.miner.upgrade().and_then(|miner| (f)(client, miner))) } - fn with_core_void(&self, f: F) where F: Fn(Arc, Arc) { - self.client.upgrade().map(|client| self.miner.upgrade().map(|miner| (f)(client, miner))); + fn with_core_result(&self, f: F) -> Result<(), StratumServiceError> where F: Fn(Arc, Arc) -> Result<(), StratumServiceError> { + match (self.client.upgrade(), self.miner.upgrade()) { + (Some(client), Some(miner)) => f(client, miner), + _ => Ok(()), + } } } @@ -230,7 +234,7 @@ impl Stratum { let dispatcher = Arc::new(StratumJobDispatcher::new(miner, client)); let stratum_svc = StratumService::start( - &SocketAddr::new(IpAddr::from_str(&options.listen_addr)?, options.port), + &SocketAddr::new(options.listen_addr.parse::()?, options.port), dispatcher.clone(), options.secret.clone(), )?; diff --git a/mac/Parity.pkgproj b/mac/Parity.pkgproj index cc7810dba..8179fa168 100755 --- a/mac/Parity.pkgproj +++ b/mac/Parity.pkgproj @@ -462,7 +462,7 @@ OVERWRITE_PERMISSIONS VERSION - 1.7.0 + 1.7.1 UUID 2DCD5B81-7BAF-4DA1-9251-6274B089FD36 diff --git a/nsis/installer.nsi b/nsis/installer.nsi index 564fbfce8..fe769256f 100644 --- a/nsis/installer.nsi +++ b/nsis/installer.nsi @@ -10,7 +10,7 @@ !define DESCRIPTION "Fast, light, robust Ethereum implementation" !define VERSIONMAJOR 1 !define VERSIONMINOR 7 -!define VERSIONBUILD 0 +!define VERSIONBUILD 1 !define ARGS "--warp" !define FIRST_START_ARGS "ui --warp --mode=passive" diff --git a/parity/cli/config.toml b/parity/cli/config.toml index 0ad9e7753..459deaea0 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -78,7 +78,7 @@ disable_periodic = true jit = false [misc] -ntp_server = "pool.ntp.org:123" +ntp_servers = ["0.parity.pool.ntp.org:123"] logging = "own_tx=trace" log_file = "/var/log/parity.log" color = true diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index b27809970..b3f899b86 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -356,8 +356,8 @@ usage! { or |c: &Config| otry!(c.vm).jit.clone(), // -- Miscellaneous Options - flag_ntp_server: String = "none", - or |c: &Config| otry!(c.misc).ntp_server.clone(), + flag_ntp_servers: String = "0.parity.pool.ntp.org:123,1.parity.pool.ntp.org:123,2.parity.pool.ntp.org:123,3.parity.pool.ntp.org:123", + or |c: &Config| otry!(c.misc).ntp_servers.clone().map(|vec| vec.join(",")), flag_logging: Option = None, or |c: &Config| otry!(c.misc).logging.clone().map(Some), flag_log_file: Option = None, @@ -595,7 +595,7 @@ struct VM { #[derive(Default, Debug, PartialEq, Deserialize)] struct Misc { - ntp_server: Option, + ntp_servers: Option>, logging: Option, log_file: Option, color: Option, @@ -897,7 +897,7 @@ mod tests { flag_dapps_apis_all: None, // -- Miscellaneous Options - flag_ntp_server: "none".into(), + flag_ntp_servers: "0.parity.pool.ntp.org:123,1.parity.pool.ntp.org:123,2.parity.pool.ntp.org:123,3.parity.pool.ntp.org:123".into(), flag_version: false, flag_logging: Some("own_tx=trace".into()), flag_log_file: Some("/var/log/parity.log".into()), @@ -1075,7 +1075,7 @@ mod tests { jit: Some(false), }), misc: Some(Misc { - ntp_server: Some("pool.ntp.org:123".into()), + ntp_servers: Some(vec!["0.parity.pool.ntp.org:123".into()]), logging: Some("own_tx=trace".into()), log_file: Some("/var/log/parity.log".into()), color: Some(true), diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index dc4796e05..c82fe5762 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -470,8 +470,10 @@ Internal Options: --can-restart Executable will auto-restart if exiting with 69. Miscellaneous Options: - --ntp-server HOST NTP server to provide current time (host:port). Used to verify node health. - (default: {flag_ntp_server}) + --ntp-servers HOSTS Comma separated list of NTP servers to provide current time (host:port). + Used to verify node health. Parity uses pool.ntp.org NTP servers, + consider joining the pool: http://www.pool.ntp.org/join.html + (default: {flag_ntp_servers}) -l --logging LOGGING Specify the logging level. Must conform to the same format as RUST_LOG. (default: {flag_logging:?}) --log-file FILENAME Specify a filename into which logging should be diff --git a/parity/configuration.rs b/parity/configuration.rs index 5815230dd..dabe20e59 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -20,6 +20,7 @@ use std::net::SocketAddr; use std::path::{Path, PathBuf}; use std::collections::BTreeMap; use std::cmp::max; +use std::str::FromStr; use cli::{Args, ArgsError}; use util::{Hashable, H256, U256, Bytes, version_data, Address}; use util::journaldb::Algorithm; @@ -556,31 +557,57 @@ impl Configuration { Ok(options) } + fn ui_port(&self) -> u16 { + self.args.flag_ports_shift + self.args.flag_ui_port + } + + fn ntp_servers(&self) -> Vec { + self.args.flag_ntp_servers.split(",").map(str::to_owned).collect() + } + fn ui_config(&self) -> UiConfiguration { UiConfiguration { enabled: self.ui_enabled(), - ntp_server: self.args.flag_ntp_server.clone(), + ntp_servers: self.ntp_servers(), interface: self.ui_interface(), - port: self.args.flag_ports_shift + self.args.flag_ui_port, + port: self.ui_port(), hosts: self.ui_hosts(), } } fn dapps_config(&self) -> DappsConfiguration { + let dev_ui = if self.args.flag_ui_no_validation { vec![("localhost".to_owned(), 3000)] } else { vec![] }; + let ui_port = self.ui_port(); + DappsConfiguration { enabled: self.dapps_enabled(), - ntp_server: self.args.flag_ntp_server.clone(), + ntp_servers: self.ntp_servers(), dapps_path: PathBuf::from(self.directories().dapps), extra_dapps: if self.args.cmd_dapp { self.args.arg_path.iter().map(|path| PathBuf::from(path)).collect() } else { vec![] }, - extra_embed_on: if self.args.flag_ui_no_validation { - vec![("localhost".to_owned(), 3000)] - } else { - vec![] + extra_embed_on: { + let mut extra_embed = dev_ui.clone(); + match self.ui_hosts() { + // In case host validation is disabled allow all frame ancestors + None => extra_embed.push(("*".to_owned(), ui_port)), + Some(hosts) => extra_embed.extend(hosts.into_iter().filter_map(|host| { + let mut it = host.split(":"); + let host = it.next(); + let port = it.next().and_then(|v| u16::from_str(v).ok()); + + match (host, port) { + (Some(host), Some(port)) => Some((host.into(), port)), + (Some(host), None) => Some((host.into(), ui_port)), + _ => None, + } + })), + } + extra_embed }, + extra_script_src: dev_ui, } } @@ -908,13 +935,10 @@ impl Configuration { } else { self.args.flag_db_path.as_ref().map_or(dir::CHAINS_PATH, |s| &s) }; - let cache_path = if is_using_base_path { - "$BASE/cache".into() - } else { - replace_home_and_local(&data_path, &local_path, &dir::CACHE_PATH) - }; + let cache_path = if is_using_base_path { "$BASE/cache" } else { dir::CACHE_PATH }; let db_path = replace_home_and_local(&data_path, &local_path, &base_db_path); + let cache_path = replace_home_and_local(&data_path, &local_path, cache_path); let keys_path = replace_home(&data_path, &self.args.flag_keys_path); let dapps_path = replace_home(&data_path, &self.args.flag_dapps_path); let secretstore_path = replace_home(&data_path, &self.args.flag_secretstore_path); @@ -1272,7 +1296,12 @@ mod tests { support_token_api: true }, UiConfiguration { enabled: true, - ntp_server: "none".into(), + ntp_servers: vec![ + "0.parity.pool.ntp.org:123".into(), + "1.parity.pool.ntp.org:123".into(), + "2.parity.pool.ntp.org:123".into(), + "3.parity.pool.ntp.org:123".into(), + ], interface: "127.0.0.1".into(), port: 8180, hosts: Some(vec![]), @@ -1510,10 +1539,16 @@ mod tests { let conf3 = parse(&["parity", "--ui-path", "signer", "--ui-interface", "test"]); // then + let ntp_servers = vec![ + "0.parity.pool.ntp.org:123".into(), + "1.parity.pool.ntp.org:123".into(), + "2.parity.pool.ntp.org:123".into(), + "3.parity.pool.ntp.org:123".into(), + ]; assert_eq!(conf0.directories().signer, "signer".to_owned()); assert_eq!(conf0.ui_config(), UiConfiguration { enabled: true, - ntp_server: "none".into(), + ntp_servers: ntp_servers.clone(), interface: "127.0.0.1".into(), port: 8180, hosts: Some(vec![]), @@ -1522,7 +1557,7 @@ mod tests { assert_eq!(conf1.directories().signer, "signer".to_owned()); assert_eq!(conf1.ui_config(), UiConfiguration { enabled: true, - ntp_server: "none".into(), + ntp_servers: ntp_servers.clone(), interface: "127.0.0.1".into(), port: 8180, hosts: Some(vec![]), @@ -1532,7 +1567,7 @@ mod tests { assert_eq!(conf2.directories().signer, "signer".to_owned()); assert_eq!(conf2.ui_config(), UiConfiguration { enabled: true, - ntp_server: "none".into(), + ntp_servers: ntp_servers.clone(), interface: "127.0.0.1".into(), port: 3123, hosts: Some(vec![]), @@ -1541,7 +1576,7 @@ mod tests { assert_eq!(conf3.directories().signer, "signer".to_owned()); assert_eq!(conf3.ui_config(), UiConfiguration { enabled: true, - ntp_server: "none".into(), + ntp_servers: ntp_servers.clone(), interface: "test".into(), port: 8180, hosts: Some(vec![]), @@ -1655,4 +1690,15 @@ mod tests { assert_eq!(&conf0.ipfs_config().interface, "0.0.0.0"); assert_eq!(conf0.ipfs_config().hosts, None); } + + #[test] + fn should_use_correct_cache_path_if_base_is_set() { + let std = parse(&["parity"]); + let base = parse(&["parity", "--base-path", "/test"]); + + let base_path = ::dir::default_data_path(); + let local_path = ::dir::default_local_path(); + assert_eq!(std.directories().cache, ::helpers::replace_home_and_local(&base_path, &local_path, ::dir::CACHE_PATH)); + assert_eq!(base.directories().cache, "/test/cache"); + } } diff --git a/parity/dapps.rs b/parity/dapps.rs index 8d996a68b..98959c2fd 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -36,10 +36,11 @@ use util::{Bytes, Address}; #[derive(Debug, PartialEq, Clone)] pub struct Configuration { pub enabled: bool, - pub ntp_server: String, + pub ntp_servers: Vec, pub dapps_path: PathBuf, pub extra_dapps: Vec, pub extra_embed_on: Vec<(String, u16)>, + pub extra_script_src: Vec<(String, u16)>, } impl Default for Configuration { @@ -47,10 +48,16 @@ impl Default for Configuration { let data_dir = default_data_path(); Configuration { enabled: true, - ntp_server: "none".into(), + ntp_servers: vec![ + "0.parity.pool.ntp.org:123".into(), + "1.parity.pool.ntp.org:123".into(), + "2.parity.pool.ntp.org:123".into(), + "3.parity.pool.ntp.org:123".into(), + ], dapps_path: replace_home(&data_dir, "$BASE/dapps").into(), extra_dapps: vec![], extra_embed_on: vec![], + extra_script_src: vec![], } } } @@ -158,22 +165,23 @@ pub fn new(configuration: Configuration, deps: Dependencies) -> Result Result, String> { +pub fn new_ui(enabled: bool, ntp_servers: &[String], deps: Dependencies) -> Result, String> { if !enabled { return Ok(None); } server::ui_middleware( deps, - ntp_server, + ntp_servers, rpc::DAPPS_DOMAIN, ).map(Some) } @@ -201,18 +209,19 @@ mod server { pub fn dapps_middleware( _deps: Dependencies, - _ntp_server: &str, + _ntp_servers: &[String], _dapps_path: PathBuf, _extra_dapps: Vec, _dapps_domain: &str, _extra_embed_on: Vec<(String, u16)>, + _extra_script_src: Vec<(String, u16)>, ) -> Result { Err("Your Parity version has been compiled without WebApps support.".into()) } pub fn ui_middleware( _deps: Dependencies, - _ntp_server: &str, + _ntp_servers: &[String], _dapps_domain: &str, ) -> Result { Err("Your Parity version has been compiled without UI support.".into()) @@ -238,22 +247,24 @@ mod server { pub fn dapps_middleware( deps: Dependencies, - ntp_server: &str, + ntp_servers: &[String], dapps_path: PathBuf, extra_dapps: Vec, dapps_domain: &str, extra_embed_on: Vec<(String, u16)>, + extra_script_src: Vec<(String, u16)>, ) -> Result { let signer = deps.signer; let parity_remote = parity_reactor::Remote::new(deps.remote.clone()); let web_proxy_tokens = Arc::new(move |token| signer.web_proxy_access_token_domain(&token)); Ok(parity_dapps::Middleware::dapps( - ntp_server, + ntp_servers, deps.pool, parity_remote, deps.ui_address, extra_embed_on, + extra_script_src, dapps_path, extra_dapps, dapps_domain, @@ -266,12 +277,12 @@ mod server { pub fn ui_middleware( deps: Dependencies, - ntp_server: &str, + ntp_servers: &[String], dapps_domain: &str, ) -> Result { let parity_remote = parity_reactor::Remote::new(deps.remote.clone()); Ok(parity_dapps::Middleware::ui( - ntp_server, + ntp_servers, deps.pool, parity_remote, dapps_domain, diff --git a/parity/rpc.rs b/parity/rpc.rs index d919a8496..c853d5bac 100644 --- a/parity/rpc.rs +++ b/parity/rpc.rs @@ -74,7 +74,7 @@ impl Default for HttpConfiguration { #[derive(Debug, PartialEq, Clone)] pub struct UiConfiguration { pub enabled: bool, - pub ntp_server: String, + pub ntp_servers: Vec, pub interface: String, pub port: u16, pub hosts: Option>, @@ -95,7 +95,7 @@ impl From for HttpConfiguration { enabled: conf.enabled, interface: conf.interface, port: conf.port, - apis: rpc_apis::ApiSet::SafeContext, + apis: rpc_apis::ApiSet::UnsafeContext, cors: None, hosts: conf.hosts, server_threads: None, @@ -108,7 +108,12 @@ impl Default for UiConfiguration { fn default() -> Self { UiConfiguration { enabled: true && cfg!(feature = "ui-enabled"), - ntp_server: "none".into(), + ntp_servers: vec![ + "0.parity.pool.ntp.org:123".into(), + "1.parity.pool.ntp.org:123".into(), + "2.parity.pool.ntp.org:123".into(), + "3.parity.pool.ntp.org:123".into(), + ], port: 8180, interface: "127.0.0.1".into(), hosts: Some(vec![]), diff --git a/parity/run.rs b/parity/run.rs index c28f8e1ba..00db46b37 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -298,7 +298,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc) -> }; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; - let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_server, dapps_deps)?; + let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_servers, dapps_deps)?; // start RPCs let dapps_service = dapps::service(&dapps_middleware); @@ -660,7 +660,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R } }; let dapps_middleware = dapps::new(cmd.dapps_conf.clone(), dapps_deps.clone())?; - let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_server, dapps_deps)?; + let ui_middleware = dapps::new_ui(cmd.ui_conf.enabled, &cmd.ui_conf.ntp_servers, dapps_deps)?; let dapps_service = dapps::service(&dapps_middleware); let deps_for_rpc_apis = Arc::new(rpc_apis::FullDependencies { diff --git a/rpc/src/v1/helpers/dispatch.rs b/rpc/src/v1/helpers/dispatch.rs index ddd238fd8..c72f1a890 100644 --- a/rpc/src/v1/helpers/dispatch.rs +++ b/rpc/src/v1/helpers/dispatch.rs @@ -512,6 +512,10 @@ pub fn execute( ).boxed() }, ConfirmationPayload::EthSignMessage(address, data) => { + if accounts.is_hardware_address(address) { + return future::err(errors::unsupported("Signing via hardware wallets is not supported.", None)).boxed(); + } + let hash = eth_data_hash(data); let res = signature(&accounts, address, hash, pass) .map(|result| result @@ -522,6 +526,10 @@ pub fn execute( future::done(res).boxed() }, ConfirmationPayload::Decrypt(address, data) => { + if accounts.is_hardware_address(address) { + return future::err(errors::unsupported("Decrypting via hardware wallets is not supported.", None)).boxed(); + } + let res = decrypt(&accounts, address, data, pass) .map(|result| result .map(RpcBytes) diff --git a/rpc/src/v1/helpers/errors.rs b/rpc/src/v1/helpers/errors.rs index 9be54991f..4c4af6f97 100644 --- a/rpc/src/v1/helpers/errors.rs +++ b/rpc/src/v1/helpers/errors.rs @@ -71,6 +71,14 @@ pub fn public_unsupported(details: Option) -> Error { } } +pub fn unsupported>(msg: T, details: Option) -> Error { + Error { + code: ErrorCode::ServerError(codes::UNSUPPORTED_REQUEST), + message: msg.into(), + data: details.map(Into::into).map(Value::String), + } +} + pub fn request_not_found() -> Error { Error { code: ErrorCode::ServerError(codes::REQUEST_NOT_FOUND), diff --git a/util/Cargo.toml b/util/Cargo.toml index 8a0928ff5..6a270e118 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -3,7 +3,7 @@ description = "Ethcore utility library" homepage = "http://parity.io" license = "GPL-3.0" name = "ethcore-util" -version = "1.7.0" +version = "1.7.1" authors = ["Parity Technologies "] build = "build.rs" diff --git a/util/rlp/src/error.rs b/util/rlp/src/error.rs index 6b15ea8a6..5113fdc17 100644 --- a/util/rlp/src/error.rs +++ b/util/rlp/src/error.rs @@ -30,6 +30,8 @@ pub enum DecoderError { RlpInvalidIndirection, /// Declared length is inconsistent with data specified after. RlpInconsistentLengthAndData, + /// Declared length is invalid and results in overflow + RlpInvalidLength, /// Custom rlp decoding error. Custom(&'static str), } diff --git a/util/rlp/src/untrusted_rlp.rs b/util/rlp/src/untrusted_rlp.rs index c027438b0..10c80b7d8 100644 --- a/util/rlp/src/untrusted_rlp.rs +++ b/util/rlp/src/untrusted_rlp.rs @@ -371,7 +371,8 @@ impl<'a> BasicDecoder<'a> { } let len = decode_usize(&bytes[1..begin_of_value])?; - let last_index_of_value = begin_of_value + len; + let last_index_of_value = begin_of_value.checked_add(len) + .ok_or(DecoderError::RlpInvalidLength)?; if bytes.len() < last_index_of_value { return Err(DecoderError::RlpInconsistentLengthAndData); } @@ -385,7 +386,7 @@ impl<'a> BasicDecoder<'a> { #[cfg(test)] mod tests { - use UntrustedRlp; + use {UntrustedRlp, DecoderError}; #[test] fn test_rlp_display() { @@ -394,4 +395,12 @@ mod tests { let rlp = UntrustedRlp::new(&data); assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); } + + #[test] + fn length_overflow() { + let bs = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; + let rlp = UntrustedRlp::new(&bs); + let res: Result = rlp.as_val(); + assert_eq!(Err(DecoderError::RlpInvalidLength), res); + } }