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:
Nikolay Volf 2016-07-20 18:13:56 +02:00 committed by Arkadiy Paronyan
parent 7ae9e61d6c
commit 8ab56ea3d1
22 changed files with 439 additions and 88 deletions

14
Cargo.lock generated
View File

@ -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"

View File

@ -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"

View File

@ -46,3 +46,4 @@ test-heavy = []
dev = ["clippy"]
default = []
benches = []
ipc = []

View File

@ -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) {

View File

@ -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;

View File

@ -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::*;

View File

@ -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
})
}

View File

@ -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());
}
}

View File

@ -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()) }

View File

@ -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);
}

View File

@ -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
}
}

View File

@ -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
View 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

View File

@ -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();

View File

@ -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)]

View File

@ -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(),

View File

@ -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>))

View File

@ -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>);

View File

@ -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,
}

View File

@ -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};

View File

@ -16,3 +16,4 @@
pub mod helpers;
mod chain;
mod rpc;

29
sync/src/tests/rpc.rs Normal file
View 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);
}