new requests in provider.
This commit is contained in:
parent
8e9faa416d
commit
87f3d53607
@ -315,50 +315,3 @@ impl LightChainClient for Client {
|
|||||||
Client::cht_root(self, i)
|
Client::cht_root(self, i)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// dummy implementation, should be removed when a `TestClient` is added.
|
|
||||||
impl ::provider::Provider for Client {
|
|
||||||
fn chain_info(&self) -> BlockChainInfo {
|
|
||||||
Client::chain_info(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn reorg_depth(&self, _a: &H256, _b: &H256) -> Option<u64> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn earliest_state(&self) -> Option<u64> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_header(&self, id: BlockId) -> Option<encoded::Header> {
|
|
||||||
Client::block_header(self, id)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_body(&self, _id: BlockId) -> Option<encoded::Body> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state_proof(&self, _req: ::request::StateProof) -> Vec<Bytes> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn contract_code(&self, _req: ::request::ContractCode) -> Bytes {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn header_proof(&self, _req: ::request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction_proof(&self, _req: ::request::TransactionProof) -> Option<Vec<DBValue>> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn ready_transactions(&self) -> Vec<::ethcore::transaction::PendingTransaction> {
|
|
||||||
Vec::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -59,10 +59,10 @@ pub trait Provider: Send + Sync {
|
|||||||
///
|
///
|
||||||
/// The returned vector may have any length in the range [0, `max`], but the
|
/// The returned vector may have any length in the range [0, `max`], but the
|
||||||
/// results within must adhere to the `skip` and `reverse` parameters.
|
/// results within must adhere to the `skip` and `reverse` parameters.
|
||||||
fn block_headers(&self, req: request::Headers) -> Vec<encoded::Header> {
|
fn block_headers(&self, req: request::CompleteHeadersRequest) -> Option<request::HeadersResponse> {
|
||||||
use request::HashOrNumber;
|
use request::HashOrNumber;
|
||||||
|
|
||||||
if req.max == 0 { return Vec::new() }
|
if req.max == 0 { return None }
|
||||||
|
|
||||||
let best_num = self.chain_info().best_block_number;
|
let best_num = self.chain_info().best_block_number;
|
||||||
let start_num = match req.start {
|
let start_num = match req.start {
|
||||||
@ -70,7 +70,7 @@ pub trait Provider: Send + Sync {
|
|||||||
HashOrNumber::Hash(hash) => match self.block_header(BlockId::Hash(hash)) {
|
HashOrNumber::Hash(hash) => match self.block_header(BlockId::Hash(hash)) {
|
||||||
None => {
|
None => {
|
||||||
trace!(target: "les_provider", "Unknown block hash {} requested", hash);
|
trace!(target: "les_provider", "Unknown block hash {} requested", hash);
|
||||||
return Vec::new();
|
return None;
|
||||||
}
|
}
|
||||||
Some(header) => {
|
Some(header) => {
|
||||||
let num = header.number();
|
let num = header.number();
|
||||||
@ -79,7 +79,9 @@ pub trait Provider: Send + Sync {
|
|||||||
|
|
||||||
if req.max == 1 || canon_hash != Some(hash) {
|
if req.max == 1 || canon_hash != Some(hash) {
|
||||||
// Non-canonical header or single header requested.
|
// Non-canonical header or single header requested.
|
||||||
return vec![header];
|
return Some(::request::HeadersResponse {
|
||||||
|
headers: vec![header],
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
num
|
num
|
||||||
@ -87,109 +89,39 @@ pub trait Provider: Send + Sync {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
(0u64..req.max as u64)
|
let headers = (0u64..req.max as u64)
|
||||||
.map(|x: u64| x.saturating_mul(req.skip + 1))
|
.map(|x: u64| x.saturating_mul(req.skip + 1))
|
||||||
.take_while(|x| if req.reverse { x < &start_num } else { best_num.saturating_sub(start_num) >= *x })
|
.take_while(|x| if req.reverse { x < &start_num } else { best_num.saturating_sub(start_num) >= *x })
|
||||||
.map(|x| if req.reverse { start_num - x } else { start_num + x })
|
.map(|x| if req.reverse { start_num - x } else { start_num + x })
|
||||||
.map(|x| self.block_header(BlockId::Number(x)))
|
.map(|x| self.block_header(BlockId::Number(x)))
|
||||||
.take_while(|x| x.is_some())
|
.take_while(|x| x.is_some())
|
||||||
.flat_map(|x| x)
|
.flat_map(|x| x)
|
||||||
.collect()
|
.collect();
|
||||||
|
|
||||||
|
Some(::request::HeadersResponse { headers: headers })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a block header by id.
|
/// Get a block header by id.
|
||||||
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
|
fn block_header(&self, id: BlockId) -> Option<encoded::Header>;
|
||||||
|
|
||||||
/// Provide as many as possible of the requested blocks (minus the headers) encoded
|
/// Fulfill a block body request.
|
||||||
/// in RLP format.
|
fn block_body(&self, req: request::CompleteBodyRequest) -> Option<request::BodyResponse>;
|
||||||
fn block_bodies(&self, req: request::Bodies) -> Vec<Option<encoded::Body>> {
|
|
||||||
req.block_hashes.into_iter()
|
|
||||||
.map(|hash| self.block_body(BlockId::Hash(hash)))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a block body by id.
|
/// Fulfill a request for block receipts.
|
||||||
fn block_body(&self, id: BlockId) -> Option<encoded::Body>;
|
fn block_receipts(&self, req: request::CompleteReceiptsRequest) -> Option<request::ReceiptsResponse>;
|
||||||
|
|
||||||
/// Provide the receipts as many as possible of the requested blocks.
|
/// Get an account proof.
|
||||||
/// Returns a vector of RLP-encoded lists of receipts.
|
fn account_proof(&self, req: request::CompleteAccountRequest) -> Option<request::AccountResponse>;
|
||||||
fn receipts(&self, req: request::Receipts) -> Vec<Bytes> {
|
|
||||||
req.block_hashes.into_iter()
|
|
||||||
.map(|hash| self.block_receipts(&hash))
|
|
||||||
.map(|receipts| receipts.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a block's receipts as an RLP-encoded list by block hash.
|
/// Get a storage proof.
|
||||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
|
fn storage_proof(&self, req: request::CompleteStorageRequest) -> Option<request::StorageResponse>;
|
||||||
|
|
||||||
/// Provide a set of merkle proofs, as requested. Each request is a
|
/// Provide contract code for the specified (block_hash, code_hash) pair.
|
||||||
/// block hash and request parameters.
|
fn contract_code(&self, req: request::CompleteCodeRequest) -> Option<request::CodeResponse>;
|
||||||
///
|
|
||||||
/// Returns a vector of RLP-encoded lists satisfying the requests.
|
|
||||||
fn proofs(&self, req: request::StateProofs) -> Vec<Bytes> {
|
|
||||||
use rlp::{RlpStream, Stream};
|
|
||||||
|
|
||||||
let mut results = Vec::with_capacity(req.requests.len());
|
|
||||||
|
|
||||||
for request in req.requests {
|
|
||||||
let proof = self.state_proof(request);
|
|
||||||
|
|
||||||
let mut stream = RlpStream::new_list(proof.len());
|
|
||||||
for node in proof {
|
|
||||||
stream.append_raw(&node, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
results.push(stream.out());
|
|
||||||
}
|
|
||||||
|
|
||||||
results
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get a state proof from a request. Each proof should be a vector
|
|
||||||
/// of rlp-encoded trie nodes, in ascending order by distance from the root.
|
|
||||||
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes>;
|
|
||||||
|
|
||||||
/// Provide contract code for the specified (block_hash, account_hash) pairs.
|
|
||||||
/// Each item in the resulting vector is either the raw bytecode or empty.
|
|
||||||
fn contract_codes(&self, req: request::ContractCodes) -> Vec<Bytes> {
|
|
||||||
req.code_requests.into_iter()
|
|
||||||
.map(|req| self.contract_code(req))
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get contract code by request. Either the raw bytecode or empty.
|
|
||||||
fn contract_code(&self, req: request::ContractCode) -> Bytes;
|
|
||||||
|
|
||||||
/// Provide header proofs from the Canonical Hash Tries as well as the headers
|
|
||||||
/// they correspond to -- each element in the returned vector is a 2-tuple.
|
|
||||||
/// The first element is a block header and the second a merkle proof of
|
|
||||||
/// the header in a requested CHT.
|
|
||||||
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes> {
|
|
||||||
use rlp::{self, RlpStream, Stream};
|
|
||||||
|
|
||||||
req.requests.into_iter()
|
|
||||||
.map(|req| self.header_proof(req))
|
|
||||||
.map(|maybe_proof| match maybe_proof {
|
|
||||||
None => rlp::EMPTY_LIST_RLP.to_vec(),
|
|
||||||
Some((header, proof)) => {
|
|
||||||
let mut stream = RlpStream::new_list(2);
|
|
||||||
stream.append_raw(&header.into_inner(), 1).begin_list(proof.len());
|
|
||||||
|
|
||||||
for node in proof {
|
|
||||||
stream.append_raw(&node, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
stream.out()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Provide a header proof from a given Canonical Hash Trie as well as the
|
/// Provide a header proof from a given Canonical Hash Trie as well as the
|
||||||
/// corresponding header. The first element is the block header and the
|
/// corresponding header.
|
||||||
/// second is a merkle proof of the CHT.
|
fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option<request::HeaderProofResponse>;
|
||||||
fn header_proof(&self, req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)>;
|
|
||||||
|
|
||||||
/// Provide pending transactions.
|
/// Provide pending transactions.
|
||||||
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
||||||
@ -217,32 +149,52 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
BlockChainClient::block_header(self, id)
|
BlockChainClient::block_header(self, id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, id: BlockId) -> Option<encoded::Body> {
|
fn block_body(&self, req: request::CompleteBodyRequest) -> Option<request::BodyResponse>;
|
||||||
BlockChainClient::block_body(self, id)
|
BlockChainClient::block_body(self, id)
|
||||||
|
.map(|body| ::request::BodyResponse { body: body })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
fn block_receipts(&self, req: request::CompleteReceiptsRequest) -> Option<request::ReceiptsResponse>;
|
||||||
BlockChainClient::block_receipts(self, hash)
|
BlockChainClient::block_receipts(self, hash)
|
||||||
|
.map(|x| ::request::ReceiptsResponse { receipts: ::rlp::decode(&x) })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes> {
|
fn account_proof(&self, req: request::CompleteAccountRequest) -> Option<request::AccountResponse> {
|
||||||
match req.key2 {
|
self.prove_account(req.address_hash, BlockId::Hash(req.block_hash)).map(|(proof, acc)| {
|
||||||
Some(key2) => self.prove_storage(req.key1, key2, req.from_level, BlockId::Hash(req.block)),
|
::request::AccountResponse {
|
||||||
None => self.prove_account(req.key1, req.from_level, BlockId::Hash(req.block)),
|
proof: proof,
|
||||||
|
nonce: acc.nonce,
|
||||||
|
balance: acc.balance,
|
||||||
|
code_hash: acc.code_hash,
|
||||||
|
storage_root: acc.storage_root,
|
||||||
}
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contract_code(&self, req: request::ContractCode) -> Bytes {
|
fn storage_proof(&self, req: request::CompleteStorageRequest) -> Option<request::StorageResponse> {
|
||||||
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
|
self.prove_account(req.address_hash, req.key_hash, BlockId::Hash(req.block_hash)).map(|(proof, item) | {
|
||||||
|
::request::StorageResponse {
|
||||||
|
proof: proof,
|
||||||
|
value: item,
|
||||||
|
}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_proof(&self, req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
|
fn contract_code(&self, req: request::ContractCode) -> Option<request::CodeResponse> {
|
||||||
if Some(req.cht_number) != cht::block_to_cht_number(req.block_number) {
|
self.state_data(&req.code_hash)
|
||||||
debug!(target: "les_provider", "Requested CHT number mismatch with block number.");
|
.map(|code| ::request::CodeResponse { code: code })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option<request::HeaderProofResponse>;
|
||||||
|
let cht_number = match cht::block_to_cht_number(req.num) {
|
||||||
|
Some(cht_num) => cht_num,
|
||||||
|
None => {
|
||||||
|
debug!(target: "les_provider", "Requested CHT proof with invalid block number");
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let mut needed_hdr = None;
|
let mut needed = None;
|
||||||
|
|
||||||
// build the CHT, caching the requested header as we pass through it.
|
// build the CHT, caching the requested header as we pass through it.
|
||||||
let cht = {
|
let cht = {
|
||||||
@ -258,8 +210,8 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
total_difficulty: td,
|
total_difficulty: td,
|
||||||
};
|
};
|
||||||
|
|
||||||
if hdr.number() == req.block_number {
|
if hdr.number() == req.num {
|
||||||
needed_hdr = Some(hdr);
|
needed = Some((hdr, td));
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(info)
|
Some(info)
|
||||||
@ -268,17 +220,21 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match cht::build(req.cht_number, block_info) {
|
match cht::build(cht_number, block_info) {
|
||||||
Some(cht) => cht,
|
Some(cht) => cht,
|
||||||
None => return None, // incomplete CHT.
|
None => return None, // incomplete CHT.
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let needed_hdr = needed_hdr.expect("`needed_hdr` always set in loop, number checked before; qed");
|
let (needed_hdr, needed_td) = needed.expect("`needed` always set in loop, number checked before; qed");
|
||||||
|
|
||||||
// prove our result.
|
// prove our result.
|
||||||
match cht.prove(req.block_number, req.from_level) {
|
match cht.prove(req.num, 0) {
|
||||||
Ok(Some(proof)) => Some((needed_hdr, proof)),
|
Ok(Some(proof)) => Some(::request::HeaderProofResponse {
|
||||||
|
proof: proof,
|
||||||
|
hash: needed_hdr.hash(),
|
||||||
|
td: needed_td,
|
||||||
|
}),
|
||||||
Ok(None) => None,
|
Ok(None) => None,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "les_provider", "Error looking up number in freshly-created CHT: {}", e);
|
debug!(target: "les_provider", "Error looking up number in freshly-created CHT: {}", e);
|
||||||
@ -347,23 +303,27 @@ impl<L: AsLightClient + Send + Sync> Provider for LightProvider<L> {
|
|||||||
self.client.as_light_client().block_header(id)
|
self.client.as_light_client().block_header(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_body(&self, _id: BlockId) -> Option<encoded::Body> {
|
fn block_body(&self, req: request::CompleteBodyRequest) -> Option<request::BodyResponse> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
|
fn block_receipts(&self, req: request::CompleteReceiptsRequest) -> Option<request::ReceiptsResponse> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn state_proof(&self, _req: request::StateProof) -> Vec<Bytes> {
|
fn account_proof(&self, req: request::CompleteAccountRequest) -> Option<request::AccountResponse> {
|
||||||
Vec::new()
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contract_code(&self, _req: request::ContractCode) -> Bytes {
|
fn storage_proof(&self, req: request::CompleteStorageRequest) -> Option<request::StorageResponse> {
|
||||||
Vec::new()
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(encoded::Header, Vec<Bytes>)> {
|
fn contract_code(&self, req: request::CompleteCodeRequest) -> Option<request::CodeResponse> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn header_proof(&self, req: request::CompleteHeaderProofRequest) -> Option<request::HeaderProofResponse> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,6 +113,15 @@ pub enum Output {
|
|||||||
Number(u64),
|
Number(u64),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
fn kind(&self) -> OutputKind {
|
||||||
|
match *self {
|
||||||
|
Output::Hash(_) => OutputKind::Hash,
|
||||||
|
Output::Number(_) => OutputKind::Number,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Response output kinds which can be used as back-references.
|
/// Response output kinds which can be used as back-references.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum OutputKind {
|
pub enum OutputKind {
|
||||||
@ -145,6 +154,7 @@ impl From<u64> for HashOrNumber {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// All request types, as they're sent over the network.
|
/// All request types, as they're sent over the network.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum Request {
|
pub enum Request {
|
||||||
/// A request for block headers.
|
/// A request for block headers.
|
||||||
Headers(IncompleteHeadersRequest),
|
Headers(IncompleteHeadersRequest),
|
||||||
@ -164,6 +174,27 @@ pub enum Request {
|
|||||||
// Transaction proof.
|
// Transaction proof.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All request types, as they're sent over the network.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum CompleteRequest {
|
||||||
|
/// A request for block headers.
|
||||||
|
Headers(CompleteHeadersRequest),
|
||||||
|
/// A request for a header proof (from a CHT)
|
||||||
|
HeaderProof(CompleteHeaderProofRequest),
|
||||||
|
// TransactionIndex,
|
||||||
|
/// A request for a block's receipts.
|
||||||
|
Receipts(CompleteReceiptsRequest),
|
||||||
|
/// A request for a block body.
|
||||||
|
Body(CompleteBodyRequest),
|
||||||
|
/// A request for a merkle proof of an account.
|
||||||
|
Account(CompleteAccountRequest),
|
||||||
|
/// A request for a merkle proof of contract storage.
|
||||||
|
Storage(CompleteStorageRequest),
|
||||||
|
/// A request for contract code.
|
||||||
|
Code(CompleteCodeRequest),
|
||||||
|
// Transaction proof.
|
||||||
|
}
|
||||||
|
|
||||||
impl Request {
|
impl Request {
|
||||||
fn kind(&self) -> RequestKind {
|
fn kind(&self) -> RequestKind {
|
||||||
match *self {
|
match *self {
|
||||||
@ -210,10 +241,54 @@ impl Encodable for Request {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl IncompleteRequest for Request {
|
||||||
|
type Complete = CompleteRequest;
|
||||||
|
|
||||||
|
fn check_outputs<F>(&self, f: F) -> Result<(), NoSuchOutput>
|
||||||
|
where F: FnMut(usize, usize, OutputKind) -> Result<(), NoSuchOutput>
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
Request::Headers(ref req) => req.check_outputs(f),
|
||||||
|
Request::HeaderProof(ref req) => req.check_outputs(f),
|
||||||
|
Request::Receipts(ref req) => req.check_outputs(f),
|
||||||
|
Request::Body(ref req) => req.check_outputs(f),
|
||||||
|
Request::Account(ref req) => req.check_outputs(f),
|
||||||
|
Request::Storage(ref req) => req.check_outputs(f),
|
||||||
|
Request::Code(ref req) => req.check_outputs(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn note_outputs<F>(&self, f: F) where F: FnMut(usize, OutputKind) {
|
||||||
|
match *self {
|
||||||
|
Request::Headers(ref req) => req.note_outputs(f),
|
||||||
|
Request::HeaderProof(ref req) => req.note_outputs(f),
|
||||||
|
Request::Receipts(ref req) => req.note_outputs(f),
|
||||||
|
Request::Body(ref req) => req.note_outputs(f),
|
||||||
|
Request::Account(ref req) => req.note_outputs(f),
|
||||||
|
Request::Storage(ref req) => req.note_outputs(f),
|
||||||
|
Request::Code(ref req) => req.note_outputs(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fill<F>(self, oracle: F) -> Result<Self::Complete, NoSuchOutput>
|
||||||
|
where F: Fn(usize, usize) -> Result<Output, NoSuchOutput>
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Request::Headers(req) => CompleteRequest::Headers(req.fill(oracle)),
|
||||||
|
Request::HeaderProof(req) => CompleteRequest::HeaderProof(req.fill(oracle)),
|
||||||
|
Request::Receipts(req) => CompleteRequest::Receipts(req.fill(oracle)),
|
||||||
|
Request::Body(req) => CompleteRequest::Body(req.fill(oracle)),
|
||||||
|
Request::Account(req) => CompleteRequest::Account(req.fill(oracle)),
|
||||||
|
Request::Storage(req) => CompleteRequest::Storage(req.fill(oracle)),
|
||||||
|
Request::Code(req) => CompleteRequest::Code(req.fill(oracle)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// 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)]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub enum RequestKind {
|
pub enum RequestKind {
|
||||||
/// A request for headers.
|
/// A request for headers.
|
||||||
Headers = 0,
|
Headers = 0,
|
||||||
@ -252,6 +327,42 @@ impl Encodable for RequestKind {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// All response types.
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Response {
|
||||||
|
/// A response for block headers.
|
||||||
|
Headers(HeadersResponse),
|
||||||
|
/// A response for a header proof (from a CHT)
|
||||||
|
HeaderProof(HeaderProofResponse),
|
||||||
|
// TransactionIndex,
|
||||||
|
/// A response for a block's receipts.
|
||||||
|
Receipts(ReceiptsResponse),
|
||||||
|
/// A response for a block body.
|
||||||
|
Body(BodyResponse),
|
||||||
|
/// A response for a merkle proof of an account.
|
||||||
|
Account(AccountResponse),
|
||||||
|
/// A response for a merkle proof of contract storage.
|
||||||
|
Storage(StorageResponse),
|
||||||
|
/// A response for contract code.
|
||||||
|
Code(CodeResponse),
|
||||||
|
// Transaction proof.
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Response {
|
||||||
|
/// Fill reusable outputs by writing them into the function.
|
||||||
|
pub fn fill_outputs<F>(&self, mut f: F) where F: FnMut(usize, Output) {
|
||||||
|
match *self {
|
||||||
|
Response::Headers(res) => res.fill_outputs(f)
|
||||||
|
Response::HeaderProof(res) => res.fill_outputs(f)
|
||||||
|
Response::Receipts(res) => res.fill_outputs(f)
|
||||||
|
Response::Body(res) => res.fill_outputs(f)
|
||||||
|
Response::Account(res) => res.fill_outputs(f)
|
||||||
|
Response::Storage(res) => res.fill_outputs(f)
|
||||||
|
Response::Code(res) => res.fill_outputs(f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A potentially incomplete request.
|
/// A potentially incomplete request.
|
||||||
pub trait IncompleteRequest: Sized {
|
pub trait IncompleteRequest: Sized {
|
||||||
type Complete;
|
type Complete;
|
||||||
@ -369,7 +480,8 @@ pub mod header {
|
|||||||
/// The output of a request for headers.
|
/// The output of a request for headers.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct Response {
|
pub struct Response {
|
||||||
header: Vec<encoded::Header>,
|
/// The headers requested.
|
||||||
|
pub headers: Vec<encoded::Header>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Response {
|
impl Response {
|
||||||
@ -523,7 +635,6 @@ pub mod block_receipts {
|
|||||||
hash: hash,
|
hash: hash,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A complete block receipts request.
|
/// A complete block receipts request.
|
||||||
|
Loading…
Reference in New Issue
Block a user