diff --git a/parity/dapps.rs b/parity/dapps.rs index 29268e904..970f51b96 100644 --- a/parity/dapps.rs +++ b/parity/dapps.rs @@ -18,13 +18,15 @@ use std::path::PathBuf; use std::sync::Arc; 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 ethsync::SyncProvider; use hash_fetch::fetch::Client as FetchClient; +use hash_fetch::urlhint::ContractClient; use helpers::replace_home; use rpc_apis::{self, SignerService}; use parity_reactor; +use util::{Bytes, Address, U256}; #[derive(Debug, PartialEq, Clone)] pub struct Configuration { @@ -58,17 +60,56 @@ impl Default for Configuration { } } -pub struct Dependencies { - pub apis: Arc, +/// Registrar implementation of the full client. +pub struct FullRegistrar { + /// Handle to the full client. pub client: Arc, - pub sync: Arc, +} + +impl ContractClient for FullRegistrar { + fn registrar(&self) -> Result { + 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 { + 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 { + pub apis: Arc, + pub sync_status: Arc<::ethcore_dapps::SyncStatus>, + pub contract_client: Arc, pub remote: parity_reactor::TokioRemote, pub fetch: FetchClient, pub signer: Arc, pub stats: Arc, } -pub fn new(configuration: Configuration, deps: Dependencies) -> Result, String> { +pub fn new(configuration: Configuration, deps: Dependencies) -> Result, String> + where D: rpc_apis::Dependencies +{ if !configuration.enabled { return Ok(None); } @@ -130,21 +171,16 @@ mod server { use std::sync::Arc; use std::net::SocketAddr; use std::io; - use util::{Bytes, Address, U256}; use ansi_term::Colour; - use ethcore::transaction::{Transaction, Action}; - use ethcore::client::{Client, BlockChainClient, BlockId}; use ethcore_dapps::{AccessControlAllowOrigin, Host}; - use ethcore_rpc::is_major_importing; - use hash_fetch::urlhint::ContractClient; use parity_reactor; use rpc_apis; pub use ethcore_dapps::Server as WebappServer; - pub fn setup_dapps_server( - deps: Dependencies, + pub fn setup_dapps_server( + deps: Dependencies, dapps_path: PathBuf, extra_dapps: Vec, url: &SocketAddr, @@ -157,18 +193,16 @@ mod server { let server = dapps::ServerBuilder::new( &dapps_path, - Arc::new(Registrar { client: deps.client.clone() }), + deps.contract_client, parity_reactor::Remote::new(deps.remote.clone()), ); let allowed_hosts: Option> = allowed_hosts.map(|hosts| hosts.into_iter().map(Host::from).collect()); let cors: Option> = 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 server = server .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))) .extra_dapps(&extra_dapps) .signer_address(deps.signer.address()) @@ -201,36 +235,4 @@ mod server { Ok(server) => Ok(server), } } - - struct Registrar { - client: Arc, - } - - impl ContractClient for Registrar { - fn registrar(&self) -> Result { - 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 { - 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 - }) - } - } } diff --git a/parity/rpc_apis.rs b/parity/rpc_apis.rs index 3f8f38a3a..6f5a0c5f8 100644 --- a/parity/rpc_apis.rs +++ b/parity/rpc_apis.rs @@ -291,7 +291,6 @@ pub struct LightDependencies { pub on_demand: Arc<::light::on_demand::OnDemand>, pub cache: Arc>, pub transaction_queue: Arc>, - pub updater: Arc, pub dapps_interface: Option, pub dapps_port: Option, pub fetch: FetchClient, diff --git a/parity/run.rs b/parity/run.rs index be4e25f97..74cae07fd 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -30,6 +30,7 @@ use ethcore::account_provider::{AccountProvider, AccountProviderSettings}; use ethcore::miner::{Miner, MinerService, ExternalMiner, MinerOptions}; use ethcore::snapshot; use ethcore::verification::queue::VerifierSettings; +use light::Cache as LightDataCache; use ethsync::SyncConfig; use informant::Informant; use updater::{UpdatePolicy, Updater}; @@ -61,6 +62,10 @@ const SNAPSHOT_PERIOD: u64 = 10000; // 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: i64 = 60 * 6; + // 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."; @@ -155,7 +160,7 @@ impl ::local_store::NodeInfo for FullNodeInfo { } // helper for light execution. -fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc) -> Result<(bool, Option), String> { +fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc) -> Result<(bool, Option), String> { use light::client as light_client; use ethsync::{LightSyncParams, LightSync, ManageNetwork}; use util::RwLock; @@ -206,7 +211,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc) - let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm)) .map_err(|e| format!("Error starting light client: {}", e))?; 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. // set up bootnodes @@ -215,6 +220,13 @@ fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc) - 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. net_conf.net_config_path = Some(db_dirs.network_path().to_string_lossy().into_owned()); let sync_params = LightSyncParams { @@ -222,16 +234,70 @@ fn execute_light(cmd: RunCmd, can_restart: bool, _logger: Arc) - client: Arc::new(provider), network_id: cmd.network_id.unwrap_or(spec.network_id()), 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 = Arc::new(light_sync); light_sync.start_network(); // 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)?; // prepare account provider - let _account_provider = Arc::new(prepare_account_provider(&cmd.spec, &cmd.dirs, &spec.data_dir, cmd.acc_conf, &passwords)?); - // rest TODO + 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()); + 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. Ok(wait_for_exit(panic_handler, None, None, can_restart)) @@ -536,14 +602,19 @@ pub fn execute(cmd: RunCmd, can_restart: bool, logger: Arc) -> R let ipc_server = rpc::new_ipc(cmd.ipc_conf, &dependencies)?; // the dapps server - let dapps_deps = dapps::Dependencies { - apis: deps_for_rpc_apis.clone(), - client: client.clone(), - sync: sync_provider.clone(), - remote: event_loop.raw_remote(), - fetch: fetch.clone(), - signer: deps_for_rpc_apis.signer_service.clone(), - stats: rpc_stats.clone(), + let dapps_deps = { + let (sync, client) = (sync_provider.clone(), client.clone()); + let contract_client = Arc::new(::dapps::FullRegistrar { client: client.clone() }); + + dapps::Dependencies { + apis: deps_for_rpc_apis.clone(), + sync_status: Arc::new(move || is_major_importing(Some(sync.status().state), client.queue_info())), + 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)?; diff --git a/sync/src/api.rs b/sync/src/api.rs index e6c093893..927d8fce6 100644 --- a/sync/src/api.rs +++ b/sync/src/api.rs @@ -662,6 +662,8 @@ pub struct LightSyncParams { pub network_id: u64, /// Subprotocol name. pub subprotocol_name: [u8; 3], + /// Other handlers to attach. + pub handlers: Vec>, } /// Service for light synchronization. @@ -696,6 +698,10 @@ impl LightSync { let sync_handler = try!(SyncHandler::new(params.client.clone())); light_proto.add_handler(Arc::new(sync_handler)); + for handler in params.handlers { + light_proto.add_handler(handler); + } + Arc::new(light_proto) };