IPC (feature-gated) (#1654)
* moving ipc deriving to trait * refactoring of the client * all compiled * proved all working * warnings purged * allow hypervisor to specify initialization payload in two ways * using binary initialisation payload for sync * some docs * logger to separate crate * log settings for sync bin * forwarding logging arguments to the sync
This commit is contained in:
parent
7ae9e61d6c
commit
8ab56ea3d1
14
Cargo.lock
generated
14
Cargo.lock
generated
@ -15,6 +15,7 @@ dependencies = [
|
||||
"ethcore-ipc-codegen 1.3.0",
|
||||
"ethcore-ipc-hypervisor 1.2.0",
|
||||
"ethcore-ipc-nano 1.3.0",
|
||||
"ethcore-logger 1.3.0",
|
||||
"ethcore-rpc 1.3.0",
|
||||
"ethcore-signer 1.3.0",
|
||||
"ethcore-util 1.3.0",
|
||||
@ -343,6 +344,19 @@ dependencies = [
|
||||
"nanomsg 0.5.1 (git+https://github.com/ethcore/nanomsg.rs.git)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ethcore-logger"
|
||||
version = "1.3.0"
|
||||
dependencies = [
|
||||
"env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"ethcore-util 1.3.0",
|
||||
"isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"regex 0.1.68 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ethcore-rpc"
|
||||
version = "1.3.0"
|
||||
|
@ -36,6 +36,7 @@ ethcore-signer = { path = "signer" }
|
||||
ethcore-ipc-nano = { path = "ipc/nano" }
|
||||
ethcore-ipc = { path = "ipc/rpc" }
|
||||
ethcore-ipc-hypervisor = { path = "ipc/hypervisor" }
|
||||
ethcore-logger = { path = "logger" }
|
||||
json-ipc-server = { git = "https://github.com/ethcore/json-ipc-server.git" }
|
||||
ethcore-dapps = { path = "dapps", optional = true }
|
||||
clippy = { version = "0.0.79", optional = true}
|
||||
@ -58,6 +59,7 @@ dapps = ["ethcore-dapps"]
|
||||
dev = ["clippy", "ethcore/dev", "ethcore-util/dev", "ethsync/dev", "ethcore-rpc/dev", "ethcore-dapps/dev", "ethcore-signer/dev"]
|
||||
travis-beta = ["ethcore/json-tests"]
|
||||
travis-nightly = ["ethcore/json-tests", "dev"]
|
||||
ipc = ["ethcore/ipc"]
|
||||
|
||||
[[bin]]
|
||||
path = "parity/main.rs"
|
||||
|
@ -46,3 +46,4 @@ test-heavy = []
|
||||
dev = ["clippy"]
|
||||
default = []
|
||||
benches = []
|
||||
ipc = []
|
||||
|
@ -235,8 +235,8 @@ impl Client {
|
||||
}
|
||||
|
||||
/// Adds an actor to be notified on certain events
|
||||
pub fn add_notify(&self, target: &Arc<ChainNotify>) {
|
||||
self.notify.write().push(Arc::downgrade(target));
|
||||
pub fn add_notify(&self, target: Arc<ChainNotify>) {
|
||||
self.notify.write().push(Arc::downgrade(&target));
|
||||
}
|
||||
|
||||
fn notify<F>(&self, f: F) where F: Fn(&ChainNotify) {
|
||||
|
@ -30,7 +30,7 @@ pub use self::test_client::{TestBlockChainClient, EachBlockWith};
|
||||
pub use types::trace_filter::Filter as TraceFilter;
|
||||
pub use executive::{Executed, Executive, TransactOptions};
|
||||
pub use env_info::{LastHashes, EnvInfo};
|
||||
pub use self::chain_notify::ChainNotify;
|
||||
pub use self::chain_notify::{ChainNotify, ChainNotifyClient};
|
||||
|
||||
pub use types::call_analytics::CallAnalytics;
|
||||
pub use block_import_error::BlockImportError;
|
||||
|
@ -22,6 +22,12 @@ use spec::Spec;
|
||||
use error::*;
|
||||
use client::{Client, ClientConfig, ChainNotify};
|
||||
use miner::Miner;
|
||||
use std::sync::atomic::AtomicBool;
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
use nanoipc;
|
||||
#[cfg(feature="ipc")]
|
||||
use client::BlockChainClient;
|
||||
|
||||
/// Message type for external and internal events
|
||||
#[derive(Clone)]
|
||||
@ -38,7 +44,8 @@ pub enum ClientIoMessage {
|
||||
pub struct ClientService {
|
||||
io_service: Arc<IoService<ClientIoMessage>>,
|
||||
client: Arc<Client>,
|
||||
panic_handler: Arc<PanicHandler>
|
||||
panic_handler: Arc<PanicHandler>,
|
||||
_stop_guard: ::devtools::StopGuard,
|
||||
}
|
||||
|
||||
impl ClientService {
|
||||
@ -62,10 +69,14 @@ impl ClientService {
|
||||
});
|
||||
try!(io_service.register_handler(client_io));
|
||||
|
||||
let stop_guard = ::devtools::StopGuard::new();
|
||||
run_ipc(client.clone(), stop_guard.share());
|
||||
|
||||
Ok(ClientService {
|
||||
io_service: Arc::new(io_service),
|
||||
client: client,
|
||||
panic_handler: panic_handler,
|
||||
_stop_guard: stop_guard,
|
||||
})
|
||||
}
|
||||
|
||||
@ -90,7 +101,7 @@ impl ClientService {
|
||||
}
|
||||
|
||||
/// Set the actor to be notified on certain chain events
|
||||
pub fn add_notify(&self, notify: &Arc<ChainNotify>) {
|
||||
pub fn add_notify(&self, notify: Arc<ChainNotify>) {
|
||||
self.client.add_notify(notify);
|
||||
}
|
||||
}
|
||||
@ -130,6 +141,22 @@ impl IoHandler<ClientIoMessage> for ClientIoHandler {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
fn run_ipc(client: Arc<Client>, stop: Arc<AtomicBool>) {
|
||||
::std::thread::spawn(move || {
|
||||
let mut worker = nanoipc::Worker::new(&(client as Arc<BlockChainClient>));
|
||||
worker.add_reqrep("ipc:///tmp/parity-chain.ipc").expect("Ipc expected to initialize with no issues");
|
||||
|
||||
while !stop.load(::std::sync::atomic::Ordering::Relaxed) {
|
||||
worker.poll();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
fn run_ipc(_client: Arc<Client>, _stop: Arc<AtomicBool>) {
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
@ -273,7 +273,12 @@ fn implement_dispatch_arm(
|
||||
{
|
||||
let index_ident = builder.id(format!("{}", index + (RESERVED_MESSAGE_IDS as u32)).as_str());
|
||||
let invoke_expr = implement_dispatch_arm_invoke(cx, builder, dispatch, buffer);
|
||||
quote_arm!(cx, $index_ident => { $invoke_expr } )
|
||||
let dispatching_trace = "Dispatching: ".to_owned() + &dispatch.function_name;
|
||||
let dispatching_trace_literal = builder.expr().lit().str::<&str>(&dispatching_trace);
|
||||
quote_arm!(cx, $index_ident => {
|
||||
trace!(target: "ipc", $dispatching_trace_literal);
|
||||
$invoke_expr
|
||||
})
|
||||
}
|
||||
|
||||
fn implement_dispatch_arms(
|
||||
@ -420,17 +425,22 @@ fn implement_client_method_body(
|
||||
request_serialization_statements
|
||||
};
|
||||
|
||||
let invocation_trace = "Invoking: ".to_owned() + &dispatch.function_name;
|
||||
let invocation_trace_literal = builder.expr().lit().str::<&str>(&invocation_trace);
|
||||
|
||||
if let Some(ref return_ty) = dispatch.return_type_ty {
|
||||
let return_expr = quote_expr!(cx,
|
||||
::ipc::binary::deserialize_from::<$return_ty, _>(&mut *socket).unwrap()
|
||||
);
|
||||
quote_expr!(cx, {
|
||||
trace!(target: "ipc", $invocation_trace_literal);
|
||||
$request
|
||||
$return_expr
|
||||
})
|
||||
}
|
||||
else {
|
||||
quote_expr!(cx, {
|
||||
trace!(target: "ipc", $invocation_trace_literal);
|
||||
$request
|
||||
})
|
||||
}
|
||||
|
@ -261,6 +261,10 @@ fn binary_expr_struct(
|
||||
|
||||
let raw_ident = ::syntax::print::pprust::ty_to_string(&codegen::strip_ptr(&field.ty));
|
||||
let range_ident = builder.id(format!("r{}", index));
|
||||
|
||||
let error_message = "Error serializing member: ".to_owned() + &::syntax::print::pprust::expr_to_string(&member_expr);
|
||||
let error_message_literal = builder.expr().lit().str::<&str>(&error_message);
|
||||
|
||||
match raw_ident.as_ref() {
|
||||
"u8" => {
|
||||
write_stmts.push(quote_stmt!(cx, let next_line = offset + 1;).unwrap());
|
||||
@ -280,7 +284,13 @@ fn binary_expr_struct(
|
||||
}).unwrap());
|
||||
write_stmts.push(quote_stmt!(cx, let $range_ident = offset..next_line; ).unwrap());
|
||||
post_write_stmts.push(quote_stmt!(cx,
|
||||
if let Err(e) = $member_expr .to_bytes(&mut buffer[$range_ident], length_stack) { return Err(e) };).unwrap());
|
||||
if $range_ident.end - $range_ident.start > 0 {
|
||||
if let Err(e) = $member_expr .to_bytes(&mut buffer[$range_ident], length_stack) {
|
||||
warn!(target: "ipc", $error_message_literal);
|
||||
return Err(e)
|
||||
};
|
||||
}
|
||||
).unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,35 @@ pub struct Hypervisor {
|
||||
service: Arc<HypervisorService>,
|
||||
ipc_worker: RwLock<nanoipc::Worker<HypervisorService>>,
|
||||
processes: RwLock<HashMap<BinaryId, Child>>,
|
||||
modules: HashMap<IpcModuleId, (BinaryId, Vec<String>)>,
|
||||
modules: HashMap<IpcModuleId, (BinaryId, BootArgs)>,
|
||||
}
|
||||
|
||||
/// Boot arguments for binary
|
||||
pub struct BootArgs {
|
||||
cli: Option<Vec<String>>,
|
||||
stdin: Option<Vec<u8>>,
|
||||
}
|
||||
|
||||
impl BootArgs {
|
||||
/// New empty boot arguments
|
||||
pub fn new() -> BootArgs {
|
||||
BootArgs {
|
||||
cli: None,
|
||||
stdin: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set command-line arguments for boot
|
||||
pub fn cli(mut self, cli: Vec<String>) -> BootArgs {
|
||||
self.cli = Some(cli);
|
||||
self
|
||||
}
|
||||
|
||||
/// Set std-in stream for boot
|
||||
pub fn stdin(mut self, stdin: Vec<u8>) -> BootArgs {
|
||||
self.stdin = Some(stdin);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl Hypervisor {
|
||||
@ -51,7 +79,7 @@ impl Hypervisor {
|
||||
Hypervisor::with_url(HYPERVISOR_IPC_URL)
|
||||
}
|
||||
|
||||
pub fn module(mut self, module_id: IpcModuleId, binary_id: BinaryId, args: Vec<String>) -> Hypervisor {
|
||||
pub fn module(mut self, module_id: IpcModuleId, binary_id: BinaryId, args: BootArgs) -> Hypervisor {
|
||||
self.modules.insert(module_id, (binary_id, args));
|
||||
self.service.add_module(module_id);
|
||||
self
|
||||
@ -78,7 +106,7 @@ impl Hypervisor {
|
||||
|
||||
/// Since one binary can host multiple modules
|
||||
/// we match binaries
|
||||
fn match_module(&self, module_id: &IpcModuleId) -> Option<&(BinaryId, Vec<String>)> {
|
||||
fn match_module(&self, module_id: &IpcModuleId) -> Option<&(BinaryId, BootArgs)> {
|
||||
self.modules.get(module_id)
|
||||
}
|
||||
|
||||
@ -96,6 +124,8 @@ impl Hypervisor {
|
||||
/// Does nothing when it is already started on module is inside the
|
||||
/// main binary
|
||||
fn start_module(&self, module_id: IpcModuleId) {
|
||||
use std::io::Write;
|
||||
|
||||
self.match_module(&module_id).map(|&(ref binary_id, ref binary_args)| {
|
||||
let mut processes = self.processes.write().unwrap();
|
||||
{
|
||||
@ -109,13 +139,30 @@ impl Hypervisor {
|
||||
executable_path.pop();
|
||||
executable_path.push(binary_id);
|
||||
|
||||
let mut command = Command::new(&executable_path.to_str().unwrap());
|
||||
for arg in binary_args { command.arg(arg); }
|
||||
let executable_path = executable_path.to_str().unwrap();
|
||||
let mut command = Command::new(&executable_path);
|
||||
command.stderr(std::process::Stdio::inherit());
|
||||
|
||||
if let Some(ref cli_args) = binary_args.cli {
|
||||
for arg in cli_args { command.arg(arg); }
|
||||
}
|
||||
|
||||
command.stdin(std::process::Stdio::piped());
|
||||
|
||||
trace!(target: "hypervisor", "Spawn executable: {:?}", command);
|
||||
|
||||
let child = command.spawn().unwrap_or_else(
|
||||
let mut child = command.spawn().unwrap_or_else(
|
||||
|e| panic!("Hypervisor cannot start binary ({:?}): {}", executable_path, e));
|
||||
|
||||
if let Some(ref std_in) = binary_args.stdin {
|
||||
trace!(target: "hypervisor", "Pushing std-in payload...");
|
||||
child.stdin.as_mut()
|
||||
.expect("std-in should be piped above")
|
||||
.write(std_in)
|
||||
.unwrap_or_else(|e| panic!(format!("Error trying to pipe stdin for {}: {:?}", &executable_path, e)));
|
||||
drop(child.stdin.take());
|
||||
}
|
||||
|
||||
processes.insert(binary_id, child);
|
||||
});
|
||||
}
|
||||
@ -133,6 +180,7 @@ impl Hypervisor {
|
||||
}
|
||||
}
|
||||
|
||||
/// Shutdown the ipc and all managed child processes
|
||||
pub fn shutdown(&self, wait_time: Option<std::time::Duration>) {
|
||||
if wait_time.is_some() { std::thread::sleep(wait_time.unwrap()) }
|
||||
|
||||
|
@ -60,6 +60,7 @@ impl HypervisorService {
|
||||
})
|
||||
}
|
||||
|
||||
/// Add the module to the check-list
|
||||
pub fn add_module(&self, module_id: IpcModuleId) {
|
||||
self.check_list.write().unwrap().insert(module_id, false);
|
||||
}
|
||||
|
@ -23,6 +23,7 @@ extern crate jsonrpc_core;
|
||||
use jsonrpc_core::IoHandler;
|
||||
|
||||
pub use ipc::{WithSocket, IpcInterface, IpcConfig};
|
||||
pub use nanomsg::Socket as NanoSocket;
|
||||
|
||||
use std::sync::*;
|
||||
use std::sync::atomic::*;
|
||||
@ -54,9 +55,9 @@ impl<S> GuardedSocket<S> where S: WithSocket<Socket> {
|
||||
}
|
||||
|
||||
impl<S> Deref for GuardedSocket<S> where S: WithSocket<Socket> {
|
||||
type Target = S;
|
||||
type Target = Arc<S>;
|
||||
|
||||
fn deref(&self) -> &S {
|
||||
fn deref(&self) -> &Arc<S> {
|
||||
&self.client
|
||||
}
|
||||
}
|
||||
|
@ -54,6 +54,7 @@ impl<T> BinaryConvertable for Option<T> where T: BinaryConvertable {
|
||||
}
|
||||
|
||||
fn from_bytes(buffer: &[u8], length_stack: &mut VecDeque<usize>) -> Result<Self, BinaryConvertError> {
|
||||
if buffer.len() == 0 { return Self::from_empty_bytes(); }
|
||||
Ok(Some(try!(T::from_bytes(buffer, length_stack))))
|
||||
}
|
||||
|
||||
@ -779,6 +780,42 @@ fn serialize_into_deserialize_from() {
|
||||
assert_eq!(v, de_v);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_vec_str() {
|
||||
// empty
|
||||
let source = Vec::<String>::new();
|
||||
let serialized = serialize(&source).unwrap();
|
||||
let deserialized = deserialize::<Vec<String>>(&serialized).unwrap();
|
||||
|
||||
assert_eq!(source, deserialized);
|
||||
|
||||
// with few values
|
||||
let mut source = Vec::<String>::new();
|
||||
source.push("val1".to_owned());
|
||||
source.push("val2".to_owned());
|
||||
let serialized = serialize(&source).unwrap();
|
||||
let deserialized = deserialize::<Vec<String>>(&serialized).unwrap();
|
||||
|
||||
assert_eq!(source, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_opt_str() {
|
||||
// none
|
||||
let source: Option<String> = None;
|
||||
let serialized = serialize(&source).unwrap();
|
||||
let deserialized = deserialize::<Option<String>>(&serialized).unwrap();
|
||||
|
||||
assert_eq!(source, deserialized);
|
||||
|
||||
// value
|
||||
let source: Option<String> = Some("i have value".to_owned());
|
||||
let serialized = serialize(&source).unwrap();
|
||||
let deserialized = deserialize::<Option<String>>(&serialized).unwrap();
|
||||
|
||||
assert_eq!(source, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn serialize_opt_vec() {
|
||||
use std::io::Cursor;
|
||||
|
19
logger/Cargo.toml
Normal file
19
logger/Cargo.toml
Normal file
@ -0,0 +1,19 @@
|
||||
[package]
|
||||
description = "Ethcore client."
|
||||
name = "ethcore-logger"
|
||||
version = "1.3.0"
|
||||
license = "GPL-3.0"
|
||||
authors = ["Ethcore <admin@ethcore.io>"]
|
||||
|
||||
[dependencies]
|
||||
log = "0.3"
|
||||
env_logger = "0.3"
|
||||
ethcore-util = { path = "../util" }
|
||||
isatty = "0.1"
|
||||
lazy_static = "0.2"
|
||||
regex = "0.1"
|
||||
time = "0.1"
|
||||
|
||||
[profile.release]
|
||||
debug = true
|
||||
lto = false
|
@ -14,20 +14,61 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
//! Logger for parity executables
|
||||
|
||||
extern crate ethcore_util as util;
|
||||
#[macro_use]
|
||||
extern crate log as rlog;
|
||||
extern crate isatty;
|
||||
extern crate regex;
|
||||
extern crate env_logger;
|
||||
extern crate time;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
|
||||
use std::env;
|
||||
use std::sync::Arc;
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use isatty::{stderr_isatty};
|
||||
use time;
|
||||
use env_logger::LogBuilder;
|
||||
use regex::Regex;
|
||||
use util::RotatingLogger;
|
||||
use util::log::Colour;
|
||||
|
||||
pub struct Settings {
|
||||
pub color: bool,
|
||||
pub init: Option<String>,
|
||||
pub file: Option<String>,
|
||||
}
|
||||
|
||||
impl Settings {
|
||||
pub fn new() -> Settings {
|
||||
Settings {
|
||||
color: true,
|
||||
init: None,
|
||||
file: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(mut self, init: String) -> Settings {
|
||||
self.init = Some(init);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn file(mut self, file: String) -> Settings {
|
||||
self.file = Some(file);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn no_color(mut self) -> Settings {
|
||||
self.color = false;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// Sets up the logger
|
||||
pub fn setup_log(init: &Option<String>, enable_color: bool, log_to_file: &Option<String>) -> Arc<RotatingLogger> {
|
||||
pub fn setup_log(settings: &Settings) -> Arc<RotatingLogger> {
|
||||
use rlog::*;
|
||||
|
||||
let mut levels = String::new();
|
||||
@ -43,15 +84,15 @@ pub fn setup_log(init: &Option<String>, enable_color: bool, log_to_file: &Option
|
||||
builder.parse(lvl);
|
||||
}
|
||||
|
||||
if let Some(ref s) = *init {
|
||||
if let Some(ref s) = settings.init {
|
||||
levels.push_str(s);
|
||||
builder.parse(s);
|
||||
}
|
||||
|
||||
let enable_color = enable_color && stderr_isatty();
|
||||
let enable_color = settings.color && stderr_isatty();
|
||||
let logs = Arc::new(RotatingLogger::new(levels));
|
||||
let logger = logs.clone();
|
||||
let maybe_file = log_to_file.as_ref().map(|f| File::create(f).unwrap_or_else(|_| die!("Cannot write to log file given: {}", f)));
|
||||
let maybe_file = settings.file.as_ref().map(|f| File::create(f).unwrap_or_else(|_| panic!("Cannot write to log file given: {}", f)));
|
||||
let format = move |record: &LogRecord| {
|
||||
let timestamp = time::strftime("%Y-%m-%d %H:%M:%S %Z", &time::now()).unwrap();
|
||||
|
@ -34,6 +34,7 @@ use ethcore::ethereum;
|
||||
use ethcore::spec::Spec;
|
||||
use ethsync::SyncConfig;
|
||||
use rpc::IpcConfiguration;
|
||||
use ethcore_logger::Settings as LogSettings;
|
||||
|
||||
pub struct Configuration {
|
||||
pub args: Args
|
||||
@ -564,6 +565,20 @@ impl Configuration {
|
||||
(self.args.flag_unlock.is_none() && !self.args.flag_no_signer) ||
|
||||
self.args.flag_force_signer
|
||||
}
|
||||
|
||||
pub fn log_settings(&self) -> LogSettings {
|
||||
let mut settings = LogSettings::new();
|
||||
if self.args.flag_no_color || cfg!(windows) {
|
||||
settings = settings.no_color();
|
||||
}
|
||||
if let Some(ref init) = self.args.flag_logging {
|
||||
settings = settings.init(init.to_owned())
|
||||
}
|
||||
if let Some(ref file) = self.args.flag_log_file {
|
||||
settings = settings.file(file.to_owned())
|
||||
}
|
||||
settings
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -53,15 +53,16 @@ extern crate ansi_term;
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
extern crate regex;
|
||||
extern crate ethcore_logger;
|
||||
extern crate isatty;
|
||||
|
||||
#[cfg(feature = "dapps")]
|
||||
extern crate ethcore_dapps;
|
||||
|
||||
|
||||
#[macro_use]
|
||||
mod die;
|
||||
mod upgrade;
|
||||
mod setup_log;
|
||||
mod rpc;
|
||||
mod dapps;
|
||||
mod informant;
|
||||
@ -86,7 +87,7 @@ use rustc_serialize::hex::FromHex;
|
||||
use ctrlc::CtrlC;
|
||||
use util::{H256, ToPretty, PayloadInfo, Bytes, Colour, version, journaldb, RotatingLogger};
|
||||
use util::panics::{MayPanic, ForwardPanic, PanicHandler};
|
||||
use ethcore::client::{BlockID, BlockChainClient, ClientConfig, get_db_path, BlockImportError, Mode, ChainNotify};
|
||||
use ethcore::client::{BlockID, BlockChainClient, ClientConfig, get_db_path, BlockImportError, Mode};
|
||||
use ethcore::error::{ImportError};
|
||||
use ethcore::service::ClientService;
|
||||
use ethcore::spec::Spec;
|
||||
@ -95,6 +96,9 @@ use ethcore::miner::{Miner, MinerService, ExternalMiner};
|
||||
use migration::migrate;
|
||||
use informant::Informant;
|
||||
use util::{Mutex, Condvar};
|
||||
use ethcore_logger::setup_log;
|
||||
#[cfg(feature="ipc")]
|
||||
use ethcore::client::ChainNotify;
|
||||
|
||||
use die::*;
|
||||
use cli::print_version;
|
||||
@ -132,7 +136,7 @@ fn execute(conf: Configuration) {
|
||||
// Setup panic handler
|
||||
let panic_handler = PanicHandler::new_in_arc();
|
||||
// Setup logging
|
||||
let logger = setup_log::setup_log(&conf.args.flag_logging, conf.have_color(), &conf.args.flag_log_file);
|
||||
let logger = setup_log(&conf.log_settings());
|
||||
// Raise fdlimit
|
||||
unsafe { ::fdlimit::raise_fd_limit(); }
|
||||
|
||||
@ -192,6 +196,8 @@ fn execute_upgrades(conf: &Configuration, spec: &Spec, client_config: &ClientCon
|
||||
}
|
||||
|
||||
fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig, panic_handler: Arc<PanicHandler>, logger: Arc<RotatingLogger>) {
|
||||
let mut hypervisor = modules::hypervisor();
|
||||
|
||||
info!("Starting {}", Colour::White.bold().paint(format!("{}", version())));
|
||||
info!("Using state DB journalling strategy {}", Colour::White.bold().paint(match client_config.pruning {
|
||||
journaldb::Algorithm::Archive => "archive",
|
||||
@ -244,9 +250,10 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig,
|
||||
|
||||
// Sync
|
||||
let (sync_provider, manage_network, chain_notify) =
|
||||
modules::sync(sync_config, NetworkConfiguration::from(net_settings), client.clone())
|
||||
modules::sync(&mut hypervisor, sync_config, NetworkConfiguration::from(net_settings), client.clone(), &conf.log_settings())
|
||||
.unwrap_or_else(|e| die_with_error("Sync", e));
|
||||
service.add_notify(&chain_notify);
|
||||
|
||||
service.add_notify(chain_notify.clone());
|
||||
|
||||
// if network is active by default
|
||||
if match conf.mode() { Mode::Dark(..) => false, _ => !conf.args.flag_no_network } {
|
||||
@ -311,8 +318,7 @@ fn execute_client(conf: Configuration, spec: Spec, client_config: ClientConfig,
|
||||
});
|
||||
|
||||
let informant = Arc::new(Informant::new(service.client(), Some(sync_provider.clone()), Some(manage_network.clone()), conf.have_color()));
|
||||
let info_notify: Arc<ChainNotify> = informant.clone();
|
||||
service.add_notify(&info_notify);
|
||||
service.add_notify(informant.clone());
|
||||
// Register IO handler
|
||||
let io_handler = Arc::new(ClientIoHandler {
|
||||
client: service.client(),
|
||||
|
@ -14,28 +14,116 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
use ethsync::{EthSync, SyncProvider, ManageNetwork, SyncConfig, NetworkConfiguration};
|
||||
use std::sync::Arc;
|
||||
use ethcore::client::{ChainNotify, BlockChainClient};
|
||||
use ethcore::client::BlockChainClient;
|
||||
use ethcore;
|
||||
use hypervisor::Hypervisor;
|
||||
use ethsync::{SyncConfig, NetworkConfiguration};
|
||||
#[cfg(not(feature="ipc"))]
|
||||
use self::no_ipc_deps::*;
|
||||
#[cfg(feature="ipc")]
|
||||
use self::ipc_deps::*;
|
||||
|
||||
pub type Modules = (Arc<SyncProvider>, Arc<ManageNetwork>, Arc<ChainNotify>);
|
||||
use ethcore_logger::Settings as LogSettings;
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
mod no_ipc_deps {
|
||||
pub use ethsync::{EthSync, SyncProvider, ManageNetwork};
|
||||
pub use ethcore::client::ChainNotify;
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
pub fn sync(
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
client: Arc<BlockChainClient>)
|
||||
-> Result<Modules, ethcore::error::Error>
|
||||
{
|
||||
pub type SyncModules = (
|
||||
GuardedSocket<SyncClient<NanoSocket>>,
|
||||
GuardedSocket<NetworkManagerClient<NanoSocket>>,
|
||||
GuardedSocket<ChainNotifyClient<NanoSocket>>
|
||||
);
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
pub type SyncModules = (Arc<SyncProvider>, Arc<ManageNetwork>, Arc<ChainNotify>);
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
mod ipc_deps {
|
||||
pub use ethsync::{SyncClient, NetworkManagerClient, ServiceConfiguration};
|
||||
pub use ethcore::client::ChainNotifyClient;
|
||||
pub use hypervisor::{SYNC_MODULE_ID, BootArgs};
|
||||
pub use nanoipc::{GuardedSocket, NanoSocket, init_client};
|
||||
pub use ipc::IpcSocket;
|
||||
pub use ipc::binary::serialize;
|
||||
}
|
||||
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
pub fn hypervisor() -> Option<Hypervisor> {
|
||||
Some(Hypervisor::new())
|
||||
}
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
pub fn sync(
|
||||
pub fn hypervisor() -> Option<Hypervisor> {
|
||||
None
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
fn sync_arguments(sync_cfg: SyncConfig, net_cfg: NetworkConfiguration, log_settings: &LogSettings) -> BootArgs {
|
||||
let service_config = ServiceConfiguration {
|
||||
sync: sync_cfg,
|
||||
net: net_cfg,
|
||||
};
|
||||
|
||||
// initialisation payload is passed via stdin
|
||||
let service_payload = serialize(&service_config).expect("Any binary-derived struct is serializable by definition");
|
||||
|
||||
// client service url and logging settings are passed in command line
|
||||
let mut cli_args = Vec::new();
|
||||
cli_args.push("ipc:///tmp/parity-chain.ipc".to_owned());
|
||||
if !log_settings.color { cli_args.push("--no-color".to_owned()); }
|
||||
if let Some(ref init) = log_settings.init {
|
||||
cli_args.push("-l".to_owned());
|
||||
cli_args.push(init.to_owned());
|
||||
}
|
||||
if let Some(ref file) = log_settings.file {
|
||||
cli_args.push("--log-file".to_owned());
|
||||
cli_args.push(file.to_owned());
|
||||
}
|
||||
|
||||
BootArgs::new().stdin(service_payload).cli(cli_args)
|
||||
}
|
||||
|
||||
#[cfg(feature="ipc")]
|
||||
pub fn sync
|
||||
(
|
||||
hypervisor_ref: &mut Option<Hypervisor>,
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
client: Arc<BlockChainClient>)
|
||||
-> Result<Modules, ethcore::error::Error>
|
||||
_client: Arc<BlockChainClient>,
|
||||
log_settings: &LogSettings,
|
||||
)
|
||||
-> Result<SyncModules, ethcore::error::Error>
|
||||
{
|
||||
let mut hypervisor = hypervisor_ref.take().expect("There should be hypervisor for ipc configuration");
|
||||
hypervisor = hypervisor.module(SYNC_MODULE_ID, "sync", sync_arguments(sync_cfg, net_cfg, log_settings));
|
||||
|
||||
hypervisor.start();
|
||||
hypervisor.wait_for_startup();
|
||||
|
||||
let sync_client = init_client::<SyncClient<_>>("ipc:///tmp/parity-sync.ipc").unwrap();
|
||||
let notify_client = init_client::<ChainNotifyClient<_>>("ipc:///tmp/parity-sync-notify.ipc").unwrap();
|
||||
let manage_client = init_client::<NetworkManagerClient<_>>("ipc:///tmp/parity-manage-net.ipc").unwrap();
|
||||
|
||||
*hypervisor_ref = Some(hypervisor);
|
||||
Ok((sync_client, manage_client, notify_client))
|
||||
}
|
||||
|
||||
#[cfg(not(feature="ipc"))]
|
||||
pub fn sync
|
||||
(
|
||||
_hypervisor: &mut Option<Hypervisor>,
|
||||
sync_cfg: SyncConfig,
|
||||
net_cfg: NetworkConfiguration,
|
||||
client: Arc<BlockChainClient>,
|
||||
_log_settings: &LogSettings,
|
||||
)
|
||||
-> Result<SyncModules, ethcore::error::Error>
|
||||
{
|
||||
let eth_sync = try!(EthSync::new(sync_cfg, client, net_cfg).map_err(ethcore::error::Error::Util));
|
||||
Ok((eth_sync.clone() as Arc<SyncProvider>, eth_sync.clone() as Arc<ManageNetwork>, eth_sync.clone() as Arc<ChainNotify>))
|
||||
|
@ -26,6 +26,7 @@ extern crate rustc_serialize;
|
||||
extern crate docopt;
|
||||
extern crate ethcore;
|
||||
extern crate ethcore_util as util;
|
||||
extern crate ethcore_logger;
|
||||
|
||||
use std::sync::Arc;
|
||||
use hypervisor::{HypervisorServiceClient, SYNC_MODULE_ID, HYPERVISOR_IPC_URL};
|
||||
@ -33,63 +34,47 @@ use ctrlc::CtrlC;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use docopt::Docopt;
|
||||
use ethcore::client::{RemoteClient, ChainNotify};
|
||||
use ethsync::{SyncProvider, SyncConfig, EthSync, ManageNetwork, NetworkConfiguration};
|
||||
use ethsync::{SyncProvider, EthSync, ManageNetwork, ServiceConfiguration};
|
||||
use std::thread;
|
||||
use util::numbers::{U256, H256};
|
||||
use std::str::FromStr;
|
||||
use nanoipc::IpcInterface;
|
||||
use util::sha3::Hashable;
|
||||
|
||||
use ethcore_logger::Settings as LogSettings;
|
||||
use ethcore_logger::setup_log;
|
||||
|
||||
const USAGE: &'static str = "
|
||||
Ethcore sync service
|
||||
Usage:
|
||||
sync <client-url> <network-id> <listen-address> <nat-enabled> <discovery-enabled> <ideal-peers> <config-path> <allow-non-reserved> [options]
|
||||
sync <client-url> [options]
|
||||
|
||||
Options:
|
||||
--public-address IP Public address.
|
||||
--boot-nodes LIST List of boot nodes.
|
||||
--reserved-nodes LIST List of reserved peers,
|
||||
--secret HEX Use node key hash
|
||||
--udp-port UDP port
|
||||
Options:
|
||||
-l --logging LOGGING Specify the logging level. Must conform to the same
|
||||
format as RUST_LOG.
|
||||
--log-file FILENAME Specify a filename into which logging should be
|
||||
directed.
|
||||
--no-color Don't use terminal color codes in output.
|
||||
";
|
||||
|
||||
#[derive(Debug, RustcDecodable)]
|
||||
struct Args {
|
||||
arg_network_id: String,
|
||||
arg_listen_address: String,
|
||||
arg_nat_enabled: bool,
|
||||
arg_discovery_enabled: bool,
|
||||
arg_ideal_peers: u32,
|
||||
arg_config_path: String,
|
||||
arg_client_url: String,
|
||||
arg_allow_non_reserved: bool,
|
||||
flag_public_address: Option<String>,
|
||||
flag_secret: Option<String>,
|
||||
flag_boot_nodes: Vec<String>,
|
||||
flag_reserved_nodes: Vec<String>,
|
||||
flag_udp_port: Option<u16>,
|
||||
flag_logging: Option<String>,
|
||||
flag_log_file: Option<String>,
|
||||
flag_no_color: bool,
|
||||
}
|
||||
|
||||
impl Args {
|
||||
pub fn into_config(self) -> (SyncConfig, NetworkConfiguration, String) {
|
||||
let mut sync_config = SyncConfig::default();
|
||||
sync_config.network_id = U256::from_str(&self.arg_network_id).unwrap();
|
||||
|
||||
let network_config = NetworkConfiguration {
|
||||
udp_port: self.flag_udp_port,
|
||||
nat_enabled: self.arg_nat_enabled,
|
||||
boot_nodes: self.flag_boot_nodes,
|
||||
listen_address: Some(self.arg_listen_address),
|
||||
public_address: self.flag_public_address,
|
||||
use_secret: self.flag_secret.as_ref().map(|s| H256::from_str(s).unwrap_or_else(|_| s.sha3())),
|
||||
discovery_enabled: self.arg_discovery_enabled,
|
||||
ideal_peers: self.arg_ideal_peers,
|
||||
config_path: Some(self.arg_config_path),
|
||||
reserved_nodes: self.flag_reserved_nodes,
|
||||
allow_non_reserved: self.arg_allow_non_reserved,
|
||||
};
|
||||
|
||||
(sync_config, network_config, self.arg_client_url)
|
||||
pub fn log_settings(&self) -> LogSettings {
|
||||
let mut settings = LogSettings::new();
|
||||
if self.flag_no_color || cfg!(windows) {
|
||||
settings = settings.no_color();
|
||||
}
|
||||
if let Some(ref init) = self.flag_logging {
|
||||
settings = settings.init(init.to_owned())
|
||||
}
|
||||
if let Some(ref file) = self.flag_log_file {
|
||||
settings = settings.file(file.to_owned())
|
||||
}
|
||||
settings
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,16 +91,24 @@ fn run_service<T: ?Sized + Send + Sync + 'static>(addr: &str, stop_guard: Arc<At
|
||||
}
|
||||
|
||||
fn main() {
|
||||
use std::io::{self, Read};
|
||||
|
||||
let args: Args = Docopt::new(USAGE)
|
||||
.and_then(|d| d.decode())
|
||||
.unwrap_or_else(|e| e.exit());
|
||||
let (sync_config, network_config, client_url) = args.into_config();
|
||||
let remote_client = nanoipc::init_client::<RemoteClient<_>>(&client_url).unwrap();
|
||||
|
||||
setup_log(&args.log_settings());
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
io::stdin().read_to_end(&mut buffer).expect("Failed to read initialisation payload");
|
||||
let service_config = ipc::binary::deserialize::<ServiceConfiguration>(&buffer).expect("Failed deserializing initialisation payload");
|
||||
|
||||
let remote_client = nanoipc::init_client::<RemoteClient<_>>(&args.arg_client_url).unwrap();
|
||||
|
||||
remote_client.handshake().unwrap();
|
||||
|
||||
let stop = Arc::new(AtomicBool::new(false));
|
||||
let sync = EthSync::new(sync_config, remote_client.service().clone(), network_config).unwrap();
|
||||
let sync = EthSync::new(service_config.sync, remote_client.service().clone(), service_config.net).unwrap();
|
||||
|
||||
run_service("ipc:///tmp/parity-sync.ipc", stop.clone(), sync.clone() as Arc<SyncProvider>);
|
||||
run_service("ipc:///tmp/parity-manage-net.ipc", stop.clone(), sync.clone() as Arc<ManageNetwork>);
|
||||
|
@ -32,6 +32,7 @@ use parking_lot::RwLock;
|
||||
pub const ETH_PROTOCOL: &'static str = "eth";
|
||||
|
||||
/// Sync configuration
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct SyncConfig {
|
||||
/// Max blocks to download ahead
|
||||
pub max_download_ahead_blocks: usize,
|
||||
@ -272,3 +273,9 @@ impl From<BasicNetworkConfiguration> for NetworkConfiguration {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Binary, Clone)]
|
||||
pub struct ServiceConfiguration {
|
||||
pub sync: SyncConfig,
|
||||
pub net: NetworkConfiguration,
|
||||
}
|
||||
|
@ -87,6 +87,7 @@ mod api {
|
||||
include!(concat!(env!("OUT_DIR"), "/api.ipc.rs"));
|
||||
}
|
||||
|
||||
pub use api::{EthSync, SyncProvider, ManageNetwork, SyncConfig, NetworkConfiguration};
|
||||
pub use api::{EthSync, SyncProvider, SyncClient, NetworkManagerClient, ManageNetwork, SyncConfig,
|
||||
NetworkConfiguration, ServiceConfiguration};
|
||||
pub use chain::{SyncStatus, SyncState};
|
||||
|
||||
|
@ -16,3 +16,4 @@
|
||||
|
||||
pub mod helpers;
|
||||
mod chain;
|
||||
mod rpc;
|
||||
|
29
sync/src/tests/rpc.rs
Normal file
29
sync/src/tests/rpc.rs
Normal file
@ -0,0 +1,29 @@
|
||||
// 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 <http://www.gnu.org/licenses/>.
|
||||
|
||||
use super::super::NetworkConfiguration;
|
||||
use util::NetworkConfiguration as BasicNetworkConfiguration;
|
||||
use std::convert::From;
|
||||
use ipc::binary::{serialize, deserialize};
|
||||
|
||||
#[test]
|
||||
fn network_settings_serialize() {
|
||||
let net_cfg = NetworkConfiguration::from(BasicNetworkConfiguration::new_local());
|
||||
let serialized = serialize(&net_cfg).unwrap();
|
||||
let deserialized = deserialize::<NetworkConfiguration>(&serialized).unwrap();
|
||||
|
||||
assert_eq!(net_cfg.udp_port, deserialized.udp_port);
|
||||
}
|
Loading…
Reference in New Issue
Block a user