diff --git a/ethcore/light/src/client/fetch.rs b/ethcore/light/src/client/fetch.rs
new file mode 100644
index 000000000..0f11ef2f4
--- /dev/null
+++ b/ethcore/light/src/client/fetch.rs
@@ -0,0 +1,69 @@
+// 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 .
+
+//! Trait for fetching chain data.
+
+use ethcore::header::Header;
+use ethcore::receipt::Receipt;
+use futures::future::IntoFuture;
+
+/// Provides full chain data.
+pub trait ChainDataFetcher: Send + Sync + 'static {
+ /// Error type when data unavailable.
+ type Error: ::std::fmt::Debug;
+
+ /// Future for fetching block body.
+ type Body: IntoFuture- ,Error=Self::Error>;
+ /// Future for fetching block receipts.
+ type Receipts: IntoFuture
- ,Error=Self::Error>;
+ /// Future for fetching epoch transition
+ type Transition: IntoFuture
- ,Error=Self::Error>;
+
+ /// Fetch a block body.
+ fn block_body(&self, header: &Header) -> Self::Body;
+
+ /// Fetch block receipts.
+ fn block_receipts(&self, header: &Header) -> Self::Receipts;
+
+ /// Fetch epoch transition proof at given header.
+ fn epoch_transition(&self, header: &Header) -> Self::Transition;
+}
+
+/// Fetcher implementation which cannot fetch anything.
+pub struct Unavailable;
+
+/// Create a fetcher which has all data unavailable.
+pub fn unavailable() -> Unavailable { Unavailable }
+
+impl ChainDataFetcher for Unavailable {
+ type Error = &'static str;
+
+ type Body = Result, &'static str>;
+ type Receipts = Result, &'static str>;
+ type Transition = Result, &'static str>;
+
+ fn block_body(&self, _header: &Header) -> Self::Body {
+ Err("fetching block bodies unavailable")
+ }
+
+ fn block_receipts(&self, _header: &Header) -> Self::Receipts {
+ Err("fetching block receipts unavailable")
+ }
+
+ fn epoch_transition(&self, _header: &Header) -> Self::Body {
+ Err("fetching epoch transition proofs unavailable")
+ }
+}
diff --git a/ethcore/light/src/client/mod.rs b/ethcore/light/src/client/mod.rs
index 3f0e50584..b3d2dff4f 100644
--- a/ethcore/light/src/client/mod.rs
+++ b/ethcore/light/src/client/mod.rs
@@ -20,7 +20,7 @@ use std::sync::{Weak, Arc};
use ethcore::block_status::BlockStatus;
use ethcore::client::{ClientReport, EnvInfo};
-use ethcore::engines::Engine;
+use ethcore::engines::{Engine, EpochChange, Proof, Unsure};
use ethcore::error::BlockImportError;
use ethcore::ids::BlockId;
use ethcore::header::Header;
@@ -31,9 +31,12 @@ use ethcore::service::ClientIoMessage;
use ethcore::encoded;
use io::IoChannel;
+use futures::{IntoFuture, Future};
+
use util::{H256, U256, Mutex, RwLock};
use util::kvdb::{KeyValueDB, CompactionProfile};
+use self::fetch::ChainDataFetcher;
use self::header_chain::{AncestryIter, HeaderChain};
use cache::Cache;
@@ -43,6 +46,8 @@ pub use self::service::Service;
mod header_chain;
mod service;
+pub mod fetch;
+
/// Configuration for the light client.
#[derive(Debug, Clone)]
pub struct Config {
@@ -154,7 +159,7 @@ impl AsLightClient for T {
}
/// Light client implementation.
-pub struct Client {
+pub struct Client {
queue: HeaderQueue,
engine: Arc,
chain: HeaderChain,
@@ -162,12 +167,21 @@ pub struct Client {
import_lock: Mutex<()>,
db: Arc,
listeners: RwLock>>,
+ fetcher: T,
verify_full: bool,
}
-impl Client {
+impl Client {
/// Create a new `Client`.
- pub fn new(config: Config, db: Arc, chain_col: Option, spec: &Spec, io_channel: IoChannel, cache: Arc>) -> Result {
+ pub fn new(
+ config: Config,
+ db: Arc,
+ chain_col: Option,
+ spec: &Spec,
+ fetcher: T,
+ io_channel: IoChannel,
+ cache: Arc>
+ ) -> Result {
let gh = ::rlp::encode(&spec.genesis_header());
Ok(Client {
@@ -178,6 +192,7 @@ impl Client {
import_lock: Mutex::new(()),
db: db,
listeners: RwLock::new(vec![]),
+ fetcher: fetcher,
verify_full: config.verify_full,
})
}
@@ -189,10 +204,24 @@ impl Client {
/// Create a new `Client` backed purely in-memory.
/// This will ignore all database options in the configuration.
- pub fn in_memory(config: Config, spec: &Spec, io_channel: IoChannel, cache: Arc>) -> Self {
+ pub fn in_memory(
+ config: Config,
+ spec: &Spec,
+ fetcher: T,
+ io_channel: IoChannel,
+ cache: Arc>
+ ) -> Self {
let db = ::util::kvdb::in_memory(0);
- Client::new(config, Arc::new(db), None, spec, io_channel, cache).expect("New DB creation infallible; qed")
+ Client::new(
+ config,
+ Arc::new(db),
+ None,
+ spec,
+ fetcher,
+ io_channel,
+ cache
+ ).expect("New DB creation infallible; qed")
}
/// Import a header to the queue for additional verification.
@@ -291,9 +320,14 @@ impl Client {
continue
}
- // TODO: `epoch_end_signal`, `is_epoch_end`.
- // proofs we get from the network would be _complete_, whereas we need
- // _incomplete_ signals
+ let _write_proof_result = match self.check_epoch_signal(&verified_header) {
+ Ok(Some(proof)) => self.write_pending_proof(&verified_header, proof),
+ Ok(None) => Ok(()),
+ Err(e) =>
+ panic!("Unable to fetch epoch transition proof: {:?}", e),
+ };
+
+ // TODO: check epoch end.
let mut tx = self.db.transaction();
let pending = match self.chain.insert(&mut tx, verified_header) {
@@ -419,9 +453,71 @@ impl Client {
true
}
+
+ fn check_epoch_signal(&self, verified_header: &Header) -> Result