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-01-23 23:53:20 +01:00
extern crate docopt ;
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-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 ;
2015-12-22 22:19:50 +01:00
2016-01-20 04:19:38 +01:00
#[ cfg(feature = " rpc " ) ]
2016-01-26 13:14:22 +01:00
extern crate ethcore_rpc as rpc ;
2016-01-20 04:19:38 +01:00
2016-02-08 15:04:12 +01:00
use std ::net ::{ SocketAddr } ;
2016-01-14 22:38:49 +01:00
use std ::env ;
2016-02-19 12:54:51 +01:00
use std ::process ::exit ;
2016-02-15 18:36:34 +01:00
use std ::path ::PathBuf ;
2016-01-14 22:38:49 +01:00
use env_logger ::LogBuilder ;
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-02-09 15:51:48 +01:00
use ethcore ::spec ::* ;
2016-01-16 13:30:27 +01:00
use ethcore ::client ::* ;
2016-01-21 23:33:52 +01:00
use ethcore ::service ::{ ClientService , NetSyncMessage } ;
2016-01-09 18:50:45 +01:00
use ethcore ::ethereum ;
2016-03-10 17:32:17 +01:00
use ethsync ::{ EthSync , SyncConfig , SyncProvider } ;
2016-02-18 14:16:55 +01:00
use docopt ::Docopt ;
use daemonize ::Daemonize ;
2016-02-25 14:09:39 +01:00
use number_prefix ::{ binary_prefix , Standalone , Prefixed } ;
2016-01-23 23:53:20 +01:00
2016-03-07 12:21:11 +01:00
fn die_with_message ( msg : & str ) -> ! {
println! ( " ERROR: {} " , msg ) ;
exit ( 1 ) ;
}
#[ macro_export ]
macro_rules ! die {
( $( $arg :tt ) * ) = > ( die_with_message ( & format! ( " {} " , format_args! ( $( $arg ) * ) ) ) ) ;
}
2016-02-22 13:41:38 +01:00
const USAGE : & 'static str = r #"
2016-01-23 23:53:20 +01:00
Parity . Ethereum Client .
2016-02-09 15:51:48 +01:00
By Wood / Paronyan / Kotewicz / Drwięga / Volf .
Copyright 2015 , 2016 Ethcore ( UK ) Limited
2016-01-23 23:53:20 +01:00
Usage :
2016-02-18 14:28:24 +01:00
parity daemon < pid - file > [ options ] [ - - no - bootstrap | < enode > .. . ]
2016-03-09 20:39:36 +01:00
parity account ( new | list )
2016-02-11 10:46:55 +01:00
parity [ options ] [ - - no - bootstrap | < enode > .. . ]
2016-01-23 23:53:20 +01:00
2016-03-07 12:21:11 +01:00
Protocol Options :
2016-02-09 15:51:48 +01:00
- - chain CHAIN Specify the blockchain type . CHAIN may be either a JSON chain specification file
2016-03-07 12:21:11 +01:00
or olympic , frontier , homestead , mainnet , morden , or testnet [ default : homestead ] .
- - testnet Equivalent to - - chain testnet ( geth - compatible ) .
- - networkid INDEX Override the network identifier from the chain we are on .
2016-03-10 17:09:34 +01:00
- - pruning Client should prune the state / storage trie .
2016-03-07 12:21:11 +01:00
- d - - datadir PATH Specify the database & configuration directory path [ default : $HOME / . parity ]
2016-02-18 12:42:01 +01:00
- - keys - path PATH Specify the path for JSON key files to be found [ default : $HOME / . web3 / keys ]
2016-03-07 12:21:11 +01:00
- - identity NAME Specify your node ' s name .
2016-02-02 01:59:14 +01:00
2016-03-07 12:21:11 +01:00
Networking Options :
2016-02-11 10:46:55 +01:00
- - no - bootstrap Don ' t bother trying to connect to any nodes initially .
2016-02-08 15:04:12 +01:00
- - listen - address URL Specify the IP / port on which to listen for peers [ default : 0. 0. 0.0 :30304 ] .
2016-02-16 02:05:36 +01:00
- - public - address URL Specify the IP / port on which peers may connect .
2016-02-08 15:04:12 +01:00
- - address URL Equivalent to - - listen - address URL - - public - address URL .
2016-02-26 22:40:32 +01:00
- - peers NUM Try to maintain that many peers [ default : 25 ] .
- - no - discovery Disable new peer discovery .
2016-02-23 19:38:06 +01:00
- - no - upnp Disable trying to figure out the correct public adderss over UPnP .
2016-02-22 18:10:21 +01:00
- - node - key KEY Specify node secret key , either as 64 - character hex string or input to SHA3 operation .
2016-02-08 15:04:12 +01:00
2016-03-07 12:21:11 +01:00
API and Console Options :
2016-02-09 15:51:48 +01:00
- j - - jsonrpc Enable the JSON - RPC API sever .
2016-03-07 12:21:11 +01:00
- - jsonrpc - addr HOST Specify the hostname portion of the JSONRPC API server [ default : 127. 0. 0.1 ] .
- - jsonrpc - port PORT Specify the port portion of the JSONRPC API server [ default : 8545 ] .
2016-02-22 13:41:38 +01:00
- - jsonrpc - cors URL Specify CORS header for JSON - RPC API responses [ default : null ] .
2016-03-07 12:21:11 +01:00
- - jsonrpc - apis APIS Specify the APIs available through the JSONRPC interface . APIS is a comma - delimited
list of API name . Possible name are web3 , eth and net . [ default : web3 , eth , net ] .
- - rpc Equivalent to - - jsonrpc ( geth - compatible ) .
- - rpcaddr HOST Equivalent to - - jsonrpc - addr HOST ( geth - compatible ) .
- - rpcport PORT Equivalent to - - jsonrpc - port PORT ( geth - compatible ) .
- - rpcapi APIS Equivalent to - - jsonrpc - apis APIS ( geth - compatible ) .
- - rpccorsdomain URL Equivalent to - - jsonrpc - cors URL ( geth - compatible ) .
Sealing / Mining Options :
2016-03-01 16:58:14 +01:00
- - author ADDRESS Specify the block author ( aka " coinbase " ) address for sending block rewards
from sealed blocks [ default : 0037 a6b811ffeb6e072da21179d11b1406371c63 ] .
2016-03-07 12:21:11 +01:00
- - extradata STRING Specify a custom extra - data for authored blocks , no more than 32 characters .
Memory Footprint Options :
- - cache - pref - size BYTES Specify the prefered size of the blockchain cache in bytes [ default : 16384 ] .
- - cache - max - size BYTES Specify the maximum size of the blockchain cache in bytes [ default : 262144 ] .
- - queue - max - size BYTES Specify the maximum size of memory to use for block queue [ default : 52428800 ] .
2016-03-08 16:42:30 +01:00
- - cache MEGABYTES Set total amount of cache to use for the entire system , mutually exclusive with
2016-03-07 12:21:11 +01:00
other cache options ( geth - compatible ) .
2016-03-01 16:58:14 +01:00
2016-03-07 12:21:11 +01:00
Miscellaneous Options :
2016-02-09 15:51:48 +01:00
- l - - logging LOGGING Specify the logging level .
- v - - version Show information about version .
2016-02-02 01:59:14 +01:00
- h - - help Show this screen .
2016-02-22 13:41:38 +01:00
" #;
2016-02-18 14:16:55 +01:00
#[ derive(Debug, RustcDecodable) ]
struct Args {
cmd_daemon : bool ,
2016-03-09 14:11:15 +01:00
cmd_account : bool ,
2016-03-09 20:39:36 +01:00
cmd_new : bool ,
cmd_list : bool ,
2016-02-18 14:16:55 +01:00
arg_pid_file : String ,
arg_enode : Vec < String > ,
flag_chain : String ,
2016-03-07 12:21:11 +01:00
flag_testnet : bool ,
2016-03-08 16:42:30 +01:00
flag_datadir : String ,
2016-03-07 12:21:11 +01:00
flag_networkid : Option < String > ,
flag_identity : String ,
flag_cache : Option < usize > ,
2016-02-18 14:16:55 +01:00
flag_keys_path : String ,
2016-03-10 17:09:34 +01:00
flag_pruning : bool ,
2016-02-18 14:16:55 +01:00
flag_no_bootstrap : bool ,
flag_listen_address : String ,
2016-02-18 21:49:11 +01:00
flag_public_address : Option < String > ,
2016-02-18 14:16:55 +01:00
flag_address : Option < String > ,
2016-03-07 12:21:11 +01:00
flag_peers : usize ,
2016-02-18 21:49:11 +01:00
flag_no_discovery : bool ,
2016-02-23 19:38:06 +01:00
flag_no_upnp : bool ,
2016-02-18 14:16:55 +01:00
flag_node_key : Option < String > ,
flag_cache_pref_size : usize ,
flag_cache_max_size : usize ,
2016-02-25 14:09:39 +01:00
flag_queue_max_size : usize ,
2016-02-18 14:16:55 +01:00
flag_jsonrpc : bool ,
2016-03-07 12:21:11 +01:00
flag_jsonrpc_addr : String ,
flag_jsonrpc_port : u16 ,
2016-02-22 13:41:38 +01:00
flag_jsonrpc_cors : String ,
2016-03-07 12:21:11 +01:00
flag_jsonrpc_apis : String ,
flag_rpc : bool ,
flag_rpcaddr : Option < String > ,
flag_rpcport : Option < u16 > ,
flag_rpccorsdomain : Option < String > ,
flag_rpcapi : Option < String > ,
2016-02-18 14:16:55 +01:00
flag_logging : Option < String > ,
flag_version : bool ,
2016-03-01 16:58:14 +01:00
flag_author : String ,
flag_extra_data : Option < String > ,
2016-02-18 14:16:55 +01:00
}
2015-12-22 22:19:50 +01:00
2016-02-18 14:16:55 +01:00
fn setup_log ( init : & Option < String > ) {
2016-02-23 20:14:37 +01:00
use rlog ::* ;
2016-01-14 22:38:49 +01:00
let mut builder = LogBuilder ::new ( ) ;
2016-01-15 01:44:57 +01:00
builder . filter ( None , LogLevelFilter ::Info ) ;
2016-01-14 22:38:49 +01:00
if env ::var ( " RUST_LOG " ) . is_ok ( ) {
builder . parse ( & env ::var ( " RUST_LOG " ) . unwrap ( ) ) ;
}
2016-02-18 14:16:55 +01:00
if let Some ( ref s ) = * init {
builder . parse ( s ) ;
}
2016-01-23 23:53:20 +01:00
2016-02-23 20:14:37 +01:00
let format = | record : & LogRecord | {
let timestamp = time ::strftime ( " %Y-%m-%d %H:%M:%S %Z " , & time ::now ( ) ) . unwrap ( ) ;
if max_log_level ( ) < = LogLevelFilter ::Info {
format! ( " {} {} " , timestamp , record . args ( ) )
} else {
format! ( " {} {} : {} : {} " , timestamp , record . level ( ) , record . target ( ) , record . args ( ) )
}
} ;
builder . format ( format ) ;
2016-01-14 22:38:49 +01:00
builder . init ( ) . unwrap ( ) ;
}
2016-01-20 04:19:38 +01:00
#[ cfg(feature = " rpc " ) ]
2016-03-09 13:46:08 +01:00
fn setup_rpc_server ( client : Arc < Client > , sync : Arc < EthSync > , url : & str , cors_domain : & str , apis : Vec < & str > ) -> Option < Arc < PanicHandler > > {
2016-01-27 17:14:41 +01:00
use rpc ::v1 ::* ;
2016-02-10 12:50:27 +01:00
2016-03-09 18:04:13 +01:00
let server = rpc ::RpcServer ::new ( ) ;
2016-03-07 12:21:11 +01:00
for api in apis . into_iter ( ) {
match api {
" web3 " = > server . add_delegate ( Web3Client ::new ( ) . to_delegate ( ) ) ,
" net " = > server . add_delegate ( NetClient ::new ( & sync ) . to_delegate ( ) ) ,
" eth " = > {
server . add_delegate ( EthClient ::new ( & client , & sync ) . to_delegate ( ) ) ;
server . add_delegate ( EthFilterClient ::new ( & client ) . to_delegate ( ) ) ;
}
_ = > {
die! ( " {}: Invalid API name to be enabled. " , api ) ;
}
}
}
2016-03-09 18:04:13 +01:00
Some ( server . start_http ( url , cors_domain , 1 ) )
2016-01-20 04:19:38 +01:00
}
#[ cfg(not(feature = " rpc " )) ]
2016-03-09 11:38:53 +01:00
fn setup_rpc_server ( _client : Arc < Client > , _sync : Arc < EthSync > , _url : & str ) -> Option < Arc < PanicHandler > > {
None
2016-01-20 04:19:38 +01:00
}
2016-02-10 18:11:10 +01:00
fn print_version ( ) {
println! ( " \
2016-02-21 20:00:45 +01:00
Parity
version { }
2016-02-09 15:51:48 +01:00
Copyright 2015 , 2016 Ethcore ( UK ) Limited
License GPLv3 + : GNU GPL version 3 or later < http ://gnu.org/licenses/gpl.html>.
This is free software : you are free to change and redistribute it .
There is NO WARRANTY , to the extent permitted by law .
2016-02-09 17:23:25 +01:00
By Wood / Paronyan / Kotewicz / Drwięga / Volf . \
2016-02-21 20:00:45 +01:00
" , version());
2016-02-10 18:11:10 +01:00
}
struct Configuration {
args : Args
}
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-08 16:42:30 +01:00
self . args . flag_datadir . 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 {
Address ::from_str ( & self . args . flag_author ) . unwrap_or_else ( | _ | die! ( " {}: Invalid address for --author. Must be 40 hex characters, without the 0x at the beginning. " , self . args . flag_author ) )
}
fn extra_data ( & self ) -> Bytes {
match self . args . flag_extra_data {
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-02-18 21:49:11 +01: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-02-19 12:54:51 +01:00
f = > Spec ::from_json_utf8 ( contents ( f ) . unwrap_or_else ( | _ | die! ( " {}: Couldn't read chain specification file. Sure it exists? " , f ) ) . as_ref ( ) ) ,
}
}
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-02-11 10:46:55 +01:00
if self . args . flag_no_bootstrap { Vec ::new ( ) } else {
match self . args . arg_enode . len ( ) {
0 = > spec . nodes ( ) . clone ( ) ,
2016-02-19 12:54:51 +01:00
_ = > self . args . arg_enode . iter ( ) . map ( | s | Self ::normalize_enode ( s ) . unwrap_or_else ( | | die! ( " {}: Invalid node address format given for a boot node. " , s ) ) ) . collect ( ) ,
2016-02-11 10:46:55 +01:00
}
2016-02-10 12:50:27 +01:00
}
}
2016-03-11 11:16:49 +01:00
#[ cfg_attr(feature= " dev " , allow(useless_format)) ]
2016-02-16 02:05:36 +01:00
fn net_addresses ( & self ) -> ( Option < SocketAddr > , Option < SocketAddr > ) {
let mut listen_address = None ;
let mut public_address = None ;
2016-02-10 12:50:27 +01:00
2016-02-16 02:05:36 +01:00
if let Some ( ref a ) = self . args . flag_address {
2016-02-22 13:58:41 +01:00
public_address = Some ( SocketAddr ::from_str ( a . as_ref ( ) ) . unwrap_or_else ( | _ | die! ( " {}: Invalid listen/public address given with --address " , a ) ) ) ;
2016-02-16 02:05:36 +01:00
listen_address = public_address ;
}
2016-02-16 19:51:51 +01:00
if listen_address . is_none ( ) {
2016-02-22 13:58:41 +01:00
listen_address = Some ( SocketAddr ::from_str ( self . args . flag_listen_address . as_ref ( ) ) . unwrap_or_else ( | _ | die! ( " {}: Invalid listen/public address given with --listen-address " , self . args . flag_listen_address ) ) ) ;
2016-02-16 02:05:36 +01:00
}
if let Some ( ref a ) = self . args . flag_public_address {
if public_address . is_some ( ) {
2016-02-22 13:58:41 +01:00
die! ( " Conflicting flags provided: --address and --public-address " ) ;
2016-02-10 12:50:27 +01:00
}
2016-02-22 13:58:41 +01:00
public_address = Some ( SocketAddr ::from_str ( a . as_ref ( ) ) . unwrap_or_else ( | _ | die! ( " {}: Invalid listen/public address given with --public-address " , a ) ) ) ;
2016-02-16 02:05:36 +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-02-23 19:38:06 +01:00
ret . nat_enabled = ! self . args . flag_no_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-02-19 19:55:26 +01:00
ret . discovery_enabled = ! self . args . flag_no_discovery ;
2016-03-07 12:21:11 +01:00
ret . ideal_peers = 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-02-18 12:42:01 +01:00
fn execute ( & self ) {
if self . args . flag_version {
print_version ( ) ;
return ;
}
2016-02-18 13:10:04 +01:00
if self . args . cmd_daemon {
2016-02-19 12:54:51 +01:00
Daemonize ::new ( )
. pid_file ( self . args . arg_pid_file . clone ( ) )
. chown_pid_file ( true )
. start ( )
. unwrap_or_else ( | e | die! ( " Couldn't daemonize; {} " , e ) ) ;
2016-02-18 13:10:04 +01:00
}
2016-03-09 14:11:15 +01:00
if self . args . cmd_account {
2016-03-09 20:39:36 +01:00
self . execute_account_cli ( ) ;
2016-03-09 14:11:15 +01:00
return ;
}
2016-02-18 12:42:01 +01:00
self . execute_client ( ) ;
}
2016-03-09 20:39:36 +01:00
fn execute_account_cli ( & self ) {
2016-03-09 14:11:15 +01:00
use util ::keys ::store ::SecretStore ;
use rpassword ::read_password ;
let mut secret_store = SecretStore ::new ( ) ;
2016-03-09 20:39:36 +01:00
if self . args . cmd_new {
2016-03-09 14:11:15 +01:00
println! ( " Please note that password is NOT RECOVERABLE. " ) ;
println! ( " Type password: " ) ;
let password = read_password ( ) . unwrap ( ) ;
println! ( " 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 ) ;
2016-03-09 16:27:44 +01:00
return ;
2016-03-09 14:11:15 +01:00
}
2016-03-09 20:39:36 +01:00
if self . args . cmd_list {
2016-03-09 14:11:15 +01:00
println! ( " Known addresses: " ) ;
for & ( addr , _ ) in secret_store . accounts ( ) . unwrap ( ) . iter ( ) {
println! ( " {:?} " , addr ) ;
}
}
}
2016-02-18 12:42:01 +01:00
fn execute_client ( & self ) {
2016-03-09 15:32:27 +01:00
// Setup panic handler
let panic_handler = PanicHandler ::new_in_arc ( ) ;
2016-02-18 12:42:01 +01:00
// Setup logging
setup_log ( & self . args . flag_logging ) ;
// Raise fdlimit
unsafe { ::fdlimit ::raise_fd_limit ( ) ; }
let spec = self . spec ( ) ;
2016-02-19 12:54:51 +01:00
let net_settings = self . net_settings ( & spec ) ;
2016-02-24 21:23:58 +01:00
let mut sync_config = SyncConfig ::default ( ) ;
2016-03-07 12:21:11 +01:00
sync_config . network_id = self . args . flag_networkid . as_ref ( ) . map ( | id | U256 ::from_str ( id ) . unwrap_or_else ( | _ | die! ( " {}: Invalid index given with --networkid " , id ) ) ) . unwrap_or ( spec . network_id ( ) ) ;
2016-02-18 12:42:01 +01:00
// Build client
2016-02-25 14:09:39 +01:00
let mut client_config = ClientConfig ::default ( ) ;
2016-03-07 12:21:11 +01:00
match self . args . flag_cache {
Some ( mb ) = > {
client_config . blockchain . max_cache_size = mb * 1024 * 1024 ;
client_config . blockchain . pref_cache_size = client_config . blockchain . max_cache_size / 2 ;
}
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-10 17:09:34 +01:00
client_config . prefer_journal = self . args . flag_pruning ;
2016-03-07 12:21:11 +01:00
client_config . name = self . args . flag_identity . clone ( ) ;
2016-02-25 14:09:39 +01:00
client_config . queue . max_mem_use = self . args . flag_queue_max_size ;
let mut service = ClientService ::start ( client_config , spec , net_settings , & Path ::new ( & self . path ( ) ) ) . unwrap ( ) ;
2016-03-09 15:32:27 +01:00
panic_handler . forward_from ( & service ) ;
2016-02-18 12:42:01 +01:00
let client = service . client ( ) . clone ( ) ;
2016-03-01 16:58:14 +01:00
client . set_author ( self . author ( ) ) ;
client . set_extra_data ( self . extra_data ( ) ) ;
2016-02-18 12:42:01 +01:00
// Sync
2016-02-24 21:23:58 +01:00
let sync = EthSync ::register ( service . network ( ) , sync_config , client ) ;
2016-02-18 12:42:01 +01:00
// Setup rpc
2016-03-09 15:32:27 +01:00
if self . args . flag_jsonrpc | | self . args . flag_rpc {
2016-03-07 12:21:11 +01:00
let url = format! ( " {} : {} " ,
self . args . flag_rpcaddr . as_ref ( ) . unwrap_or ( & self . args . flag_jsonrpc_addr ) ,
self . args . flag_rpcport . unwrap_or ( self . args . flag_jsonrpc_port )
) ;
SocketAddr ::from_str ( & url ) . unwrap_or_else ( | _ | die! ( " {}: Invalid JSONRPC listen host/port given. " , url ) ) ;
let cors = self . args . flag_rpccorsdomain . as_ref ( ) . unwrap_or ( & self . args . flag_jsonrpc_cors ) ;
// TODO: use this as the API list.
let apis = self . args . flag_rpcapi . as_ref ( ) . unwrap_or ( & self . args . flag_jsonrpc_apis ) ;
2016-03-09 15:32:27 +01:00
let server_handler = setup_rpc_server ( service . client ( ) , sync . clone ( ) , & url , cors , apis . split ( " , " ) . collect ( ) ) ;
if let Some ( handler ) = server_handler {
panic_handler . forward_from ( handler . deref ( ) ) ;
}
2016-02-18 12:42:01 +01:00
}
// Register IO handler
let io_handler = Arc ::new ( ClientIoHandler {
client : service . client ( ) ,
info : Default ::default ( ) ,
2016-03-09 11:38:53 +01:00
sync : sync . clone ( ) ,
2016-02-18 12:42:01 +01:00
} ) ;
service . io ( ) . register_handler ( io_handler ) . expect ( " Error registering IO handler " ) ;
// Handle exit
2016-03-09 15:32:27 +01:00
wait_for_exit ( panic_handler ) ;
2016-02-18 12:42:01 +01:00
}
2016-02-10 12:50:27 +01:00
}
2016-03-09 15:32:27 +01:00
fn wait_for_exit ( panic_handler : Arc < PanicHandler > ) {
2016-02-10 12:50:27 +01:00
let exit = Arc ::new ( Condvar ::new ( ) ) ;
2016-02-19 12:54:51 +01:00
2016-02-10 12:50:27 +01:00
// Handle possible exits
let e = exit . clone ( ) ;
CtrlC ::set_handler ( move | | { e . notify_all ( ) ; } ) ;
2016-02-19 12:54:51 +01:00
2016-03-09 15:32:27 +01:00
// Handle panics
2016-02-10 12:50:27 +01:00
let e = exit . clone ( ) ;
2016-03-09 15:32:27 +01:00
panic_handler . on_panic ( move | _reason | { e . notify_all ( ) ; } ) ;
2016-02-19 12:54:51 +01:00
2016-02-10 12:50:27 +01:00
// Wait for signal
let mutex = Mutex ::new ( ( ) ) ;
let _ = exit . wait ( mutex . lock ( ) . unwrap ( ) ) . unwrap ( ) ;
}
2015-12-22 22:19:50 +01:00
fn main ( ) {
2016-02-18 12:42:01 +01:00
Configuration ::parse ( ) . execute ( ) ;
2015-12-22 22:19:50 +01:00
}
2016-01-18 23:23:32 +01:00
struct Informant {
2016-01-21 17:21:51 +01:00
chain_info : RwLock < Option < BlockChainInfo > > ,
2016-02-25 14:09:39 +01:00
cache_info : RwLock < Option < BlockChainCacheSize > > ,
2016-01-21 17:21:51 +01:00
report : RwLock < Option < ClientReport > > ,
}
impl Default for Informant {
fn default ( ) -> Self {
Informant {
chain_info : RwLock ::new ( None ) ,
cache_info : RwLock ::new ( None ) ,
report : RwLock ::new ( None ) ,
}
}
2016-01-18 23:23:32 +01:00
}
impl Informant {
2016-02-25 14:09:39 +01:00
fn format_bytes ( b : usize ) -> String {
match binary_prefix ( b as f64 ) {
Standalone ( bytes ) = > format! ( " {} bytes " , bytes ) ,
Prefixed ( prefix , n ) = > format! ( " {:.0} {} B " , n , prefix ) ,
}
}
2016-01-22 04:54:38 +01:00
pub fn tick ( & self , client : & Client , sync : & EthSync ) {
2016-01-18 23:23:32 +01:00
// 5 seconds betwen calls. TODO: calculate this properly.
let dur = 5 usize ;
let chain_info = client . chain_info ( ) ;
2016-01-22 04:54:38 +01:00
let queue_info = client . queue_info ( ) ;
2016-02-25 14:09:39 +01:00
let cache_info = client . blockchain_cache_info ( ) ;
2016-01-18 23:23:32 +01:00
let report = client . report ( ) ;
2016-01-22 04:54:38 +01:00
let sync_info = sync . status ( ) ;
2016-01-18 23:23:32 +01:00
2016-02-25 14:09:39 +01:00
if let ( _ , _ , & Some ( ref last_report ) ) = ( self . chain_info . read ( ) . unwrap ( ) . deref ( ) , self . cache_info . read ( ) . unwrap ( ) . deref ( ) , self . report . read ( ) . unwrap ( ) . deref ( ) ) {
2016-03-06 22:39:04 +01:00
println! ( " [ # {} {} ]---[ {} blk/s | {} tx/s | {} gas/s //··· {} / {} peers, # {} , {} + {} queued ···// mem: {} db, {} chain, {} queue, {} sync ] " ,
2016-01-18 23:23:32 +01:00
chain_info . best_block_number ,
chain_info . best_block_hash ,
( report . blocks_imported - last_report . blocks_imported ) / dur ,
( report . transactions_applied - last_report . transactions_applied ) / dur ,
( report . gas_processed - last_report . gas_processed ) / From ::from ( dur ) ,
2016-01-22 04:54:38 +01:00
sync_info . num_active_peers ,
sync_info . num_peers ,
2016-02-11 22:14:06 +01:00
sync_info . last_imported_block_number . unwrap_or ( chain_info . best_block_number ) ,
2016-01-22 15:58:52 +01:00
queue_info . unverified_queue_size ,
queue_info . verified_queue_size ,
2016-01-22 04:54:38 +01:00
2016-03-06 22:39:04 +01:00
Informant ::format_bytes ( report . state_db_mem ) ,
2016-02-25 14:09:39 +01:00
Informant ::format_bytes ( cache_info . total ( ) ) ,
Informant ::format_bytes ( queue_info . mem_used ) ,
Informant ::format_bytes ( sync_info . mem_used ) ,
2016-01-18 23:23:32 +01:00
) ;
}
2016-01-21 17:21:51 +01:00
* self . chain_info . write ( ) . unwrap ( ) . deref_mut ( ) = Some ( chain_info ) ;
* self . cache_info . write ( ) . unwrap ( ) . deref_mut ( ) = Some ( cache_info ) ;
* self . report . write ( ) . unwrap ( ) . deref_mut ( ) = Some ( report ) ;
2016-01-18 23:23:32 +01:00
}
}
2016-01-16 13:30:27 +01:00
2016-01-21 17:21:51 +01:00
const INFO_TIMER : TimerToken = 0 ;
2016-01-16 13:30:27 +01:00
struct ClientIoHandler {
2016-01-21 23:33:52 +01:00
client : Arc < Client > ,
2016-01-22 04:54:38 +01:00
sync : Arc < EthSync > ,
2016-01-18 23:23:32 +01:00
info : Informant ,
2016-01-16 13:30:27 +01:00
}
impl IoHandler < NetSyncMessage > for ClientIoHandler {
2016-02-10 12:50:27 +01:00
fn initialize ( & self , io : & IoContext < NetSyncMessage > ) {
2016-01-21 17:21:51 +01:00
io . register_timer ( INFO_TIMER , 5000 ) . expect ( " Error registering timer " ) ;
2016-01-16 13:30:27 +01:00
}
2016-01-21 17:21:51 +01:00
fn timeout ( & self , _io : & IoContext < NetSyncMessage > , timer : TimerToken ) {
if INFO_TIMER = = timer {
2016-01-22 04:54:38 +01:00
self . info . tick ( & self . client , & self . sync ) ;
2016-01-16 13:30:27 +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 ( ) {
}