complete quick'n'dirty light CLI

This commit is contained in:
Robert Habermeier 2017-03-22 22:00:52 +01:00
parent 73b2dd7a59
commit 83911a7290
4 changed files with 140 additions and 62 deletions

View File

@ -18,13 +18,15 @@ use std::path::PathBuf;
use std::sync::Arc; use std::sync::Arc;
use dir::default_data_path; use dir::default_data_path;
use ethcore::client::Client; use ethcore::client::{Client, BlockChainClient, BlockId};
use ethcore::transaction::{Transaction, Action};
use ethcore_rpc::informant::RpcStats; use ethcore_rpc::informant::RpcStats;
use ethsync::SyncProvider;
use hash_fetch::fetch::Client as FetchClient; use hash_fetch::fetch::Client as FetchClient;
use hash_fetch::urlhint::ContractClient;
use helpers::replace_home; use helpers::replace_home;
use rpc_apis::{self, SignerService}; use rpc_apis::{self, SignerService};
use parity_reactor; use parity_reactor;
use util::{Bytes, Address, U256};
#[derive(Debug, PartialEq, Clone)] #[derive(Debug, PartialEq, Clone)]
pub struct Configuration { pub struct Configuration {
@ -58,17 +60,56 @@ impl Default for Configuration {
} }
} }
pub struct Dependencies { /// Registrar implementation of the full client.
pub apis: Arc<rpc_apis::FullDependencies>, pub struct FullRegistrar {
/// Handle to the full client.
pub client: Arc<Client>, pub client: Arc<Client>,
pub sync: Arc<SyncProvider>, }
impl ContractClient for FullRegistrar {
fn registrar(&self) -> Result<Address, String> {
self.client.additional_params().get("registrar")
.ok_or_else(|| "Registrar not defined.".into())
.and_then(|registrar| {
registrar.parse().map_err(|e| format!("Invalid registrar address: {:?}", e))
})
}
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
let from = Address::default();
let transaction = Transaction {
nonce: self.client.latest_nonce(&from),
action: Action::Call(address),
gas: U256::from(50_000_000),
gas_price: U256::default(),
value: U256::default(),
data: data,
}.fake_sign(from);
self.client.call(&transaction, BlockId::Latest, Default::default())
.map_err(|e| format!("{:?}", e))
.map(|executed| {
executed.output
})
}
}
// TODO: light client implementation forwarding to OnDemand and waiting for future
// to resolve.
pub struct Dependencies<D: rpc_apis::Dependencies> {
pub apis: Arc<D>,
pub sync_status: Arc<::ethcore_dapps::SyncStatus>,
pub contract_client: Arc<ContractClient>,
pub remote: parity_reactor::TokioRemote, pub remote: parity_reactor::TokioRemote,
pub fetch: FetchClient, pub fetch: FetchClient,
pub signer: Arc<SignerService>, pub signer: Arc<SignerService>,
pub stats: Arc<RpcStats>, pub stats: Arc<RpcStats>,
} }
pub fn new(configuration: Configuration, deps: Dependencies) -> Result<Option<WebappServer>, String> { pub fn new<D>(configuration: Configuration, deps: Dependencies<D>) -> Result<Option<WebappServer>, String>
where D: rpc_apis::Dependencies
{
if !configuration.enabled { if !configuration.enabled {
return Ok(None); return Ok(None);
} }
@ -130,21 +171,16 @@ mod server {
use std::sync::Arc; use std::sync::Arc;
use std::net::SocketAddr; use std::net::SocketAddr;
use std::io; use std::io;
use util::{Bytes, Address, U256};
use ansi_term::Colour; use ansi_term::Colour;
use ethcore::transaction::{Transaction, Action};
use ethcore::client::{Client, BlockChainClient, BlockId};
use ethcore_dapps::{AccessControlAllowOrigin, Host}; use ethcore_dapps::{AccessControlAllowOrigin, Host};
use ethcore_rpc::is_major_importing;
use hash_fetch::urlhint::ContractClient;
use parity_reactor; use parity_reactor;
use rpc_apis; use rpc_apis;
pub use ethcore_dapps::Server as WebappServer; pub use ethcore_dapps::Server as WebappServer;
pub fn setup_dapps_server( pub fn setup_dapps_server<D: rpc_apis::Dependencies>(
deps: Dependencies, deps: Dependencies<D>,
dapps_path: PathBuf, dapps_path: PathBuf,
extra_dapps: Vec<PathBuf>, extra_dapps: Vec<PathBuf>,
url: &SocketAddr, url: &SocketAddr,
@ -157,18 +193,16 @@ mod server {
let server = dapps::ServerBuilder::new( let server = dapps::ServerBuilder::new(
&dapps_path, &dapps_path,
Arc::new(Registrar { client: deps.client.clone() }), deps.contract_client,
parity_reactor::Remote::new(deps.remote.clone()), parity_reactor::Remote::new(deps.remote.clone()),
); );
let allowed_hosts: Option<Vec<_>> = allowed_hosts.map(|hosts| hosts.into_iter().map(Host::from).collect()); let allowed_hosts: Option<Vec<_>> = allowed_hosts.map(|hosts| hosts.into_iter().map(Host::from).collect());
let cors: Option<Vec<_>> = cors.map(|cors| cors.into_iter().map(AccessControlAllowOrigin::from).collect()); let cors: Option<Vec<_>> = cors.map(|cors| cors.into_iter().map(AccessControlAllowOrigin::from).collect());
let sync = deps.sync.clone();
let client = deps.client.clone();
let signer = deps.signer.clone(); let signer = deps.signer.clone();
let server = server let server = server
.fetch(deps.fetch.clone()) .fetch(deps.fetch.clone())
.sync_status(Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info()))) .sync_status(deps.sync_status)
.web_proxy_tokens(Arc::new(move |token| signer.is_valid_web_proxy_access_token(&token))) .web_proxy_tokens(Arc::new(move |token| signer.is_valid_web_proxy_access_token(&token)))
.extra_dapps(&extra_dapps) .extra_dapps(&extra_dapps)
.signer_address(deps.signer.address()) .signer_address(deps.signer.address())
@ -201,36 +235,4 @@ mod server {
Ok(server) => Ok(server), Ok(server) => Ok(server),
} }
} }
struct Registrar {
client: Arc<Client>,
}
impl ContractClient for Registrar {
fn registrar(&self) -> Result<Address, String> {
self.client.additional_params().get("registrar")
.ok_or_else(|| "Registrar not defined.".into())
.and_then(|registrar| {
registrar.parse().map_err(|e| format!("Invalid registrar address: {:?}", e))
})
}
fn call(&self, address: Address, data: Bytes) -> Result<Bytes, String> {
let from = Address::default();
let transaction = Transaction {
nonce: self.client.latest_nonce(&from),
action: Action::Call(address),
gas: U256::from(50_000_000),
gas_price: U256::default(),
value: U256::default(),
data: data,
}.fake_sign(from);
self.client.call(&transaction, BlockId::Latest, Default::default())
.map_err(|e| format!("{:?}", e))
.map(|executed| {
executed.output
})
}
}
} }

View File

@ -291,7 +291,6 @@ pub struct LightDependencies {
pub on_demand: Arc<::light::on_demand::OnDemand>, pub on_demand: Arc<::light::on_demand::OnDemand>,
pub cache: Arc<Mutex<LightDataCache>>, pub cache: Arc<Mutex<LightDataCache>>,
pub transaction_queue: Arc<RwLock<LightTransactionQueue>>, pub transaction_queue: Arc<RwLock<LightTransactionQueue>>,
pub updater: Arc<Updater>,
pub dapps_interface: Option<String>, pub dapps_interface: Option<String>,
pub dapps_port: Option<u16>, pub dapps_port: Option<u16>,
pub fetch: FetchClient, pub fetch: FetchClient,

View File

@ -30,6 +30,7 @@ use ethcore::account_provider::{AccountProvider, AccountProviderSettings};
use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions}; use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions};
use ethcore::snapshot; use ethcore::snapshot;
use ethcore::verification::queue::VerifierSettings; use ethcore::verification::queue::VerifierSettings;
use light::Cache as LightDataCache;
use ethsync::SyncConfig; use ethsync::SyncConfig;
use informant::Informant; use informant::Informant;
use updater::{UpdatePolicy, Updater}; use updater::{UpdatePolicy, Updater};
@ -61,6 +62,10 @@ const SNAPSHOT_PERIOD: u64 = 10000;
// how many blocks to wait before starting a periodic snapshot. // how many blocks to wait before starting a periodic snapshot.
const SNAPSHOT_HISTORY: u64 = 100; const SNAPSHOT_HISTORY: u64 = 100;
// Number of minutes before a given gas price corpus should expire.
// Light client only.
const GAS_CORPUS_EXPIRATION_MINUTES: i64 = 60 * 6;
// Pops along with error messages when a password is missing or invalid. // 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."; const VERIFY_PASSWORD_HINT: &'static str = "Make sure valid password is present in files passed using `--password` or in the configuration file.";
@ -155,7 +160,7 @@ impl ::local_store::NodeInfo for FullNodeInfo {
} }
// helper for light execution. // helper for light execution.
fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> { fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> Result<(bool, Option<String>), String> {
use light::client as light_client; use light::client as light_client;
use ethsync::{LightSyncParams, LightSync, ManageNetwork}; use ethsync::{LightSyncParams, LightSync, ManageNetwork};
use util::RwLock; use util::RwLock;
@ -206,7 +211,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc<RotatingLogger>) -
let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm)) let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm))
.map_err(|e| format!("Error starting light client: {}", e))?; .map_err(|e| format!("Error starting light client: {}", e))?;
let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default())); let txq = Arc::new(RwLock::new(::light::transaction_queue::TransactionQueue::default()));
let provider = ::light::provider::LightProvider::new(service.client().clone(), txq); let provider = ::light::provider::LightProvider::new(service.client().clone(), txq.clone());
// start network. // start network.
// set up bootnodes // set up bootnodes
@ -215,6 +220,13 @@ fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc<RotatingLogger>) -
net_conf.boot_nodes = spec.nodes.clone(); net_conf.boot_nodes = spec.nodes.clone();
} }
// TODO: configurable cache size.
let cache = LightDataCache::new(Default::default(), ::time::Duration::minutes(GAS_CORPUS_EXPIRATION_MINUTES));
let cache = Arc::new(::util::Mutex::new(cache));
// start on_demand service.
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone()));
// set network path. // set network path.
net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned());
let sync_params = LightSyncParams { let sync_params = LightSyncParams {
@ -222,16 +234,70 @@ fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc<RotatingLogger>) -
client: Arc::new(provider), client: Arc::new(provider),
network_id: cmd.network_id.unwrap_or(spec.network_id()), network_id: cmd.network_id.unwrap_or(spec.network_id()),
subprotocol_name: ::ethsync::LIGHT_PROTOCOL, subprotocol_name: ::ethsync::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 = LightSync::new(sync_params).map_err(|e| format!("Error starting network: {}", e))?;
let light_sync = Arc::new(light_sync);
light_sync.start_network(); light_sync.start_network();
// start RPCs. // start RPCs.
// spin up event loop
let event_loop = EventLoop::spawn();
// fetch service
let fetch = FetchClient::new().map_err(|e| format!("Error starting fetch client: {:?}", e))?;
let passwords = passwords_from_files(&cmd.acc_conf.password_files)?; let passwords = passwords_from_files(&cmd.acc_conf.password_files)?;
// prepare account provider // prepare account provider
let _account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?); let account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?);
// rest TODO let rpc_stats = Arc::new(informant::RpcStats::default());
let signer_path = cmd.signer_conf.signer_path.clone();
let deps_for_rpc_apis = Arc::new(rpc_apis::LightDependencies {
signer_service: Arc::new(rpc_apis::SignerService::new(move || {
signer::generate_new_token(signer_path.clone()).map_err(|e| format!("{:?}", e))
}, cmd.ui_address)),
client: service.client().clone(),
sync: light_sync.clone(),
net: light_sync.clone(),
secret_store: account_provider,
logger: logger,
settings: Arc::new(cmd.net_settings),
on_demand: on_demand,
cache: cache,
transaction_queue: txq,
dapps_interface: match cmd.dapps_conf.enabled {
true => Some(cmd.dapps_conf.interface.clone()),
false => None,
},
dapps_port: match cmd.dapps_conf.enabled {
true => Some(cmd.dapps_conf.port),
false => None,
},
fetch: fetch,
geth_compatibility: cmd.geth_compatibility,
});
let dependencies = rpc::Dependencies {
apis: deps_for_rpc_apis.clone(),
remote: event_loop.raw_remote(),
stats: rpc_stats.clone(),
};
// start rpc servers
let _http_server = rpc::new_http(cmd.http_conf, &dependencies)?;
let _ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
// the signer server
let signer_deps = signer::Dependencies {
apis: deps_for_rpc_apis.clone(),
remote: event_loop.raw_remote(),
rpc_stats: rpc_stats.clone(),
};
let signing_queue = deps_for_rpc_apis.signer_service.queue();
let _signer_server = signer::start(cmd.signer_conf.clone(), signing_queue, signer_deps)?;
// TODO: Dapps
// wait for ctrl-c. // wait for ctrl-c.
Ok(wait_for_exit(panic_handler, None, None, can_restart)) Ok(wait_for_exit(panic_handler, None, None, can_restart))
@ -536,14 +602,19 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) -> R
let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?;
// the dapps server // the dapps server
let dapps_deps = dapps::Dependencies { let dapps_deps = {
apis: deps_for_rpc_apis.clone(), let (sync, client) = (sync_provider.clone(), client.clone());
client: client.clone(), let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() });
sync: sync_provider.clone(),
remote: event_loop.raw_remote(), dapps::Dependencies {
fetch: fetch.clone(), apis: deps_for_rpc_apis.clone(),
signer: deps_for_rpc_apis.signer_service.clone(), sync_status: Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())),
stats: rpc_stats.clone(), contract_client: contract_client,
remote: event_loop.raw_remote(),
fetch: fetch.clone(),
signer: deps_for_rpc_apis.signer_service.clone(),
stats: rpc_stats.clone(),
}
}; };
let dapps_server = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?; let dapps_server = dapps::new(cmd.dapps_conf.clone(), dapps_deps)?;

View File

@ -662,6 +662,8 @@ pub struct LightSyncParams<L> {
pub network_id: u64, pub network_id: u64,
/// Subprotocol name. /// Subprotocol name.
pub subprotocol_name: [u8; 3], pub subprotocol_name: [u8; 3],
/// Other handlers to attach.
pub handlers: Vec<Arc<LightHandler>>,
} }
/// Service for light synchronization. /// Service for light synchronization.
@ -696,6 +698,10 @@ impl LightSync {
let sync_handler = try!(SyncHandler::new(params.client.clone())); let sync_handler = try!(SyncHandler::new(params.client.clone()));
light_proto.add_handler(Arc::new(sync_handler)); light_proto.add_handler(Arc::new(sync_handler));
for handler in params.handlers {
light_proto.add_handler(handler);
}
Arc::new(light_proto) Arc::new(light_proto)
}; };