mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-06-13 23:21:06 +00:00
Fetching multiple remote values using single message (#3612)
* multiple remote values in single message * keys_str: String ->keys_str: closure
This commit is contained in:
committed by
GitHub
parent
c45a15e559
commit
849e824652
@@ -23,8 +23,6 @@
|
||||
//! root has. A correct proof implies that the claimed block is identical to the one
|
||||
//! we discarded.
|
||||
|
||||
use std::collections::HashSet;
|
||||
|
||||
use hash_db;
|
||||
use codec::Encode;
|
||||
use trie;
|
||||
@@ -105,15 +103,10 @@ pub fn build_proof<Header, Hasher, BlocksI, HashesI>(
|
||||
let mut storage = InMemoryState::<Hasher>::default().update(transaction);
|
||||
let trie_storage = storage.as_trie_backend()
|
||||
.expect("InMemoryState::as_trie_backend always returns Some; qed");
|
||||
let mut total_proof = HashSet::new();
|
||||
for block in blocks.into_iter() {
|
||||
debug_assert_eq!(block_to_cht_number(cht_size, block), Some(cht_num));
|
||||
|
||||
let (value, proof) = prove_read_on_trie_backend(trie_storage, &encode_cht_key(block))?;
|
||||
assert!(value.is_some(), "we have just built trie that includes the value for block");
|
||||
total_proof.extend(proof);
|
||||
}
|
||||
Ok(total_proof.into_iter().collect())
|
||||
prove_read_on_trie_backend(
|
||||
trie_storage,
|
||||
blocks.into_iter().map(|number| encode_cht_key(number)),
|
||||
).map_err(ClientError::Execution)
|
||||
}
|
||||
|
||||
/// Check CHT-based header proof.
|
||||
@@ -128,9 +121,21 @@ pub fn check_proof<Header, Hasher>(
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
{
|
||||
do_check_proof::<Header, Hasher, _>(local_root, local_number, remote_hash, move |local_root, local_cht_key|
|
||||
read_proof_check::<Hasher>(local_root, remote_proof,
|
||||
local_cht_key).map_err(|e| ClientError::from(e)))
|
||||
do_check_proof::<Header, Hasher, _>(
|
||||
local_root,
|
||||
local_number,
|
||||
remote_hash,
|
||||
move |local_root, local_cht_key|
|
||||
read_proof_check::<Hasher, _>(
|
||||
local_root,
|
||||
remote_proof,
|
||||
::std::iter::once(local_cht_key),
|
||||
)
|
||||
.map(|mut map| map
|
||||
.remove(local_cht_key)
|
||||
.expect("checked proof of local_cht_key; qed"))
|
||||
.map_err(|e| ClientError::from(e)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Check CHT-based header proof on pre-created proving backend.
|
||||
@@ -145,9 +150,16 @@ pub fn check_proof_on_proving_backend<Header, Hasher>(
|
||||
Hasher: hash_db::Hasher,
|
||||
Hasher::Out: Ord,
|
||||
{
|
||||
do_check_proof::<Header, Hasher, _>(local_root, local_number, remote_hash, |_, local_cht_key|
|
||||
read_proof_check_on_proving_backend::<Hasher>(
|
||||
proving_backend, local_cht_key).map_err(|e| ClientError::from(e)))
|
||||
do_check_proof::<Header, Hasher, _>(
|
||||
local_root,
|
||||
local_number,
|
||||
remote_hash,
|
||||
|_, local_cht_key|
|
||||
read_proof_check_on_proving_backend::<Hasher>(
|
||||
proving_backend,
|
||||
local_cht_key,
|
||||
).map_err(|e| ClientError::from(e)),
|
||||
)
|
||||
}
|
||||
|
||||
/// Check CHT-based header proof using passed checker function.
|
||||
|
||||
@@ -436,24 +436,28 @@ impl<B, E, Block, RA> Client<B, E, Block, RA> where
|
||||
}
|
||||
|
||||
/// Reads storage value at a given block + key, returning read proof.
|
||||
pub fn read_proof(&self, id: &BlockId<Block>, key: &[u8]) -> error::Result<Vec<Vec<u8>>> {
|
||||
pub fn read_proof<I>(&self, id: &BlockId<Block>, keys: I) -> error::Result<Vec<Vec<u8>>> where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
self.state_at(id)
|
||||
.and_then(|state| prove_read(state, key)
|
||||
.map(|(_, proof)| proof)
|
||||
.and_then(|state| prove_read(state, keys)
|
||||
.map_err(Into::into))
|
||||
}
|
||||
|
||||
/// Reads child storage value at a given block + storage_key + key, returning
|
||||
/// read proof.
|
||||
pub fn read_child_proof(
|
||||
pub fn read_child_proof<I>(
|
||||
&self,
|
||||
id: &BlockId<Block>,
|
||||
storage_key: &[u8],
|
||||
key: &[u8]
|
||||
) -> error::Result<Vec<Vec<u8>>> {
|
||||
keys: I,
|
||||
) -> error::Result<Vec<Vec<u8>>> where
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
self.state_at(id)
|
||||
.and_then(|state| prove_child_read(state, storage_key, key)
|
||||
.map(|(_, proof)| proof)
|
||||
.and_then(|state| prove_child_read(state, storage_key, keys)
|
||||
.map_err(Into::into))
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
//! Light client data fetcher. Fetches requested data from remote full nodes.
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::BTreeMap;
|
||||
use std::collections::{BTreeMap, HashMap};
|
||||
use std::marker::PhantomData;
|
||||
use std::future::Future;
|
||||
|
||||
@@ -73,7 +73,7 @@ pub struct RemoteReadRequest<Header: HeaderT> {
|
||||
/// Header of block at which read is performed.
|
||||
pub header: Header,
|
||||
/// Storage key to read.
|
||||
pub key: Vec<u8>,
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
/// Number of times to retry request. None means that default RETRY_COUNT is used.
|
||||
pub retry_count: Option<usize>,
|
||||
}
|
||||
@@ -88,7 +88,7 @@ pub struct RemoteReadChildRequest<Header: HeaderT> {
|
||||
/// Storage key for child.
|
||||
pub storage_key: Vec<u8>,
|
||||
/// Child storage key to read.
|
||||
pub key: Vec<u8>,
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
/// Number of times to retry request. None means that default RETRY_COUNT is used.
|
||||
pub retry_count: Option<usize>,
|
||||
}
|
||||
@@ -147,7 +147,7 @@ pub trait Fetcher<Block: BlockT>: Send + Sync {
|
||||
/// Remote header future.
|
||||
type RemoteHeaderResult: Future<Output = Result<Block::Header, ClientError>> + Send + 'static;
|
||||
/// Remote storage read future.
|
||||
type RemoteReadResult: Future<Output = Result<Option<Vec<u8>>, ClientError>> + Send + 'static;
|
||||
type RemoteReadResult: Future<Output = Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>> + Send + 'static;
|
||||
/// Remote call result future.
|
||||
type RemoteCallResult: Future<Output = Result<Vec<u8>, ClientError>> + Send + 'static;
|
||||
/// Remote changes result future.
|
||||
@@ -193,13 +193,13 @@ pub trait FetchChecker<Block: BlockT>: Send + Sync {
|
||||
&self,
|
||||
request: &RemoteReadRequest<Block::Header>,
|
||||
remote_proof: Vec<Vec<u8>>
|
||||
) -> ClientResult<Option<Vec<u8>>>;
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>>;
|
||||
/// Check remote storage read proof.
|
||||
fn check_read_child_proof(
|
||||
&self,
|
||||
request: &RemoteReadChildRequest<Block::Header>,
|
||||
remote_proof: Vec<Vec<u8>>
|
||||
) -> ClientResult<Option<Vec<u8>>>;
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>>;
|
||||
/// Check remote method execution proof.
|
||||
fn check_execution_proof(
|
||||
&self,
|
||||
@@ -395,23 +395,26 @@ impl<E, Block, H, S> FetchChecker<Block> for LightDataChecker<E, H, Block, S>
|
||||
fn check_read_proof(
|
||||
&self,
|
||||
request: &RemoteReadRequest<Block::Header>,
|
||||
remote_proof: Vec<Vec<u8>>
|
||||
) -> ClientResult<Option<Vec<u8>>> {
|
||||
read_proof_check::<H>(convert_hash(request.header.state_root()), remote_proof, &request.key)
|
||||
.map_err(Into::into)
|
||||
remote_proof: Vec<Vec<u8>>,
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>> {
|
||||
read_proof_check::<H, _>(
|
||||
convert_hash(request.header.state_root()),
|
||||
remote_proof,
|
||||
request.keys.iter(),
|
||||
).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn check_read_child_proof(
|
||||
&self,
|
||||
request: &RemoteReadChildRequest<Block::Header>,
|
||||
remote_proof: Vec<Vec<u8>>
|
||||
) -> ClientResult<Option<Vec<u8>>> {
|
||||
read_child_proof_check::<H>(
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>> {
|
||||
read_child_proof_check::<H, _>(
|
||||
convert_hash(request.header.state_root()),
|
||||
remote_proof,
|
||||
&request.storage_key,
|
||||
&request.key)
|
||||
.map_err(Into::into)
|
||||
request.keys.iter(),
|
||||
).map_err(Into::into)
|
||||
}
|
||||
|
||||
fn check_execution_proof(
|
||||
@@ -529,7 +532,7 @@ pub mod tests {
|
||||
|
||||
impl Fetcher<Block> for OkCallFetcher {
|
||||
type RemoteHeaderResult = Ready<Result<Header, ClientError>>;
|
||||
type RemoteReadResult = Ready<Result<Option<Vec<u8>>, ClientError>>;
|
||||
type RemoteReadResult = Ready<Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>;
|
||||
type RemoteCallResult = Ready<Result<Vec<u8>, ClientError>>;
|
||||
type RemoteChangesResult = Ready<Result<Vec<(NumberFor<Block>, u32)>, ClientError>>;
|
||||
type RemoteBodyResult = Ready<Result<Vec<Extrinsic>, ClientError>>;
|
||||
@@ -579,7 +582,10 @@ pub mod tests {
|
||||
let heap_pages = remote_client.storage(&remote_block_id, &StorageKey(well_known_keys::HEAP_PAGES.to_vec()))
|
||||
.unwrap()
|
||||
.and_then(|v| Decode::decode(&mut &v.0[..]).ok()).unwrap();
|
||||
let remote_read_proof = remote_client.read_proof(&remote_block_id, well_known_keys::HEAP_PAGES).unwrap();
|
||||
let remote_read_proof = remote_client.read_proof(
|
||||
&remote_block_id,
|
||||
&[well_known_keys::HEAP_PAGES],
|
||||
).unwrap();
|
||||
|
||||
// check remote read proof locally
|
||||
let local_storage = InMemoryBlockchain::<Block>::new();
|
||||
@@ -618,7 +624,7 @@ pub mod tests {
|
||||
let remote_read_proof = remote_client.read_child_proof(
|
||||
&remote_block_id,
|
||||
b":child_storage:default:child1",
|
||||
b"key1",
|
||||
&[b"key1"],
|
||||
).unwrap();
|
||||
|
||||
// check locally
|
||||
@@ -676,9 +682,9 @@ pub mod tests {
|
||||
assert_eq!((&local_checker as &dyn FetchChecker<Block>).check_read_proof(&RemoteReadRequest::<Header> {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
key: well_known_keys::HEAP_PAGES.to_vec(),
|
||||
keys: vec![well_known_keys::HEAP_PAGES.to_vec()],
|
||||
retry_count: None,
|
||||
}, remote_read_proof).unwrap().unwrap()[0], heap_pages as u8);
|
||||
}, remote_read_proof).unwrap().remove(well_known_keys::HEAP_PAGES).unwrap().unwrap()[0], heap_pages as u8);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -694,11 +700,11 @@ pub mod tests {
|
||||
block: remote_block_header.hash(),
|
||||
header: remote_block_header,
|
||||
storage_key: b":child_storage:default:child1".to_vec(),
|
||||
key: b"key1".to_vec(),
|
||||
keys: vec![b"key1".to_vec()],
|
||||
retry_count: None,
|
||||
},
|
||||
remote_read_proof
|
||||
).unwrap().unwrap(), result);
|
||||
).unwrap().remove(b"key1".as_ref()).unwrap().unwrap(), result);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -49,10 +49,15 @@ pub trait Client<Block: BlockT>: Send + Sync {
|
||||
fn header_proof(&self, block_number: <Block::Header as HeaderT>::Number) -> Result<(Block::Header, Vec<Vec<u8>>), Error>;
|
||||
|
||||
/// Get storage read execution proof.
|
||||
fn read_proof(&self, block: &Block::Hash, key: &[u8]) -> Result<Vec<Vec<u8>>, Error>;
|
||||
fn read_proof(&self, block: &Block::Hash, keys: &[Vec<u8>]) -> Result<Vec<Vec<u8>>, Error>;
|
||||
|
||||
/// Get child storage read execution proof.
|
||||
fn read_child_proof(&self, block: &Block::Hash, storage_key: &[u8], key: &[u8]) -> Result<Vec<Vec<u8>>, Error>;
|
||||
fn read_child_proof(
|
||||
&self,
|
||||
block: &Block::Hash,
|
||||
storage_key: &[u8],
|
||||
keys: &[Vec<u8>],
|
||||
) -> Result<Vec<Vec<u8>>, Error>;
|
||||
|
||||
/// Get method execution proof.
|
||||
fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec<u8>, Vec<Vec<u8>>), Error>;
|
||||
@@ -113,18 +118,18 @@ impl<B, E, Block, RA> Client<Block> for SubstrateClient<B, E, Block, RA> where
|
||||
(self as &SubstrateClient<B, E, Block, RA>).header_proof(&BlockId::Number(block_number))
|
||||
}
|
||||
|
||||
fn read_proof(&self, block: &Block::Hash, key: &[u8]) -> Result<Vec<Vec<u8>>, Error> {
|
||||
(self as &SubstrateClient<B, E, Block, RA>).read_proof(&BlockId::Hash(block.clone()), key)
|
||||
fn read_proof(&self, block: &Block::Hash, keys: &[Vec<u8>]) -> Result<Vec<Vec<u8>>, Error> {
|
||||
(self as &SubstrateClient<B, E, Block, RA>).read_proof(&BlockId::Hash(block.clone()), keys)
|
||||
}
|
||||
|
||||
fn read_child_proof(
|
||||
&self,
|
||||
block: &Block::Hash,
|
||||
storage_key: &[u8],
|
||||
key: &[u8]
|
||||
keys: &[Vec<u8>],
|
||||
) -> Result<Vec<Vec<u8>>, Error> {
|
||||
(self as &SubstrateClient<B, E, Block, RA>)
|
||||
.read_child_proof(&BlockId::Hash(block.clone()), storage_key, key)
|
||||
.read_child_proof(&BlockId::Hash(block.clone()), storage_key, keys)
|
||||
}
|
||||
|
||||
fn execution_proof(&self, block: &Block::Hash, method: &str, data: &[u8]) -> Result<(Vec<u8>, Vec<Vec<u8>>), Error> {
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
//! On-demand requests service.
|
||||
|
||||
use crate::protocol::light_dispatch::RequestData;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use futures::{prelude::*, sync::mpsc, sync::oneshot};
|
||||
use futures03::compat::{Compat01As03, Future01CompatExt as _};
|
||||
@@ -84,7 +85,7 @@ impl<B> Fetcher<B> for OnDemand<B> where
|
||||
B::Header: HeaderT,
|
||||
{
|
||||
type RemoteHeaderResult = Compat01As03<RemoteResponse<B::Header>>;
|
||||
type RemoteReadResult = Compat01As03<RemoteResponse<Option<Vec<u8>>>>;
|
||||
type RemoteReadResult = Compat01As03<RemoteResponse<HashMap<Vec<u8>, Option<Vec<u8>>>>>;
|
||||
type RemoteCallResult = Compat01As03<RemoteResponse<Vec<u8>>>;
|
||||
type RemoteChangesResult = Compat01As03<RemoteResponse<Vec<(NumberFor<B>, u32)>>>;
|
||||
type RemoteBodyResult = Compat01As03<RemoteResponse<Vec<B::Extrinsic>>>;
|
||||
|
||||
@@ -172,11 +172,17 @@ impl<'a, B: BlockT> LightDispatchNetwork<B> for LightDispatchIn<'a, B> {
|
||||
self.behaviour.send_packet(who, message)
|
||||
}
|
||||
|
||||
fn send_read_request(&mut self, who: &PeerId, id: RequestId, block: <B as BlockT>::Hash, key: Vec<u8>) {
|
||||
fn send_read_request(
|
||||
&mut self,
|
||||
who: &PeerId,
|
||||
id: RequestId,
|
||||
block: <B as BlockT>::Hash,
|
||||
keys: Vec<Vec<u8>>,
|
||||
) {
|
||||
let message = message::generic::Message::RemoteReadRequest(message::RemoteReadRequest {
|
||||
id,
|
||||
block,
|
||||
key,
|
||||
keys,
|
||||
});
|
||||
|
||||
self.behaviour.send_packet(who, message)
|
||||
@@ -188,13 +194,13 @@ impl<'a, B: BlockT> LightDispatchNetwork<B> for LightDispatchIn<'a, B> {
|
||||
id: RequestId,
|
||||
block: <B as BlockT>::Hash,
|
||||
storage_key: Vec<u8>,
|
||||
key: Vec<u8>
|
||||
keys: Vec<Vec<u8>>,
|
||||
) {
|
||||
let message = message::generic::Message::RemoteReadChildRequest(message::RemoteReadChildRequest {
|
||||
id,
|
||||
block,
|
||||
storage_key,
|
||||
key,
|
||||
keys,
|
||||
});
|
||||
|
||||
self.behaviour.send_packet(who, message)
|
||||
@@ -1272,15 +1278,24 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
|
||||
who: PeerId,
|
||||
request: message::RemoteReadRequest<B::Hash>,
|
||||
) {
|
||||
let keys_str = || match request.keys.len() {
|
||||
1 => request.keys[0].to_hex::<String>(),
|
||||
_ => format!(
|
||||
"{}..{}",
|
||||
request.keys[0].to_hex::<String>(),
|
||||
request.keys[request.keys.len() - 1].to_hex::<String>(),
|
||||
),
|
||||
};
|
||||
|
||||
trace!(target: "sync", "Remote read request {} from {} ({} at {})",
|
||||
request.id, who, request.key.to_hex::<String>(), request.block);
|
||||
let proof = match self.context_data.chain.read_proof(&request.block, &request.key) {
|
||||
request.id, who, keys_str(), request.block);
|
||||
let proof = match self.context_data.chain.read_proof(&request.block, &request.keys) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
trace!(target: "sync", "Remote read request {} from {} ({} at {}) failed with: {}",
|
||||
request.id,
|
||||
who,
|
||||
request.key.to_hex::<String>(),
|
||||
keys_str(),
|
||||
request.block,
|
||||
error
|
||||
);
|
||||
@@ -1301,16 +1316,29 @@ impl<B: BlockT, S: NetworkSpecialization<B>, H: ExHashT> Protocol<B, S, H> {
|
||||
who: PeerId,
|
||||
request: message::RemoteReadChildRequest<B::Hash>,
|
||||
) {
|
||||
let keys_str = || match request.keys.len() {
|
||||
1 => request.keys[0].to_hex::<String>(),
|
||||
_ => format!(
|
||||
"{}..{}",
|
||||
request.keys[0].to_hex::<String>(),
|
||||
request.keys[request.keys.len() - 1].to_hex::<String>(),
|
||||
),
|
||||
};
|
||||
|
||||
trace!(target: "sync", "Remote read child request {} from {} ({} {} at {})",
|
||||
request.id, who, request.storage_key.to_hex::<String>(), request.key.to_hex::<String>(), request.block);
|
||||
let proof = match self.context_data.chain.read_child_proof(&request.block, &request.storage_key, &request.key) {
|
||||
request.id, who, request.storage_key.to_hex::<String>(), keys_str(), request.block);
|
||||
let proof = match self.context_data.chain.read_child_proof(
|
||||
&request.block,
|
||||
&request.storage_key,
|
||||
&request.keys,
|
||||
) {
|
||||
Ok(proof) => proof,
|
||||
Err(error) => {
|
||||
trace!(target: "sync", "Remote read child request {} from {} ({} {} at {}) failed with: {}",
|
||||
request.id,
|
||||
who,
|
||||
request.storage_key.to_hex::<String>(),
|
||||
request.key.to_hex::<String>(),
|
||||
keys_str(),
|
||||
request.block,
|
||||
error
|
||||
);
|
||||
|
||||
@@ -53,7 +53,13 @@ pub trait LightDispatchNetwork<B: BlockT> {
|
||||
fn send_header_request(&mut self, who: &PeerId, id: RequestId, block: <<B as BlockT>::Header as HeaderT>::Number);
|
||||
|
||||
/// Send to `who` a read request.
|
||||
fn send_read_request(&mut self, who: &PeerId, id: RequestId, block: <B as BlockT>::Hash, key: Vec<u8>);
|
||||
fn send_read_request(
|
||||
&mut self,
|
||||
who: &PeerId,
|
||||
id: RequestId,
|
||||
block: <B as BlockT>::Hash,
|
||||
keys: Vec<Vec<u8>>,
|
||||
);
|
||||
|
||||
/// Send to `who` a child read request.
|
||||
fn send_read_child_request(
|
||||
@@ -62,7 +68,7 @@ pub trait LightDispatchNetwork<B: BlockT> {
|
||||
id: RequestId,
|
||||
block: <B as BlockT>::Hash,
|
||||
storage_key: Vec<u8>,
|
||||
key: Vec<u8>
|
||||
keys: Vec<Vec<u8>>,
|
||||
);
|
||||
|
||||
/// Send to `who` a call request.
|
||||
@@ -135,10 +141,13 @@ struct Request<Block: BlockT> {
|
||||
pub(crate) enum RequestData<Block: BlockT> {
|
||||
RemoteBody(RemoteBodyRequest<Block::Header>, OneShotSender<Result<Vec<Block::Extrinsic>, ClientError>>),
|
||||
RemoteHeader(RemoteHeaderRequest<Block::Header>, OneShotSender<Result<Block::Header, ClientError>>),
|
||||
RemoteRead(RemoteReadRequest<Block::Header>, OneShotSender<Result<Option<Vec<u8>>, ClientError>>),
|
||||
RemoteRead(
|
||||
RemoteReadRequest<Block::Header>,
|
||||
OneShotSender<Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>,
|
||||
),
|
||||
RemoteReadChild(
|
||||
RemoteReadChildRequest<Block::Header>,
|
||||
OneShotSender<Result<Option<Vec<u8>>, ClientError>>
|
||||
OneShotSender<Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError>>
|
||||
),
|
||||
RemoteCall(RemoteCallRequest<Block::Header>, OneShotSender<Result<Vec<u8>, ClientError>>),
|
||||
RemoteChanges(
|
||||
@@ -174,7 +183,7 @@ impl<Block: BlockT> FetchChecker<Block> for AlwaysBadChecker {
|
||||
&self,
|
||||
_request: &RemoteReadRequest<Block::Header>,
|
||||
_remote_proof: Vec<Vec<u8>>
|
||||
) -> Result<Option<Vec<u8>>, ClientError> {
|
||||
) -> Result<HashMap<Vec<u8>,Option<Vec<u8>>>, ClientError> {
|
||||
Err(ClientError::Msg("AlwaysBadChecker".into()))
|
||||
}
|
||||
|
||||
@@ -182,7 +191,7 @@ impl<Block: BlockT> FetchChecker<Block> for AlwaysBadChecker {
|
||||
&self,
|
||||
_request: &RemoteReadChildRequest<Block::Header>,
|
||||
_remote_proof: Vec<Vec<u8>>
|
||||
) -> Result<Option<Vec<u8>>, ClientError> {
|
||||
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, ClientError> {
|
||||
Err(ClientError::Msg("AlwaysBadChecker".into()))
|
||||
}
|
||||
|
||||
@@ -604,7 +613,7 @@ impl<Block: BlockT> Request<Block> {
|
||||
peer,
|
||||
self.id,
|
||||
data.block,
|
||||
data.key.clone(),
|
||||
data.keys.clone(),
|
||||
),
|
||||
RequestData::RemoteReadChild(ref data, _) =>
|
||||
out.send_read_child_request(
|
||||
@@ -612,7 +621,7 @@ impl<Block: BlockT> Request<Block> {
|
||||
self.id,
|
||||
data.block,
|
||||
data.storage_key.clone(),
|
||||
data.key.clone(),
|
||||
data.keys.clone(),
|
||||
),
|
||||
RequestData::RemoteCall(ref data, _) =>
|
||||
out.send_call_request(
|
||||
@@ -663,7 +672,7 @@ impl<Block: BlockT> RequestData<Block> {
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::collections::HashSet;
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
use futures::{Future, sync::oneshot};
|
||||
@@ -693,20 +702,34 @@ pub mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
fn check_read_proof(&self, _: &RemoteReadRequest<Header>, _: Vec<Vec<u8>>) -> ClientResult<Option<Vec<u8>>> {
|
||||
fn check_read_proof(
|
||||
&self,
|
||||
request: &RemoteReadRequest<Header>,
|
||||
_: Vec<Vec<u8>>,
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>> {
|
||||
match self.ok {
|
||||
true => Ok(Some(vec![42])),
|
||||
true => Ok(request.keys
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|k| (k, Some(vec![42])))
|
||||
.collect()
|
||||
),
|
||||
false => Err(ClientError::Backend("Test error".into())),
|
||||
}
|
||||
}
|
||||
|
||||
fn check_read_child_proof(
|
||||
&self,
|
||||
_: &RemoteReadChildRequest<Header>,
|
||||
request: &RemoteReadChildRequest<Header>,
|
||||
_: Vec<Vec<u8>>
|
||||
) -> ClientResult<Option<Vec<u8>>> {
|
||||
) -> ClientResult<HashMap<Vec<u8>, Option<Vec<u8>>>> {
|
||||
match self.ok {
|
||||
true => Ok(Some(vec![42])),
|
||||
true => Ok(request.keys
|
||||
.iter()
|
||||
.cloned()
|
||||
.map(|k| (k, Some(vec![42])))
|
||||
.collect()
|
||||
),
|
||||
false => Err(ClientError::Backend("Test error".into())),
|
||||
}
|
||||
}
|
||||
@@ -782,9 +805,9 @@ pub mod tests {
|
||||
self.disconnected_peers.insert(who.clone());
|
||||
}
|
||||
fn send_header_request(&mut self, _: &PeerId, _: RequestId, _: <<B as BlockT>::Header as HeaderT>::Number) {}
|
||||
fn send_read_request(&mut self, _: &PeerId, _: RequestId, _: <B as BlockT>::Hash, _: Vec<u8>) {}
|
||||
fn send_read_request(&mut self, _: &PeerId, _: RequestId, _: <B as BlockT>::Hash, _: Vec<Vec<u8>>) {}
|
||||
fn send_read_child_request(&mut self, _: &PeerId, _: RequestId, _: <B as BlockT>::Hash, _: Vec<u8>,
|
||||
_: Vec<u8>) {}
|
||||
_: Vec<Vec<u8>>) {}
|
||||
fn send_call_request(&mut self, _: &PeerId, _: RequestId, _: <B as BlockT>::Hash, _: String, _: Vec<u8>) {}
|
||||
fn send_changes_request(&mut self, _: &PeerId, _: RequestId, _: <B as BlockT>::Hash, _: <B as BlockT>::Hash,
|
||||
_: <B as BlockT>::Hash, _: <B as BlockT>::Hash, _: Option<Vec<u8>>, _: Vec<u8>) {}
|
||||
@@ -984,7 +1007,7 @@ pub mod tests {
|
||||
light_dispatch.add_request(&mut network_interface, RequestData::RemoteRead(RemoteReadRequest {
|
||||
header: dummy_header(),
|
||||
block: Default::default(),
|
||||
key: b":key".to_vec(),
|
||||
keys: vec![b":key".to_vec()],
|
||||
retry_count: None,
|
||||
}, tx));
|
||||
|
||||
@@ -992,7 +1015,7 @@ pub mod tests {
|
||||
id: 0,
|
||||
proof: vec![vec![2]],
|
||||
});
|
||||
assert_eq!(response.wait().unwrap().unwrap(), Some(vec![42]));
|
||||
assert_eq!(response.wait().unwrap().unwrap().remove(b":key".as_ref()).unwrap(), Some(vec![42]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1007,7 +1030,7 @@ pub mod tests {
|
||||
header: dummy_header(),
|
||||
block: Default::default(),
|
||||
storage_key: b":child_storage:sub".to_vec(),
|
||||
key: b":key".to_vec(),
|
||||
keys: vec![b":key".to_vec()],
|
||||
retry_count: None,
|
||||
}, tx));
|
||||
|
||||
@@ -1016,7 +1039,7 @@ pub mod tests {
|
||||
id: 0,
|
||||
proof: vec![vec![2]],
|
||||
});
|
||||
assert_eq!(response.wait().unwrap().unwrap(), Some(vec![42]));
|
||||
assert_eq!(response.wait().unwrap().unwrap().remove(b":key".as_ref()).unwrap(), Some(vec![42]));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -284,7 +284,7 @@ pub mod generic {
|
||||
/// Block at which to perform call.
|
||||
pub block: H,
|
||||
/// Storage key.
|
||||
pub key: Vec<u8>,
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
|
||||
@@ -297,7 +297,7 @@ pub mod generic {
|
||||
/// Child Storage key.
|
||||
pub storage_key: Vec<u8>,
|
||||
/// Storage key.
|
||||
pub key: Vec<u8>,
|
||||
pub keys: Vec<Vec<u8>>,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone, Encode, Decode)]
|
||||
|
||||
@@ -153,9 +153,16 @@ impl<Block, F, B, E, RA> StateBackend<B, E, Block, RA> for LightState<Block, F,
|
||||
Ok(header) => Either::Left(fetcher.remote_read(RemoteReadRequest {
|
||||
block: header.hash(),
|
||||
header,
|
||||
key: key.0,
|
||||
keys: vec![key.0.clone()],
|
||||
retry_count: Default::default(),
|
||||
}).then(|result| ready(result.map(|data| data.map(StorageData)).map_err(client_err)))),
|
||||
}).then(move |result| ready(result
|
||||
.map(|mut data| data
|
||||
.remove(&key.0)
|
||||
.expect("successful result has entry for all keys; qed")
|
||||
.map(StorageData)
|
||||
)
|
||||
.map_err(client_err)
|
||||
))),
|
||||
Err(error) => Either::Right(ready(Err(error))),
|
||||
});
|
||||
|
||||
@@ -197,9 +204,16 @@ impl<Block, F, B, E, RA> StateBackend<B, E, Block, RA> for LightState<Block, F,
|
||||
block: header.hash(),
|
||||
header,
|
||||
storage_key: child_storage_key.0,
|
||||
key: key.0,
|
||||
keys: vec![key.0.clone()],
|
||||
retry_count: Default::default(),
|
||||
}).then(|result| ready(result.map(|data| data.map(StorageData)).map_err(client_err)))),
|
||||
}).then(move |result| ready(result
|
||||
.map(|mut data| data
|
||||
.remove(&key.0)
|
||||
.expect("successful result has entry for all keys; qed")
|
||||
.map(StorageData)
|
||||
)
|
||||
.map_err(client_err)
|
||||
))),
|
||||
Err(error) => Either::Right(ready(Err(error))),
|
||||
});
|
||||
|
||||
|
||||
@@ -18,7 +18,10 @@
|
||||
|
||||
#![warn(missing_docs)]
|
||||
|
||||
use std::{fmt, panic::UnwindSafe, result, marker::PhantomData};
|
||||
use std::{
|
||||
fmt, result, collections::HashMap,
|
||||
marker::PhantomData, panic::UnwindSafe,
|
||||
};
|
||||
use log::warn;
|
||||
use hash_db::Hasher;
|
||||
use codec::{Decode, Encode};
|
||||
@@ -524,97 +527,130 @@ where
|
||||
}
|
||||
|
||||
/// Generate storage read proof.
|
||||
pub fn prove_read<B, H>(
|
||||
pub fn prove_read<B, H, I>(
|
||||
mut backend: B,
|
||||
key: &[u8]
|
||||
) -> Result<(Option<Vec<u8>>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
where
|
||||
B: Backend<H>,
|
||||
H: Hasher,
|
||||
H::Out: Ord,
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
let trie_backend = backend.as_trie_backend()
|
||||
.ok_or_else(
|
||||
|| Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>
|
||||
)?;
|
||||
prove_read_on_trie_backend(trie_backend, key)
|
||||
prove_read_on_trie_backend(trie_backend, keys)
|
||||
}
|
||||
|
||||
/// Generate child storage read proof.
|
||||
pub fn prove_child_read<B, H>(
|
||||
pub fn prove_child_read<B, H, I>(
|
||||
mut backend: B,
|
||||
storage_key: &[u8],
|
||||
key: &[u8],
|
||||
) -> Result<(Option<Vec<u8>>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
where
|
||||
B: Backend<H>,
|
||||
H: Hasher,
|
||||
H::Out: Ord,
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
let trie_backend = backend.as_trie_backend()
|
||||
.ok_or_else(|| Box::new(ExecutionError::UnableToGenerateProof) as Box<dyn Error>)?;
|
||||
prove_child_read_on_trie_backend(trie_backend, storage_key, key)
|
||||
prove_child_read_on_trie_backend(trie_backend, storage_key, keys)
|
||||
}
|
||||
|
||||
/// Generate storage read proof on pre-created trie backend.
|
||||
pub fn prove_read_on_trie_backend<S, H>(
|
||||
pub fn prove_read_on_trie_backend<S, H, I>(
|
||||
trie_backend: &TrieBackend<S, H>,
|
||||
key: &[u8]
|
||||
) -> Result<(Option<Vec<u8>>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
H: Hasher,
|
||||
H::Out: Ord,
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend);
|
||||
let result = proving_backend.storage(key).map_err(|e| Box::new(e) as Box<dyn Error>)?;
|
||||
Ok((result, proving_backend.extract_proof()))
|
||||
for key in keys.into_iter() {
|
||||
proving_backend
|
||||
.storage(key.as_ref())
|
||||
.map_err(|e| Box::new(e) as Box<dyn Error>)?;
|
||||
}
|
||||
Ok(proving_backend.extract_proof())
|
||||
}
|
||||
|
||||
/// Generate storage read proof on pre-created trie backend.
|
||||
pub fn prove_child_read_on_trie_backend<S, H>(
|
||||
pub fn prove_child_read_on_trie_backend<S, H, I>(
|
||||
trie_backend: &TrieBackend<S, H>,
|
||||
storage_key: &[u8],
|
||||
key: &[u8]
|
||||
) -> Result<(Option<Vec<u8>>, Vec<Vec<u8>>), Box<dyn Error>>
|
||||
keys: I,
|
||||
) -> Result<Vec<Vec<u8>>, Box<dyn Error>>
|
||||
where
|
||||
S: trie_backend_essence::TrieBackendStorage<H>,
|
||||
H: Hasher,
|
||||
H::Out: Ord,
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
let proving_backend = proving_backend::ProvingBackend::<_, H>::new(trie_backend);
|
||||
let result = proving_backend.child_storage(storage_key, key)
|
||||
.map_err(|e| Box::new(e) as Box<dyn Error>)?;
|
||||
Ok((result, proving_backend.extract_proof()))
|
||||
for key in keys.into_iter() {
|
||||
proving_backend
|
||||
.child_storage(storage_key, key.as_ref())
|
||||
.map_err(|e| Box::new(e) as Box<dyn Error>)?;
|
||||
}
|
||||
Ok(proving_backend.extract_proof())
|
||||
}
|
||||
|
||||
/// Check storage read proof, generated by `prove_read` call.
|
||||
pub fn read_proof_check<H>(
|
||||
pub fn read_proof_check<H, I>(
|
||||
root: H::Out,
|
||||
proof: Vec<Vec<u8>>,
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Box<dyn Error>>
|
||||
keys: I,
|
||||
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, Box<dyn Error>>
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Ord,
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
let proving_backend = create_proof_check_backend::<H>(root, proof)?;
|
||||
read_proof_check_on_proving_backend(&proving_backend, key)
|
||||
let mut result = HashMap::new();
|
||||
for key in keys.into_iter() {
|
||||
let value = read_proof_check_on_proving_backend(&proving_backend, key.as_ref())?;
|
||||
result.insert(key.as_ref().to_vec(), value);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Check child storage read proof, generated by `prove_child_read` call.
|
||||
pub fn read_child_proof_check<H>(
|
||||
pub fn read_child_proof_check<H, I>(
|
||||
root: H::Out,
|
||||
proof: Vec<Vec<u8>>,
|
||||
storage_key: &[u8],
|
||||
key: &[u8],
|
||||
) -> Result<Option<Vec<u8>>, Box<dyn Error>>
|
||||
keys: I,
|
||||
) -> Result<HashMap<Vec<u8>, Option<Vec<u8>>>, Box<dyn Error>>
|
||||
where
|
||||
H: Hasher,
|
||||
H::Out: Ord,
|
||||
I: IntoIterator,
|
||||
I::Item: AsRef<[u8]>,
|
||||
{
|
||||
let proving_backend = create_proof_check_backend::<H>(root, proof)?;
|
||||
read_child_proof_check_on_proving_backend(&proving_backend, storage_key, key)
|
||||
let mut result = HashMap::new();
|
||||
for key in keys.into_iter() {
|
||||
let value = read_child_proof_check_on_proving_backend(
|
||||
&proving_backend,
|
||||
storage_key,
|
||||
key.as_ref(),
|
||||
)?;
|
||||
result.insert(key.as_ref().to_vec(), value);
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Check storage read proof on pre-created proving backend.
|
||||
@@ -963,20 +999,23 @@ mod tests {
|
||||
// fetch read proof from 'remote' full node
|
||||
let remote_backend = trie_backend::tests::test_trie();
|
||||
let remote_root = remote_backend.storage_root(::std::iter::empty()).0;
|
||||
let remote_proof = prove_read(remote_backend, b"value2").unwrap().1;
|
||||
let remote_proof = prove_read(remote_backend, &[b"value2"]).unwrap();
|
||||
// check proof locally
|
||||
let local_result1 = read_proof_check::<Blake2Hasher>(
|
||||
let local_result1 = read_proof_check::<Blake2Hasher, _>(
|
||||
remote_root,
|
||||
remote_proof.clone(),
|
||||
b"value2"
|
||||
&[b"value2"],
|
||||
).unwrap();
|
||||
let local_result2 = read_proof_check::<Blake2Hasher>(
|
||||
let local_result2 = read_proof_check::<Blake2Hasher, _>(
|
||||
remote_root,
|
||||
remote_proof.clone(),
|
||||
&[0xff]
|
||||
&[&[0xff]],
|
||||
).is_ok();
|
||||
// check that results are correct
|
||||
assert_eq!(local_result1, Some(vec![24]));
|
||||
assert_eq!(
|
||||
local_result1.into_iter().collect::<Vec<_>>(),
|
||||
vec![(b"value2".to_vec(), Some(vec![24]))],
|
||||
);
|
||||
assert_eq!(local_result2, false);
|
||||
// on child trie
|
||||
let remote_backend = trie_backend::tests::test_trie();
|
||||
@@ -984,21 +1023,28 @@ mod tests {
|
||||
let remote_proof = prove_child_read(
|
||||
remote_backend,
|
||||
b":child_storage:default:sub1",
|
||||
b"value3"
|
||||
).unwrap().1;
|
||||
let local_result1 = read_child_proof_check::<Blake2Hasher>(
|
||||
remote_root,
|
||||
remote_proof.clone(),
|
||||
b":child_storage:default:sub1",b"value3"
|
||||
&[b"value3"],
|
||||
).unwrap();
|
||||
let local_result2 = read_child_proof_check::<Blake2Hasher>(
|
||||
let local_result1 = read_child_proof_check::<Blake2Hasher, _>(
|
||||
remote_root,
|
||||
remote_proof.clone(),
|
||||
b":child_storage:default:sub1",
|
||||
b"value2"
|
||||
&[b"value3"],
|
||||
).unwrap();
|
||||
assert_eq!(local_result1, Some(vec![142]));
|
||||
assert_eq!(local_result2, None);
|
||||
let local_result2 = read_child_proof_check::<Blake2Hasher, _>(
|
||||
remote_root,
|
||||
remote_proof.clone(),
|
||||
b":child_storage:default:sub1",
|
||||
&[b"value2"],
|
||||
).unwrap();
|
||||
assert_eq!(
|
||||
local_result1.into_iter().collect::<Vec<_>>(),
|
||||
vec![(b"value3".to_vec(), Some(vec![142]))],
|
||||
);
|
||||
assert_eq!(
|
||||
local_result2.into_iter().collect::<Vec<_>>(),
|
||||
vec![(b"value2".to_vec(), None)],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -36,12 +36,9 @@ pub use state_machine::ExecutionStrategy;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::collections::HashMap;
|
||||
use futures::future::Ready;
|
||||
use hash_db::Hasher;
|
||||
use primitives::storage::well_known_keys;
|
||||
use sr_primitives::traits::{
|
||||
Block as BlockT, NumberFor
|
||||
};
|
||||
use sr_primitives::traits::Block as BlockT;
|
||||
use client::LocalCallExecutor;
|
||||
|
||||
/// Test client light database backend.
|
||||
@@ -50,9 +47,6 @@ pub type LightBackend<Block> = client::light::backend::Backend<
|
||||
Blake2Hasher,
|
||||
>;
|
||||
|
||||
/// Test client light fetcher.
|
||||
pub struct LightFetcher;
|
||||
|
||||
/// A genesis storage initialisation trait.
|
||||
pub trait GenesisInit: Default {
|
||||
/// Construct genesis storage.
|
||||
@@ -231,53 +225,3 @@ impl<E, Backend, G: GenesisInit> TestClientBuilder<
|
||||
self.build_with_executor(executor)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block: BlockT> client::light::fetcher::Fetcher<Block> for LightFetcher {
|
||||
type RemoteHeaderResult = Ready<Result<Block::Header, client::error::Error>>;
|
||||
type RemoteReadResult = Ready<Result<Option<Vec<u8>>, client::error::Error>>;
|
||||
type RemoteCallResult = Ready<Result<Vec<u8>, client::error::Error>>;
|
||||
type RemoteChangesResult = Ready<Result<Vec<(NumberFor<Block>, u32)>, client::error::Error>>;
|
||||
type RemoteBodyResult = Ready<Result<Vec<Block::Extrinsic>, client::error::Error>>;
|
||||
|
||||
fn remote_header(
|
||||
&self,
|
||||
_request: client::light::fetcher::RemoteHeaderRequest<Block::Header>,
|
||||
) -> Self::RemoteHeaderResult {
|
||||
unimplemented!("not (yet) used in tests")
|
||||
}
|
||||
|
||||
fn remote_read(
|
||||
&self,
|
||||
_request: client::light::fetcher::RemoteReadRequest<Block::Header>,
|
||||
) -> Self::RemoteReadResult {
|
||||
unimplemented!("not (yet) used in tests")
|
||||
}
|
||||
|
||||
fn remote_read_child(
|
||||
&self,
|
||||
_request: client::light::fetcher::RemoteReadChildRequest<Block::Header>,
|
||||
) -> Self::RemoteReadResult {
|
||||
unimplemented!("not (yet) used in tests")
|
||||
}
|
||||
|
||||
fn remote_call(
|
||||
&self,
|
||||
_request: client::light::fetcher::RemoteCallRequest<Block::Header>,
|
||||
) -> Self::RemoteCallResult {
|
||||
unimplemented!("not (yet) used in tests")
|
||||
}
|
||||
|
||||
fn remote_changes(
|
||||
&self,
|
||||
_request: client::light::fetcher::RemoteChangesRequest<Block::Header>,
|
||||
) -> Self::RemoteChangesResult {
|
||||
unimplemented!("not (yet) used in tests")
|
||||
}
|
||||
|
||||
fn remote_body(
|
||||
&self,
|
||||
_request: client::light::fetcher::RemoteBodyRequest<Block::Header>,
|
||||
) -> Self::RemoteBodyResult {
|
||||
unimplemented!("not (yet) used in tests")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user