// Copyright 2015-2018 Parity Technologies (UK) Ltd. // This file is part of Parity. // Parity is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // Parity is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with Parity. If not, see . //! Minimal IO service for light client. //! Just handles block import messages and passes them to the client. use std::fmt; use std::sync::Arc; use ethcore::client::ClientIoMessage; use ethcore::{db, BlockChainDB}; use ethcore::error::Error as CoreError; use ethcore::spec::Spec; use io::{IoContext, IoError, IoHandler, IoService}; use cache::Cache; use parking_lot::Mutex; use super::{ChainDataFetcher, LightChainNotify, Client, Config as ClientConfig}; /// Errors on service initialization. #[derive(Debug)] pub enum Error { /// Core error. Core(CoreError), /// I/O service error. Io(IoError), } impl From for Error { #[inline] fn from(err: CoreError) -> Error { Error::Core(err) } } impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { Error::Core(ref msg) => write!(f, "Core error: {}", msg), Error::Io(ref err) => write!(f, "I/O service error: {}", err), } } } /// Light client service. pub struct Service { client: Arc>, io_service: IoService, } impl Service { /// Start the service: initialize I/O workers and client itself. pub fn start(config: ClientConfig, spec: &Spec, fetcher: T, db: Arc, cache: Arc>) -> Result { let io_service = IoService::::start().map_err(Error::Io)?; let client = Arc::new(Client::new(config, db.key_value().clone(), db::COL_LIGHT_CHAIN, spec, fetcher, io_service.channel(), cache, )?); io_service.register_handler(Arc::new(ImportBlocks(client.clone()))).map_err(Error::Io)?; spec.engine.register_client(Arc::downgrade(&client) as _); Ok(Service { client: client, io_service: io_service, }) } /// Set the actor to be notified on certain chain events pub fn add_notify(&self, notify: Arc) { self.client.add_listener(Arc::downgrade(¬ify)); } /// Register an I/O handler on the service. pub fn register_handler(&self, handler: Arc + Send>) -> Result<(), IoError> { self.io_service.register_handler(handler) } /// Get a handle to the client. pub fn client(&self) -> &Arc> { &self.client } } struct ImportBlocks(Arc>); impl IoHandler for ImportBlocks { fn message(&self, _io: &IoContext, message: &ClientIoMessage) { if let ClientIoMessage::BlockVerified = *message { self.0.import_verified(); } } } #[cfg(test)] mod tests { use super::Service; use ethcore::spec::Spec; use std::sync::Arc; use cache::Cache; use client::fetch; use std::time::Duration; use parking_lot::Mutex; use ethcore::test_helpers; #[test] fn it_works() { let db = test_helpers::new_db(); let spec = Spec::new_test(); let cache = Arc::new(Mutex::new(Cache::new(Default::default(), Duration::from_secs(6 * 3600)))); Service::start(Default::default(), &spec, fetch::unavailable(), db, cache).unwrap(); } }