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-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 ;
2015-12-22 22:19:50 +01:00
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-01-26 13:14:22 +01:00
extern crate ethcore_rpc as rpc ;
2016-04-07 10:49:00 +02:00
#[ cfg(feature = " webapp " ) ]
extern crate ethcore_webapp as webapp ;
2016-01-20 04:19:38 +01:00
2016-04-07 12:49:20 +02:00
use std ::any ::Any ;
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-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-03-19 23:51:24 +01:00
use util ::keys ::store ::* ;
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-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-02-25 14:09:39 +01:00
use number_prefix ::{ binary_prefix , Standalone , Prefixed } ;
2016-01-23 23:53:20 +01:00
2016-03-28 00:49:35 +02:00
mod price_info ;
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-03-10 19:50:04 +01:00
parity daemon < pid - file > [ options ]
2016-04-06 13:03:53 +02:00
parity account ( new | list ) [ options ]
2016-03-10 19:50:04 +01:00
parity [ options ]
2016-01-23 23:53:20 +01:00
2016-03-07 12:21:11 +01:00
Protocol Options :
2016-03-14 00:52:31 +01:00
- - chain CHAIN Specify the blockchain type . CHAIN may be either a
JSON chain specification file or olympic , frontier ,
homestead , mainnet , morden , or testnet
[ default : homestead ] .
- d - - db - path PATH Specify the database & configuration directory path
[ default : $HOME / . parity ] .
- - keys - path PATH Specify the path for JSON key files to be found
2016-04-06 13:03:53 +02:00
[ default : $HOME / . parity / 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-27 01:35:42 +01:00
Account Options :
- - unlock ACCOUNT Unlock ACCOUNT for the duration of the execution .
- - password FILE Provide a file containing a password for unlocking
an account .
2016-03-07 12:21:11 +01:00
Networking Options :
2016-03-14 00:52:31 +01:00
- - port PORT Override the port on which the node should listen
[ default : 30303 ] .
2016-02-26 22:40:32 +01:00
- - peers NUM Try to maintain that many peers [ default : 25 ] .
2016-03-14 00:52:31 +01:00
- - nat METHOD Specify method to use for determining public
address . Must be one of : any , none , upnp ,
extip :< IP > [ default : any ] .
- - network - id INDEX Override the network identifier from the chain we
are on .
- - bootnodes NODES Override the bootnodes from our chain . NODES should
be comma - delimited enodes .
2016-02-26 22:40:32 +01:00
- - no - discovery Disable new peer discovery .
2016-03-14 00:52:31 +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-04-07 11:06:49 +02:00
- j - - jsonrpc Enable the JSON - RPC API server .
2016-03-20 10:19:21 +01:00
- - jsonrpc - interface IP Specify the hostname portion of the JSONRPC API
server , IP should be an interface ' s IP address , or
2016-03-20 10:34:34 +01:00
all ( all interfaces ) or local [ default : local ] .
2016-03-14 00:52:31 +01:00
- - jsonrpc - port PORT Specify the port portion of the JSONRPC API server
[ default : 8545 ] .
- - jsonrpc - cors URL Specify CORS header for JSON - RPC API responses
[ default : null ] .
- - 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 , personal ] .
2016-04-07 12:10:26 +02:00
- w - - webapp Enable the web applications server ( e . g . status page ) .
2016-04-07 11:06:49 +02:00
- - webapp - port PORT Specify the port portion of the WebApps server
[ default : 8080 ] .
2016-03-07 12:21:11 +01:00
Sealing / Mining Options :
2016-03-28 00:49:35 +02:00
- - usd - per - tx USD Amount of USD to be paid for a basic transaction
[ default : 0.005 ] . The minimum gas price is set
accordingly .
- - usd - per - eth SOURCE USD value of a single ETH . SOURCE may be either an
amount in USD or a web service [ default : etherscan ] .
2016-03-14 10:54:38 +01:00
- - gas - floor - target GAS Amount of gas per block to target when sealing a new
block [ default : 4712388 ] .
2016-03-14 00:52:31 +01:00
- - author ADDRESS Specify the block author ( aka " coinbase " ) address
for sending block rewards from sealed blocks
[ default : 0037 a6b811ffeb6e072da21179d11b1406371c63 ] .
- - extra - data STRING Specify a custom extra - data for authored blocks , no
more than 32 characters .
Footprint Options :
- - pruning METHOD Configure pruning of the state / storage trie . METHOD
may be one of : archive , basic ( experimental ) , fast
( experimental ) [ default : archive ] .
- - 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 ] .
- - cache MEGABYTES Set total amount of discretionary memory to use for
the entire system , overrides other cache and queue
options .
Geth - compatibility Options :
2016-03-10 21:36:45 +01:00
- - datadir PATH Equivalent to - - db - path PATH .
- - testnet Equivalent to - - chain testnet .
2016-03-14 00:52:31 +01:00
- - networkid INDEX Equivalent to - - network - id INDEX .
- - maxpeers COUNT Equivalent to - - peers COUNT .
- - nodekey KEY Equivalent to - - node - key KEY .
- - nodiscover Equivalent to - - no - discovery .
2016-03-10 19:50:04 +01:00
- - rpc Equivalent to - - jsonrpc .
2016-03-20 10:19:21 +01:00
- - rpcaddr IP Equivalent to - - jsonrpc - interface IP .
2016-03-10 19:50:04 +01:00
- - rpcport PORT Equivalent to - - jsonrpc - port PORT .
- - rpcapi APIS Equivalent to - - jsonrpc - apis APIS .
- - rpccorsdomain URL Equivalent to - - jsonrpc - cors URL .
2016-03-28 00:49:35 +02:00
- - gasprice WEI Minimum amount of Wei per GAS to be paid for a
transaction to be accepted for mining . Overrides
- - basic - tx - usd .
2016-03-10 19:50:04 +01:00
- - etherbase ADDRESS Equivalent to - - author ADDRESS .
- - extradata STRING Equivalent to - - extra - data STRING .
2016-03-07 12:21:11 +01:00
Miscellaneous Options :
2016-03-14 00:52:31 +01:00
- l - - logging LOGGING Specify the logging level . Must conform to the same
format as RUST_LOG .
2016-02-09 15:51:48 +01:00
- 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 ,
flag_chain : String ,
2016-03-10 21:36:45 +01:00
flag_db_path : String ,
2016-03-07 12:21:11 +01:00
flag_identity : String ,
2016-03-27 01:35:42 +01:00
flag_unlock : Vec < String > ,
flag_password : Vec < String > ,
2016-03-07 12:21:11 +01:00
flag_cache : Option < usize > ,
2016-02-18 14:16:55 +01:00
flag_keys_path : String ,
2016-03-10 21:36:45 +01:00
flag_bootnodes : Option < String > ,
2016-03-14 00:52:31 +01:00
flag_network_id : Option < String > ,
2016-03-11 14:45:19 +01:00
flag_pruning : String ,
2016-03-10 21:36:45 +01:00
flag_port : u16 ,
2016-03-07 12:21:11 +01:00
flag_peers : usize ,
2016-02-18 21:49:11 +01:00
flag_no_discovery : bool ,
2016-03-10 21:36:45 +01:00
flag_nat : String ,
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-20 10:19:21 +01:00
flag_jsonrpc_interface : String ,
2016-03-07 12:21:11 +01:00
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 ,
2016-04-07 11:06:49 +02:00
flag_webapp : bool ,
flag_webapp_port : u16 ,
2016-03-13 15:29:55 +01:00
flag_author : String ,
2016-03-28 00:49:35 +02:00
flag_usd_per_tx : String ,
flag_usd_per_eth : String ,
2016-03-14 02:00:22 +01:00
flag_gas_floor_target : String ,
2016-03-13 15:29:55 +01:00
flag_extra_data : Option < String > ,
2016-03-10 21:36:45 +01:00
flag_logging : Option < String > ,
flag_version : bool ,
// geth-compatibility...
flag_nodekey : Option < String > ,
flag_nodiscover : bool ,
flag_maxpeers : Option < usize > ,
flag_datadir : Option < String > ,
flag_extradata : Option < String > ,
flag_etherbase : Option < String > ,
2016-03-13 15:29:55 +01:00
flag_gasprice : Option < String > ,
2016-03-07 12:21:11 +01:00
flag_rpc : bool ,
flag_rpcaddr : Option < String > ,
flag_rpcport : Option < u16 > ,
flag_rpccorsdomain : Option < String > ,
flag_rpcapi : Option < String > ,
2016-03-10 21:36:45 +01:00
flag_testnet : bool ,
flag_networkid : 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-11 14:26:23 +01:00
fn setup_rpc_server (
2016-03-12 19:19:16 +01:00
client : Arc < Client > ,
sync : Arc < EthSync > ,
secret_store : Arc < AccountService > ,
miner : Arc < Miner > ,
url : & str ,
cors_domain : & str ,
apis : Vec < & str >
2016-04-07 12:55:06 +02:00
) -> Box < Any > {
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 " = > {
2016-03-11 14:26:23 +01:00
server . add_delegate ( EthClient ::new ( & client , & sync , & secret_store , & miner ) . to_delegate ( ) ) ;
2016-03-10 16:00:55 +01:00
server . add_delegate ( EthFilterClient ::new ( & client , & miner ) . to_delegate ( ) ) ;
2016-03-07 12:21:11 +01:00
}
2016-03-11 12:49:49 +01:00
" personal " = > server . add_delegate ( PersonalClient ::new ( & secret_store ) . to_delegate ( ) ) ,
2016-03-07 12:21:11 +01:00
_ = > {
die! ( " {}: Invalid API name to be enabled. " , api ) ;
}
}
}
2016-04-07 12:49:20 +02:00
let start_result = server . start_http ( url , cors_domain , ::num_cpus ::get ( ) ) ;
match start_result {
Err ( rpc ::RpcServerError ::IoError ( err ) ) = > die_with_io_error ( err ) ,
Err ( e ) = > die! ( " {:?} " , e ) ,
2016-04-07 12:55:06 +02:00
Ok ( handle ) = > Box ::new ( handle ) ,
2016-04-07 12:49:20 +02:00
}
2016-01-20 04:19:38 +01:00
}
2016-04-07 11:06:49 +02:00
#[ cfg(feature = " webapp " ) ]
fn setup_webapp_server (
2016-04-07 12:12:02 +02:00
client : Arc < Client > ,
sync : Arc < EthSync > ,
secret_store : Arc < AccountService > ,
miner : Arc < Miner > ,
2016-04-07 11:06:49 +02:00
url : & str
2016-04-07 13:09:58 +02:00
) -> Box < Any > {
2016-04-07 12:10:26 +02:00
use rpc ::v1 ::* ;
2016-04-07 11:06:49 +02:00
let server = webapp ::WebappServer ::new ( ) ;
2016-04-07 12:10:26 +02:00
server . add_delegate ( Web3Client ::new ( ) . to_delegate ( ) ) ;
2016-04-07 12:12:02 +02:00
server . add_delegate ( NetClient ::new ( & sync ) . to_delegate ( ) ) ;
server . add_delegate ( EthClient ::new ( & client , & sync , & secret_store , & miner ) . to_delegate ( ) ) ;
server . add_delegate ( EthFilterClient ::new ( & client , & miner ) . to_delegate ( ) ) ;
server . add_delegate ( PersonalClient ::new ( & secret_store ) . to_delegate ( ) ) ;
2016-04-07 13:09:58 +02:00
let start_result = server . start_http ( url , ::num_cpus ::get ( ) ) ;
match start_result {
Err ( webapp ::WebappServerError ::IoError ( err ) ) = > die_with_io_error ( err ) ,
Err ( e ) = > die! ( " {:?} " , e ) ,
Ok ( handle ) = > Box ::new ( handle ) ,
}
2016-04-07 11:06:49 +02:00
}
2016-01-20 04:19:38 +01:00
#[ cfg(not(feature = " rpc " )) ]
2016-03-11 14:26:23 +01:00
fn setup_rpc_server (
2016-03-12 10:44:48 +01:00
_client : Arc < Client > ,
_sync : Arc < EthSync > ,
_secret_store : Arc < AccountService > ,
_miner : Arc < Miner > ,
_url : & str ,
_cors_domain : & str ,
_apis : Vec < & str >
2016-04-07 12:49:20 +02:00
) -> ! {
2016-04-07 12:13:06 +02:00
die! ( " Your Parity version has been compiled without JSON-RPC support. " )
2016-01-20 04:19:38 +01:00
}
2016-04-07 11:06:49 +02:00
#[ cfg(not(feature = " webapp " )) ]
fn setup_webapp_server (
2016-04-07 12:12:02 +02:00
_client : Arc < Client > ,
_sync : Arc < EthSync > ,
_secret_store : Arc < AccountService > ,
_miner : Arc < Miner > ,
2016-04-07 11:06:49 +02:00
_url : & str
2016-04-07 13:09:58 +02:00
) -> ! {
2016-04-07 12:13:06 +02:00
die! ( " Your Parity version has been compiled without WebApps support. " )
2016-04-07 11:06:49 +02: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-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-03-10 10:09:55 +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 ( ) ) ,
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-03-08 15:46:44 +01:00
fn client_config ( & self ) -> ClientConfig {
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-03-11 19:22:40 +01:00
_ = > { die! ( " Invalid pruning method given. " ) ; }
} ;
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-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 ;
2016-04-06 13:21:19 +02:00
let mut secret_store = SecretStore ::new_in ( Path ::new ( & self . keys_path ( ) ) ) ;
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: " ) ;
2016-03-12 10:07:55 +01:00
for & ( addr , _ ) in & secret_store . accounts ( ) . unwrap ( ) {
2016-03-09 14:11:15 +01:00
println! ( " {:?} " , addr ) ;
}
}
}
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-03-27 01:45:43 +01:00
2016-04-06 13:21:19 +02:00
let account_service = AccountService ::new_in ( Path ::new ( & self . keys_path ( ) ) ) ;
2016-03-27 01:35:42 +01:00
for d in & self . args . flag_unlock {
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 )
} ) ;
2016-03-27 01:45:43 +01:00
if passwords . iter ( ) . find ( | p | account_service . unlock_account_no_expire ( & a , p ) . is_ok ( ) ) . is_none ( ) {
2016-03-27 01:35:42 +01:00
die! ( " No password given to unlock account {}. Pass the password using `--password`. " , a ) ;
}
}
account_service
}
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-03-08 15:46:44 +01:00
let sync_config = self . sync_config ( & spec ) ;
2016-02-18 12:42:01 +01:00
2016-03-27 01:35:42 +01:00
// Secret Store
let account_service = Arc ::new ( self . account_service ( ) ) ;
2016-02-18 12:42:01 +01:00
// Build client
2016-04-06 19:07:27 +02:00
let mut service = ClientService ::start (
self . client_config ( ) , spec , net_settings , & Path ::new ( & self . path ( ) )
) . unwrap_or_else ( | e | die_with_error ( e ) ) ;
2016-03-09 15:32:27 +01:00
panic_handler . forward_from ( & service ) ;
2016-03-08 15:46:44 +01:00
let client = service . client ( ) ;
// Miner
2016-03-09 14:26:28 +01:00
let miner = Miner ::new ( ) ;
2016-03-08 15:46:44 +01:00
miner . set_author ( self . author ( ) ) ;
2016-03-14 02:00:22 +01:00
miner . set_gas_floor_target ( self . gas_floor_target ( ) ) ;
2016-03-08 15:46:44 +01:00
miner . set_extra_data ( self . extra_data ( ) ) ;
2016-03-13 15:29:55 +01:00
miner . set_minimal_gas_price ( self . gas_price ( ) ) ;
2016-02-18 12:42:01 +01:00
// Sync
2016-03-08 15:46:44 +01:00
let sync = EthSync ::register ( service . network ( ) , sync_config , client . clone ( ) , miner . clone ( ) ) ;
2016-02-18 12:42:01 +01:00
// Setup rpc
2016-04-06 19:07:27 +02:00
let rpc_server = if self . args . flag_jsonrpc | | self . args . flag_rpc {
let apis = self . args . flag_rpcapi . as_ref ( ) . unwrap_or ( & self . args . flag_jsonrpc_apis ) ;
2016-03-07 12:21:11 +01:00
let url = format! ( " {} : {} " ,
2016-03-20 10:19:21 +01:00
match self . args . flag_rpcaddr . as_ref ( ) . unwrap_or ( & self . args . flag_jsonrpc_interface ) . as_str ( ) {
" all " = > " 0.0.0.0 " ,
" local " = > " 127.0.0.1 " ,
x = > x ,
} ,
2016-03-07 12:21:11 +01:00
self . args . flag_rpcport . unwrap_or ( self . args . flag_jsonrpc_port )
) ;
2016-03-11 14:45:19 +01:00
SocketAddr ::from_str ( & url ) . unwrap_or_else ( | _ | die! ( " {}: Invalid JSONRPC listen host/port given. " , url ) ) ;
2016-04-06 19:07:27 +02:00
let cors_domain = self . args . flag_rpccorsdomain . as_ref ( ) . unwrap_or ( & self . args . flag_jsonrpc_cors ) ;
2016-04-07 12:49:20 +02:00
2016-04-07 12:55:06 +02:00
Some ( setup_rpc_server (
2016-03-11 14:26:23 +01:00
service . client ( ) ,
sync . clone ( ) ,
account_service . clone ( ) ,
miner . clone ( ) ,
2016-03-12 19:22:38 +01:00
& url ,
2016-04-07 12:49:20 +02:00
& cors_domain ,
2016-03-12 19:22:38 +01:00
apis . split ( ',' ) . collect ( )
2016-04-07 12:55:06 +02:00
) )
2016-04-07 12:49:20 +02:00
} else {
None
} ;
2016-02-18 12:42:01 +01:00
2016-04-07 13:09:58 +02:00
let webapp_server = if self . args . flag_webapp {
2016-04-07 12:20:35 +02:00
let url = format! ( " 127.0.0.1: {} " , self . args . flag_webapp_port ) ;
2016-04-07 13:09:58 +02:00
Some ( setup_webapp_server (
2016-04-07 12:12:02 +02:00
service . client ( ) ,
sync . clone ( ) ,
account_service . clone ( ) ,
miner . clone ( ) ,
2016-04-07 11:06:49 +02:00
& url ,
2016-04-07 13:09:58 +02:00
) )
} else {
None
} ;
2016-04-07 11:06:49 +02:00
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-03-13 14:46:45 +01:00
accounts : account_service . clone ( ) ,
2016-02-18 12:42:01 +01:00
} ) ;
service . io ( ) . register_handler ( io_handler ) . expect ( " Error registering IO handler " ) ;
// Handle exit
2016-04-07 13:09:58 +02:00
wait_for_exit ( panic_handler , rpc_server , webapp_server ) ;
2016-02-18 12:42:01 +01:00
}
2016-02-10 12:50:27 +01:00
}
2016-04-07 13:09:58 +02:00
fn wait_for_exit ( panic_handler : Arc < PanicHandler > , _rpc_server : Option < Box < Any > > , _webapp_server : Option < Box < Any > > ) {
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 ( ) ;
2016-04-06 23:58:23 +02:00
info! ( " Finishing work, please wait... " ) ;
2016-04-06 19:07:27 +02:00
}
fn die_with_error ( e : ethcore ::error ::Error ) -> ! {
use ethcore ::error ::Error ;
match e {
Error ::Util ( UtilError ::StdIo ( e ) ) = > die_with_io_error ( e ) ,
_ = > die! ( " {:?} " , e ) ,
}
}
fn die_with_io_error ( e : std ::io ::Error ) -> ! {
match e . kind ( ) {
std ::io ::ErrorKind ::PermissionDenied = > {
2016-04-06 19:22:10 +02:00
die! ( " No permissions to bind to specified port. " )
2016-04-06 19:07:27 +02:00
} ,
std ::io ::ErrorKind ::AddrInUse = > {
2016-04-06 19:22:10 +02:00
die! ( " Specified address is already in use. Please make sure that nothing is listening on the same port or try using a different one. " )
2016-04-06 19:07:27 +02:00
} ,
std ::io ::ErrorKind ::AddrNotAvailable = > {
2016-04-06 19:22:10 +02:00
die! ( " Could not use specified interface or given address is invalid. " )
2016-04-06 19:07:27 +02:00
} ,
_ = > die! ( " {:?} " , e ) ,
}
2016-02-10 12:50:27 +01:00
}
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-22 04:54:38 +01:00
let sync_info = sync . status ( ) ;
2016-01-18 23:23:32 +01:00
2016-03-14 14:22:18 +01:00
let mut write_report = self . report . write ( ) . unwrap ( ) ;
2016-03-14 12:41:11 +01:00
let report = client . report ( ) ;
2016-03-10 10:09:55 +01:00
if let ( _ , _ , & Some ( ref last_report ) ) = (
self . chain_info . read ( ) . unwrap ( ) . deref ( ) ,
self . cache_info . read ( ) . unwrap ( ) . deref ( ) ,
2016-03-14 12:41:11 +01:00
write_report . deref ( )
2016-03-10 10:09:55 +01:00
) {
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 ) ;
2016-03-14 12:41:11 +01:00
* write_report . 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-03-13 14:46:45 +01:00
const ACCOUNT_TICK_TIMER : TimerToken = 10 ;
const ACCOUNT_TICK_MS : u64 = 60000 ;
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-03-13 14:46:45 +01:00
accounts : Arc < AccountService > ,
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-03-13 14:46:45 +01:00
io . register_timer ( ACCOUNT_TICK_TIMER , ACCOUNT_TICK_MS ) . expect ( " Error registering account 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 ) {
2016-03-13 14:46:45 +01:00
match timer {
INFO_TIMER = > { self . info . tick ( & self . client , & self . sync ) ; }
2016-03-13 15:11:16 +01:00
ACCOUNT_TICK_TIMER = > { self . accounts . tick ( ) ; } ,
_ = > { }
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 ( ) {
}