diff --git a/ethcore/light/src/on_demand/request.rs b/ethcore/light/src/on_demand/request.rs index 4039c2cb3..8f4be1632 100644 --- a/ethcore/light/src/on_demand/request.rs +++ b/ethcore/light/src/on_demand/request.rs @@ -354,23 +354,32 @@ impl net_request::CheckedRequest for CheckedRequest { fn check_response(&self, cache: &Mutex<::cache::Cache>, response: &Self::Response) -> Result { use ::request::Response as NetResponse; + // helper for expecting a specific response for a given request. + macro_rules! expect { + ($res: pat => $e: expr) => { + match *response { + $res => $e, + _ => Err(Error::WrongKind), + } + } + } + // check response against contained prover. - match (self, response) { - (&CheckedRequest::HeaderProof(ref prover, _), &NetResponse::HeaderProof(ref res)) => - prover.check_response(cache, &res.proof).map(Response::HeaderProof), - (&CheckedRequest::HeaderByHash(ref prover, _), &NetResponse::Headers(ref res)) => - prover.check_response(cache, &res.headers).map(Response::HeaderByHash), - (&CheckedRequest::Receipts(ref prover, _), &NetResponse::Receipts(ref res)) => - prover.check_response(cache, &res.receipts).map(Response::Receipts), - (&CheckedRequest::Body(ref prover, _), &NetResponse::Body(ref res)) => - prover.check_response(cache, &res.body).map(Response::Body), - (&CheckedRequest::Account(ref prover, _), &NetResponse::Account(ref res)) => - prover.check_response(cache, &res.proof).map(Response::Account), - (&CheckedRequest::Code(ref prover, _), &NetResponse::Code(ref res)) => - prover.check_response(cache, &res.code).map(Response::Code), - (&CheckedRequest::Execution(ref prover, _), &NetResponse::Execution(ref res)) => - prover.check_response(cache, &res.items).map(Response::Execution), - _ => Err(Error::WrongKind), + match *self { + CheckedRequest::HeaderProof(ref prover, _) => expect!(NetResponse::HeaderProof(ref res) => + prover.check_response(cache, &res.proof).map(Response::HeaderProof)), + CheckedRequest::HeaderByHash(ref prover, _) => expect!(NetResponse::Headers(ref res) => + prover.check_response(cache, &res.headers).map(Response::HeaderByHash)), + CheckedRequest::Receipts(ref prover, _) => expect!(NetResponse::Receipts(ref res) => + prover.check_response(cache, &res.receipts).map(Response::Receipts)), + CheckedRequest::Body(ref prover, _) => expect!(NetResponse::Body(ref res) => + prover.check_response(cache, &res.body).map(Response::Body)), + CheckedRequest::Account(ref prover, _) => expect!(NetResponse::Account(ref res) => + prover.check_response(cache, &res.proof).map(Response::Account)), + CheckedRequest::Code(ref prover, _) => expect!(NetResponse::Code(ref res) => + prover.check_response(cache, &res.code).map(Response::Code)), + CheckedRequest::Execution(ref prover, _) => expect!(NetResponse::Execution(ref res) => + prover.check_response(cache, &res.items).map(Response::Execution)), } } } diff --git a/ethcore/light/src/types/request/builder.rs b/ethcore/light/src/types/request/builder.rs index 3dfb9ff40..27875dc7b 100644 --- a/ethcore/light/src/types/request/builder.rs +++ b/ethcore/light/src/types/request/builder.rs @@ -26,12 +26,12 @@ use request::{ /// Build chained requests. Push them onto the series with `push`, /// and produce a `Requests` object with `build`. Outputs are checked for consistency. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct RequestBuilder { +pub struct RequestBuilder { output_kinds: HashMap<(usize, usize), OutputKind>, requests: Vec, } -impl Default for RequestBuilder { +impl Default for RequestBuilder { fn default() -> Self { RequestBuilder { output_kinds: HashMap::new(), @@ -73,13 +73,13 @@ impl RequestBuilder { /// Requests pending responses. #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Requests { +pub struct Requests { outputs: HashMap<(usize, usize), Output>, requests: Vec, answered: usize, } -impl Requests { +impl Requests { /// Get access to the underlying slice of requests. // TODO: unimplemented -> Vec, // do we _have to_ allocate? pub fn requests(&self) -> &[T] { &self.requests } @@ -92,17 +92,6 @@ impl Requests { self.answered == self.requests.len() } - /// Get the next request as a filled request. Returns `None` when all requests answered. - pub fn next_complete(&self) -> Option { - if self.is_complete() { - None - } else { - Some(self.requests[self.answered].clone() - .complete() - .expect("All outputs checked as invariant of `Requests` object; qed")) - } - } - /// Map requests from one type into another. pub fn map_requests(self, f: F) -> Requests where F: FnMut(T) -> U, U: IncompleteRequest @@ -115,6 +104,19 @@ impl Requests { } } +impl Requests { + /// Get the next request as a filled request. Returns `None` when all requests answered. + pub fn next_complete(&self) -> Option { + if self.is_complete() { + None + } else { + Some(self.requests[self.answered].clone() + .complete() + .expect("All outputs checked as invariant of `Requests` object; qed")) + } + } +} + impl Requests { /// Supply a response for the next request. /// Fails on: wrong request kind, all requests answered already. @@ -124,7 +126,8 @@ impl Requests { let idx = self.answered; // check validity. - if idx == self.requests.len() { return Err(ResponseError::Unexpected) } + if self.is_complete() { return Err(ResponseError::Unexpected) } + let extracted = self.requests[idx] .check_response(env, response).map_err(ResponseError::Validity)?; diff --git a/rpc/src/v1/impls/light/eth.rs b/rpc/src/v1/impls/light/eth.rs index 37ae164ad..e02ccc987 100644 --- a/rpc/src/v1/impls/light/eth.rs +++ b/rpc/src/v1/impls/light/eth.rs @@ -185,7 +185,7 @@ impl EthClient { // three possible outcomes: // - network is down. // - we get a score, but our hash is non-canonical. - // - we get ascore, and our hash is canonical. + // - we get a score, and our hash is canonical. let maybe_fut = sync.with_context(move |ctx| on_demand.hash_and_score_by_number(ctx, req)); match maybe_fut { Some(fut) => fut.map(move |(hash, score)| {