2016-12-11 19:14:42 +01:00
// Copyright 2015, 2016 Parity Technologies (UK) Ltd.
2016-02-05 13:40:41 +01:00
// 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/>.
2016-01-27 17:18:38 +01:00
//! Ethcore client application.
#![ warn(missing_docs) ]
2016-03-11 11:16:49 +01:00
#![ cfg_attr(feature= " dev " , feature(plugin)) ]
#![ cfg_attr(feature= " dev " , plugin(clippy)) ]
2016-04-06 10:07:24 +02:00
#![ cfg_attr(feature= " dev " , allow(useless_format)) ]
2016-07-10 13:18:33 +02:00
#![ cfg_attr(feature= " dev " , allow(match_bool)) ]
2016-04-21 13:12:43 +02:00
2016-01-23 23:53:20 +01:00
extern crate docopt ;
2016-03-22 19:12:17 +01:00
extern crate num_cpus ;
2016-01-23 23:53:20 +01:00
extern crate rustc_serialize ;
2016-07-29 10:48:05 +02:00
extern crate ethcore_devtools as devtools ;
2016-01-07 16:08:12 +01:00
extern crate ethcore ;
2016-01-29 15:56:06 +01:00
extern crate ethsync ;
2016-01-09 23:21:57 +01:00
extern crate env_logger ;
2016-07-25 16:09:47 +02:00
extern crate ethcore_logger ;
2016-01-22 00:11:19 +01:00
extern crate ctrlc ;
2016-02-05 13:49:36 +01:00
extern crate fdlimit ;
2016-02-23 20:14:37 +01:00
extern crate time ;
2016-02-25 14:09:39 +01:00
extern crate number_prefix ;
2016-03-09 14:11:15 +01:00
extern crate rpassword ;
2016-04-10 15:12:20 +02:00
extern crate semver ;
2016-08-05 10:32:04 +02:00
extern crate ethcore_io as io ;
2016-04-13 18:03:57 +02:00
extern crate ethcore_ipc as ipc ;
extern crate ethcore_ipc_nano as nanoipc ;
2016-09-26 19:21:25 +02:00
extern crate serde ;
extern crate serde_json ;
2016-09-01 14:55:07 +02:00
extern crate rlp ;
2016-12-08 23:21:47 +01:00
extern crate ethcore_light as light ;
2016-12-11 19:14:42 +01:00
extern crate parity_hash_fetch as hash_fetch ;
2016-09-01 14:55:07 +02:00
2016-07-09 17:18:34 +02:00
extern crate ethcore_ipc_hypervisor as hypervisor ;
2016-04-21 13:12:43 +02:00
extern crate ethcore_rpc ;
2016-07-11 17:11:49 +02:00
extern crate ethcore_signer ;
2016-12-11 19:14:42 +01:00
extern crate parity_updater as updater ;
2016-07-11 17:11:49 +02:00
extern crate ansi_term ;
2016-09-01 14:55:07 +02:00
2016-07-13 09:05:26 +02:00
extern crate regex ;
2016-07-15 10:11:14 +02:00
extern crate isatty ;
2016-09-10 11:37:14 +02:00
extern crate toml ;
2016-12-13 23:38:29 +01:00
extern crate app_dirs ;
2016-07-11 17:11:49 +02:00
2016-09-01 14:55:07 +02:00
#[ macro_use ]
extern crate ethcore_util as util ;
#[ macro_use ]
extern crate log as rlog ;
#[ macro_use ]
extern crate hyper ; // for price_info.rs
#[ macro_use ]
extern crate lazy_static ;
2016-08-24 18:35:38 +02:00
#[ cfg(feature= " stratum " ) ]
extern crate ethcore_stratum ;
2016-05-26 18:21:15 +02:00
#[ cfg(feature = " dapps " ) ]
extern crate ethcore_dapps ;
2016-01-20 04:19:38 +01:00
2016-08-24 18:35:38 +02:00
macro_rules ! dependency {
( $dep_ty :ident , $url :expr ) = > {
{
let dep = boot ::dependency ::< $dep_ty < _ > > ( $url )
. unwrap_or_else ( | e | panic! ( " Fatal: error connecting service ( {:?} ) " , e ) ) ;
dep . handshake ( )
. unwrap_or_else ( | e | panic! ( " Fatal: error in connected service ( {:?} ) " , e ) ) ;
dep
}
}
}
2016-07-25 16:09:47 +02:00
mod cache ;
2016-04-10 15:12:20 +02:00
mod upgrade ;
2016-04-21 13:12:43 +02:00
mod rpc ;
2016-05-26 18:21:15 +02:00
mod dapps ;
2016-04-21 13:57:27 +02:00
mod informant ;
2016-04-21 15:41:25 +02:00
mod cli ;
2016-04-21 16:45:04 +02:00
mod configuration ;
2016-05-26 18:24:51 +02:00
mod migration ;
2016-05-27 13:03:00 +02:00
mod signer ;
2016-06-01 19:37:34 +02:00
mod rpc_apis ;
2016-06-14 16:12:46 +02:00
mod url ;
2016-07-25 16:09:47 +02:00
mod helpers ;
mod params ;
mod deprecated ;
mod dir ;
2016-07-16 14:24:57 +02:00
mod modules ;
2016-07-25 16:09:47 +02:00
mod account ;
mod blockchain ;
mod presale ;
2016-09-06 15:31:13 +02:00
mod snapshot ;
2016-07-25 16:09:47 +02:00
mod run ;
2016-09-06 15:31:13 +02:00
#[ cfg(feature= " ipc " ) ]
2016-07-26 00:21:08 +02:00
mod sync ;
2016-09-06 15:31:13 +02:00
#[ cfg(feature= " ipc " ) ]
2016-08-24 18:35:38 +02:00
mod boot ;
2016-09-26 19:21:25 +02:00
mod user_defaults ;
2016-08-24 18:35:38 +02:00
#[ cfg(feature= " stratum " ) ]
mod stratum ;
2016-04-21 16:45:04 +02:00
2016-07-25 16:09:47 +02:00
use std ::{ process , env } ;
2016-12-10 23:58:39 +01:00
use std ::collections ::HashMap ;
2016-12-11 03:33:10 +01:00
use std ::io ::{ self as stdio , BufReader , Read , Write } ;
2016-09-23 15:28:09 +02:00
use std ::fs ::File ;
2016-12-10 23:58:39 +01:00
use std ::path ::PathBuf ;
2016-09-23 15:28:09 +02:00
use util ::sha3 ::sha3 ;
2016-09-10 11:37:14 +02:00
use cli ::Args ;
2016-11-02 19:42:21 +01:00
use configuration ::{ Cmd , Execute , Configuration } ;
2016-07-25 16:09:47 +02:00
use deprecated ::find_deprecated ;
2016-11-02 19:42:21 +01:00
use ethcore_logger ::setup_log ;
2016-07-25 16:09:47 +02:00
2016-09-23 15:28:09 +02:00
fn print_hash_of ( maybe_file : Option < String > ) -> Result < String , String > {
if let Some ( file ) = maybe_file {
let mut f = BufReader ::new ( try ! ( File ::open ( & file ) . map_err ( | _ | " Unable to open file " . to_owned ( ) ) ) ) ;
let hash = try ! ( sha3 ( & mut f ) . map_err ( | _ | " Unable to read from file " . to_owned ( ) ) ) ;
Ok ( hash . hex ( ) )
} else {
Err ( " Streaming from standard input not yet supported. Specify a file. " . to_owned ( ) )
}
}
2016-12-10 23:58:39 +01:00
enum PostExecutionAction {
Print ( String ) ,
Restart ,
Quit ,
}
2016-12-11 04:05:02 +01:00
fn execute ( command : Execute , can_restart : bool ) -> Result < PostExecutionAction , String > {
2016-11-02 19:42:21 +01:00
let logger = setup_log ( & command . logger ) . expect ( " Logger is initialized only once; qed " ) ;
match command . cmd {
2016-07-25 16:09:47 +02:00
Cmd ::Run ( run_cmd ) = > {
2016-12-11 04:05:02 +01:00
let restart = run ::execute ( run_cmd , can_restart , logger ) ? ;
2016-12-10 23:58:39 +01:00
Ok ( if restart { PostExecutionAction ::Restart } else { PostExecutionAction ::Quit } )
2016-04-21 15:41:25 +02:00
} ,
2016-12-10 23:58:39 +01:00
Cmd ::Version = > Ok ( PostExecutionAction ::Print ( Args ::print_version ( ) ) ) ,
Cmd ::Hash ( maybe_file ) = > print_hash_of ( maybe_file ) . map ( | s | PostExecutionAction ::Print ( s ) ) ,
Cmd ::Account ( account_cmd ) = > account ::execute ( account_cmd ) . map ( | s | PostExecutionAction ::Print ( s ) ) ,
Cmd ::ImportPresaleWallet ( presale_cmd ) = > presale ::execute ( presale_cmd ) . map ( | s | PostExecutionAction ::Print ( s ) ) ,
Cmd ::Blockchain ( blockchain_cmd ) = > blockchain ::execute ( blockchain_cmd ) . map ( | s | PostExecutionAction ::Print ( s ) ) ,
Cmd ::SignerToken ( signer_cmd ) = > signer ::execute ( signer_cmd ) . map ( | s | PostExecutionAction ::Print ( s ) ) ,
Cmd ::Snapshot ( snapshot_cmd ) = > snapshot ::execute ( snapshot_cmd ) . map ( | s | PostExecutionAction ::Print ( s ) ) ,
2016-05-26 18:24:51 +02:00
}
2016-04-21 15:41:25 +02:00
}
2016-12-11 04:05:02 +01:00
fn start ( can_restart : bool ) -> Result < PostExecutionAction , String > {
2016-09-10 11:37:14 +02:00
let args : Vec < String > = env ::args ( ) . collect ( ) ;
let conf = Configuration ::parse ( & args ) . unwrap_or_else ( | e | e . exit ( ) ) ;
2016-04-21 15:41:25 +02:00
2016-07-25 16:09:47 +02:00
let deprecated = find_deprecated ( & conf . args ) ;
for d in deprecated {
println! ( " {} " , d ) ;
2016-06-14 16:12:46 +02:00
}
2016-07-25 16:09:47 +02:00
let cmd = try ! ( conf . into_command ( ) ) ;
2016-12-11 04:05:02 +01:00
execute ( cmd , can_restart )
2016-05-23 18:42:59 +02:00
}
2016-12-10 23:58:39 +01:00
#[ cfg(not(feature= " stratum " )) ]
fn stratum_main ( _ : & mut HashMap < String , fn ( ) > ) { }
2016-08-24 18:35:38 +02:00
#[ cfg(feature= " stratum " ) ]
2016-12-10 23:58:39 +01:00
fn stratum_main ( alt_mains : & mut HashMap < String , fn ( ) > ) {
alt_mains . insert ( " stratum " . to_owned ( ) , stratum ::main ) ;
2016-08-24 18:35:38 +02:00
}
2016-12-10 23:58:39 +01:00
#[ cfg(not(feature= " ipc " )) ]
fn sync_main ( _ : & mut HashMap < String , fn ( ) > ) { }
#[ cfg(feature= " ipc " ) ]
fn sync_main ( alt_mains : & mut HashMap < String , fn ( ) > ) {
alt_mains . insert ( " sync " . to_owned ( ) , sync ::main ) ;
2016-08-24 18:35:38 +02:00
}
2016-12-10 23:58:39 +01:00
// TODO: merge with version in Updater.
2016-12-11 03:33:10 +01:00
fn updates_path ( name : & str ) -> PathBuf {
2016-12-10 23:58:39 +01:00
let mut dest = PathBuf ::from ( env ::home_dir ( ) . unwrap ( ) . to_str ( ) . expect ( " env filesystem paths really should be valid; qed " ) ) ;
dest . push ( " .parity-updates " ) ;
2016-12-11 03:33:10 +01:00
dest . push ( name ) ;
2016-12-10 23:58:39 +01:00
dest
2016-09-06 15:31:13 +02:00
}
2016-12-11 03:33:10 +01:00
fn latest_exe_path ( ) -> Option < PathBuf > {
File ::open ( updates_path ( " latest " ) ) . ok ( )
. and_then ( | mut f | { let mut exe = String ::new ( ) ; f . read_to_string ( & mut exe ) . ok ( ) . map ( | _ | updates_path ( & exe ) ) } )
}
2016-12-10 23:58:39 +01:00
// Starts ~/.parity-updates/parity and returns the code it exits with.
fn run_parity ( ) -> Option < i32 > {
2016-12-11 04:05:02 +01:00
use ::std ::ffi ::OsString ;
let prefix = vec! [ OsString ::from ( " --can-restart " ) , OsString ::from ( " --force-direct " ) ] ;
2016-12-11 03:33:10 +01:00
latest_exe_path ( ) . and_then ( | exe | process ::Command ::new ( exe )
2016-12-11 04:05:02 +01:00
. args ( & ( env ::args_os ( ) . chain ( prefix . into_iter ( ) ) . collect ::< Vec < _ > > ( ) ) )
. status ( )
. map ( | es | es . code ( ) . unwrap_or ( 128 ) )
. ok ( )
)
2016-12-10 23:58:39 +01:00
}
const PLEASE_RESTART_EXIT_CODE : i32 = 69 ;
// Run our version of parity.
// Returns the exit error code.
2016-12-11 04:05:02 +01:00
fn main_direct ( can_restart : bool ) -> i32 {
2016-12-10 23:58:39 +01:00
let mut alt_mains = HashMap ::new ( ) ;
sync_main ( & mut alt_mains ) ;
stratum_main ( & mut alt_mains ) ;
if let Some ( f ) = std ::env ::args ( ) . nth ( 1 ) . and_then ( | arg | alt_mains . get ( & arg . to_string ( ) ) ) {
f ( ) ;
0
2016-09-06 15:31:13 +02:00
} else {
2016-12-11 04:05:02 +01:00
match start ( can_restart ) {
2016-12-10 23:58:39 +01:00
Ok ( result ) = > match result {
2016-12-13 20:20:10 +01:00
PostExecutionAction ::Print ( s ) = > { println! ( " {} " , s ) ; 0 } ,
2016-12-10 23:58:39 +01:00
PostExecutionAction ::Restart = > PLEASE_RESTART_EXIT_CODE ,
PostExecutionAction ::Quit = > 0 ,
} ,
Err ( err ) = > {
writeln! ( & mut stdio ::stderr ( ) , " {} " , err ) . expect ( " StdErr available; qed " ) ;
1
} ,
}
2016-09-06 15:31:13 +02:00
}
}
2016-12-10 23:58:39 +01:00
fn println_trace_main ( s : String ) {
if env ::var ( " RUST_LOG " ) . ok ( ) . and_then ( | s | s . find ( " main=trace " ) ) . is_some ( ) {
println! ( " {} " , s ) ;
2016-07-26 00:21:08 +02:00
}
2016-12-10 23:58:39 +01:00
}
2016-07-26 00:21:08 +02:00
2016-12-10 23:58:39 +01:00
#[ macro_export ]
macro_rules ! trace_main {
( $arg :expr ) = > ( println_trace_main ( $arg . into ( ) ) ) ;
( $( $arg :tt ) * ) = > ( println_trace_main ( format! ( " {} " , format_args! ( $( $arg ) * ) ) ) ) ;
}
2016-08-24 18:35:38 +02:00
2016-12-10 23:58:39 +01:00
fn main ( ) {
// Always print backtrace on panic.
env ::set_var ( " RUST_BACKTRACE " , " 1 " ) ;
// assuming the user is not running with `--force-direct`, then:
// if argv[0] == "parity" and this executable != ~/.parity-updates/parity, run that instead.
let force_direct = std ::env ::args ( ) . any ( | arg | arg = = " --force-direct " ) ;
let exe = std ::env ::current_exe ( ) . ok ( ) ;
2016-12-11 02:02:40 +01:00
let development = exe . as_ref ( ) . and_then ( | p | p . parent ( ) . and_then ( | p | p . parent ( ) ) . and_then ( | p | p . file_name ( ) ) . map ( | n | n = = " target " ) ) . unwrap_or ( false ) ;
2016-12-11 03:33:10 +01:00
let same_name = exe . as_ref ( ) . map ( | p | p . file_stem ( ) . map_or ( false , | s | s = = " parity " ) & & p . extension ( ) . map_or ( true , | x | x = = " exe " ) ) . unwrap_or ( false ) ;
let latest_exe = latest_exe_path ( ) ;
let have_update = latest_exe . as_ref ( ) . map_or ( false , | p | p . exists ( ) ) ;
let is_non_updated_current = exe . map_or ( false , | exe | latest_exe . as_ref ( ) . map_or ( false , | lexe | exe . canonicalize ( ) . ok ( ) ! = lexe . canonicalize ( ) . ok ( ) ) ) ;
2016-12-11 02:02:40 +01:00
trace_main! ( " Starting up {} (force-direct: {}, development: {}, same-name: {}, have-update: {}, non-updated-current: {}) " , std ::env ::current_exe ( ) . map ( | x | format! ( " {} " , x . display ( ) ) ) . unwrap_or ( " <unknown> " . to_owned ( ) ) , force_direct , development , same_name , have_update , is_non_updated_current ) ;
if ! force_direct & & ! development & & same_name & & have_update & & is_non_updated_current {
2016-12-10 23:58:39 +01:00
// looks like we're not running ~/.parity-updates/parity when the user is expecting otherwise.
// Everything run inside a loop, so we'll be able to restart from the child into a new version seamlessly.
loop {
// If we fail to run the updated parity then fallback to local version.
2016-12-11 03:33:10 +01:00
trace_main! ( " Attempting to run latest update ({})... " , latest_exe . as_ref ( ) . expect ( " guarded by have_update; latest_exe must exist for have_update; qed " ) . display ( ) ) ;
2016-12-11 04:05:02 +01:00
let exit_code = run_parity ( ) . unwrap_or_else ( | | { trace_main! ( " Falling back to local... " ) ; main_direct ( true ) } ) ;
2016-12-10 23:58:39 +01:00
trace_main! ( " Latest exited with {} " , exit_code ) ;
if exit_code ! = PLEASE_RESTART_EXIT_CODE {
trace_main! ( " Quitting... " ) ;
process ::exit ( exit_code ) ;
}
trace_main! ( " Rerunning... " ) ;
2016-05-24 20:29:19 +02:00
}
2016-12-10 23:58:39 +01:00
} else {
trace_main! ( " Running direct " ) ;
// Otherwise, we're presumably running the version we want. Just run and fall-through.
2016-12-11 04:05:02 +01:00
let can_restart = std ::env ::args ( ) . any ( | arg | arg = = " --can-restart " ) ;
process ::exit ( main_direct ( can_restart ) ) ;
2016-05-24 20:29:19 +02:00
}
2016-06-07 17:21:19 +02:00
}