generalize RequestBuilder
This commit is contained in:
parent
60ce0aee1a
commit
35740456a4
@ -20,7 +20,7 @@ use network::{NetworkContext, PeerId, NodeId};
|
||||
|
||||
use super::{Announcement, LightProtocol, ReqId};
|
||||
use super::error::Error;
|
||||
use request::Requests;
|
||||
use request::NetworkRequests as Requests;
|
||||
|
||||
/// An I/O context which allows sending and receiving packets as well as
|
||||
/// disconnecting peers. This is used as a generalization of the portions
|
||||
|
@ -33,7 +33,7 @@ use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
use provider::Provider;
|
||||
use request::{Request, Requests, Response};
|
||||
use request::{Request, NetworkRequests as Requests, Response};
|
||||
|
||||
use self::request_credits::{Credits, FlowParams};
|
||||
use self::context::{Ctx, TickCtx};
|
||||
|
@ -25,7 +25,7 @@ use std::collections::{BTreeMap, HashMap};
|
||||
use std::iter::FromIterator;
|
||||
|
||||
use request::Request;
|
||||
use request::Requests;
|
||||
use request::NetworkRequests as Requests;
|
||||
use net::{timeout, ReqId};
|
||||
use util::U256;
|
||||
|
||||
|
@ -39,14 +39,14 @@ use std::sync::Arc;
|
||||
|
||||
// helper for encoding a single request into a packet.
|
||||
// panics on bad backreference.
|
||||
fn encode_single(request: Request) -> Requests {
|
||||
fn encode_single(request: Request) -> NetworkRequests {
|
||||
let mut builder = RequestBuilder::default();
|
||||
builder.push(request).unwrap();
|
||||
builder.build()
|
||||
}
|
||||
|
||||
// helper for making a packet out of `Requests`.
|
||||
fn make_packet(req_id: usize, requests: &Requests) -> Vec<u8> {
|
||||
fn make_packet(req_id: usize, requests: &NetworkRequests) -> Vec<u8> {
|
||||
let mut stream = RlpStream::new_list(2);
|
||||
stream.append(&req_id).append_list(&requests.requests());
|
||||
stream.out()
|
||||
|
@ -562,7 +562,7 @@ mod tests {
|
||||
|
||||
use cache::Cache;
|
||||
use net::{Announcement, BasicContext, ReqId, Error as LesError};
|
||||
use request::Requests;
|
||||
use request::NetworkRequests;
|
||||
|
||||
use network::{PeerId, NodeId};
|
||||
use time::Duration;
|
||||
@ -572,7 +572,7 @@ mod tests {
|
||||
|
||||
impl BasicContext for FakeContext {
|
||||
fn persistent_peer_id(&self, _: PeerId) -> Option<NodeId> { None }
|
||||
fn request_from(&self, _: PeerId, _: Requests) -> Result<ReqId, LesError> {
|
||||
fn request_from(&self, _: PeerId, _: NetworkRequests) -> Result<ReqId, LesError> {
|
||||
unimplemented!()
|
||||
}
|
||||
fn make_announcement(&self, _: Announcement) { }
|
||||
|
@ -20,22 +20,30 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use request::{
|
||||
IncompleteRequest, CompleteRequest, Request,
|
||||
OutputKind, Output, NoSuchOutput, Response, ResponseError,
|
||||
IncompleteRequest, OutputKind, Output, NoSuchOutput, ResponseError, ResponseLike,
|
||||
};
|
||||
|
||||
/// Build chained requests. Push them onto the series with `push`,
|
||||
/// and produce a `Requests` object with `build`. Outputs are checked for consistency.
|
||||
#[derive(Debug, Default, Clone, PartialEq, Eq)]
|
||||
pub struct RequestBuilder {
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct RequestBuilder<T: IncompleteRequest> {
|
||||
output_kinds: HashMap<(usize, usize), OutputKind>,
|
||||
requests: Vec<Request>,
|
||||
requests: Vec<T>,
|
||||
}
|
||||
|
||||
impl RequestBuilder {
|
||||
impl<T: IncompleteRequest> Default for RequestBuilder<T> {
|
||||
fn default() -> Self {
|
||||
RequestBuilder {
|
||||
output_kinds: HashMap::new(),
|
||||
requests: Vec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: IncompleteRequest> RequestBuilder<T> {
|
||||
/// Attempt to push a request onto the request chain. Fails if the request
|
||||
/// references a non-existent output of a prior request.
|
||||
pub fn push(&mut self, request: Request) -> Result<(), NoSuchOutput> {
|
||||
pub fn push(&mut self, request: T) -> Result<(), NoSuchOutput> {
|
||||
request.check_outputs(|req, idx, kind| {
|
||||
match self.output_kinds.get(&(req, idx)) {
|
||||
Some(k) if k == &kind => Ok(()),
|
||||
@ -54,7 +62,7 @@ impl RequestBuilder {
|
||||
}
|
||||
|
||||
/// Convert this into a "requests" object.
|
||||
pub fn build(self) -> Requests {
|
||||
pub fn build(self) -> Requests<T> {
|
||||
Requests {
|
||||
outputs: HashMap::new(),
|
||||
requests: self.requests,
|
||||
@ -65,18 +73,18 @@ impl RequestBuilder {
|
||||
|
||||
/// Requests pending responses.
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct Requests {
|
||||
pub struct Requests<T: IncompleteRequest> {
|
||||
outputs: HashMap<(usize, usize), Output>,
|
||||
requests: Vec<Request>,
|
||||
requests: Vec<T>,
|
||||
answered: usize,
|
||||
}
|
||||
|
||||
impl Requests {
|
||||
/// For each request, produce responses for each.
|
||||
impl<T: IncompleteRequest + Clone> Requests<T> {
|
||||
/// For each request, produce a response.
|
||||
/// The responses vector produced goes up to the point where the responder
|
||||
/// first returns `None`, an invalid response, or until all requests have been responded to.
|
||||
pub fn respond_to_all<F>(mut self, responder: F) -> Vec<Response>
|
||||
where F: Fn(CompleteRequest) -> Option<Response>
|
||||
pub fn respond_to_all<F>(mut self, responder: F) -> Vec<T::Response>
|
||||
where F: Fn(T::Complete) -> Option<T::Response>
|
||||
{
|
||||
let mut responses = Vec::new();
|
||||
|
||||
@ -95,13 +103,13 @@ impl Requests {
|
||||
|
||||
/// Get access to the underlying slice of requests.
|
||||
// TODO: unimplemented -> Vec<Request>, // do we _have to_ allocate?
|
||||
pub fn requests(&self) -> &[Request] { &self.requests }
|
||||
pub fn requests(&self) -> &[T] { &self.requests }
|
||||
|
||||
/// Get the number of answered requests.
|
||||
pub fn num_answered(&self) -> usize { self.answered }
|
||||
|
||||
/// Get the next request as a filled request. Returns `None` when all requests answered.
|
||||
pub fn next_complete(&self) -> Option<CompleteRequest> {
|
||||
pub fn next_complete(&self) -> Option<T::Complete> {
|
||||
if self.answered == self.requests.len() {
|
||||
None
|
||||
} else {
|
||||
@ -113,12 +121,12 @@ impl Requests {
|
||||
|
||||
/// Supply a response for the next request.
|
||||
/// Fails on: wrong request kind, all requests answered already.
|
||||
pub fn supply_response(&mut self, response: &Response) -> Result<(), ResponseError> {
|
||||
pub fn supply_response(&mut self, response: &T::Response) -> Result<(), ResponseError> {
|
||||
let idx = self.answered;
|
||||
|
||||
// check validity.
|
||||
if idx == self.requests.len() { return Err(ResponseError::Unexpected) }
|
||||
if self.requests[idx].kind() != response.kind() { return Err(ResponseError::WrongKind) }
|
||||
if !self.requests[idx].check_response(&response) { return Err(ResponseError::WrongKind) }
|
||||
|
||||
let outputs = &mut self.outputs;
|
||||
response.fill_outputs(|out_idx, output| {
|
||||
|
@ -197,6 +197,9 @@ impl Encodable for HashOrNumber {
|
||||
}
|
||||
}
|
||||
|
||||
/// Type alias for "network requests".
|
||||
pub type NetworkRequests = Requests<Request>;
|
||||
|
||||
/// All request types, as they're sent over the network.
|
||||
/// They may be incomplete, with back-references to outputs
|
||||
/// of prior requests.
|
||||
@ -296,6 +299,7 @@ impl Encodable for Request {
|
||||
|
||||
impl IncompleteRequest for Request {
|
||||
type Complete = CompleteRequest;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -338,6 +342,10 @@ impl IncompleteRequest for Request {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_response(&self, response: &Response) -> bool {
|
||||
self.kind() == response.kind()
|
||||
}
|
||||
|
||||
fn complete(self) -> Result<Self::Complete, NoSuchOutput> {
|
||||
match self {
|
||||
Request::Headers(req) => req.complete().map(CompleteRequest::Headers),
|
||||
@ -421,9 +429,9 @@ pub enum Response {
|
||||
Execution(ExecutionResponse),
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl ResponseLike for Response {
|
||||
/// Fill reusable outputs by writing them into the function.
|
||||
pub fn fill_outputs<F>(&self, f: F) where F: FnMut(usize, Output) {
|
||||
fn fill_outputs<F>(&self, f: F) where F: FnMut(usize, Output) {
|
||||
match *self {
|
||||
Response::Headers(ref res) => res.fill_outputs(f),
|
||||
Response::HeaderProof(ref res) => res.fill_outputs(f),
|
||||
@ -435,7 +443,9 @@ impl Response {
|
||||
Response::Execution(ref res) => res.fill_outputs(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Response {
|
||||
/// Inspect the kind of this response.
|
||||
pub fn kind(&self) -> Kind {
|
||||
match *self {
|
||||
@ -490,6 +500,8 @@ impl Encodable for Response {
|
||||
pub trait IncompleteRequest: Sized {
|
||||
/// The complete variant of this request.
|
||||
type Complete;
|
||||
/// The response to this request.
|
||||
type Response: ResponseLike;
|
||||
|
||||
/// Check prior outputs against the needed inputs.
|
||||
///
|
||||
@ -508,11 +520,22 @@ pub trait IncompleteRequest: Sized {
|
||||
/// Only outputs previously checked with `check_outputs` may be available.
|
||||
fn fill<F>(&mut self, oracle: F) where F: Fn(usize, usize) -> Result<Output, NoSuchOutput>;
|
||||
|
||||
/// Check whether the response matches (beyond the type).
|
||||
fn check_response(&self, _response: &Self::Response) -> bool { true }
|
||||
|
||||
/// Attempt to convert this request into its complete variant.
|
||||
/// Will succeed if all fields have been filled, will fail otherwise.
|
||||
fn complete(self) -> Result<Self::Complete, NoSuchOutput>;
|
||||
}
|
||||
|
||||
/// A response-like object.
|
||||
///
|
||||
/// These contain re-usable outputs.
|
||||
pub trait ResponseLike {
|
||||
/// Write all re-usable outputs into the provided function.
|
||||
fn fill_outputs<F>(&self, output_store: F) where F: FnMut(usize, Output);
|
||||
}
|
||||
|
||||
/// Header request.
|
||||
pub mod header {
|
||||
use super::{Field, HashOrNumber, NoSuchOutput, OutputKind, Output};
|
||||
@ -555,6 +578,7 @@ pub mod header {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -608,9 +632,9 @@ pub mod header {
|
||||
pub headers: Vec<encoded::Header>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by writing them into the function.
|
||||
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) { }
|
||||
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) { }
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
@ -671,6 +695,7 @@ pub mod header_proof {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -719,9 +744,9 @@ pub mod header_proof {
|
||||
pub td: U256,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||
fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||
f(0, Output::Hash(self.hash));
|
||||
}
|
||||
}
|
||||
@ -776,6 +801,7 @@ pub mod block_receipts {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -818,9 +844,9 @@ pub mod block_receipts {
|
||||
pub receipts: Vec<Receipt>
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
@ -868,6 +894,7 @@ pub mod block_body {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -910,9 +937,9 @@ pub mod block_body {
|
||||
pub body: encoded::Body,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
@ -971,6 +998,7 @@ pub mod account {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -1039,9 +1067,9 @@ pub mod account {
|
||||
pub storage_root: H256,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||
fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||
f(0, Output::Hash(self.code_hash));
|
||||
f(1, Output::Hash(self.storage_root));
|
||||
}
|
||||
@ -1109,6 +1137,7 @@ pub mod storage {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -1184,9 +1213,9 @@ pub mod storage {
|
||||
pub value: H256,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||
fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||
f(0, Output::Hash(self.value));
|
||||
}
|
||||
}
|
||||
@ -1243,6 +1272,7 @@ pub mod contract_code {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -1299,9 +1329,9 @@ pub mod contract_code {
|
||||
pub code: Bytes,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
@ -1380,6 +1410,7 @@ pub mod execution {
|
||||
|
||||
impl super::IncompleteRequest for Incomplete {
|
||||
type Complete = Complete;
|
||||
type Response = Response;
|
||||
|
||||
fn check_outputs<F>(&self, mut f: F) -> Result<(), NoSuchOutput>
|
||||
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||
@ -1440,9 +1471,9 @@ pub mod execution {
|
||||
pub items: Vec<DBValue>,
|
||||
}
|
||||
|
||||
impl Response {
|
||||
impl super::ResponseLike for Response {
|
||||
/// Fill reusable outputs by providing them to the function.
|
||||
pub fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
fn fill_outputs<F>(&self, _: F) where F: FnMut(usize, Output) {}
|
||||
}
|
||||
|
||||
impl Decodable for Response {
|
||||
|
Loading…
Reference in New Issue
Block a user