RPC middleware: Informant & Client.keep_alive (#4384)

* Adding RPC informant structs

* RPC informant

* Middleware counting RPC requests

* Moving client keep_alive to middleware
This commit is contained in:
Tomasz Drwięga 2017-02-04 22:18:19 +01:00 committed by Gav Wood
parent d7b937fe88
commit 248cd5e036
31 changed files with 520 additions and 407 deletions

44
Cargo.lock generated
View File

@ -28,7 +28,7 @@ dependencies = [
"fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.9.14 (registry+https://github.com/rust-lang/crates.io-index)",
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
@ -423,7 +423,7 @@ dependencies = [
"fetch 0.1.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-http-server 7.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"linked-hash-map 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -594,11 +594,12 @@ dependencies = [
"ethsync 1.6.0",
"fetch 0.1.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-http-server 7.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-ipc-server 1.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-macros 0.2.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-reactor 0.1.0",
"parity-updater 1.6.0",
"rlp 0.1.0",
@ -621,7 +622,7 @@ dependencies = [
"ethcore-io 1.6.0",
"ethcore-rpc 1.6.0",
"ethcore-util 1.6.0",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
"parity-ui 1.6.0",
@ -641,7 +642,7 @@ dependencies = [
"ethcore-ipc-nano 1.6.0",
"ethcore-util 1.6.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-macros 0.2.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-tcp-server 1.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1001,8 +1002,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "jsonrpc-core"
version = "5.0.0"
source = "git+https://github.com/ethcore/jsonrpc.git#5eeee0980e4d2682a831c633fa03a8af99e0d68c"
version = "5.1.0"
source = "git+https://github.com/ethcore/jsonrpc.git#d179ce34d8da8ea1cd67e93a5b4cb1e30f48c156"
dependencies = [
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1015,11 +1016,10 @@ dependencies = [
[[package]]
name = "jsonrpc-http-server"
version = "7.0.0"
source = "git+https://github.com/ethcore/jsonrpc.git#5eeee0980e4d2682a831c633fa03a8af99e0d68c"
source = "git+https://github.com/ethcore/jsonrpc.git#d179ce34d8da8ea1cd67e93a5b4cb1e30f48c156"
dependencies = [
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"hyper 0.10.0-a.0 (git+https://github.com/ethcore/hyper)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"tokio-core 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1028,11 +1028,11 @@ dependencies = [
[[package]]
name = "jsonrpc-ipc-server"
version = "1.0.0"
source = "git+https://github.com/ethcore/jsonrpc.git#5eeee0980e4d2682a831c633fa03a8af99e0d68c"
source = "git+https://github.com/ethcore/jsonrpc.git#d179ce34d8da8ea1cd67e93a5b4cb1e30f48c156"
dependencies = [
"bytes 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1044,21 +1044,19 @@ dependencies = [
[[package]]
name = "jsonrpc-macros"
version = "0.2.0"
source = "git+https://github.com/ethcore/jsonrpc.git#5eeee0980e4d2682a831c633fa03a8af99e0d68c"
source = "git+https://github.com/ethcore/jsonrpc.git#d179ce34d8da8ea1cd67e93a5b4cb1e30f48c156"
dependencies = [
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"serde 0.8.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "jsonrpc-tcp-server"
version = "1.0.0"
source = "git+https://github.com/ethcore/jsonrpc.git#5eeee0980e4d2682a831c633fa03a8af99e0d68c"
source = "git+https://github.com/ethcore/jsonrpc.git#d179ce34d8da8ea1cd67e93a5b4cb1e30f48c156"
dependencies = [
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
@ -1477,6 +1475,11 @@ dependencies = [
"user32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "order-stat"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "owning_ref"
version = "0.2.2"
@ -1528,7 +1531,7 @@ dependencies = [
"ethcore-signer 1.6.0",
"ethcore-util 1.6.0",
"futures 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
"jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)",
"jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)",
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"matches 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
@ -2521,7 +2524,7 @@ dependencies = [
"checksum itertools 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "086e1fa5fe48840b1cfdef3a20c7e3115599f8d5c4c87ef32a794a7cdd184d76"
"checksum itoa 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ae3088ea4baeceb0284ee9eea42f591226e6beaecf65373e41b38d95a1b8e7a1"
"checksum itoa 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91fd9dc2c587067de817fec4ad355e3818c3d893a78cab32a0a474c7a15bb8d5"
"checksum jsonrpc-core 5.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-core 5.1.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-http-server 7.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-ipc-server 1.0.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
"checksum jsonrpc-macros 0.2.0 (git+https://github.com/ethcore/jsonrpc.git)" = "<none>"
@ -2570,6 +2573,7 @@ dependencies = [
"checksum ole32-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5d2c49021782e5233cd243168edfa8037574afed4eba4bbaf538b3d8d1789d8c"
"checksum openssl 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "12be61c7eaa23228316ff02c39807e4c1b1af84ba81420f19fd58dade304b25c"
"checksum openssl-sys 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d2845e841700e7b04282ceaa115407ea84e0db918ae689ad9ceb6f06fa6046bd"
"checksum order-stat 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "efa535d5117d3661134dbf1719b6f0ffe06f2375843b13935db186cd094105eb"
"checksum owning_ref 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "8d91377085359426407a287ab16884a0111ba473aa6844ff01d4ec20ce3d75e7"
"checksum parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98378dec0a185da2b7180308752f0bad73aaa949c3e0a3b0528d0e067945f7ab"
"checksum parity-ui-precompiled 1.4.0 (git+https://github.com/ethcore/js-precompiled.git)" = "<none>"

View File

@ -70,9 +70,10 @@ use std::sync::{Arc, Mutex};
use std::net::SocketAddr;
use std::collections::HashMap;
use ethcore_rpc::Metadata;
use ethcore_rpc::{Metadata};
use fetch::{Fetch, Client as FetchClient};
use hash_fetch::urlhint::ContractClient;
use jsonrpc_core::Middleware;
use jsonrpc_core::reactor::RpcHandler;
use router::auth::{Authorization, NoAuth, HttpBasicAuth};
use parity_reactor::Remote;
@ -179,7 +180,7 @@ impl<T: Fetch> ServerBuilder<T> {
/// Asynchronously start server with no authentication,
/// returns result with `Server` handle on success or an error.
pub fn start_unsecured_http(self, addr: &SocketAddr, handler: RpcHandler<Metadata>) -> Result<Server, ServerError> {
pub fn start_unsecured_http<S: Middleware<Metadata>>(self, addr: &SocketAddr, handler: RpcHandler<Metadata, S>) -> Result<Server, ServerError> {
let fetch = self.fetch_client()?;
Server::start_http(
addr,
@ -199,7 +200,7 @@ impl<T: Fetch> ServerBuilder<T> {
/// Asynchronously start server with `HTTP Basic Authentication`,
/// return result with `Server` handle on success or an error.
pub fn start_basic_auth_http(self, addr: &SocketAddr, username: &str, password: &str, handler: RpcHandler<Metadata>) -> Result<Server, ServerError> {
pub fn start_basic_auth_http<S: Middleware<Metadata>>(self, addr: &SocketAddr, username: &str, password: &str, handler: RpcHandler<Metadata, S>) -> Result<Server, ServerError> {
let fetch = self.fetch_client()?;
Server::start_http(
addr,
@ -258,11 +259,11 @@ impl Server {
}
}
fn start_http<A: Authorization + 'static, F: Fetch>(
fn start_http<A: Authorization + 'static, F: Fetch, T: Middleware<Metadata>>(
addr: &SocketAddr,
hosts: Option<Vec<String>>,
authorization: A,
handler: RpcHandler<Metadata>,
handler: RpcHandler<Metadata, T>,
dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>,
signer_address: Option<(String, u16)>,

View File

@ -18,11 +18,15 @@ use std::sync::{Arc, Mutex};
use hyper;
use ethcore_rpc::{Metadata, Origin};
use jsonrpc_core::Middleware;
use jsonrpc_core::reactor::RpcHandler;
use jsonrpc_http_server::{Rpc, ServerHandler, PanicHandler, AccessControlAllowOrigin, HttpMetaExtractor};
use endpoint::{Endpoint, EndpointPath, Handler};
pub fn rpc(handler: RpcHandler<Metadata>, panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>) -> Box<Endpoint> {
pub fn rpc<T: Middleware<Metadata>>(
handler: RpcHandler<Metadata, T>,
panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>,
) -> Box<Endpoint> {
Box::new(RpcEndpoint {
handler: handler,
meta_extractor: Arc::new(MetadataExtractor),
@ -33,15 +37,15 @@ pub fn rpc(handler: RpcHandler<Metadata>, panic_handler: Arc<Mutex<Option<Box<Fn
})
}
struct RpcEndpoint {
handler: RpcHandler<Metadata>,
struct RpcEndpoint<T: Middleware<Metadata>> {
handler: RpcHandler<Metadata, T>,
meta_extractor: Arc<HttpMetaExtractor<Metadata>>,
panic_handler: Arc<Mutex<Option<Box<Fn() -> () + Send>>>>,
cors_domain: Option<Vec<AccessControlAllowOrigin>>,
allowed_hosts: Option<Vec<String>>,
}
impl Endpoint for RpcEndpoint {
impl<T: Middleware<Metadata>> Endpoint for RpcEndpoint<T> {
fn to_async_handler(&self, _path: EndpointPath, control: hyper::Control) -> Box<Handler> {
let panic_handler = PanicHandler { handler: self.panic_handler.clone() };
Box::new(ServerHandler::new(

View File

@ -23,7 +23,7 @@ use tests::helpers::{serve_with_rpc, request};
#[test]
fn should_serve_rpc() {
// given
let mut io = MetaIoHandler::new();
let mut io = MetaIoHandler::default();
io.add_method("rpc_test", |_| {
Ok(Value::String("Hello World!".into()))
});
@ -53,7 +53,7 @@ fn should_serve_rpc() {
#[test]
fn should_extract_metadata() {
// given
let mut io = MetaIoHandler::new();
let mut io = MetaIoHandler::default();
io.add_method_with_meta("rpc_test", |_params, meta: Metadata| {
assert_eq!(meta.dapp_id, Some("https://parity.io/".to_owned()));
assert_eq!(meta.origin, Origin::Dapps);
@ -87,7 +87,7 @@ fn should_extract_metadata() {
#[test]
fn should_extract_metadata_from_custom_header() {
// given
let mut io = MetaIoHandler::new();
let mut io = MetaIoHandler::default();
io.add_method_with_meta("rpc_test", |_params, meta: Metadata| {
assert_eq!(meta.dapp_id, Some("https://parity.io/".to_owned()));
assert_eq!(meta.origin, Origin::Dapps);

View File

@ -262,6 +262,18 @@ impl Client {
Ok(client)
}
/// Wakes up client if it's a sleep.
pub fn keep_alive(&self) {
let should_wake = match *self.mode.lock() {
Mode::Dark(..) | Mode::Passive(..) => true,
_ => false,
};
if should_wake {
self.wake_up();
(*self.sleep_state.lock()).last_activity = Some(Instant::now());
}
}
/// Adds an actor to be notified on certain events
pub fn add_notify(&self, target: Arc<ChainNotify>) {
self.notify.write().push(Arc::downgrade(&target));
@ -1011,17 +1023,6 @@ impl BlockChainClient for Client {
Ok(ret)
}
fn keep_alive(&self) {
let should_wake = match *self.mode.lock() {
Mode::Dark(..) | Mode::Passive(..) => true,
_ => false,
};
if should_wake {
self.wake_up();
(*self.sleep_state.lock()).last_activity = Some(Instant::now());
}
}
fn mode(&self) -> IpcMode {
let r = self.mode.lock().clone().into();
trace!(target: "mode", "Asked for mode = {:?}. returning {:?}", &*self.mode.lock(), r);

View File

@ -46,10 +46,6 @@ use encoded;
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
/// Should be called by any external-facing interface when actively using the client.
/// To minimise chatter, there's no need to call more than once every 30s.
fn keep_alive(&self) {}
/// Get raw block header data by block id.
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;

View File

@ -242,7 +242,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
}
};
let informant = Arc::new(Informant::new(client.clone(), None, None, None, cmd.with_color));
let informant = Arc::new(Informant::new(client.clone(), None, None, None, None, cmd.with_color));
service.register_io_handler(informant).map_err(|_| "Unable to register informant handler".to_owned())?;
let do_import = |bytes| {

View File

@ -19,6 +19,7 @@ use std::sync::Arc;
use dir::default_data_path;
use ethcore::client::Client;
use ethcore_rpc::informant::RpcStats;
use ethsync::SyncProvider;
use hash_fetch::fetch::Client as FetchClient;
use helpers::replace_home;
@ -64,6 +65,7 @@ pub struct Dependencies {
pub remote: Remote,
pub fetch: FetchClient,
pub signer: Arc<SignerService>,
pub stats: Arc<RpcStats>,
}
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<WebappServer>, String> {
@ -174,7 +176,7 @@ mod server {
} else {
rpc_apis::ApiSet::UnsafeContext
};
let apis = rpc_apis::setup_rpc(Default::default(), deps.apis.clone(), api_set);
let apis = rpc_apis::setup_rpc(deps.stats, deps.apis.clone(), api_set);
let handler = RpcHandler::new(Arc::new(apis), deps.remote);
let start_result = match auth {
None => {

View File

@ -30,7 +30,8 @@ use ethcore::service::ClientIoMessage;
use ethcore::snapshot::service::Service as SnapshotService;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};
use number_prefix::{binary_prefix, Standalone, Prefixed};
use ethcore_rpc::is_major_importing;
use ethcore_rpc::{is_major_importing};
use ethcore_rpc::informant::RpcStats;
use rlp::View;
pub struct Informant {
@ -41,6 +42,7 @@ pub struct Informant {
snapshot: Option<Arc<SnapshotService>>,
sync: Option<Arc<SyncProvider>>,
net: Option<Arc<ManageNetwork>>,
rpc_stats: Option<Arc<RpcStats>>,
last_import: Mutex<Instant>,
skipped: AtomicUsize,
skipped_txs: AtomicUsize,
@ -63,13 +65,20 @@ pub trait MillisecondDuration {
impl MillisecondDuration for Duration {
fn as_milliseconds(&self) -> u64 {
self.as_secs() * 1000 + self.subsec_nanos() as u64 / 1000000
self.as_secs() * 1000 + self.subsec_nanos() as u64 / 1_000_000
}
}
impl Informant {
/// Make a new instance potentially `with_color` output.
pub fn new(client: Arc<Client>, sync: Option<Arc<SyncProvider>>, net: Option<Arc<ManageNetwork>>, snapshot: Option<Arc<SnapshotService>>, with_color: bool) -> Self {
pub fn new(
client: Arc<Client>,
sync: Option<Arc<SyncProvider>>,
net: Option<Arc<ManageNetwork>>,
snapshot: Option<Arc<SnapshotService>>,
rpc_stats: Option<Arc<RpcStats>>,
with_color: bool,
) -> Self {
Informant {
report: RwLock::new(None),
last_tick: RwLock::new(Instant::now()),
@ -78,6 +87,7 @@ impl Informant {
snapshot: snapshot,
sync: sync,
net: net,
rpc_stats: rpc_stats,
last_import: Mutex::new(Instant::now()),
skipped: AtomicUsize::new(0),
skipped_txs: AtomicUsize::new(0),
@ -102,6 +112,7 @@ impl Informant {
let cache_info = self.client.blockchain_cache_info();
let network_config = self.net.as_ref().map(|n| n.network_config());
let sync_status = self.sync.as_ref().map(|s| s.status());
let rpc_stats = self.rpc_stats.as_ref();
let importing = is_major_importing(sync_status.map(|s| s.state), self.client.queue_info());
let (snapshot_sync, snapshot_current, snapshot_total) = self.snapshot.as_ref().map_or((false, 0, 0), |s|
@ -126,7 +137,7 @@ impl Informant {
false => t,
};
info!(target: "import", "{} {} {}",
info!(target: "import", "{} {} {} {}",
match importing {
true => match snapshot_sync {
false => format!("Syncing {} {} {} {}+{} Qed",
@ -170,7 +181,16 @@ impl Informant {
Some(ref sync_info) => format!(" {} sync", paint(Blue.bold(), format!("{:>8}", format_bytes(sync_info.mem_used)))),
_ => String::new(),
}
)
),
match rpc_stats {
Some(ref rpc_stats) => format!(
"RPC: {} conn, {} req/s, {} µs",
paint(Blue.bold(), format!("{:2}", rpc_stats.sessions())),
paint(Blue.bold(), format!("{:2}", rpc_stats.requests_rate())),
paint(Blue.bold(), format!("{:3}", rpc_stats.approximated_roundtrip())),
),
_ => String::new(),
},
);
*write_report = Some(report);

View File

@ -22,6 +22,7 @@ use io::PanicHandler;
use dir::default_data_path;
use ethcore_rpc::{self as rpc, RpcServerError, IpcServerError, Metadata};
use ethcore_rpc::informant::{RpcStats, Middleware};
use helpers::parity_ipc_path;
use jsonrpc_core::MetaIoHandler;
use jsonrpc_core::reactor::{RpcHandler, Remote};
@ -85,6 +86,7 @@ pub struct Dependencies {
pub panic_handler: Arc<PanicHandler>,
pub apis: Arc<rpc_apis::Dependencies>,
pub remote: Remote,
pub stats: Arc<RpcStats>,
}
pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Result<Option<HttpServer>, String> {
@ -97,8 +99,8 @@ pub fn new_http(conf: HttpConfiguration, deps: &Dependencies) -> Result<Option<H
Ok(Some(setup_http_rpc_server(deps, &addr, conf.cors, conf.hosts, conf.apis)?))
}
fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler<Metadata> {
rpc_apis::setup_rpc(MetaIoHandler::default(), deps.apis.clone(), apis)
fn setup_apis(apis: ApiSet, deps: &Dependencies) -> MetaIoHandler<Metadata, Middleware> {
rpc_apis::setup_rpc(deps.stats.clone(), deps.apis.clone(), apis)
}
pub fn setup_http_rpc_server(
@ -122,12 +124,12 @@ pub fn setup_http_rpc_server(
}
}
pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Result<Option<IpcServer<Metadata>>, String> {
pub fn new_ipc(conf: IpcConfiguration, deps: &Dependencies) -> Result<Option<IpcServer<Metadata, Middleware>>, String> {
if !conf.enabled { return Ok(None); }
Ok(Some(setup_ipc_rpc_server(deps, &conf.socket_addr, conf.apis)?))
}
pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: ApiSet) -> Result<IpcServer<Metadata>, String> {
pub fn setup_ipc_rpc_server(dependencies: &Dependencies, addr: &str, apis: ApiSet) -> Result<IpcServer<Metadata, Middleware>, String> {
let apis = setup_apis(apis, dependencies);
let handler = RpcHandler::new(Arc::new(apis), dependencies.remote.clone());
match rpc::start_ipc(addr, handler) {

View File

@ -14,22 +14,25 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::cmp::PartialEq;
use std::collections::BTreeMap;
use std::collections::HashSet;
use std::cmp::PartialEq;
use std::str::FromStr;
use std::sync::Arc;
use util::RotatingLogger;
use jsonrpc_core::{MetaIoHandler};
use ethcore::miner::{Miner, ExternalMiner};
use ethcore::client::Client;
use ethcore::account_provider::AccountProvider;
use ethcore::snapshot::SnapshotService;
use ethsync::{ManageNetwork, SyncProvider};
use ethcore_rpc::{Metadata, NetworkSettings};
pub use ethcore_rpc::SignerService;
use updater::Updater;
use ethcore::account_provider::AccountProvider;
use ethcore::client::Client;
use ethcore::miner::{Miner, ExternalMiner};
use ethcore::snapshot::SnapshotService;
use ethcore_rpc::{Metadata, NetworkSettings};
use ethcore_rpc::informant::{Middleware, RpcStats, ClientNotifier};
use ethsync::{ManageNetwork, SyncProvider};
use hash_fetch::fetch::Client as FetchClient;
use jsonrpc_core::{MetaIoHandler};
use updater::Updater;
use util::RotatingLogger;
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
pub enum Api {
@ -182,9 +185,13 @@ macro_rules! add_signing_methods {
}
}
pub fn setup_rpc(mut handler: MetaIoHandler<Metadata>, deps: Arc<Dependencies>, apis: ApiSet) -> MetaIoHandler<Metadata> {
pub fn setup_rpc(stats: Arc<RpcStats>, deps: Arc<Dependencies>, apis: ApiSet) -> MetaIoHandler<Metadata, Middleware> {
use ethcore_rpc::v1::*;
let mut handler = MetaIoHandler::with_middleware(Middleware::new(stats, ClientNotifier {
client: deps.client.clone(),
}));
// it's turned into vector, cause ont of the cases requires &[]
let apis = apis.list_apis().into_iter().collect::<Vec<_>>();
for api in &apis {
@ -244,7 +251,7 @@ pub fn setup_rpc(mut handler: MetaIoHandler<Metadata>, deps: Arc<Dependencies>,
add_signing_methods!(ParitySigning, handler, deps);
},
Api::ParityAccounts => {
handler.extend_with(ParityAccountsClient::new(&deps.secret_store, &deps.client).to_delegate());
handler.extend_with(ParityAccountsClient::new(&deps.secret_store).to_delegate());
},
Api::ParitySet => {
handler.extend_with(ParitySetClient::new(

View File

@ -18,7 +18,7 @@ use std::sync::Arc;
use std::net::{TcpListener};
use ctrlc::CtrlC;
use fdlimit::raise_fd_limit;
use ethcore_rpc::{NetworkSettings, is_major_importing};
use ethcore_rpc::{NetworkSettings, informant, is_major_importing};
use ethsync::NetworkConfiguration;
use util::{Colour, version, RotatingLogger, Mutex, Condvar};
use io::{MayPanic, ForwardPanic, PanicHandler};
@ -358,6 +358,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
service.add_notify(updater.clone());
// set up dependencies for rpc servers
let rpc_stats = Arc::new(informant::RpcStats::default());
let signer_path = cmd.signer_conf.signer_path.clone();
let deps_for_rpc_apis = Arc::new(rpc_apis::Dependencies {
signer_service: Arc::new(rpc_apis::SignerService::new(move || {
@ -390,6 +391,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
panic_handler: panic_handler.clone(),
apis: deps_for_rpc_apis.clone(),
remote: event_loop.raw_remote(),
stats: rpc_stats.clone(),
};
// start rpc servers
@ -405,6 +407,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
remote: event_loop.raw_remote(),
fetch: fetch.clone(),
signer: deps_for_rpc_apis.signer_service.clone(),
stats: rpc_stats.clone(),
};
let dapps_server = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;
@ -413,6 +416,7 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
panic_handler: panic_handler.clone(),
apis: deps_for_rpc_apis.clone(),
remote: event_loop.raw_remote(),
rpc_stats: rpc_stats.clone(),
};
let signer_server = signer::start(cmd.signer_conf.clone(), signer_deps)?;
@ -422,7 +426,8 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
Some(sync_provider.clone()),
Some(manage_network.clone()),
Some(snapshot_service.clone()),
cmd.logger_config.color
Some(rpc_stats.clone()),
cmd.logger_config.color,
));
service.add_notify(informant.clone());
service.register_io_handler(informant.clone()).map_err(|_| "Unable to register informant handler".to_owned())?;

View File

@ -15,18 +15,21 @@
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::io;
use std::sync::Arc;
use std::path::PathBuf;
use ansi_term::Colour;
use io::{ForwardPanic, PanicHandler};
use util::path::restrict_permissions_owner;
use rpc_apis;
use ethcore_signer as signer;
use dir::default_data_path;
use helpers::replace_home;
use jsonrpc_core::reactor::{RpcHandler, Remote};
use std::sync::Arc;
pub use ethcore_signer::Server as SignerServer;
use ansi_term::Colour;
use dir::default_data_path;
use ethcore_rpc::informant::RpcStats;
use ethcore_signer as signer;
use helpers::replace_home;
use io::{ForwardPanic, PanicHandler};
use jsonrpc_core::reactor::{RpcHandler, Remote};
use rpc_apis;
use util::path::restrict_permissions_owner;
const CODES_FILENAME: &'static str = "authcodes";
#[derive(Debug, PartialEq, Clone)]
@ -55,6 +58,7 @@ pub struct Dependencies {
pub panic_handler: Arc<PanicHandler>,
pub apis: Arc<rpc_apis::Dependencies>,
pub remote: Remote,
pub rpc_stats: Arc<RpcStats>,
}
pub struct NewToken {
@ -126,7 +130,8 @@ fn do_start(conf: Configuration, deps: Dependencies) -> Result<SignerServer, Str
info!("If you do not intend this, exit now.");
}
let server = server.skip_origin_validation(conf.skip_origin_validation);
let apis = rpc_apis::setup_rpc(Default::default(), deps.apis, rpc_apis::ApiSet::SafeContext);
let server = server.stats(deps.rpc_stats.clone());
let apis = rpc_apis::setup_rpc(deps.rpc_stats, deps.apis, rpc_apis::ApiSet::SafeContext);
let handler = RpcHandler::new(Arc::new(apis), deps.remote);
server.start(addr, handler)
};

View File

@ -17,6 +17,7 @@ serde_json = "0.8"
rustc-serialize = "0.3"
time = "0.1"
transient-hashmap = "0.1"
order-stat = "0.1"
jsonrpc-core = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-http-server = { git = "https://github.com/ethcore/jsonrpc.git" }
jsonrpc-ipc-server = { git = "https://github.com/ethcore/jsonrpc.git" }

View File

@ -40,6 +40,7 @@ extern crate time;
extern crate rlp;
extern crate fetch;
extern crate futures;
extern crate order_stat;
extern crate parity_updater as updater;
extern crate parity_reactor;
@ -63,16 +64,16 @@ use jsonrpc_core::reactor::RpcHandler;
pub use ipc::{Server as IpcServer, Error as IpcServerError};
pub use jsonrpc_http_server::{ServerBuilder, Server, RpcServerError};
pub mod v1;
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, Metadata, Origin};
pub use v1::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, Metadata, Origin, informant};
pub use v1::block_import::is_major_importing;
/// Start http server asynchronously and returns result with `Server` handle on success or an error.
pub fn start_http<M: jsonrpc_core::Metadata>(
pub fn start_http<M: jsonrpc_core::Metadata, S: jsonrpc_core::Middleware<M>>(
addr: &SocketAddr,
cors_domains: Option<Vec<String>>,
allowed_hosts: Option<Vec<String>>,
panic_handler: Arc<PanicHandler>,
handler: RpcHandler<M>,
handler: RpcHandler<M, S>,
) -> Result<Server, RpcServerError> {
let cors_domains = cors_domains.map(|domains| {
@ -95,7 +96,10 @@ pub fn start_http<M: jsonrpc_core::Metadata>(
}
/// Start ipc server asynchronously and returns result with `Server` handle on success or an error.
pub fn start_ipc<M: jsonrpc_core::Metadata>(addr: &str, handler: RpcHandler<M>) -> Result<ipc::Server<M>, ipc::Error> {
pub fn start_ipc<M: jsonrpc_core::Metadata, S: jsonrpc_core::Middleware<M>>(
addr: &str,
handler: RpcHandler<M, S>,
) -> Result<ipc::Server<M, S>, ipc::Error> {
let server = ipc::Server::with_rpc_handler(addr, handler)?;
server.run_async()?;
Ok(server)

View File

@ -0,0 +1,301 @@
// Copyright 2015-2017 Parity Technologies (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 <http://www.gnu.org/licenses/>.
//! RPC Requests Statistics
use std::fmt;
use std::sync::Arc;
use std::sync::atomic::{self, AtomicUsize};
use std::time;
use futures::Future;
use jsonrpc_core as rpc;
use order_stat;
use util::RwLock;
const RATE_SECONDS: usize = 10;
const STATS_SAMPLES: usize = 60;
struct RateCalculator {
era: time::Instant,
samples: [u16; RATE_SECONDS],
}
impl fmt::Debug for RateCalculator {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "{} req/s", self.rate())
}
}
impl Default for RateCalculator {
fn default() -> Self {
RateCalculator {
era: time::Instant::now(),
samples: [0; RATE_SECONDS],
}
}
}
impl RateCalculator {
fn elapsed(&self) -> u64 {
self.era.elapsed().as_secs()
}
pub fn tick(&mut self) -> u16 {
if self.elapsed() >= RATE_SECONDS as u64 {
self.era = time::Instant::now();
self.samples[0] = 0;
}
let pos = self.elapsed() as usize % RATE_SECONDS;
let next = (pos + 1) % RATE_SECONDS;
self.samples[next] = 0;
self.samples[pos] = self.samples[pos].saturating_add(1);
self.samples[pos]
}
fn current_rate(&self) -> usize {
let now = match self.elapsed() {
i if i >= RATE_SECONDS as u64 => RATE_SECONDS,
i => i as usize + 1,
};
let sum: usize = self.samples[0..now].iter().map(|x| *x as usize).sum();
sum / now
}
pub fn rate(&self) -> usize {
if self.elapsed() > RATE_SECONDS as u64 {
0
} else {
self.current_rate()
}
}
}
struct StatsCalculator<T = u32> {
filled: bool,
idx: usize,
samples: [T; STATS_SAMPLES],
}
impl<T: Default + Copy> Default for StatsCalculator<T> {
fn default() -> Self {
StatsCalculator {
filled: false,
idx: 0,
samples: [T::default(); STATS_SAMPLES],
}
}
}
impl<T: fmt::Display + Default + Copy + Ord> fmt::Debug for StatsCalculator<T> {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
write!(fmt, "median: {} ms", self.approximated_median())
}
}
impl<T: Default + Copy + Ord> StatsCalculator<T> {
pub fn add(&mut self, sample: T) {
self.idx += 1;
if self.idx >= STATS_SAMPLES {
self.filled = true;
self.idx = 0;
}
self.samples[self.idx] = sample;
}
/// Returns aproximate of media
pub fn approximated_median(&self) -> T {
let mut copy = [T::default(); STATS_SAMPLES];
copy.copy_from_slice(&self.samples);
let bound = if self.filled { STATS_SAMPLES } else { self.idx + 1 };
let (_, &mut median) = order_stat::median_of_medians(&mut copy[0..bound]);
median
}
}
/// RPC Statistics
#[derive(Default, Debug)]
pub struct RpcStats {
requests: RwLock<RateCalculator>,
roundtrips: RwLock<StatsCalculator<u32>>,
active_sessions: AtomicUsize,
}
impl RpcStats {
/// Count session opened
pub fn open_session(&self) {
self.active_sessions.fetch_add(1, atomic::Ordering::SeqCst);
}
/// Count session closed.
/// Silently overflows if closing unopened session.
pub fn close_session(&self) {
self.active_sessions.fetch_sub(1, atomic::Ordering::SeqCst);
}
/// Count request. Returns number of requests in current second.
pub fn count_request(&self) -> u16 {
self.requests.write().tick()
}
/// Add roundtrip time (microseconds)
pub fn add_roundtrip(&self, microseconds: u32) {
self.roundtrips.write().add(microseconds)
}
/// Returns number of open sessions
pub fn sessions(&self) -> usize {
self.active_sessions.load(atomic::Ordering::Relaxed)
}
/// Returns requests rate
pub fn requests_rate(&self) -> usize {
self.requests.read().rate()
}
/// Returns approximated roundtrip in microseconds
pub fn approximated_roundtrip(&self) -> u32 {
self.roundtrips.read().approximated_median()
}
}
/// Notifies about RPC activity.
pub trait ActivityNotifier: Send + Sync + 'static {
/// Activity on RPC interface
fn active(&self);
}
/// Stats-counting RPC middleware
pub struct Middleware<T: ActivityNotifier = ClientNotifier> {
stats: Arc<RpcStats>,
notifier: T,
}
impl<T: ActivityNotifier> Middleware<T> {
/// Create new Middleware with stats counter and activity notifier.
pub fn new(stats: Arc<RpcStats>, notifier: T) -> Self {
Middleware {
stats: stats,
notifier: notifier,
}
}
fn as_micro(dur: time::Duration) -> u32 {
(dur.as_secs() * 1_000_000) as u32 + dur.subsec_nanos() / 1_000
}
}
impl<M: rpc::Metadata, T: ActivityNotifier> rpc::Middleware<M> for Middleware<T> {
fn on_request<F>(&self, request: rpc::Request, meta: M, process: F) -> rpc::FutureResponse where
F: FnOnce(rpc::Request, M) -> rpc::FutureResponse,
{
let start = time::Instant::now();
let response = process(request, meta);
self.notifier.active();
let stats = self.stats.clone();
stats.count_request();
response.map(move |res| {
stats.add_roundtrip(Self::as_micro(start.elapsed()));
res
}).boxed()
}
}
/// Client Notifier
pub struct ClientNotifier {
/// Client
pub client: Arc<::ethcore::client::Client>,
}
impl ActivityNotifier for ClientNotifier {
fn active(&self) {
self.client.keep_alive()
}
}
#[cfg(test)]
mod tests {
use super::{RateCalculator, StatsCalculator, RpcStats};
#[test]
fn should_calculate_rate() {
// given
let mut avg = RateCalculator::default();
// when
avg.tick();
avg.tick();
avg.tick();
let rate = avg.rate();
// then
assert_eq!(rate, 3usize);
}
#[test]
fn should_approximate_median() {
// given
let mut stats = StatsCalculator::default();
stats.add(5);
stats.add(100);
stats.add(3);
stats.add(15);
stats.add(20);
stats.add(6);
// when
let median = stats.approximated_median();
// then
assert_eq!(median, 5);
}
#[test]
fn should_count_rpc_stats() {
// given
let stats = RpcStats::default();
assert_eq!(stats.sessions(), 0);
assert_eq!(stats.requests_rate(), 0);
assert_eq!(stats.approximated_roundtrip(), 0);
// when
stats.open_session();
stats.close_session();
stats.open_session();
stats.count_request();
stats.count_request();
stats.add_roundtrip(125);
// then
assert_eq!(stats.sessions(), 1);
assert_eq!(stats.requests_rate(), 2);
assert_eq!(stats.approximated_roundtrip(), 125);
}
#[test]
fn should_be_sync_and_send() {
let stats = RpcStats::default();
is_sync(stats);
}
fn is_sync<F: Send + Sync>(x: F) {
drop(x)
}
}

View File

@ -17,16 +17,18 @@
#[macro_use]
pub mod errors;
pub mod dispatch;
pub mod block_import;
pub mod dispatch;
pub mod informant;
mod network_settings;
mod poll_manager;
mod poll_filter;
mod requests;
mod signer;
mod signing_queue;
mod network_settings;
pub use self::network_settings::NetworkSettings;
pub use self::poll_manager::PollManager;
pub use self::poll_filter::{PollFilter, limit_logs};
pub use self::requests::{
@ -36,4 +38,3 @@ pub use self::signing_queue::{
ConfirmationsQueue, ConfirmationPromise, ConfirmationResult, SigningQueue, QueueEvent, DefaultAccount,
};
pub use self::signer::SignerService;
pub use self::network_settings::NetworkSettings;

View File

@ -258,20 +258,6 @@ fn check_known<C>(client: &C, number: BlockNumber) -> Result<(), Error> where C:
const MAX_QUEUE_SIZE_TO_MINE_ON: usize = 4; // because uncles go back 6.
impl<C, SN: ?Sized, S: ?Sized, M, EM> EthClient<C, SN, S, M, EM> where
C: MiningBlockChainClient + 'static,
SN: SnapshotService + 'static,
S: SyncProvider + 'static,
M: MinerService + 'static,
EM: ExternalMinerService + 'static {
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
#[cfg(windows)]
static SOLC: &'static str = "solc.exe";
@ -288,8 +274,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
type Metadata = Metadata;
fn protocol_version(&self) -> Result<String, Error> {
self.active()?;
let version = take_weak!(self.sync).status().protocol_version.to_owned();
Ok(format!("{}", version))
}
@ -297,7 +281,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
fn syncing(&self) -> Result<SyncStatus, Error> {
use ethcore::snapshot::RestorationStatus;
self.active()?;
let status = take_weak!(self.sync).status();
let client = take_weak!(self.client);
let snapshot_status = take_weak!(self.snapshot).status();
@ -331,8 +314,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
let dapp = meta.dapp_id.unwrap_or_default();
let author = move || {
self.active()?;
let mut miner = take_weak!(self.miner).author();
if miner == 0.into() {
let accounts = self.dapp_accounts(dapp.into())?;
@ -348,20 +329,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn is_mining(&self) -> Result<bool, Error> {
self.active()?;
Ok(take_weak!(self.miner).is_sealing())
}
fn hashrate(&self) -> Result<RpcU256, Error> {
self.active()?;
Ok(RpcU256::from(self.external_miner.hashrate()))
}
fn gas_price(&self) -> Result<RpcU256, Error> {
self.active()?;
let (client, miner) = (take_weak!(self.client), take_weak!(self.miner));
Ok(RpcU256::from(default_gas_price(&*client, &*miner)))
}
@ -370,8 +345,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
let dapp = meta.dapp_id.unwrap_or_default();
let accounts = move || {
self.active()?;
let accounts = self.dapp_accounts(dapp.into())?;
Ok(accounts.into_iter().map(Into::into).collect())
};
@ -380,14 +353,10 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_number(&self) -> Result<RpcU256, Error> {
self.active()?;
Ok(RpcU256::from(take_weak!(self.client).chain_info().best_block_number))
}
fn balance(&self, address: RpcH160, num: Trailing<BlockNumber>) -> Result<RpcU256, Error> {
self.active()?;
let address = address.into();
match num.0 {
BlockNumber::Pending => Ok(take_weak!(self.miner).balance(&*take_weak!(self.client), &address).into()),
@ -404,7 +373,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn storage_at(&self, address: RpcH160, pos: RpcU256, num: Trailing<BlockNumber>) -> Result<RpcH256, Error> {
self.active()?;
let address: Address = RpcH160::into(address);
let position: U256 = RpcU256::into(pos);
match num.0 {
@ -422,8 +390,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn transaction_count(&self, address: RpcH160, num: Trailing<BlockNumber>) -> Result<RpcU256, Error> {
self.active()?;
let address: Address = RpcH160::into(address);
match num.0 {
BlockNumber::Pending => Ok(take_weak!(self.miner).nonce(&*take_weak!(self.client), &address).into()),
@ -440,7 +406,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_transaction_count_by_hash(&self, hash: RpcH256) -> Result<Option<RpcU256>, Error> {
self.active()?;
Ok(
take_weak!(self.client).block(BlockId::Hash(hash.into()))
.map(|block| block.transactions_count().into())
@ -448,8 +413,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_transaction_count_by_number(&self, num: BlockNumber) -> Result<Option<RpcU256>, Error> {
self.active()?;
match num {
BlockNumber::Pending => Ok(Some(
take_weak!(self.miner).status().transactions_in_pending_block.into()
@ -462,8 +425,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_uncles_count_by_hash(&self, hash: RpcH256) -> Result<Option<RpcU256>, Error> {
self.active()?;
Ok(
take_weak!(self.client).block(BlockId::Hash(hash.into()))
.map(|block| block.uncles_count().into())
@ -471,8 +432,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_uncles_count_by_number(&self, num: BlockNumber) -> Result<Option<RpcU256>, Error> {
self.active()?;
match num {
BlockNumber::Pending => Ok(Some(0.into())),
_ => Ok(
@ -483,8 +442,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn code_at(&self, address: RpcH160, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {
self.active()?;
let address: Address = RpcH160::into(address);
match num.0 {
BlockNumber::Pending => Ok(take_weak!(self.miner).code(&*take_weak!(self.client), &address).map_or_else(Bytes::default, Bytes::new)),
@ -501,19 +458,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn block_by_hash(&self, hash: RpcH256, include_txs: bool) -> Result<Option<RichBlock>, Error> {
self.active()?;
self.block(BlockId::Hash(hash.into()), include_txs)
}
fn block_by_number(&self, num: BlockNumber, include_txs: bool) -> Result<Option<RichBlock>, Error> {
self.active()?;
self.block(num.into(), include_txs)
}
fn transaction_by_hash(&self, hash: RpcH256) -> Result<Option<Transaction>, Error> {
self.active()?;
let hash: H256 = hash.into();
let miner = take_weak!(self.miner);
let client = take_weak!(self.client);
@ -521,20 +473,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn transaction_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result<Option<Transaction>, Error> {
self.active()?;
self.transaction(TransactionId::Location(BlockId::Hash(hash.into()), index.value()))
}
fn transaction_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> Result<Option<Transaction>, Error> {
self.active()?;
self.transaction(TransactionId::Location(num.into(), index.value()))
}
fn transaction_receipt(&self, hash: RpcH256) -> Result<Option<Receipt>, Error> {
self.active()?;
let miner = take_weak!(self.miner);
let best_block = take_weak!(self.client).chain_info().best_block_number;
let hash: H256 = hash.into();
@ -549,20 +495,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn uncle_by_block_hash_and_index(&self, hash: RpcH256, index: Index) -> Result<Option<RichBlock>, Error> {
self.active()?;
self.uncle(UncleId { block: BlockId::Hash(hash.into()), position: index.value() })
}
fn uncle_by_block_number_and_index(&self, num: BlockNumber, index: Index) -> Result<Option<RichBlock>, Error> {
self.active()?;
self.uncle(UncleId { block: num.into(), position: index.value() })
}
fn compilers(&self) -> Result<Vec<String>, Error> {
self.active()?;
let mut compilers = vec![];
if Command::new(SOLC).output().is_ok() {
compilers.push("solidity".to_owned())
@ -591,7 +531,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn work(&self, no_new_work_timeout: Trailing<u64>) -> Result<Work, Error> {
self.active()?;
let no_new_work_timeout = no_new_work_timeout.0;
let client = take_weak!(self.client);
@ -643,8 +582,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn submit_work(&self, nonce: RpcH64, pow_hash: RpcH256, mix_hash: RpcH256) -> Result<bool, Error> {
self.active()?;
let nonce: H64 = nonce.into();
let pow_hash: H256 = pow_hash.into();
let mix_hash: H256 = mix_hash.into();
@ -657,14 +594,11 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn submit_hashrate(&self, rate: RpcU256, id: RpcH256) -> Result<bool, Error> {
self.active()?;
self.external_miner.submit_hashrate(rate.into(), id.into());
Ok(true)
}
fn send_raw_transaction(&self, raw: Bytes) -> Result<RpcH256, Error> {
self.active()?;
UntrustedRlp::new(&raw.into_vec()).as_val()
.map_err(errors::from_rlp_error)
.and_then(|tx| SignedTransaction::new(tx).map_err(errors::from_transaction_error))
@ -679,8 +613,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn call(&self, request: CallRequest, num: Trailing<BlockNumber>) -> Result<Bytes, Error> {
self.active()?;
let request = CallRequest::into(request);
let signed = self.sign_call(request)?;
@ -695,8 +627,6 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn estimate_gas(&self, request: CallRequest, num: Trailing<BlockNumber>) -> Result<RpcU256, Error> {
self.active()?;
let request = CallRequest::into(request);
let signed = self.sign_call(request)?;
take_weak!(self.client).estimate_gas(&signed, num.0.into())
@ -705,19 +635,14 @@ impl<C, SN: ?Sized, S: ?Sized, M, EM> Eth for EthClient<C, SN, S, M, EM> where
}
fn compile_lll(&self, _: String) -> Result<Bytes, Error> {
self.active()?;
rpc_unimplemented!()
}
fn compile_serpent(&self, _: String) -> Result<Bytes, Error> {
self.active()?;
rpc_unimplemented!()
}
fn compile_solidity(&self, code: String) -> Result<Bytes, Error> {
self.active()?;
let maybe_child = Command::new(SOLC)
.arg("--bin")
.arg("--optimize")

View File

@ -50,19 +50,12 @@ impl<C, M> EthFilterClient<C, M> where
polls: Mutex::new(PollManager::new()),
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C, M> EthFilter for EthFilterClient<C, M>
where C: BlockChainClient + 'static, M: MinerService + 'static
{
fn new_filter(&self, filter: Filter) -> Result<RpcU256, Error> {
self.active()?;
let mut polls = self.polls.lock();
let block_number = take_weak!(self.client).chain_info().best_block_number;
let id = polls.create_poll(PollFilter::Logs(block_number, Default::default(), filter));
@ -70,16 +63,12 @@ impl<C, M> EthFilter for EthFilterClient<C, M>
}
fn new_block_filter(&self) -> Result<RpcU256, Error> {
self.active()?;
let mut polls = self.polls.lock();
let id = polls.create_poll(PollFilter::Block(take_weak!(self.client).chain_info().best_block_number));
Ok(id.into())
}
fn new_pending_transaction_filter(&self) -> Result<RpcU256, Error> {
self.active()?;
let mut polls = self.polls.lock();
let best_block = take_weak!(self.client).chain_info().best_block_number;
let pending_transactions = take_weak!(self.miner).pending_transactions_hashes(best_block);
@ -88,7 +77,6 @@ impl<C, M> EthFilter for EthFilterClient<C, M>
}
fn filter_changes(&self, index: Index) -> Result<FilterChanges, Error> {
self.active()?;
let client = take_weak!(self.client);
let mut polls = self.polls.lock();
match polls.poll_mut(&index.value()) {
@ -180,8 +168,6 @@ impl<C, M> EthFilter for EthFilterClient<C, M>
}
fn filter_logs(&self, index: Index) -> Result<Vec<Log>, Error> {
self.active()?;
let mut polls = self.polls.lock();
match polls.poll(&index.value()) {
Some(&PollFilter::Logs(ref _block_number, ref _previous_log, ref filter)) => {
@ -207,8 +193,6 @@ impl<C, M> EthFilter for EthFilterClient<C, M>
}
fn uninstall_filter(&self, index: Index) -> Result<bool, Error> {
self.active()?;
self.polls.lock().remove_poll(&index.value());
Ok(true)
}

View File

@ -101,12 +101,6 @@ impl<C, M, S: ?Sized, U> ParityClient<C, M, S, U> where
dapps_port: dapps_port,
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
@ -118,8 +112,6 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
type Metadata = Metadata;
fn accounts_info(&self, dapp: Trailing<DappId>) -> Result<BTreeMap<String, BTreeMap<String, String>>, Error> {
self.active()?;
let dapp = dapp.0;
let store = take_weak!(self.accounts);
@ -149,8 +141,6 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
fn default_account(&self, meta: Self::Metadata) -> BoxFuture<H160, Error> {
let dapp_id = meta.dapp_id.unwrap_or_default();
let default_account = move || {
self.active()?;
Ok(take_weak!(self.accounts)
.dapps_addresses(dapp_id.into())
.ok()
@ -163,57 +153,39 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn transactions_limit(&self) -> Result<usize, Error> {
self.active()?;
Ok(take_weak!(self.miner).transactions_limit())
}
fn min_gas_price(&self) -> Result<U256, Error> {
self.active()?;
Ok(U256::from(take_weak!(self.miner).minimal_gas_price()))
}
fn extra_data(&self) -> Result<Bytes, Error> {
self.active()?;
Ok(Bytes::new(take_weak!(self.miner).extra_data()))
}
fn gas_floor_target(&self) -> Result<U256, Error> {
self.active()?;
Ok(U256::from(take_weak!(self.miner).gas_floor_target()))
}
fn gas_ceil_target(&self) -> Result<U256, Error> {
self.active()?;
Ok(U256::from(take_weak!(self.miner).gas_ceil_target()))
}
fn dev_logs(&self) -> Result<Vec<String>, Error> {
self.active()?;
let logs = self.logger.logs();
Ok(logs.as_slice().to_owned())
}
fn dev_logs_levels(&self) -> Result<String, Error> {
self.active()?;
Ok(self.logger.levels().to_owned())
}
fn net_chain(&self) -> Result<String, Error> {
self.active()?;
Ok(self.settings.chain.clone())
}
fn net_peers(&self) -> Result<Peers, Error> {
self.active()?;
let sync = take_weak!(self.sync);
let sync_status = sync.status();
let net_config = take_weak!(self.net).network_config();
@ -228,20 +200,14 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn net_port(&self) -> Result<u16, Error> {
self.active()?;
Ok(self.settings.network_port)
}
fn node_name(&self) -> Result<String, Error> {
self.active()?;
Ok(self.settings.name.clone())
}
fn registry_address(&self) -> Result<Option<H160>, Error> {
self.active()?;
Ok(
take_weak!(self.client)
.additional_params()
@ -252,7 +218,6 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn rpc_settings(&self) -> Result<RpcSettings, Error> {
self.active()?;
Ok(RpcSettings {
enabled: self.settings.rpc_enabled,
interface: self.settings.rpc_interface.clone(),
@ -261,19 +226,14 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn default_extra_data(&self) -> Result<Bytes, Error> {
self.active()?;
Ok(Bytes::new(version_data()))
}
fn gas_price_histogram(&self) -> Result<Histogram, Error> {
self.active()?;
take_weak!(self.client).gas_price_histogram(100, 10).ok_or_else(errors::not_enough_data).map(Into::into)
}
fn unsigned_transactions_count(&self) -> Result<usize, Error> {
self.active()?;
match self.signer {
None => Err(errors::signer_disabled()),
Some(ref signer) => Ok(signer.len()),
@ -281,56 +241,40 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn generate_secret_phrase(&self) -> Result<String, Error> {
self.active()?;
Ok(random_phrase(12))
}
fn phrase_to_address(&self, phrase: String) -> Result<H160, Error> {
self.active()?;
Ok(Brain::new(phrase).generate().unwrap().address().into())
}
fn list_accounts(&self, count: u64, after: Option<H160>, block_number: Trailing<BlockNumber>) -> Result<Option<Vec<H160>>, Error> {
self.active()?;
Ok(take_weak!(self.client)
.list_accounts(block_number.0.into(), after.map(Into::into).as_ref(), count)
.map(|a| a.into_iter().map(Into::into).collect()))
}
fn list_storage_keys(&self, address: H160, count: u64, after: Option<H256>, block_number: Trailing<BlockNumber>) -> Result<Option<Vec<H256>>, Error> {
self.active()?;
Ok(take_weak!(self.client)
.list_storage(block_number.0.into(), &address.into(), after.map(Into::into).as_ref(), count)
.map(|a| a.into_iter().map(Into::into).collect()))
}
fn encrypt_message(&self, key: H512, phrase: Bytes) -> Result<Bytes, Error> {
self.active()?;
ecies::encrypt(&key.into(), &DEFAULT_MAC, &phrase.0)
.map_err(errors::encryption_error)
.map(Into::into)
}
fn pending_transactions(&self) -> Result<Vec<Transaction>, Error> {
self.active()?;
Ok(take_weak!(self.miner).pending_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
}
fn future_transactions(&self) -> Result<Vec<Transaction>, Error> {
self.active()?;
Ok(take_weak!(self.miner).future_transactions().into_iter().map(Into::into).collect::<Vec<_>>())
}
fn pending_transactions_stats(&self) -> Result<BTreeMap<H256, TransactionStats>, Error> {
self.active()?;
let stats = take_weak!(self.sync).transactions_stats();
Ok(stats.into_iter()
.map(|(hash, stats)| (hash.into(), stats.into()))
@ -339,8 +283,6 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn local_transactions(&self) -> Result<BTreeMap<H256, LocalTransactionStatus>, Error> {
self.active()?;
let transactions = take_weak!(self.miner).local_transactions();
Ok(transactions
.into_iter()
@ -350,8 +292,6 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn signer_port(&self) -> Result<u16, Error> {
self.active()?;
self.signer
.clone()
.and_then(|signer| signer.address())
@ -360,21 +300,16 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn dapps_port(&self) -> Result<u16, Error> {
self.active()?;
self.dapps_port
.ok_or_else(|| errors::dapps_disabled())
}
fn dapps_interface(&self) -> Result<String, Error> {
self.active()?;
self.dapps_interface.clone()
.ok_or_else(|| errors::dapps_disabled())
}
fn next_nonce(&self, address: H160) -> Result<U256, Error> {
self.active()?;
let address: Address = address.into();
let miner = take_weak!(self.miner);
let client = take_weak!(self.client);
@ -400,26 +335,21 @@ impl<C, M, S: ?Sized, U> Parity for ParityClient<C, M, S, U> where
}
fn consensus_capability(&self) -> Result<ConsensusCapability, Error> {
self.active()?;
let updater = take_weak!(self.updater);
Ok(updater.capability().into())
}
fn version_info(&self) -> Result<VersionInfo, Error> {
self.active()?;
let updater = take_weak!(self.updater);
Ok(updater.version_info().into())
}
fn releases_info(&self) -> Result<Option<OperationsInfo>, Error> {
self.active()?;
let updater = take_weak!(self.updater);
Ok(updater.info().map(Into::into))
}
fn chain_status(&self) -> Result<ChainStatus, Error> {
self.active()?;
let chain_info = take_weak!(self.client).chain_info();
let gap = chain_info.ancient_block_number.map(|x| U256::from(x + 1))

View File

@ -21,7 +21,6 @@ use util::{Address};
use ethkey::{Brain, Generator, Secret};
use ethcore::account_provider::AccountProvider;
use ethcore::client::MiningBlockChainClient;
use jsonrpc_core::Error;
use v1::helpers::errors;
@ -29,30 +28,21 @@ use v1::traits::ParityAccounts;
use v1::types::{H160 as RpcH160, H256 as RpcH256, DappId};
/// Account management (personal) rpc implementation.
pub struct ParityAccountsClient<C> where C: MiningBlockChainClient {
pub struct ParityAccountsClient {
accounts: Weak<AccountProvider>,
client: Weak<C>,
}
impl<C> ParityAccountsClient<C> where C: MiningBlockChainClient {
impl ParityAccountsClient {
/// Creates new PersonalClient
pub fn new(store: &Arc<AccountProvider>, client: &Arc<C>) -> Self {
pub fn new(store: &Arc<AccountProvider>) -> Self {
ParityAccountsClient {
accounts: Arc::downgrade(store),
client: Arc::downgrade(client),
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlockChainClient {
impl ParityAccounts for ParityAccountsClient {
fn all_accounts_info(&self) -> Result<BTreeMap<RpcH160, BTreeMap<String, String>>, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let info = store.accounts_info().map_err(|e| errors::account("Could not fetch account info.", e))?;
let other = store.addresses_info();
@ -75,7 +65,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn new_account_from_phrase(&self, phrase: String, pass: String) -> Result<RpcH160, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let brain = Brain::new(phrase).generate().unwrap();
@ -85,7 +74,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn new_account_from_wallet(&self, json: String, pass: String) -> Result<RpcH160, Error> {
self.active()?;
let store = take_weak!(self.accounts);
store.import_presale(json.as_bytes(), &pass)
@ -95,7 +83,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn new_account_from_secret(&self, secret: RpcH256, pass: String) -> Result<RpcH160, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let secret = Secret::from_slice(&secret.0)
@ -106,7 +93,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn test_password(&self, account: RpcH160, password: String) -> Result<bool, Error> {
self.active()?;
let account: Address = account.into();
take_weak!(self.accounts)
@ -115,7 +101,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn change_password(&self, account: RpcH160, password: String, new_password: String) -> Result<bool, Error> {
self.active()?;
let account: Address = account.into();
take_weak!(self.accounts)
.change_password(&account, password, new_password)
@ -124,7 +109,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn kill_account(&self, account: RpcH160, password: String) -> Result<bool, Error> {
self.active()?;
let account: Address = account.into();
take_weak!(self.accounts)
.kill_account(&account, &password)
@ -133,7 +117,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn remove_address(&self, addr: RpcH160) -> Result<bool, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let addr: Address = addr.into();
@ -142,7 +125,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn set_account_name(&self, addr: RpcH160, name: String) -> Result<bool, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let addr: Address = addr.into();
@ -152,7 +134,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn set_account_meta(&self, addr: RpcH160, meta: String) -> Result<bool, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let addr: Address = addr.into();
@ -216,7 +197,6 @@ impl<C: 'static> ParityAccounts for ParityAccountsClient<C> where C: MiningBlock
}
fn geth_accounts(&self) -> Result<Vec<RpcH160>, Error> {
self.active()?;
let store = take_weak!(self.accounts);
Ok(into_vec(store.list_geth_accounts(false)))

View File

@ -23,7 +23,7 @@ use ethcore::client::MiningBlockChainClient;
use ethcore::mode::Mode;
use ethsync::ManageNetwork;
use fetch::{self, Fetch};
use futures::{self, BoxFuture, Future};
use futures::{BoxFuture, Future};
use util::sha3;
use updater::{Service as UpdateService};
@ -62,12 +62,6 @@ impl<C, M, U, F> ParitySetClient<C, M, U, F> where
fetch: fetch,
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
@ -78,63 +72,46 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
{
fn set_min_gas_price(&self, gas_price: U256) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_minimal_gas_price(gas_price.into());
Ok(true)
}
fn set_gas_floor_target(&self, target: U256) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_gas_floor_target(target.into());
Ok(true)
}
fn set_gas_ceil_target(&self, target: U256) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_gas_ceil_target(target.into());
Ok(true)
}
fn set_extra_data(&self, extra_data: Bytes) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_extra_data(extra_data.into_vec());
Ok(true)
}
fn set_author(&self, author: H160) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_author(author.into());
Ok(true)
}
fn set_engine_signer(&self, address: H160, password: String) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::from_password_error)?;
Ok(true)
}
fn set_transactions_limit(&self, limit: usize) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_transactions_limit(limit);
Ok(true)
}
fn set_tx_gas_limit(&self, limit: U256) -> Result<bool, Error> {
self.active()?;
take_weak!(self.miner).set_tx_gas_limit(limit.into());
Ok(true)
}
fn add_reserved_peer(&self, peer: String) -> Result<bool, Error> {
self.active()?;
match take_weak!(self.net).add_reserved_peer(peer) {
Ok(()) => Ok(true),
Err(e) => Err(errors::invalid_params("Peer address", e)),
@ -142,8 +119,6 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
}
fn remove_reserved_peer(&self, peer: String) -> Result<bool, Error> {
self.active()?;
match take_weak!(self.net).remove_reserved_peer(peer) {
Ok(()) => Ok(true),
Err(e) => Err(errors::invalid_params("Peer address", e)),
@ -151,15 +126,11 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
}
fn drop_non_reserved_peers(&self) -> Result<bool, Error> {
self.active()?;
take_weak!(self.net).deny_unreserved_peers();
Ok(true)
}
fn accept_non_reserved_peers(&self) -> Result<bool, Error> {
self.active()?;
take_weak!(self.net).accept_unreserved_peers();
Ok(true)
}
@ -186,10 +157,6 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
}
fn hash_content(&self, url: String) -> BoxFuture<H256, Error> {
if let Err(e) = self.active() {
return futures::failed(e).boxed();
}
self.fetch.process(self.fetch.fetch(&url).then(move |result| {
result
.map_err(errors::from_fetch_error)
@ -201,13 +168,11 @@ impl<C, M, U, F> ParitySet for ParitySetClient<C, M, U, F> where
}
fn upgrade_ready(&self) -> Result<Option<ReleaseInfo>, Error> {
self.active()?;
let updater = take_weak!(self.updater);
Ok(updater.upgrade_ready().map(Into::into))
}
fn execute_upgrade(&self) -> Result<bool, Error> {
self.active()?;
let updater = take_weak!(self.updater);
Ok(updater.execute_upgrade())
}

View File

@ -54,12 +54,6 @@ impl<C, M> PersonalClient<C, M> where
allow_perm_unlock: allow_perm_unlock,
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C, M> Personal for PersonalClient<C, M> where
@ -69,15 +63,12 @@ impl<C, M> Personal for PersonalClient<C, M> where
type Metadata = Metadata;
fn accounts(&self) -> Result<Vec<RpcH160>, Error> {
self.active()?;
let store = take_weak!(self.accounts);
let accounts = store.accounts().map_err(|e| errors::account("Could not fetch accounts.", e))?;
Ok(accounts.into_iter().map(Into::into).collect::<Vec<RpcH160>>())
}
fn new_account(&self, pass: String) -> Result<RpcH160, Error> {
self.active()?;
let store = take_weak!(self.accounts);
store.new_account(&pass)
@ -86,7 +77,6 @@ impl<C, M> Personal for PersonalClient<C, M> where
}
fn unlock_account(&self, account: RpcH160, account_pass: String, duration: Option<RpcU128>) -> Result<bool, Error> {
self.active()?;
let account: Address = account.into();
let store = take_weak!(self.accounts);
let duration = match duration {
@ -117,7 +107,6 @@ impl<C, M> Personal for PersonalClient<C, M> where
fn send_transaction(&self, meta: Metadata, request: TransactionRequest, password: String) -> BoxFuture<RpcH256, Error> {
let sign_and_send = move || {
self.active()?;
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);
let accounts = take_weak!(self.accounts);

View File

@ -55,17 +55,9 @@ impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient,
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
fn confirm_internal<F>(&self, id: U256, modification: TransactionModification, f: F) -> Result<WithToken<ConfirmationResponse>, Error> where
F: FnOnce(&C, &M, &AccountProvider, ConfirmationPayload) -> Result<WithToken<ConfirmationResponse>, Error>,
{
self.active()?;
let id = id.into();
let accounts = take_weak!(self.accounts);
let signer = take_weak!(self.signer);
@ -104,7 +96,6 @@ impl<C: 'static, M: 'static> SignerClient<C, M> where C: MiningBlockChainClient,
impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockChainClient, M: MinerService {
fn requests_to_confirm(&self) -> Result<Vec<ConfirmationRequest>, Error> {
self.active()?;
let signer = take_weak!(self.signer);
Ok(signer.requests()
@ -135,8 +126,6 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
}
fn confirm_request_raw(&self, id: U256, bytes: Bytes) -> Result<ConfirmationResponse, Error> {
self.active()?;
let id = id.into();
let signer = take_weak!(self.signer);
let client = take_weak!(self.client);
@ -187,7 +176,6 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
}
fn reject_request(&self, id: U256) -> Result<bool, Error> {
self.active()?;
let signer = take_weak!(self.signer);
let res = signer.request_rejected(id.into());
@ -195,7 +183,6 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
}
fn generate_token(&self) -> Result<String, Error> {
self.active()?;
let signer = take_weak!(self.signer);
signer.generate_token()
@ -203,7 +190,6 @@ impl<C: 'static, M: 'static> Signer for SignerClient<C, M> where C: MiningBlockC
}
fn generate_web_proxy_token(&self) -> Result<String, Error> {
try!(self.active());
let signer = take_weak!(self.signer);
Ok(signer.generate_web_proxy_access_token())

View File

@ -74,12 +74,6 @@ impl<C, M> SigningQueueClient<C, M> where
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
fn handle_dispatch<OnResponse>(&self, res: Result<DispatchResult, Error>, on_response: OnResponse)
where OnResponse: FnOnce(Result<RpcConfirmationResponse, Error>) + Send + 'static
{
@ -131,7 +125,6 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
type Metadata = Metadata;
fn post_sign(&self, address: RpcH160, data: RpcBytes) -> Result<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
self.active()?;
self.dispatch(RpcConfirmationPayload::Signature((address.clone(), data).into()), DefaultAccount::Provided(address.into()))
.map(|result| match result {
DispatchResult::Value(v) => RpcEither::Or(v),
@ -145,7 +138,6 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
fn post_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcEither<RpcU256, RpcConfirmationResponse>, Error> {
let post_transaction = move || {
self.active()?;
self.dispatch(RpcConfirmationPayload::SendTransaction(request), meta.into())
.map(|result| match result {
DispatchResult::Value(v) => RpcEither::Or(v),
@ -160,7 +152,6 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
}
fn check_request(&self, id: RpcU256) -> Result<Option<RpcConfirmationResponse>, Error> {
self.active()?;
let mut pending = self.pending.lock();
let id: U256 = id.into();
let res = match pending.get(&id) {
@ -176,8 +167,7 @@ impl<C: 'static, M: 'static> ParitySigning for SigningQueueClient<C, M> where
}
fn decrypt_message(&self, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcBytes, Error> {
let res = self.active()
.and_then(|_| self.dispatch(RpcConfirmationPayload::Decrypt((address.clone(), data).into()), address.into()));
let res = self.dispatch(RpcConfirmationPayload::Decrypt((address.clone(), data).into()), address.into());
let (ready, p) = futures::oneshot();
// TODO [todr] typed handle_dispatch
@ -200,8 +190,7 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
type Metadata = Metadata;
fn sign(&self, address: RpcH160, data: RpcBytes) -> BoxFuture<RpcH520, Error> {
let res = self.active()
.and_then(|_| self.dispatch(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into()));
let res = self.dispatch(RpcConfirmationPayload::Signature((address.clone(), data).into()), address.into());
let (ready, p) = futures::oneshot();
self.handle_dispatch(res, |response| {
@ -216,8 +205,7 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
}
fn send_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcH256, Error> {
let res = self.active()
.and_then(|_| self.dispatch(RpcConfirmationPayload::SendTransaction(request), meta.into()));
let res = self.dispatch(RpcConfirmationPayload::SendTransaction(request), meta.into());
let (ready, p) = futures::oneshot();
self.handle_dispatch(res, |response| {
@ -232,7 +220,7 @@ impl<C: 'static, M: 'static> EthSigning for SigningQueueClient<C, M> where
}
fn sign_transaction(&self, meta: Metadata, request: RpcTransactionRequest) -> BoxFuture<RpcRichRawTransaction, Error> {
let res = self.active().and_then(|_| self.dispatch(RpcConfirmationPayload::SignTransaction(request), meta.into()));
let res = self.dispatch(RpcConfirmationPayload::SignTransaction(request), meta.into());
let (ready, p) = futures::oneshot();
self.handle_dispatch(res, |response| {

View File

@ -62,14 +62,7 @@ impl<C, M> SigningUnsafeClient<C, M> where
}
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
fn handle(&self, payload: RpcConfirmationPayload, account: DefaultAccount) -> Result<RpcConfirmationResponse, Error> {
self.active()?;
let client = take_weak!(self.client);
let miner = take_weak!(self.miner);
let accounts = take_weak!(self.accounts);

View File

@ -66,17 +66,10 @@ impl<C, M> TracesClient<C, M> where C: BlockChainClient, M: MinerService {
data: request.data.map_or_else(Vec::new, |d| d.to_vec())
}.fake_sign(from))
}
fn active(&self) -> Result<(), Error> {
// TODO: only call every 30s at most.
take_weak!(self.client).keep_alive();
Ok(())
}
}
impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M: MinerService + 'static {
fn filter(&self, filter: TraceFilter) -> Result<Vec<LocalizedTrace>, Error> {
self.active()?;
let client = take_weak!(self.client);
let traces = client.filter_traces(filter.into());
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
@ -84,7 +77,6 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
}
fn block_traces(&self, block_number: BlockNumber) -> Result<Vec<LocalizedTrace>, Error> {
self.active()?;
let client = take_weak!(self.client);
let traces = client.block_traces(block_number.into());
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
@ -92,7 +84,6 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
}
fn transaction_traces(&self, transaction_hash: H256) -> Result<Vec<LocalizedTrace>, Error> {
self.active()?;
let client = take_weak!(self.client);
let traces = client.transaction_traces(TransactionId::Hash(transaction_hash.into()));
let traces = traces.map_or_else(Vec::new, |traces| traces.into_iter().map(LocalizedTrace::from).collect());
@ -100,7 +91,6 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
}
fn trace(&self, transaction_hash: H256, address: Vec<Index>) -> Result<Option<LocalizedTrace>, Error> {
self.active()?;
let client = take_weak!(self.client);
let id = TraceId {
transaction: TransactionId::Hash(transaction_hash.into()),
@ -113,7 +103,6 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
}
fn call(&self, request: CallRequest, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error> {
self.active()?;
let block = block.0;
let request = CallRequest::into(request);
@ -125,7 +114,6 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
}
fn raw_transaction(&self, raw_transaction: Bytes, flags: Vec<String>, block: Trailing<BlockNumber>) -> Result<Option<TraceResults>, Error> {
self.active()?;
let block = block.0;
UntrustedRlp::new(&raw_transaction.into_vec()).as_val()
@ -140,8 +128,6 @@ impl<C, M> Traces for TracesClient<C, M> where C: BlockChainClient + 'static, M:
}
fn replay_transaction(&self, transaction_hash: H256, flags: Vec<String>) -> Result<Option<TraceResults>, Error> {
self.active()?;
Ok(match take_weak!(self.client).replay(TransactionId::Hash(transaction_hash.into()), to_call_analytics(flags)) {
Ok(e) => Some(TraceResults::from(e)),
_ => None,

View File

@ -29,5 +29,5 @@ pub mod types;
pub use self::traits::{Web3, Eth, EthFilter, EthSigning, Net, Parity, ParityAccounts, ParitySet, ParitySigning, Signer, Personal, Traces, Rpc};
pub use self::impls::*;
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import};
pub use self::helpers::{SigningQueue, SignerService, ConfirmationsQueue, NetworkSettings, block_import, informant};
pub use self::metadata::{Metadata, Origin};

View File

@ -17,7 +17,6 @@
use std::sync::Arc;
use ethcore::account_provider::AccountProvider;
use ethcore::client::TestBlockChainClient;
use jsonrpc_core::IoHandler;
use v1::{ParityAccounts, ParityAccountsClient};
@ -25,14 +24,6 @@ use v1::{ParityAccounts, ParityAccountsClient};
struct ParityAccountsTester {
accounts: Arc<AccountProvider>,
io: IoHandler,
// these unused fields are necessary to keep the data alive
// as the handler has only weak pointers.
_client: Arc<TestBlockChainClient>,
}
fn blockchain_client() -> Arc<TestBlockChainClient> {
let client = TestBlockChainClient::new();
Arc::new(client)
}
fn accounts_provider() -> Arc<AccountProvider> {
@ -41,8 +32,7 @@ fn accounts_provider() -> Arc<AccountProvider> {
fn setup() -> ParityAccountsTester {
let accounts = accounts_provider();
let client = blockchain_client();
let parity_accounts = ParityAccountsClient::new(&accounts, &client);
let parity_accounts = ParityAccountsClient::new(&accounts);
let mut io = IoHandler::default();
io.extend_with(parity_accounts.to_delegate());
@ -50,7 +40,6 @@ fn setup() -> ParityAccountsTester {
let tester = ParityAccountsTester {
accounts: accounts,
io: io,
_client: client,
};
tester

View File

@ -17,17 +17,19 @@
//! `WebSockets` server.
use ws;
use std;
use std::thread;
use std::path::PathBuf;
use std::default::Default;
use std::ops::Drop;
use std::sync::Arc;
use std::net::SocketAddr;
use std::ops::Drop;
use std::path::PathBuf;
use std::sync::Arc;
use std::thread;
use std;
use io::{PanicHandler, OnPanicListener, MayPanic};
use jsonrpc_core::Metadata;
use jsonrpc_core::{Metadata, Middleware};
use jsonrpc_core::reactor::RpcHandler;
use rpc::ConfirmationsQueue;
use rpc::{ConfirmationsQueue};
use rpc::informant::RpcStats;
mod session;
@ -54,6 +56,7 @@ pub struct ServerBuilder {
queue: Arc<ConfirmationsQueue>,
authcodes_path: PathBuf,
skip_origin_validation: bool,
stats: Option<Arc<RpcStats>>,
}
impl ServerBuilder {
@ -63,6 +66,7 @@ impl ServerBuilder {
queue: queue,
authcodes_path: authcodes_path,
skip_origin_validation: false,
stats: None,
}
}
@ -73,10 +77,23 @@ impl ServerBuilder {
self
}
/// Configure statistic collection
pub fn stats(mut self, stats: Arc<RpcStats>) -> Self {
self.stats = Some(stats);
self
}
/// Starts a new `WebSocket` server in separate thread.
/// Returns a `Server` handle which closes the server when droped.
pub fn start<M: Metadata>(self, addr: SocketAddr, handler: RpcHandler<M>) -> Result<Server, ServerError> {
Server::start(addr, handler, self.queue, self.authcodes_path, self.skip_origin_validation)
pub fn start<M: Metadata, S: Middleware<M>>(self, addr: SocketAddr, handler: RpcHandler<M, S>) -> Result<Server, ServerError> {
Server::start(
addr,
handler,
self.queue,
self.authcodes_path,
self.skip_origin_validation,
self.stats,
)
}
}
@ -97,7 +114,14 @@ impl Server {
/// Starts a new `WebSocket` server in separate thread.
/// Returns a `Server` handle which closes the server when droped.
fn start<M: Metadata>(addr: SocketAddr, handler: RpcHandler<M>, queue: Arc<ConfirmationsQueue>, authcodes_path: PathBuf, skip_origin_validation: bool) -> Result<Server, ServerError> {
fn start<M: Metadata, S: Middleware<M>>(
addr: SocketAddr,
handler: RpcHandler<M, S>,
queue: Arc<ConfirmationsQueue>,
authcodes_path: PathBuf,
skip_origin_validation: bool,
stats: Option<Arc<RpcStats>>,
) -> Result<Server, ServerError> {
let config = {
let mut config = ws::Settings::default();
// accept only handshakes beginning with GET
@ -111,7 +135,7 @@ impl Server {
let origin = format!("{}", addr);
let port = addr.port();
let ws = ws::Builder::new().with_settings(config).build(
session::Factory::new(handler, origin, port, authcodes_path, skip_origin_validation)
session::Factory::new(handler, origin, port, authcodes_path, skip_origin_validation, stats)
)?;
let panic_handler = PanicHandler::new_in_arc();

View File

@ -21,8 +21,9 @@ use authcode_store::AuthCodes;
use std::path::{PathBuf, Path};
use std::sync::Arc;
use std::str::FromStr;
use jsonrpc_core::{Metadata};
use jsonrpc_core::{Metadata, Middleware};
use jsonrpc_core::reactor::RpcHandler;
use rpc::informant::RpcStats;
use util::{H256, version};
#[cfg(feature = "parity-ui")]
@ -124,17 +125,24 @@ fn add_headers(mut response: ws::Response, mime: &str) -> ws::Response {
response
}
pub struct Session<M: Metadata> {
pub struct Session<M: Metadata, S: Middleware<M>> {
out: ws::Sender,
skip_origin_validation: bool,
self_origin: String,
self_port: u16,
authcodes_path: PathBuf,
handler: RpcHandler<M>,
handler: RpcHandler<M, S>,
file_handler: Arc<ui::Handler>,
stats: Option<Arc<RpcStats>>,
}
impl<M: Metadata> ws::Handler for Session<M> {
impl<M: Metadata, S: Middleware<M>> Drop for Session<M, S> {
fn drop(&mut self) {
self.stats.as_ref().map(|stats| stats.close_session());
}
}
impl<M: Metadata, S: Middleware<M>> ws::Handler for Session<M, S> {
#[cfg_attr(feature="dev", allow(collapsible_if))]
fn on_request(&mut self, req: &ws::Request) -> ws::Result<(ws::Response)> {
trace!(target: "signer", "Handling request: {:?}", req);
@ -221,17 +229,25 @@ impl<M: Metadata> ws::Handler for Session<M> {
}
}
pub struct Factory<M: Metadata> {
handler: RpcHandler<M>,
pub struct Factory<M: Metadata, S: Middleware<M>> {
handler: RpcHandler<M, S>,
skip_origin_validation: bool,
self_origin: String,
self_port: u16,
authcodes_path: PathBuf,
file_handler: Arc<ui::Handler>,
stats: Option<Arc<RpcStats>>,
}
impl<M: Metadata> Factory<M> {
pub fn new(handler: RpcHandler<M>, self_origin: String, self_port: u16, authcodes_path: PathBuf, skip_origin_validation: bool) -> Self {
impl<M: Metadata, S: Middleware<M>> Factory<M, S> {
pub fn new(
handler: RpcHandler<M, S>,
self_origin: String,
self_port: u16,
authcodes_path: PathBuf,
skip_origin_validation: bool,
stats: Option<Arc<RpcStats>>,
) -> Self {
Factory {
handler: handler,
skip_origin_validation: skip_origin_validation,
@ -239,14 +255,17 @@ impl<M: Metadata> Factory<M> {
self_port: self_port,
authcodes_path: authcodes_path,
file_handler: Arc::new(ui::Handler::default()),
stats: stats,
}
}
}
impl<M: Metadata> ws::Factory for Factory<M> {
type Handler = Session<M>;
impl<M: Metadata, S: Middleware<M>> ws::Factory for Factory<M, S> {
type Handler = Session<M, S>;
fn connection_made(&mut self, sender: ws::Sender) -> Self::Handler {
self.stats.as_ref().map(|stats| stats.open_session());
Session {
out: sender,
handler: self.handler.clone(),
@ -255,6 +274,7 @@ impl<M: Metadata> ws::Factory for Factory<M> {
self_port: self.self_port,
authcodes_path: self.authcodes_path.clone(),
file_handler: self.file_handler.clone(),
stats: self.stats.clone(),
}
}
}