checked request for OnDemand
This commit is contained in:
		
							parent
							
								
									35740456a4
								
							
						
					
					
						commit
						08d8709ef6
					
				@ -459,15 +459,13 @@ impl Handler for OnDemand {
 | 
			
		||||
			}
 | 
			
		||||
			Pending::HeaderByHash(req, sender) => {
 | 
			
		||||
				if let NetworkResponse::Headers(ref response) = *response {
 | 
			
		||||
					if let Some(header) = response.headers.get(0) {
 | 
			
		||||
						match req.check_response(header) {
 | 
			
		||||
							Ok(header) => {
 | 
			
		||||
								self.cache.lock().insert_block_header(req.0, header.clone());
 | 
			
		||||
								let _ = sender.send(header);
 | 
			
		||||
								return
 | 
			
		||||
							}
 | 
			
		||||
							Err(e) => warn!(target: "on_demand", "Error handling response for header request: {:?}", e),
 | 
			
		||||
					match req.check_response(&response.headers) {
 | 
			
		||||
						Ok(header) => {
 | 
			
		||||
							self.cache.lock().insert_block_header(req.0, header.clone());
 | 
			
		||||
							let _ = sender.send(header);
 | 
			
		||||
							return
 | 
			
		||||
						}
 | 
			
		||||
						Err(e) => warn!(target: "on_demand", "Error handling response for header request: {:?}", e),
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
@ -521,8 +519,8 @@ impl Handler for OnDemand {
 | 
			
		||||
			Pending::Code(req, sender) => {
 | 
			
		||||
				if let NetworkResponse::Code(ref response) = *response {
 | 
			
		||||
					match req.check_response(response.code.as_slice()) {
 | 
			
		||||
						Ok(()) => {
 | 
			
		||||
							let _ = sender.send(response.code.clone());
 | 
			
		||||
						Ok(code) => {
 | 
			
		||||
							let _ = sender.send(code);
 | 
			
		||||
							return
 | 
			
		||||
						}
 | 
			
		||||
						Err(e) => warn!(target: "on_demand", "Error handling response for code request: {:?}", e),
 | 
			
		||||
 | 
			
		||||
@ -26,17 +26,171 @@ use ethcore::receipt::Receipt;
 | 
			
		||||
use ethcore::state::{self, ProvedExecution};
 | 
			
		||||
use ethcore::transaction::SignedTransaction;
 | 
			
		||||
 | 
			
		||||
use request::{self as net_request, IncompleteRequest, Output, OutputKind};
 | 
			
		||||
 | 
			
		||||
use rlp::{RlpStream, UntrustedRlp};
 | 
			
		||||
use util::{Address, Bytes, DBValue, HashDB, H256, U256};
 | 
			
		||||
use util::memorydb::MemoryDB;
 | 
			
		||||
use util::sha3::Hashable;
 | 
			
		||||
use util::trie::{Trie, TrieDB, TrieError};
 | 
			
		||||
 | 
			
		||||
/// Core unit of the API: submit batches of these to be answered with `Response`s.
 | 
			
		||||
pub enum Request {
 | 
			
		||||
	/// A request for a header proof.
 | 
			
		||||
	HeaderProof(HeaderProof),
 | 
			
		||||
	/// A request for a header by hash.
 | 
			
		||||
	HeaderByHash(HeaderByHash),
 | 
			
		||||
	/// A request for block receipts.
 | 
			
		||||
	Receipts(BlockReceipts),
 | 
			
		||||
	/// A request for a block body.
 | 
			
		||||
	Body(Body),
 | 
			
		||||
	/// A request for an account.
 | 
			
		||||
	Account(Account),
 | 
			
		||||
	/// A request for a contract's code.
 | 
			
		||||
	Code(Code),
 | 
			
		||||
	/// A request for proof of execution.
 | 
			
		||||
	Execution(TransactionProof),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Requests coupled with their required data for verification.
 | 
			
		||||
/// This is used internally but not part of the public API.
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
#[allow(missing_docs)]
 | 
			
		||||
pub enum CheckedRequest {
 | 
			
		||||
	HeaderProof(HeaderProof, net_request::IncompleteHeaderProofRequest),
 | 
			
		||||
	HeaderByHash(HeaderByHash, net_request::IncompleteHeadersRequest),
 | 
			
		||||
	Receipts(BlockReceipts, net_request::IncompleteReceiptsRequest),
 | 
			
		||||
	Body(Body, net_request::IncompleteBodyRequest),
 | 
			
		||||
	Account(Account, net_request::IncompleteAccountRequest),
 | 
			
		||||
	Code(Code, net_request::IncompleteCodeRequest),
 | 
			
		||||
	Execution(TransactionProof, net_request::IncompleteExecutionRequest),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl IncompleteRequest for CheckedRequest {
 | 
			
		||||
	type Complete = net_request::CompleteRequest;
 | 
			
		||||
	type Response = net_request::Response;
 | 
			
		||||
 | 
			
		||||
	/// Check prior outputs against the needed inputs.
 | 
			
		||||
	///
 | 
			
		||||
	/// This is called to ensure consistency of this request with
 | 
			
		||||
	/// others in the same packet.
 | 
			
		||||
	fn check_outputs<F>(&self, f: F) -> Result<(), net_request::NoSuchOutput>
 | 
			
		||||
		where F: FnMut(usize, usize, OutputKind) -> Result<(), net_request::NoSuchOutput>
 | 
			
		||||
	{
 | 
			
		||||
		match *self {
 | 
			
		||||
			CheckedRequest::HeaderProof(_, ref req) => req.check_outputs(f),
 | 
			
		||||
			CheckedRequest::HeaderByHash(_, ref req) => req.check_outputs(f),
 | 
			
		||||
			CheckedRequest::Receipts(_, ref req) => req.check_outputs(f),
 | 
			
		||||
			CheckedRequest::Body(_, ref req) => req.check_outputs(f),
 | 
			
		||||
			CheckedRequest::Account(_, ref req) => req.check_outputs(f),
 | 
			
		||||
			CheckedRequest::Code(_, ref req) => req.check_outputs(f),
 | 
			
		||||
			CheckedRequest::Execution(_, ref req) => req.check_outputs(f),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Note that this request will produce the following outputs.
 | 
			
		||||
	fn note_outputs<F>(&self, f: F) where F: FnMut(usize, OutputKind) {
 | 
			
		||||
		match *self {
 | 
			
		||||
			CheckedRequest::HeaderProof(_, ref req) => req.note_outputs(f),
 | 
			
		||||
			CheckedRequest::HeaderByHash(_, ref req) => req.note_outputs(f),
 | 
			
		||||
			CheckedRequest::Receipts(_, ref req) => req.note_outputs(f),
 | 
			
		||||
			CheckedRequest::Body(_, ref req) => req.note_outputs(f),
 | 
			
		||||
			CheckedRequest::Account(_, ref req) => req.note_outputs(f),
 | 
			
		||||
			CheckedRequest::Code(_, ref req) => req.note_outputs(f),
 | 
			
		||||
			CheckedRequest::Execution(_, ref req) => req.note_outputs(f),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Fill fields of the request.
 | 
			
		||||
	///
 | 
			
		||||
	/// This function is provided an "output oracle" which allows fetching of
 | 
			
		||||
	/// prior request outputs.
 | 
			
		||||
	/// Only outputs previously checked with `check_outputs` may be available.
 | 
			
		||||
	fn fill<F>(&mut self, f: F) where F: Fn(usize, usize) -> Result<Output, net_request::NoSuchOutput> {
 | 
			
		||||
		match *self {
 | 
			
		||||
			CheckedRequest::HeaderProof(_, ref mut req) => req.fill(f),
 | 
			
		||||
			CheckedRequest::HeaderByHash(_, ref mut req) => req.fill(f),
 | 
			
		||||
			CheckedRequest::Receipts(_, ref mut req) => req.fill(f),
 | 
			
		||||
			CheckedRequest::Body(_, ref mut req) => req.fill(f),
 | 
			
		||||
			CheckedRequest::Account(_, ref mut req) => req.fill(f),
 | 
			
		||||
			CheckedRequest::Code(_, ref mut req) => req.fill(f),
 | 
			
		||||
			CheckedRequest::Execution(_, ref mut req) => req.fill(f),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Will succeed if all fields have been filled, will fail otherwise.
 | 
			
		||||
	fn complete(self) -> Result<Self::Complete, net_request::NoSuchOutput> {
 | 
			
		||||
		use ::request::CompleteRequest;
 | 
			
		||||
 | 
			
		||||
		match self {
 | 
			
		||||
			CheckedRequest::HeaderProof(_, req) => req.complete().map(CompleteRequest::HeaderProof),
 | 
			
		||||
			CheckedRequest::HeaderByHash(_, req) => req.complete().map(CompleteRequest::Headers),
 | 
			
		||||
			CheckedRequest::Receipts(_, req) => req.complete().map(CompleteRequest::Receipts),
 | 
			
		||||
			CheckedRequest::Body(_, req) => req.complete().map(CompleteRequest::Body),
 | 
			
		||||
			CheckedRequest::Account(_, req) => req.complete().map(CompleteRequest::Account),
 | 
			
		||||
			CheckedRequest::Code(_, req) => req.complete().map(CompleteRequest::Code),
 | 
			
		||||
			CheckedRequest::Execution(_, req) => req.complete().map(CompleteRequest::Execution),
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl net_request::CheckedRequest for CheckedRequest {
 | 
			
		||||
	type Extract = Response;
 | 
			
		||||
	type Error = Error;
 | 
			
		||||
 | 
			
		||||
	/// Check whether the response matches (beyond the type).
 | 
			
		||||
	fn check_response(&self, response: &Self::Response) -> Result<Response, Error> {
 | 
			
		||||
		use ::request::Response as NetResponse;
 | 
			
		||||
 | 
			
		||||
		// check response against contained prover.
 | 
			
		||||
		match (self, response) {
 | 
			
		||||
			(&CheckedRequest::HeaderProof(ref prover, _), &NetResponse::HeaderProof(ref res)) =>
 | 
			
		||||
				prover.check_response(&res.proof).map(|(h, s)| Response::HeaderProof(h, s)),
 | 
			
		||||
			(&CheckedRequest::HeaderByHash(ref prover, _), &NetResponse::Headers(ref res)) =>
 | 
			
		||||
				prover.check_response(&res.headers).map(Response::HeaderByHash),
 | 
			
		||||
			(&CheckedRequest::Receipts(ref prover, _), &NetResponse::Receipts(ref res)) =>
 | 
			
		||||
				prover.check_response(&res.receipts).map(Response::Receipts),
 | 
			
		||||
			(&CheckedRequest::Body(ref prover, _), &NetResponse::Body(ref res)) =>
 | 
			
		||||
				prover.check_response(&res.body).map(Response::Body),
 | 
			
		||||
			(&CheckedRequest::Account(ref prover, _), &NetResponse::Account(ref res)) =>
 | 
			
		||||
				prover.check_response(&res.proof).map(Response::Account),
 | 
			
		||||
			(&CheckedRequest::Code(ref prover, _), &NetResponse::Code(ref res)) =>
 | 
			
		||||
				prover.check_response(&res.code).map(Response::Code),
 | 
			
		||||
			(&CheckedRequest::Execution(ref prover, _), &NetResponse::Execution(ref res)) =>
 | 
			
		||||
				Ok(Response::Execution(prover.check_response(&res.items))),
 | 
			
		||||
			_ => Err(Error::WrongKind),
 | 
			
		||||
		}
 | 
			
		||||
	 }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Responses to on-demand requests.
 | 
			
		||||
/// All of these are checked.
 | 
			
		||||
pub enum Response {
 | 
			
		||||
	/// Response to a header proof request.
 | 
			
		||||
	/// Returns the hash and chain score.
 | 
			
		||||
	HeaderProof(H256, U256),
 | 
			
		||||
	/// Response to a header-by-hash request.
 | 
			
		||||
	HeaderByHash(encoded::Header),
 | 
			
		||||
	/// Response to a receipts request.
 | 
			
		||||
	Receipts(Vec<Receipt>),
 | 
			
		||||
	/// Response to a block body request.
 | 
			
		||||
	Body(encoded::Block),
 | 
			
		||||
	/// Response to an Account request.
 | 
			
		||||
	// TODO: `unwrap_or(engine_defaults)`
 | 
			
		||||
	Account(Option<BasicAccount>),
 | 
			
		||||
	/// Response to a request for code.
 | 
			
		||||
	Code(Vec<u8>),
 | 
			
		||||
	/// Response to a request for proved execution.
 | 
			
		||||
	Execution(ProvedExecution), // TODO: make into `Result`
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Errors in verification.
 | 
			
		||||
#[derive(Debug, PartialEq)]
 | 
			
		||||
pub enum Error {
 | 
			
		||||
	/// RLP decoder error.
 | 
			
		||||
	Decoder(::rlp::DecoderError),
 | 
			
		||||
	/// Empty response.
 | 
			
		||||
	Empty,
 | 
			
		||||
	/// Trie lookup error (result of bad proof)
 | 
			
		||||
	Trie(TrieError),
 | 
			
		||||
	/// Bad inclusion proof
 | 
			
		||||
@ -47,6 +201,8 @@ pub enum Error {
 | 
			
		||||
	WrongHash(H256, H256),
 | 
			
		||||
	/// Wrong trie root.
 | 
			
		||||
	WrongTrieRoot(H256, H256),
 | 
			
		||||
	/// Wrong response kind.
 | 
			
		||||
	WrongKind,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<::rlp::DecoderError> for Error {
 | 
			
		||||
@ -107,7 +263,8 @@ pub struct HeaderByHash(pub H256);
 | 
			
		||||
 | 
			
		||||
impl HeaderByHash {
 | 
			
		||||
	/// Check a response for the header.
 | 
			
		||||
	pub fn check_response(&self, header: &encoded::Header) -> Result<encoded::Header, Error> {
 | 
			
		||||
	pub fn check_response(&self, headers: &[encoded::Header]) -> Result<encoded::Header, Error> {
 | 
			
		||||
		let header = headers.get(0).ok_or(Error::Empty)?;
 | 
			
		||||
		let hash = header.sha3();
 | 
			
		||||
		match hash == self.0 {
 | 
			
		||||
			true => Ok(header.clone()),
 | 
			
		||||
@ -208,6 +365,7 @@ impl Account {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Request for account code.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
pub struct Code {
 | 
			
		||||
	/// Block hash, number pair.
 | 
			
		||||
	pub block_id: (H256, u64),
 | 
			
		||||
@ -217,10 +375,10 @@ pub struct Code {
 | 
			
		||||
 | 
			
		||||
impl Code {
 | 
			
		||||
	/// Check a response with code against the code hash.
 | 
			
		||||
	pub fn check_response(&self, code: &[u8]) -> Result<(), Error> {
 | 
			
		||||
	pub fn check_response(&self, code: &[u8]) -> Result<Vec<u8>, Error> {
 | 
			
		||||
		let found_hash = code.sha3();
 | 
			
		||||
		if found_hash == self.code_hash {
 | 
			
		||||
			Ok(())
 | 
			
		||||
			Ok(code.to_vec())
 | 
			
		||||
		} else {
 | 
			
		||||
			Err(Error::WrongHash(self.code_hash, found_hash))
 | 
			
		||||
		}
 | 
			
		||||
@ -228,6 +386,7 @@ impl Code {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Request for transaction execution, along with the parts necessary to verify the proof.
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct TransactionProof {
 | 
			
		||||
	/// The transaction to request proof of.
 | 
			
		||||
	pub tx: SignedTransaction,
 | 
			
		||||
 | 
			
		||||
@ -80,27 +80,6 @@ pub struct Requests<T: IncompleteRequest> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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<T::Response>
 | 
			
		||||
		where F: Fn(T::Complete) -> Option<T::Response>
 | 
			
		||||
	{
 | 
			
		||||
		let mut responses = Vec::new();
 | 
			
		||||
 | 
			
		||||
		while let Some(response) = self.next_complete().and_then(&responder) {
 | 
			
		||||
			match self.supply_response(&response) {
 | 
			
		||||
				Ok(()) => responses.push(response),
 | 
			
		||||
				Err(e) => {
 | 
			
		||||
					debug!(target: "pip", "produced bad response to request: {:?}", e);
 | 
			
		||||
					return responses;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		responses
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/// Get access to the underlying slice of requests.
 | 
			
		||||
	// TODO: unimplemented -> Vec<Request>, // do we _have to_ allocate?
 | 
			
		||||
	pub fn requests(&self) -> &[T] { &self.requests }
 | 
			
		||||
@ -118,15 +97,20 @@ impl<T: IncompleteRequest + Clone> Requests<T> {
 | 
			
		||||
				.expect("All outputs checked as invariant of `Requests` object; qed"))
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<T: super::CheckedRequest> Requests<T> {
 | 
			
		||||
	/// Supply a response for the next request.
 | 
			
		||||
	/// Fails on: wrong request kind, all requests answered already.
 | 
			
		||||
	pub fn supply_response(&mut self, response: &T::Response) -> Result<(), ResponseError> {
 | 
			
		||||
	pub fn supply_response(&mut self, response: &T::Response)
 | 
			
		||||
		-> Result<T::Extract, ResponseError<T::Error>>
 | 
			
		||||
	{
 | 
			
		||||
		let idx = self.answered;
 | 
			
		||||
 | 
			
		||||
		// check validity.
 | 
			
		||||
		if idx == self.requests.len() { return Err(ResponseError::Unexpected) }
 | 
			
		||||
		if !self.requests[idx].check_response(&response) { return Err(ResponseError::WrongKind) }
 | 
			
		||||
		let extracted = self.requests[idx]
 | 
			
		||||
			.check_response(&response).map_err(ResponseError::Validity)?;
 | 
			
		||||
 | 
			
		||||
		let outputs = &mut self.outputs;
 | 
			
		||||
		response.fill_outputs(|out_idx, output| {
 | 
			
		||||
@ -143,7 +127,30 @@ impl<T: IncompleteRequest + Clone> Requests<T> {
 | 
			
		||||
			req.fill(|req_idx, out_idx| outputs.get(&(req_idx, out_idx)).cloned().ok_or(NoSuchOutput))
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		Ok(())
 | 
			
		||||
		Ok(extracted)
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Requests<super::Request> {
 | 
			
		||||
	/// 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<super::Response>
 | 
			
		||||
		where F: Fn(super::CompleteRequest) -> Option<super::Response>
 | 
			
		||||
	{
 | 
			
		||||
		let mut responses = Vec::new();
 | 
			
		||||
 | 
			
		||||
		while let Some(response) = self.next_complete().and_then(&responder) {
 | 
			
		||||
			match self.supply_response(&response) {
 | 
			
		||||
				Ok(()) => responses.push(response),
 | 
			
		||||
				Err(e) => {
 | 
			
		||||
					debug!(target: "pip", "produced bad response to request: {:?}", e);
 | 
			
		||||
					return responses;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		responses
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -69,11 +69,15 @@ pub use self::builder::{RequestBuilder, Requests};
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
pub struct NoSuchOutput;
 | 
			
		||||
 | 
			
		||||
/// Wrong kind of response corresponding to request.
 | 
			
		||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 | 
			
		||||
pub struct WrongKind;
 | 
			
		||||
 | 
			
		||||
/// Error on processing a response.
 | 
			
		||||
#[derive(Debug, Clone, PartialEq, Eq)]
 | 
			
		||||
pub enum ResponseError {
 | 
			
		||||
	/// Wrong kind of response.
 | 
			
		||||
	WrongKind,
 | 
			
		||||
pub enum ResponseError<T> {
 | 
			
		||||
	/// Error in validity.
 | 
			
		||||
	Validity(T),
 | 
			
		||||
	/// No responses expected.
 | 
			
		||||
	Unexpected,
 | 
			
		||||
}
 | 
			
		||||
@ -342,10 +346,6 @@ 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),
 | 
			
		||||
@ -360,6 +360,19 @@ impl IncompleteRequest for Request {
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl CheckedRequest for Request {
 | 
			
		||||
	type Extract = ();
 | 
			
		||||
	type Error = WrongKind;
 | 
			
		||||
 | 
			
		||||
	fn check_response(&self, response: &Response) -> Result<(), WrongKind> {
 | 
			
		||||
		if self.kind() == response.kind() {
 | 
			
		||||
			Ok(())
 | 
			
		||||
		} else {
 | 
			
		||||
			Err(WrongKind)
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// Kinds of requests.
 | 
			
		||||
/// Doubles as the "ID" field of the request.
 | 
			
		||||
#[repr(u8)]
 | 
			
		||||
@ -520,14 +533,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 request which can be checked against its response for more validity.
 | 
			
		||||
pub trait CheckedRequest: IncompleteRequest {
 | 
			
		||||
	/// Data extracted during the check.
 | 
			
		||||
	type Extract;
 | 
			
		||||
	/// Error encountered during the check.
 | 
			
		||||
	type Error;
 | 
			
		||||
 | 
			
		||||
	/// Check whether the response matches (beyond the type).
 | 
			
		||||
	fn check_response(&self, _response: &Self::Response) -> Result<Self::Extract, Self::Error>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// A response-like object.
 | 
			
		||||
///
 | 
			
		||||
/// These contain re-usable outputs.
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user