2016-02-05 13:40:41 +01:00
// 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/>.
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-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 ;
2015-12-22 22:19:50 +01:00
extern crate ethcore_util as util ;
2016-01-07 16:08:12 +01:00
extern crate ethcore ;
2016-01-29 15:56:06 +01:00
extern crate ethsync ;
2016-03-08 15:46:44 +01:00
extern crate ethminer ;
2016-02-18 12:42:01 +01:00
#[ macro_use ]
2016-01-31 11:08:04 +01:00
extern crate log as rlog ;
2016-01-09 23:21:57 +01:00
extern crate env_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-18 13:10:04 +01:00
extern crate daemonize ;
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-04-13 18:03:57 +02:00
extern crate ethcore_ipc as ipc ;
extern crate ethcore_ipc_nano as nanoipc ;
extern crate serde ;
extern crate bincode ;
2016-03-28 00:49:35 +02:00
// for price_info.rs
#[ macro_use ] extern crate hyper ;
2016-01-20 04:19:38 +01:00
#[ cfg(feature = " rpc " ) ]
2016-04-21 13:12:43 +02:00
extern crate ethcore_rpc ;
2016-04-07 10:49:00 +02:00
#[ cfg(feature = " webapp " ) ]
2016-04-21 13:57:27 +02:00
extern crate ethcore_webapp ;
2016-01-20 04:19:38 +01:00
2016-03-27 03:15:41 +02:00
use std ::io ::{ BufRead , BufReader } ;
2016-03-27 01:35:42 +01:00
use std ::fs ::File ;
2016-03-10 21:36:45 +01:00
use std ::net ::{ SocketAddr , IpAddr } ;
2016-01-14 22:38:49 +01:00
use std ::env ;
2016-02-15 18:36:34 +01:00
use std ::path ::PathBuf ;
2016-01-22 00:11:19 +01:00
use ctrlc ::CtrlC ;
2016-01-16 13:30:27 +01:00
use util ::* ;
2016-03-09 15:32:27 +01:00
use util ::panics ::{ MayPanic , ForwardPanic , PanicHandler } ;
2016-04-21 15:41:25 +02:00
use util ::keys ::store ::AccountService ;
2016-01-09 18:50:45 +01:00
use ethcore ::ethereum ;
2016-04-21 15:41:25 +02:00
use ethcore ::client ::{ append_path , get_db_path , ClientConfig } ;
use ethcore ::spec ::Spec ;
2016-04-21 13:57:27 +02:00
use ethcore ::service ::ClientService ;
use ethsync ::{ EthSync , SyncConfig } ;
2016-03-09 14:26:28 +01:00
use ethminer ::{ Miner , MinerService } ;
2016-02-18 14:16:55 +01:00
use docopt ::Docopt ;
use daemonize ::Daemonize ;
2016-01-23 23:53:20 +01:00
2016-04-21 13:12:43 +02:00
#[ macro_use ]
mod die ;
2016-03-28 00:49:35 +02:00
mod price_info ;
2016-04-10 15:12:20 +02:00
mod upgrade ;
2016-04-13 18:03:57 +02:00
mod hypervisor ;
2016-04-21 13:12:43 +02:00
mod setup_log ;
mod rpc ;
2016-04-21 13:57:27 +02:00
mod webapp ;
mod informant ;
mod io_handler ;
2016-04-21 15:41:25 +02:00
mod cli ;
2016-03-28 00:49:35 +02:00
2016-04-21 13:12:43 +02:00
use die ::* ;
2016-04-21 15:41:25 +02:00
use cli ::{ USAGE , print_version , Args } ;
2016-04-21 13:12:43 +02:00
use rpc ::RpcServer ;
2016-04-21 13:57:27 +02:00
use webapp ::WebappServer ;
use io_handler ::ClientIoHandler ;
2016-03-07 12:21:11 +01:00
2016-04-21 15:41:25 +02:00
struct Configuration {
args : Args
}
fn main ( ) {
let conf = Configuration ::parse ( ) ;
execute ( conf ) ;
2016-02-18 14:16:55 +01:00
}
2015-12-22 22:19:50 +01:00
2016-04-21 15:41:25 +02:00
fn execute ( conf : Configuration ) {
if conf . args . flag_version {
print_version ( ) ;
return ;
}
execute_upgrades ( & conf ) ;
if conf . args . cmd_daemon {
Daemonize ::new ( )
. pid_file ( conf . args . arg_pid_file . clone ( ) )
. chown_pid_file ( true )
. start ( )
. unwrap_or_else ( | e | die! ( " Couldn't daemonize; {} " , e ) ) ;
}
2016-01-20 04:19:38 +01:00
2016-04-21 15:41:25 +02:00
if conf . args . cmd_account {
execute_account_cli ( conf ) ;
return ;
}
2016-02-09 15:51:48 +01:00
2016-04-21 15:41:25 +02:00
execute_client ( conf ) ;
2016-02-10 18:11:10 +01:00
}
2016-04-21 15:41:25 +02:00
fn execute_upgrades ( conf : & Configuration ) {
match ::upgrade ::upgrade ( Some ( & conf . path ( ) ) ) {
Ok ( upgrades_applied ) if upgrades_applied > 0 = > {
println! ( " Executed {} upgrade scripts - ok " , upgrades_applied ) ;
} ,
Err ( e ) = > {
die! ( " Error upgrading parity data: {:?} " , e ) ;
} ,
_ = > { } ,
}
}
fn execute_client ( conf : Configuration ) {
// Setup panic handler
let panic_handler = PanicHandler ::new_in_arc ( ) ;
// Setup logging
let logger = setup_log ::setup_log ( & conf . args . flag_logging ) ;
// Raise fdlimit
unsafe { ::fdlimit ::raise_fd_limit ( ) ; }
let spec = conf . spec ( ) ;
let net_settings = conf . net_settings ( & spec ) ;
let sync_config = conf . sync_config ( & spec ) ;
let client_config = conf . client_config ( & spec ) ;
// Secret Store
let account_service = Arc ::new ( conf . account_service ( ) ) ;
// Build client
let mut service = ClientService ::start (
client_config , spec , net_settings , & Path ::new ( & conf . path ( ) )
) . unwrap_or_else ( | e | die_with_error ( e ) ) ;
panic_handler . forward_from ( & service ) ;
let client = service . client ( ) ;
// Miner
let miner = Miner ::new ( conf . args . flag_force_sealing ) ;
miner . set_author ( conf . author ( ) ) ;
miner . set_gas_floor_target ( conf . gas_floor_target ( ) ) ;
miner . set_extra_data ( conf . extra_data ( ) ) ;
miner . set_minimal_gas_price ( conf . gas_price ( ) ) ;
miner . set_transactions_limit ( conf . args . flag_tx_limit ) ;
// Sync
let sync = EthSync ::register ( service . network ( ) , sync_config , client . clone ( ) , miner . clone ( ) ) ;
// Setup rpc
let rpc_server = rpc ::new ( rpc ::Configuration {
enabled : conf . args . flag_jsonrpc | | conf . args . flag_rpc ,
interface : conf . args . flag_rpcaddr . clone ( ) . unwrap_or ( conf . args . flag_jsonrpc_interface . clone ( ) ) ,
port : conf . args . flag_rpcport . unwrap_or ( conf . args . flag_jsonrpc_port ) ,
apis : conf . args . flag_rpcapi . clone ( ) . unwrap_or ( conf . args . flag_jsonrpc_apis . clone ( ) ) ,
cors : conf . args . flag_jsonrpc_cors . clone ( ) . or ( conf . args . flag_rpccorsdomain . clone ( ) ) ,
} , rpc ::Dependencies {
client : client . clone ( ) ,
sync : sync . clone ( ) ,
secret_store : account_service . clone ( ) ,
miner : miner . clone ( ) ,
logger : logger . clone ( )
} ) ;
let webapp_server = webapp ::new ( webapp ::Configuration {
enabled : conf . args . flag_webapp ,
interface : conf . args . flag_webapp_interface . clone ( ) ,
port : conf . args . flag_webapp_port ,
user : conf . args . flag_webapp_user . clone ( ) ,
pass : conf . args . flag_webapp_pass . clone ( ) ,
} , webapp ::Dependencies {
client : client . clone ( ) ,
sync : sync . clone ( ) ,
secret_store : account_service . clone ( ) ,
miner : miner . clone ( ) ,
logger : logger . clone ( )
} ) ;
// Register IO handler
let io_handler = Arc ::new ( ClientIoHandler {
client : service . client ( ) ,
info : Default ::default ( ) ,
sync : sync . clone ( ) ,
accounts : account_service . clone ( ) ,
} ) ;
service . io ( ) . register_handler ( io_handler ) . expect ( " Error registering IO handler " ) ;
// Handle exit
wait_for_exit ( panic_handler , rpc_server , webapp_server ) ;
}
fn execute_account_cli ( conf : Configuration ) {
use util ::keys ::store ::SecretStore ;
use rpassword ::read_password ;
let mut secret_store = SecretStore ::new_in ( Path ::new ( & conf . keys_path ( ) ) ) ;
if conf . args . cmd_new {
println! ( " Please note that password is NOT RECOVERABLE. " ) ;
print! ( " Type password: " ) ;
let password = read_password ( ) . unwrap ( ) ;
print! ( " Repeat password: " ) ;
let password_repeat = read_password ( ) . unwrap ( ) ;
if password ! = password_repeat {
println! ( " Passwords do not match! " ) ;
return ;
}
println! ( " New account address: " ) ;
let new_address = secret_store . new_account ( & password ) . unwrap ( ) ;
println! ( " {:?} " , new_address ) ;
return ;
}
if conf . args . cmd_list {
println! ( " Known addresses: " ) ;
for & ( addr , _ ) in & secret_store . accounts ( ) . unwrap ( ) {
println! ( " {:?} " , addr ) ;
}
}
}
fn wait_for_exit ( panic_handler : Arc < PanicHandler > , _rpc_server : Option < RpcServer > , _webapp_server : Option < WebappServer > ) {
let exit = Arc ::new ( Condvar ::new ( ) ) ;
// Handle possible exits
let e = exit . clone ( ) ;
CtrlC ::set_handler ( move | | { e . notify_all ( ) ; } ) ;
// Handle panics
let e = exit . clone ( ) ;
panic_handler . on_panic ( move | _reason | { e . notify_all ( ) ; } ) ;
// Wait for signal
let mutex = Mutex ::new ( ( ) ) ;
let _ = exit . wait ( mutex . lock ( ) . unwrap ( ) ) . unwrap ( ) ;
info! ( " Finishing work, please wait... " ) ;
2016-02-10 18:11:10 +01:00
}
impl Configuration {
fn parse ( ) -> Self {
Configuration {
2016-02-18 14:16:55 +01:00
args : Docopt ::new ( USAGE ) . and_then ( | d | d . decode ( ) ) . unwrap_or_else ( | e | e . exit ( ) ) ,
2016-02-10 18:11:10 +01:00
}
2016-02-10 13:13:04 +01:00
}
2016-02-10 21:17:47 +01:00
fn path ( & self ) -> String {
2016-03-10 21:36:45 +01:00
let d = self . args . flag_datadir . as_ref ( ) . unwrap_or ( & self . args . flag_db_path ) ;
d . replace ( " $HOME " , env ::home_dir ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) )
2016-02-10 21:17:47 +01:00
}
2016-03-01 16:58:14 +01:00
fn author ( & self ) -> Address {
2016-03-10 21:36:45 +01:00
let d = self . args . flag_etherbase . as_ref ( ) . unwrap_or ( & self . args . flag_author ) ;
2016-03-19 23:51:24 +01:00
Address ::from_str ( clean_0x ( d ) ) . unwrap_or_else ( | _ | {
2016-04-04 02:03:20 +02:00
die! ( " {}: Invalid address for --author. Must be 40 hex characters, with or without the 0x at the beginning. " , d )
2016-03-10 10:09:55 +01:00
} )
2016-03-01 16:58:14 +01:00
}
2016-03-14 02:00:22 +01:00
fn gas_floor_target ( & self ) -> U256 {
let d = & self . args . flag_gas_floor_target ;
U256 ::from_dec_str ( d ) . unwrap_or_else ( | _ | {
die! ( " {}: Invalid target gas floor given. Must be a decimal unsigned 256-bit number. " , d )
} )
}
2016-03-13 15:29:55 +01:00
fn gas_price ( & self ) -> U256 {
2016-03-28 00:49:35 +02:00
match self . args . flag_gasprice . as_ref ( ) {
Some ( d ) = > {
U256 ::from_dec_str ( d ) . unwrap_or_else ( | _ | {
die! ( " {}: Invalid gas price given. Must be a decimal unsigned 256-bit number. " , d )
} )
}
_ = > {
let usd_per_tx : f32 = FromStr ::from_str ( & self . args . flag_usd_per_tx ) . unwrap_or_else ( | _ | {
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 ( ) {
2016-04-06 10:07:24 +02:00
" etherscan " = > price_info ::PriceInfo ::get ( ) . map_or_else ( | | {
2016-03-28 00:49:35 +02:00
die! ( " Unable to retrieve USD value of ETH from etherscan. Rerun with a different value for --usd-per-eth. " )
2016-04-06 10:07:24 +02:00
} , | x | x . ethusd ) ,
2016-03-28 00:49:35 +02:00
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 ;
let gas_per_tx : f32 = 21000.0 ;
let wei_per_gas : f32 = wei_per_usd * usd_per_tx / gas_per_tx ;
info! ( " Using a conversion rate of Ξ1 = US${} ({} wei/gas) " , usd_per_eth , wei_per_gas ) ;
U256 ::from_dec_str ( & format! ( " {:.0} " , wei_per_gas ) ) . unwrap ( )
}
}
2016-03-01 16:58:14 +01:00
}
fn extra_data ( & self ) -> Bytes {
2016-03-10 21:36:45 +01:00
match self . args . flag_extradata . as_ref ( ) . or ( self . args . flag_extra_data . as_ref ( ) ) {
2016-03-01 16:58:14 +01:00
Some ( ref x ) if x . len ( ) < = 32 = > x . as_bytes ( ) . to_owned ( ) ,
None = > version_data ( ) ,
Some ( ref x ) = > { die! ( " {}: Extra data must be at most 32 characters. " , x ) ; }
}
}
2016-04-06 13:21:19 +02:00
fn keys_path ( & self ) -> String {
2016-02-23 11:40:23 +01:00
self . args . flag_keys_path . replace ( " $HOME " , env ::home_dir ( ) . unwrap ( ) . to_str ( ) . unwrap ( ) )
2016-02-18 12:42:01 +01:00
}
2016-02-10 21:17:47 +01:00
fn spec ( & self ) -> Spec {
2016-03-07 12:21:11 +01:00
if self . args . flag_testnet {
return ethereum ::new_morden ( ) ;
}
2016-02-10 14:16:42 +01:00
match self . args . flag_chain . as_ref ( ) {
2016-03-07 12:21:11 +01:00
" frontier " | " homestead " | " mainnet " = > ethereum ::new_frontier ( ) ,
2016-02-10 13:13:04 +01:00
" morden " | " testnet " = > ethereum ::new_morden ( ) ,
" olympic " = > ethereum ::new_olympic ( ) ,
2016-04-09 19:20:35 +02:00
f = > Spec ::load ( contents ( f ) . unwrap_or_else ( | _ | {
2016-03-10 10:09:55 +01:00
die! ( " {}: Couldn't read chain specification file. Sure it exists? " , f )
} ) . as_ref ( ) ) ,
2016-02-19 12:54:51 +01:00
}
}
fn normalize_enode ( e : & str ) -> Option < String > {
2016-02-23 11:40:23 +01:00
if is_valid_node_url ( e ) {
Some ( e . to_owned ( ) )
} else {
None
2016-02-19 20:02:23 +01:00
}
2016-02-10 13:13:04 +01:00
}
2016-02-10 21:17:47 +01:00
fn init_nodes ( & self , spec : & Spec ) -> Vec < String > {
2016-03-14 00:52:31 +01:00
match self . args . flag_bootnodes {
2016-03-18 10:14:19 +01:00
Some ( ref x ) if ! x . is_empty ( ) = > x . split ( ',' ) . map ( | s | {
2016-03-11 14:26:23 +01:00
Self ::normalize_enode ( s ) . unwrap_or_else ( | | {
2016-03-10 10:09:55 +01:00
die! ( " {}: Invalid node address format given for a boot node. " , s )
2016-03-11 14:26:23 +01:00
} )
2016-03-14 00:52:31 +01:00
} ) . collect ( ) ,
Some ( _ ) = > Vec ::new ( ) ,
None = > spec . nodes ( ) . clone ( ) ,
2016-02-10 12:50:27 +01:00
}
}
2016-02-16 02:05:36 +01:00
fn net_addresses ( & self ) -> ( Option < SocketAddr > , Option < SocketAddr > ) {
2016-03-11 10:05:27 +01:00
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: " ) {
let host = & self . args . flag_nat [ 6 .. ] ;
let host = IpAddr ::from_str ( host ) . unwrap_or_else ( | _ | die! ( " Invalid host given with `--nat extip:{}` " , host ) ) ;
Some ( SocketAddr ::new ( host , self . args . flag_port ) )
2016-03-10 21:36:45 +01:00
} else {
2016-03-12 10:07:55 +01:00
listen_address
2016-03-10 21:36:45 +01:00
} ;
2016-02-10 12:50:27 +01:00
( listen_address , public_address )
}
2016-02-18 12:42:01 +01:00
2016-02-19 12:54:51 +01:00
fn net_settings ( & self , spec : & Spec ) -> NetworkConfiguration {
let mut ret = NetworkConfiguration ::new ( ) ;
2016-03-10 21:36:45 +01:00
ret . nat_enabled = self . args . flag_nat = = " any " | | self . args . flag_nat = = " upnp " ;
2016-02-19 12:54:51 +01:00
ret . boot_nodes = self . init_nodes ( spec ) ;
let ( listen , public ) = self . net_addresses ( ) ;
ret . listen_address = listen ;
ret . public_address = public ;
2016-02-22 13:58:41 +01:00
ret . use_secret = self . args . flag_node_key . as_ref ( ) . map ( | s | Secret ::from_str ( & s ) . unwrap_or_else ( | _ | s . sha3 ( ) ) ) ;
2016-03-10 21:36:45 +01:00
ret . discovery_enabled = ! self . args . flag_no_discovery & & ! self . args . flag_nodiscover ;
ret . ideal_peers = self . args . flag_maxpeers . unwrap_or ( self . args . flag_peers ) as u32 ;
2016-02-19 19:55:26 +01:00
let mut net_path = PathBuf ::from ( & self . path ( ) ) ;
net_path . push ( " network " ) ;
ret . config_path = Some ( net_path . to_str ( ) . unwrap ( ) . to_owned ( ) ) ;
2016-02-19 20:02:23 +01:00
ret
2016-02-19 12:54:51 +01:00
}
2016-04-12 03:42:50 +02:00
fn find_best_db ( & self , spec : & Spec ) -> Option < journaldb ::Algorithm > {
2016-04-12 00:51:14 +02:00
let mut ret = None ;
let mut latest_era = None ;
2016-04-12 03:42:50 +02:00
let jdb_types = [ journaldb ::Algorithm ::Archive , journaldb ::Algorithm ::EarlyMerge , journaldb ::Algorithm ::OverlayRecent , journaldb ::Algorithm ::RefCounted ] ;
for i in jdb_types . into_iter ( ) {
let db = journaldb ::new ( & append_path ( & get_db_path ( & Path ::new ( & self . path ( ) ) , * i , spec . genesis_header ( ) . hash ( ) ) , " state " ) , * i ) ;
2016-04-13 20:26:41 +02:00
trace! ( target : " parity " , " Looking for best DB: {} at {:?} " , i , db . latest_era ( ) ) ;
2016-04-12 00:51:14 +02:00
match ( latest_era , db . latest_era ( ) ) {
( Some ( best ) , Some ( this ) ) if best > = this = > { }
( _ , None ) = > { }
( _ , Some ( this ) ) = > {
latest_era = Some ( this ) ;
2016-04-12 03:42:50 +02:00
ret = Some ( * i ) ;
2016-04-12 00:51:14 +02:00
}
}
}
ret
}
2016-04-12 03:42:50 +02:00
fn client_config ( & self , spec : & Spec ) -> ClientConfig {
2016-03-08 15:46:44 +01:00
let mut client_config = ClientConfig ::default ( ) ;
match self . args . flag_cache {
Some ( mb ) = > {
client_config . blockchain . max_cache_size = mb * 1024 * 1024 ;
2016-03-14 00:52:31 +01:00
client_config . blockchain . pref_cache_size = client_config . blockchain . max_cache_size * 3 / 4 ;
2016-03-08 15:46:44 +01:00
}
None = > {
client_config . blockchain . pref_cache_size = self . args . flag_cache_pref_size ;
client_config . blockchain . max_cache_size = self . args . flag_cache_max_size ;
}
}
2016-03-11 19:22:40 +01:00
client_config . pruning = match self . args . flag_pruning . as_str ( ) {
2016-03-13 21:43:41 +01:00
" archive " = > journaldb ::Algorithm ::Archive ,
" light " = > journaldb ::Algorithm ::EarlyMerge ,
2016-03-12 10:22:43 +01:00
" fast " = > journaldb ::Algorithm ::OverlayRecent ,
2016-03-13 21:43:41 +01:00
" basic " = > journaldb ::Algorithm ::RefCounted ,
2016-04-12 03:42:50 +02:00
" auto " = > self . find_best_db ( spec ) . unwrap_or ( journaldb ::Algorithm ::OverlayRecent ) ,
2016-03-11 19:22:40 +01:00
_ = > { die! ( " Invalid pruning method given. " ) ; }
} ;
2016-04-13 20:26:41 +02:00
trace! ( target : " parity " , " Using pruning strategy of {} " , client_config . pruning ) ;
2016-03-08 15:46:44 +01:00
client_config . name = self . args . flag_identity . clone ( ) ;
client_config . queue . max_mem_use = self . args . flag_queue_max_size ;
client_config
}
fn sync_config ( & self , spec : & Spec ) -> SyncConfig {
let mut sync_config = SyncConfig ::default ( ) ;
2016-03-14 00:52:31 +01:00
sync_config . network_id = self . args . flag_network_id . as_ref ( ) . or ( self . args . flag_networkid . as_ref ( ) ) . map_or ( spec . network_id ( ) , | id | {
U256 ::from_str ( id ) . unwrap_or_else ( | _ | die! ( " {}: Invalid index given with --network-id/--networkid " , id ) )
2016-03-11 14:52:47 +01:00
} ) ;
2016-03-08 15:46:44 +01:00
sync_config
}
2016-03-27 01:35:42 +01:00
fn account_service ( & self ) -> AccountService {
// Secret Store
2016-03-27 03:15:41 +02:00
let passwords = self . args . flag_password . iter ( ) . flat_map ( | filename | {
BufReader ::new ( & File ::open ( filename ) . unwrap_or_else ( | _ | die! ( " {} Unable to read password file. Ensure it exists and permissions are correct. " , filename ) ) )
. lines ( )
. map ( | l | l . unwrap ( ) )
. collect ::< Vec < _ > > ( )
. into_iter ( )
} ) . collect ::< Vec < _ > > ( ) ;
2016-04-06 13:21:19 +02:00
let account_service = AccountService ::new_in ( Path ::new ( & self . keys_path ( ) ) ) ;
2016-04-09 21:58:13 +02:00
if let Some ( ref unlocks ) = self . args . flag_unlock {
for d in unlocks . split ( ',' ) {
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 )
} ) ;
if passwords . iter ( ) . find ( | p | account_service . unlock_account_no_expire ( & a , p ) . is_ok ( ) ) . is_none ( ) {
die! ( " No password given to unlock account {}. Pass the password using `--password`. " , a ) ;
}
2016-03-27 01:35:42 +01:00
}
}
account_service
}
2015-12-22 22:19:50 +01:00
}
2016-02-02 02:04:03 +01:00
/// Parity needs at least 1 test to generate coverage reports correctly.
#[ test ]
fn if_works ( ) {
}