Remove light client

This commit is contained in:
Artem Vorotnikov
2020-08-13 19:25:19 +03:00
parent 2ab8c72ce3
commit 194101ed00
94 changed files with 59 additions and 44043 deletions

View File

@@ -14,14 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::{
fs, io,
io::{BufRead, BufReader},
str::from_utf8,
sync::Arc,
thread::sleep,
time::{Duration, Instant},
};
use std::{fs, io, sync::Arc, time::Instant};
use ansi_term::Colour;
use bytes::ToPretty;
@@ -33,7 +26,6 @@ use ethcore::{
Balance, BlockChainClient, BlockChainReset, BlockId, DatabaseCompactionProfile,
ImportExportBlocks, Mode, Nonce, VMType,
},
error::{Error as EthcoreError, ErrorKind as EthcoreErrorKind, ImportErrorKind},
miner::Miner,
verification::queue::VerifierSettings,
};
@@ -44,8 +36,6 @@ use hash::{keccak, KECCAK_NULL_RLP};
use helpers::{execute_upgrades, to_client_config};
use informant::{FullNodeInformantData, Informant, MillisecondDuration};
use params::{fatdb_switch_to_bool, tracing_switch_to_bool, Pruning, SpecType, Switch};
use rlp::PayloadInfo;
use rustc_hex::FromHex;
use types::data_format::DataFormat;
use user_defaults::UserDefaults;
@@ -96,7 +86,6 @@ pub struct ImportBlockchain {
pub check_seal: bool,
pub with_color: bool,
pub verifier_settings: VerifierSettings,
pub light: bool,
pub max_round_blocks_to_import: usize,
}
@@ -143,201 +132,13 @@ pub struct ExportState {
pub fn execute(cmd: BlockchainCmd) -> Result<(), String> {
match cmd {
BlockchainCmd::Kill(kill_cmd) => kill_db(kill_cmd),
BlockchainCmd::Import(import_cmd) => {
if import_cmd.light {
execute_import_light(import_cmd)
} else {
execute_import(import_cmd)
}
}
BlockchainCmd::Import(import_cmd) => execute_import(import_cmd),
BlockchainCmd::Export(export_cmd) => execute_export(export_cmd),
BlockchainCmd::ExportState(export_cmd) => execute_export_state(export_cmd),
BlockchainCmd::Reset(reset_cmd) => execute_reset(reset_cmd),
}
}
fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> {
use light::{
cache::Cache as LightDataCache,
client::{Config as LightClientConfig, Service as LightClientService},
};
use parking_lot::Mutex;
let timer = Instant::now();
// load spec file
let spec = cmd.spec.spec(&cmd.dirs.cache)?;
// load genesis hash
let genesis_hash = spec.genesis_header().hash();
// database paths
let db_dirs = cmd.dirs.database(genesis_hash, None, 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);
// prepare client and snapshot paths.
let client_path = db_dirs.client_path(algorithm);
// execute upgrades
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?;
// create dirs used by parity
cmd.dirs.create_dirs(false, false)?;
let cache = Arc::new(Mutex::new(LightDataCache::new(
Default::default(),
Duration::new(0, 0),
)));
let mut config = LightClientConfig {
queue: Default::default(),
chain_column: ethcore_db::COL_LIGHT_CHAIN,
verify_full: true,
check_seal: cmd.check_seal,
no_hardcoded_sync: true,
};
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings;
// initialize database.
let db = db::open_db(
&client_path
.to_str()
.expect("DB path could not be converted to string."),
&cmd.cache_config,
&cmd.compaction,
)
.map_err(|e| format!("Failed to open database: {:?}", e))?;
// TODO: could epoch signals be available at the end of the file?
let fetch = ::light::client::fetch::unavailable();
let service = LightClientService::start(config, &spec, fetch, db, cache)
.map_err(|e| format!("Failed to start client: {}", e))?;
// free up the spec in memory.
drop(spec);
let client = service.client();
let mut instream: Box<dyn io::Read> = match cmd.file_path {
Some(f) => {
Box::new(fs::File::open(&f).map_err(|_| format!("Cannot open given file: {}", f))?)
}
None => Box::new(io::stdin()),
};
const READAHEAD_BYTES: usize = 8;
let mut first_bytes: Vec<u8> = vec![0; READAHEAD_BYTES];
let mut first_read = 0;
let format = match cmd.format {
Some(format) => format,
None => {
first_read = instream
.read(&mut first_bytes)
.map_err(|_| "Error reading from the file/stream.")?;
match first_bytes[0] {
0xf9 => DataFormat::Binary,
_ => DataFormat::Hex,
}
}
};
let do_import = |bytes: Vec<u8>| {
while client.queue_info().is_full() {
sleep(Duration::from_secs(1));
}
let header: ::types::header::Header = ::rlp::Rlp::new(&bytes)
.val_at(0)
.map_err(|e| format!("Bad block: {}", e))?;
if client.best_block_header().number() >= header.number() {
return Ok(());
}
if header.number() % 10000 == 0 {
info!("#{}", header.number());
}
match client.import_header(header) {
Err(EthcoreError(EthcoreErrorKind::Import(ImportErrorKind::AlreadyInChain), _)) => {
trace!("Skipping block already in chain.");
}
Err(e) => {
return Err(format!("Cannot import block: {:?}", e));
}
Ok(_) => {}
}
Ok(())
};
match format {
DataFormat::Binary => loop {
let mut bytes = if first_read > 0 {
first_bytes.clone()
} else {
vec![0; READAHEAD_BYTES]
};
let n = if first_read > 0 {
first_read
} else {
instream
.read(&mut bytes)
.map_err(|_| "Error reading from the file/stream.")?
};
if n == 0 {
break;
}
first_read = 0;
let s = PayloadInfo::from(&bytes)
.map_err(|e| format!("Invalid RLP in the file/stream: {:?}", e))?
.total();
bytes.resize(s, 0);
instream
.read_exact(&mut bytes[n..])
.map_err(|_| "Error reading from the file/stream.")?;
do_import(bytes)?;
},
DataFormat::Hex => {
for line in BufReader::new(instream).lines() {
let s = line.map_err(|_| "Error reading from the file/stream.")?;
let s = if first_read > 0 {
from_utf8(&first_bytes).unwrap().to_owned() + &(s[..])
} else {
s
};
first_read = 0;
let bytes = s.from_hex().map_err(|_| "Invalid hex in file/stream.")?;
do_import(bytes)?;
}
}
}
client.flush_queue();
let ms = timer.elapsed().as_milliseconds();
let report = client.report();
info!(
"Import completed in {} seconds, {} headers, {} hdr/s",
ms / 1000,
report.blocks_imported,
(report.blocks_imported * 1000) as u64 / ms,
);
Ok(())
}
fn execute_import(cmd: ImportBlockchain) -> Result<(), String> {
let timer = Instant::now();

View File

@@ -230,11 +230,6 @@ usage! {
}
}
CMD cmd_export_hardcoded_sync
{
"Print the hashed light clients headers of the given --chain (default: mainnet) in a JSON format. To be used as hardcoded headers in a genesis file.",
}
}
{
// Global flags and arguments
@@ -247,14 +242,6 @@ usage! {
"--no-consensus",
"Force the binary to run even if there are known issues regarding consensus. Not recommended.",
FLAG flag_light: (bool) = false, or |c: &Config| c.parity.as_ref()?.light,
"--light",
"Experimental: run in light client mode. Light clients synchronize a bare minimum of data and fetch necessary data on-demand from the network. Much lower in storage, potentially higher in bandwidth. Has no effect with subcommands.",
FLAG flag_no_hardcoded_sync: (bool) = false, or |c: &Config| c.parity.as_ref()?.no_hardcoded_sync,
"--no-hardcoded-sync",
"By default, if there is no existing database the light client will automatically jump to a block hardcoded in the chain's specifications. This disables this feature.",
FLAG flag_force_direct: (bool) = false, or |_| None,
"--force-direct",
"Run the originally installed version of Parity, ignoring any updates that have since been installed.",
@@ -392,10 +379,6 @@ usage! {
"--no-ancient-blocks",
"Disable downloading old blocks after snapshot restoration or warp sync. Not recommended.",
FLAG flag_no_serve_light: (bool) = false, or |c: &Config| c.network.as_ref()?.no_serve_light.clone(),
"--no-serve-light",
"Disable serving of light peers.",
ARG arg_warp_barrier: (Option<u64>) = None, or |c: &Config| c.network.as_ref()?.warp_barrier.clone(),
"--warp-barrier=[NUM]",
"When warp enabled never attempt regular sync before warping to block NUM.",
@@ -574,27 +557,6 @@ usage! {
"--ipfs-api-cors=[URL]",
"Specify CORS header for IPFS API responses. Special options: \"all\", \"none\".",
["Light Client Options"]
ARG arg_on_demand_response_time_window: (Option<u64>) = None, or |c: &Config| c.light.as_ref()?.on_demand_response_time_window,
"--on-demand-time-window=[S]",
"Specify the maximum time to wait for a successful response",
ARG arg_on_demand_request_backoff_start: (Option<u64>) = None, or |c: &Config| c.light.as_ref()?.on_demand_request_backoff_start,
"--on-demand-start-backoff=[S]",
"Specify light client initial backoff time for a request",
ARG arg_on_demand_request_backoff_max: (Option<u64>) = None, or |c: &Config| c.light.as_ref()?.on_demand_request_backoff_max,
"--on-demand-end-backoff=[S]",
"Specify light client maximum backoff time for a request",
ARG arg_on_demand_request_backoff_rounds_max: (Option<usize>) = None, or |c: &Config| c.light.as_ref()?.on_demand_request_backoff_rounds_max,
"--on-demand-max-backoff-rounds=[TIMES]",
"Specify light client maximum number of backoff iterations for a request",
ARG arg_on_demand_request_consecutive_failures: (Option<usize>) = None, or |c: &Config| c.light.as_ref()?.on_demand_request_consecutive_failures,
"--on-demand-consecutive-failures=[TIMES]",
"Specify light client the number of failures for a request until it gets exponentially backed off",
["Secret Store Options"]
FLAG flag_no_secretstore: (bool) = false, or |c: &Config| c.secretstore.as_ref()?.disable.clone(),
"--no-secretstore",
@@ -926,7 +888,6 @@ struct Config {
snapshots: Option<Snapshots>,
misc: Option<Misc>,
stratum: Option<Stratum>,
light: Option<Light>,
}
#[derive(Default, Debug, PartialEq, Deserialize)]
@@ -946,9 +907,7 @@ struct Operating {
db_path: Option<String>,
keys_path: Option<String>,
identity: Option<String>,
light: Option<bool>,
no_persistent_txqueue: Option<bool>,
no_hardcoded_sync: Option<bool>,
}
#[derive(Default, Debug, PartialEq, Deserialize)]
@@ -998,7 +957,6 @@ struct Network {
node_key: Option<String>,
reserved_peers: Option<String>,
reserved_only: Option<bool>,
no_serve_light: Option<bool>,
}
#[derive(Default, Debug, PartialEq, Deserialize)]
@@ -1154,21 +1112,11 @@ struct Misc {
unsafe_expose: Option<bool>,
}
#[derive(Default, Debug, PartialEq, Deserialize)]
#[serde(deny_unknown_fields)]
struct Light {
on_demand_response_time_window: Option<u64>,
on_demand_request_backoff_start: Option<u64>,
on_demand_request_backoff_max: Option<u64>,
on_demand_request_backoff_rounds_max: Option<usize>,
on_demand_request_consecutive_failures: Option<usize>,
}
#[cfg(test)]
mod tests {
use super::{
Account, Args, ArgsError, Config, Footprint, Ipc, Ipfs, Light, Mining, Misc, Network,
Operating, Rpc, SecretStore, Snapshots, Ws,
Account, Args, ArgsError, Config, Footprint, Ipc, Ipfs, Mining, Misc, Network, Operating,
Rpc, SecretStore, Snapshots, Ws,
};
use clap::ErrorKind as ClapErrorKind;
use toml;
@@ -1373,7 +1321,6 @@ mod tests {
cmd_db: false,
cmd_db_kill: false,
cmd_db_reset: false,
cmd_export_hardcoded_sync: false,
// Arguments
arg_daemon_pid_file: None,
@@ -1408,8 +1355,6 @@ mod tests {
arg_db_path: Some("$HOME/.parity/chains".into()),
arg_keys_path: "$HOME/.parity/keys".into(),
arg_identity: "".into(),
flag_light: false,
flag_no_hardcoded_sync: false,
flag_no_persistent_txqueue: false,
flag_force_direct: false,
@@ -1453,7 +1398,6 @@ mod tests {
arg_reserved_peers: Some("./path_to_file".into()),
flag_reserved_only: false,
flag_no_ancient_blocks: false,
flag_no_serve_light: false,
arg_warp_barrier: None,
// -- API and Console Options
@@ -1582,13 +1526,6 @@ mod tests {
flag_no_periodic_snapshot: false,
arg_snapshot_threads: None,
// -- Light options.
arg_on_demand_response_time_window: Some(2),
arg_on_demand_request_backoff_start: Some(9),
arg_on_demand_request_backoff_max: Some(15),
arg_on_demand_request_backoff_rounds_max: Some(100),
arg_on_demand_request_consecutive_failures: Some(1),
// -- Internal Options
flag_can_restart: false,
@@ -1648,8 +1585,6 @@ mod tests {
db_path: None,
keys_path: None,
identity: None,
light: None,
no_hardcoded_sync: None,
no_persistent_txqueue: None,
}),
account: Some(Account {
@@ -1677,7 +1612,6 @@ mod tests {
node_key: None,
reserved_peers: Some("./path/to/reserved_peers".into()),
reserved_only: Some(true),
no_serve_light: None,
}),
websockets: Some(Ws {
disable: Some(true),
@@ -1787,13 +1721,6 @@ mod tests {
scale_verifiers: Some(false),
num_verifiers: None,
}),
light: Some(Light {
on_demand_response_time_window: Some(2),
on_demand_request_backoff_start: Some(9),
on_demand_request_backoff_max: Some(15),
on_demand_request_backoff_rounds_max: Some(10),
on_demand_request_consecutive_failures: Some(1),
}),
snapshots: Some(Snapshots {
disable_periodic: Some(true),
processing_threads: None,

View File

@@ -15,8 +15,6 @@ base_path = "$HOME/.parity"
db_path = "$HOME/.parity/chains"
keys_path = "$HOME/.parity/keys"
identity = ""
light = false
no_hardcoded_sync = false
[account]
unlock = ["0xdeadbeefcafe0000000000000000000000000000"]
@@ -47,7 +45,6 @@ warp = true
allow_ips = "all"
snapshot_peers = 0
max_pending_peers = 64
no_serve_light = false
reserved_only = false
reserved_peers = "./path_to_file"
@@ -142,13 +139,6 @@ fat_db = "auto"
scale_verifiers = true
num_verifiers = 6
[light]
on_demand_response_time_window = 2
on_demand_request_backoff_start = 9
on_demand_request_backoff_max = 15
on_demand_request_backoff_rounds_max = 100
on_demand_request_consecutive_failures = 1
[snapshots]
disable_periodic = false

View File

@@ -62,13 +62,6 @@ db_compaction = "ssd"
fat_db = "off"
scale_verifiers = false
[light]
on_demand_response_time_window = 2
on_demand_request_backoff_start = 9
on_demand_request_backoff_max = 15
on_demand_request_backoff_rounds_max = 10
on_demand_request_consecutive_failures = 1
[snapshots]
disable_periodic = true

View File

@@ -53,7 +53,6 @@ use dir::{
};
use ethcore_logger::Config as LogConfig;
use ethcore_private_tx::{EncryptorConfig, ProviderConfig};
use export_hardcoded_sync::ExportHsyncCmd;
use helpers::{
parity_ipc_path, to_address, to_addresses, to_block_id, to_bootnodes, to_duration, to_mode,
to_pending_set, to_price, to_queue_penalization, to_queue_strategy, to_u256,
@@ -103,7 +102,6 @@ pub enum Cmd {
},
Snapshot(SnapshotCommand),
Hash(Option<String>),
ExportHardcodedSync(ExportHsyncCmd),
}
pub struct Execute {
@@ -286,7 +284,6 @@ impl Configuration {
check_seal: !self.args.flag_no_seal_check,
with_color: logger_config.color,
verifier_settings: self.verifier_settings(),
light: self.args.flag_light,
max_round_blocks_to_import: self.args.arg_max_round_blocks_to_import,
};
Cmd::Blockchain(BlockchainCmd::Import(import_cmd))
@@ -376,15 +373,6 @@ impl Configuration {
snapshot_conf: snapshot_conf,
};
Cmd::Snapshot(restore_cmd)
} else if self.args.cmd_export_hardcoded_sync {
let export_hs_cmd = ExportHsyncCmd {
cache_config: cache_config,
dirs: dirs,
spec: spec,
pruning: pruning,
compaction: compaction,
};
Cmd::ExportHardcodedSync(export_hs_cmd)
} else {
let daemon = if self.args.cmd_daemon {
Some(
@@ -444,20 +432,8 @@ impl Configuration {
check_seal: !self.args.flag_no_seal_check,
download_old_blocks: !self.args.flag_no_ancient_blocks,
verifier_settings: verifier_settings,
serve_light: !self.args.flag_no_serve_light,
light: self.args.flag_light,
no_persistent_txqueue: self.args.flag_no_persistent_txqueue,
no_hardcoded_sync: self.args.flag_no_hardcoded_sync,
max_round_blocks_to_import: self.args.arg_max_round_blocks_to_import,
on_demand_response_time_window: self.args.arg_on_demand_response_time_window,
on_demand_request_backoff_start: self.args.arg_on_demand_request_backoff_start,
on_demand_request_backoff_max: self.args.arg_on_demand_request_backoff_max,
on_demand_request_backoff_rounds_max: self
.args
.arg_on_demand_request_backoff_rounds_max,
on_demand_request_consecutive_failures: self
.args
.arg_on_demand_request_consecutive_failures,
};
Cmd::Run(run_cmd)
};
@@ -1106,16 +1082,7 @@ impl Configuration {
let is_using_base_path = self.args.arg_base_path.is_some();
// If base_path is set and db_path is not we default to base path subdir instead of LOCAL.
let base_db_path = if is_using_base_path && self.args.arg_db_path.is_none() {
if self.args.flag_light {
"$BASE/chains_light"
} else {
"$BASE/chains"
}
} else if self.args.flag_light {
self.args
.arg_db_path
.as_ref()
.map_or(dir::CHAINS_PATH_LIGHT, |s| &s)
"$BASE/chains"
} else {
self.args
.arg_db_path
@@ -1479,7 +1446,6 @@ mod tests {
check_seal: true,
with_color: !cfg!(windows),
verifier_settings: Default::default(),
light: false,
max_round_blocks_to_import: 12,
}))
);
@@ -1674,16 +1640,8 @@ mod tests {
check_seal: true,
download_old_blocks: true,
verifier_settings: Default::default(),
serve_light: true,
light: false,
no_hardcoded_sync: false,
no_persistent_txqueue: false,
max_round_blocks_to_import: 12,
on_demand_response_time_window: None,
on_demand_request_backoff_start: None,
on_demand_request_backoff_max: None,
on_demand_request_backoff_rounds_max: None,
on_demand_request_consecutive_failures: None,
};
expected.secretstore_conf.enabled = cfg!(feature = "secretstore");
expected.secretstore_conf.http_enabled = cfg!(feature = "secretstore");

View File

@@ -19,7 +19,7 @@
#[path = "rocksdb/mod.rs"]
mod impls;
pub use self::impls::{migrate, open_db, restoration_db_handler};
pub use self::impls::{migrate, restoration_db_handler};
#[cfg(feature = "secretstore")]
pub use self::impls::open_secretstore_db;

View File

@@ -23,13 +23,10 @@ use self::{
kvdb_rocksdb::{Database, DatabaseConfig},
};
use blooms_db;
use ethcore::client::{ClientConfig, DatabaseCompactionProfile};
use ethcore_db::NUM_COLUMNS;
use ethcore::client::ClientConfig;
use kvdb::KeyValueDB;
use std::{fs, io, path::Path, sync::Arc};
use cache::CacheConfig;
mod blooms;
mod helpers;
mod migration;
@@ -93,23 +90,6 @@ pub fn restoration_db_handler(
})
}
/// Open a new main DB.
pub fn open_db(
client_path: &str,
cache_config: &CacheConfig,
compaction: &DatabaseCompactionProfile,
) -> io::Result<Arc<dyn BlockChainDB>> {
let path = Path::new(client_path);
let db_config = DatabaseConfig {
memory_budget: Some(cache_config.blockchain() as usize * 1024 * 1024),
compaction: helpers::compaction_profile(&compaction, path),
..DatabaseConfig::with_columns(NUM_COLUMNS)
};
open_database(client_path, &db_config)
}
pub fn open_database(
client_path: &str,
config: &DatabaseConfig,

View File

@@ -1,121 +0,0 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::{sync::Arc, time::Duration};
use ethcore::{
client::DatabaseCompactionProfile,
spec::{OptimizeFor, SpecParams},
};
use light::{client::fetch::Unavailable as UnavailableDataFetcher, Cache as LightDataCache};
use cache::CacheConfig;
use db;
use dir::Directories;
use helpers::execute_upgrades;
use params::{Pruning, SpecType};
use user_defaults::UserDefaults;
// Number of minutes before a given gas price corpus should expire.
// Light client only.
const GAS_CORPUS_EXPIRATION_MINUTES: u64 = 60 * 6;
#[derive(Debug, PartialEq)]
pub struct ExportHsyncCmd {
pub cache_config: CacheConfig,
pub dirs: Directories,
pub spec: SpecType,
pub pruning: Pruning,
pub compaction: DatabaseCompactionProfile,
}
pub fn execute(cmd: ExportHsyncCmd) -> Result<String, String> {
use light::client as light_client;
use parking_lot::Mutex;
// load spec
let spec = cmd.spec.spec(SpecParams::new(
cmd.dirs.cache.as_ref(),
OptimizeFor::Memory,
))?;
// 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);
// execute upgrades
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?;
// create dirs used by parity
cmd.dirs.create_dirs(false, false)?;
// TODO: configurable cache size.
let cache = LightDataCache::new(
Default::default(),
Duration::from_secs(60 * GAS_CORPUS_EXPIRATION_MINUTES),
);
let cache = Arc::new(Mutex::new(cache));
// start client and create transaction queue.
let mut config = light_client::Config {
queue: Default::default(),
chain_column: ::ethcore_db::COL_LIGHT_CHAIN,
verify_full: true,
check_seal: true,
no_hardcoded_sync: true,
};
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
// initialize database.
let db = db::open_db(
&db_dirs
.client_path(algorithm)
.to_str()
.expect("DB path could not be converted to string."),
&cmd.cache_config,
&cmd.compaction,
)
.map_err(|e| format!("Failed to open database {:?}", e))?;
let service = light_client::Service::start(config, &spec, UnavailableDataFetcher, db, cache)
.map_err(|e| format!("Error starting light client: {}", e))?;
let hs = service
.client()
.read_hardcoded_sync()
.map_err(|e| format!("Error reading hardcoded sync: {}", e))?;
if let Some(hs) = hs {
Ok(::serde_json::to_string_pretty(&hs.to_json()).expect("generated JSON is always valid"))
} else {
Err("Error: cannot generate hardcoded sync because the database is empty.".into())
}
}

View File

@@ -37,16 +37,11 @@ use ethcore::{
},
snapshot::{service::Service as SnapshotService, RestorationStatus, SnapshotService as SS},
};
use ethereum_types::H256;
use io::{IoContext, IoHandler, TimerToken};
use light::{
client::{LightChainClient, LightChainNotify},
Cache as LightDataCache,
};
use number_prefix::{binary_prefix, Prefixed, Standalone};
use parity_rpc::{informant::RpcStats, is_major_importing_or_waiting};
use parking_lot::{Mutex, RwLock};
use sync::{LightSync, LightSyncProvider, ManageNetwork, SyncProvider};
use sync::{ManageNetwork, SyncProvider};
use types::BlockNumber;
/// Format byte counts to standard denominations.
@@ -189,53 +184,6 @@ impl InformantData for FullNodeInformantData {
}
}
/// Informant data for a light node -- note that the network is required.
pub struct LightNodeInformantData {
pub client: Arc<dyn LightChainClient>,
pub sync: Arc<LightSync>,
pub cache: Arc<Mutex<LightDataCache>>,
}
impl InformantData for LightNodeInformantData {
fn executes_transactions(&self) -> bool {
false
}
fn is_major_importing(&self) -> bool {
self.sync.is_major_importing()
}
fn report(&self) -> Report {
let (client_report, queue_info, chain_info) = (
self.client.report(),
self.client.queue_info(),
self.client.chain_info(),
);
let mut cache_sizes = CacheSizes::default();
cache_sizes.insert("queue", queue_info.mem_used);
cache_sizes.insert("cache", self.cache.lock().mem_used());
let peer_numbers = self.sync.peer_numbers();
let sync_info = Some(SyncInfo {
last_imported_block_number: chain_info.best_block_number,
last_imported_old_block_number: None,
num_peers: peer_numbers.connected,
max_peers: peer_numbers.max as u32,
snapshot_sync: false,
});
Report {
importing: self.sync.is_major_importing(),
chain_info,
client_report,
queue_info,
cache_sizes,
sync_info,
}
}
}
pub struct Informant<T> {
last_tick: RwLock<Instant>,
with_color: bool,
@@ -449,36 +397,6 @@ impl ChainNotify for Informant<FullNodeInformantData> {
}
}
impl LightChainNotify for Informant<LightNodeInformantData> {
fn new_headers(&self, good: &[H256]) {
let mut last_import = self.last_import.lock();
let client = &self.target.client;
let importing = self.target.is_major_importing();
let ripe = Instant::now() > *last_import + Duration::from_secs(1) && !importing;
if ripe {
if let Some(header) = good
.last()
.and_then(|h| client.block_header(BlockId::Hash(*h)))
{
info!(target: "import", "Imported {} {} ({} Mgas){}",
Colour::White.bold().paint(format!("#{}", header.number())),
Colour::White.bold().paint(format!("{}", header.hash())),
Colour::Yellow.bold().paint(format!("{:.2}", header.gas_used().low_u64() as f32 / 1000000f32)),
if good.len() > 1 {
format!(" + another {} header(s)",
Colour::Red.bold().paint(format!("{}", good.len() - 1)))
} else {
String::new()
}
);
*last_import = Instant::now();
}
}
}
}
const INFO_TIMER: TimerToken = 0;
impl<T: InformantData> IoHandler<ClientIoMessage> for Informant<T> {

View File

@@ -46,7 +46,6 @@ extern crate ethcore;
extern crate ethcore_call_contract as call_contract;
extern crate ethcore_db;
extern crate ethcore_io as io;
extern crate ethcore_light as light;
extern crate ethcore_logger;
extern crate ethcore_miner as miner;
extern crate ethcore_network as network;
@@ -98,11 +97,9 @@ mod cache;
mod cli;
mod configuration;
mod db;
mod export_hardcoded_sync;
mod helpers;
mod informant;
mod ipfs;
mod light_helpers;
mod modules;
mod params;
mod presale;
@@ -235,9 +232,6 @@ where
Cmd::Snapshot(snapshot_cmd) => {
snapshot::execute(snapshot_cmd).map(|s| ExecutionAction::Instant(Some(s)))
}
Cmd::ExportHardcodedSync(export_hs_cmd) => {
export_hardcoded_sync::execute(export_hs_cmd).map(|s| ExecutionAction::Instant(Some(s)))
}
}
}

View File

@@ -1,100 +0,0 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Weak};
use ethcore::{
engines::{EthEngine, StateDependentProof},
machine::EthereumMachine,
};
use sync::{LightNetworkDispatcher, LightSync};
use types::{encoded, header::Header, receipt::Receipt};
use futures::{future, future::Either, Future};
use light::{
client::fetch::ChainDataFetcher,
on_demand::{request, OnDemand, OnDemandRequester},
};
use ethereum_types::H256;
use parking_lot::RwLock;
const ALL_VALID_BACKREFS: &str = "no back-references, therefore all back-references valid; qed";
type BoxFuture<T, E> = Box<dyn Future<Item = T, Error = E>>;
/// Allows on-demand fetch of data useful for the light client.
pub struct EpochFetch {
/// A handle to the sync service.
pub sync: Arc<RwLock<Weak<LightSync>>>,
/// The on-demand request service.
pub on_demand: Arc<OnDemand>,
}
impl EpochFetch {
fn request<T>(&self, req: T) -> BoxFuture<T::Out, &'static str>
where
T: Send + request::RequestAdapter + 'static,
T::Out: Send + 'static,
{
Box::new(match self.sync.read().upgrade() {
Some(sync) => {
let on_demand = &self.on_demand;
let maybe_future = sync.with_context(move |ctx| {
on_demand.request(ctx, req).expect(ALL_VALID_BACKREFS)
});
match maybe_future {
Some(x) => Either::A(x.map_err(|_| "Request canceled")),
None => Either::B(future::err("Unable to access network.")),
}
}
None => Either::B(future::err("Unable to access network")),
})
}
}
impl ChainDataFetcher for EpochFetch {
type Error = &'static str;
type Body = BoxFuture<encoded::Block, &'static str>;
type Receipts = BoxFuture<Vec<Receipt>, &'static str>;
type Transition = BoxFuture<Vec<u8>, &'static str>;
fn block_body(&self, header: &Header) -> Self::Body {
self.request(request::Body(header.encoded().into()))
}
/// Fetch block receipts.
fn block_receipts(&self, header: &Header) -> Self::Receipts {
self.request(request::BlockReceipts(header.encoded().into()))
}
/// Fetch epoch transition proof at given header.
fn epoch_transition(
&self,
hash: H256,
engine: Arc<dyn EthEngine>,
checker: Arc<dyn StateDependentProof<EthereumMachine>>,
) -> Self::Transition {
self.request(request::Signal {
hash: hash,
engine: engine,
proof_check: checker,
})
}
}

View File

@@ -1,21 +0,0 @@
// Copyright 2015-2019 Parity Technologies (UK) Ltd.
// This file is part of Parity Ethereum.
// Parity Ethereum 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 Ethereum 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 Ethereum. If not, see <http://www.gnu.org/licenses/>.
//! Utilities and helpers for the light client.
mod epoch_fetch;
pub use self::epoch_fetch::EpochFetch;

View File

@@ -17,7 +17,6 @@
use std::sync::{mpsc, Arc};
use ethcore::{client::BlockChainClient, snapshot::SnapshotService};
use light::Provider;
use sync::{self, ConnectionFilter, NetworkConfiguration, Params, SyncConfig};
pub use ethcore::client::ChainNotify;
@@ -37,7 +36,6 @@ pub fn sync(
chain: Arc<dyn BlockChainClient>,
snapshot_service: Arc<dyn SnapshotService>,
private_tx_handler: Option<Arc<dyn PrivateTxHandler>>,
provider: Arc<dyn Provider>,
_log_settings: &LogConfig,
connection_filter: Option<Arc<dyn ConnectionFilter>>,
) -> Result<SyncModules, sync::Error> {
@@ -45,7 +43,6 @@ pub fn sync(
Params {
config,
chain,
provider,
snapshot_service,
private_tx_handler,
network_config,

View File

@@ -14,34 +14,25 @@
// You should have received a copy of the GNU General Public License
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
use std::{
cmp::PartialEq,
collections::HashSet,
str::FromStr,
sync::{Arc, Weak},
};
use std::{cmp::PartialEq, collections::HashSet, str::FromStr, sync::Arc};
pub use parity_rpc::signer::SignerService;
use account_utils::{self, AccountProvider};
use ethcore::{client::Client, miner::Miner, snapshot::SnapshotService};
use ethcore_logger::RotatingLogger;
use ethcore_private_tx::Provider as PrivateTransactionManager;
use ethcore_service::PrivateTxService;
use hash_fetch::fetch::Client as FetchClient;
use jsonrpc_core::{self as core, MetaIoHandler};
use light::{
client::LightChainClient, Cache as LightDataCache, TransactionQueue as LightTransactionQueue,
};
use miner::external::ExternalMiner;
use parity_rpc::{
dispatch::{FullDispatcher, LightDispatcher},
dispatch::FullDispatcher,
informant::{ActivityNotifier, ClientNotifier},
Host, Metadata, NetworkSettings,
};
use parity_runtime::Executor;
use parking_lot::{Mutex, RwLock};
use sync::{LightSync, ManageNetwork, SyncProvider};
use parking_lot::Mutex;
use sync::{ManageNetwork, SyncProvider};
use updater::Updater;
#[derive(Debug, PartialEq, Clone, Eq, Hash)]
@@ -426,220 +417,6 @@ impl Dependencies for FullDependencies {
}
}
/// Light client notifier. Doesn't do anything yet, but might in the future.
pub struct LightClientNotifier;
impl ActivityNotifier for LightClientNotifier {
fn active(&self) {}
}
/// RPC dependencies for a light client.
pub struct LightDependencies<T> {
pub signer_service: Arc<SignerService>,
pub client: Arc<T>,
pub sync: Arc<LightSync>,
pub net: Arc<dyn ManageNetwork>,
pub accounts: Arc<AccountProvider>,
pub logger: Arc<RotatingLogger>,
pub settings: Arc<NetworkSettings>,
pub on_demand: Arc<::light::on_demand::OnDemand>,
pub cache: Arc<Mutex<LightDataCache>>,
pub transaction_queue: Arc<RwLock<LightTransactionQueue>>,
pub ws_address: Option<Host>,
pub fetch: FetchClient,
pub experimental_rpcs: bool,
pub executor: Executor,
pub private_tx_service: Option<Arc<PrivateTransactionManager>>,
pub gas_price_percentile: usize,
pub poll_lifetime: u32,
}
impl<C: LightChainClient + 'static> LightDependencies<C> {
fn extend_api<T: core::Middleware<Metadata>>(
&self,
handler: &mut MetaIoHandler<Metadata, T>,
apis: &HashSet<Api>,
for_generic_pubsub: bool,
) {
use parity_rpc::v1::*;
let dispatcher = LightDispatcher::new(
self.sync.clone(),
self.client.clone(),
self.on_demand.clone(),
self.cache.clone(),
self.transaction_queue.clone(),
Arc::new(Mutex::new(dispatch::Reservations::new(
self.executor.clone(),
))),
self.gas_price_percentile,
);
let account_signer = Arc::new(dispatch::Signer::new(self.accounts.clone())) as _;
let accounts = account_utils::accounts_list(self.accounts.clone());
for api in apis {
match *api {
Api::Debug => {
warn!(target: "rpc", "Debug API is not available in light client mode.")
}
Api::Web3 => {
handler.extend_with(Web3Client::default().to_delegate());
}
Api::Net => {
handler.extend_with(light::NetClient::new(self.sync.clone()).to_delegate());
}
Api::Eth => {
let client = light::EthClient::new(
self.sync.clone(),
self.client.clone(),
self.on_demand.clone(),
self.transaction_queue.clone(),
accounts.clone(),
self.cache.clone(),
self.gas_price_percentile,
self.poll_lifetime,
);
handler.extend_with(Eth::to_delegate(client.clone()));
if !for_generic_pubsub {
handler.extend_with(EthFilter::to_delegate(client));
add_signing_methods!(
EthSigning,
handler,
self,
(&dispatcher, &account_signer)
);
}
}
Api::EthPubSub => {
let client = EthPubSubClient::light(
self.client.clone(),
self.on_demand.clone(),
self.sync.clone(),
self.cache.clone(),
self.executor.clone(),
self.gas_price_percentile,
);
self.client.add_listener(client.handler() as Weak<_>);
let h = client.handler();
self.transaction_queue
.write()
.add_listener(Box::new(move |transactions| {
if let Some(h) = h.upgrade() {
h.notify_new_transactions(transactions);
}
}));
handler.extend_with(EthPubSub::to_delegate(client));
}
Api::Personal => {
#[cfg(feature = "accounts")]
handler.extend_with(
PersonalClient::new(
&self.accounts,
dispatcher.clone(),
self.experimental_rpcs,
)
.to_delegate(),
);
}
Api::Signer => {
handler.extend_with(
SignerClient::new(
account_signer.clone(),
dispatcher.clone(),
&self.signer_service,
self.executor.clone(),
)
.to_delegate(),
);
}
Api::Parity => {
let signer = match self.signer_service.is_enabled() {
true => Some(self.signer_service.clone()),
false => None,
};
handler.extend_with(
light::ParityClient::new(
Arc::new(dispatcher.clone()),
self.logger.clone(),
self.settings.clone(),
signer,
self.ws_address.clone(),
self.gas_price_percentile,
)
.to_delegate(),
);
#[cfg(feature = "accounts")]
handler.extend_with(ParityAccountsInfo::to_delegate(
ParityAccountsClient::new(&self.accounts),
));
if !for_generic_pubsub {
add_signing_methods!(
ParitySigning,
handler,
self,
(&dispatcher, &account_signer)
);
}
}
Api::ParityPubSub => {
if !for_generic_pubsub {
let mut rpc = MetaIoHandler::default();
let apis = ApiSet::List(apis.clone())
.retain(ApiSet::PubSub)
.list_apis();
self.extend_api(&mut rpc, &apis, true);
handler.extend_with(
PubSubClient::new(rpc, self.executor.clone()).to_delegate(),
);
}
}
Api::ParityAccounts => {
#[cfg(feature = "accounts")]
handler.extend_with(ParityAccounts::to_delegate(ParityAccountsClient::new(
&self.accounts,
)));
}
Api::ParitySet => handler.extend_with(
light::ParitySetClient::new(
self.client.clone(),
self.sync.clone(),
self.fetch.clone(),
)
.to_delegate(),
),
Api::Traces => handler.extend_with(light::TracesClient.to_delegate()),
Api::SecretStore => {
#[cfg(feature = "accounts")]
handler.extend_with(SecretStoreClient::new(&self.accounts).to_delegate());
}
Api::Private => {
if let Some(ref tx_manager) = self.private_tx_service {
let private_tx_service = Some(tx_manager.clone());
handler.extend_with(PrivateClient::new(private_tx_service).to_delegate());
}
}
}
}
}
}
impl<T: LightChainClient + 'static> Dependencies for LightDependencies<T> {
type Notifier = LightClientNotifier;
fn activity_notifier(&self) -> Self::Notifier {
LightClientNotifier
}
fn extend_with_set<S>(&self, handler: &mut MetaIoHandler<Metadata, S>, apis: &HashSet<Api>)
where
S: core::Middleware<Metadata>,
{
self.extend_api(handler, apis, false)
}
}
impl ApiSet {
/// Retains only APIs in given set.
pub fn retain(self, set: Self) -> Self {

View File

@@ -34,7 +34,6 @@ use ethcore::{
},
miner::{self, stratum, Miner, MinerOptions, MinerService},
snapshot::{self, SnapshotConfiguration},
spec::{OptimizeFor, SpecParams},
verification::queue::VerifierSettings,
};
use ethcore_logger::{Config as LogConfig, RotatingLogger};
@@ -44,11 +43,10 @@ use ethereum_types::Address;
use futures::IntoFuture;
use hash_fetch::{self, fetch};
use helpers::{execute_upgrades, passwords_from_files, to_client_config};
use informant::{FullNodeInformantData, Informant, LightNodeInformantData};
use informant::{FullNodeInformantData, Informant};
use ipfs;
use journaldb::Algorithm;
use jsonrpc_core;
use light::Cache as LightDataCache;
use miner::{external::ExternalMiner, work_notify::WorkPoster};
use modules;
use node_filter::NodeFilter;
@@ -77,16 +75,9 @@ const SNAPSHOT_PERIOD: u64 = 5000;
// how many blocks to wait before starting a periodic snapshot.
const SNAPSHOT_HISTORY: u64 = 100;
// Number of minutes before a given gas price corpus should expire.
// Light client only.
const GAS_CORPUS_EXPIRATION_MINUTES: u64 = 60 * 6;
// Full client number of DNS threads
const FETCH_FULL_NUM_DNS_THREADS: usize = 4;
// Light client number of DNS threads
const FETCH_LIGHT_NUM_DNS_THREADS: usize = 1;
#[derive(Debug, PartialEq)]
pub struct RunCmd {
pub cache_config: CacheConfig,
@@ -132,16 +123,8 @@ pub struct RunCmd {
pub allow_missing_blocks: bool,
pub download_old_blocks: bool,
pub verifier_settings: VerifierSettings,
pub serve_light: bool,
pub light: bool,
pub no_persistent_txqueue: bool,
pub no_hardcoded_sync: bool,
pub max_round_blocks_to_import: usize,
pub on_demand_response_time_window: Option<u64>,
pub on_demand_request_backoff_start: Option<u64>,
pub on_demand_request_backoff_max: Option<u64>,
pub on_demand_request_backoff_rounds_max: Option<usize>,
pub on_demand_request_consecutive_failures: Option<usize>,
}
// node info fetcher for the local store.
@@ -169,252 +152,15 @@ impl ::local_store::NodeInfo for FullNodeInfo {
}
}
type LightClient = ::light::client::Client<::light_helpers::EpochFetch>;
// helper for light execution.
fn execute_light_impl<Cr>(
cmd: RunCmd,
logger: Arc<RotatingLogger>,
on_client_rq: Cr,
) -> Result<RunningClient, String>
where
Cr: Fn(String) + 'static + Send,
{
use light::client as light_client;
use parking_lot::{Mutex, RwLock};
use sync::{LightSync, LightSyncParams, ManageNetwork};
// load spec
let spec = cmd.spec.spec(SpecParams::new(
cmd.dirs.cache.as_ref(),
OptimizeFor::Memory,
))?;
// 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);
// execute upgrades
execute_upgrades(&cmd.dirs.base, &db_dirs, algorithm, &cmd.compaction)?;
// create dirs used by parity
cmd.dirs.create_dirs(
cmd.acc_conf.unlocked_accounts.len() == 0,
cmd.secretstore_conf.enabled,
)?;
//print out running parity environment
print_running_environment(&spec.data_dir, &cmd.dirs, &db_dirs);
info!(
"Running in experimental {} mode.",
Colour::Blue.bold().paint("Light Client")
);
// TODO: configurable cache size.
let cache = LightDataCache::new(
Default::default(),
Duration::from_secs(60 * GAS_CORPUS_EXPIRATION_MINUTES),
);
let cache = Arc::new(Mutex::new(cache));
// start client and create transaction queue.
let mut config = light_client::Config {
queue: Default::default(),
chain_column: ::ethcore_db::COL_LIGHT_CHAIN,
verify_full: true,
check_seal: cmd.check_seal,
no_hardcoded_sync: cmd.no_hardcoded_sync,
};
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings;
// start on_demand service.
let response_time_window = cmd
.on_demand_response_time_window
.map_or(::light::on_demand::DEFAULT_RESPONSE_TIME_TO_LIVE, |s| {
Duration::from_secs(s)
});
let request_backoff_start = cmd.on_demand_request_backoff_start.map_or(
::light::on_demand::DEFAULT_REQUEST_MIN_BACKOFF_DURATION,
|s| Duration::from_secs(s),
);
let request_backoff_max = cmd.on_demand_request_backoff_max.map_or(
::light::on_demand::DEFAULT_REQUEST_MAX_BACKOFF_DURATION,
|s| Duration::from_secs(s),
);
let on_demand = Arc::new({
::light::on_demand::OnDemand::new(
cache.clone(),
response_time_window,
request_backoff_start,
request_backoff_max,
cmd.on_demand_request_backoff_rounds_max
.unwrap_or(::light::on_demand::DEFAULT_MAX_REQUEST_BACKOFF_ROUNDS),
cmd.on_demand_request_consecutive_failures
.unwrap_or(::light::on_demand::DEFAULT_NUM_CONSECUTIVE_FAILED_REQUESTS),
)
});
let sync_handle = Arc::new(RwLock::new(Weak::new()));
let fetch = ::light_helpers::EpochFetch {
on_demand: on_demand.clone(),
sync: sync_handle.clone(),
};
// initialize database.
let db = db::open_db(
&db_dirs
.client_path(algorithm)
.to_str()
.expect("DB path could not be converted to string."),
&cmd.cache_config,
&cmd.compaction,
)
.map_err(|e| format!("Failed to open database {:?}", e))?;
let service = light_client::Service::start(config, &spec, fetch, db, cache.clone())
.map_err(|e| format!("Error starting light client: {}", e))?;
let client = service.client().clone();
let txq = Arc::new(RwLock::new(
::light::transaction_queue::TransactionQueue::default(),
));
let provider = ::light::provider::LightProvider::new(client.clone(), txq.clone());
// start network.
// set up bootnodes
let mut net_conf = cmd.net_conf;
if !cmd.custom_bootnodes {
net_conf.boot_nodes = spec.nodes.clone();
}
// 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()),
subprotocol_name: sync::LIGHT_PROTOCOL,
handlers: vec![on_demand.clone()],
};
let light_sync =
LightSync::new(sync_params).map_err(|e| format!("Error starting network: {}", e))?;
let light_sync = Arc::new(light_sync);
*sync_handle.write() = Arc::downgrade(&light_sync);
// spin up event loop
let runtime = Runtime::with_default_thread_count();
// start the network.
light_sync.start_network();
// fetch service
let fetch = fetch::Client::new(FETCH_LIGHT_NUM_DNS_THREADS)
.map_err(|e| format!("Error starting fetch client: {:?}", e))?;
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
// prepare account provider
let account_provider = Arc::new(account_utils::prepare_account_provider(
&cmd.spec,
&cmd.dirs,
&spec.data_dir,
cmd.acc_conf,
&passwords,
)?);
let rpc_stats = Arc::new(informant::RpcStats::default());
// the dapps server
let signer_service = Arc::new(signer::new_service(&cmd.ws_conf, &cmd.logger_config));
// start RPCs
let deps_for_rpc_apis = Arc::new(rpc_apis::LightDependencies {
signer_service: signer_service,
client: client.clone(),
sync: light_sync.clone(),
net: light_sync.clone(),
accounts: account_provider,
logger: logger,
settings: Arc::new(cmd.net_settings),
on_demand: on_demand,
cache: cache.clone(),
transaction_queue: txq,
ws_address: cmd.ws_conf.address(),
fetch: fetch,
experimental_rpcs: cmd.experimental_rpcs,
executor: runtime.executor(),
private_tx_service: None, //TODO: add this to client.
gas_price_percentile: cmd.gas_price_percentile,
poll_lifetime: cmd.poll_lifetime,
});
let dependencies = rpc::Dependencies {
apis: deps_for_rpc_apis.clone(),
executor: runtime.executor(),
stats: rpc_stats.clone(),
};
// start rpc servers
let rpc_direct = rpc::setup_apis(rpc_apis::ApiSet::All, &dependencies);
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,
)?;
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
// the informant
let informant = Arc::new(Informant::new(
LightNodeInformantData {
client: client.clone(),
sync: light_sync.clone(),
cache: cache,
},
None,
Some(rpc_stats),
cmd.logger_config.color,
));
service.add_notify(informant.clone());
service
.register_handler(informant.clone())
.map_err(|_| "Unable to register informant handler".to_owned())?;
client.set_exit_handler(on_client_rq);
Ok(RunningClient {
inner: RunningClientInner::Light {
rpc: rpc_direct,
informant,
client,
keep_alive: Box::new((service, ws_server, http_server, ipc_server, runtime)),
},
})
}
fn execute_impl<Cr, Rr>(
/// Executes the given run command.
///
/// `on_client_rq` is the action to perform when the client receives an RPC request to be restarted
/// with a different chain.
///
/// `on_updater_rq` is the action to perform when the updater has a new binary to execute.
///
/// On error, returns what to print on stderr.
pub fn execute<Cr, Rr>(
cmd: RunCmd,
logger: Arc<RotatingLogger>,
on_client_rq: Cr,
@@ -540,7 +286,6 @@ where
_ => sync::WarpSync::Disabled,
};
sync_config.download_old_blocks = cmd.download_old_blocks;
sync_config.serve_light = cmd.serve_light;
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
@@ -597,11 +342,6 @@ where
}
}
// display warning if using --no-hardcoded-sync
if cmd.no_hardcoded_sync {
warn!("The --no-hardcoded-sync flag has no effect if you don't use --light");
}
// create client config
let mut client_config = to_client_config(
&cmd.cache_config,
@@ -747,7 +487,6 @@ where
client.clone(),
snapshot_service.clone(),
private_tx_sync,
client.clone(),
&cmd.logger_config,
connection_filter
.clone()
@@ -965,15 +704,6 @@ pub struct RunningClient {
}
enum RunningClientInner {
Light {
rpc: jsonrpc_core::MetaIoHandler<
Metadata,
informant::Middleware<rpc_apis::LightClientNotifier>,
>,
informant: Arc<Informant<LightNodeInformantData>>,
client: Arc<LightClient>,
keep_alive: Box<dyn Any>,
},
Full {
rpc:
jsonrpc_core::MetaIoHandler<Metadata, informant::Middleware<informant::ClientNotifier>>,
@@ -998,7 +728,6 @@ impl RunningClient {
};
match self.inner {
RunningClientInner::Light { ref rpc, .. } => rpc.handle_request(request, metadata),
RunningClientInner::Full { ref rpc, .. } => rpc.handle_request(request, metadata),
}
}
@@ -1006,22 +735,6 @@ impl RunningClient {
/// Shuts down the client.
pub fn shutdown(self) {
match self.inner {
RunningClientInner::Light {
rpc,
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(rpc);
drop(keep_alive);
informant.shutdown();
drop(informant);
drop(client);
wait_for_drop(weak_client);
}
RunningClientInner::Full {
rpc,
informant,
@@ -1060,31 +773,6 @@ impl RunningClient {
}
}
/// Executes the given run command.
///
/// `on_client_rq` is the action to perform when the client receives an RPC request to be restarted
/// with a different chain.
///
/// `on_updater_rq` is the action to perform when the updater has a new binary to execute.
///
/// On error, returns what to print on stderr.
pub fn execute<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,
{
if cmd.light {
execute_light_impl(cmd, logger, on_client_rq)
} else {
execute_impl(cmd, logger, on_client_rq, on_updater_rq)
}
}
fn print_running_environment(data_dir: &str, dirs: &Directories, db_dirs: &DatabaseDirectories) {
info!("Starting {}", Colour::White.bold().paint(version()));
info!(