glue for fetching epoch proofs from network

This commit is contained in:
Robert Habermeier
2017-08-24 15:17:48 +02:00
parent 871a9c063e
commit b953f9b66a
15 changed files with 168 additions and 38 deletions

View File

@@ -204,7 +204,9 @@ fn execute_import_light(cmd: ImportBlockchain) -> Result<(), String> {
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings;
let service = LightClientService::start(config, &spec, &client_path, cache)
// TODO: could epoch signals be avilable at the end of the file?
let fetch = ::light::client::fetch::unavailable();
let service = LightClientService::start(config, &spec, fetch, &client_path, cache)
.map_err(|e| format!("Failed to start client: {}", e))?;
// free up the spec in memory.

View File

@@ -26,7 +26,7 @@ use futures_cpupool::CpuPool;
use hash_fetch::fetch::Client as FetchClient;
use hash_fetch::urlhint::ContractClient;
use helpers::replace_home;
use light::client::Client as LightClient;
use light::client::LightChainClient;
use light::on_demand::{self, OnDemand};
use rpc;
use rpc_apis::SignerService;
@@ -94,16 +94,16 @@ impl ContractClient for FullRegistrar {
}
/// Registrar implementation for the light client.
pub struct LightRegistrar {
pub struct LightRegistrar<T> {
/// The light client.
pub client: Arc<LightClient>,
pub client: Arc<T>,
/// Handle to the on-demand service.
pub on_demand: Arc<OnDemand>,
/// Handle to the light network service.
pub sync: Arc<LightSync>,
}
impl ContractClient for LightRegistrar {
impl<T: LightChainClient + 'static> ContractClient for LightRegistrar<T> {
fn registrar(&self) -> Result<Address, String> {
self.client.engine().additional_params().get("registrar")
.ok_or_else(|| "Registrar not defined.".into())
@@ -113,7 +113,14 @@ impl ContractClient for LightRegistrar {
}
fn call(&self, address: Address, data: Bytes) -> BoxFuture<Bytes, String> {
let (header, env_info) = (self.client.best_block_header(), self.client.latest_env_info());
let header = self.client.best_block_header();
let env_info = self.client.env_info(BlockId::Hash(header.hash()))
.ok_or_else(|| format!("Cannot fetch env info for header {}", header.hash()));
let env_info = match env_info {
Ok(x) => x,
Err(e) => return future::err(e).boxed(),
};
let maybe_future = self.sync.with_context(move |ctx| {
self.on_demand

View File

@@ -22,7 +22,7 @@ use std::sync::{Arc};
use std::sync::atomic::{AtomicUsize, AtomicBool, Ordering as AtomicOrdering};
use std::time::{Instant, Duration};
use ethcore::client::*;
use ethcore::client::{BlockId, BlockChainClient, BlockChainInfo, BlockQueueInfo, ChainNotify, ClientReport, Client};
use ethcore::header::BlockNumber;
use ethcore::service::ClientIoMessage;
use ethcore::snapshot::{RestorationStatus, SnapshotService as SS};

View File

@@ -0,0 +1,89 @@
// Copyright 2015-2017 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 <http://www.gnu.org/licenses/>.
use std::sync::{Arc, Weak};
use ethcore::encoded;
use ethcore::engines::{Engine, StateDependentProof};
use ethcore::header::Header;
use ethcore::receipt::Receipt;
use ethsync::LightSync;
use futures::{future, Future, BoxFuture};
use light::client::fetch::ChainDataFetcher;
use light::on_demand::{request, OnDemand};
use util::{RwLock, H256};
const ALL_VALID_BACKREFS: &str = "no back-references, therefore all back-references valid; qed";
/// 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
{
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) => x.map_err(|_| "Request canceled").boxed(),
None => future::err("Unable to access network.").boxed(),
}
}
None => future::err("Unable to access network").boxed(),
}
}
}
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<Engine>, checker: Arc<StateDependentProof>)
-> Self::Transition
{
self.request(request::Signal {
hash: hash,
engine: engine,
proof_check: checker,
})
}
}

View File

@@ -16,6 +16,8 @@
//! Utilities and helpers for the light client.
mod epoch_fetch;
mod queue_cull;
pub use self::epoch_fetch::EpochFetch;
pub use self::queue_cull::QueueCull;

View File

@@ -23,7 +23,7 @@ use ethcore::service::ClientIoMessage;
use ethsync::LightSync;
use io::{IoContext, IoHandler, TimerToken};
use light::client::Client;
use light::client::LightChainClient;
use light::on_demand::{request, OnDemand};
use light::TransactionQueue;
@@ -41,9 +41,9 @@ const TIMEOUT_MS: u64 = 1000 * 60 * 10;
const PURGE_TIMEOUT_MS: u64 = 1000 * 60 * 9;
/// Periodically culls the transaction queue of mined transactions.
pub struct QueueCull {
pub struct QueueCull<T> {
/// A handle to the client, for getting the latest block header.
pub client: Arc<Client>,
pub client: Arc<T>,
/// A handle to the sync service.
pub sync: Arc<LightSync>,
/// The on-demand request service.
@@ -54,7 +54,7 @@ pub struct QueueCull {
pub remote: Remote,
}
impl IoHandler<ClientIoMessage> for QueueCull {
impl<T: LightChainClient + 'static> IoHandler<ClientIoMessage> for QueueCull<T> {
fn initialize(&self, io: &IoContext<ClientIoMessage>) {
io.register_timer(TOKEN, TIMEOUT_MS).expect("Error registering timer");
}

View File

@@ -34,6 +34,7 @@ use ethsync::{ManageNetwork, SyncProvider, LightSync};
use hash_fetch::fetch::Client as FetchClient;
use jsonrpc_core::{self as core, MetaIoHandler};
use light::{TransactionQueue as LightTransactionQueue, Cache as LightDataCache};
use light::client::LightChainClient;
use updater::Updater;
use util::{Mutex, RwLock};
use ethcore_logger::RotatingLogger;
@@ -395,9 +396,9 @@ impl ActivityNotifier for LightClientNotifier {
}
/// RPC dependencies for a light client.
pub struct LightDependencies {
pub struct LightDependencies<T> {
pub signer_service: Arc<SignerService>,
pub client: Arc<::light::client::Client>,
pub client: Arc<T>,
pub sync: Arc<LightSync>,
pub net: Arc<ManageNetwork>,
pub secret_store: Arc<AccountProvider>,
@@ -415,7 +416,7 @@ pub struct LightDependencies {
pub whisper_rpc: Option<::whisper::RpcFactory>,
}
impl LightDependencies {
impl<C: LightChainClient + 'static> LightDependencies<C> {
fn extend_api<T: core::Middleware<Metadata>>(
&self,
handler: &mut MetaIoHandler<Metadata, T>,
@@ -563,7 +564,7 @@ impl LightDependencies {
}
}
impl Dependencies for LightDependencies {
impl<T: LightChainClient + 'static> Dependencies for LightDependencies<T> {
type Notifier = LightClientNotifier;
fn activity_notifier(&self) -> Self::Notifier { LightClientNotifier }

View File

@@ -14,7 +14,7 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::sync::Arc;
use std::sync::{Arc, Weak};
use std::net::{TcpListener};
use ctrlc::CtrlC;
@@ -217,7 +217,16 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
config.queue.max_mem_use = cmd.cache_config.queue() as usize * 1024 * 1024;
config.queue.verifier_settings = cmd.verifier_settings;
let service = light_client::Service::start(config, &spec, &db_dirs.client_path(algorithm), cache.clone())
// 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(),
};
let service = light_client::Service::start(config, &spec, fetch, &db_dirs.client_path(algorithm), cache.clone())
.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.clone());
@@ -229,9 +238,6 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
net_conf.boot_nodes = spec.nodes.clone();
}
// start on_demand service.
let on_demand = Arc::new(::light::on_demand::OnDemand::new(cache.clone()));
let mut attached_protos = Vec::new();
let whisper_factory = if cmd.whisper.enabled {
let (whisper_net, whisper_factory) = ::whisper::setup(cmd.whisper.target_message_pool_size)
@@ -255,6 +261,7 @@ fn execute_light(cmd: RunCmd, can_restart: bool, logger: Arc<RotatingLogger>) ->
};
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 event_loop = EventLoop::spawn();