2017-01-25 18:51:41 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-07-25 16:09:47 +02: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/>.
2018-04-04 11:50:28 +02:00
use std ::any ::Any ;
2017-08-28 14:11:55 +02:00
use std ::fmt ;
2017-08-24 15:17:48 +02:00
use std ::sync ::{ Arc , Weak } ;
2018-01-31 11:41:29 +01:00
use std ::time ::{ Duration , Instant } ;
use std ::thread ;
2016-11-03 12:00:39 +01:00
use std ::net ::{ TcpListener } ;
2017-07-10 13:21:11 +02:00
2018-03-23 14:33:23 +01:00
use ansi_term ::{ Colour , Style } ;
2016-07-25 16:09:47 +02:00
use ctrlc ::CtrlC ;
2017-02-10 01:07:06 +01:00
use ethcore ::account_provider ::{ AccountProvider , AccountProviderSettings } ;
2017-07-10 13:21:11 +02:00
use ethcore ::client ::{ Client , Mode , DatabaseCompactionProfile , VMType , BlockChainClient } ;
2018-03-01 19:53:15 +01:00
use ethcore ::db ::NUM_COLUMNS ;
2017-07-10 13:21:11 +02:00
use ethcore ::ethstore ::ethkey ;
2018-01-11 17:49:10 +01:00
use ethcore ::miner ::{ Miner , MinerService , MinerOptions } ;
2017-07-10 13:21:11 +02:00
use ethcore ::miner ::{ StratumOptions , Stratum } ;
2016-09-02 18:48:07 +02:00
use ethcore ::snapshot ;
2017-09-26 14:19:08 +02:00
use ethcore ::spec ::{ SpecParams , OptimizeFor } ;
2016-12-02 18:21:54 +01:00
use ethcore ::verification ::queue ::VerifierSettings ;
2018-01-11 17:49:10 +01:00
use ethcore_logger ::{ Config as LogConfig , RotatingLogger } ;
2018-03-13 11:49:57 +01:00
use ethcore_service ::ClientService ;
2017-07-11 12:23:46 +02:00
use ethsync ::{ self , SyncConfig } ;
2017-07-10 13:21:11 +02:00
use fdlimit ::raise_fd_limit ;
2018-03-14 13:40:54 +01:00
use futures_cpupool ::CpuPool ;
use hash_fetch ::{ self , fetch } ;
2017-07-10 13:21:11 +02:00
use informant ::{ Informant , LightNodeInformantData , FullNodeInformantData } ;
2018-01-11 17:49:10 +01:00
use journaldb ::Algorithm ;
2018-03-01 19:53:15 +01:00
use kvdb_rocksdb ::{ Database , DatabaseConfig } ;
2017-07-10 13:21:11 +02:00
use light ::Cache as LightDataCache ;
2018-01-11 17:49:10 +01:00
use miner ::external ::ExternalMiner ;
use node_filter ::NodeFilter ;
2017-08-28 14:11:55 +02:00
use node_health ;
2017-07-10 13:21:11 +02:00
use parity_reactor ::EventLoop ;
use parity_rpc ::{ NetworkSettings , informant , is_major_importing } ;
2018-01-11 17:49:10 +01:00
use parking_lot ::{ Condvar , Mutex } ;
2017-07-10 13:21:11 +02:00
use updater ::{ UpdatePolicy , Updater } ;
2017-12-22 14:37:39 +01:00
use parity_version ::version ;
2016-07-25 16:09:47 +02:00
2016-10-03 11:13:10 +02:00
use params ::{
SpecType , Pruning , AccountsConfig , GasPricerConfig , MinerExtras , Switch ,
2016-11-05 10:38:00 +01:00
tracing_switch_to_bool , fatdb_switch_to_bool , mode_switch_to_bool
2016-10-03 11:13:10 +02:00
} ;
2016-07-25 16:09:47 +02:00
use helpers ::{ to_client_config , execute_upgrades , passwords_from_files } ;
2016-12-12 16:51:07 +01:00
use upgrade ::upgrade_key_location ;
2017-06-22 20:08:56 +02:00
use dir ::{ Directories , DatabaseDirectories } ;
2016-07-25 16:09:47 +02:00
use cache ::CacheConfig ;
2016-09-26 19:21:25 +02:00
use user_defaults ::UserDefaults ;
2016-07-25 16:09:47 +02:00
use dapps ;
2017-02-14 19:30:37 +01:00
use ipfs ;
2016-07-25 16:09:47 +02:00
use modules ;
use rpc ;
2017-05-24 12:24:07 +02:00
use rpc_apis ;
use secretstore ;
use signer ;
2016-07-25 16:09:47 +02:00
use url ;
2016-09-02 20:24:59 +02:00
// how often to take periodic snapshots.
2017-08-22 11:24:56 +02:00
const SNAPSHOT_PERIOD : u64 = 5000 ;
2016-09-02 20:24:59 +02:00
// how many blocks to wait before starting a periodic snapshot.
2016-10-30 15:39:36 +01:00
const SNAPSHOT_HISTORY : u64 = 100 ;
2016-09-02 18:48:07 +02:00
2017-03-22 22:00:52 +01:00
// Number of minutes before a given gas price corpus should expire.
// Light client only.
2018-03-14 12:29:52 +01:00
const GAS_CORPUS_EXPIRATION_MINUTES : u64 = 60 * 6 ;
2017-03-22 22:00:52 +01:00
2017-01-04 14:48:32 +01:00
// Pops along with error messages when a password is missing or invalid.
const VERIFY_PASSWORD_HINT : & 'static str = " Make sure valid password is present in files passed using `--password` or in the configuration file. " ;
2016-07-25 16:09:47 +02:00
#[ derive(Debug, PartialEq) ]
pub struct RunCmd {
pub cache_config : CacheConfig ,
pub dirs : Directories ,
pub spec : SpecType ,
pub pruning : Pruning ,
2016-10-14 14:44:56 +02:00
pub pruning_history : u64 ,
2017-01-20 13:25:53 +01:00
pub pruning_memory : usize ,
2016-07-25 16:09:47 +02:00
/// Some if execution should be daemonized. Contains pid_file path.
pub daemon : Option < String > ,
pub logger_config : LogConfig ,
pub miner_options : MinerOptions ,
2018-01-09 12:43:36 +01:00
pub gas_price_percentile : usize ,
2017-08-28 14:11:55 +02:00
pub ntp_servers : Vec < String > ,
2017-04-13 16:32:07 +02:00
pub ws_conf : rpc ::WsConfiguration ,
2017-04-03 10:27:37 +02:00
pub http_conf : rpc ::HttpConfiguration ,
pub ipc_conf : rpc ::IpcConfiguration ,
2017-07-11 12:23:46 +02:00
pub net_conf : ethsync ::NetworkConfiguration ,
2016-12-05 15:54:31 +01:00
pub network_id : Option < u64 > ,
2016-10-18 18:16:00 +02:00
pub warp_sync : bool ,
2018-03-29 11:20:27 +02:00
pub warp_barrier : Option < u64 > ,
2017-03-29 17:07:58 +02:00
pub public_node : bool ,
2016-07-25 16:09:47 +02:00
pub acc_conf : AccountsConfig ,
2017-07-16 18:22:45 +02:00
pub gas_pricer_conf : GasPricerConfig ,
2016-07-25 16:09:47 +02:00
pub miner_extras : MinerExtras ,
2016-11-23 20:35:21 +01:00
pub update_policy : UpdatePolicy ,
2016-11-05 10:38:00 +01:00
pub mode : Option < Mode > ,
2016-07-25 16:09:47 +02:00
pub tracing : Switch ,
2016-10-03 11:13:10 +02:00
pub fat_db : Switch ,
2016-07-25 16:09:47 +02:00
pub compaction : DatabaseCompactionProfile ,
2016-07-29 15:36:00 +02:00
pub wal : bool ,
2016-07-25 16:09:47 +02:00
pub vm_type : VMType ,
pub geth_compatibility : bool ,
pub net_settings : NetworkSettings ,
pub dapps_conf : dapps ::Configuration ,
2017-02-16 14:41:33 +01:00
pub ipfs_conf : ipfs ::Configuration ,
2017-05-24 12:24:07 +02:00
pub ui_conf : rpc ::UiConfiguration ,
2017-02-20 16:13:21 +01:00
pub secretstore_conf : secretstore ::Configuration ,
2017-01-06 16:05:58 +01:00
pub dapp : Option < String > ,
2016-07-25 16:09:47 +02:00
pub ui : bool ,
pub name : String ,
pub custom_bootnodes : bool ,
2017-01-25 11:03:36 +01:00
pub stratum : Option < StratumOptions > ,
2016-09-02 20:24:59 +02:00
pub no_periodic_snapshot : bool ,
2016-10-24 15:09:13 +02:00
pub check_seal : bool ,
2016-11-22 18:03:35 +01:00
pub download_old_blocks : bool ,
2016-12-02 18:21:54 +01:00
pub verifier_settings : VerifierSettings ,
2017-03-22 16:45:50 +01:00
pub serve_light : bool ,
pub light : bool ,
2017-05-04 12:13:50 +02:00
pub no_persistent_txqueue : bool ,
2018-03-27 13:56:59 +02:00
pub whisper : ::whisper ::Config ,
pub no_hardcoded_sync : bool ,
2016-07-25 16:09:47 +02:00
}
2017-07-28 19:07:38 +02:00
pub fn open_ui ( ws_conf : & rpc ::WsConfiguration , ui_conf : & rpc ::UiConfiguration , logger_config : & LogConfig ) -> Result < ( ) , String > {
2017-05-24 12:24:07 +02:00
if ! ui_conf . enabled {
2016-11-14 11:56:01 +01:00
return Err ( " Cannot use UI command with UI turned off. " . into ( ) )
}
2017-07-28 19:07:38 +02:00
let token = signer ::generate_token_and_url ( ws_conf , ui_conf , logger_config ) ? ;
2016-11-16 09:37:48 +01:00
// Open a browser
url ::open ( & token . url ) ;
// Print a message
println! ( " {} " , token . message ) ;
2016-11-14 11:56:01 +01:00
Ok ( ( ) )
}
2017-04-03 10:27:37 +02:00
pub fn open_dapp ( dapps_conf : & dapps ::Configuration , rpc_conf : & rpc ::HttpConfiguration , dapp : & str ) -> Result < ( ) , String > {
2017-01-06 16:05:58 +01:00
if ! dapps_conf . enabled {
return Err ( " Cannot use DAPP command with Dapps turned off. " . into ( ) )
}
2017-04-03 10:27:37 +02:00
let url = format! ( " http:// {} : {} / {} / " , rpc_conf . interface , rpc_conf . port , dapp ) ;
2017-01-06 16:05:58 +01:00
url ::open ( & url ) ;
Ok ( ( ) )
}
2017-02-20 17:21:55 +01:00
// node info fetcher for the local store.
struct FullNodeInfo {
2017-05-04 12:13:50 +02:00
miner : Option < Arc < Miner > > , // TODO: only TXQ needed, just use that after decoupling.
2017-02-20 17:21:55 +01:00
}
impl ::local_store ::NodeInfo for FullNodeInfo {
2018-01-11 17:49:10 +01:00
fn pending_transactions ( & self ) -> Vec < ::transaction ::PendingTransaction > {
2017-05-04 12:13:50 +02:00
let miner = match self . miner . as_ref ( ) {
Some ( m ) = > m ,
None = > return Vec ::new ( ) ,
} ;
let local_txs = miner . local_transactions ( ) ;
miner . pending_transactions ( )
2017-02-20 17:21:55 +01:00
. into_iter ( )
2017-05-04 12:13:50 +02:00
. chain ( miner . future_transactions ( ) )
2017-02-20 17:21:55 +01:00
. filter ( | tx | local_txs . contains_key ( & tx . hash ( ) ) )
. collect ( )
}
}
2017-01-06 16:05:58 +01:00
2018-01-31 11:41:29 +01:00
type LightClient = ::light ::client ::Client < ::light_helpers ::EpochFetch > ;
2017-03-22 18:32:04 +01:00
// helper for light execution.
2018-04-04 11:50:28 +02:00
fn execute_light_impl ( cmd : RunCmd , logger : Arc < RotatingLogger > ) -> Result < RunningClient , String > {
2017-03-22 18:32:04 +01:00
use light ::client as light_client ;
use ethsync ::{ LightSyncParams , LightSync , ManageNetwork } ;
2017-09-02 20:09:13 +02:00
use parking_lot ::{ Mutex , RwLock } ;
2017-03-22 18:32:04 +01:00
// load spec
2017-09-25 19:45:33 +02:00
let spec = cmd . spec . spec ( SpecParams ::new ( cmd . dirs . cache . as_ref ( ) , OptimizeFor ::Memory ) ) ? ;
2017-03-22 18:32:04 +01:00
// load genesis hash
let genesis_hash = spec . genesis_header ( ) . hash ( ) ;
// database paths
let db_dirs = cmd . dirs . database ( genesis_hash , cmd . spec . legacy_fork_name ( ) , spec . data_dir . clone ( ) ) ;
// user defaults path
let user_defaults_path = db_dirs . user_defaults_path ( ) ;
// load user defaults
let user_defaults = UserDefaults ::load ( & user_defaults_path ) ? ;
// select pruning algorithm
let algorithm = cmd . pruning . to_algorithm ( & user_defaults ) ;
let compaction = cmd . compaction . compaction_profile ( db_dirs . db_root_path ( ) . as_path ( ) ) ;
// execute upgrades
execute_upgrades ( & cmd . dirs . base , & db_dirs , algorithm , compaction . clone ( ) ) ? ;
// create dirs used by parity
2017-05-24 12:24:07 +02:00
cmd . dirs . create_dirs ( cmd . dapps_conf . enabled , cmd . ui_conf . enabled , cmd . secretstore_conf . enabled ) ? ;
2017-03-22 18:32:04 +01:00
2017-06-22 20:08:56 +02:00
//print out running parity environment
print_running_environment ( & spec . name , & cmd . dirs , & db_dirs , & cmd . dapps_conf ) ;
2017-03-22 18:32:04 +01:00
info! ( " Running in experimental {} mode. " , Colour ::Blue . bold ( ) . paint ( " Light Client " ) ) ;
2017-04-07 17:38:03 +02:00
// TODO: configurable cache size.
2018-03-14 12:29:52 +01:00
let cache = LightDataCache ::new ( Default ::default ( ) , Duration ::from_secs ( 60 * GAS_CORPUS_EXPIRATION_MINUTES ) ) ;
2017-09-02 20:09:13 +02:00
let cache = Arc ::new ( Mutex ::new ( cache ) ) ;
2017-04-07 17:38:03 +02:00
2017-03-22 18:32:04 +01:00
// start client and create transaction queue.
let mut config = light_client ::Config {
queue : Default ::default ( ) ,
chain_column : ::ethcore ::db ::COL_LIGHT_CHAIN ,
2017-07-10 13:21:11 +02:00
verify_full : true ,
2017-07-27 13:50:12 +02:00
check_seal : cmd . check_seal ,
2018-03-27 13:56:59 +02:00
no_hardcoded_sync : cmd . no_hardcoded_sync ,
2017-03-22 18:32:04 +01:00
} ;
config . queue . max_mem_use = cmd . cache_config . queue ( ) as usize * 1024 * 1024 ;
config . queue . verifier_settings = cmd . verifier_settings ;
2017-09-05 17:54:05 +02:00
// start on_demand service.
let on_demand = Arc ::new ( ::light ::on_demand ::OnDemand ::new ( cache . clone ( ) ) ) ;
let sync_handle = Arc ::new ( RwLock ::new ( Weak ::new ( ) ) ) ;
let fetch = ::light_helpers ::EpochFetch {
on_demand : on_demand . clone ( ) ,
sync : sync_handle . clone ( ) ,
} ;
2018-03-01 19:53:15 +01:00
// initialize database.
let db = {
let db_config = DatabaseConfig {
memory_budget : Some ( cmd . cache_config . blockchain ( ) as usize * 1024 * 1024 ) ,
compaction : compaction ,
wal : cmd . wal ,
.. DatabaseConfig ::with_columns ( NUM_COLUMNS )
} ;
Arc ::new ( Database ::open (
& db_config ,
& db_dirs . client_path ( algorithm ) . to_str ( ) . expect ( " DB path could not be converted to string. " )
) . map_err ( | e | format! ( " Error opening database: {} " , e ) ) ? )
} ;
let service = light_client ::Service ::start ( config , & spec , fetch , db , cache . clone ( ) )
2017-03-22 18:32:04 +01:00
. map_err ( | e | format! ( " Error starting light client: {} " , e ) ) ? ;
2018-04-04 11:50:28 +02:00
let client = service . client ( ) . clone ( ) ;
2017-03-22 18:32:04 +01:00
let txq = Arc ::new ( RwLock ::new ( ::light ::transaction_queue ::TransactionQueue ::default ( ) ) ) ;
2018-01-31 11:41:29 +01:00
let provider = ::light ::provider ::LightProvider ::new ( client . clone ( ) , txq . clone ( ) ) ;
2017-03-22 18:32:04 +01:00
// start network.
// set up bootnodes
let mut net_conf = cmd . net_conf ;
if ! cmd . custom_bootnodes {
net_conf . boot_nodes = spec . nodes . clone ( ) ;
}
2017-07-14 20:40:28 +02:00
let mut attached_protos = Vec ::new ( ) ;
let whisper_factory = if cmd . whisper . enabled {
2017-09-10 18:02:14 +02:00
let whisper_factory = ::whisper ::setup ( cmd . whisper . target_message_pool_size , & mut attached_protos )
2017-07-14 20:40:28 +02:00
. map_err ( | e | format! ( " Failed to initialize whisper: {} " , e ) ) ? ;
whisper_factory
} else {
None
} ;
2017-03-22 18:32:04 +01:00
// set network path.
net_conf . net_config_path = Some ( db_dirs . network_path ( ) . to_string_lossy ( ) . into_owned ( ) ) ;
let sync_params = LightSyncParams {
network_config : net_conf . into_basic ( ) . map_err ( | e | format! ( " Failed to produce network config: {} " , e ) ) ? ,
client : Arc ::new ( provider ) ,
network_id : cmd . network_id . unwrap_or ( spec . network_id ( ) ) ,
2017-07-11 12:23:46 +02:00
subprotocol_name : ethsync ::LIGHT_PROTOCOL ,
2017-03-22 22:00:52 +01:00
handlers : vec ! [ on_demand . clone ( ) ] ,
2017-07-14 20:40:28 +02:00
attached_protos : attached_protos ,
2017-03-22 18:32:04 +01:00
} ;
let light_sync = LightSync ::new ( sync_params ) . map_err ( | e | format! ( " Error starting network: {} " , e ) ) ? ;
2017-03-22 22:00:52 +01:00
let light_sync = Arc ::new ( light_sync ) ;
2017-09-05 17:54:05 +02:00
* sync_handle . write ( ) = Arc ::downgrade ( & light_sync ) ;
2017-03-22 18:32:04 +01:00
2017-03-22 22:00:52 +01:00
// spin up event loop
let event_loop = EventLoop ::spawn ( ) ;
2017-03-23 22:20:00 +01:00
// queue cull service.
let queue_cull = Arc ::new ( ::light_helpers ::QueueCull {
2018-01-31 11:41:29 +01:00
client : client . clone ( ) ,
2017-03-23 22:20:00 +01:00
sync : light_sync . clone ( ) ,
on_demand : on_demand . clone ( ) ,
txq : txq . clone ( ) ,
remote : event_loop . remote ( ) ,
} ) ;
service . register_handler ( queue_cull ) . map_err ( | e | format! ( " Error attaching service: {:?} " , e ) ) ? ;
// start the network.
light_sync . start_network ( ) ;
2018-03-14 13:40:54 +01:00
let cpu_pool = CpuPool ::new ( 4 ) ;
2017-03-22 22:00:52 +01:00
// fetch service
2018-03-14 13:40:54 +01:00
let fetch = fetch ::Client ::new ( ) . map_err ( | e | format! ( " Error starting fetch client: {:?} " , e ) ) ? ;
2017-03-22 18:32:04 +01:00
let passwords = passwords_from_files ( & cmd . acc_conf . password_files ) ? ;
// prepare account provider
2017-03-22 22:00:52 +01:00
let account_provider = Arc ::new ( prepare_account_provider ( & cmd . spec , & cmd . dirs , & spec . data_dir , cmd . acc_conf , & passwords ) ? ) ;
let rpc_stats = Arc ::new ( informant ::RpcStats ::default ( ) ) ;
2017-05-24 12:24:07 +02:00
// the dapps server
2018-03-20 18:57:37 +01:00
let signer_service = Arc ::new ( signer ::new_service ( & cmd . ws_conf , & cmd . logger_config ) ) ;
2017-08-28 14:11:55 +02:00
let ( node_health , dapps_deps ) = {
2018-02-09 09:32:06 +01:00
let contract_client = ::dapps ::LightRegistrar {
2018-01-31 11:41:29 +01:00
client : client . clone ( ) ,
2017-05-24 12:24:07 +02:00
sync : light_sync . clone ( ) ,
on_demand : on_demand . clone ( ) ,
2018-02-09 09:32:06 +01:00
} ;
2017-05-24 12:24:07 +02:00
2017-07-11 12:23:46 +02:00
struct LightSyncStatus ( Arc < LightSync > ) ;
2017-08-28 14:11:55 +02:00
impl fmt ::Debug for LightSyncStatus {
fn fmt ( & self , fmt : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( fmt , " Light Sync Status " )
}
}
impl node_health ::SyncStatus for LightSyncStatus {
2017-07-11 12:23:46 +02:00
fn is_major_importing ( & self ) -> bool { self . 0. is_major_importing ( ) }
fn peers ( & self ) -> ( usize , usize ) {
let peers = ethsync ::LightSyncProvider ::peer_numbers ( & * self . 0 ) ;
( peers . connected , peers . max )
}
}
2017-08-28 14:11:55 +02:00
let sync_status = Arc ::new ( LightSyncStatus ( light_sync . clone ( ) ) ) ;
let node_health = node_health ::NodeHealth ::new (
sync_status . clone ( ) ,
2018-03-14 13:40:54 +01:00
node_health ::TimeChecker ::new ( & cmd . ntp_servers , cpu_pool . clone ( ) ) ,
2017-08-28 14:11:55 +02:00
event_loop . remote ( ) ,
) ;
( node_health . clone ( ) , dapps ::Dependencies {
sync_status ,
node_health ,
2018-02-09 09:32:06 +01:00
contract_client : Arc ::new ( contract_client ) ,
2017-05-24 12:24:07 +02:00
fetch : fetch . clone ( ) ,
2018-03-14 13:40:54 +01:00
pool : cpu_pool . clone ( ) ,
2017-05-24 12:24:07 +02:00
signer : signer_service . clone ( ) ,
2017-09-21 14:52:44 +02:00
ui_address : cmd . ui_conf . redirection_address ( ) ,
2017-08-28 14:11:55 +02:00
} )
2017-05-24 12:24:07 +02:00
} ;
let dapps_middleware = dapps ::new ( cmd . dapps_conf . clone ( ) , dapps_deps . clone ( ) ) ? ;
2017-08-28 14:11:55 +02:00
let ui_middleware = dapps ::new_ui ( cmd . ui_conf . enabled , dapps_deps ) ? ;
2017-03-22 22:00:52 +01:00
2017-03-23 22:20:00 +01:00
// start RPCs
2017-05-24 12:24:07 +02:00
let dapps_service = dapps ::service ( & dapps_middleware ) ;
2017-03-22 22:00:52 +01:00
let deps_for_rpc_apis = Arc ::new ( rpc_apis ::LightDependencies {
2017-05-24 12:24:07 +02:00
signer_service : signer_service ,
2018-01-31 11:41:29 +01:00
client : client . clone ( ) ,
2017-03-22 22:00:52 +01:00
sync : light_sync . clone ( ) ,
net : light_sync . clone ( ) ,
2017-08-28 14:11:55 +02:00
health : node_health ,
2017-03-22 22:00:52 +01:00
secret_store : account_provider ,
logger : logger ,
settings : Arc ::new ( cmd . net_settings ) ,
2017-05-24 12:24:07 +02:00
on_demand : on_demand ,
2017-07-10 13:21:11 +02:00
cache : cache . clone ( ) ,
2017-03-22 22:00:52 +01:00
transaction_queue : txq ,
2017-05-24 12:24:07 +02:00
dapps_service : dapps_service ,
dapps_address : cmd . dapps_conf . address ( cmd . http_conf . address ( ) ) ,
ws_address : cmd . ws_conf . address ( ) ,
fetch : fetch ,
2018-03-14 13:40:54 +01:00
pool : cpu_pool . clone ( ) ,
2017-03-22 22:00:52 +01:00
geth_compatibility : cmd . geth_compatibility ,
2017-05-17 16:20:41 +02:00
remote : event_loop . remote ( ) ,
2017-07-14 20:40:28 +02:00
whisper_rpc : whisper_factory ,
2018-01-09 12:43:36 +01:00
gas_price_percentile : cmd . gas_price_percentile ,
2017-03-22 22:00:52 +01:00
} ) ;
let dependencies = rpc ::Dependencies {
apis : deps_for_rpc_apis . clone ( ) ,
remote : event_loop . raw_remote ( ) ,
stats : rpc_stats . clone ( ) ,
2017-07-11 12:22:19 +02:00
pool : if cmd . http_conf . processing_threads > 0 {
Some ( rpc ::CpuPool ::new ( cmd . http_conf . processing_threads ) )
} else {
None
} ,
2017-03-22 22:00:52 +01:00
} ;
// start rpc servers
2018-04-04 11:50:28 +02:00
let ws_server = rpc ::new_ws ( cmd . ws_conf , & dependencies ) ? ;
let http_server = rpc ::new_http ( " HTTP JSON-RPC " , " jsonrpc " , cmd . http_conf . clone ( ) , & dependencies , dapps_middleware ) ? ;
let ipc_server = rpc ::new_ipc ( cmd . ipc_conf , & dependencies ) ? ;
let ui_server = rpc ::new_http ( " Parity Wallet (UI) " , " ui " , cmd . ui_conf . clone ( ) . into ( ) , & dependencies , ui_middleware ) ? ;
2017-03-22 22:00:52 +01:00
2017-07-10 13:21:11 +02:00
// the informant
let informant = Arc ::new ( Informant ::new (
LightNodeInformantData {
2018-01-31 11:41:29 +01:00
client : client . clone ( ) ,
2017-07-10 13:21:11 +02:00
sync : light_sync . clone ( ) ,
cache : cache ,
} ,
None ,
Some ( rpc_stats ) ,
cmd . logger_config . color ,
) ) ;
service . register_handler ( informant . clone ( ) ) . map_err ( | _ | " Unable to register informant handler " . to_owned ( ) ) ? ;
2017-03-23 22:20:00 +01:00
2018-04-04 11:50:28 +02:00
Ok ( RunningClient ::Light {
informant ,
client ,
keep_alive : Box ::new ( ( service , ws_server , http_server , ipc_server , ui_server ) ) ,
} )
2018-01-31 11:41:29 +01:00
}
2017-03-22 18:32:04 +01:00
2018-04-04 11:50:28 +02:00
fn execute_impl < Cr , Rr > ( cmd : RunCmd , logger : Arc < RotatingLogger > , on_client_rq : Cr ,
on_updater_rq : Rr ) -> Result < RunningClient , String >
where Cr : Fn ( String ) + 'static + Send ,
Rr : Fn ( ) + 'static + Send
{
2016-07-25 16:09:47 +02:00
// load spec
2017-07-10 12:57:40 +02:00
let spec = cmd . spec . spec ( & cmd . dirs . cache ) ? ;
2016-07-25 16:09:47 +02:00
// load genesis hash
let genesis_hash = spec . genesis_header ( ) . hash ( ) ;
2016-09-26 19:21:25 +02:00
// database paths
2016-12-12 16:51:07 +01:00
let db_dirs = cmd . dirs . database ( genesis_hash , cmd . spec . legacy_fork_name ( ) , spec . data_dir . clone ( ) ) ;
2016-09-26 19:21:25 +02:00
// user defaults path
let user_defaults_path = db_dirs . user_defaults_path ( ) ;
// load user defaults
2016-12-27 12:53:56 +01:00
let mut user_defaults = UserDefaults ::load ( & user_defaults_path ) ? ;
2016-09-26 19:21:25 +02:00
2016-10-03 11:13:10 +02:00
// select pruning algorithm
let algorithm = cmd . pruning . to_algorithm ( & user_defaults ) ;
2016-09-26 19:21:25 +02:00
// check if tracing is on
2016-12-27 12:53:56 +01:00
let tracing = tracing_switch_to_bool ( cmd . tracing , & user_defaults ) ? ;
2016-09-26 19:21:25 +02:00
2016-10-03 11:13:10 +02:00
// check if fatdb is on
2016-12-27 12:53:56 +01:00
let fat_db = fatdb_switch_to_bool ( cmd . fat_db , & user_defaults , algorithm ) ? ;
2016-07-25 16:09:47 +02:00
2016-11-05 10:38:00 +01:00
// get the mode
2016-12-27 12:53:56 +01:00
let mode = mode_switch_to_bool ( cmd . mode , & user_defaults ) ? ;
2016-11-05 10:38:00 +01:00
trace! ( target : " mode " , " mode is {:?} " , mode ) ;
2016-11-28 13:20:49 +01:00
let network_enabled = match mode { Mode ::Dark ( _ ) | Mode ::Off = > false , _ = > true , } ;
2016-11-05 10:38:00 +01:00
2016-11-23 20:35:21 +01:00
// get the update policy
let update_policy = cmd . update_policy ;
2016-09-07 15:27:28 +02:00
// prepare client and snapshot paths.
2016-09-26 19:21:25 +02:00
let client_path = db_dirs . client_path ( algorithm ) ;
let snapshot_path = db_dirs . snapshot_path ( ) ;
2016-07-25 16:09:47 +02:00
// execute upgrades
2016-12-27 12:53:56 +01:00
execute_upgrades ( & cmd . dirs . base , & db_dirs , algorithm , cmd . compaction . compaction_profile ( db_dirs . db_root_path ( ) . as_path ( ) ) ) ? ;
2016-07-25 16:09:47 +02:00
2016-12-13 23:38:29 +01:00
// create dirs used by parity
2017-05-24 12:24:07 +02:00
cmd . dirs . create_dirs ( cmd . dapps_conf . enabled , cmd . ui_conf . enabled , cmd . secretstore_conf . enabled ) ? ;
2016-07-25 16:09:47 +02:00
// run in daemon mode
if let Some ( pid_file ) = cmd . daemon {
2016-12-27 12:53:56 +01:00
daemonize ( pid_file ) ? ;
2016-07-25 16:09:47 +02:00
}
2017-06-22 20:08:56 +02:00
//print out running parity environment
print_running_environment ( & spec . name , & cmd . dirs , & db_dirs , & cmd . dapps_conf ) ;
2016-07-25 16:09:47 +02:00
// display info about used pruning algorithm
2016-12-14 15:15:19 +01:00
info! ( " State DB configuration: {}{}{} " ,
2016-10-03 11:13:10 +02:00
Colour ::White . bold ( ) . paint ( algorithm . as_str ( ) ) ,
match fat_db {
true = > Colour ::White . bold ( ) . paint ( " +Fat " ) . to_string ( ) ,
false = > " " . to_owned ( ) ,
} ,
match tracing {
true = > Colour ::White . bold ( ) . paint ( " +Trace " ) . to_string ( ) ,
false = > " " . to_owned ( ) ,
}
) ;
2016-11-05 10:38:00 +01:00
info! ( " Operating mode: {} " , Colour ::White . bold ( ) . paint ( format! ( " {} " , mode ) ) ) ;
2016-07-25 16:09:47 +02:00
2017-05-09 17:46:46 +02:00
// display warning about using experimental journaldb algorithm
2016-07-25 16:09:47 +02:00
if ! algorithm . is_stable ( ) {
warn! ( " Your chosen strategy is {}! You can re-run with --pruning to change. " , Colour ::Red . bold ( ) . paint ( " unstable " ) ) ;
}
// create sync config
let mut sync_config = SyncConfig ::default ( ) ;
sync_config . network_id = match cmd . network_id {
Some ( id ) = > id ,
None = > spec . network_id ( ) ,
} ;
2016-09-28 14:21:59 +02:00
if spec . subprotocol_name ( ) . len ( ) ! = 3 {
warn! ( " Your chain specification's subprotocol length is not 3. Ignoring. " ) ;
} else {
sync_config . subprotocol_name . clone_from_slice ( spec . subprotocol_name ( ) . as_bytes ( ) ) ;
}
2017-05-10 17:12:00 +02:00
2016-08-03 19:01:48 +02:00
sync_config . fork_block = spec . fork_block ( ) ;
2018-03-29 11:20:27 +02:00
let mut warp_sync = spec . engine . supports_warp ( ) & & cmd . warp_sync ;
2017-10-10 17:42:20 +02:00
if warp_sync {
// Logging is not initialized yet, so we print directly to stderr
if fat_db {
warn! ( " Warning: Warp Sync is disabled because Fat DB is turned on. " ) ;
warp_sync = false ;
} else if tracing {
warn! ( " Warning: Warp Sync is disabled because tracing is turned on. " ) ;
warp_sync = false ;
} else if algorithm ! = Algorithm ::OverlayRecent {
warn! ( " Warning: Warp Sync is disabled because of non-default pruning mode. " ) ;
warp_sync = false ;
}
}
2018-03-29 11:20:27 +02:00
sync_config . warp_sync = match ( warp_sync , cmd . warp_barrier ) {
( true , Some ( block ) ) = > ethsync ::WarpSync ::OnlyAndAfter ( block ) ,
( true , _ ) = > ethsync ::WarpSync ::Enabled ,
_ = > ethsync ::WarpSync ::Disabled ,
} ;
2016-11-22 18:03:35 +01:00
sync_config . download_old_blocks = cmd . download_old_blocks ;
2017-03-22 16:45:50 +01:00
sync_config . serve_light = cmd . serve_light ;
2016-07-25 16:09:47 +02:00
2016-12-27 12:53:56 +01:00
let passwords = passwords_from_files ( & cmd . acc_conf . password_files ) ? ;
2016-12-05 20:23:03 +01:00
2016-07-25 16:09:47 +02:00
// prepare account provider
2017-01-04 16:51:27 +01:00
let account_provider = Arc ::new ( prepare_account_provider ( & cmd . spec , & cmd . dirs , & spec . data_dir , cmd . acc_conf , & passwords ) ? ) ;
2016-07-25 16:09:47 +02:00
2018-03-14 13:40:54 +01:00
let cpu_pool = CpuPool ::new ( 4 ) ;
2017-07-16 18:22:45 +02:00
// fetch service
2018-03-14 13:40:54 +01:00
let fetch = fetch ::Client ::new ( ) . map_err ( | e | format! ( " Error starting fetch client: {:?} " , e ) ) ? ;
2017-07-16 18:22:45 +02:00
2016-07-25 16:09:47 +02:00
// create miner
2017-07-16 18:22:45 +02:00
let initial_min_gas_price = cmd . gas_pricer_conf . initial_min ( ) ;
2018-03-14 13:40:54 +01:00
let miner = Miner ::new ( cmd . miner_options , cmd . gas_pricer_conf . to_gas_pricer ( fetch . clone ( ) , cpu_pool . clone ( ) ) , & spec , Some ( account_provider . clone ( ) ) ) ;
2016-07-25 16:09:47 +02:00
miner . set_author ( cmd . miner_extras . author ) ;
miner . set_gas_floor_target ( cmd . miner_extras . gas_floor_target ) ;
miner . set_gas_ceil_target ( cmd . miner_extras . gas_ceil_target ) ;
miner . set_extra_data ( cmd . miner_extras . extra_data ) ;
2017-01-18 19:44:24 +01:00
miner . set_minimal_gas_price ( initial_min_gas_price ) ;
miner . recalibrate_minimal_gas_price ( ) ;
2016-12-05 22:31:38 +01:00
let engine_signer = cmd . miner_extras . engine_signer ;
2017-01-04 12:50:50 +01:00
2016-12-07 10:34:06 +01:00
if engine_signer ! = Default ::default ( ) {
2017-01-04 12:50:50 +01:00
// Check if engine signer exists
if ! account_provider . has_account ( engine_signer ) . unwrap_or ( false ) {
2017-01-04 16:51:27 +01:00
return Err ( format! ( " Consensus signer account not found for the current chain. {} " , build_create_account_hint ( & cmd . spec , & cmd . dirs . keys ) ) ) ;
2017-01-04 12:50:50 +01:00
}
// Check if any passwords have been read from the password file(s)
if passwords . is_empty ( ) {
2017-01-04 14:48:32 +01:00
return Err ( format! ( " No password found for the consensus signer {} . {} " , engine_signer , VERIFY_PASSWORD_HINT ) ) ;
2017-01-04 12:50:50 +01:00
}
// Attempt to sign in the engine signer.
2017-08-09 11:09:40 +02:00
if ! passwords . iter ( ) . any ( | p | miner . set_engine_signer ( engine_signer , ( * p ) . clone ( ) ) . is_ok ( ) ) {
2017-01-04 14:48:32 +01:00
return Err ( format! ( " No valid password for the consensus signer {} . {} " , engine_signer , VERIFY_PASSWORD_HINT ) ) ;
2016-12-07 10:34:06 +01:00
}
2016-12-05 20:23:03 +01:00
}
2016-07-25 16:09:47 +02:00
2018-03-27 13:56:59 +02:00
// display warning if using --no-hardcoded-sync
2018-03-29 14:33:57 +02:00
if cmd . no_hardcoded_sync {
2018-03-27 13:56:59 +02:00
warn! ( " The --no-hardcoded-sync flag has no effect if you don't use --light " ) ;
}
2016-07-25 16:09:47 +02:00
// create client config
2016-12-02 18:21:54 +01:00
let mut client_config = to_client_config (
2016-07-25 16:09:47 +02:00
& cmd . cache_config ,
2017-03-13 12:10:53 +01:00
spec . name . to_lowercase ( ) ,
2016-11-27 11:11:56 +01:00
mode . clone ( ) ,
2016-09-26 19:21:25 +02:00
tracing ,
2016-10-03 11:13:10 +02:00
fat_db ,
2016-07-25 16:09:47 +02:00
cmd . compaction ,
2016-07-29 15:36:00 +02:00
cmd . wal ,
2016-07-25 16:09:47 +02:00
cmd . vm_type ,
cmd . name ,
2016-09-26 19:21:25 +02:00
algorithm ,
2016-10-14 14:44:56 +02:00
cmd . pruning_history ,
2017-01-20 13:25:53 +01:00
cmd . pruning_memory ,
2016-10-24 15:09:13 +02:00
cmd . check_seal ,
2016-07-25 16:09:47 +02:00
) ;
2016-12-02 18:21:54 +01:00
client_config . queue . verifier_settings = cmd . verifier_settings ;
2016-07-25 16:09:47 +02:00
// set up bootnodes
let mut net_conf = cmd . net_conf ;
if ! cmd . custom_bootnodes {
net_conf . boot_nodes = spec . nodes . clone ( ) ;
}
2016-10-11 18:42:20 +02:00
// set network path.
net_conf . net_config_path = Some ( db_dirs . network_path ( ) . to_string_lossy ( ) . into_owned ( ) ) ;
2016-08-05 17:00:46 +02:00
// create client service.
2016-12-27 12:53:56 +01:00
let service = ClientService ::start (
2016-07-25 16:09:47 +02:00
client_config ,
2016-08-05 23:33:55 +02:00
& spec ,
2016-09-07 15:27:28 +02:00
& client_path ,
& snapshot_path ,
& cmd . dirs . ipc_path ( ) ,
2016-07-25 16:09:47 +02:00
miner . clone ( ) ,
2016-12-27 12:53:56 +01:00
) . map_err ( | e | format! ( " Client service error: {:?} " , e ) ) ? ;
2016-07-25 16:09:47 +02:00
2017-08-29 14:38:01 +02:00
let connection_filter_address = spec . params ( ) . node_permission_contract ;
2016-11-15 19:07:23 +01:00
// drop the spec to free up genesis state.
drop ( spec ) ;
2016-07-25 16:09:47 +02:00
// take handle to client
let client = service . client ( ) ;
2017-08-29 14:38:01 +02:00
let connection_filter = connection_filter_address . map ( | a | Arc ::new ( NodeFilter ::new ( Arc ::downgrade ( & client ) as Weak < BlockChainClient > , a ) ) ) ;
2016-09-06 15:31:13 +02:00
let snapshot_service = service . snapshot_service ( ) ;
2016-07-25 16:09:47 +02:00
2017-02-20 17:21:55 +01:00
// initialize the local node information store.
let store = {
let db = service . db ( ) ;
let node_info = FullNodeInfo {
2017-05-04 12:13:50 +02:00
miner : match cmd . no_persistent_txqueue {
true = > None ,
false = > Some ( miner . clone ( ) ) ,
}
2017-02-20 17:21:55 +01:00
} ;
let store = ::local_store ::create ( db , ::ethcore ::db ::COL_NODE_INFO , node_info ) ;
2017-05-04 12:13:50 +02:00
if cmd . no_persistent_txqueue {
info! ( " Running without a persistent transaction queue. " ) ;
if let Err ( e ) = store . clear ( ) {
warn! ( " Error clearing persistent transaction queue: {} " , e ) ;
}
}
2017-02-20 17:21:55 +01:00
// re-queue pending transactions.
match store . pending_transactions ( ) {
Ok ( pending ) = > {
for pending_tx in pending {
if let Err ( e ) = miner . import_own_transaction ( & * client , pending_tx ) {
warn! ( " Error importing saved transaction: {} " , e )
}
}
}
Err ( e ) = > warn! ( " Error loading cached pending transactions from disk: {} " , e ) ,
}
Arc ::new ( store )
} ;
// register it as an IO service to update periodically.
service . register_io_handler ( store ) . map_err ( | _ | " Unable to register local store handler " . to_owned ( ) ) ? ;
2016-07-25 16:09:47 +02:00
// create external miner
let external_miner = Arc ::new ( ExternalMiner ::default ( ) ) ;
2017-01-25 11:03:36 +01:00
// start stratum
if let Some ( ref stratum_config ) = cmd . stratum {
Stratum ::register ( stratum_config , miner . clone ( ) , Arc ::downgrade ( & client ) )
. map_err ( | e | format! ( " Stratum start error: {:?} " , e ) ) ? ;
}
2017-07-14 20:40:28 +02:00
let mut attached_protos = Vec ::new ( ) ;
let whisper_factory = if cmd . whisper . enabled {
2017-09-10 18:02:14 +02:00
let whisper_factory = ::whisper ::setup ( cmd . whisper . target_message_pool_size , & mut attached_protos )
2017-07-14 20:40:28 +02:00
. map_err ( | e | format! ( " Failed to initialize whisper: {} " , e ) ) ? ;
whisper_factory
} else {
None
} ;
2016-07-25 16:09:47 +02:00
// create sync object
2016-12-27 12:53:56 +01:00
let ( sync_provider , manage_network , chain_notify ) = modules ::sync (
2016-12-15 23:50:16 +01:00
sync_config ,
2017-07-11 12:23:46 +02:00
net_conf . clone ( ) . into ( ) ,
2016-12-15 23:50:16 +01:00
client . clone ( ) ,
snapshot_service . clone ( ) ,
client . clone ( ) ,
2016-12-08 23:21:47 +01:00
& cmd . logger_config ,
2017-07-14 20:40:28 +02:00
attached_protos ,
2017-08-29 14:38:01 +02:00
connection_filter . clone ( ) . map ( | f | f as Arc < ::ethsync ::ConnectionFilter + 'static > ) ,
2016-12-27 12:53:56 +01:00
) . map_err ( | e | format! ( " Sync error: {} " , e ) ) ? ;
2016-07-25 16:09:47 +02:00
service . add_notify ( chain_notify . clone ( ) ) ;
// start network
2016-11-05 10:38:00 +01:00
if network_enabled {
2016-07-25 16:09:47 +02:00
chain_notify . start ( ) ;
}
2016-12-22 18:26:39 +01:00
// spin up event loop
let event_loop = EventLoop ::spawn ( ) ;
2018-02-09 09:32:06 +01:00
let contract_client = Arc ::new ( ::dapps ::FullRegistrar ::new ( client . clone ( ) ) ) ;
2016-12-10 23:58:39 +01:00
// the updater service
2018-03-14 13:40:54 +01:00
let updater_fetch = fetch . clone ( ) ;
2016-12-22 18:26:39 +01:00
let updater = Updater ::new (
Arc ::downgrade ( & ( service . client ( ) as Arc < BlockChainClient > ) ) ,
Arc ::downgrade ( & sync_provider ) ,
update_policy ,
2018-03-14 13:40:54 +01:00
hash_fetch ::Client ::with_fetch ( contract_client . clone ( ) , cpu_pool . clone ( ) , updater_fetch , event_loop . remote ( ) )
2016-12-22 18:26:39 +01:00
) ;
2016-12-11 02:02:40 +01:00
service . add_notify ( updater . clone ( ) ) ;
2016-12-10 23:58:39 +01:00
2016-07-25 16:09:47 +02:00
// set up dependencies for rpc servers
2017-02-04 22:18:19 +01:00
let rpc_stats = Arc ::new ( informant ::RpcStats ::default ( ) ) ;
2017-03-29 17:07:58 +02:00
let secret_store = match cmd . public_node {
true = > None ,
false = > Some ( account_provider . clone ( ) )
} ;
2017-04-03 08:51:23 +02:00
2018-03-20 18:57:37 +01:00
let signer_service = Arc ::new ( signer ::new_service ( & cmd . ws_conf , & cmd . logger_config ) ) ;
2017-05-24 12:24:07 +02:00
// the dapps server
2017-08-28 14:11:55 +02:00
let ( node_health , dapps_deps ) = {
2017-05-24 12:24:07 +02:00
let ( sync , client ) = ( sync_provider . clone ( ) , client . clone ( ) ) ;
2017-07-11 12:23:46 +02:00
struct SyncStatus ( Arc < ethsync ::SyncProvider > , Arc < Client > , ethsync ::NetworkConfiguration ) ;
2017-08-28 14:11:55 +02:00
impl fmt ::Debug for SyncStatus {
fn fmt ( & self , fmt : & mut fmt ::Formatter ) -> fmt ::Result {
write! ( fmt , " Dapps Sync Status " )
}
}
impl node_health ::SyncStatus for SyncStatus {
2017-07-11 12:23:46 +02:00
fn is_major_importing ( & self ) -> bool {
is_major_importing ( Some ( self . 0. status ( ) . state ) , self . 1. queue_info ( ) )
}
fn peers ( & self ) -> ( usize , usize ) {
let status = self . 0. status ( ) ;
( status . num_peers , status . current_max_peers ( self . 2. min_peers , self . 2. max_peers ) as usize )
}
}
2017-08-28 14:11:55 +02:00
let sync_status = Arc ::new ( SyncStatus ( sync , client , net_conf ) ) ;
let node_health = node_health ::NodeHealth ::new (
sync_status . clone ( ) ,
2018-03-14 13:40:54 +01:00
node_health ::TimeChecker ::new ( & cmd . ntp_servers , cpu_pool . clone ( ) ) ,
2017-08-28 14:11:55 +02:00
event_loop . remote ( ) ,
) ;
( node_health . clone ( ) , dapps ::Dependencies {
sync_status ,
node_health ,
2018-02-09 09:32:06 +01:00
contract_client ,
2017-05-24 12:24:07 +02:00
fetch : fetch . clone ( ) ,
2018-03-14 13:40:54 +01:00
pool : cpu_pool . clone ( ) ,
2017-05-24 12:24:07 +02:00
signer : signer_service . clone ( ) ,
2017-09-21 14:52:44 +02:00
ui_address : cmd . ui_conf . redirection_address ( ) ,
2017-08-28 14:11:55 +02:00
} )
2017-05-24 12:24:07 +02:00
} ;
let dapps_middleware = dapps ::new ( cmd . dapps_conf . clone ( ) , dapps_deps . clone ( ) ) ? ;
2017-08-28 14:11:55 +02:00
let ui_middleware = dapps ::new_ui ( cmd . ui_conf . enabled , dapps_deps ) ? ;
2017-05-24 12:24:07 +02:00
let dapps_service = dapps ::service ( & dapps_middleware ) ;
2017-03-22 20:14:40 +01:00
let deps_for_rpc_apis = Arc ::new ( rpc_apis ::FullDependencies {
2017-05-24 12:24:07 +02:00
signer_service : signer_service ,
2016-10-31 17:32:53 +01:00
snapshot : snapshot_service . clone ( ) ,
2016-07-25 16:09:47 +02:00
client : client . clone ( ) ,
sync : sync_provider . clone ( ) ,
2017-08-28 14:11:55 +02:00
health : node_health ,
2016-07-25 16:09:47 +02:00
net : manage_network . clone ( ) ,
2017-03-29 17:07:58 +02:00
secret_store : secret_store ,
2016-07-25 16:09:47 +02:00
miner : miner . clone ( ) ,
external_miner : external_miner . clone ( ) ,
logger : logger . clone ( ) ,
settings : Arc ::new ( cmd . net_settings . clone ( ) ) ,
2016-08-03 15:31:00 +02:00
net_service : manage_network . clone ( ) ,
2016-12-11 19:14:42 +01:00
updater : updater . clone ( ) ,
2016-08-03 15:31:00 +02:00
geth_compatibility : cmd . geth_compatibility ,
2017-05-24 12:24:07 +02:00
dapps_service : dapps_service ,
dapps_address : cmd . dapps_conf . address ( cmd . http_conf . address ( ) ) ,
ws_address : cmd . ws_conf . address ( ) ,
2016-12-22 18:26:39 +01:00
fetch : fetch . clone ( ) ,
2018-03-14 13:40:54 +01:00
pool : cpu_pool . clone ( ) ,
2017-05-06 13:24:18 +02:00
remote : event_loop . remote ( ) ,
2017-07-14 20:40:28 +02:00
whisper_rpc : whisper_factory ,
2018-01-09 12:43:36 +01:00
gas_price_percentile : cmd . gas_price_percentile ,
2016-07-25 16:09:47 +02:00
} ) ;
let dependencies = rpc ::Dependencies {
apis : deps_for_rpc_apis . clone ( ) ,
2017-01-11 20:02:27 +01:00
remote : event_loop . raw_remote ( ) ,
2017-02-04 22:18:19 +01:00
stats : rpc_stats . clone ( ) ,
2017-07-11 12:22:19 +02:00
pool : if cmd . http_conf . processing_threads > 0 {
Some ( rpc ::CpuPool ::new ( cmd . http_conf . processing_threads ) )
} else {
None
} ,
2016-07-25 16:09:47 +02:00
} ;
2017-04-03 10:27:37 +02:00
// start rpc servers
2017-05-24 12:24:07 +02:00
let ws_server = rpc ::new_ws ( cmd . ws_conf . clone ( ) , & dependencies ) ? ;
2017-04-03 10:27:37 +02:00
let ipc_server = rpc ::new_ipc ( cmd . ipc_conf , & dependencies ) ? ;
2017-05-24 12:24:07 +02:00
let http_server = rpc ::new_http ( " HTTP JSON-RPC " , " jsonrpc " , cmd . http_conf . clone ( ) , & dependencies , dapps_middleware ) ? ;
// the ui server
let ui_server = rpc ::new_http ( " UI WALLET " , " ui " , cmd . ui_conf . clone ( ) . into ( ) , & dependencies , ui_middleware ) ? ;
2016-07-25 16:09:47 +02:00
2017-02-20 16:13:21 +01:00
// secret store key server
2017-04-03 17:46:51 +02:00
let secretstore_deps = secretstore ::Dependencies {
client : client . clone ( ) ,
2017-11-20 13:18:31 +01:00
sync : sync_provider . clone ( ) ,
2017-08-09 11:09:40 +02:00
account_provider : account_provider ,
accounts_passwords : & passwords ,
2017-04-03 17:46:51 +02:00
} ;
2017-04-08 11:26:16 +02:00
let secretstore_key_server = secretstore ::start ( cmd . secretstore_conf . clone ( ) , secretstore_deps ) ? ;
2017-02-20 16:13:21 +01:00
2017-02-14 19:30:37 +01:00
// the ipfs server
2017-02-24 10:32:42 +01:00
let ipfs_server = ipfs ::start_server ( cmd . ipfs_conf . clone ( ) , client . clone ( ) ) ? ;
2017-02-14 19:30:37 +01:00
2016-12-10 23:58:39 +01:00
// the informant
2016-10-18 18:16:00 +02:00
let informant = Arc ::new ( Informant ::new (
2017-07-10 13:21:11 +02:00
FullNodeInformantData {
client : service . client ( ) ,
sync : Some ( sync_provider . clone ( ) ) ,
net : Some ( manage_network . clone ( ) ) ,
} ,
2016-10-18 18:16:00 +02:00
Some ( snapshot_service . clone ( ) ) ,
2017-02-04 22:18:19 +01:00
Some ( rpc_stats . clone ( ) ) ,
cmd . logger_config . color ,
2016-10-18 18:16:00 +02:00
) ) ;
2016-12-10 23:58:39 +01:00
service . add_notify ( informant . clone ( ) ) ;
service . register_io_handler ( informant . clone ( ) ) . map_err ( | _ | " Unable to register informant handler " . to_owned ( ) ) ? ;
2016-07-25 16:09:47 +02:00
2016-11-05 10:38:00 +01:00
// save user defaults
2017-07-18 15:38:38 +02:00
user_defaults . is_first_launch = false ;
2016-11-05 10:38:00 +01:00
user_defaults . pruning = algorithm ;
user_defaults . tracing = tracing ;
2016-11-27 11:11:56 +01:00
user_defaults . fat_db = fat_db ;
user_defaults . mode = mode ;
2016-12-27 12:53:56 +01:00
user_defaults . save ( & user_defaults_path ) ? ;
2016-11-05 10:38:00 +01:00
2016-12-10 23:58:39 +01:00
// tell client how to save the default mode if it gets changed.
2017-03-13 12:10:53 +01:00
client . on_user_defaults_change ( move | mode : Option < Mode > | {
if let Some ( mode ) = mode {
user_defaults . mode = mode ;
}
2016-11-05 10:38:00 +01:00
let _ = user_defaults . save ( & user_defaults_path ) ; // discard failures - there's nothing we can do
2016-12-10 23:58:39 +01:00
} ) ;
2016-11-05 10:38:00 +01:00
2016-09-05 14:25:56 +02:00
// the watcher must be kept alive.
2018-04-04 11:50:28 +02:00
let watcher = match cmd . no_periodic_snapshot {
2016-09-05 14:25:56 +02:00
true = > None ,
false = > {
2016-09-07 15:27:14 +02:00
let sync = sync_provider . clone ( ) ;
2017-03-13 12:10:53 +01:00
let client = client . clone ( ) ;
2016-09-05 14:25:56 +02:00
let watcher = Arc ::new ( snapshot ::Watcher ::new (
service . client ( ) ,
2016-10-20 23:36:18 +02:00
move | | is_major_importing ( Some ( sync . status ( ) . state ) , client . queue_info ( ) ) ,
2016-09-05 14:25:56 +02:00
service . io ( ) . channel ( ) ,
SNAPSHOT_PERIOD ,
SNAPSHOT_HISTORY ,
) ) ;
service . add_notify ( watcher . clone ( ) ) ;
Some ( watcher )
} ,
} ;
2016-07-25 16:09:47 +02:00
// start ui
if cmd . ui {
2017-07-28 19:07:38 +02:00
open_ui ( & cmd . ws_conf , & cmd . ui_conf , & cmd . logger_config ) ? ;
2016-07-25 16:09:47 +02:00
}
2017-01-06 16:05:58 +01:00
if let Some ( dapp ) = cmd . dapp {
2017-04-03 10:27:37 +02:00
open_dapp ( & cmd . dapps_conf , & cmd . http_conf , & dapp ) ? ;
2017-01-06 16:05:58 +01:00
}
2018-04-04 11:50:28 +02:00
client . set_exit_handler ( on_client_rq ) ;
updater . set_exit_handler ( on_updater_rq ) ;
2016-12-10 23:58:39 +01:00
2018-04-04 11:50:28 +02:00
Ok ( RunningClient ::Full {
informant ,
client ,
keep_alive : Box ::new ( ( watcher , service , updater , ws_server , http_server , ipc_server , ui_server , secretstore_key_server , ipfs_server , event_loop ) ) ,
} )
}
2017-05-24 12:24:07 +02:00
2018-04-04 11:50:28 +02:00
enum RunningClient {
Light {
informant : Arc < Informant < LightNodeInformantData > > ,
client : Arc < LightClient > ,
keep_alive : Box < Any > ,
} ,
Full {
informant : Arc < Informant < FullNodeInformantData > > ,
client : Arc < Client > ,
keep_alive : Box < Any > ,
} ,
}
2016-09-03 10:31:29 +02:00
2018-04-04 11:50:28 +02:00
impl RunningClient {
fn shutdown ( self ) {
match self {
RunningClient ::Light { informant , client , keep_alive } = > {
// Create a weak reference to the client so that we can wait on shutdown
// until it is dropped
let weak_client = Arc ::downgrade ( & client ) ;
drop ( keep_alive ) ;
informant . shutdown ( ) ;
drop ( informant ) ;
drop ( client ) ;
wait_for_drop ( weak_client ) ;
} ,
RunningClient ::Full { informant , client , keep_alive } = > {
info! ( " Finishing work, please wait... " ) ;
// Create a weak reference to the client so that we can wait on shutdown
// until it is dropped
let weak_client = Arc ::downgrade ( & client ) ;
// drop this stuff as soon as exit detected.
drop ( keep_alive ) ;
// to make sure timer does not spawn requests while shutdown is in progress
informant . shutdown ( ) ;
// just Arc is dropping here, to allow other reference release in its default time
drop ( informant ) ;
drop ( client ) ;
wait_for_drop ( weak_client ) ;
}
}
}
2018-01-31 11:41:29 +01:00
}
pub fn execute ( cmd : RunCmd , can_restart : bool , logger : Arc < RotatingLogger > ) -> Result < ( bool , Option < String > ) , String > {
2018-03-19 18:11:00 +01:00
if cmd . ui_conf . enabled {
2018-03-23 14:33:23 +01:00
warn! ( " {} " , Style ::new ( ) . bold ( ) . paint ( " Parity browser interface is deprecated. It's going to be removed in the next version, use standalone Parity UI instead. " ) ) ;
warn! ( " {} " , Style ::new ( ) . bold ( ) . paint ( " Standalone Parity UI: https://github.com/Parity-JS/shell/releases " ) ) ;
2018-03-19 18:11:00 +01:00
}
2018-01-31 11:41:29 +01:00
if cmd . ui & & cmd . dapps_conf . enabled {
// Check if Parity is already running
let addr = format! ( " {} : {} " , cmd . ui_conf . interface , cmd . ui_conf . port ) ;
if ! TcpListener ::bind ( & addr as & str ) . is_ok ( ) {
return open_ui ( & cmd . ws_conf , & cmd . ui_conf , & cmd . logger_config ) . map ( | _ | ( false , None ) ) ;
}
}
// increase max number of open files
raise_fd_limit ( ) ;
2018-04-04 11:50:28 +02:00
let exit = Arc ::new ( ( Mutex ::new ( ( false , None ) ) , Condvar ::new ( ) ) ) ;
2018-01-31 11:41:29 +01:00
2018-04-04 11:50:28 +02:00
let running_client = if cmd . light {
execute_light_impl ( cmd , logger ) ?
} else if can_restart {
let e1 = exit . clone ( ) ;
let e2 = exit . clone ( ) ;
execute_impl ( cmd , logger ,
move | new_chain : String | { * e1 . 0. lock ( ) = ( true , Some ( new_chain ) ) ; e1 . 1. notify_all ( ) ; } ,
move | | { * e2 . 0. lock ( ) = ( true , None ) ; e2 . 1. notify_all ( ) ; } ) ?
2018-01-31 11:41:29 +01:00
} else {
2018-04-04 11:50:28 +02:00
trace! ( target : " mode " , " Not hypervised: not setting exit handlers. " ) ;
execute_impl ( cmd , logger , move | _ | { } , move | | { } ) ?
} ;
// Handle possible exits
CtrlC ::set_handler ( {
let e = exit . clone ( ) ;
move | | { e . 1. notify_all ( ) ; }
} ) ;
// Wait for signal
let mut l = exit . 0. lock ( ) ;
let _ = exit . 1. wait ( & mut l ) ;
running_client . shutdown ( ) ;
Ok ( l . clone ( ) )
2016-07-25 16:09:47 +02:00
}
#[ cfg(not(windows)) ]
fn daemonize ( pid_file : String ) -> Result < ( ) , String > {
extern crate daemonize ;
daemonize ::Daemonize ::new ( )
2016-12-10 23:58:39 +01:00
. pid_file ( pid_file )
. chown_pid_file ( true )
. start ( )
. map ( | _ | ( ) )
. map_err ( | e | format! ( " Couldn't daemonize; {} " , e ) )
2016-07-25 16:09:47 +02:00
}
#[ cfg(windows) ]
fn daemonize ( _pid_file : String ) -> Result < ( ) , String > {
Err ( " daemon is no supported on windows " . into ( ) )
}
2017-06-22 20:08:56 +02:00
fn print_running_environment ( spec_name : & String , dirs : & Directories , db_dirs : & DatabaseDirectories , dapps_conf : & dapps ::Configuration ) {
info! ( " Starting {} " , Colour ::White . bold ( ) . paint ( version ( ) ) ) ;
info! ( " Keys path {} " , Colour ::White . bold ( ) . paint ( dirs . keys_path ( spec_name ) . to_string_lossy ( ) . into_owned ( ) ) ) ;
info! ( " DB path {} " , Colour ::White . bold ( ) . paint ( db_dirs . db_root_path ( ) . to_string_lossy ( ) . into_owned ( ) ) ) ;
info! ( " Path to dapps {} " , Colour ::White . bold ( ) . paint ( dapps_conf . dapps_path . to_string_lossy ( ) . into_owned ( ) ) ) ;
}
2017-01-04 16:51:27 +01:00
fn prepare_account_provider ( spec : & SpecType , dirs : & Directories , data_dir : & str , cfg : AccountsConfig , passwords : & [ String ] ) -> Result < AccountProvider , String > {
2016-10-04 10:44:47 +02:00
use ethcore ::ethstore ::EthStore ;
2017-12-24 09:34:43 +01:00
use ethcore ::ethstore ::accounts_dir ::RootDiskDirectory ;
2016-07-25 16:09:47 +02:00
2016-12-12 16:51:07 +01:00
let path = dirs . keys_path ( data_dir ) ;
upgrade_key_location ( & dirs . legacy_keys_path ( cfg . testnet ) , & path ) ;
2017-01-30 11:44:09 +01:00
let dir = Box ::new ( RootDiskDirectory ::create ( & path ) . map_err ( | e | format! ( " Could not open keys directory: {} " , e ) ) ? ) ;
2017-02-10 01:07:06 +01:00
let account_settings = AccountProviderSettings {
enable_hardware_wallets : cfg . enable_hardware_wallets ,
hardware_wallet_classic_key : spec = = & SpecType ::Classic ,
2017-06-14 12:06:15 +02:00
unlock_keep_secret : cfg . enable_fast_unlock ,
2017-06-07 11:34:53 +02:00
blacklisted_accounts : match * spec {
SpecType ::Morden | SpecType ::Ropsten | SpecType ::Kovan | SpecType ::Dev = > vec! [ ] ,
_ = > vec! [
" 00a329c0648769a73afac7f9381e08fb43dbea72 " . into ( )
] ,
} ,
2017-02-10 01:07:06 +01:00
} ;
2017-12-22 04:33:49 +01:00
let ethstore = EthStore ::open_with_iterations ( dir , cfg . iterations ) . map_err ( | e | format! ( " Could not open keys directory: {} " , e ) ) ? ;
if cfg . refresh_time > 0 {
ethstore . set_refresh_time ( ::std ::time ::Duration ::from_secs ( cfg . refresh_time ) ) ;
}
2017-02-10 01:07:06 +01:00
let account_provider = AccountProvider ::new (
2017-12-22 04:33:49 +01:00
Box ::new ( ethstore ) ,
account_settings ,
) ;
2016-07-25 16:09:47 +02:00
for a in cfg . unlocked_accounts {
2017-01-04 14:05:32 +01:00
// Check if the account exists
if ! account_provider . has_account ( a ) . unwrap_or ( false ) {
2017-01-04 16:51:27 +01:00
return Err ( format! ( " Account {} not found for the current chain. {} " , a , build_create_account_hint ( spec , & dirs . keys ) ) ) ;
2017-01-04 14:05:32 +01:00
}
// Check if any passwords have been read from the password file(s)
if passwords . is_empty ( ) {
2017-01-04 14:48:32 +01:00
return Err ( format! ( " No password found to unlock account {} . {} " , a , VERIFY_PASSWORD_HINT ) ) ;
2017-01-04 14:05:32 +01:00
}
if ! passwords . iter ( ) . any ( | p | account_provider . unlock_account_permanently ( a , ( * p ) . clone ( ) ) . is_ok ( ) ) {
2017-01-04 14:48:32 +01:00
return Err ( format! ( " No valid password to unlock account {} . {} " , a , VERIFY_PASSWORD_HINT ) ) ;
2016-07-25 16:09:47 +02:00
}
}
2017-05-19 17:06:36 +02:00
// Add development account if running dev chain:
if let SpecType ::Dev = * spec {
insert_dev_account ( & account_provider ) ;
}
2017-01-04 14:05:32 +01:00
Ok ( account_provider )
2016-07-25 16:09:47 +02:00
}
2017-05-19 17:06:36 +02:00
fn insert_dev_account ( account_provider : & AccountProvider ) {
let secret : ethkey ::Secret = " 4d5db4107d237df6a3d58ee5f70ae63d73d7658d4026f2eefd2f204c81682cb7 " . into ( ) ;
let dev_account = ethkey ::KeyPair ::from_secret ( secret . clone ( ) ) . expect ( " Valid secret produces valid key;qed " ) ;
if let Ok ( false ) = account_provider . has_account ( dev_account . address ( ) ) {
match account_provider . insert_account ( secret , " " ) {
Err ( e ) = > warn! ( " Unable to add development account: {} " , e ) ,
Ok ( address ) = > {
let _ = account_provider . set_account_name ( address . clone ( ) , " Development Account " . into ( ) ) ;
let _ = account_provider . set_account_meta ( address , ::serde_json ::to_string ( & ( vec! [
2018-02-13 07:52:05 +01:00
( " description " , " Never use this account outside of development chain! " ) ,
2017-05-19 17:06:36 +02:00
( " passwordHint " , " Password is empty string " ) ,
] . into_iter ( ) . collect ::< ::std ::collections ::HashMap < _ , _ > > ( ) ) ) . expect ( " Serialization of hashmap does not fail. " ) ) ;
} ,
}
}
}
2017-01-04 16:51:27 +01:00
// Construct an error `String` with an adaptive hint on how to create an account.
fn build_create_account_hint ( spec : & SpecType , keys : & str ) -> String {
format! ( " You can create an account via RPC, UI or `parity account new --chain {} --keys-path {} `. " , spec , keys )
}
2018-01-31 11:41:29 +01:00
fn wait_for_drop < T > ( w : Weak < T > ) {
let sleep_duration = Duration ::from_secs ( 1 ) ;
let warn_timeout = Duration ::from_secs ( 60 ) ;
let max_timeout = Duration ::from_secs ( 300 ) ;
let instant = Instant ::now ( ) ;
let mut warned = false ;
while instant . elapsed ( ) < max_timeout {
if w . upgrade ( ) . is_none ( ) {
return ;
}
if ! warned & & instant . elapsed ( ) > warn_timeout {
warned = true ;
warn! ( " Shutdown is taking longer than expected. " ) ;
}
thread ::sleep ( sleep_duration ) ;
}
warn! ( " Shutdown timeout reached, exiting uncleanly. " ) ;
}