diff --git a/ethcore/src/light/client.rs b/ethcore/src/light/client.rs index 7f061e3ab..ae882b1a8 100644 --- a/ethcore/src/light/client.rs +++ b/ethcore/src/light/client.rs @@ -27,18 +27,19 @@ use block_import_error::BlockImportError; use block_status::BlockStatus; use verification::queue::{Config as QueueConfig, HeaderQueue, QueueInfo, Status}; use transaction::SignedTransaction; +use types::blockchain_info::BlockChainInfo; use super::provider::{CHTProofRequest, Provider, ProofRequest}; use io::IoChannel; use util::hash::H256; -use util::Bytes; +use util::{Bytes, Mutex}; /// Light client implementation. pub struct Client { engine: Arc, header_queue: HeaderQueue, - message_channel: IoChannel, + message_channel: Mutex>, } impl Client { @@ -70,11 +71,12 @@ impl Client { } /// Get the chain info. - pub fn chain_info(&self) -> ChainInfo { - + pub fn chain_info(&self) -> BlockChainInfo { + unimplemented!() } } +// dummy implementation -- may draw from canonical cache further on. impl Provider for Client { fn block_headers(&self, block: H256, skip: usize, max: usize, reverse: bool) -> Vec { Vec::new() diff --git a/sync/src/light/mod.rs b/sync/src/light/mod.rs index fe60c30e5..4c32d52ae 100644 --- a/sync/src/light/mod.rs +++ b/sync/src/light/mod.rs @@ -29,6 +29,10 @@ use parking_lot::{Mutex, RwLock}; use std::collections::{HashMap, HashSet}; use std::sync::atomic::{AtomicUsize, Ordering}; +use self::request::Request; + +mod request; + const TIMEOUT: TimerToken = 0; const TIMEOUT_INTERVAL_MS: u64 = 1000; @@ -87,11 +91,9 @@ mod packet { pub const TRANSACTION_PROOFS: u8 = 0x13; } -struct Request; - struct Requested { timestamp: usize, - total: Request, + req: Request, } // data about each peer. @@ -172,7 +174,7 @@ impl Chain { unimplemented!() } - fn status(&self, peer: &PeerId, io: &NetworkContext) { + fn status(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) { unimplemented!() } @@ -205,6 +207,16 @@ impl Chain { unimplemented!() } + // Handle a request for receipts. + fn get_receipts(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) { + unimplemented!() + } + + // Receive a response for receipts. + fn receipts(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) { + unimplemented!() + } + // Handle a request for proofs. fn get_proofs(&self, peer: &PeerId, io: &NetworkContext, data: UntrustedRlp) { unimplemented!() @@ -284,7 +296,7 @@ impl NetworkProtocolHandler for Chain { packet::BLOCK_BODIES => self.block_bodies(peer, io, rlp), packet::GET_RECEIPTS => self.get_receipts(peer, io, rlp), - packet::RECEIPTS => self.receipt(peer, io, rlp), + packet::RECEIPTS => self.receipts(peer, io, rlp), packet::GET_PROOFS => self.get_proofs(peer, io, rlp), packet::PROOFS => self.proofs(peer, io, rlp), @@ -311,7 +323,7 @@ impl NetworkProtocolHandler for Chain { } fn disconnected(&self, io: &NetworkContext, peer: &PeerId) { - self.on_disconnect(peer, io); + self.on_disconnect(*peer, io); } fn timeout(&self, io: &NetworkContext, timer: TimerToken) { diff --git a/sync/src/light/request.rs b/sync/src/light/request.rs index 112cbcc42..bbb91e415 100644 --- a/sync/src/light/request.rs +++ b/sync/src/light/request.rs @@ -14,125 +14,152 @@ // You should have received a copy of the GNU General Public License // along with Parity. If not, see . -//! LES request types. +/// LES request types. -use util::bigint::prelude::*; -use rlp::*; +use ethcore::transaction::Transaction; +use util::{Address, H256}; -/// An LES request. This defines its data format, and the format of its response type. -pub trait Request: Sized { - /// The response type of this request. - type Response: Response; - - /// The error type when decoding a response. - type Error; - - /// Whether this request is empty. - fn is_empty(&self) -> bool; - - /// The remainder of this request unfulfilled by the response. Required to return - /// an equivalent request when provided with an empty response. - fn remainder(&self, res: &Self::Response) -> Self; - - /// Attempt to parse raw data into a response object - /// or an error. Behavior undefined if the raw data didn't originate from - /// this request. - fn parse_response(&self, raw: &[u8]) -> Result; +/// A request for block headers. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Headers { + /// Block information for the request being made. + pub block: (u64, H256), + /// The maximum amount of headers which can be returned. + pub max: u64, + /// The amount of headers to skip between each response entry. + pub skip: u64, + /// Whether the headers should proceed in falling number from the initial block. + pub reverse: bool, } -/// Request responses. These must have a combination operation used to fill the gaps -/// in one response with data from another. -pub trait Response: Sized { - /// Combine the two responses into one. This can only be relied on to behave correctly - /// if `other` is a response to a sub-request of the request this response was - /// produced from. - fn combine(&mut self, other: Self); +/// A request for specific block bodies. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Bodies { + /// Hashes which bodies are being requested for. + pub block_hashes: Vec } -/// A request for block bodies. -pub struct BlockBodies { - hashes: Vec, +/// A request for transaction receipts. +/// +/// This request is answered with a list of transaction receipts for each block +/// requested. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct Receipts { + /// Block hashes to return receipts for. + pub block_hashes: Vec, } -/// A response for block bodies. -pub struct BlockBodiesResponse { - bodies: Vec<(H256, Vec)>, +/// A request for state proofs. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct StateProofs { + /// Block hash to query state from. + pub block: H256, + /// Key of the state trie -- corresponds to account hash. + pub key1: H256, + /// Key in that account's storage trie; if empty, then the account RLP should be + /// returned. + pub key2: Option, + /// if greater than zero, trie nodes beyond this level may be omitted. + pub from_level: u32, // could even safely be u8; trie w/ 32-byte key can be at most 64-levels deep. } -impl Request for BlockBodies { - type Response = BlockBodiesResponse; - type Error = ::rlp::DecoderError; - - fn is_empty(&self) -> bool { self.hashes.is_empty() } - - fn remainder(&self, res: &Self::Response) -> Self { - let mut remaining = Vec::new(); - - let bodies = res.bodies.iter().map(|&(_, ref b) b).chain(::std::iter::repeat(&Vec::new())); - for (hash, body) in self.hashes.iter().zip(bodies) { - if body.is_empty() { - remaining.push(hash); - } - } - - BlockBodies { - hashes: remaining, - } - } - - fn parse_response(&self, raw: &[u8]) -> Result { - use ethcore::transaction::SignedTransaction; - use ethcore::header::Header; - - let rlp = UntrustedRlp::new(raw); - - let mut bodies = Vec::with_capacity(self.hashes.len()); - - let items = rlp.iter(); - for hash in self.hashes.iter().cloned() { - let res_bytes = match items.next() { - Some(rlp) => { - // perform basic block verification. - // TODO: custom error type? - try!(rlp.val_at::>(0) - .and_then(|_| rlp.val_at::>(1))); - - try!(rlp.data()).to_owned() - } - None => Vec::new(), - }; - - bodies.push((hash, res_bytes)); - } - - Ok(BlockBodiesResponse { - bodies: bodies, - }) - } +/// A request for contract code. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ContractCodes { + /// Block hash and account key (== sha3(address)) pairs to fetch code for. + pub code_requests: Vec<(H256, H256)>, } -impl Response for BlockBodiesResponse { - fn identity() -> Self { - BlockBodiesResponse { - bodies: Vec::new(), - } - } +/// A request for header proofs from the Canonical Hash Trie. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct HeaderProofs { + /// Number of the CHT. + pub cht_number: u64, + /// Block number requested. + pub block_number: u64, + /// If greater than zero, trie nodes beyond this level may be omitted. + pub from_level: u32, +} - fn combine(&mut self, other: Self) { - let other_iter = other.bodies.into_iter(); +/// A request for block deltas -- merkle proofs of all changed trie nodes and code. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct BlockDeltas { + /// Block hashes deltas are being requested for. + pub block_hashes: Vec, +} - 'a: - for &mut (ref my_hash, ref mut my_body) in self.bodies.iter_mut() { - loop { - match other_iter.next() { - Some((hash, body)) if hash == my_hash && !body.is_empty() => { - *my_body = body.to_owned(); - break - } - Some(_) => continue, - None => break 'a, - } - } +/// A request for a single transaction merkle proof. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TransactionProof { + /// The block hash to use the initial state from. + pub block_hash: H256, + /// The address to treat as the sender of the transaction. + pub sender: Address, + /// The raw transaction request itself. + pub transaction: Transaction, +} + +/// A request for transaction merkle proofs. +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct TransactionProofs { + /// Transaction proof requests. + pub tx_reqs: Vec, +} + +/// Kinds of requests. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Kind { + /// Requesting headers. + Headers, + /// Requesting block bodies. + Bodies, + /// Requesting transaction receipts. + Receipts, + /// Requesting proofs of state trie nodes. + StateProofs, + /// Requesting contract code by hash. + Codes, + /// Requesting header proofs (from the CHT). + HeaderProofs, + /// Requesting block deltas. + Deltas, + /// Requesting merkle proofs for transactions. + TransactionProofs, +} + +/// Encompasses all possible types of requests in a single structure. +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum Request { + /// Requesting headers. + Headers(Headers), + /// Requesting block bodies. + Bodies(Bodies), + /// Requesting transaction receipts. + Receipts(Receipts), + /// Requesting state proofs. + StateProofs(StateProofs), + /// Requesting contract codes. + Codes(ContractCodes), + /// Requesting header proofs. + HeaderProofs(HeaderProofs), + /// Requesting block deltas. + Deltas(BlockDeltas), + /// Requesting transaction proofs. + TransactionProofs(TransactionProofs), +} + +impl Request { + /// Get the kind of request this is. + pub fn kind(&self) -> Kind { + match *self { + Request::Headers(_) => Kind::Headers, + Request::Bodies(_) => Kind::Bodies, + Request::Receipts(_) => Kind::Receipts, + Request::StateProofs(_) => Kind::StateProofs, + Request::Codes(_) => Kind::Codes, + Request::HeaderProofs(_) => Kind::HeaderProofs, + Request::Deltas(_) => Kind::Deltas, + Request::TransactionProofs(_) => Kind::TransactionProofs, } } } \ No newline at end of file