From 0a60da622f0ab36a4a2a1afca086c51770172f9a Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 3 Apr 2016 21:43:35 +0300 Subject: [PATCH 01/52] new crate --- ipc/nano/Cargo.toml | 11 +++++++++++ ipc/nano/src/lib.rs | 20 ++++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 ipc/nano/Cargo.toml create mode 100644 ipc/nano/src/lib.rs diff --git a/ipc/nano/Cargo.toml b/ipc/nano/Cargo.toml new file mode 100644 index 000000000..73de137c3 --- /dev/null +++ b/ipc/nano/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "ethcore-ipc-nano" +version = "1.1.0" +authors = ["Nikolay Volf "] +license = "GPL-3.0" + +[features] + +[dependencies] +"ethcore-ipc" = { path = "../rpc" } +nanomsg = "0.5.0" diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs new file mode 100644 index 000000000..a77ff7f05 --- /dev/null +++ b/ipc/nano/src/lib.rs @@ -0,0 +1,20 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Ethcore implementation of IPC over nanomsg transport + +extern crate ethcore_ipc as ipc; +extern crate nanomsg; From b04d8196c7496cfdec7cc2d1dfb200e4abdffd28 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 3 Apr 2016 23:39:49 +0300 Subject: [PATCH 02/52] dispatch_buf --- ipc/codegen/src/codegen.rs | 9 +++++++++ ipc/nano/src/lib.rs | 24 +++++++++++++++++++++++- ipc/rpc/src/interface.rs | 4 ++++ 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/ipc/codegen/src/codegen.rs b/ipc/codegen/src/codegen.rs index 166ae87bd..f0c404132 100644 --- a/ipc/codegen/src/codegen.rs +++ b/ipc/codegen/src/codegen.rs @@ -531,6 +531,15 @@ fn implement_interface( _ => vec![] } } + + fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec + where R: ::std::io::Read + { + match method_num { + $dispatch_arms + _ => vec![] + } + } } ).unwrap(), dispatch_table)) } diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index a77ff7f05..166c4ea53 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -14,7 +14,29 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Ethcore implementation of IPC over nanomsg transport +//! IPC over nanomsg transport extern crate ethcore_ipc as ipc; extern crate nanomsg; + +pub use ipc::*; + +use std::sync::*; +use nanomsg::{Socket, Protocol}; + +pub struct Worker where S: IpcInterface { + service: Arc, + sockets: Vec, +} + +impl Worker where S: IpcInterface { + pub fn new(service: Arc, socket_addr: &str) -> Worker { + Worker:: { + service: service.clone(), + sockets: Vec::new(), + } + } + + pub fn work_loop(&mut self) { + } +} diff --git a/ipc/rpc/src/interface.rs b/ipc/rpc/src/interface.rs index 8d67deca3..a55133191 100644 --- a/ipc/rpc/src/interface.rs +++ b/ipc/rpc/src/interface.rs @@ -23,6 +23,10 @@ use std::sync::atomic::*; pub trait IpcInterface { /// reads the message from io, dispatches the call and returns result fn dispatch(&self, r: &mut R) -> Vec where R: Read; + + /// deserialize the payload from the io `r` and invokes method specified by `method_num` + /// (for non-blocking io) + fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec where R: Read; } /// serializes method invocation (method_num and parameters) to the stream specified by `w` From 326855dc3a8e5bf2fbbaa05afbe7ea8c89489d8c Mon Sep 17 00:00:00 2001 From: NikVolf Date: Sun, 3 Apr 2016 23:58:18 +0300 Subject: [PATCH 03/52] basic polling --- ipc/nano/src/lib.rs | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 166c4ea53..c43cb9b3e 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -22,21 +22,34 @@ extern crate nanomsg; pub use ipc::*; use std::sync::*; +use std::io::Write; use nanomsg::{Socket, Protocol}; pub struct Worker where S: IpcInterface { service: Arc, sockets: Vec, + method_buf: [u8;2], } impl Worker where S: IpcInterface { - pub fn new(service: Arc, socket_addr: &str) -> Worker { + pub fn new(service: Arc) -> Worker { Worker:: { service: service.clone(), sockets: Vec::new(), + method_buf: [0,0] } } - pub fn work_loop(&mut self) { + pub fn poll(&mut self) { + for socket in self.sockets.iter_mut() { + if let Ok(method_sig_len) = socket.nb_read(&mut self.method_buf) { + if method_sig_len == 2 { + let result = self.service.dispatch_buf( + self.method_buf[1] as u16 * 256 + self.method_buf[0] as u16, + socket); + socket.write(&result); + } + } + } } } From 5cd6a0408245c43aa515d894873bf396b3e79a04 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 00:00:57 +0300 Subject: [PATCH 04/52] to pollng also --- ipc/nano/Cargo.toml | 1 + ipc/nano/src/lib.rs | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/ipc/nano/Cargo.toml b/ipc/nano/Cargo.toml index 73de137c3..c13a7b5a5 100644 --- a/ipc/nano/Cargo.toml +++ b/ipc/nano/Cargo.toml @@ -9,3 +9,4 @@ license = "GPL-3.0" [dependencies] "ethcore-ipc" = { path = "../rpc" } nanomsg = "0.5.0" +log = "0.3" diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index c43cb9b3e..e92542d03 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -18,6 +18,7 @@ extern crate ethcore_ipc as ipc; extern crate nanomsg; +#[macro_use] extern crate log; pub use ipc::*; @@ -47,7 +48,9 @@ impl Worker where S: IpcInterface { let result = self.service.dispatch_buf( self.method_buf[1] as u16 * 256 + self.method_buf[0] as u16, socket); - socket.write(&result); + if let Err(e) = socket.write(&result) { + warn!(target: "ipc", "Failed to write response: {:?}", e); + } } } } From 99d127bb34fb02d4b99c70cec62f06ab3a078f12 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 00:33:30 +0300 Subject: [PATCH 05/52] duplex & tests --- ipc/nano/src/lib.rs | 52 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index e92542d03..1b0d0ca7b 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -32,6 +32,10 @@ pub struct Worker where S: IpcInterface { method_buf: [u8;2], } +pub enum SocketError { + DuplexLink +} + impl Worker where S: IpcInterface { pub fn new(service: Arc) -> Worker { Worker:: { @@ -43,8 +47,9 @@ impl Worker where S: IpcInterface { pub fn poll(&mut self) { for socket in self.sockets.iter_mut() { - if let Ok(method_sig_len) = socket.nb_read(&mut self.method_buf) { - if method_sig_len == 2 { + // non-blocking read only ok if there is something to read from socket + if let Ok(method_sign_len) = socket.nb_read(&mut self.method_buf) { + if method_sign_len == 2 { let result = self.service.dispatch_buf( self.method_buf[1] as u16 * 256 + self.method_buf[0] as u16, socket); @@ -52,7 +57,50 @@ impl Worker where S: IpcInterface { warn!(target: "ipc", "Failed to write response: {:?}", e); } } + else { + warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len); + } } } } + + pub fn add_duplex(&mut self, addr: &str) -> Result<(), SocketError> { + let mut socket = try!(Socket::new(Protocol::Pair).map_err(|e| { + warn!(target: "ipc", "Failed to create ipc socket: {:?}", e); + SocketError::DuplexLink + })); + + try!(socket.bind(addr).map_err(|e| { + warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e); + SocketError::DuplexLink + })); + + self.sockets.push(socket); + Ok(()) + } +} + +#[cfg(test)] +mod tests { + + use super::Worker; + use ipc::*; + use std::io::Read; + use std::sync::Arc; + + struct DummyService; + + impl IpcInterface for DummyService { + fn dispatch(&self, r: &mut R) -> Vec where R: Read { + vec![] + } + fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec where R: Read { + vec![] + } + } + + fn can_create_worker() { + let worker = Worker::::new(Arc::new(DummyService)); + assert_eq!(0, worker.sockets.len()); + } } From 1395d58d3941b4fd2ba4e5a2b5dd8a137734c8c9 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 00:42:00 +0300 Subject: [PATCH 06/52] actual test flag --- ipc/nano/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 1b0d0ca7b..51b484049 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -99,6 +99,7 @@ mod tests { } } + #[test] fn can_create_worker() { let worker = Worker::::new(Arc::new(DummyService)); assert_eq!(0, worker.sockets.len()); From 675af841e8aa49ccc02baefb1b5f7ebbd02e6a87 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 00:54:30 +0300 Subject: [PATCH 07/52] dummy service --- ipc/nano/src/lib.rs | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 51b484049..28fbef610 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -32,6 +32,7 @@ pub struct Worker where S: IpcInterface { method_buf: [u8;2], } +#[derive(Debug)] pub enum SocketError { DuplexLink } @@ -86,22 +87,49 @@ mod tests { use super::Worker; use ipc::*; use std::io::Read; - use std::sync::Arc; + use std::sync::{Arc, RwLock}; - struct DummyService; + struct TestInvoke { + method_num: u16, + params: Vec, + } + + struct DummyService { + methods_stack: RwLock>, + } + + impl DummyService { + fn new() -> DummyService { + DummyService { methods_stack: RwLock::new(Vec::new()) } + } + } impl IpcInterface for DummyService { - fn dispatch(&self, r: &mut R) -> Vec where R: Read { + fn dispatch(&self, _r: &mut R) -> Vec where R: Read { vec![] } fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec where R: Read { + let mut buf = vec![0u8; 4096]; + let size = r.read_to_end(&mut buf).unwrap(); + self.methods_stack.write().unwrap().push( + TestInvoke { + method_num: method_num, + params: unsafe { Vec::from_raw_parts(buf.as_mut_ptr(), size, size) } + }); vec![] } } #[test] fn can_create_worker() { - let worker = Worker::::new(Arc::new(DummyService)); + let worker = Worker::::new(Arc::new(DummyService::new())); assert_eq!(0, worker.sockets.len()); } + + #[test] + fn can_add_duplex_socket_to_worker() { + let mut worker = Worker::::new(Arc::new(DummyService::new())); + worker.add_duplex("ipc://tmp/parity/test1").unwrap(); + assert_eq!(1, worker.sockets.len()); + } } From fa63d9e34ade52529b1f2d003ab949b2401b0415 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 01:44:30 +0300 Subject: [PATCH 08/52] non-working test for dispatching --- ipc/nano/src/lib.rs | 66 ++++++++++++++++++++++++++++++++++++--------- 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 28fbef610..81d3ac6ec 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -24,7 +24,7 @@ pub use ipc::*; use std::sync::*; use std::io::Write; -use nanomsg::{Socket, Protocol}; +use nanomsg::{Socket, Protocol, Error}; pub struct Worker where S: IpcInterface { service: Arc, @@ -49,17 +49,25 @@ impl Worker where S: IpcInterface { pub fn poll(&mut self) { for socket in self.sockets.iter_mut() { // non-blocking read only ok if there is something to read from socket - if let Ok(method_sign_len) = socket.nb_read(&mut self.method_buf) { - if method_sign_len == 2 { - let result = self.service.dispatch_buf( - self.method_buf[1] as u16 * 256 + self.method_buf[0] as u16, - socket); - if let Err(e) = socket.write(&result) { - warn!(target: "ipc", "Failed to write response: {:?}", e); + match socket.nb_read(&mut self.method_buf) { + Ok(method_sign_len) => { + if method_sign_len == 2 { + let result = self.service.dispatch_buf( + self.method_buf[1] as u16 * 256 + self.method_buf[0] as u16, + socket); + if let Err(e) = socket.write(&result) { + warn!(target: "ipc", "Failed to write response: {:?}", e); + } } + else { + warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len); + } + }, + Err(Error::TryAgain) => { } - else { - warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len); + Err(x) => { + warn!(target: "ipc", "Error polling connection {:?}", x); + panic!(); } } } @@ -86,8 +94,10 @@ mod tests { use super::Worker; use ipc::*; - use std::io::Read; + use std::io::{Read, Write}; use std::sync::{Arc, RwLock}; + use nanomsg::{Socket, Protocol}; + use std::thread; struct TestInvoke { method_num: u16, @@ -120,6 +130,15 @@ mod tests { } } + fn dummy_write(addr: &str, buf: &[u8]) { + let mut socket = Socket::new(Protocol::Pair).unwrap(); + socket.connect(addr).unwrap(); + thread::sleep_ms(10); +// socket.nb_write(buf).unwrap(); +// socket.flush(); + socket.write_all(buf).unwrap(); + } + #[test] fn can_create_worker() { let worker = Worker::::new(Arc::new(DummyService::new())); @@ -129,7 +148,30 @@ mod tests { #[test] fn can_add_duplex_socket_to_worker() { let mut worker = Worker::::new(Arc::new(DummyService::new())); - worker.add_duplex("ipc://tmp/parity/test1").unwrap(); + worker.add_duplex("ipc://tmp/parity-test10.ipc").unwrap(); assert_eq!(1, worker.sockets.len()); } + + #[test] + fn worker_can_poll_empty() { + let service = Arc::new(DummyService::new()); + let mut worker = Worker::::new(service.clone()); + worker.add_duplex("ipc://tmp/parity-test20.ipc").unwrap(); + worker.poll(); + assert_eq!(0, service.methods_stack.read().unwrap().len()); + } + + #[test] + fn worker_can_poll() { + let service = Arc::new(DummyService::new()); + let mut worker = Worker::::new(service.clone()); + worker.add_duplex("ipc:///tmp/parity-test30.ipc").unwrap(); + thread::sleep_ms(10); + + dummy_write("ipc:///tmp/parity-test30.ipc", &vec![0, 0, 6, 6, 6, 6]); + thread::sleep_ms(10); + worker.poll(); + + assert_eq!(1, service.methods_stack.read().unwrap().len()); + } } From 35465debd69d84a13dd37d4e7c5e4f8f861649d9 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 01:52:19 +0300 Subject: [PATCH 09/52] flush --- ipc/nano/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 81d3ac6ec..f44a68bd5 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -148,7 +148,7 @@ mod tests { #[test] fn can_add_duplex_socket_to_worker() { let mut worker = Worker::::new(Arc::new(DummyService::new())); - worker.add_duplex("ipc://tmp/parity-test10.ipc").unwrap(); + worker.add_duplex("ipc:///tmp/parity-test10.ipc").unwrap(); assert_eq!(1, worker.sockets.len()); } @@ -156,7 +156,7 @@ mod tests { fn worker_can_poll_empty() { let service = Arc::new(DummyService::new()); let mut worker = Worker::::new(service.clone()); - worker.add_duplex("ipc://tmp/parity-test20.ipc").unwrap(); + worker.add_duplex("ipc:///tmp/parity-test20.ipc").unwrap(); worker.poll(); assert_eq!(0, service.methods_stack.read().unwrap().len()); } From 952a834e43c3a1c2f610b97ae40d3ed20aa8c0b8 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 10:55:06 +0300 Subject: [PATCH 10/52] savework --- ipc/nano/src/lib.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index f44a68bd5..da820855d 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -23,7 +23,7 @@ extern crate nanomsg; pub use ipc::*; use std::sync::*; -use std::io::Write; +use std::io::{Write, Read}; use nanomsg::{Socket, Protocol, Error}; pub struct Worker where S: IpcInterface { @@ -64,7 +64,7 @@ impl Worker where S: IpcInterface { } }, Err(Error::TryAgain) => { - } + }, Err(x) => { warn!(target: "ipc", "Error polling connection {:?}", x); panic!(); @@ -134,8 +134,6 @@ mod tests { let mut socket = Socket::new(Protocol::Pair).unwrap(); socket.connect(addr).unwrap(); thread::sleep_ms(10); -// socket.nb_write(buf).unwrap(); -// socket.flush(); socket.write_all(buf).unwrap(); } @@ -163,15 +161,16 @@ mod tests { #[test] fn worker_can_poll() { - let service = Arc::new(DummyService::new()); - let mut worker = Worker::::new(service.clone()); - worker.add_duplex("ipc:///tmp/parity-test30.ipc").unwrap(); + let url = "ipc:///tmp/parity-test30.ipc"; + + let mut worker = Worker::::new(Arc::new(DummyService::new())); + worker.add_duplex(url).unwrap(); thread::sleep_ms(10); - dummy_write("ipc:///tmp/parity-test30.ipc", &vec![0, 0, 6, 6, 6, 6]); + dummy_write(url, &vec![0, 0]); thread::sleep_ms(10); worker.poll(); - assert_eq!(1, service.methods_stack.read().unwrap().len()); + assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); } } From 4cde01d81aedf17a0cdf1433234388d719651b02 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Mon, 4 Apr 2016 20:47:16 +0300 Subject: [PATCH 11/52] guarding endpoints --- ipc/nano/src/lib.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index da820855d..d1cc58c48 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -24,11 +24,11 @@ pub use ipc::*; use std::sync::*; use std::io::{Write, Read}; -use nanomsg::{Socket, Protocol, Error}; +use nanomsg::{Socket, Protocol, Error, Endpoint}; pub struct Worker where S: IpcInterface { service: Arc, - sockets: Vec, + sockets: Vec<(Socket, Endpoint)>, method_buf: [u8;2], } @@ -47,7 +47,8 @@ impl Worker where S: IpcInterface { } pub fn poll(&mut self) { - for socket in self.sockets.iter_mut() { + for item in self.sockets.iter_mut() { + let socket = &mut item.0; // non-blocking read only ok if there is something to read from socket match socket.nb_read(&mut self.method_buf) { Ok(method_sign_len) => { @@ -79,12 +80,12 @@ impl Worker where S: IpcInterface { SocketError::DuplexLink })); - try!(socket.bind(addr).map_err(|e| { + let endpoint = try!(socket.bind(addr).map_err(|e| { warn!(target: "ipc", "Failed to bind socket to address '{}': {:?}", addr, e); SocketError::DuplexLink })); - self.sockets.push(socket); + self.sockets.push((socket, endpoint)); Ok(()) } } @@ -132,7 +133,7 @@ mod tests { fn dummy_write(addr: &str, buf: &[u8]) { let mut socket = Socket::new(Protocol::Pair).unwrap(); - socket.connect(addr).unwrap(); + let endpoint = socket.connect(addr).unwrap(); thread::sleep_ms(10); socket.write_all(buf).unwrap(); } @@ -165,10 +166,8 @@ mod tests { let mut worker = Worker::::new(Arc::new(DummyService::new())); worker.add_duplex(url).unwrap(); - thread::sleep_ms(10); - dummy_write(url, &vec![0, 0]); - thread::sleep_ms(10); + dummy_write(url, &vec![0, 0, 7, 7, 6, 6]); worker.poll(); assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); From 0d7e52ac6fa5e08edc960178cf36a61b196c50ea Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 5 Apr 2016 12:08:42 +0300 Subject: [PATCH 12/52] dispatch buf and proper polling --- ipc/codegen/src/codegen.rs | 164 ++++++++++++++++++++++--------------- ipc/nano/src/lib.rs | 62 +++++++++----- ipc/rpc/src/interface.rs | 2 +- 3 files changed, 139 insertions(+), 89 deletions(-) diff --git a/ipc/codegen/src/codegen.rs b/ipc/codegen/src/codegen.rs index f0c404132..5385c72d7 100644 --- a/ipc/codegen/src/codegen.rs +++ b/ipc/codegen/src/codegen.rs @@ -145,14 +145,20 @@ struct Dispatch { return_type_ty: Option>, } -fn implement_dispatch_arm_invoke( +// This is the expanded version of this: +// +// let invoke_serialize_stmt = quote_stmt!(cx, { +// ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap() +// }); +// +// But the above does not allow comma-separated expressions for arbitrary number +// of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n +fn implement_dispatch_arm_invoke_stmt( cx: &ExtCtxt, builder: &aster::AstBuilder, dispatch: &Dispatch, -) -> P +) -> ast::Stmt { - let deserialize_expr = quote_expr!(cx, ::bincode::serde::deserialize_from(r, ::bincode::SizeLimit::Infinite).expect("ipc deserialization error, aborting")); - let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str()); let function_name = builder.id(dispatch.function_name.as_str()); let output_type_id = builder.id(dispatch.return_type_name.clone().unwrap().as_str()); @@ -161,63 +167,71 @@ fn implement_dispatch_arm_invoke( quote_expr!(cx, input. $arg_ident) }).collect::>>(); - // This is the expanded version of this: - // - // let invoke_serialize_stmt = quote_stmt!(cx, { - // ::bincode::serde::serialize(& $output_type_id { payload: self. $function_name ($hand_param_a, $hand_param_b) }, ::bincode::SizeLimit::Infinite).unwrap() - // }); - // - // But the above does not allow comma-separated expressions for arbitrary number - // of parameters ...$hand_param_a, $hand_param_b, ... $hand_param_n - let invoke_serialize_stmt = { - let ext_cx = &*cx; - ::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts( - ext_cx.parse_sess(), - ext_cx.cfg(), - { - let _sp = ext_cx.call_site(); - let mut tt = ::std::vec::Vec::new(); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serde"), ::syntax::parse::token::ModName))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And))); - tt.extend(::quasi::ToTokens::to_tokens(&output_type_id, ext_cx).into_iter()); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"), ::syntax::parse::token::Plain))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"), ::syntax::parse::token::Plain))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); - tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter()); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); + let ext_cx = &*cx; + ::quasi::parse_stmt_panic(&mut ::syntax::parse::new_parser_from_tts( + ext_cx.parse_sess(), + ext_cx.cfg(), + { + let _sp = ext_cx.call_site(); + let mut tt = ::std::vec::Vec::new(); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serde"), ::syntax::parse::token::ModName))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("serialize"), ::syntax::parse::token::Plain))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::BinOp(::syntax::parse::token::And))); + tt.extend(::quasi::ToTokens::to_tokens(&output_type_id, ext_cx).into_iter()); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Brace))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("payload"), ::syntax::parse::token::Plain))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Colon)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("self"), ::syntax::parse::token::Plain))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); + tt.extend(::quasi::ToTokens::to_tokens(&function_name, ext_cx).into_iter()); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); - for arg_expr in input_args_exprs { - tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter()); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma)); - } - - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace))); + for arg_expr in input_args_exprs { + tt.extend(::quasi::ToTokens::to_tokens(&arg_expr, ext_cx).into_iter()); tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("SizeLimit"), ::syntax::parse::token::ModName))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Infinite"), ::syntax::parse::token::Plain))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"), ::syntax::parse::token::Plain))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); - tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace))); - tt - })) + } + + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Comma)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("bincode"), ::syntax::parse::token::ModName))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("SizeLimit"), ::syntax::parse::token::ModName))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::ModSep)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("Infinite"), ::syntax::parse::token::Plain))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Dot)); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::Ident(ext_cx.ident_of("unwrap"), ::syntax::parse::token::Plain))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::OpenDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Paren))); + tt.push(::syntax::ast::TokenTree::Token(_sp, ::syntax::parse::token::CloseDelim(::syntax::parse::token::Brace))); + tt + })).unwrap() +} + +fn implement_dispatch_arm_invoke( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + dispatch: &Dispatch, + buffer: bool, +) -> P +{ + let deserialize_expr = if buffer { + quote_expr!(cx, ::bincode::serde::deserialize(buf).expect("ipc deserialization error, aborting")) + } else { + quote_expr!(cx, ::bincode::serde::deserialize_from(r, ::bincode::SizeLimit::Infinite).expect("ipc deserialization error, aborting")) }; + + let input_type_id = builder.id(dispatch.input_type_name.clone().unwrap().as_str()); + + let invoke_serialize_stmt = implement_dispatch_arm_invoke_stmt(cx, builder, dispatch); quote_expr!(cx, { let input: $input_type_id = $deserialize_expr; $invoke_serialize_stmt @@ -225,14 +239,31 @@ fn implement_dispatch_arm_invoke( } /// generates dispatch match for method id -fn implement_dispatch_arm(cx: &ExtCtxt, builder: &aster::AstBuilder, index: u32, dispatch: &Dispatch) - -> ast::Arm +fn implement_dispatch_arm( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + index: u32, + dispatch: &Dispatch, + buffer: bool, +) -> ast::Arm { let index_ident = builder.id(format!("{}", index).as_str()); - let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch); + let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer); quote_arm!(cx, $index_ident => { $invoke_expr } ) } +fn implement_dispatch_arms( + cx: &ExtCtxt, + builder: &aster::AstBuilder, + dispatches: &[Dispatch], + buffer: bool, +) -> Vec +{ + let mut index = -1; + dispatches.iter() + .map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch, buffer) }).collect() +} + /// generates client type for specified server type /// for say `Service` it generates `ServiceClient` fn push_client_struct(cx: &ExtCtxt, builder: &aster::AstBuilder, item: &Item, push: &mut FnMut(Annotatable)) { @@ -511,9 +542,9 @@ fn implement_interface( dispatch_table.push(push_invoke_signature_aster(builder, &impl_item, signature, push)); } } - let mut index = -1; - let dispatch_arms: Vec<_> = dispatch_table.iter() - .map(|dispatch| { index = index + 1; implement_dispatch_arm(cx, builder, index as u32, dispatch) }).collect(); + + let dispatch_arms = implement_dispatch_arms(cx, builder, &dispatch_table, false); + let dispatch_arms_buffered = implement_dispatch_arms(cx, builder, &dispatch_table, true); Ok((quote_item!(cx, impl $impl_generics ::ipc::IpcInterface<$ty> for $ty $where_clause { @@ -532,11 +563,10 @@ fn implement_interface( } } - fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec - where R: ::std::io::Read + fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec { match method_num { - $dispatch_arms + $dispatch_arms_buffered _ => vec![] } } diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index d1cc58c48..871575750 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -23,13 +23,11 @@ extern crate nanomsg; pub use ipc::*; use std::sync::*; -use std::io::{Write, Read}; use nanomsg::{Socket, Protocol, Error, Endpoint}; pub struct Worker where S: IpcInterface { service: Arc, sockets: Vec<(Socket, Endpoint)>, - method_buf: [u8;2], } #[derive(Debug)] @@ -42,21 +40,26 @@ impl Worker where S: IpcInterface { Worker:: { service: service.clone(), sockets: Vec::new(), - method_buf: [0,0] } } pub fn poll(&mut self) { for item in self.sockets.iter_mut() { let socket = &mut item.0; + let mut buf = Vec::new(); // non-blocking read only ok if there is something to read from socket - match socket.nb_read(&mut self.method_buf) { + match socket.nb_read_to_end(&mut buf) { Ok(method_sign_len) => { - if method_sign_len == 2 { - let result = self.service.dispatch_buf( - self.method_buf[1] as u16 * 256 + self.method_buf[0] as u16, - socket); - if let Err(e) = socket.write(&result) { + if method_sign_len >= 2 { + // method_num + let method_num = buf[1] as u16 * 256 + buf[0] as u16; + // payload + let payload = &buf[2..]; + + // dispatching for ipc interface + let result = self.service.dispatch_buf(method_num, payload); + + if let Err(e) = socket.nb_write(&result) { warn!(target: "ipc", "Failed to write response: {:?}", e); } } @@ -67,7 +70,7 @@ impl Worker where S: IpcInterface { Err(Error::TryAgain) => { }, Err(x) => { - warn!(target: "ipc", "Error polling connection {:?}", x); + warn!(target: "ipc", "Error polling connections {:?}", x); panic!(); } } @@ -97,8 +100,7 @@ mod tests { use ipc::*; use std::io::{Read, Write}; use std::sync::{Arc, RwLock}; - use nanomsg::{Socket, Protocol}; - use std::thread; + use nanomsg::{Socket, Protocol, Endpoint}; struct TestInvoke { method_num: u16, @@ -119,23 +121,22 @@ mod tests { fn dispatch(&self, _r: &mut R) -> Vec where R: Read { vec![] } - fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec where R: Read { - let mut buf = vec![0u8; 4096]; - let size = r.read_to_end(&mut buf).unwrap(); + fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec { self.methods_stack.write().unwrap().push( TestInvoke { method_num: method_num, - params: unsafe { Vec::from_raw_parts(buf.as_mut_ptr(), size, size) } + params: buf.to_vec(), }); vec![] } } - fn dummy_write(addr: &str, buf: &[u8]) { + fn dummy_write(addr: &str, buf: &[u8]) -> (Socket, Endpoint) { let mut socket = Socket::new(Protocol::Pair).unwrap(); let endpoint = socket.connect(addr).unwrap(); - thread::sleep_ms(10); - socket.write_all(buf).unwrap(); + //thread::sleep_ms(10); + socket.write(buf).unwrap(); + (socket, endpoint) } #[test] @@ -167,9 +168,28 @@ mod tests { let mut worker = Worker::::new(Arc::new(DummyService::new())); worker.add_duplex(url).unwrap(); - dummy_write(url, &vec![0, 0, 7, 7, 6, 6]); - worker.poll(); + let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]); + for _ in 0..1000 { worker.poll(); } assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); + assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num); + assert_eq!([7, 7, 6, 6], worker.service.methods_stack.read().unwrap()[0].params[..]); + } + + #[test] + fn worker_can_poll_long() { + let url = "ipc:///tmp/parity-test30.ipc"; + + let mut worker = Worker::::new(Arc::new(DummyService::new())); + worker.add_duplex(url).unwrap(); + + let message = [0u8; 1024*1024]; + + let (_socket, _endpoint) = dummy_write(url, &message); + for _ in 0..10000 { worker.poll(); } + + assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); + assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num); + assert_eq!(vec![0u8; 1024*1024-2], worker.service.methods_stack.read().unwrap()[0].params); } } diff --git a/ipc/rpc/src/interface.rs b/ipc/rpc/src/interface.rs index a55133191..95a360cad 100644 --- a/ipc/rpc/src/interface.rs +++ b/ipc/rpc/src/interface.rs @@ -26,7 +26,7 @@ pub trait IpcInterface { /// deserialize the payload from the io `r` and invokes method specified by `method_num` /// (for non-blocking io) - fn dispatch_buf(&self, method_num: u16, r: &mut R) -> Vec where R: Read; + fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec; } /// serializes method invocation (method_num and parameters) to the stream specified by `w` From 201d47a4835b2a47297109c952a2c40ef9a53a03 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 5 Apr 2016 12:11:05 +0300 Subject: [PATCH 13/52] fixing url --- ipc/nano/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 871575750..c520d8dc5 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -178,7 +178,7 @@ mod tests { #[test] fn worker_can_poll_long() { - let url = "ipc:///tmp/parity-test30.ipc"; + let url = "ipc:///tmp/parity-test40.ipc"; let mut worker = Worker::::new(Arc::new(DummyService::new())); worker.add_duplex(url).unwrap(); From 6d425bb5bb8a6dc81949ccad51cefe08a8788e97 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 5 Apr 2016 12:35:45 +0300 Subject: [PATCH 14/52] fix doc --- ipc/rpc/src/interface.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipc/rpc/src/interface.rs b/ipc/rpc/src/interface.rs index 95a360cad..7ed8b60c4 100644 --- a/ipc/rpc/src/interface.rs +++ b/ipc/rpc/src/interface.rs @@ -21,10 +21,10 @@ use std::marker::Sync; use std::sync::atomic::*; pub trait IpcInterface { - /// reads the message from io, dispatches the call and returns result + /// reads the message from io, dispatches the call and returns serialized result fn dispatch(&self, r: &mut R) -> Vec where R: Read; - /// deserialize the payload from the io `r` and invokes method specified by `method_num` + /// deserialize the payload from buffer, dispatches invoke and returns serialized result /// (for non-blocking io) fn dispatch_buf(&self, method_num: u16, buf: &[u8]) -> Vec; } From 47cfab2bbf2ec8c9f019935efa361c6809993a9f Mon Sep 17 00:00:00 2001 From: NikVolf Date: Tue, 5 Apr 2016 12:37:05 +0300 Subject: [PATCH 15/52] loop size --- ipc/nano/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index c520d8dc5..369fc444c 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -169,7 +169,7 @@ mod tests { worker.add_duplex(url).unwrap(); let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]); - for _ in 0..1000 { worker.poll(); } + for _ in 0..100 { worker.poll(); } assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num); @@ -186,7 +186,7 @@ mod tests { let message = [0u8; 1024*1024]; let (_socket, _endpoint) = dummy_write(url, &message); - for _ in 0..10000 { worker.poll(); } + for _ in 0..1000 { worker.poll(); } assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num); From aea185471a1afd4e8183d285493af70ceb7b7765 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 6 Apr 2016 00:10:24 +0300 Subject: [PATCH 16/52] using nanomsg polling --- ipc/nano/src/lib.rs | 73 ++++++++++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 27 deletions(-) diff --git a/ipc/nano/src/lib.rs b/ipc/nano/src/lib.rs index 369fc444c..6a0a3d4bf 100644 --- a/ipc/nano/src/lib.rs +++ b/ipc/nano/src/lib.rs @@ -23,11 +23,15 @@ extern crate nanomsg; pub use ipc::*; use std::sync::*; -use nanomsg::{Socket, Protocol, Error, Endpoint}; +use nanomsg::{Socket, Protocol, Error, Endpoint, PollRequest, PollFd, PollInOut}; + +const POLL_TIMEOUT: isize = 100; pub struct Worker where S: IpcInterface { service: Arc, sockets: Vec<(Socket, Endpoint)>, + polls: Vec, + buf: Vec, } #[derive(Debug)] @@ -40,43 +44,55 @@ impl Worker where S: IpcInterface { Worker:: { service: service.clone(), sockets: Vec::new(), + polls: Vec::new(), + buf: Vec::new(), } } pub fn poll(&mut self) { - for item in self.sockets.iter_mut() { - let socket = &mut item.0; - let mut buf = Vec::new(); - // non-blocking read only ok if there is something to read from socket - match socket.nb_read_to_end(&mut buf) { - Ok(method_sign_len) => { - if method_sign_len >= 2 { - // method_num - let method_num = buf[1] as u16 * 256 + buf[0] as u16; - // payload - let payload = &buf[2..]; + let mut request = PollRequest::new(&mut self.polls[..]); + let _result_guard = Socket::poll(&mut request, POLL_TIMEOUT); - // dispatching for ipc interface - let result = self.service.dispatch_buf(method_num, payload); + for (fd_index, fd) in request.get_fds().iter().enumerate() { + if fd.can_read() { + let (ref mut socket, _) = self.sockets[fd_index]; + unsafe { self.buf.set_len(0); } + match socket.nb_read_to_end(&mut self.buf) { + Ok(method_sign_len) => { + if method_sign_len >= 2 { + // method_num + let method_num = self.buf[1] as u16 * 256 + self.buf[0] as u16; + // payload + let payload = &self.buf[2..]; - if let Err(e) = socket.nb_write(&result) { - warn!(target: "ipc", "Failed to write response: {:?}", e); + // dispatching for ipc interface + let result = self.service.dispatch_buf(method_num, payload); + + if let Err(e) = socket.nb_write(&result) { + warn!(target: "ipc", "Failed to write response: {:?}", e); + } } + else { + warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len); + } + }, + Err(Error::TryAgain) => { + }, + Err(x) => { + warn!(target: "ipc", "Error polling connections {:?}", x); + panic!(); } - else { - warn!(target: "ipc", "Failed to read method signature from socket: unexpected message length({})", method_sign_len); - } - }, - Err(Error::TryAgain) => { - }, - Err(x) => { - warn!(target: "ipc", "Error polling connections {:?}", x); - panic!(); } } } } + fn rebuild_poll_request(&mut self) { + self.polls = self.sockets.iter() + .map(|&(ref socket, _)| socket.new_pollfd(PollInOut::In)) + .collect::>(); + } + pub fn add_duplex(&mut self, addr: &str) -> Result<(), SocketError> { let mut socket = try!(Socket::new(Protocol::Pair).map_err(|e| { warn!(target: "ipc", "Failed to create ipc socket: {:?}", e); @@ -89,6 +105,9 @@ impl Worker where S: IpcInterface { })); self.sockets.push((socket, endpoint)); + + self.rebuild_poll_request(); + Ok(()) } } @@ -169,7 +188,7 @@ mod tests { worker.add_duplex(url).unwrap(); let (_socket, _endpoint) = dummy_write(url, &vec![0, 0, 7, 7, 6, 6]); - for _ in 0..100 { worker.poll(); } + worker.poll(); assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num); @@ -186,7 +205,7 @@ mod tests { let message = [0u8; 1024*1024]; let (_socket, _endpoint) = dummy_write(url, &message); - for _ in 0..1000 { worker.poll(); } + worker.poll(); assert_eq!(1, worker.service.methods_stack.read().unwrap().len()); assert_eq!(0, worker.service.methods_stack.read().unwrap()[0].method_num); From e8fa429438018c4d3ac9f10b449362c684adaf10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 09:53:56 +0200 Subject: [PATCH 17/52] Bumping clippy --- Cargo.lock | 20 +++++++++++++------- Cargo.toml | 2 +- ethcore/Cargo.toml | 2 +- json/Cargo.toml | 2 +- miner/Cargo.toml | 2 +- rpc/Cargo.toml | 2 +- sync/Cargo.toml | 2 +- util/Cargo.toml | 2 +- 8 files changed, 20 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b24bc9219..471f35067 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,7 +2,7 @@ name = "parity" version = "1.1.0" dependencies = [ - "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "ctrlc 1.1.1 (git+https://github.com/tomusdrw/rust-ctrlc.git)", "daemonize 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 0.6.78 (registry+https://github.com/rust-lang/crates.io-index)", @@ -97,9 +97,10 @@ dependencies = [ [[package]] name = "clippy" -version = "0.0.54" +version = "0.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "quine-mc_cluskey 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "semver 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "toml 0.1.28 (registry+https://github.com/rust-lang/crates.io-index)", @@ -211,7 +212,7 @@ dependencies = [ name = "ethcore" version = "1.1.0" dependencies = [ - "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.1.0", @@ -238,7 +239,7 @@ dependencies = [ name = "ethcore-rpc" version = "1.1.0" dependencies = [ - "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "ethash 1.1.0", "ethcore 1.1.0", "ethcore-util 1.1.0", @@ -262,7 +263,7 @@ dependencies = [ "arrayvec 0.3.16 (registry+https://github.com/rust-lang/crates.io-index)", "bigint 0.1.0", "chrono 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", - "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", "elastic-array 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", @@ -306,7 +307,7 @@ dependencies = [ name = "ethminer" version = "1.1.0" dependencies = [ - "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.1.0", "ethcore-util 1.1.0", @@ -320,7 +321,7 @@ dependencies = [ name = "ethsync" version = "1.1.0" dependencies = [ - "clippy 0.0.54 (registry+https://github.com/rust-lang/crates.io-index)", + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", "ethcore 1.1.0", "ethcore-util 1.1.0", @@ -695,6 +696,11 @@ dependencies = [ "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quine-mc_cluskey" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "rand" version = "0.3.14" diff --git a/Cargo.toml b/Cargo.toml index e18aab30c..f38fe5b10 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ daemonize = "0.2" num_cpus = "0.2" number_prefix = "0.2" rpassword = "0.1" -clippy = { version = "0.0.54", optional = true } +clippy = { version = "0.0.61", optional = true} ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/Cargo.toml b/ethcore/Cargo.toml index 5b613fdb2..6a158bb86 100644 --- a/ethcore/Cargo.toml +++ b/ethcore/Cargo.toml @@ -17,7 +17,7 @@ ethcore-util = { path = "../util" } evmjit = { path = "../evmjit", optional = true } ethash = { path = "../ethash" } num_cpus = "0.2" -clippy = { version = "0.0.54", optional = true } +clippy = { version = "0.0.61", optional = true} crossbeam = "0.1.5" lazy_static = "0.1" ethcore-devtools = { path = "../devtools" } diff --git a/json/Cargo.toml b/json/Cargo.toml index 7887f2cea..871c83272 100644 --- a/json/Cargo.toml +++ b/json/Cargo.toml @@ -10,7 +10,7 @@ rustc-serialize = "0.3" serde = "0.7.0" serde_json = "0.7.0" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.54", optional = true } +clippy = { version = "0.0.61", optional = true} [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/miner/Cargo.toml b/miner/Cargo.toml index 2d5bf8e61..18bf78104 100644 --- a/miner/Cargo.toml +++ b/miner/Cargo.toml @@ -17,7 +17,7 @@ log = "0.3" env_logger = "0.3" rustc-serialize = "0.3" rayon = "0.3.1" -clippy = { version = "0.0.54", optional = true } +clippy = { version = "0.0.61", optional = true} [features] default = [] diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c28f598fd..17ddf3702 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -22,7 +22,7 @@ ethminer = { path = "../miner" } rustc-serialize = "0.3" transient-hashmap = "0.1" serde_macros = { version = "0.7.0", optional = true } -clippy = { version = "0.0.54", optional = true } +clippy = { version = "0.0.61", optional = true} [build-dependencies] serde_codegen = { version = "0.7.0", optional = true } diff --git a/sync/Cargo.toml b/sync/Cargo.toml index 91732fea8..842924ba0 100644 --- a/sync/Cargo.toml +++ b/sync/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore Date: Wed, 6 Apr 2016 10:07:24 +0200 Subject: [PATCH 18/52] Fixing warnings --- ethcore/src/block.rs | 14 ++++++++------ ethcore/src/block_queue.rs | 4 ++-- ethcore/src/blockchain/blockchain.rs | 2 ++ ethcore/src/chainfilter/indexer.rs | 3 ++- ethcore/src/chainfilter/tests.rs | 2 +- ethcore/src/evm/evm.rs | 6 +++--- ethcore/src/verification/verification.rs | 5 +++-- miner/src/miner.rs | 5 +++-- miner/src/transaction_queue.rs | 6 +++--- parity/main.rs | 8 +++----- parity/price_info.rs | 4 ++-- sync/src/chain.rs | 14 +++++++------- util/src/crypto.rs | 4 ++++ util/src/hash.rs | 12 ++++++------ util/src/journaldb/archivedb.rs | 9 +++++---- util/src/journaldb/earlymergedb.rs | 9 +++++---- util/src/journaldb/mod.rs | 6 +++--- util/src/journaldb/overlayrecentdb.rs | 9 +++++---- util/src/journaldb/refcounteddb.rs | 9 +++++---- util/src/journaldb/traits.rs | 4 ++-- util/src/keys/directory.rs | 6 +++--- util/src/kvdb.rs | 2 +- util/src/memorydb.rs | 4 ++-- util/src/network/connection.rs | 4 ++-- util/src/network/handshake.rs | 22 +++++++++++----------- util/src/overlaydb.rs | 4 ++-- util/src/rlp/bytes.rs | 4 ++-- util/src/trie/sectriedb.rs | 10 +++++----- util/src/trie/sectriedbmut.rs | 6 +++--- 29 files changed, 105 insertions(+), 92 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 6d5b9f25f..c5e1ca003 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -154,7 +154,7 @@ impl ExecutedBlock { } } -/// Trait for a object that is_a `ExecutedBlock`. +/// Trait for a object that is a `ExecutedBlock`. pub trait IsBlock { /// Get the block associated with this object. fn block(&self) -> &ExecutedBlock; @@ -192,7 +192,7 @@ pub struct OpenBlock<'x> { last_hashes: LastHashes, } -/// Just like OpenBlock, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, +/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields, /// and collected the uncles. /// /// There is no function available to push a transaction. @@ -204,7 +204,7 @@ pub struct ClosedBlock { unclosed_state: State, } -/// Just like ClosedBlock except that we can't reopen it and it's faster. +/// Just like `ClosedBlock` except that we can't reopen it and it's faster. /// /// We actually store the post-`Engine::on_close_block` state, unlike in `ClosedBlock` where it's the pre. #[derive(Clone)] @@ -216,14 +216,15 @@ pub struct LockedBlock { /// A block that has a valid seal. /// -/// The block's header has valid seal arguments. The block cannot be reversed into a ClosedBlock or OpenBlock. +/// The block's header has valid seal arguments. The block cannot be reversed into a `ClosedBlock` or `OpenBlock`. pub struct SealedBlock { block: ExecutedBlock, uncle_bytes: Bytes, } impl<'x> OpenBlock<'x> { - /// Create a new OpenBlock ready for transaction pushing. + #[cfg_attr(feature="dev", allow(too_many_arguments))] + /// Create a new `OpenBlock` ready for transaction pushing. pub fn new(engine: &'x Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes, author: Address, gas_floor_target: U256, extra_data: Bytes) -> Self { let mut r = OpenBlock { block: ExecutedBlock::new(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()), tracing), @@ -319,7 +320,7 @@ impl<'x> OpenBlock<'x> { } } - /// Turn this into a `ClosedBlock`. A BlockChain must be provided in order to figure out the uncles. + /// Turn this into a `ClosedBlock`. A `BlockChain` must be provided in order to figure out the uncles. pub fn close(self) -> ClosedBlock { let mut s = self; @@ -454,6 +455,7 @@ impl IsBlock for SealedBlock { } /// Enact the block given by block header, transactions and uncles +#[cfg_attr(feature="dev", allow(too_many_arguments))] pub fn enact(header: &Header, transactions: &[SignedTransaction], uncles: &[Header], engine: &Engine, tracing: bool, db: Box, parent: &Header, last_hashes: LastHashes) -> Result { { if ::log::max_log_level() >= ::log::LogLevel::Trace { diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 042df1dc1..4a52d6a6b 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! A queue of blocks. Sits between network or other I/O and the BlockChain. +//! A queue of blocks. Sits between network or other I/O and the `BlockChain`. //! Sorts them ready for blockchain insertion. use std::thread::{JoinHandle, self}; use std::sync::atomic::{AtomicBool, Ordering as AtomicOrdering}; @@ -89,7 +89,7 @@ impl BlockQueueInfo { } } -/// A queue of blocks. Sits between network or other I/O and the BlockChain. +/// A queue of blocks. Sits between network or other I/O and the `BlockChain`. /// Sorts them ready for blockchain insertion. pub struct BlockQueue { panic_handler: Arc, diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 43920708b..ebbae306e 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -427,6 +427,7 @@ impl BlockChain { } } + #[cfg_attr(feature="dev", allow(similar_names))] /// Inserts the block into backing cache database. /// Expects the block to be valid and already verified. /// If the block is already known, does nothing. @@ -855,6 +856,7 @@ impl BlockChain { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(similar_names))] use std::str::FromStr; use rustc_serialize::hex::FromHex; use util::hash::*; diff --git a/ethcore/src/chainfilter/indexer.rs b/ethcore/src/chainfilter/indexer.rs index 524fab1a9..a10bb69d2 100644 --- a/ethcore/src/chainfilter/indexer.rs +++ b/ethcore/src/chainfilter/indexer.rs @@ -60,7 +60,7 @@ impl Indexer { } /// Return bloom which are dependencies for given index. - /// + /// /// Bloom indexes are ordered from lowest to highest. pub fn lower_level_bloom_indexes(&self, index: &BloomIndex) -> Vec { // this is the lowest level @@ -87,6 +87,7 @@ impl Indexer { #[cfg(test)] mod tests { + #![cfg_attr(feature="dev", allow(similar_names))] use chainfilter::BloomIndex; use chainfilter::indexer::Indexer; diff --git a/ethcore/src/chainfilter/tests.rs b/ethcore/src/chainfilter/tests.rs index 7dac29f11..560662829 100644 --- a/ethcore/src/chainfilter/tests.rs +++ b/ethcore/src/chainfilter/tests.rs @@ -23,7 +23,7 @@ use chainfilter::{BloomIndex, FilterDataSource, ChainFilter}; /// In memory cache for blooms. /// -/// Stores all blooms in HashMap, which indexes them by `BloomIndex`. +/// Stores all blooms in `HashMap`, which indexes them by `BloomIndex`. pub struct MemoryCache { blooms: HashMap, } diff --git a/ethcore/src/evm/evm.rs b/ethcore/src/evm/evm.rs index c1107f003..b6c2debc5 100644 --- a/ethcore/src/evm/evm.rs +++ b/ethcore/src/evm/evm.rs @@ -44,7 +44,7 @@ pub enum Error { /// Invoked instruction instruction: &'static str, /// How many stack elements was requested by instruction - wanted: usize, + wanted: usize, /// How many elements were on stack on_stack: usize }, @@ -64,8 +64,8 @@ pub enum Error { } /// Evm result. -/// -/// Returns gas_left if execution is successful, otherwise error. +/// +/// Returns `gas_left` if execution is successful, otherwise error. pub type Result = result::Result; /// Evm interface. diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 6e79d737e..bd0ce426f 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -55,7 +55,7 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Still operates on a individual block -/// Returns a PreverifiedBlock structure populated with transactions +/// Returns a `PreverifiedBlock` structure populated with transactions pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { try!(engine.verify_block_unordered(&header, Some(&bytes))); for u in Rlp::new(&bytes).at(2).iter().map(|rlp| rlp.as_val::
()) { @@ -279,7 +279,7 @@ mod tests { impl BlockProvider for TestBlockChain { fn have_tracing(&self) -> bool { false } - + fn is_known(&self, hash: &H256) -> bool { self.blocks.contains_key(hash) } @@ -331,6 +331,7 @@ mod tests { } #[test] + #[cfg_attr(feature="dev", allow(similar_names))] fn test_verify_block() { // Test against morden let mut good = Header::new(); diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 70bf1711a..ec821bf25 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -94,6 +94,7 @@ impl Miner { } /// Prepares new block for sealing including top transactions from queue. + #[cfg_attr(feature="dev", allow(match_same_arms))] fn prepare_sealing(&self, chain: &BlockChainClient) { trace!(target: "miner", "prepare_sealing: entering"); let transactions = self.transaction_queue.lock().unwrap().top_transactions(); @@ -164,7 +165,7 @@ impl Miner { } ); if let Some(block) = b { - if sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash() != block.block().fields().header.hash()).unwrap_or(true) { + if sealing_work.peek_last_ref().map_or(true, |pb| pb.block().fields().header.hash() != block.block().fields().header.hash()) { trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash()); sealing_work.push(block); } @@ -200,7 +201,7 @@ impl MinerService for Miner { fn sensible_gas_price(&self) -> U256 { // 10% above our minimum. - self.transaction_queue.lock().unwrap().minimal_gas_price().clone() * x!(110) / x!(100) + *self.transaction_queue.lock().unwrap().minimal_gas_price() * x!(110) / x!(100) } fn author(&self) -> Address { diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 659e1a663..46188e1d1 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -18,7 +18,7 @@ //! Transaction Queue //! -//! TransactionQueue keeps track of all transactions seen by the node (received from other peers) and own transactions +//! `TransactionQueue` keeps track of all transactions seen by the node (received from other peers) and own transactions //! and orders them by priority. Top priority transactions are those with low nonce height (difference between //! transaction's nonce and next nonce expected from this sender). If nonces are equal transaction's gas price is used //! for comparison (higher gas price = higher priority). @@ -179,7 +179,7 @@ impl VerifiedTransaction { /// Holds transactions accessible by (address, nonce) and by priority /// -/// TransactionSet keeps number of entries below limit, but it doesn't +/// `TransactionSet` keeps number of entries below limit, but it doesn't /// automatically happen during `insert/remove` operations. /// You have to call `enforce_limit` to remove lowest priority transactions from set. struct TransactionSet { @@ -262,7 +262,7 @@ pub struct AccountDetails { /// Transactions with `gas > (gas_limit + gas_limit * Factor(in percents))` are not imported to the queue. const GAS_LIMIT_HYSTERESIS: usize = 10; // % -/// TransactionQueue implementation +/// `TransactionQueue` implementation pub struct TransactionQueue { /// Gas Price threshold for transactions that can be imported to this queue (defaults to 0) minimal_gas_price: U256, diff --git a/parity/main.rs b/parity/main.rs index c5e0dce54..f701ff97b 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -19,6 +19,7 @@ #![warn(missing_docs)] #![cfg_attr(feature="dev", feature(plugin))] #![cfg_attr(feature="dev", plugin(clippy))] +#![cfg_attr(feature="dev", allow(useless_format))] extern crate docopt; extern crate num_cpus; extern crate rustc_serialize; @@ -361,9 +362,9 @@ impl Configuration { die!("{}: Invalid basic transaction price given in USD. Must be a decimal number.", self.args.flag_usd_per_tx) }); let usd_per_eth = match self.args.flag_usd_per_eth.as_str() { - "etherscan" => price_info::PriceInfo::get().map(|x| x.ethusd).unwrap_or_else(|| { + "etherscan" => price_info::PriceInfo::get().map_or_else(|| { die!("Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth.") - }), + }, |x| x.ethusd), x => FromStr::from_str(x).unwrap_or_else(|_| die!("{}: Invalid ether price given in USD. Must be a decimal number.", x)) }; let wei_per_usd: f32 = 1.0e18 / usd_per_eth; @@ -421,7 +422,6 @@ impl Configuration { } } - #[cfg_attr(feature="dev", allow(useless_format))] fn net_addresses(&self) -> (Option, Option) { let listen_address = Some(SocketAddr::new(IpAddr::from_str("0.0.0.0").unwrap(), self.args.flag_port)); let public_address = if self.args.flag_nat.starts_with("extip:") { @@ -450,7 +450,6 @@ impl Configuration { ret } - #[cfg_attr(feature="dev", allow(useless_format))] fn client_config(&self) -> ClientConfig { let mut client_config = ClientConfig::default(); match self.args.flag_cache { @@ -551,7 +550,6 @@ impl Configuration { account_service } - #[cfg_attr(feature="dev", allow(useless_format))] fn execute_client(&self) { // Setup panic handler let panic_handler = PanicHandler::new_in_arc(); diff --git a/parity/price_info.rs b/parity/price_info.rs index 29e7505ee..405424b3d 100644 --- a/parity/price_info.rs +++ b/parity/price_info.rs @@ -19,8 +19,8 @@ impl PriceInfo { .and_then(|mut s| s.read_to_string(&mut body).ok()) .and_then(|_| Json::from_str(&body).ok()) .and_then(|json| json.find_path(&["result", "ethusd"]) - .and_then(|obj| match obj { - &Json::String(ref s) => Some(PriceInfo { + .and_then(|obj| match *obj { + Json::String(ref s) => Some(PriceInfo { ethusd: FromStr::from_str(&s).unwrap() }), _ => None diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 16bc41b70..1a7d11f51 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -15,7 +15,7 @@ // along with Parity. If not, see . /// -/// BlockChain synchronization strategy. +/// `BlockChain` synchronization strategy. /// Syncs to peers and keeps up to date. /// This implementation uses ethereum protocol v63 /// @@ -127,7 +127,7 @@ pub struct SyncStatus { pub protocol_version: u8, /// The underlying p2p network version. pub network_id: U256, - /// BlockChain height for the moment the sync started. + /// `BlockChain` height for the moment the sync started. pub start_block_number: BlockNumber, /// Last fully downloaded and imported block number (if any). pub last_imported_block_number: Option, @@ -1292,12 +1292,12 @@ impl ChainSync { fn propagate_new_transactions(&mut self, io: &mut SyncIo) -> usize { // Early out of nobody to send to. - if self.peers.len() == 0 { + if self.peers.is_empty() { return 0; } let mut packet = RlpStream::new_list(self.transactions_to_send.len()); - for tx in self.transactions_to_send.iter() { + for tx in &self.transactions_to_send { packet.append_raw(tx, 1); } self.transactions_to_send.clear(); @@ -1312,7 +1312,7 @@ impl ChainSync { .collect::>(); // taking at max of MAX_PEERS_PROPAGATION - lucky_peers.iter().map(|&id| id.clone()).take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::>() + lucky_peers.iter().cloned().take(min(lucky_peers.len(), MAX_PEERS_PROPAGATION)).collect::>() }; let sent = lucky_peers.len(); @@ -1701,8 +1701,8 @@ mod tests { let retracted_blocks = vec![client.block_hash_delta_minus(1)]; // Add some balance to clients - for h in vec![good_blocks[0], retracted_blocks[0]] { - let block = client.block(BlockId::Hash(h)).unwrap(); + for h in &[good_blocks[0], retracted_blocks[0]] { + let block = client.block(BlockId::Hash(*h)).unwrap(); let view = BlockView::new(&block); client.set_balance(view.transactions()[0].sender().unwrap(), U256::from(1_000_000_000)); } diff --git a/util/src/crypto.rs b/util/src/crypto.rs index e9b3116fd..040db3bca 100644 --- a/util/src/crypto.rs +++ b/util/src/crypto.rs @@ -157,6 +157,7 @@ impl KeyPair { } /// EC functions +#[cfg_attr(feature="dev", allow(similar_names))] pub mod ec { use numbers::*; use standard::*; @@ -193,6 +194,7 @@ pub mod ec { } Ok(signature) } + /// Verify signature. pub fn verify(public: &Public, signature: &Signature, message: &H256) -> Result { use secp256k1::*; @@ -233,6 +235,7 @@ pub mod ec { } /// ECDH functions +#[cfg_attr(feature="dev", allow(similar_names))] pub mod ecdh { use crypto::*; use crypto::{self}; @@ -254,6 +257,7 @@ pub mod ecdh { } /// ECIES function +#[cfg_attr(feature="dev", allow(similar_names))] pub mod ecies { use hash::*; use bytes::*; diff --git a/util/src/hash.rs b/util/src/hash.rs index b7fddbe8b..1b894d82f 100644 --- a/util/src/hash.rs +++ b/util/src/hash.rs @@ -392,7 +392,7 @@ macro_rules! impl_hash { } } - /// BitOr on references + /// `BitOr` on references impl<'a> BitOr for &'a $from { type Output = $from; @@ -408,7 +408,7 @@ macro_rules! impl_hash { } } - /// Moving BitOr + /// Moving `BitOr` impl BitOr for $from { type Output = $from; @@ -417,7 +417,7 @@ macro_rules! impl_hash { } } - /// BitAnd on references + /// `BitAnd` on references impl <'a> BitAnd for &'a $from { type Output = $from; @@ -433,7 +433,7 @@ macro_rules! impl_hash { } } - /// Moving BitAnd + /// Moving `BitAnd` impl BitAnd for $from { type Output = $from; @@ -442,7 +442,7 @@ macro_rules! impl_hash { } } - /// BitXor on references + /// `BitXor` on references impl <'a> BitXor for &'a $from { type Output = $from; @@ -458,7 +458,7 @@ macro_rules! impl_hash { } } - /// Moving BitXor + /// Moving `BitXor` impl BitXor for $from { type Output = $from; diff --git a/util/src/journaldb/archivedb.rs b/util/src/journaldb/archivedb.rs index 9a0ac5e43..380e8e423 100644 --- a/util/src/journaldb/archivedb.rs +++ b/util/src/journaldb/archivedb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Disk-backed HashDB implementation. +//! Disk-backed `HashDB` implementation. use common::*; use rlp::*; @@ -25,11 +25,11 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; -/// Implementation of the HashDB trait for a disk-backed database with a memory overlay +/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to -/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect +/// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to +/// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. pub struct ArchiveDB { @@ -176,6 +176,7 @@ impl JournalDB for ArchiveDB { #[cfg(test)] mod tests { #![cfg_attr(feature="dev", allow(blacklisted_name))] + #![cfg_attr(feature="dev", allow(similar_names))] use common::*; use super::*; diff --git a/util/src/journaldb/earlymergedb.rs b/util/src/journaldb/earlymergedb.rs index 6279d6f40..eada4bbaa 100644 --- a/util/src/journaldb/earlymergedb.rs +++ b/util/src/journaldb/earlymergedb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Disk-backed HashDB implementation. +//! Disk-backed `HashDB` implementation. use common::*; use rlp::*; @@ -53,11 +53,11 @@ enum RemoveFrom { Archive, } -/// Implementation of the HashDB trait for a disk-backed database with a memory overlay +/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to -/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect +/// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to +/// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. pub struct EarlyMergeDB { @@ -528,6 +528,7 @@ impl JournalDB for EarlyMergeDB { #[cfg(test)] mod tests { #![cfg_attr(feature="dev", allow(blacklisted_name))] + #![cfg_attr(feature="dev", allow(similar_names))] use common::*; use super::*; diff --git a/util/src/journaldb/mod.rs b/util/src/journaldb/mod.rs index e73c12969..f65aebde1 100644 --- a/util/src/journaldb/mod.rs +++ b/util/src/journaldb/mod.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! JournalDB interface and implementation. +//! `JournalDB` interface and implementation. use common::*; @@ -25,7 +25,7 @@ mod earlymergedb; mod overlayrecentdb; mod refcounteddb; -/// Export the JournalDB trait. +/// Export the `JournalDB` trait. pub use self::traits::JournalDB; /// A journal database algorithm. @@ -70,7 +70,7 @@ impl fmt::Display for Algorithm { } } -/// Create a new JournalDB trait object. +/// Create a new `JournalDB` trait object. pub fn new(path: &str, algorithm: Algorithm) -> Box { match algorithm { Algorithm::Archive => Box::new(archivedb::ArchiveDB::new(path)), diff --git a/util/src/journaldb/overlayrecentdb.rs b/util/src/journaldb/overlayrecentdb.rs index 31b68f802..0b9ad4fda 100644 --- a/util/src/journaldb/overlayrecentdb.rs +++ b/util/src/journaldb/overlayrecentdb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! JournalDB over in-memory overlay +//! `JournalDB` over in-memory overlay use common::*; use rlp::*; @@ -25,11 +25,11 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; use std::env; use super::JournalDB; -/// Implementation of the JournalDB trait for a disk-backed database with a memory overlay +/// Implementation of the `JournalDB` trait for a disk-backed database with a memory overlay /// and, possibly, latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to -/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect +/// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to +/// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. /// @@ -359,6 +359,7 @@ impl HashDB for OverlayRecentDB { #[cfg(test)] mod tests { #![cfg_attr(feature="dev", allow(blacklisted_name))] + #![cfg_attr(feature="dev", allow(similar_names))] use common::*; use super::*; diff --git a/util/src/journaldb/refcounteddb.rs b/util/src/journaldb/refcounteddb.rs index 20e1efb3f..e69eccab7 100644 --- a/util/src/journaldb/refcounteddb.rs +++ b/util/src/journaldb/refcounteddb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Disk-backed, ref-counted JournalDB implementation. +//! Disk-backed, ref-counted `JournalDB` implementation. use common::*; use rlp::*; @@ -25,11 +25,11 @@ use kvdb::{Database, DBTransaction, DatabaseConfig}; #[cfg(test)] use std::env; -/// Implementation of the HashDB trait for a disk-backed database with a memory overlay +/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay /// and latent-removal semantics. /// -/// Like OverlayDB, there is a memory overlay; `commit()` must be called in order to -/// write operations out to disk. Unlike OverlayDB, `remove()` operations do not take effect +/// Like `OverlayDB`, there is a memory overlay; `commit()` must be called in order to +/// write operations out to disk. Unlike `OverlayDB`, `remove()` operations do not take effect /// immediately. Rather some age (based on a linear but arbitrary metric) must pass before /// the removals actually take effect. pub struct RefCountedDB { @@ -195,6 +195,7 @@ impl JournalDB for RefCountedDB { #[cfg(test)] mod tests { #![cfg_attr(feature="dev", allow(blacklisted_name))] + #![cfg_attr(feature="dev", allow(similar_names))] use common::*; use super::*; diff --git a/util/src/journaldb/traits.rs b/util/src/journaldb/traits.rs index afc6ab89a..b1ba27957 100644 --- a/util/src/journaldb/traits.rs +++ b/util/src/journaldb/traits.rs @@ -14,12 +14,12 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Disk-backed HashDB implementation. +//! Disk-backed `HashDB` implementation. use common::*; use hashdb::*; -/// A HashDB which can manage a short-term journal potentially containing many forks of mutually +/// A `HashDB` which can manage a short-term journal potentially containing many forks of mutually /// exclusive actions. pub trait JournalDB : HashDB + Send + Sync { /// Return a copy of ourself, in a box. diff --git a/util/src/keys/directory.rs b/util/src/keys/directory.rs index a92bf4593..082a7f427 100644 --- a/util/src/keys/directory.rs +++ b/util/src/keys/directory.rs @@ -326,7 +326,7 @@ fn uuid_from_string(s: &str) -> Result { #[derive(Clone)] -/// Stored key file struct with encrypted message (cipher_text) +/// Stored key file struct with encrypted message (`cipher_text`) /// also contains password derivation function settings (PBKDF2/Scrypt) pub struct KeyFileContent { version: KeyFileVersion, @@ -369,9 +369,9 @@ enum KeyFileParseError { } impl KeyFileContent { - /// New stored key file struct with encrypted message (cipher_text) + /// New stored key file struct with encrypted message (`cipher_text`) /// also contains password derivation function settings (PBKDF2/Scrypt) - /// to decrypt cipher_text given the password is provided. + /// to decrypt `cipher_text` given the password is provided. pub fn new(crypto: KeyFileCrypto) -> KeyFileContent { KeyFileContent { id: new_uuid(), diff --git a/util/src/kvdb.rs b/util/src/kvdb.rs index df5c2c448..9de71bd35 100644 --- a/util/src/kvdb.rs +++ b/util/src/kvdb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Key-Value store abstraction with RocksDB backend. +//! Key-Value store abstraction with `RocksDB` backend. use std::default::Default; use rocksdb::{DB, Writable, WriteBatch, IteratorMode, DBVector, DBIterator, diff --git a/util/src/memorydb.rs b/util/src/memorydb.rs index 0d4f8b2c9..cfd7237e6 100644 --- a/util/src/memorydb.rs +++ b/util/src/memorydb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Reference-counted memory-based HashDB implementation. +//! Reference-counted memory-based `HashDB` implementation. use hash::*; use bytes::*; @@ -27,7 +27,7 @@ use std::collections::HashMap; use std::default::Default; #[derive(Debug,Clone)] -/// Reference-counted memory-based HashDB implementation. +/// Reference-counted memory-based `HashDB` implementation. /// /// Use `new()` to create a new database. Insert items with `insert()`, remove items /// with `remove()`, check for existence with `containce()` and lookup a hash to derive diff --git a/util/src/network/connection.rs b/util/src/network/connection.rs index 02c0e2cde..a3a42b44e 100644 --- a/util/src/network/connection.rs +++ b/util/src/network/connection.rs @@ -223,7 +223,7 @@ pub enum WriteStatus { Complete } -/// RLPx packet +/// `RLPx` packet pub struct Packet { pub protocol: u16, pub data: Bytes, @@ -237,7 +237,7 @@ enum EncryptedConnectionState { Payload, } -/// Connection implementing RLPx framing +/// Connection implementing `RLPx` framing /// https://github.com/ethereum/devp2p/blob/master/rlpx.md#framing pub struct EncryptedConnection { /// Underlying tcp connection diff --git a/util/src/network/handshake.rs b/util/src/network/handshake.rs index a72cc28ad..123531d8d 100644 --- a/util/src/network/handshake.rs +++ b/util/src/network/handshake.rs @@ -48,7 +48,7 @@ enum HandshakeState { StartSession, } -/// RLPx protocol handhake. See https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake +/// `RLPx` protocol handhake. See https://github.com/ethereum/devp2p/blob/master/rlpx.md#encrypted-handshake pub struct Handshake { /// Remote node public key pub id: NodeId, @@ -66,11 +66,11 @@ pub struct Handshake { pub remote_ephemeral: Public, /// Remote connection nonce. pub remote_nonce: H256, - /// Remote RLPx protocol version. + /// Remote `RLPx` protocol version. pub remote_version: u64, - /// A copy of received encryped auth packet + /// A copy of received encryped auth packet pub auth_cipher: Bytes, - /// A copy of received encryped ack packet + /// A copy of received encryped ack packet pub ack_cipher: Bytes, /// This Handshake is marked for deleteion flag pub expired: bool, @@ -413,7 +413,7 @@ mod test { fn test_handshake_auth_plain() { let mut h = create_handshake(None); let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); - let auth = + let auth = "\ 048ca79ad18e4b0659fab4853fe5bc58eb83992980f4c9cc147d2aa31532efd29a3d3dc6a3d89eaf\ 913150cfc777ce0ce4af2758bf4810235f6e6ceccfee1acc6b22c005e9e3a49d6448610a58e98744\ @@ -434,7 +434,7 @@ mod test { fn test_handshake_auth_eip8() { let mut h = create_handshake(None); let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); - let auth = + let auth = "\ 01b304ab7578555167be8154d5cc456f567d5ba302662433674222360f08d5f1534499d3678b513b\ 0fca474f3a514b18e75683032eb63fccb16c156dc6eb2c0b1593f0d84ac74f6e475f1b8d56116b84\ @@ -460,7 +460,7 @@ mod test { fn test_handshake_auth_eip8_2() { let mut h = create_handshake(None); let secret = Secret::from_str("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291").unwrap(); - let auth = + let auth = "\ 01b8044c6c312173685d1edd268aa95e1d495474c6959bcdd10067ba4c9013df9e40ff45f5bfd6f7\ 2471f93a91b493f8e00abc4b80f682973de715d77ba3a005a242eb859f9a211d93a347fa64b597bf\ @@ -481,7 +481,7 @@ mod test { h.read_auth_eip8(&secret, &auth[super::V4_AUTH_PACKET_SIZE..]).unwrap(); assert_eq!(h.state, super::HandshakeState::StartSession); check_auth(&h, 56); - let ack = h.ack_cipher.clone(); + let ack = h.ack_cipher.clone(); let total = (((ack[0] as u16) << 8 | (ack[1] as u16)) as usize) + 2; assert_eq!(ack.len(), total); } @@ -491,7 +491,7 @@ mod test { let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); let mut h = create_handshake(Some(&remote)); let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); - let ack = + let ack = "\ 049f8abcfa9c0dc65b982e98af921bc0ba6e4243169348a236abe9df5f93aa69d99cadddaa387662\ b0ff2c08e9006d5a11a278b1b3331e5aaabf0a32f01281b6f4ede0e09a2d5f585b26513cb794d963\ @@ -511,7 +511,7 @@ mod test { let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); let mut h = create_handshake(Some(&remote)); let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); - let ack = + let ack = "\ 01ea0451958701280a56482929d3b0757da8f7fbe5286784beead59d95089c217c9b917788989470\ b0e330cc6e4fb383c0340ed85fab836ec9fb8a49672712aeabbdfd1e837c1ff4cace34311cd7f4de\ @@ -540,7 +540,7 @@ mod test { let remote = Public::from_str("fda1cff674c90c9a197539fe3dfb53086ace64f83ed7c6eabec741f7f381cc803e52ab2cd55d5569bce4347107a310dfd5f88a010cd2ffd1005ca406f1842877").unwrap(); let mut h = create_handshake(Some(&remote)); let secret = Secret::from_str("49a7b37aa6f6645917e7b807e9d1c00d4fa71f18343b0d4122a4d2df64dd6fee").unwrap(); - let ack = + let ack = "\ 01f004076e58aae772bb101ab1a8e64e01ee96e64857ce82b1113817c6cdd52c09d26f7b90981cd7\ ae835aeac72e1573b8a0225dd56d157a010846d888dac7464baf53f2ad4e3d584531fa203658fab0\ diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index 63a935ca9..ce4e894c8 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -14,7 +14,7 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! Disk-backed HashDB implementation. +//! Disk-backed `HashDB` implementation. use error::*; use hash::*; @@ -28,7 +28,7 @@ use std::env; use std::collections::HashMap; use kvdb::{Database, DBTransaction}; -/// Implementation of the HashDB trait for a disk-backed database with a memory overlay. +/// Implementation of the `HashDB` trait for a disk-backed database with a memory overlay. /// /// The operations `insert()` and `remove()` take place on the memory overlay; batches of /// such operations may be flushed to the disk-backed DB with `commit()` or discarded with diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs index e8bfa57b0..1145ba27e 100644 --- a/util/src/rlp/bytes.rs +++ b/util/src/rlp/bytes.rs @@ -153,7 +153,7 @@ impl ToBytes for T where T: FixedHash { fn to_bytes_len(&self) -> usize { self.bytes().len() } } -/// Error returned when FromBytes conversation goes wrong +/// Error returned when `FromBytes` conversation goes wrong #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { /// Expected more RLP data @@ -174,7 +174,7 @@ impl fmt::Display for FromBytesError { } } -/// Alias for the result of FromBytes trait +/// Alias for the result of `FromBytes` trait pub type FromBytesResult = Result; /// Converts to given type from its bytes representation diff --git a/util/src/trie/sectriedb.rs b/util/src/trie/sectriedb.rs index 9f74e9917..3e74f8655 100644 --- a/util/src/trie/sectriedb.rs +++ b/util/src/trie/sectriedb.rs @@ -22,8 +22,8 @@ use super::triedb::*; use super::trietraits::*; /// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. -/// -/// Use it as a `Trie` trait object. You can use `raw()` to get the backing TrieDB object. +/// +/// Use it as a `Trie` trait object. You can use `raw()` to get the backing `TrieDB` object. pub struct SecTrieDB<'db> { raw: TrieDB<'db> } @@ -32,16 +32,16 @@ impl<'db> SecTrieDB<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db HashDB, root: &'db H256) -> Self { + pub fn new(db: &'db HashDB, root: &'db H256) -> Self { SecTrieDB { raw: TrieDB::new(db, root) } } - /// Get a reference to the underlying raw TrieDB struct. + /// Get a reference to the underlying raw `TrieDB` struct. pub fn raw(&self) -> &TrieDB { &self.raw } - /// Get a mutable reference to the underlying raw TrieDB struct. + /// Get a mutable reference to the underlying raw `TrieDB` struct. pub fn raw_mut(&mut self) -> &TrieDB { &mut self.raw } diff --git a/util/src/trie/sectriedbmut.rs b/util/src/trie/sectriedbmut.rs index 662f6852a..7e17610f8 100644 --- a/util/src/trie/sectriedbmut.rs +++ b/util/src/trie/sectriedbmut.rs @@ -22,8 +22,8 @@ use super::triedbmut::*; use super::trietraits::*; /// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. -/// -/// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing TrieDBMut object. +/// +/// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing `TrieDBMut` object. pub struct SecTrieDBMut<'db> { raw: TrieDBMut<'db> } @@ -32,7 +32,7 @@ impl<'db> SecTrieDBMut<'db> { /// Create a new trie with the backing database `db` and empty `root` /// Initialise to the state entailed by the genesis block. /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { + pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { SecTrieDBMut { raw: TrieDBMut::new(db, root) } } From 1105b74174a711555695e10051540fe48380d3ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 10:58:07 +0200 Subject: [PATCH 19/52] Fixing match on constant --- ethcore/src/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index 6901996bc..87f2a05be 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -138,7 +138,7 @@ impl Account { /// get someone who knows to call `note_code`. pub fn code(&self) -> Option<&[u8]> { match self.code_hash { - Some(SHA3_EMPTY) | None if self.code_cache.is_empty() => Some(&self.code_cache), + Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache), Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache), None => Some(&self.code_cache), _ => None, From d5f9cccf5e4c41f25bdaa1cb9bcdba1f8d28995d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 10:58:51 +0200 Subject: [PATCH 20/52] Removing match on constant --- ethcore/src/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ethcore/src/account.rs b/ethcore/src/account.rs index 6901996bc..87f2a05be 100644 --- a/ethcore/src/account.rs +++ b/ethcore/src/account.rs @@ -138,7 +138,7 @@ impl Account { /// get someone who knows to call `note_code`. pub fn code(&self) -> Option<&[u8]> { match self.code_hash { - Some(SHA3_EMPTY) | None if self.code_cache.is_empty() => Some(&self.code_cache), + Some(c) if c == SHA3_EMPTY && self.code_cache.is_empty() => Some(&self.code_cache), Some(_) if !self.code_cache.is_empty() => Some(&self.code_cache), None => Some(&self.code_cache), _ => None, From d14d590c2bcb3c282ef5615615d56e9e536bec66 Mon Sep 17 00:00:00 2001 From: debris Date: Wed, 6 Apr 2016 12:15:20 +0200 Subject: [PATCH 21/52] fixed #875 and added tests for eth_sendTransaction --- miner/src/lib.rs | 3 ++ miner/src/miner.rs | 4 ++ miner/src/transaction_queue.rs | 30 +++++++++++ rpc/src/v1/impls/eth.rs | 14 ++++-- rpc/src/v1/impls/personal.rs | 2 +- rpc/src/v1/tests/eth.rs | 53 ++++++++++++++++++-- rpc/src/v1/tests/helpers/account_provider.rs | 33 ++++++++---- rpc/src/v1/tests/helpers/miner_service.rs | 51 ++++++++++++++----- rpc/src/v1/tests/personal.rs | 28 ++++++++--- 9 files changed, 181 insertions(+), 37 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 0daac48e6..9f757fb67 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -108,6 +108,9 @@ pub trait MinerService : Send + Sync { /// Query pending transactions for hash fn transaction(&self, hash: &H256) -> Option; + /// Returns highest transaction nonce for given address. + fn last_nonce(&self, address: &Address) -> Option; + /// Suggested gas price fn sensible_gas_price(&self) -> U256 { x!(20000000000u64) } } diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 70bf1711a..aee344925 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -227,6 +227,10 @@ impl MinerService for Miner { queue.find(hash) } + fn last_nonce(&self, address: &Address) -> Option { + self.transaction_queue.lock().unwrap().last_nonce(address) + } + fn update_sealing(&self, chain: &BlockChainClient) { if self.sealing_enabled.load(atomic::Ordering::Relaxed) { let current_no = chain.chain_info().best_block_number; diff --git a/miner/src/transaction_queue.rs b/miner/src/transaction_queue.rs index 659e1a663..8cd9157ee 100644 --- a/miner/src/transaction_queue.rs +++ b/miner/src/transaction_queue.rs @@ -523,6 +523,11 @@ impl TransactionQueue { self.last_nonces.clear(); } + /// Returns highest transaction nonce for given address. + pub fn last_nonce(&self, address: &Address) -> Option { + self.last_nonces.get(address).cloned() + } + /// Checks if there are any transactions in `future` that should actually be promoted to `current` /// (because nonce matches). fn move_matching_future_to_current(&mut self, address: Address, mut current_nonce: U256, first_nonce: U256) { @@ -1255,4 +1260,29 @@ mod test { assert_eq!(stats.future, 0); assert_eq!(stats.pending, 1); } + + #[test] + fn should_return_none_when_transaction_from_given_address_does_not_exist() { + // given + let mut txq = TransactionQueue::new(); + + // then + assert_eq!(txq.last_nonce(&Address::default()), None); + } + + #[test] + fn should_return_correct_nonce_when_transactions_from_given_address_exist() { + // given + let mut txq = TransactionQueue::new(); + let tx = new_tx(); + let from = tx.sender().unwrap(); + let nonce = tx.nonce; + let details = |a: &Address| AccountDetails { nonce: nonce, balance: !U256::zero() }; + + // when + txq.add(tx, &details).unwrap(); + + // then + assert_eq!(txq.last_nonce(&from), Some(nonce)); + } } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index dd241c9ec..1fff89ba8 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -184,11 +184,15 @@ impl EthClient fn dispatch_transaction(&self, signed_transaction: SignedTransaction, raw_transaction: Vec) -> Result { let hash = signed_transaction.hash(); - + let import = { + let miner = take_weak!(self.miner); let client = take_weak!(self.client); take_weak!(self.miner).import_transactions(vec![signed_transaction], |a: &Address| AccountDetails { - nonce: client.nonce(a), + nonce: miner + .last_nonce(a) + .map(|nonce| nonce + U256::one()) + .unwrap_or_else(|| client.nonce(a)), balance: client.balance(a), }) }; @@ -484,7 +488,11 @@ impl Eth for EthClient let client = take_weak!(self.client); let miner = take_weak!(self.miner); EthTransaction { - nonce: request.nonce.unwrap_or_else(|| client.nonce(&request.from)), + nonce: request.nonce + .or_else(|| miner + .last_nonce(&request.from) + .map(|nonce| nonce + U256::one())) + .unwrap_or_else(|| client.nonce(&request.from)), action: request.to.map_or(Action::Create, Action::Call), gas: request.gas.unwrap_or_else(default_gas), gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()), diff --git a/rpc/src/v1/impls/personal.rs b/rpc/src/v1/impls/personal.rs index 2822059d6..5bb0d3eee 100644 --- a/rpc/src/v1/impls/personal.rs +++ b/rpc/src/v1/impls/personal.rs @@ -49,7 +49,7 @@ impl Personal for PersonalClient where A: AccountProvider + 'static { |(pass, )| { let store = take_weak!(self.accounts); match store.new_account(&pass) { - Ok(address) => Ok(Value::String(format!("0x{:?}", address))), + Ok(address) => to_value(&address), Err(_) => Err(Error::internal_error()) } } diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 40748d990..bde351486 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -23,6 +23,7 @@ use util::numbers::{Uint, U256}; use ethcore::client::{TestBlockChainClient, EachBlockWith, Executed, TransactionId}; use ethcore::log_entry::{LocalizedLogEntry, LogEntry}; use ethcore::receipt::LocalizedReceipt; +use ethcore::transaction::{Transaction, Action}; use v1::{Eth, EthClient}; use v1::tests::helpers::{TestAccount, TestAccountProvider, TestSyncProvider, Config, TestMinerService, TestExternalMiner}; @@ -52,7 +53,7 @@ fn miner_service() -> Arc { struct EthTester { pub client: Arc, pub sync: Arc, - _accounts_provider: Arc, + pub accounts_provider: Arc, miner: Arc, hashrates: Arc>>, pub io: IoHandler, @@ -72,7 +73,7 @@ impl Default for EthTester { EthTester { client: client, sync: sync, - _accounts_provider: ap, + accounts_provider: ap, miner: miner, io: io, hashrates: hashrates, @@ -453,9 +454,53 @@ fn rpc_eth_estimate_gas_default_block() { } #[test] -#[ignore] fn rpc_eth_send_transaction() { - unimplemented!() + let account = TestAccount::new("123"); + let address = account.address(); + let secret = account.secret.clone(); + + let tester = EthTester::default(); + tester.accounts_provider.accounts.write().unwrap().insert(address.clone(), account); + let request = r#"{ + "jsonrpc": "2.0", + "method": "eth_sendTransaction", + "params": [{ + "from": ""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"", + "to": "0xd46e8dd67c5d32be8058bb8eb970870f07244567", + "gas": "0x76c0", + "gasPrice": "0x9184e72a000", + "value": "0x9184e72a" + }], + "id": 1 + }"#; + + let t = Transaction { + nonce: U256::zero(), + gas_price: U256::from(0x9184e72a000u64), + gas: U256::from(0x76c0), + action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + value: U256::from(0x9184e72au64), + data: vec![] + }.sign(&secret); + + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + + assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); + + tester.miner.last_nonces.write().unwrap().insert(address.clone(), U256::zero()); + + let t = Transaction { + nonce: U256::one(), + gas_price: U256::from(0x9184e72a000u64), + gas: U256::from(0x76c0), + action: Action::Call(Address::from_str("d46e8dd67c5d32be8058bb8eb970870f07244567").unwrap()), + value: U256::from(0x9184e72au64), + data: vec![] + }.sign(&secret); + + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", t.hash()).as_ref() + r#"","id":1}"#; + + assert_eq!(tester.io.handle_request(request.as_ref()), Some(response)); } #[test] diff --git a/rpc/src/v1/tests/helpers/account_provider.rs b/rpc/src/v1/tests/helpers/account_provider.rs index 6ef6e2b59..cace69658 100644 --- a/rpc/src/v1/tests/helpers/account_provider.rs +++ b/rpc/src/v1/tests/helpers/account_provider.rs @@ -20,7 +20,7 @@ use std::sync::RwLock; use std::collections::HashMap; use std::io; use util::hash::{Address, H256, FixedHash}; -use util::crypto::{Secret, Signature}; +use util::crypto::{Secret, Signature, KeyPair}; use util::keys::store::{AccountProvider, SigningError, EncryptedHashMapError}; /// Account mock. @@ -30,23 +30,31 @@ pub struct TestAccount { pub unlocked: bool, /// Account's password. pub password: String, + /// Account's secret. + pub secret: Secret, } impl TestAccount { /// Creates new test account. pub fn new(password: &str) -> Self { + let pair = KeyPair::create().unwrap(); TestAccount { unlocked: false, password: password.to_owned(), + secret: pair.secret().clone() } } + + /// Returns account address. + pub fn address(&self) -> Address { + KeyPair::from_secret(self.secret.clone()).unwrap().address() + } } /// Test account provider. pub struct TestAccountProvider { - accounts: RwLock>, - /// Added accounts passwords. - pub adds: RwLock>, + /// Test provider accounts. + pub accounts: RwLock>, } impl TestAccountProvider { @@ -54,7 +62,6 @@ impl TestAccountProvider { pub fn new(accounts: HashMap) -> Self { TestAccountProvider { accounts: RwLock::new(accounts), - adds: RwLock::new(vec![]), } } } @@ -76,14 +83,20 @@ impl AccountProvider for TestAccountProvider { } fn new_account(&self, pass: &str) -> Result { - let mut adds = self.adds.write().unwrap(); - let address = Address::from(adds.len() as u64 + 2); - adds.push(pass.to_owned()); + let account = TestAccount::new(pass); + let address = KeyPair::from_secret(account.secret.clone()).unwrap().address(); + self.accounts.write().unwrap().insert(address.clone(), account); Ok(address) } - fn account_secret(&self, _account: &Address) -> Result { - Ok(Secret::random()) + fn account_secret(&self, address: &Address) -> Result { + // todo: consider checking if account is unlock. some test may need alteration then. + self.accounts + .read() + .unwrap() + .get(address) + .ok_or(SigningError::NoAccount) + .map(|acc| acc.secret.clone()) } fn sign(&self, _account: &Address, _message: &H256) -> Result { diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 517f2deb5..80a5e356d 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -16,7 +16,7 @@ //! Test implementation of miner service. -use util::{Address, H256, Bytes}; +use util::{Address, H256, Bytes, U256}; use util::standard::*; use ethcore::error::Error; use ethcore::client::BlockChainClient; @@ -27,19 +27,22 @@ use ethminer::{MinerService, MinerStatus, AccountDetails}; /// Test miner service. pub struct TestMinerService { /// Imported transactions. - pub imported_transactions: RwLock>, + pub imported_transactions: Mutex>, /// Latest closed block. pub latest_closed_block: Mutex>, /// Pre-existed pending transactions pub pending_transactions: Mutex>, + /// Last nonces. + pub last_nonces: RwLock>, } impl Default for TestMinerService { fn default() -> TestMinerService { TestMinerService { - imported_transactions: RwLock::new(Vec::new()), + imported_transactions: Mutex::new(Vec::new()), latest_closed_block: Mutex::new(None), pending_transactions: Mutex::new(HashMap::new()), + last_nonces: RwLock::new(HashMap::new()), } } } @@ -56,28 +59,52 @@ impl MinerService for TestMinerService { } /// Imports transactions to transaction queue. - fn import_transactions(&self, _transactions: Vec, _fetch_account: T) -> Vec> - where T: Fn(&Address) -> AccountDetails { unimplemented!(); } + fn import_transactions(&self, transactions: Vec, _fetch_account: T) -> Vec> + where T: Fn(&Address) -> AccountDetails { + // lets assume that all txs are valid + self.imported_transactions.lock().unwrap().extend_from_slice(&transactions); + + transactions + .iter() + .map(|_| Ok(())) + .collect() + } /// Returns hashes of transactions currently in pending - fn pending_transactions_hashes(&self) -> Vec { vec![] } + fn pending_transactions_hashes(&self) -> Vec { + vec![] + } /// Removes all transactions from the queue and restart mining operation. - fn clear_and_reset(&self, _chain: &BlockChainClient) { unimplemented!(); } + fn clear_and_reset(&self, _chain: &BlockChainClient) { + unimplemented!(); + } /// Called when blocks are imported to chain, updates transactions queue. - fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { unimplemented!(); } + fn chain_new_blocks(&self, _chain: &BlockChainClient, _imported: &[H256], _invalid: &[H256], _enacted: &[H256], _retracted: &[H256]) { + unimplemented!(); + } /// New chain head event. Restart mining operation. - fn update_sealing(&self, _chain: &BlockChainClient) { unimplemented!(); } + fn update_sealing(&self, _chain: &BlockChainClient) { + unimplemented!(); + } - fn map_sealing_work(&self, _chain: &BlockChainClient, _f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { unimplemented!(); } + fn map_sealing_work(&self, _chain: &BlockChainClient, _f: F) -> Option where F: FnOnce(&ClosedBlock) -> T { + unimplemented!(); + } fn transaction(&self, hash: &H256) -> Option { - self.pending_transactions.lock().unwrap().get(hash).and_then(|tx_ref| Some(tx_ref.clone())) + self.pending_transactions.lock().unwrap().get(hash).cloned() + } + + fn last_nonce(&self, address: &Address) -> Option { + self.last_nonces.read().unwrap().get(address).cloned() } /// Submit `seal` as a valid solution for the header of `pow_hash`. /// Will check the seal, but not actually insert the block into the chain. - fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { unimplemented!(); } + fn submit_seal(&self, _chain: &BlockChainClient, _pow_hash: H256, _seal: Vec) -> Result<(), Error> { + unimplemented!(); + } } diff --git a/rpc/src/v1/tests/personal.rs b/rpc/src/v1/tests/personal.rs index 261527c47..458669b42 100644 --- a/rpc/src/v1/tests/personal.rs +++ b/rpc/src/v1/tests/personal.rs @@ -22,8 +22,7 @@ use util::numbers::*; use std::collections::*; fn accounts_provider() -> Arc { - let mut accounts = HashMap::new(); - accounts.insert(Address::from(1), TestAccount::new("test")); + let accounts = HashMap::new(); let ap = TestAccountProvider::new(accounts); Arc::new(ap) } @@ -38,7 +37,11 @@ fn setup() -> (Arc, IoHandler) { #[test] fn accounts() { - let (_test_provider, io) = setup(); + let (test_provider, io) = setup(); + test_provider.accounts + .write() + .unwrap() + .insert(Address::from(1), TestAccount::new("test")); let request = r#"{"jsonrpc": "2.0", "method": "personal_listAccounts", "params": [], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":["0x0000000000000000000000000000000000000001"],"id":1}"#; @@ -49,11 +52,22 @@ fn accounts() { #[test] fn new_account() { - let (_test_provider, io) = setup(); - + let (test_provider, io) = setup(); let request = r#"{"jsonrpc": "2.0", "method": "personal_newAccount", "params": ["pass"], "id": 1}"#; - let response = r#"{"jsonrpc":"2.0","result":"0x0000000000000000000000000000000000000002","id":1}"#; - assert_eq!(io.handle_request(request), Some(response.to_owned())); + let res = io.handle_request(request); + + let accounts = test_provider.accounts.read().unwrap(); + assert_eq!(accounts.len(), 1); + + let address = accounts + .keys() + .nth(0) + .cloned() + .unwrap(); + + let response = r#"{"jsonrpc":"2.0","result":""#.to_owned() + format!("0x{:?}", address).as_ref() + r#"","id":1}"#; + + assert_eq!(res, Some(response)); } From 8b3e84f7fe8731d2cc670f3294c19d5e6f11f2ca Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 6 Apr 2016 14:03:53 +0300 Subject: [PATCH 22/52] passing key path to all invocations --- parity/main.rs | 8 ++++---- util/src/keys/store.rs | 11 ++++++++++- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index c5e0dce54..872c91d03 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -82,7 +82,7 @@ Parity. Ethereum Client. Usage: parity daemon [options] - parity account (new | list) + parity account (new | list) [options] parity [options] Protocol Options: @@ -93,7 +93,7 @@ Protocol Options: -d --db-path PATH Specify the database & configuration directory path [default: $HOME/.parity]. --keys-path PATH Specify the path for JSON key files to be found - [default: $HOME/.web3/keys]. + [default: $HOME/.parity/keys]. --identity NAME Specify your node's name. Account Options: @@ -505,7 +505,7 @@ impl Configuration { fn execute_account_cli(&self) { use util::keys::store::SecretStore; use rpassword::read_password; - let mut secret_store = SecretStore::new(); + let mut secret_store = SecretStore::new_in(Path::new(&self.args.flag_keys_path)); if self.args.cmd_new { println!("Please note that password is NOT RECOVERABLE."); println!("Type password: "); @@ -539,7 +539,7 @@ impl Configuration { .into_iter() }).collect::>(); - let account_service = AccountService::new(); + let account_service = AccountService::new_in(Path::new(&self.args.flag_keys_path)); for d in &self.args.flag_unlock { let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| { die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d) diff --git a/util/src/keys/store.rs b/util/src/keys/store.rs index a4b6f2c7b..5dec27fc3 100644 --- a/util/src/keys/store.rs +++ b/util/src/keys/store.rs @@ -128,7 +128,7 @@ impl Default for AccountService { } impl AccountService { - /// New account service with the default location + /// New account service with the keys store in default location pub fn new() -> Self { let secret_store = RwLock::new(SecretStore::new()); secret_store.write().unwrap().try_import_existing(); @@ -137,6 +137,15 @@ impl AccountService { } } + /// New account service with the keys store in specific location + pub fn new_in(path: &Path) -> Self { + let secret_store = RwLock::new(SecretStore::new_in(path)); + secret_store.write().unwrap().try_import_existing(); + AccountService { + secret_store: secret_store + } + } + #[cfg(test)] fn new_test(temp: &::devtools::RandomTempPath) -> Self { let secret_store = RwLock::new(SecretStore::new_test(temp)); From 9b7c48110af586eec8e6ddc00615823338f2252a Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 6 Apr 2016 13:05:58 +0200 Subject: [PATCH 23/52] Fixed eth_call nonce and gas handling --- ethcore/src/client/client.rs | 5 +++-- ethcore/src/executive.rs | 33 ++++++++++++++++++++++++--------- ethcore/src/state.rs | 5 +++-- rpc/src/v1/impls/eth.rs | 6 +++++- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index dfdad70a9..554a839e1 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -38,7 +38,7 @@ use block_queue::{BlockQueue, BlockQueueInfo}; use blockchain::{BlockChain, BlockProvider, TreeRoute, ImportRoute}; use client::{BlockId, TransactionId, UncleId, ClientConfig, BlockChainClient}; use env_info::EnvInfo; -use executive::{Executive, Executed, contract_address}; +use executive::{Executive, Executed, TransactOptions, contract_address}; use receipt::LocalizedReceipt; pub use blockchain::CacheSize as BlockChainCacheSize; @@ -418,7 +418,8 @@ impl BlockChainClient for Client where V: Verifier { // give the sender max balance state.sub_balance(&sender, &balance); state.add_balance(&sender, &U256::max_value()); - Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, false) + let options = TransactOptions { tracing: false, check_nonce: false }; + Executive::new(&mut state, &env_info, self.engine.deref().deref()).transact(t, options) } // TODO [todr] Should be moved to miner crate eventually. diff --git a/ethcore/src/executive.rs b/ethcore/src/executive.rs index fe26846c7..3e74895bd 100644 --- a/ethcore/src/executive.rs +++ b/ethcore/src/executive.rs @@ -36,6 +36,14 @@ pub fn contract_address(address: &Address, nonce: &U256) -> Address { From::from(stream.out().sha3()) } +/// Transaction execution options. +pub struct TransactOptions { + /// Enable call tracing. + pub tracing: bool, + /// Check transaction nonce before execution. + pub check_nonce: bool, +} + /// Transaction execution receipt. #[derive(Debug, PartialEq, Clone)] pub struct Executed { @@ -110,7 +118,7 @@ impl<'a> Executive<'a> { } /// This funtion should be used to execute transaction. - pub fn transact(&'a mut self, t: &SignedTransaction, tracing: bool) -> Result { + pub fn transact(&'a mut self, t: &SignedTransaction, options: TransactOptions) -> Result { let sender = try!(t.sender()); let nonce = self.state.nonce(&sender); @@ -124,8 +132,10 @@ impl<'a> Executive<'a> { let init_gas = t.gas - base_gas_required; // validate transaction nonce - if t.nonce != nonce { - return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); + if options.check_nonce { + if t.nonce != nonce { + return Err(From::from(ExecutionError::InvalidNonce { expected: nonce, got: t.nonce })); + } } // validate if transaction fits into given block @@ -151,7 +161,7 @@ impl<'a> Executive<'a> { self.state.inc_nonce(&sender); self.state.sub_balance(&sender, &U256::from(gas_cost)); - let mut substate = Substate::new(tracing); + let mut substate = Substate::new(options.tracing); let (gas_left, output) = match t.action { Action::Create => { @@ -881,7 +891,8 @@ mod tests { let executed = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t, false).unwrap() + let opts = TransactOptions { check_nonce: true, tracing: false }; + ex.transact(&t, opts).unwrap() }; assert_eq!(executed.gas, U256::from(100_000)); @@ -914,7 +925,8 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t, false) + let opts = TransactOptions { check_nonce: true, tracing: false }; + ex.transact(&t, opts) }; match res { @@ -945,7 +957,8 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t, false) + let opts = TransactOptions { check_nonce: true, tracing: false }; + ex.transact(&t, opts) }; match res { @@ -978,7 +991,8 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t, false) + let opts = TransactOptions { check_nonce: true, tracing: false }; + ex.transact(&t, opts) }; match res { @@ -1011,7 +1025,8 @@ mod tests { let res = { let mut ex = Executive::new(&mut state, &info, &engine); - ex.transact(&t, false) + let opts = TransactOptions { check_nonce: true, tracing: false }; + ex.transact(&t, opts) }; match res { diff --git a/ethcore/src/state.rs b/ethcore/src/state.rs index c0a676a7d..fca578a09 100644 --- a/ethcore/src/state.rs +++ b/ethcore/src/state.rs @@ -16,7 +16,7 @@ use common::*; use engine::Engine; -use executive::Executive; +use executive::{Executive, TransactOptions}; use account_db::*; #[cfg(test)] #[cfg(feature = "json-tests")] @@ -220,7 +220,8 @@ impl State { pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult { // let old = self.to_pod(); - let e = try!(Executive::new(self, env_info, engine).transact(t, tracing)); + let options = TransactOptions { tracing: tracing, check_nonce: true }; + let e = try!(Executive::new(self, env_info, engine).transact(t, options)); // TODO uncomment once to_pod() works correctly. // trace!("Applied transaction. Diff:\n{}\n", StateDiff::diff_pod(&old, &self.to_pod())); diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index dd241c9ec..b26ce8ac9 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -43,6 +43,10 @@ fn default_gas() -> U256 { U256::from(21_000) } +fn default_call_gas() -> U256 { + U256::from(50_000_000) +} + /// Eth rpc implementation. pub struct EthClient where C: BlockChainClient, @@ -175,7 +179,7 @@ impl EthClient Ok(EthTransaction { nonce: request.nonce.unwrap_or_else(|| client.nonce(&from)), action: request.to.map_or(Action::Create, Action::Call), - gas: request.gas.unwrap_or_else(default_gas), + gas: request.gas.unwrap_or_else(default_call_gas), gas_price: request.gas_price.unwrap_or_else(|| miner.sensible_gas_price()), value: request.value.unwrap_or_else(U256::zero), data: request.data.map_or_else(Vec::new, |d| d.to_vec()) From e6be5016f93ac8a0589c59b6d44ce240f54f62f6 Mon Sep 17 00:00:00 2001 From: NikVolf Date: Wed, 6 Apr 2016 14:21:19 +0300 Subject: [PATCH 24/52] replacing /home/nikky also --- parity/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 872c91d03..674be24f3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -383,7 +383,7 @@ impl Configuration { } } - fn _keys_path(&self) -> String { + fn keys_path(&self) -> String { self.args.flag_keys_path.replace("$HOME", env::home_dir().unwrap().to_str().unwrap()) } @@ -505,7 +505,7 @@ impl Configuration { fn execute_account_cli(&self) { use util::keys::store::SecretStore; use rpassword::read_password; - let mut secret_store = SecretStore::new_in(Path::new(&self.args.flag_keys_path)); + let mut secret_store = SecretStore::new_in(Path::new(&self.keys_path())); if self.args.cmd_new { println!("Please note that password is NOT RECOVERABLE."); println!("Type password: "); @@ -539,7 +539,7 @@ impl Configuration { .into_iter() }).collect::>(); - let account_service = AccountService::new_in(Path::new(&self.args.flag_keys_path)); + let account_service = AccountService::new_in(Path::new(&self.keys_path())); for d in &self.args.flag_unlock { let a = Address::from_str(clean_0x(&d)).unwrap_or_else(|_| { die!("{}: Invalid address for --unlock. Must be 40 hex characters, without the 0x at the beginning.", d) From dc91e57c2ffb0b57d5f2c7e2bea6362485604607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 19:07:27 +0200 Subject: [PATCH 25/52] Additional logging and error messages --- Cargo.lock | 6 ++-- parity/main.rs | 81 ++++++++++++++++++++++++++++++++++---------------- rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 23 +++++++++----- 4 files changed, 76 insertions(+), 36 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b24bc9219..5c54ae66d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -245,7 +245,7 @@ dependencies = [ "ethminer 1.1.0", "ethsync 1.1.0", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 3.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -452,8 +452,8 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" +version = "4.0.0" +source = "git+https://github.com/tomusdrw/jsonrpc-http-server.git#46bd4e7cf8352e0efc940cf76d3dff99f1a3da15" dependencies = [ "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/parity/main.rs b/parity/main.rs index c5e0dce54..465a21fee 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -269,10 +269,8 @@ fn setup_rpc_server( sync: Arc, secret_store: Arc, miner: Arc, - url: &str, - cors_domain: &str, apis: Vec<&str> -) -> Option> { +) -> Option { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -290,7 +288,7 @@ fn setup_rpc_server( } } } - Some(server.start_http(url, cors_domain, ::num_cpus::get())) + Some(server) } #[cfg(not(feature = "rpc"))] @@ -299,8 +297,6 @@ fn setup_rpc_server( _sync: Arc, _secret_store: Arc, _miner: Arc, - _url: &str, - _cors_domain: &str, _apis: Vec<&str> ) -> Option> { None @@ -569,7 +565,10 @@ impl Configuration { let account_service = Arc::new(self.account_service()); // Build client - let mut service = ClientService::start(self.client_config(), spec, net_settings, &Path::new(&self.path())).unwrap(); + let mut service = ClientService::start( + self.client_config(), spec, net_settings, &Path::new(&self.path()) + ).unwrap_or_else(|e| die_with_error(e)); + panic_handler.forward_from(&service); let client = service.client(); @@ -584,7 +583,23 @@ impl Configuration { let sync = EthSync::register(service.network(), sync_config, client.clone(), miner.clone()); // Setup rpc - if self.args.flag_jsonrpc || self.args.flag_rpc { + let rpc_server = if self.args.flag_jsonrpc || self.args.flag_rpc { + // TODO: use this as the API list. + let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); + setup_rpc_server( + service.client(), + sync.clone(), + account_service.clone(), + miner.clone(), + apis.split(',').collect() + ) + } else { + None + }; + let rpc_handle = rpc_server.map(|server| { + panic_handler.forward_from(&server); + server + }).map(|server| { let url = format!("{}:{}", match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() { "all" => "0.0.0.0", @@ -594,22 +609,14 @@ impl Configuration { self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); - let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); - // TODO: use this as the API list. - let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - let server_handler = setup_rpc_server( - service.client(), - sync.clone(), - account_service.clone(), - miner.clone(), - &url, - cors, - apis.split(',').collect() - ); - if let Some(handler) = server_handler { - panic_handler.forward_from(handler.deref()); + let cors_domain = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); + let start_result = server.start_http(&url, cors_domain, ::num_cpus::get()); + match start_result { + Ok(handle) => handle, + Err(rpc::RpcServerError::IoError(err)) => die_with_io_error(err), + Err(e) => die!("{:?}", e), } - } + }); // Register IO handler let io_handler = Arc::new(ClientIoHandler { @@ -621,11 +628,11 @@ impl Configuration { service.io().register_handler(io_handler).expect("Error registering IO handler"); // Handle exit - wait_for_exit(panic_handler); + wait_for_exit(panic_handler, rpc_handle); } } -fn wait_for_exit(panic_handler: Arc) { +fn wait_for_exit(panic_handler: Arc, _rpc_handle: Option) { let exit = Arc::new(Condvar::new()); // Handle possible exits @@ -639,6 +646,30 @@ fn wait_for_exit(panic_handler: Arc) { // Wait for signal let mutex = Mutex::new(()); let _ = exit.wait(mutex.lock().unwrap()).unwrap(); + info!("Closing...."); +} + +fn die_with_error(e: ethcore::error::Error) -> ! { + use ethcore::error::Error; + + match e { + Error::Util(UtilError::StdIo(e)) => die_with_io_error(e), + _ => die!("{:?}", e), + } +} +fn die_with_io_error(e: std::io::Error) -> ! { + match e.kind() { + std::io::ErrorKind::PermissionDenied => { + die!("We don't have permission to bind to this port.") + }, + std::io::ErrorKind::AddrInUse => { + die!("Specified address is already in use. Please make sure that nothing is listening on specified port or use different one") + }, + std::io::ErrorKind::AddrNotAvailable => { + die!("Couldn't use specified interface or given address is invalid.") + }, + _ => die!("{:?}", e), + } } fn main() { diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index c28f598fd..6fdf9a55e 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -13,7 +13,7 @@ log = "0.3" serde = "0.7.0" serde_json = "0.7.0" jsonrpc-core = "2.0" -jsonrpc-http-server = "3.0" +jsonrpc-http-server = { git = "https://github.com/tomusdrw/jsonrpc-http-server.git" } ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 3096a45c9..119d12a0f 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -34,14 +34,16 @@ extern crate transient_hashmap; use std::sync::Arc; use std::thread; -use util::panics::PanicHandler; +use util::panics::{MayPanic, PanicHandler, OnPanicListener}; use self::jsonrpc_core::{IoHandler, IoDelegate}; +pub use jsonrpc_http_server::{Listening, RpcServerError}; pub mod v1; /// Http server. pub struct RpcServer { handler: Arc, + panic_handler: Arc } impl RpcServer { @@ -49,6 +51,7 @@ impl RpcServer { pub fn new() -> RpcServer { RpcServer { handler: Arc::new(IoHandler::new()), + panic_handler: PanicHandler::new_in_arc(), } } @@ -58,17 +61,23 @@ impl RpcServer { } /// Start server asynchronously in new thread and returns panic handler. - pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Arc { + pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Result { let addr = addr.to_owned(); let cors_domain = cors_domain.to_owned(); - let panic_handler = PanicHandler::new_in_arc(); - let ph = panic_handler.clone(); + let ph = self.panic_handler.clone(); let server = jsonrpc_http_server::Server::new(self.handler.clone()); + thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { ph.catch_panic(move || { - server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads); + server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads) }).unwrap() - }).expect("Error while creating jsonrpc http thread"); - panic_handler + }).expect("Error while creating jsonrpc http thread").join().unwrap() } } + +impl MayPanic for RpcServer { + fn on_panic(&self, closure: F) where F: OnPanicListener { + self.panic_handler.on_panic(closure); + } +} + From a52043d5b3ab37c29abfdd03505846aa9003b848 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 19:14:05 +0200 Subject: [PATCH 26/52] Removing additional thread from JSON-RPC --- parity/main.rs | 4 +--- rpc/src/lib.rs | 18 +----------------- 2 files changed, 2 insertions(+), 20 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 1b1ca27e6..6fffa4b53 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -594,10 +594,8 @@ impl Configuration { } else { None }; + let rpc_handle = rpc_server.map(|server| { - panic_handler.forward_from(&server); - server - }).map(|server| { let url = format!("{}:{}", match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() { "all" => "0.0.0.0", diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 119d12a0f..9787db9cd 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -33,8 +33,6 @@ extern crate ethminer; extern crate transient_hashmap; use std::sync::Arc; -use std::thread; -use util::panics::{MayPanic, PanicHandler, OnPanicListener}; use self::jsonrpc_core::{IoHandler, IoDelegate}; pub use jsonrpc_http_server::{Listening, RpcServerError}; @@ -43,7 +41,6 @@ pub mod v1; /// Http server. pub struct RpcServer { handler: Arc, - panic_handler: Arc } impl RpcServer { @@ -51,7 +48,6 @@ impl RpcServer { pub fn new() -> RpcServer { RpcServer { handler: Arc::new(IoHandler::new()), - panic_handler: PanicHandler::new_in_arc(), } } @@ -64,20 +60,8 @@ impl RpcServer { pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Result { let addr = addr.to_owned(); let cors_domain = cors_domain.to_owned(); - let ph = self.panic_handler.clone(); let server = jsonrpc_http_server::Server::new(self.handler.clone()); - thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { - ph.catch_panic(move || { - server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads) - }).unwrap() - }).expect("Error while creating jsonrpc http thread").join().unwrap() + server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads) } } - -impl MayPanic for RpcServer { - fn on_panic(&self, closure: F) where F: OnPanicListener { - self.panic_handler.on_panic(closure); - } -} - From fd03f58eaebc7fd9b3fd795904c813d45184df32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 19:22:10 +0200 Subject: [PATCH 27/52] Rewriting messages --- parity/main.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 6fffa4b53..1f06298be 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -656,13 +656,13 @@ fn die_with_error(e: ethcore::error::Error) -> ! { fn die_with_io_error(e: std::io::Error) -> ! { match e.kind() { std::io::ErrorKind::PermissionDenied => { - die!("We don't have permission to bind to this port.") + die!("No permissions to bind to specified port.") }, std::io::ErrorKind::AddrInUse => { - die!("Specified address is already in use. Please make sure that nothing is listening on specified port or use different one") + die!("Specified address is already in use. Please make sure that nothing is listening on the same port or try using a different one.") }, std::io::ErrorKind::AddrNotAvailable => { - die!("Couldn't use specified interface or given address is invalid.") + die!("Could not use specified interface or given address is invalid.") }, _ => die!("{:?}", e), } From 3438cda4324106c164eac3686ff1a60efc7a3372 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 6 Apr 2016 23:03:07 +0200 Subject: [PATCH 28/52] Propagate transaction queue --- miner/src/lib.rs | 5 +++- miner/src/miner.rs | 5 ++++ rpc/src/v1/impls/eth.rs | 8 +++---- rpc/src/v1/tests/helpers/miner_service.rs | 4 ++++ rpc/src/v1/tests/helpers/sync_provider.rs | 5 +--- sync/src/chain.rs | 28 +++++++++-------------- sync/src/lib.rs | 10 +------- 7 files changed, 29 insertions(+), 36 deletions(-) diff --git a/miner/src/lib.rs b/miner/src/lib.rs index 9f757fb67..c6e07a953 100644 --- a/miner/src/lib.rs +++ b/miner/src/lib.rs @@ -105,9 +105,12 @@ pub trait MinerService : Send + Sync { /// Get the sealing work package and if `Some`, apply some transform. fn map_sealing_work(&self, chain: &BlockChainClient, f: F) -> Option where F: FnOnce(&ClosedBlock) -> T; - /// Query pending transactions for hash + /// Query pending transactions for hash. fn transaction(&self, hash: &H256) -> Option; + /// Get a list of all pending transactions. + fn pending_transactions(&self) -> Vec; + /// Returns highest transaction nonce for given address. fn last_nonce(&self, address: &Address) -> Option; diff --git a/miner/src/miner.rs b/miner/src/miner.rs index 0e31c504f..3b4d1f32d 100644 --- a/miner/src/miner.rs +++ b/miner/src/miner.rs @@ -228,6 +228,11 @@ impl MinerService for Miner { queue.find(hash) } + fn pending_transactions(&self) -> Vec { + let queue = self.transaction_queue.lock().unwrap(); + queue.top_transactions() + } + fn last_nonce(&self, address: &Address) -> Option { self.transaction_queue.lock().unwrap().last_nonce(address) } diff --git a/rpc/src/v1/impls/eth.rs b/rpc/src/v1/impls/eth.rs index 30dc79662..ad4b037df 100644 --- a/rpc/src/v1/impls/eth.rs +++ b/rpc/src/v1/impls/eth.rs @@ -186,7 +186,7 @@ impl EthClient }.fake_sign(from)) } - fn dispatch_transaction(&self, signed_transaction: SignedTransaction, raw_transaction: Vec) -> Result { + fn dispatch_transaction(&self, signed_transaction: SignedTransaction) -> Result { let hash = signed_transaction.hash(); let import = { @@ -203,7 +203,6 @@ impl EthClient match import.into_iter().collect::, _>>() { Ok(_) => { - take_weak!(self.sync).new_transaction(raw_transaction); to_value(&hash) } Err(e) => { @@ -504,8 +503,7 @@ impl Eth for EthClient data: request.data.map_or_else(Vec::new, |d| d.to_vec()), }.sign(&secret) }; - let raw_transaction = encode(&signed_transaction).to_vec(); - self.dispatch_transaction(signed_transaction, raw_transaction) + self.dispatch_transaction(signed_transaction) }, Err(_) => { to_value(&H256::zero()) } } @@ -517,7 +515,7 @@ impl Eth for EthClient .and_then(|(raw_transaction, )| { let raw_transaction = raw_transaction.to_vec(); match UntrustedRlp::new(&raw_transaction).as_val() { - Ok(signed_transaction) => self.dispatch_transaction(signed_transaction, raw_transaction), + Ok(signed_transaction) => self.dispatch_transaction(signed_transaction), Err(_) => to_value(&H256::zero()), } }) diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 80a5e356d..815085d3b 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -98,6 +98,10 @@ impl MinerService for TestMinerService { self.pending_transactions.lock().unwrap().get(hash).cloned() } + fn pending_transactions(&self) -> Vec { + self.pending_transactions.lock().unwrap().values().cloned().collect() + } + fn last_nonce(&self, address: &Address) -> Option { self.last_nonces.read().unwrap().get(address).cloned() } diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 59188f0a7..633e0d45b 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -16,7 +16,7 @@ //! Test implementation of SyncProvider. -use util::{U256, Bytes}; +use util::{U256}; use ethsync::{SyncProvider, SyncStatus, SyncState}; use std::sync::{RwLock}; @@ -59,8 +59,5 @@ impl SyncProvider for TestSyncProvider { fn status(&self) -> SyncStatus { self.status.read().unwrap().clone() } - - fn new_transaction(&self, _raw_transaction: Bytes) { - } } diff --git a/sync/src/chain.rs b/sync/src/chain.rs index 1a7d11f51..74bcb8d38 100644 --- a/sync/src/chain.rs +++ b/sync/src/chain.rs @@ -217,10 +217,6 @@ pub struct ChainSync { network_id: U256, /// Miner miner: Arc, - - /// Transactions to propagate - // TODO: reconsider where this is in the codebase - seems a little dodgy to have here. - transactions_to_send: Vec, } type RlpResponseResult = Result, PacketDecodeError>; @@ -247,7 +243,6 @@ impl ChainSync { max_download_ahead_blocks: max(MAX_HEADERS_TO_REQUEST, config.max_download_ahead_blocks), network_id: config.network_id, miner: miner, - transactions_to_send: vec![], } } @@ -950,11 +945,6 @@ impl ChainSync { } } - /// Place a new transaction on the wire. - pub fn new_transaction(&mut self, raw_transaction: Bytes) { - self.transactions_to_send.push(raw_transaction); - } - /// Called when peer sends us new transactions fn on_peer_transactions(&mut self, io: &mut SyncIo, peer_id: PeerId, r: &UntrustedRlp) -> Result<(), PacketDecodeError> { // accepting transactions once only fully synced @@ -1296,11 +1286,16 @@ impl ChainSync { return 0; } - let mut packet = RlpStream::new_list(self.transactions_to_send.len()); - for tx in &self.transactions_to_send { - packet.append_raw(tx, 1); + let mut transactions = self.miner.pending_transactions(); + if transactions.is_empty() { + return 0; + } + + let mut packet = RlpStream::new_list(transactions.len()); + let tx_count = transactions.len(); + for tx in transactions.drain(..) { + packet.append(&tx); } - self.transactions_to_send.clear(); let rlp = packet.out(); let lucky_peers = { @@ -1319,13 +1314,12 @@ impl ChainSync { for peer_id in lucky_peers { self.send_packet(io, peer_id, TRANSACTIONS_PACKET, rlp.clone()); } + trace!(target: "sync", "Sent {} transactions to {} peers.", tx_count, sent); sent } fn propagate_latest_blocks(&mut self, io: &mut SyncIo) { - if !self.transactions_to_send.is_empty() { - self.propagate_new_transactions(io); - } + self.propagate_new_transactions(io); let chain_info = io.chain().chain_info(); if (((chain_info.best_block_number as i64) - (self.last_sent_block_number as i64)).abs() as BlockNumber) < MAX_PEER_LAG_PROPAGATION { let blocks = self.propagate_blocks(&chain_info, io); diff --git a/sync/src/lib.rs b/sync/src/lib.rs index ea4a1daea..a4f6eff38 100644 --- a/sync/src/lib.rs +++ b/sync/src/lib.rs @@ -66,7 +66,7 @@ use std::ops::*; use std::sync::*; use util::network::{NetworkProtocolHandler, NetworkService, NetworkContext, PeerId}; use util::TimerToken; -use util::{U256, Bytes, ONE_U256}; +use util::{U256, ONE_U256}; use ethcore::client::Client; use ethcore::service::SyncMessage; use ethminer::Miner; @@ -101,9 +101,6 @@ impl Default for SyncConfig { pub trait SyncProvider: Send + Sync { /// Get sync status fn status(&self) -> SyncStatus; - - /// Note that a user has submitted a new transaction. - fn new_transaction(&self, raw_transaction: Bytes); } /// Ethereum network protocol handler @@ -143,11 +140,6 @@ impl SyncProvider for EthSync { fn status(&self) -> SyncStatus { self.sync.read().unwrap().status() } - - /// Note that a user has submitted a new transaction. - fn new_transaction(&self, raw_transaction: Bytes) { - self.sync.write().unwrap().new_transaction(raw_transaction); - } } impl NetworkProtocolHandler for EthSync { From d4f0902968a338345024cd75fabd969149c71a76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 23:45:19 +0200 Subject: [PATCH 29/52] Tracing shutdown and changed order of IoManager shutdown process --- ethcore/src/block_queue.rs | 2 ++ util/src/io/service.rs | 4 +++- util/src/io/worker.rs | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 4a52d6a6b..433e8b40b 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -431,12 +431,14 @@ impl MayPanic for BlockQueue { impl Drop for BlockQueue { fn drop(&mut self) { + trace!(target: "shutdown", "[BlockQueue] Closing..."); self.clear(); self.deleting.store(true, AtomicOrdering::Release); self.more_to_verify.notify_all(); for t in self.verifiers.drain(..) { t.join().unwrap(); } + trace!(target: "shutdown", "[BlockQueue] Closed."); } } diff --git a/util/src/io/service.rs b/util/src/io/service.rs index 8a34ee80a..24cc1181a 100644 --- a/util/src/io/service.rs +++ b/util/src/io/service.rs @@ -231,8 +231,8 @@ impl Handler for IoManager where Message: Send + Clone + Sync fn notify(&mut self, event_loop: &mut EventLoop, msg: Self::Message) { match msg { IoMessage::Shutdown => { - self.workers.clear(); event_loop.shutdown(); + self.workers.clear(); }, IoMessage::AddHandler { handler } => { let handler_id = { @@ -376,8 +376,10 @@ impl IoService where Message: Send + Sync + Clone + 'static { impl Drop for IoService where Message: Send + Sync + Clone { fn drop(&mut self) { + trace!(target: "shutdown", "[IoService] Closing..."); self.host_channel.send(IoMessage::Shutdown).unwrap(); self.thread.take().unwrap().join().ok(); + trace!(target: "shutdown", "[IoService] Closed."); } } diff --git a/util/src/io/worker.rs b/util/src/io/worker.rs index b874ea0a4..917b1ad79 100644 --- a/util/src/io/worker.rs +++ b/util/src/io/worker.rs @@ -120,10 +120,12 @@ impl Worker { impl Drop for Worker { fn drop(&mut self) { + trace!(target: "shutdown", "[IoWorker] Closing..."); let _ = self.wait_mutex.lock(); self.deleting.store(true, AtomicOrdering::Release); self.wait.notify_all(); let thread = mem::replace(&mut self.thread, None).unwrap(); thread.join().ok(); + trace!(target: "shutdown", "[IoWorker] Closed"); } } From f27d88f6aba8b662645586530e551f51b2fdc9fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Wed, 6 Apr 2016 23:58:23 +0200 Subject: [PATCH 30/52] More descriptive message when closing --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 1f06298be..06710a3a4 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -642,7 +642,7 @@ fn wait_for_exit(panic_handler: Arc, _rpc_handle: Option ! { From 730d60e5e4b9a0a8105f7b610cd462dc77c501d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 00:20:03 +0200 Subject: [PATCH 31/52] Avoid signalling readiness when app is about to be closed --- ethcore/src/block_queue.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/ethcore/src/block_queue.rs b/ethcore/src/block_queue.rs index 4a52d6a6b..d9f629f11 100644 --- a/ethcore/src/block_queue.rs +++ b/ethcore/src/block_queue.rs @@ -116,6 +116,7 @@ struct VerifyingBlock { } struct QueueSignal { + deleting: Arc, signalled: AtomicBool, message_channel: IoChannel, } @@ -123,10 +124,16 @@ struct QueueSignal { impl QueueSignal { #[cfg_attr(feature="dev", allow(bool_comparison))] fn set(&self) { + // Do not signal when we are about to close + if self.deleting.load(AtomicOrdering::Relaxed) { + return; + } + if self.signalled.compare_and_swap(false, true, AtomicOrdering::Relaxed) == false { self.message_channel.send(UserMessage(SyncMessage::BlockVerified)).expect("Error sending BlockVerified message"); } } + fn reset(&self) { self.signalled.store(false, AtomicOrdering::Relaxed); } @@ -150,8 +157,12 @@ impl BlockQueue { bad: Mutex::new(HashSet::new()), }); let more_to_verify = Arc::new(Condvar::new()); - let ready_signal = Arc::new(QueueSignal { signalled: AtomicBool::new(false), message_channel: message_channel }); let deleting = Arc::new(AtomicBool::new(false)); + let ready_signal = Arc::new(QueueSignal { + deleting: deleting.clone(), + signalled: AtomicBool::new(false), + message_channel: message_channel + }); let empty = Arc::new(Condvar::new()); let panic_handler = PanicHandler::new_in_arc(); From d1d3d847ab431ced381fc42ff15867ab18b7264b Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 7 Apr 2016 00:33:55 +0200 Subject: [PATCH 32/52] fixed #895 --- rpc/src/v1/traits/eth.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/rpc/src/v1/traits/eth.rs b/rpc/src/v1/traits/eth.rs index 8a48e0dfe..5d36da670 100644 --- a/rpc/src/v1/traits/eth.rs +++ b/rpc/src/v1/traits/eth.rs @@ -190,9 +190,6 @@ pub trait EthFilter: Sized + Send + Sync + 'static { /// Returns filter changes since last poll. fn filter_changes(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Returns filter logs. - fn filter_logs(&self, _: Params) -> Result { rpc_unimplemented!() } - /// Uninstalls filter. fn uninstall_filter(&self, _: Params) -> Result { rpc_unimplemented!() } @@ -203,7 +200,7 @@ pub trait EthFilter: Sized + Send + Sync + 'static { delegate.add_method("eth_newBlockFilter", EthFilter::new_block_filter); delegate.add_method("eth_newPendingTransactionFilter", EthFilter::new_pending_transaction_filter); delegate.add_method("eth_getFilterChanges", EthFilter::filter_changes); - delegate.add_method("eth_getFilterLogs", EthFilter::filter_logs); + delegate.add_method("eth_getFilterLogs", EthFilter::filter_changes); delegate.add_method("eth_uninstallFilter", EthFilter::uninstall_filter); delegate } From 12d1dcddeb17b7ffb5c48851620543b7017411f7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 10:31:42 +0200 Subject: [PATCH 33/52] Updating rpc comments --- rpc/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 9787db9cd..4de405211 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -44,7 +44,7 @@ pub struct RpcServer { } impl RpcServer { - /// Construct new http server object with given number of threads. + /// Construct new http server object. pub fn new() -> RpcServer { RpcServer { handler: Arc::new(IoHandler::new()), @@ -56,7 +56,7 @@ impl RpcServer { self.handler.add_delegate(delegate); } - /// Start server asynchronously in new thread and returns panic handler. + /// Start server asynchronously and returns result with `Listening` handle on success or an error. pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Result { let addr = addr.to_owned(); let cors_domain = cors_domain.to_owned(); From e3ce5d94e1067b301af7f54fd73e825f01945237 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 10:49:00 +0200 Subject: [PATCH 34/52] Adding webapps crate --- Cargo.lock | 88 +++++++++++++++++++++++++ Cargo.toml | 8 ++- cov.sh | 2 + doc.sh | 1 + fmt.sh | 1 + hook.sh | 2 +- parity/main.rs | 2 + test.sh | 1 + webapp/Cargo.toml | 21 ++++++ webapp/src/lib.rs | 160 ++++++++++++++++++++++++++++++++++++++++++++++ 10 files changed, 283 insertions(+), 3 deletions(-) create mode 100644 webapp/Cargo.toml create mode 100644 webapp/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 471f35067..9783413d4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -11,6 +11,7 @@ dependencies = [ "ethcore-devtools 1.1.0", "ethcore-rpc 1.1.0", "ethcore-util 1.1.0", + "ethcore-webapp 1.1.0", "ethminer 1.1.0", "ethsync 1.1.0", "fdlimit 0.1.0", @@ -107,6 +108,14 @@ dependencies = [ "unicode-normalization 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "conduit-mime-types" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cookie" version = "0.1.21" @@ -185,6 +194,15 @@ dependencies = [ "regex 0.1.61 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "error" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "eth-secp256k1" version = "0.5.4" @@ -291,6 +309,20 @@ dependencies = [ "vergen 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "ethcore-webapp" +version = "1.1.0" +dependencies = [ + "clippy 0.0.61 (registry+https://github.com/rust-lang/crates.io-index)", + "ethcore-rpc 1.1.0", + "ethcore-util 1.1.0", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "ethjson" version = "0.1.0" @@ -427,6 +459,23 @@ dependencies = [ "xmltree 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "iron" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "conduit-mime-types 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "error 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "modifier 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "plugin 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "itertools" version = "0.4.11" @@ -461,6 +510,16 @@ dependencies = [ "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-http-server" +version = "4.0.0" +source = "git+https://github.com/tomusdrw/jsonrpc-http-server.git#46bd4e7cf8352e0efc940cf76d3dff99f1a3da15" +dependencies = [ + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.1" @@ -573,6 +632,11 @@ dependencies = [ "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "modifier" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "net2" version = "0.2.23" @@ -637,6 +701,14 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "plugin" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "typemap 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "primal" version = "0.2.3" @@ -938,6 +1010,14 @@ name = "typeable" version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "typemap" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unsafe-any 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "unicase" version = "1.4.0" @@ -964,6 +1044,14 @@ name = "unicode-xid" version = "0.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "unsafe-any" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "url" version = "0.2.38" diff --git a/Cargo.toml b/Cargo.toml index f38fe5b10..3fe923db7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,15 +28,19 @@ ethsync = { path = "sync" } ethminer = { path = "miner" } ethcore-devtools = { path = "devtools" } ethcore-rpc = { path = "rpc", optional = true } +ethcore-webapp = { path = "webapp", optional = true } + [dependencies.hyper] version = "0.8" default-features = false [features] -default = ["rpc"] +default = ["rpc", "webapp"] rpc = ["ethcore-rpc"] -dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev"] +webapp = ["ethcore-webapp"] +dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev", +"ethcore-webapp/dev"] travis-beta = ["ethcore/json-tests"] travis-nightly = ["ethcore/json-tests", "dev"] diff --git a/cov.sh b/cov.sh index d60ef223d..1698d6f36 100755 --- a/cov.sh +++ b/cov.sh @@ -23,6 +23,7 @@ cargo test \ -p ethcore-rpc \ -p parity \ -p ethminer \ + -p ethcore-webapp \ --no-run || exit $? rm -rf target/coverage mkdir -p target/coverage @@ -33,5 +34,6 @@ kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage t kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_util-* kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethsync-* kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_rpc-* +kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethcore_webapp-* kcov --exclude-pattern $EXCLUDE --include-pattern src --verify target/coverage target/debug/deps/ethminer-* xdg-open target/coverage/index.html diff --git a/doc.sh b/doc.sh index a5e5e2e13..9b0f13817 100755 --- a/doc.sh +++ b/doc.sh @@ -7,5 +7,6 @@ cargo doc --no-deps --verbose \ -p ethcore \ -p ethsync \ -p ethcore-rpc \ + -p ethcore-webapp \ -p parity \ -p ethminer diff --git a/fmt.sh b/fmt.sh index a16d5ac1f..4d835967f 100755 --- a/fmt.sh +++ b/fmt.sh @@ -9,6 +9,7 @@ $RUSTFMT ./json/src/lib.rs $RUSTFMT ./miner/src/lib.rs $RUSTFMT ./parity/main.rs $RUSTFMT ./rpc/src/lib.rs +$RUSTFMT ./webapp/src/lib.rs $RUSTFMT ./sync/src/lib.rs $RUSTFMT ./util/src/lib.rs diff --git a/hook.sh b/hook.sh index 58bff20ab..d98297835 100755 --- a/hook.sh +++ b/hook.sh @@ -7,6 +7,6 @@ echo "set -e" >> $FILE echo "cargo build --release --features dev" >> $FILE # Build tests echo "cargo test --no-run --features dev \\" >> $FILE -echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer" >> $FILE +echo " -p ethash -p ethcore-util -p ethcore -p ethsync -p ethcore-rpc -p parity -p ethminer -p ethcore-webapp" >> $FILE echo "" >> $FILE chmod +x $FILE diff --git a/parity/main.rs b/parity/main.rs index f5f5cfcd4..2141a5795 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -42,6 +42,8 @@ extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; +#[cfg(feature = "webapp")] +extern crate ethcore_webapp as webapp; use std::io::{BufRead, BufReader}; use std::fs::File; diff --git a/test.sh b/test.sh index 4957fd762..5094158cc 100755 --- a/test.sh +++ b/test.sh @@ -7,6 +7,7 @@ cargo test --features ethcore/json-tests $1 \ -p ethcore \ -p ethsync \ -p ethcore-rpc \ + -p ethcore-webapp \ -p parity \ -p ethminer \ -p bigint diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml new file mode 100644 index 000000000..f6503e163 --- /dev/null +++ b/webapp/Cargo.toml @@ -0,0 +1,21 @@ +[package] +description = "Parity WebApplications crate" +name = "ethcore-webapp" +version = "1.1.0" +license = "GPL-3.0" +authors = ["Ethcore . + +//! Ethcore Webapplications for Parity +#![warn(missing_docs)] +#![cfg_attr(feature="nightly", plugin(clippy))] + +#[macro_use] +extern crate log; +extern crate hyper; +extern crate iron; +extern crate jsonrpc_core; +extern crate jsonrpc_http_server; +extern crate ethcore_rpc as rpc; +extern crate ethcore_util as util; + +use rpc::v1::*; +use std::sync::Arc; +use std::thread; + +use util::panics::PanicHandler; +use iron::request::Url; +use self::jsonrpc_core::{IoHandler, IoDelegate}; +use jsonrpc_http_server::ServerHandler; + +/// Http server. +pub struct WebappServer { + handler: Arc, +} + +impl WebappServer { + /// Construct new http server object + pub fn new() -> Self { + let server = WebappServer { + handler: Arc::new(IoHandler::new()), + }; + // TODO add more + server.add_delegate(Web3Client::new().to_delegate()); + + server + } + + /// Add io delegate. + fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { + self.handler.add_delegate(delegate); + } + + /// Start server asynchronously in new thread and returns panic handler. + pub fn start_http(&self, addr: &str, threads: usize) -> Arc { + let addr = addr.to_owned(); + let panic_handler = PanicHandler::new_in_arc(); + let ph = panic_handler.clone(); + let handler = self.handler.clone(); + + thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { + let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; + let rpc = ServerHandler::new(handler, cors_domain); + let router = Router::new(rpc); + + ph.catch_panic(move || { + hyper::Server::http(addr.as_ref() as &str).unwrap() + .handle_threads(router, threads) + .unwrap(); + }).unwrap() + }).expect("Error while creating jsonrpc http thread"); + + panic_handler + } +} + + +struct Router { + rpc: ServerHandler, + // admin: Page, + // wallet: Page, + // mist: Page, +} + +impl Router { + pub fn new(rpc: ServerHandler) -> Self { + Router { + rpc: rpc, + // admin: Page { app: AdminApp::default() }, + // wallet: Page { app: WalletApp::default() }, + // mist: Page { app: MistApp::default() }, + } + } + + fn extract_url(req: &hyper::server::Request) -> Option { + match req.uri { + hyper::uri::RequestUri::AbsoluteUri(ref url) => { + match Url::from_generic_url(url.clone()) { + Ok(url) => Some(url), + _ => None, + } + }, + hyper::uri::RequestUri::AbsolutePath(ref path) => { + // Attempt to prepend the Host header (mandatory in HTTP/1.1) + let url_string = match req.headers.get::() { + Some(ref host) => { + format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) + }, + None => return None + }; + + match Url::parse(&url_string) { + Ok(url) => Some(url), + _ => None, + } + } + _ => None, + } + } + + fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { + let url = Router::extract_url(&req); + match url { + Some(url) => { + let part = url.path[0].clone(); + let url = url.path[1..].join("/"); + req.uri = hyper::uri::RequestUri::AbsolutePath(url); + (Some(part), req) + }, + None => { + (None, req) + } + } + } +} + +impl hyper::server::Handler for Router { + fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, res: hyper::server::Response<'a>) { + let (path, req) = Router::extract_request_path(req); + match path { + // Some(ref url) if url == "admin" => { + // self.admin.handle(req, res); + // }, + // Some(ref url) if url == "wallet" => { + // self.wallet.handle(req, res); + // }, + // Some(ref url) if url == "mist" => { + // self.mist.handle(req, res); + // }, + _ => self.rpc.handle(req, res), + } + } +} From 5d6ca1498e8c1943b331d2c7fa43e7a6cc8c85da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 11:06:49 +0200 Subject: [PATCH 35/52] CLI options to run webapp server --- parity/main.rs | 31 ++++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 2141a5795..ecd72e0ff 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -120,7 +120,7 @@ Networking Options: string or input to SHA3 operation. API and Console Options: - -j --jsonrpc Enable the JSON-RPC API sever. + -j --jsonrpc Enable the JSON-RPC API server. --jsonrpc-interface IP Specify the hostname portion of the JSONRPC API server, IP should be an interface's IP address, or all (all interfaces) or local [default: local]. @@ -132,6 +132,10 @@ API and Console Options: interface. APIS is a comma-delimited list of API name. Possible name are web3, eth and net. [default: web3,eth,net,personal]. + -w --webap Enable the web applications server (e.g. status page). + --webapp-port PORT Specify the port portion of the WebApps server + [default: 8080]. + Sealing/Mining Options: --usd-per-tx USD Amount of USD to be paid for a basic transaction @@ -216,6 +220,8 @@ struct Args { flag_jsonrpc_port: u16, flag_jsonrpc_cors: String, flag_jsonrpc_apis: String, + flag_webapp: bool, + flag_webapp_port: u16, flag_author: String, flag_usd_per_tx: String, flag_usd_per_eth: String, @@ -295,6 +301,13 @@ fn setup_rpc_server( } Some(server.start_http(url, cors_domain, ::num_cpus::get())) } +#[cfg(feature = "webapp")] +fn setup_webapp_server( + url: &str +) -> Option> { + let server = webapp::WebappServer::new(); + Some(server.start_http(url, ::num_cpus::get())) +} #[cfg(not(feature = "rpc"))] fn setup_rpc_server( @@ -309,6 +322,13 @@ fn setup_rpc_server( None } +#[cfg(not(feature = "webapp"))] +fn setup_webapp_server( + _url: &str +) -> Option> { + None +} + fn print_version() { println!("\ Parity @@ -611,6 +631,15 @@ impl Configuration { } } + if self.args.flag_webapp { + let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); + setup_webapp_server( + &url, + ).map(|handler| { + panic_handler.forward_from(handler.deref()); + }); + } + // Register IO handler let io_handler = Arc::new(ClientIoHandler { client: service.client(), From ad37b7fd2a5b3297904aa4d90974390d01e196fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:10:26 +0200 Subject: [PATCH 36/52] Adding webapps router --- Cargo.lock | 15 +++++ parity/main.rs | 5 +- webapp/Cargo.toml | 4 ++ webapp/src/apps.rs | 37 ++++++++++++ webapp/src/lib.rs | 118 ++++++--------------------------------- webapp/src/page/mod.rs | 67 ++++++++++++++++++++++ webapp/src/router/mod.rs | 89 +++++++++++++++++++++++++++++ 7 files changed, 233 insertions(+), 102 deletions(-) create mode 100644 webapp/src/apps.rs create mode 100644 webapp/src/page/mod.rs create mode 100644 webapp/src/router/mod.rs diff --git a/Cargo.lock b/Cargo.lock index 9783413d4..62093c293 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,8 @@ dependencies = [ "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", + "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] [[package]] @@ -701,6 +703,19 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-wallet" +version = "0.1.0" +source = "git+https://github.com/tomusdrw/parity-wallet.git#9b0253f5cb88b31417450ca8be708cab2e437dfc" +dependencies = [ + "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", +] + +[[package]] +name = "parity-webapp" +version = "0.1.0" +source = "git+https://github.com/tomusdrw/parity-webapp.git#a24297256bae0ae0712c6478cd1ad681828b3800" + [[package]] name = "plugin" version = "0.2.6" diff --git a/parity/main.rs b/parity/main.rs index ecd72e0ff..b8498d520 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -132,7 +132,7 @@ API and Console Options: interface. APIS is a comma-delimited list of API name. Possible name are web3, eth and net. [default: web3,eth,net,personal]. - -w --webap Enable the web applications server (e.g. status page). + -w --webapp Enable the web applications server (e.g. status page). --webapp-port PORT Specify the port portion of the WebApps server [default: 8080]. @@ -305,7 +305,10 @@ fn setup_rpc_server( fn setup_webapp_server( url: &str ) -> Option> { + use rpc::v1::*; + let server = webapp::WebappServer::new(); + server.add_delegate(Web3Client::new().to_delegate()); Some(server.start_http(url, ::num_cpus::get())) } diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index f6503e163..377b0b556 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -15,7 +15,11 @@ hyper = { version = "0.8", default-features = false } iron = { version = "0.3" } ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } +parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } +# List of apps +parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true } clippy = { version = "0.0.61", optional = true} [features] +default = ["parity-wallet"] dev = ["clippy", "ethcore-rpc/dev", "ethcore-util/dev"] diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs new file mode 100644 index 000000000..6a43decab --- /dev/null +++ b/webapp/src/apps.rs @@ -0,0 +1,37 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::collections::HashMap; +use page::{Page, PageHandler}; + +extern crate parity_wallet; + +pub type Pages = HashMap>; + +pub fn all_pages() -> Pages { + let mut pages = Pages::new(); + wallet_page(&mut pages); + pages +} + +#[cfg(feature="parity-wallet")] +fn wallet_page(pages: &mut Pages) { + pages.insert("wallet".to_owned(), Box::new(PageHandler { app: parity_wallet::App::default() })); +} + +#[cfg(not(feature="parity-wallet"))] +fn wallet_page(_pages: &mut Pages) {} + diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 8fd20fdeb..7a3620e1a 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -26,16 +26,17 @@ extern crate jsonrpc_core; extern crate jsonrpc_http_server; extern crate ethcore_rpc as rpc; extern crate ethcore_util as util; +extern crate parity_webapp; -use rpc::v1::*; use std::sync::Arc; -use std::thread; - use util::panics::PanicHandler; -use iron::request::Url; use self::jsonrpc_core::{IoHandler, IoDelegate}; use jsonrpc_http_server::ServerHandler; +mod apps; +mod page; +mod router; + /// Http server. pub struct WebappServer { handler: Arc, @@ -44,117 +45,32 @@ pub struct WebappServer { impl WebappServer { /// Construct new http server object pub fn new() -> Self { - let server = WebappServer { + WebappServer { handler: Arc::new(IoHandler::new()), - }; - // TODO add more - server.add_delegate(Web3Client::new().to_delegate()); - - server + } } /// Add io delegate. - fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { + pub fn add_delegate(&self, delegate: IoDelegate) where D: Send + Sync + 'static { self.handler.add_delegate(delegate); } - /// Start server asynchronously in new thread and returns panic handler. + /// Start server asynchronously and returns panic handler. pub fn start_http(&self, addr: &str, threads: usize) -> Arc { let addr = addr.to_owned(); let panic_handler = PanicHandler::new_in_arc(); - let ph = panic_handler.clone(); let handler = self.handler.clone(); - thread::Builder::new().name("jsonrpc_http".to_string()).spawn(move || { - let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; - let rpc = ServerHandler::new(handler, cors_domain); - let router = Router::new(rpc); + let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; + let rpc = ServerHandler::new(handler, cors_domain); + let router = router::Router::new(rpc, apps::all_pages()); - ph.catch_panic(move || { - hyper::Server::http(addr.as_ref() as &str).unwrap() - .handle_threads(router, threads) - .unwrap(); - }).unwrap() - }).expect("Error while creating jsonrpc http thread"); + panic_handler.catch_panic(move || { + hyper::Server::http(addr.as_ref() as &str).unwrap() + .handle_threads(router, threads) + .unwrap(); + }).unwrap(); panic_handler } } - - -struct Router { - rpc: ServerHandler, - // admin: Page, - // wallet: Page, - // mist: Page, -} - -impl Router { - pub fn new(rpc: ServerHandler) -> Self { - Router { - rpc: rpc, - // admin: Page { app: AdminApp::default() }, - // wallet: Page { app: WalletApp::default() }, - // mist: Page { app: MistApp::default() }, - } - } - - fn extract_url(req: &hyper::server::Request) -> Option { - match req.uri { - hyper::uri::RequestUri::AbsoluteUri(ref url) => { - match Url::from_generic_url(url.clone()) { - Ok(url) => Some(url), - _ => None, - } - }, - hyper::uri::RequestUri::AbsolutePath(ref path) => { - // Attempt to prepend the Host header (mandatory in HTTP/1.1) - let url_string = match req.headers.get::() { - Some(ref host) => { - format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) - }, - None => return None - }; - - match Url::parse(&url_string) { - Ok(url) => Some(url), - _ => None, - } - } - _ => None, - } - } - - fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { - let url = Router::extract_url(&req); - match url { - Some(url) => { - let part = url.path[0].clone(); - let url = url.path[1..].join("/"); - req.uri = hyper::uri::RequestUri::AbsolutePath(url); - (Some(part), req) - }, - None => { - (None, req) - } - } - } -} - -impl hyper::server::Handler for Router { - fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, res: hyper::server::Response<'a>) { - let (path, req) = Router::extract_request_path(req); - match path { - // Some(ref url) if url == "admin" => { - // self.admin.handle(req, res); - // }, - // Some(ref url) if url == "wallet" => { - // self.wallet.handle(req, res); - // }, - // Some(ref url) if url == "mist" => { - // self.mist.handle(req, res); - // }, - _ => self.rpc.handle(req, res), - } - } -} diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs new file mode 100644 index 000000000..94a25769e --- /dev/null +++ b/webapp/src/page/mod.rs @@ -0,0 +1,67 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +use std::io::Write; +use hyper::uri::RequestUri; +use hyper::server; +use hyper::header; +use hyper::status::StatusCode; +use parity_webapp::WebApp; + +pub trait Page : Send + Sync { + fn serve_file(&self, mut path: &str, mut res: server::Response); +} + +pub struct PageHandler { + pub app: T +} + +impl Page for PageHandler { + fn serve_file(&self, mut path: &str, mut res: server::Response) { + // Support index file + if path == "" { + path = "index.html" + } + let file = self.app.file(path); + if let Some(f) = file { + *res.status_mut() = StatusCode::Ok; + res.headers_mut().set(header::ContentType(f.content_type.parse().unwrap())); + + let _ = match res.start() { + Ok(mut raw_res) => { + for chunk in f.content.chunks(1024 * 20) { + let _ = raw_res.write(chunk); + } + raw_res.end() + }, + Err(_) => { + println!("Error while writing response."); + Ok(()) + } + }; + } + } +} + +impl server::Handler for Page { + fn handle(&self, req: server::Request, mut res: server::Response) { + *res.status_mut() = StatusCode::NotFound; + + if let RequestUri::AbsolutePath(ref path) = req.uri { + self.serve_file(path, res); + } + } +} diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs new file mode 100644 index 000000000..4ed32fab9 --- /dev/null +++ b/webapp/src/router/mod.rs @@ -0,0 +1,89 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Router implementation + +use hyper; +use apps::Pages; +use iron::request::Url; +use jsonrpc_http_server::ServerHandler; + +pub struct Router { + rpc: ServerHandler, + pages: Pages, +} + +impl hyper::server::Handler for Router { + fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, res: hyper::server::Response<'a>) { + let (path, req) = Router::extract_request_path(req); + match path { + Some(ref url) if self.pages.contains_key(url) => { + self.pages.get(url).unwrap().handle(req, res); + } + _ => self.rpc.handle(req, res), + } + } +} + +impl Router { + pub fn new(rpc: ServerHandler, pages: Pages) -> Self { + Router { + rpc: rpc, + pages: pages, + } + } + + fn extract_url(req: &hyper::server::Request) -> Option { + match req.uri { + hyper::uri::RequestUri::AbsoluteUri(ref url) => { + match Url::from_generic_url(url.clone()) { + Ok(url) => Some(url), + _ => None, + } + }, + hyper::uri::RequestUri::AbsolutePath(ref path) => { + // Attempt to prepend the Host header (mandatory in HTTP/1.1) + let url_string = match req.headers.get::() { + Some(ref host) => { + format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) + }, + None => return None + }; + + match Url::parse(&url_string) { + Ok(url) => Some(url), + _ => None, + } + } + _ => None, + } + } + + fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { + let url = Router::extract_url(&req); + match url { + Some(url) => { + let part = url.path[0].clone(); + let url = url.path[1..].join("/"); + req.uri = hyper::uri::RequestUri::AbsolutePath(url); + (Some(part), req) + }, + None => { + (None, req) + } + } + } +} From da05aa51fefe34c4356d4e26fa9021d6b3f83f43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:12:02 +0200 Subject: [PATCH 37/52] Adding all APIs to webapp rpc server --- parity/main.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/parity/main.rs b/parity/main.rs index b8498d520..0e82ea4d3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -303,12 +303,20 @@ fn setup_rpc_server( } #[cfg(feature = "webapp")] fn setup_webapp_server( + client: Arc, + sync: Arc, + secret_store: Arc, + miner: Arc, url: &str ) -> Option> { use rpc::v1::*; let server = webapp::WebappServer::new(); server.add_delegate(Web3Client::new().to_delegate()); + server.add_delegate(NetClient::new(&sync).to_delegate()); + server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); + server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); + server.add_delegate(PersonalClient::new(&secret_store).to_delegate()); Some(server.start_http(url, ::num_cpus::get())) } @@ -327,6 +335,10 @@ fn setup_rpc_server( #[cfg(not(feature = "webapp"))] fn setup_webapp_server( + _client: Arc, + _sync: Arc, + _secret_store: Arc, + _miner: Arc, _url: &str ) -> Option> { None @@ -637,6 +649,10 @@ impl Configuration { if self.args.flag_webapp { let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); setup_webapp_server( + service.client(), + sync.clone(), + account_service.clone(), + miner.clone(), &url, ).map(|handler| { panic_handler.forward_from(handler.deref()); From 1e9e0c32faf5987717a34a875fd778218592860e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:13:06 +0200 Subject: [PATCH 38/52] Disabling webapp server by default --- Cargo.toml | 2 +- parity/main.rs | 29 +++++++++++++---------------- 2 files changed, 14 insertions(+), 17 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3fe923db7..276159f84 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ version = "0.8" default-features = false [features] -default = ["rpc", "webapp"] +default = ["rpc"] rpc = ["ethcore-rpc"] webapp = ["ethcore-webapp"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev", diff --git a/parity/main.rs b/parity/main.rs index 0e82ea4d3..088a61550 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -281,7 +281,7 @@ fn setup_rpc_server( url: &str, cors_domain: &str, apis: Vec<&str> -) -> Option> { +) -> Arc { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -299,7 +299,7 @@ fn setup_rpc_server( } } } - Some(server.start_http(url, cors_domain, ::num_cpus::get())) + server.start_http(url, cors_domain, ::num_cpus::get()) } #[cfg(feature = "webapp")] fn setup_webapp_server( @@ -308,7 +308,7 @@ fn setup_webapp_server( secret_store: Arc, miner: Arc, url: &str -) -> Option> { +) -> Arc { use rpc::v1::*; let server = webapp::WebappServer::new(); @@ -317,7 +317,7 @@ fn setup_webapp_server( server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); server.add_delegate(EthFilterClient::new(&client, &miner).to_delegate()); server.add_delegate(PersonalClient::new(&secret_store).to_delegate()); - Some(server.start_http(url, ::num_cpus::get())) + server.start_http(url, ::num_cpus::get()) } #[cfg(not(feature = "rpc"))] @@ -329,8 +329,8 @@ fn setup_rpc_server( _url: &str, _cors_domain: &str, _apis: Vec<&str> -) -> Option> { - None +) -> Arc { + die!("Your Parity version has been compiled without JSON-RPC support.") } #[cfg(not(feature = "webapp"))] @@ -340,8 +340,8 @@ fn setup_webapp_server( _secret_store: Arc, _miner: Arc, _url: &str -) -> Option> { - None +) -> Arc { + die!("Your Parity version has been compiled without WebApps support.") } fn print_version() { @@ -632,7 +632,7 @@ impl Configuration { let cors = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - let server_handler = setup_rpc_server( + let handler = setup_rpc_server( service.client(), sync.clone(), account_service.clone(), @@ -641,22 +641,19 @@ impl Configuration { cors, apis.split(',').collect() ); - if let Some(handler) = server_handler { - panic_handler.forward_from(handler.deref()); - } + panic_handler.forward_from(handler.deref()); } if self.args.flag_webapp { let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); - setup_webapp_server( + let handler = setup_webapp_server( service.client(), sync.clone(), account_service.clone(), miner.clone(), &url, - ).map(|handler| { - panic_handler.forward_from(handler.deref()); - }); + ); + panic_handler.forward_from(handler.deref()); } // Register IO handler From 91f1f4c174ab3216f4ec77bdfb64d47c2eff9611 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:20:35 +0200 Subject: [PATCH 39/52] Changing default setup to be safer for now --- parity/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 088a61550..c047e5eb3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -645,7 +645,7 @@ impl Configuration { } if self.args.flag_webapp { - let url = format!("0.0.0.0:{}", self.args.flag_webapp_port); + let url = format!("127.0.0.1:{}", self.args.flag_webapp_port); let handler = setup_webapp_server( service.client(), sync.clone(), From ccd417f713b793399d8325216642fb0ccc7d2840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:27:54 +0200 Subject: [PATCH 40/52] Reverting order of shutdown event --- util/src/io/service.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/io/service.rs b/util/src/io/service.rs index 24cc1181a..95aa19e47 100644 --- a/util/src/io/service.rs +++ b/util/src/io/service.rs @@ -231,8 +231,8 @@ impl Handler for IoManager where Message: Send + Clone + Sync fn notify(&mut self, event_loop: &mut EventLoop, msg: Self::Message) { match msg { IoMessage::Shutdown => { - event_loop.shutdown(); self.workers.clear(); + event_loop.shutdown(); }, IoMessage::AddHandler { handler } => { let handler_id = { From d1e3c633e5de6e88b9596415361d2dc8f2b5e310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:49:20 +0200 Subject: [PATCH 41/52] Fixing compilation with rpc feature disabled --- parity/main.rs | 55 ++++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 06710a3a4..11f9dd91d 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -43,6 +43,7 @@ extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; +use std::any::Any; use std::io::{BufRead, BufReader}; use std::fs::File; use std::net::{SocketAddr, IpAddr}; @@ -270,8 +271,10 @@ fn setup_rpc_server( sync: Arc, secret_store: Arc, miner: Arc, + url: &str, + cors_domain: &str, apis: Vec<&str> -) -> Option { +) -> Option> { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -289,7 +292,12 @@ fn setup_rpc_server( } } } - Some(server) + let start_result = server.start_http(url, cors_domain, ::num_cpus::get()); + match start_result { + Err(rpc::RpcServerError::IoError(err)) => die_with_io_error(err), + Err(e) => die!("{:?}", e), + Ok(handle) => Some(Box::new(handle)), + } } #[cfg(not(feature = "rpc"))] @@ -298,9 +306,11 @@ fn setup_rpc_server( _sync: Arc, _secret_store: Arc, _miner: Arc, + _url: &str, + _cors_domain: &str, _apis: Vec<&str> -) -> Option> { - None +) -> ! { + die!("Your Parity version has been compiled without JSON-RPC support.") } fn print_version() { @@ -582,20 +592,7 @@ impl Configuration { // Setup rpc let rpc_server = if self.args.flag_jsonrpc || self.args.flag_rpc { - // TODO: use this as the API list. let apis = self.args.flag_rpcapi.as_ref().unwrap_or(&self.args.flag_jsonrpc_apis); - setup_rpc_server( - service.client(), - sync.clone(), - account_service.clone(), - miner.clone(), - apis.split(',').collect() - ) - } else { - None - }; - - let rpc_handle = rpc_server.map(|server| { let url = format!("{}:{}", match self.args.flag_rpcaddr.as_ref().unwrap_or(&self.args.flag_jsonrpc_interface).as_str() { "all" => "0.0.0.0", @@ -606,13 +603,19 @@ impl Configuration { ); SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); let cors_domain = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); - let start_result = server.start_http(&url, cors_domain, ::num_cpus::get()); - match start_result { - Ok(handle) => handle, - Err(rpc::RpcServerError::IoError(err)) => die_with_io_error(err), - Err(e) => die!("{:?}", e), - } - }); + + setup_rpc_server( + service.client(), + sync.clone(), + account_service.clone(), + miner.clone(), + &url, + &cors_domain, + apis.split(',').collect() + ) + } else { + None + }; // Register IO handler let io_handler = Arc::new(ClientIoHandler { @@ -624,11 +627,11 @@ impl Configuration { service.io().register_handler(io_handler).expect("Error registering IO handler"); // Handle exit - wait_for_exit(panic_handler, rpc_handle); + wait_for_exit(panic_handler, rpc_server); } } -fn wait_for_exit(panic_handler: Arc, _rpc_handle: Option) { +fn wait_for_exit(panic_handler: Arc, _rpc_server: Option>) { let exit = Arc::new(Condvar::new()); // Handle possible exits From 2adeb9fe8800f8edb6f54bff03658f1cb9d9cbd9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 12:55:06 +0200 Subject: [PATCH 42/52] Removing Option from setup_rpc_server method return type --- parity/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/parity/main.rs b/parity/main.rs index 11f9dd91d..011d761ef 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -274,7 +274,7 @@ fn setup_rpc_server( url: &str, cors_domain: &str, apis: Vec<&str> -) -> Option> { +) -> Box { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -296,7 +296,7 @@ fn setup_rpc_server( match start_result { Err(rpc::RpcServerError::IoError(err)) => die_with_io_error(err), Err(e) => die!("{:?}", e), - Ok(handle) => Some(Box::new(handle)), + Ok(handle) => Box::new(handle), } } @@ -604,7 +604,7 @@ impl Configuration { SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); let cors_domain = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); - setup_rpc_server( + Some(setup_rpc_server( service.client(), sync.clone(), account_service.clone(), @@ -612,7 +612,7 @@ impl Configuration { &url, &cors_domain, apis.split(',').collect() - ) + )) } else { None }; From 6279237c86abe721da278f189da7c32d5ae48f73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 13:15:59 +0200 Subject: [PATCH 43/52] Adding documentation --- webapp/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 6150a2b39..104a8ce45 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -83,7 +83,9 @@ impl Drop for Listening { /// Webapp Server startup error #[derive(Debug)] pub enum WebappServerError { + /// Wrapped `std::io::Error` IoError(std::io::Error), + /// Other `hyper` error Other(hyper::error::Error), } From 8074fee28c806857f7b604f3562f1a3e8f6bfecb Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 7 Apr 2016 14:24:52 +0200 Subject: [PATCH 44/52] Use new json RPC server --- Cargo.lock | 60 ++++++++++++++++++++++++++++++++++++++++++++++---- parity/main.rs | 20 ++++++++++------- rpc/Cargo.toml | 2 +- rpc/src/lib.rs | 12 +++++----- 4 files changed, 74 insertions(+), 20 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7554e3b52..71b6873f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -246,7 +246,7 @@ dependencies = [ "ethminer 1.1.0", "ethsync 1.1.0", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", + "jsonrpc-http-server 5.0.0 (git+https://github.com/debris/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -415,6 +415,27 @@ dependencies = [ "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "hyper" +version = "0.9.0-mio" +source = "git+https://github.com/hyperium/hyper?branch=mio#d55a70dc56dac1f0f03bc4c3a83db0314d48e69a" +dependencies = [ + "cookie 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "httparse 1.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mime 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rotor 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "traitobject 0.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "typeable 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)", + "url 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", + "vecio 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "igd" version = "0.4.2" @@ -453,10 +474,10 @@ dependencies = [ [[package]] name = "jsonrpc-http-server" -version = "4.0.0" -source = "git+https://github.com/tomusdrw/jsonrpc-http-server.git#46bd4e7cf8352e0efc940cf76d3dff99f1a3da15" +version = "5.0.0" +source = "git+https://github.com/debris/jsonrpc-http-server.git#76fa443982b40665721fe6b1ece42fc0a53be996" dependencies = [ - "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.9.0-mio (git+https://github.com/hyperium/hyper?branch=mio)", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -696,6 +717,11 @@ dependencies = [ "syntex_syntax 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "quick-error" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "quine-mc_cluskey" version = "0.2.2" @@ -745,6 +771,18 @@ dependencies = [ "librocksdb-sys 0.2.3 (git+https://github.com/arkpar/rust-rocksdb.git)", ] +[[package]] +name = "rotor" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "mio 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "quick-error 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rpassword" version = "0.1.3" @@ -1000,6 +1038,15 @@ dependencies = [ "rustc-serialize 0.3.18 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vecio" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "vergen" version = "0.1.0" @@ -1009,6 +1056,11 @@ dependencies = [ "time 0.1.34 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "void" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "winapi" version = "0.2.6" diff --git a/parity/main.rs b/parity/main.rs index 011d761ef..192f88132 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -43,7 +43,6 @@ extern crate rpassword; #[cfg(feature = "rpc")] extern crate ethcore_rpc as rpc; -use std::any::Any; use std::io::{BufRead, BufReader}; use std::fs::File; use std::net::{SocketAddr, IpAddr}; @@ -64,6 +63,8 @@ use ethminer::{Miner, MinerService}; use docopt::Docopt; use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; +#[cfg(feature = "rpc")] +use rpc::Server as RpcServer; mod price_info; @@ -271,10 +272,10 @@ fn setup_rpc_server( sync: Arc, secret_store: Arc, miner: Arc, - url: &str, + url: &SocketAddr, cors_domain: &str, apis: Vec<&str> -) -> Box { +) -> RpcServer { use rpc::v1::*; let server = rpc::RpcServer::new(); @@ -292,14 +293,17 @@ fn setup_rpc_server( } } } - let start_result = server.start_http(url, cors_domain, ::num_cpus::get()); + let start_result = server.start_http(url, cors_domain); match start_result { Err(rpc::RpcServerError::IoError(err)) => die_with_io_error(err), Err(e) => die!("{:?}", e), - Ok(handle) => Box::new(handle), + Ok(server) => server, } } +#[cfg(not(feature = "rpc"))] +struct RpcServer; + #[cfg(not(feature = "rpc"))] fn setup_rpc_server( _client: Arc, @@ -601,7 +605,7 @@ impl Configuration { }, self.args.flag_rpcport.unwrap_or(self.args.flag_jsonrpc_port) ); - SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); + let addr = SocketAddr::from_str(&url).unwrap_or_else(|_| die!("{}: Invalid JSONRPC listen host/port given.", url)); let cors_domain = self.args.flag_rpccorsdomain.as_ref().unwrap_or(&self.args.flag_jsonrpc_cors); Some(setup_rpc_server( @@ -609,7 +613,7 @@ impl Configuration { sync.clone(), account_service.clone(), miner.clone(), - &url, + &addr, &cors_domain, apis.split(',').collect() )) @@ -631,7 +635,7 @@ impl Configuration { } } -fn wait_for_exit(panic_handler: Arc, _rpc_server: Option>) { +fn wait_for_exit(panic_handler: Arc, _rpc_server: Option) { let exit = Arc::new(Condvar::new()); // Handle possible exits diff --git a/rpc/Cargo.toml b/rpc/Cargo.toml index 4c62a45c1..183b0fa9f 100644 --- a/rpc/Cargo.toml +++ b/rpc/Cargo.toml @@ -13,7 +13,7 @@ log = "0.3" serde = "0.7.0" serde_json = "0.7.0" jsonrpc-core = "2.0" -jsonrpc-http-server = { git = "https://github.com/tomusdrw/jsonrpc-http-server.git" } +jsonrpc-http-server = { git = "https://github.com/debris/jsonrpc-http-server.git" } ethcore-util = { path = "../util" } ethcore = { path = "../ethcore" } ethash = { path = "../ethash" } diff --git a/rpc/src/lib.rs b/rpc/src/lib.rs index 4de405211..f059750d2 100644 --- a/rpc/src/lib.rs +++ b/rpc/src/lib.rs @@ -33,9 +33,10 @@ extern crate ethminer; extern crate transient_hashmap; use std::sync::Arc; +use std::net::SocketAddr; use self::jsonrpc_core::{IoHandler, IoDelegate}; -pub use jsonrpc_http_server::{Listening, RpcServerError}; +pub use jsonrpc_http_server::{Server, RpcServerError}; pub mod v1; /// Http server. @@ -56,12 +57,9 @@ impl RpcServer { self.handler.add_delegate(delegate); } - /// Start server asynchronously and returns result with `Listening` handle on success or an error. - pub fn start_http(&self, addr: &str, cors_domain: &str, threads: usize) -> Result { - let addr = addr.to_owned(); + /// Start server asynchronously and returns result with `Server` handle on success or an error. + pub fn start_http(&self, addr: &SocketAddr, cors_domain: &str) -> Result { let cors_domain = cors_domain.to_owned(); - let server = jsonrpc_http_server::Server::new(self.handler.clone()); - - server.start(addr.as_ref(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain), threads) + Server::start(addr, self.handler.clone(), jsonrpc_http_server::AccessControlAllowOrigin::Value(cors_domain)) } } From ed633bd0b701412129f471c5fd433f83cff0dc8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 15:14:39 +0200 Subject: [PATCH 45/52] Adding StatusPage and main page support --- Cargo.lock | 9 +++++++++ webapp/Cargo.toml | 1 + webapp/src/apps.rs | 10 +++++++--- webapp/src/lib.rs | 2 +- webapp/src/router/mod.rs | 19 +++++++++++++++---- 5 files changed, 33 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index af361da49..feda5db77 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,6 +321,7 @@ dependencies = [ "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", + "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] @@ -693,6 +694,14 @@ name = "odds" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "parity-status" +version = "0.1.1" +source = "git+https://github.com/tomusdrw/parity-status.git#31cdfd631af970b58c4ddb4e7d7e927af2e07ce3" +dependencies = [ + "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", +] + [[package]] name = "parity-wallet" version = "0.1.0" diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index 377b0b556..b377bb991 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -17,6 +17,7 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } # List of apps +parity-status = { git = "https://github.com/tomusdrw/parity-status.git" } parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true } clippy = { version = "0.0.61", optional = true} diff --git a/webapp/src/apps.rs b/webapp/src/apps.rs index 6a43decab..364186d04 100644 --- a/webapp/src/apps.rs +++ b/webapp/src/apps.rs @@ -17,21 +17,25 @@ use std::collections::HashMap; use page::{Page, PageHandler}; +extern crate parity_status; extern crate parity_wallet; pub type Pages = HashMap>; +pub fn main_page() -> Box { + Box::new(PageHandler { app: parity_status::App::default() }) +} + pub fn all_pages() -> Pages { let mut pages = Pages::new(); wallet_page(&mut pages); pages } -#[cfg(feature="parity-wallet")] +#[cfg(feature = "parity-wallet")] fn wallet_page(pages: &mut Pages) { pages.insert("wallet".to_owned(), Box::new(PageHandler { app: parity_wallet::App::default() })); } -#[cfg(not(feature="parity-wallet"))] +#[cfg(not(feature = "parity-wallet"))] fn wallet_page(_pages: &mut Pages) {} - diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index 104a8ce45..d8e524be8 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -60,7 +60,7 @@ impl WebappServer { let cors_domain = jsonrpc_http_server::AccessControlAllowOrigin::Null; let rpc = ServerHandler::new(handler, cors_domain); - let router = router::Router::new(rpc, apps::all_pages()); + let router = router::Router::new(rpc, apps::main_page(), apps::all_pages()); try!(hyper::Server::http(addr.as_ref() as &str)) .handle_threads(router, threads) diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index 4ed32fab9..fad8593b9 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -17,12 +17,14 @@ //! Router implementation use hyper; +use page::Page; use apps::Pages; use iron::request::Url; use jsonrpc_http_server::ServerHandler; pub struct Router { rpc: ServerHandler, + main_page: Box, pages: Pages, } @@ -33,15 +35,19 @@ impl hyper::server::Handler for Router { Some(ref url) if self.pages.contains_key(url) => { self.pages.get(url).unwrap().handle(req, res); } - _ => self.rpc.handle(req, res), + _ if req.method == hyper::method::Method::Post => { + self.rpc.handle(req, res) + }, + _ => self.main_page.handle(req, res), } } } impl Router { - pub fn new(rpc: ServerHandler, pages: Pages) -> Self { + pub fn new(rpc: ServerHandler, main_page: Box, pages: Pages) -> Self { Router { rpc: rpc, + main_page: main_page, pages: pages, } } @@ -75,13 +81,18 @@ impl Router { fn extract_request_path<'a, 'b>(mut req: hyper::server::Request<'a, 'b>) -> (Option, hyper::server::Request<'a, 'b>) { let url = Router::extract_url(&req); match url { - Some(url) => { + Some(ref url) if url.path.len() > 1 => { let part = url.path[0].clone(); let url = url.path[1..].join("/"); req.uri = hyper::uri::RequestUri::AbsolutePath(url); (Some(part), req) }, - None => { + Some(url) => { + let url = url.path.join("/"); + req.uri = hyper::uri::RequestUri::AbsolutePath(url); + (None, req) + }, + _ => { (None, req) } } From 4569c251275e8858bf56c109c5be68d24be95260 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 15:59:45 +0200 Subject: [PATCH 46/52] Specifying webapp interface --- parity/main.rs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/parity/main.rs b/parity/main.rs index 062d62244..945e0bdad 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -136,6 +136,9 @@ API and Console Options: -w --webapp Enable the web applications server (e.g. status page). --webapp-port PORT Specify the port portion of the WebApps server [default: 8080]. + --webapp-interface IP Specify the hostname portion of the WebApps + server, IP should be an interface's IP address, or + all (all interfaces) or local [default: local]. Sealing/Mining Options: @@ -223,6 +226,7 @@ struct Args { flag_jsonrpc_apis: String, flag_webapp: bool, flag_webapp_port: u16, + flag_webapp_interface: String, flag_author: String, flag_usd_per_tx: String, flag_usd_per_eth: String, @@ -662,7 +666,14 @@ impl Configuration { }; let webapp_server = if self.args.flag_webapp { - let url = format!("127.0.0.1:{}", self.args.flag_webapp_port); + let url = format!("{}:{}", + match self.args.flag_webapp_interface.as_str() { + "all" => "0.0.0.0", + "local" => "127.0.0.1", + x => x, + }, + self.args.flag_webapp_port + ); Some(setup_webapp_server( service.client(), sync.clone(), From b7c790d7410ccfebaece73e4f1b29f7c7d43d66f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 16:22:02 +0200 Subject: [PATCH 47/52] Disabling rpc until we switch to async hyper --- Cargo.lock | 2 +- parity/main.rs | 6 +++--- webapp/Cargo.toml | 2 +- webapp/src/router/mod.rs | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4c4f5970..f6ce8941d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,7 +319,7 @@ dependencies = [ "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git)", + "jsonrpc-http-server 5.0.0 (git+https://github.com/debris/jsonrpc-http-server.git)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", diff --git a/parity/main.rs b/parity/main.rs index 8dcd0c067..7ea8282f3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -67,7 +67,7 @@ use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; #[cfg(feature = "rpc")] use rpc::Server as RpcServer; -use webapp::WebappServer; +use webapp::Listening as WebappServer; mod price_info; @@ -324,7 +324,7 @@ fn setup_webapp_server( ) -> WebappServer { use rpc::v1::*; - let server = WebappServer::new(); + let server = webapp::WebappServer::new(); server.add_delegate(Web3Client::new().to_delegate()); server.add_delegate(NetClient::new(&sync).to_delegate()); server.add_delegate(EthClient::new(&client, &sync, &secret_store, &miner).to_delegate()); @@ -334,7 +334,7 @@ fn setup_webapp_server( match start_result { Err(webapp::WebappServerError::IoError(err)) => die_with_io_error(err), Err(e) => die!("{:?}", e), - Ok(handle) => Box::new(handle), + Ok(handle) => handle, } } diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index b377bb991..28df2b8f8 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore { - self.rpc.handle(req, res) + // self.rpc.handle(req, res) }, _ => self.main_page.handle(req, res), } From 9bd41761fcd8750d64029b757661ce7a5734b590 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 16:30:49 +0200 Subject: [PATCH 48/52] Reverting back to old-hyper version of rpc --- Cargo.lock | 12 +++++++++++- parity/main.rs | 1 + webapp/Cargo.toml | 2 +- webapp/src/router/mod.rs | 2 +- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f6ce8941d..d702bd4fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -319,7 +319,7 @@ dependencies = [ "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "iron 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "jsonrpc-http-server 5.0.0 (git+https://github.com/debris/jsonrpc-http-server.git)", + "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", @@ -524,6 +524,16 @@ dependencies = [ "syntex 0.30.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "jsonrpc-http-server" +version = "4.0.0" +source = "git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper#46bd4e7cf8352e0efc940cf76d3dff99f1a3da15" +dependencies = [ + "hyper 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "jsonrpc-http-server" version = "5.0.0" diff --git a/parity/main.rs b/parity/main.rs index 7ea8282f3..b9f95eee3 100644 --- a/parity/main.rs +++ b/parity/main.rs @@ -67,6 +67,7 @@ use daemonize::Daemonize; use number_prefix::{binary_prefix, Standalone, Prefixed}; #[cfg(feature = "rpc")] use rpc::Server as RpcServer; +#[cfg(feature = "webapp")] use webapp::Listening as WebappServer; mod price_info; diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index 28df2b8f8..b63c04bf5 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -10,7 +10,7 @@ authors = ["Ethcore { - // self.rpc.handle(req, res) + self.rpc.handle(req, res) }, _ => self.main_page.handle(req, res), } From 1852f1b462657995157a1598a72346ff31fe2ca7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 18:22:53 +0200 Subject: [PATCH 49/52] REST-API PoC --- webapp/src/router/api.rs | 53 ++++++++++++++++++++++++++++++++++++++++ webapp/src/router/mod.rs | 13 ++++++++-- 2 files changed, 64 insertions(+), 2 deletions(-) create mode 100644 webapp/src/router/api.rs diff --git a/webapp/src/router/api.rs b/webapp/src/router/api.rs new file mode 100644 index 000000000..1044af407 --- /dev/null +++ b/webapp/src/router/api.rs @@ -0,0 +1,53 @@ +// Copyright 2015, 2016 Ethcore (UK) Ltd. +// This file is part of Parity. + +// Parity is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// Parity is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License +// along with Parity. If not, see . + +//! Simple REST API + +use std::sync::Arc; +use hyper; +use hyper::status::StatusCode; +use hyper::header; +use hyper::uri::RequestUri::AbsolutePath as Path; +use apps::Pages; + +pub struct RestApi { + pub pages: Arc, +} + +impl RestApi { + fn list_pages(&self) -> String { + let mut s = "[".to_owned(); + for name in self.pages.keys() { + s.push_str(&format!("\"{}\",", name)); + } + s.push_str("\"rpc\""); + s.push_str("]"); + s + } +} + +impl hyper::server::Handler for RestApi { + fn handle<'b, 'a>(&'a self, req: hyper::server::Request<'a, 'b>, mut res: hyper::server::Response<'a>) { + match req.uri { + Path(ref path) if path == "apps" => { + *res.status_mut() = StatusCode::Ok; + res.headers_mut().set(header::ContentType("application/json".parse().unwrap())); + let _ = res.send(self.list_pages().as_bytes()); + }, + _ => () + } + } +} diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index fad8593b9..f0399aba8 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -16,16 +16,20 @@ //! Router implementation +use std::sync::Arc; use hyper; use page::Page; use apps::Pages; use iron::request::Url; use jsonrpc_http_server::ServerHandler; +mod api; + pub struct Router { rpc: ServerHandler, + api: api::RestApi, main_page: Box, - pages: Pages, + pages: Arc, } impl hyper::server::Handler for Router { @@ -34,7 +38,10 @@ impl hyper::server::Handler for Router { match path { Some(ref url) if self.pages.contains_key(url) => { self.pages.get(url).unwrap().handle(req, res); - } + }, + Some(ref url) if url == "api" => { + self.api.handle(req, res); + }, _ if req.method == hyper::method::Method::Post => { self.rpc.handle(req, res) }, @@ -45,8 +52,10 @@ impl hyper::server::Handler for Router { impl Router { pub fn new(rpc: ServerHandler, main_page: Box, pages: Pages) -> Self { + let pages = Arc::new(pages); Router { rpc: rpc, + api: api::RestApi { pages: pages.clone() }, main_page: main_page, pages: pages, } From 6395095659e88a26c3bc2c58e6d80e44b18a36be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Thu, 7 Apr 2016 18:42:51 +0200 Subject: [PATCH 50/52] Updating version of parity-status --- Cargo.lock | 6 +++--- webapp/Cargo.toml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d702bd4fc..210b23666 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -321,7 +321,7 @@ dependencies = [ "jsonrpc-core 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "jsonrpc-http-server 4.0.0 (git+https://github.com/tomusdrw/jsonrpc-http-server.git?branch=old-hyper)", "log 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", - "parity-status 0.1.1 (git+https://github.com/tomusdrw/parity-status.git)", + "parity-status 0.1.4 (git+https://github.com/tomusdrw/parity-status.git)", "parity-wallet 0.1.0 (git+https://github.com/tomusdrw/parity-wallet.git)", "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] @@ -727,8 +727,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "parity-status" -version = "0.1.1" -source = "git+https://github.com/tomusdrw/parity-status.git#31cdfd631af970b58c4ddb4e7d7e927af2e07ce3" +version = "0.1.4" +source = "git+https://github.com/tomusdrw/parity-status.git#380d13c8aafc3847a731968a6532edb09c78f2cf" dependencies = [ "parity-webapp 0.1.0 (git+https://github.com/tomusdrw/parity-webapp.git)", ] diff --git a/webapp/Cargo.toml b/webapp/Cargo.toml index b63c04bf5..59452f32d 100644 --- a/webapp/Cargo.toml +++ b/webapp/Cargo.toml @@ -17,7 +17,7 @@ ethcore-rpc = { path = "../rpc" } ethcore-util = { path = "../util" } parity-webapp = { git = "https://github.com/tomusdrw/parity-webapp.git" } # List of apps -parity-status = { git = "https://github.com/tomusdrw/parity-status.git" } +parity-status = { git = "https://github.com/tomusdrw/parity-status.git", version = "0.1.4" } parity-wallet = { git = "https://github.com/tomusdrw/parity-wallet.git", optional = true } clippy = { version = "0.0.61", optional = true} From f129126a8216a1804e697c6467500fa9db516dde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 8 Apr 2016 10:13:42 +0200 Subject: [PATCH 51/52] Adding couple of missing commas --- webapp/src/lib.rs | 2 +- webapp/src/page/mod.rs | 4 ++-- webapp/src/router/api.rs | 2 +- webapp/src/router/mod.rs | 6 +++--- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/webapp/src/lib.rs b/webapp/src/lib.rs index d8e524be8..35ebb4a44 100644 --- a/webapp/src/lib.rs +++ b/webapp/src/lib.rs @@ -93,7 +93,7 @@ impl From for WebappServerError { fn from(err: hyper::error::Error) -> Self { match err { hyper::error::Error::Io(e) => WebappServerError::IoError(e), - e => WebappServerError::Other(e) + e => WebappServerError::Other(e), } } } diff --git a/webapp/src/page/mod.rs b/webapp/src/page/mod.rs index 94a25769e..ce7b32947 100644 --- a/webapp/src/page/mod.rs +++ b/webapp/src/page/mod.rs @@ -26,7 +26,7 @@ pub trait Page : Send + Sync { } pub struct PageHandler { - pub app: T + pub app: T, } impl Page for PageHandler { @@ -50,7 +50,7 @@ impl Page for PageHandler { Err(_) => { println!("Error while writing response."); Ok(()) - } + }, }; } } diff --git a/webapp/src/router/api.rs b/webapp/src/router/api.rs index 1044af407..046b75957 100644 --- a/webapp/src/router/api.rs +++ b/webapp/src/router/api.rs @@ -47,7 +47,7 @@ impl hyper::server::Handler for RestApi { res.headers_mut().set(header::ContentType("application/json".parse().unwrap())); let _ = res.send(self.list_pages().as_bytes()); }, - _ => () + _ => (), } } } diff --git a/webapp/src/router/mod.rs b/webapp/src/router/mod.rs index f0399aba8..bd0d2ff18 100644 --- a/webapp/src/router/mod.rs +++ b/webapp/src/router/mod.rs @@ -75,14 +75,14 @@ impl Router { Some(ref host) => { format!("http://{}:{}{}", host.hostname, host.port.unwrap_or(80), path) }, - None => return None + None => return None, }; match Url::parse(&url_string) { Ok(url) => Some(url), _ => None, } - } + }, _ => None, } } @@ -103,7 +103,7 @@ impl Router { }, _ => { (None, req) - } + }, } } } From 508daad011b8c580b9ee8b9c6ea2b0262cc762c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Drwi=C4=99ga?= Date: Fri, 8 Apr 2016 11:18:46 +0200 Subject: [PATCH 52/52] Enabling webapps by default --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 276159f84..3fe923db7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,7 +36,7 @@ version = "0.8" default-features = false [features] -default = ["rpc"] +default = ["rpc", "webapp"] rpc = ["ethcore-rpc"] webapp = ["ethcore-webapp"] dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethminer/dev",