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) => {
|
Pending::HeaderByHash(req, sender) => {
|
||||||
if let NetworkResponse::Headers(ref response) = *response {
|
if let NetworkResponse::Headers(ref response) = *response {
|
||||||
if let Some(header) = response.headers.get(0) {
|
match req.check_response(&response.headers) {
|
||||||
match req.check_response(header) {
|
Ok(header) => {
|
||||||
Ok(header) => {
|
self.cache.lock().insert_block_header(req.0, header.clone());
|
||||||
self.cache.lock().insert_block_header(req.0, header.clone());
|
let _ = sender.send(header);
|
||||||
let _ = sender.send(header);
|
return
|
||||||
return
|
|
||||||
}
|
|
||||||
Err(e) => warn!(target: "on_demand", "Error handling response for header request: {:?}", e),
|
|
||||||
}
|
}
|
||||||
|
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) => {
|
Pending::Code(req, sender) => {
|
||||||
if let NetworkResponse::Code(ref response) = *response {
|
if let NetworkResponse::Code(ref response) = *response {
|
||||||
match req.check_response(response.code.as_slice()) {
|
match req.check_response(response.code.as_slice()) {
|
||||||
Ok(()) => {
|
Ok(code) => {
|
||||||
let _ = sender.send(response.code.clone());
|
let _ = sender.send(code);
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
Err(e) => warn!(target: "on_demand", "Error handling response for code request: {:?}", e),
|
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::state::{self, ProvedExecution};
|
||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
|
|
||||||
|
use request::{self as net_request, IncompleteRequest, Output, OutputKind};
|
||||||
|
|
||||||
use rlp::{RlpStream, UntrustedRlp};
|
use rlp::{RlpStream, UntrustedRlp};
|
||||||
use util::{Address, Bytes, DBValue, HashDB, H256, U256};
|
use util::{Address, Bytes, DBValue, HashDB, H256, U256};
|
||||||
use util::memorydb::MemoryDB;
|
use util::memorydb::MemoryDB;
|
||||||
use util::sha3::Hashable;
|
use util::sha3::Hashable;
|
||||||
use util::trie::{Trie, TrieDB, TrieError};
|
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.
|
/// Errors in verification.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
/// RLP decoder error.
|
/// RLP decoder error.
|
||||||
Decoder(::rlp::DecoderError),
|
Decoder(::rlp::DecoderError),
|
||||||
|
/// Empty response.
|
||||||
|
Empty,
|
||||||
/// Trie lookup error (result of bad proof)
|
/// Trie lookup error (result of bad proof)
|
||||||
Trie(TrieError),
|
Trie(TrieError),
|
||||||
/// Bad inclusion proof
|
/// Bad inclusion proof
|
||||||
@ -47,6 +201,8 @@ pub enum Error {
|
|||||||
WrongHash(H256, H256),
|
WrongHash(H256, H256),
|
||||||
/// Wrong trie root.
|
/// Wrong trie root.
|
||||||
WrongTrieRoot(H256, H256),
|
WrongTrieRoot(H256, H256),
|
||||||
|
/// Wrong response kind.
|
||||||
|
WrongKind,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<::rlp::DecoderError> for Error {
|
impl From<::rlp::DecoderError> for Error {
|
||||||
@ -107,7 +263,8 @@ pub struct HeaderByHash(pub H256);
|
|||||||
|
|
||||||
impl HeaderByHash {
|
impl HeaderByHash {
|
||||||
/// Check a response for the header.
|
/// 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();
|
let hash = header.sha3();
|
||||||
match hash == self.0 {
|
match hash == self.0 {
|
||||||
true => Ok(header.clone()),
|
true => Ok(header.clone()),
|
||||||
@ -208,6 +365,7 @@ impl Account {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Request for account code.
|
/// Request for account code.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Code {
|
pub struct Code {
|
||||||
/// Block hash, number pair.
|
/// Block hash, number pair.
|
||||||
pub block_id: (H256, u64),
|
pub block_id: (H256, u64),
|
||||||
@ -217,10 +375,10 @@ pub struct Code {
|
|||||||
|
|
||||||
impl Code {
|
impl Code {
|
||||||
/// Check a response with code against the code hash.
|
/// 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();
|
let found_hash = code.sha3();
|
||||||
if found_hash == self.code_hash {
|
if found_hash == self.code_hash {
|
||||||
Ok(())
|
Ok(code.to_vec())
|
||||||
} else {
|
} else {
|
||||||
Err(Error::WrongHash(self.code_hash, found_hash))
|
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.
|
/// Request for transaction execution, along with the parts necessary to verify the proof.
|
||||||
|
#[derive(Clone)]
|
||||||
pub struct TransactionProof {
|
pub struct TransactionProof {
|
||||||
/// The transaction to request proof of.
|
/// The transaction to request proof of.
|
||||||
pub tx: SignedTransaction,
|
pub tx: SignedTransaction,
|
||||||
|
@ -80,27 +80,6 @@ pub struct Requests<T: IncompleteRequest> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<T: IncompleteRequest + Clone> Requests<T> {
|
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.
|
/// Get access to the underlying slice of requests.
|
||||||
// TODO: unimplemented -> Vec<Request>, // do we _have to_ allocate?
|
// TODO: unimplemented -> Vec<Request>, // do we _have to_ allocate?
|
||||||
pub fn requests(&self) -> &[T] { &self.requests }
|
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"))
|
.expect("All outputs checked as invariant of `Requests` object; qed"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: super::CheckedRequest> Requests<T> {
|
||||||
/// Supply a response for the next request.
|
/// Supply a response for the next request.
|
||||||
/// Fails on: wrong request kind, all requests answered already.
|
/// 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;
|
let idx = self.answered;
|
||||||
|
|
||||||
// check validity.
|
// check validity.
|
||||||
if idx == self.requests.len() { return Err(ResponseError::Unexpected) }
|
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;
|
let outputs = &mut self.outputs;
|
||||||
response.fill_outputs(|out_idx, output| {
|
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))
|
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)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct NoSuchOutput;
|
pub struct NoSuchOutput;
|
||||||
|
|
||||||
|
/// Wrong kind of response corresponding to request.
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
pub struct WrongKind;
|
||||||
|
|
||||||
/// Error on processing a response.
|
/// Error on processing a response.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum ResponseError {
|
pub enum ResponseError<T> {
|
||||||
/// Wrong kind of response.
|
/// Error in validity.
|
||||||
WrongKind,
|
Validity(T),
|
||||||
/// No responses expected.
|
/// No responses expected.
|
||||||
Unexpected,
|
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> {
|
fn complete(self) -> Result<Self::Complete, NoSuchOutput> {
|
||||||
match self {
|
match self {
|
||||||
Request::Headers(req) => req.complete().map(CompleteRequest::Headers),
|
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.
|
/// Kinds of requests.
|
||||||
/// Doubles as the "ID" field of the request.
|
/// Doubles as the "ID" field of the request.
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -520,14 +533,22 @@ pub trait IncompleteRequest: Sized {
|
|||||||
/// Only outputs previously checked with `check_outputs` may be available.
|
/// 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>;
|
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.
|
/// Attempt to convert this request into its complete variant.
|
||||||
/// Will succeed if all fields have been filled, will fail otherwise.
|
/// Will succeed if all fields have been filled, will fail otherwise.
|
||||||
fn complete(self) -> Result<Self::Complete, NoSuchOutput>;
|
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.
|
/// A response-like object.
|
||||||
///
|
///
|
||||||
/// These contain re-usable outputs.
|
/// These contain re-usable outputs.
|
||||||
|
Loading…
Reference in New Issue
Block a user