Merge pull request #3897 from ethcore/single-provider-functions
require only simpler methods on Provider
This commit is contained in:
commit
5ba16e4867
@ -90,28 +90,28 @@ impl Provider for Client {
|
||||
None
|
||||
}
|
||||
|
||||
fn block_headers(&self, _req: request::Headers) -> Vec<Bytes> {
|
||||
fn block_header(&self, _id: BlockId) -> Option<Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn block_body(&self, _id: BlockId) -> Option<Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn block_receipts(&self, _hash: &H256) -> Option<Bytes> {
|
||||
None
|
||||
}
|
||||
|
||||
fn state_proof(&self, _req: request::StateProof) -> Vec<Bytes> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn block_bodies(&self, _req: request::Bodies) -> Vec<Bytes> {
|
||||
fn contract_code(&self, _req: request::ContractCode) -> Bytes {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn receipts(&self, _req: request::Receipts) -> Vec<Bytes> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn proofs(&self, _req: request::StateProofs) -> Vec<Bytes> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn contract_code(&self, _req: request::ContractCodes) -> Vec<Bytes> {
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
fn header_proofs(&self, _req: request::HeaderProofs) -> Vec<Bytes> {
|
||||
Vec::new()
|
||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||
|
@ -956,7 +956,7 @@ impl LightProtocol {
|
||||
|
||||
let max_cost = try!(peer.deduct_max(&self.flow_params, request::Kind::Codes, req.code_requests.len()));
|
||||
|
||||
let response = self.provider.contract_code(req);
|
||||
let response = self.provider.contract_codes(req);
|
||||
let response_len = response.iter().filter(|x| !x.is_empty()).count();
|
||||
let actual_cost = self.flow_params.compute_cost(request::Kind::Codes, response_len);
|
||||
assert!(max_cost >= actual_cost, "Actual cost exceeded maximum computed cost.");
|
||||
|
@ -94,79 +94,36 @@ impl Provider for TestProvider {
|
||||
None
|
||||
}
|
||||
|
||||
fn block_headers(&self, req: request::Headers) -> Vec<Bytes> {
|
||||
use request::HashOrNumber;
|
||||
use ethcore::views::HeaderView;
|
||||
|
||||
let best_num = self.chain_info().best_block_number;
|
||||
let start_num = match req.start {
|
||||
HashOrNumber::Number(start_num) => start_num,
|
||||
HashOrNumber::Hash(hash) => match self.0.client.block_header(BlockId::Hash(hash)) {
|
||||
None => {
|
||||
return Vec::new();
|
||||
}
|
||||
Some(header) => {
|
||||
let num = HeaderView::new(&header).number();
|
||||
if req.max == 1 || self.0.client.block_hash(BlockId::Number(num)) != Some(hash) {
|
||||
// Non-canonical header or single header requested.
|
||||
return vec![header];
|
||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
||||
self.0.client.block_header(id)
|
||||
}
|
||||
|
||||
num
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
(0u64..req.max as u64)
|
||||
.map(|x: u64| x.saturating_mul(req.skip + 1))
|
||||
.take_while(|x| if req.reverse { x < &start_num } else { best_num - start_num >= *x })
|
||||
.map(|x| if req.reverse { start_num - x } else { start_num + x })
|
||||
.map(|x| self.0.client.block_header(BlockId::Number(x)))
|
||||
.take_while(|x| x.is_some())
|
||||
.flat_map(|x| x)
|
||||
.collect()
|
||||
fn block_body(&self, id: BlockId) -> Option<Bytes> {
|
||||
self.0.client.block_body(id)
|
||||
}
|
||||
|
||||
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> {
|
||||
req.block_hashes.into_iter()
|
||||
.map(|hash| self.0.client.block_body(BlockId::Hash(hash)))
|
||||
.map(|body| body.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
|
||||
.collect()
|
||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
||||
self.0.client.block_receipts(&hash)
|
||||
}
|
||||
|
||||
fn receipts(&self, req: request::Receipts) -> Vec<Bytes> {
|
||||
req.block_hashes.into_iter()
|
||||
.map(|hash| self.0.client.block_receipts(&hash))
|
||||
.map(|receipts| receipts.unwrap_or_else(|| ::rlp::EMPTY_LIST_RLP.to_vec()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn proofs(&self, req: request::StateProofs) -> Vec<Bytes> {
|
||||
req.requests.into_iter()
|
||||
.map(|req| {
|
||||
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes> {
|
||||
match req.key2 {
|
||||
Some(_) => ::util::sha3::SHA3_NULL_RLP.to_vec(),
|
||||
Some(_) => vec![::util::sha3::SHA3_NULL_RLP.to_vec()],
|
||||
None => {
|
||||
// sort of a leaf node
|
||||
let mut stream = RlpStream::new_list(2);
|
||||
stream.append(&req.key1).append_empty_data();
|
||||
stream.out()
|
||||
vec![stream.out()]
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn contract_code(&self, req: request::ContractCodes) -> Vec<Bytes> {
|
||||
req.code_requests.into_iter()
|
||||
.map(|req| {
|
||||
fn contract_code(&self, req: request::ContractCode) -> Bytes {
|
||||
req.account_key.iter().chain(req.account_key.iter()).cloned().collect()
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes> {
|
||||
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
|
||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||
@ -455,8 +412,8 @@ fn get_state_proofs() {
|
||||
let request_body = encode_request(&request, req_id);
|
||||
let response = {
|
||||
let proofs = vec![
|
||||
{ let mut stream = RlpStream::new_list(2); stream.append(&key1).append_empty_data(); stream.out() },
|
||||
::util::sha3::SHA3_NULL_RLP.to_vec(),
|
||||
{ let mut stream = RlpStream::new_list(2); stream.append(&key1).append_empty_data(); vec![stream.out()] },
|
||||
vec![::util::sha3::SHA3_NULL_RLP.to_vec()],
|
||||
];
|
||||
|
||||
let new_buf = *flow_params.limit() - flow_params.compute_cost(request::Kind::StateProofs, 2);
|
||||
@ -465,7 +422,10 @@ fn get_state_proofs() {
|
||||
|
||||
response_stream.append(&req_id).append(&new_buf).begin_list(2);
|
||||
for proof in proofs {
|
||||
response_stream.append_raw(&proof, 1);
|
||||
response_stream.begin_list(proof.len());
|
||||
for node in proof {
|
||||
response_stream.append_raw(&node, 1);
|
||||
}
|
||||
}
|
||||
|
||||
response_stream.out()
|
||||
|
@ -52,54 +52,12 @@ pub trait Provider: Send + Sync {
|
||||
///
|
||||
/// The returned vector may have any length in the range [0, `max`], but the
|
||||
/// results within must adhere to the `skip` and `reverse` parameters.
|
||||
fn block_headers(&self, req: request::Headers) -> Vec<Bytes>;
|
||||
|
||||
/// Provide as many as possible of the requested blocks (minus the headers) encoded
|
||||
/// in RLP format.
|
||||
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes>;
|
||||
|
||||
/// Provide the receipts as many as possible of the requested blocks.
|
||||
/// Returns a vector of RLP-encoded lists of receipts.
|
||||
fn receipts(&self, req: request::Receipts) -> Vec<Bytes>;
|
||||
|
||||
/// Provide a set of merkle proofs, as requested. Each request is a
|
||||
/// block hash and request parameters.
|
||||
///
|
||||
/// Returns a vector of RLP-encoded lists satisfying the requests.
|
||||
fn proofs(&self, req: request::StateProofs) -> 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_code(&self, req: request::ContractCodes) -> Vec<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>;
|
||||
|
||||
/// Provide pending transactions.
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
||||
}
|
||||
|
||||
// Implementation of a light client data provider for a client.
|
||||
impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
fn chain_info(&self) -> BlockChainInfo {
|
||||
BlockChainClient::chain_info(self)
|
||||
}
|
||||
|
||||
fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> {
|
||||
self.tree_route(a, b).map(|route| route.index as u64)
|
||||
}
|
||||
|
||||
fn earliest_state(&self) -> Option<u64> {
|
||||
Some(self.pruning_info().earliest_state)
|
||||
}
|
||||
|
||||
fn block_headers(&self, req: request::Headers) -> Vec<Bytes> {
|
||||
use request::HashOrNumber;
|
||||
use ethcore::views::HeaderView;
|
||||
|
||||
if req.max == 0 { return Vec::new() }
|
||||
|
||||
let best_num = self.chain_info().best_block_number;
|
||||
let start_num = match req.start {
|
||||
HashOrNumber::Number(start_num) => start_num,
|
||||
@ -110,7 +68,10 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
}
|
||||
Some(header) => {
|
||||
let num = HeaderView::new(&header).number();
|
||||
if req.max == 1 || self.block_hash(BlockId::Number(num)) != Some(hash) {
|
||||
let canon_hash = self.block_header(BlockId::Number(num))
|
||||
.map(|h| HeaderView::new(&h).hash());
|
||||
|
||||
if req.max == 1 || canon_hash != Some(hash) {
|
||||
// Non-canonical header or single header requested.
|
||||
return vec![header];
|
||||
}
|
||||
@ -130,6 +91,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get a block header by id.
|
||||
fn block_header(&self, id: BlockId) -> Option<Bytes>;
|
||||
|
||||
/// Provide as many as possible of the requested blocks (minus the headers) encoded
|
||||
/// in RLP format.
|
||||
fn block_bodies(&self, req: request::Bodies) -> Vec<Bytes> {
|
||||
req.block_hashes.into_iter()
|
||||
.map(|hash| self.block_body(BlockId::Hash(hash)))
|
||||
@ -137,6 +103,11 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get a block body by id.
|
||||
fn block_body(&self, id: BlockId) -> Option<Bytes>;
|
||||
|
||||
/// Provide the receipts as many as possible of the requested blocks.
|
||||
/// Returns a vector of RLP-encoded lists of receipts.
|
||||
fn receipts(&self, req: request::Receipts) -> Vec<Bytes> {
|
||||
req.block_hashes.into_iter()
|
||||
.map(|hash| self.block_receipts(&hash))
|
||||
@ -144,16 +115,20 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// Get a block's receipts as an RLP-encoded list by block hash.
|
||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes>;
|
||||
|
||||
/// Provide a set of merkle proofs, as requested. Each request is a
|
||||
/// block hash and request parameters.
|
||||
///
|
||||
/// 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 = match request.key2 {
|
||||
Some(key2) => self.prove_storage(request.key1, key2, request.from_level, BlockId::Hash(request.block)),
|
||||
None => self.prove_account(request.key1, request.from_level, BlockId::Hash(request.block)),
|
||||
};
|
||||
let proof = self.state_proof(request);
|
||||
|
||||
let mut stream = RlpStream::new_list(proof.len());
|
||||
for node in proof {
|
||||
@ -166,16 +141,94 @@ impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
results
|
||||
}
|
||||
|
||||
fn contract_code(&self, req: request::ContractCodes) -> Vec<Bytes> {
|
||||
/// 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.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
|
||||
.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, 1).begin_list(proof.len());
|
||||
|
||||
for node in proof {
|
||||
stream.append_raw(&node, 1);
|
||||
}
|
||||
|
||||
stream.out()
|
||||
}
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn header_proofs(&self, req: request::HeaderProofs) -> Vec<Bytes> {
|
||||
req.requests.into_iter().map(|_| ::rlp::EMPTY_LIST_RLP.to_vec()).collect()
|
||||
/// 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
|
||||
/// second is a merkle proof of the CHT.
|
||||
fn header_proof(&self, req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)>;
|
||||
|
||||
/// Provide pending transactions.
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction>;
|
||||
}
|
||||
|
||||
// Implementation of a light client data provider for a client.
|
||||
impl<T: ProvingBlockChainClient + ?Sized> Provider for T {
|
||||
fn chain_info(&self) -> BlockChainInfo {
|
||||
BlockChainClient::chain_info(self)
|
||||
}
|
||||
|
||||
fn reorg_depth(&self, a: &H256, b: &H256) -> Option<u64> {
|
||||
self.tree_route(a, b).map(|route| route.index as u64)
|
||||
}
|
||||
|
||||
fn earliest_state(&self) -> Option<u64> {
|
||||
Some(self.pruning_info().earliest_state)
|
||||
}
|
||||
|
||||
fn block_header(&self, id: BlockId) -> Option<Bytes> {
|
||||
BlockChainClient::block_header(self, id)
|
||||
}
|
||||
|
||||
fn block_body(&self, id: BlockId) -> Option<Bytes> {
|
||||
BlockChainClient::block_body(self, id)
|
||||
}
|
||||
|
||||
fn block_receipts(&self, hash: &H256) -> Option<Bytes> {
|
||||
BlockChainClient::block_receipts(self, hash)
|
||||
}
|
||||
|
||||
fn state_proof(&self, req: request::StateProof) -> Vec<Bytes> {
|
||||
match req.key2 {
|
||||
Some(key2) => self.prove_storage(req.key1, key2, req.from_level, BlockId::Hash(req.block)),
|
||||
None => self.prove_account(req.key1, req.from_level, BlockId::Hash(req.block)),
|
||||
}
|
||||
}
|
||||
|
||||
fn contract_code(&self, req: request::ContractCode) -> Bytes {
|
||||
self.code_by_hash(req.account_key, BlockId::Hash(req.block_hash))
|
||||
}
|
||||
|
||||
fn header_proof(&self, _req: request::HeaderProof) -> Option<(Bytes, Vec<Bytes>)> {
|
||||
None
|
||||
}
|
||||
|
||||
fn ready_transactions(&self) -> Vec<PendingTransaction> {
|
||||
|
Loading…
Reference in New Issue
Block a user