mirror of
https://github.com/pezkuwichain/pezkuwi-subxt.git
synced 2026-04-26 19:17:58 +00:00
Child trie api changes BREAKING (#4857)
Co-Authored-By: thiolliere <gui.thiolliere@gmail.com>
This commit is contained in:
@@ -28,7 +28,7 @@ use rpc::{Result as RpcResult, futures::{Future, future::result}};
|
||||
|
||||
use sc_rpc_api::Subscriptions;
|
||||
use sc_client::{light::{blockchain::RemoteBlockchain, fetcher::Fetcher}};
|
||||
use sp_core::{Bytes, storage::{StorageKey, StorageData, StorageChangeSet}};
|
||||
use sp_core::{Bytes, storage::{StorageKey, PrefixedStorageKey, StorageData, StorageChangeSet}};
|
||||
use sp_version::RuntimeVersion;
|
||||
use sp_runtime::traits::Block as BlockT;
|
||||
|
||||
@@ -37,6 +37,7 @@ use sp_api::{Metadata, ProvideRuntimeApi, CallApiAt};
|
||||
use self::error::{Error, FutureResult};
|
||||
|
||||
pub use sc_rpc_api::state::*;
|
||||
pub use sc_rpc_api::child_state::*;
|
||||
use sc_client_api::{ExecutorProvider, StorageProvider, BlockchainEvents, Backend};
|
||||
use sp_blockchain::{HeaderMetadata, HeaderBackend};
|
||||
|
||||
@@ -103,49 +104,6 @@ pub trait StateBackend<Block: BlockT, Client>: Send + Sync + 'static
|
||||
.map(|x| x.map(|x| x.0.len() as u64)))
|
||||
}
|
||||
|
||||
/// Returns the keys with prefix from a child storage, leave empty to get all the keys
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
prefix: StorageKey,
|
||||
) -> FutureResult<Vec<StorageKey>>;
|
||||
|
||||
/// Returns a child storage entry at a specific block's state.
|
||||
fn child_storage(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<StorageData>>;
|
||||
|
||||
/// Returns the hash of a child storage entry at a block's state.
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>>;
|
||||
|
||||
/// Returns the size of a child storage entry at a block's state.
|
||||
fn child_storage_size(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<u64>> {
|
||||
Box::new(self.child_storage(block, child_storage_key, child_info, child_type, key)
|
||||
.map(|x| x.map(|x| x.0.len() as u64)))
|
||||
}
|
||||
|
||||
/// Returns the runtime metadata as an opaque blob.
|
||||
fn metadata(&self, block: Option<Block::Hash>) -> FutureResult<Bytes>;
|
||||
|
||||
@@ -204,7 +162,7 @@ pub trait StateBackend<Block: BlockT, Client>: Send + Sync + 'static
|
||||
pub fn new_full<BE, Block: BlockT, Client>(
|
||||
client: Arc<Client>,
|
||||
subscriptions: Subscriptions,
|
||||
) -> State<Block, Client>
|
||||
) -> (State<Block, Client>, ChildState<Block, Client>)
|
||||
where
|
||||
Block: BlockT + 'static,
|
||||
BE: Backend<Block> + 'static,
|
||||
@@ -214,9 +172,11 @@ pub fn new_full<BE, Block: BlockT, Client>(
|
||||
+ ProvideRuntimeApi<Block> + Send + Sync + 'static,
|
||||
Client::Api: Metadata<Block, Error = sp_blockchain::Error>,
|
||||
{
|
||||
State {
|
||||
backend: Box::new(self::state_full::FullState::new(client, subscriptions)),
|
||||
}
|
||||
let child_backend = Box::new(
|
||||
self::state_full::FullState::new(client.clone(), subscriptions.clone())
|
||||
);
|
||||
let backend = Box::new(self::state_full::FullState::new(client, subscriptions));
|
||||
(State { backend }, ChildState { backend: child_backend })
|
||||
}
|
||||
|
||||
/// Create new state API that works on light node.
|
||||
@@ -225,7 +185,7 @@ pub fn new_light<BE, Block: BlockT, Client, F: Fetcher<Block>>(
|
||||
subscriptions: Subscriptions,
|
||||
remote_blockchain: Arc<dyn RemoteBlockchain<Block>>,
|
||||
fetcher: Arc<F>,
|
||||
) -> State<Block, Client>
|
||||
) -> (State<Block, Client>, ChildState<Block, Client>)
|
||||
where
|
||||
Block: BlockT + 'static,
|
||||
BE: Backend<Block> + 'static,
|
||||
@@ -235,14 +195,20 @@ pub fn new_light<BE, Block: BlockT, Client, F: Fetcher<Block>>(
|
||||
+ Send + Sync + 'static,
|
||||
F: Send + Sync + 'static,
|
||||
{
|
||||
State {
|
||||
backend: Box::new(self::state_light::LightState::new(
|
||||
let child_backend = Box::new(self::state_light::LightState::new(
|
||||
client.clone(),
|
||||
subscriptions.clone(),
|
||||
remote_blockchain.clone(),
|
||||
fetcher.clone(),
|
||||
));
|
||||
|
||||
let backend = Box::new(self::state_light::LightState::new(
|
||||
client,
|
||||
subscriptions,
|
||||
remote_blockchain,
|
||||
fetcher,
|
||||
)),
|
||||
}
|
||||
));
|
||||
(State { backend }, ChildState { backend: child_backend })
|
||||
}
|
||||
|
||||
/// State API with subscriptions support.
|
||||
@@ -307,50 +273,6 @@ impl<Block, Client> StateApi<Block::Hash> for State<Block, Client>
|
||||
self.backend.storage_size(block, key)
|
||||
}
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Option<StorageData>> {
|
||||
self.backend.child_storage(block, child_storage_key, child_info, child_type, key)
|
||||
}
|
||||
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key_prefix: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Vec<StorageKey>> {
|
||||
self.backend.child_storage_keys(block, child_storage_key, child_info, child_type, key_prefix)
|
||||
}
|
||||
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
self.backend.child_storage_hash(block, child_storage_key, child_info, child_type, key)
|
||||
}
|
||||
|
||||
fn child_storage_size(
|
||||
&self,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Option<u64>> {
|
||||
self.backend.child_storage_size(block, child_storage_key, child_info, child_type, key)
|
||||
}
|
||||
|
||||
fn metadata(&self, block: Option<Block::Hash>) -> FutureResult<Bytes> {
|
||||
self.backend.metadata(block)
|
||||
}
|
||||
@@ -402,12 +324,98 @@ impl<Block, Client> StateApi<Block::Hash> for State<Block, Client>
|
||||
}
|
||||
}
|
||||
|
||||
/// Child state backend API.
|
||||
pub trait ChildStateBackend<Block: BlockT, Client>: Send + Sync + 'static
|
||||
where
|
||||
Block: BlockT + 'static,
|
||||
Client: Send + Sync + 'static,
|
||||
{
|
||||
/// Returns the keys with prefix from a child storage,
|
||||
/// leave prefix empty to get all the keys.
|
||||
fn storage_keys(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
prefix: StorageKey,
|
||||
) -> FutureResult<Vec<StorageKey>>;
|
||||
|
||||
/// Returns a child storage entry at a specific block's state.
|
||||
fn storage(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<StorageData>>;
|
||||
|
||||
/// Returns the hash of a child storage entry at a block's state.
|
||||
fn storage_hash(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>>;
|
||||
|
||||
/// Returns the size of a child storage entry at a block's state.
|
||||
fn storage_size(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<u64>> {
|
||||
Box::new(self.storage(block, storage_key, key)
|
||||
.map(|x| x.map(|x| x.0.len() as u64)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Child state API with subscriptions support.
|
||||
pub struct ChildState<Block, Client> {
|
||||
backend: Box<dyn ChildStateBackend<Block, Client>>,
|
||||
}
|
||||
|
||||
impl<Block, Client> ChildStateApi<Block::Hash> for ChildState<Block, Client>
|
||||
where
|
||||
Block: BlockT + 'static,
|
||||
Client: Send + Sync + 'static,
|
||||
{
|
||||
type Metadata = crate::metadata::Metadata;
|
||||
|
||||
fn storage(
|
||||
&self,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Option<StorageData>> {
|
||||
self.backend.storage(block, storage_key, key)
|
||||
}
|
||||
|
||||
fn storage_keys(
|
||||
&self,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key_prefix: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Vec<StorageKey>> {
|
||||
self.backend.storage_keys(block, storage_key, key_prefix)
|
||||
}
|
||||
|
||||
fn storage_hash(
|
||||
&self,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
self.backend.storage_hash(block, storage_key, key)
|
||||
}
|
||||
|
||||
fn storage_size(
|
||||
&self,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
block: Option<Block::Hash>
|
||||
) -> FutureResult<Option<u64>> {
|
||||
self.backend.storage_size(block, storage_key, key)
|
||||
}
|
||||
}
|
||||
|
||||
fn client_err(err: sp_blockchain::Error) -> Error {
|
||||
Error::Client(Box::new(err))
|
||||
}
|
||||
|
||||
const CHILD_RESOLUTION_ERROR: &str = "Unexpected child info and type";
|
||||
|
||||
fn child_resolution_error() -> sp_blockchain::Error {
|
||||
sp_blockchain::Error::Msg(CHILD_RESOLUTION_ERROR.to_string())
|
||||
}
|
||||
|
||||
@@ -29,7 +29,8 @@ use sc_client_api::backend::Backend;
|
||||
use sp_blockchain::{Result as ClientResult, Error as ClientError, HeaderMetadata, CachedHeaderMetadata, HeaderBackend};
|
||||
use sc_client::BlockchainEvents;
|
||||
use sp_core::{
|
||||
Bytes, storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet, ChildInfo},
|
||||
Bytes, storage::{well_known_keys, StorageKey, StorageData, StorageChangeSet,
|
||||
ChildInfo, ChildType, PrefixedStorageKey},
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
use sp_runtime::{
|
||||
@@ -38,7 +39,7 @@ use sp_runtime::{
|
||||
|
||||
use sp_api::{Metadata, ProvideRuntimeApi, CallApiAt};
|
||||
|
||||
use super::{StateBackend, error::{FutureResult, Error, Result}, client_err, child_resolution_error};
|
||||
use super::{StateBackend, ChildStateBackend, error::{FutureResult, Error, Result}, client_err};
|
||||
use std::marker::PhantomData;
|
||||
use sc_client_api::{CallExecutor, StorageProvider, ExecutorProvider};
|
||||
|
||||
@@ -308,66 +309,6 @@ impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Cli
|
||||
.map_err(client_err)))
|
||||
}
|
||||
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
prefix: StorageKey,
|
||||
) -> FutureResult<Vec<StorageKey>> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
.and_then(|block| self.client.child_storage_keys(
|
||||
&BlockId::Hash(block),
|
||||
&child_storage_key,
|
||||
ChildInfo::resolve_child_info(child_type, &child_info.0[..])
|
||||
.ok_or_else(child_resolution_error)?,
|
||||
&prefix,
|
||||
))
|
||||
.map_err(client_err)))
|
||||
}
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<StorageData>> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
.and_then(|block| self.client.child_storage(
|
||||
&BlockId::Hash(block),
|
||||
&child_storage_key,
|
||||
ChildInfo::resolve_child_info(child_type, &child_info.0[..])
|
||||
.ok_or_else(child_resolution_error)?,
|
||||
&key,
|
||||
))
|
||||
.map_err(client_err)))
|
||||
}
|
||||
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
.and_then(|block| self.client.child_storage_hash(
|
||||
&BlockId::Hash(block),
|
||||
&child_storage_key,
|
||||
ChildInfo::resolve_child_info(child_type, &child_info.0[..])
|
||||
.ok_or_else(child_resolution_error)?,
|
||||
&key,
|
||||
))
|
||||
.map_err(client_err)))
|
||||
}
|
||||
|
||||
fn metadata(&self, block: Option<Block::Hash>) -> FutureResult<Bytes> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
@@ -493,7 +434,7 @@ impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Cli
|
||||
let block = self.client.info().best_hash;
|
||||
let changes = keys
|
||||
.into_iter()
|
||||
.map(|key| self.storage(Some(block.clone()).into(), key.clone())
|
||||
.map(|key| StateBackend::storage(self, Some(block.clone()).into(), key.clone())
|
||||
.map(|val| (key.clone(), val))
|
||||
.wait()
|
||||
.unwrap_or_else(|_| (key, None))
|
||||
@@ -530,6 +471,82 @@ impl<BE, Block, Client> StateBackend<Block, Client> for FullState<BE, Block, Cli
|
||||
}
|
||||
}
|
||||
|
||||
impl<BE, Block, Client> ChildStateBackend<Block, Client> for FullState<BE, Block, Client> where
|
||||
Block: BlockT + 'static,
|
||||
BE: Backend<Block> + 'static,
|
||||
Client: ExecutorProvider<Block> + StorageProvider<Block, BE> + HeaderBackend<Block>
|
||||
+ HeaderMetadata<Block, Error = sp_blockchain::Error> + BlockchainEvents<Block>
|
||||
+ CallApiAt<Block, Error = sp_blockchain::Error> + ProvideRuntimeApi<Block>
|
||||
+ Send + Sync + 'static,
|
||||
Client::Api: Metadata<Block, Error = sp_blockchain::Error>,
|
||||
{
|
||||
fn storage_keys(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
prefix: StorageKey,
|
||||
) -> FutureResult<Vec<StorageKey>> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
.and_then(|block| {
|
||||
let child_info = match ChildType::from_prefixed_key(&storage_key) {
|
||||
Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key),
|
||||
None => return Err("Invalid child storage key".into()),
|
||||
};
|
||||
self.client.child_storage_keys(
|
||||
&BlockId::Hash(block),
|
||||
&child_info,
|
||||
&prefix,
|
||||
)
|
||||
})
|
||||
.map_err(client_err)))
|
||||
}
|
||||
|
||||
fn storage(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<StorageData>> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
.and_then(|block| {
|
||||
let child_info = match ChildType::from_prefixed_key(&storage_key) {
|
||||
Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key),
|
||||
None => return Err("Invalid child storage key".into()),
|
||||
};
|
||||
self.client.child_storage(
|
||||
&BlockId::Hash(block),
|
||||
&child_info,
|
||||
&key,
|
||||
)
|
||||
})
|
||||
.map_err(client_err)))
|
||||
}
|
||||
|
||||
fn storage_hash(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
Box::new(result(
|
||||
self.block_or_best(block)
|
||||
.and_then(|block| {
|
||||
let child_info = match ChildType::from_prefixed_key(&storage_key) {
|
||||
Some((ChildType::ParentKeyId, storage_key)) => ChildInfo::new_default(storage_key),
|
||||
None => return Err("Invalid child storage key".into()),
|
||||
};
|
||||
self.client.child_storage_hash(
|
||||
&BlockId::Hash(block),
|
||||
&child_info,
|
||||
&key,
|
||||
)
|
||||
})
|
||||
.map_err(client_err)))
|
||||
}
|
||||
}
|
||||
|
||||
/// Splits passed range into two subranges where:
|
||||
/// - first range has at least one element in it;
|
||||
/// - second range (optionally) starts at given `middle` element.
|
||||
|
||||
@@ -48,17 +48,19 @@ use sc_client::{
|
||||
},
|
||||
};
|
||||
use sp_core::{
|
||||
Bytes, OpaqueMetadata, storage::{StorageKey, StorageData, StorageChangeSet},
|
||||
Bytes, OpaqueMetadata,
|
||||
storage::{StorageKey, PrefixedStorageKey, StorageData, StorageChangeSet},
|
||||
};
|
||||
use sp_version::RuntimeVersion;
|
||||
use sp_runtime::{generic::BlockId, traits::{Block as BlockT, HashFor}};
|
||||
|
||||
use super::{StateBackend, error::{FutureResult, Error}, client_err};
|
||||
use super::{StateBackend, ChildStateBackend, error::{FutureResult, Error}, client_err};
|
||||
|
||||
/// Storage data map of storage keys => (optional) storage value.
|
||||
type StorageMap = HashMap<StorageKey, Option<StorageData>>;
|
||||
|
||||
/// State API backend for light nodes.
|
||||
#[derive(Clone)]
|
||||
pub struct LightState<Block: BlockT, F: Fetcher<Block>, Client> {
|
||||
client: Arc<Client>,
|
||||
subscriptions: Subscriptions,
|
||||
@@ -233,69 +235,7 @@ impl<Block, F, Client> StateBackend<Block, Client> for LightState<Block, F, Clie
|
||||
block: Option<Block::Hash>,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
Box::new(self
|
||||
.storage(block, key)
|
||||
.and_then(|maybe_storage|
|
||||
result(Ok(maybe_storage.map(|storage| HashFor::<Block>::hash(&storage.0))))
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fn child_storage_keys(
|
||||
&self,
|
||||
_block: Option<Block::Hash>,
|
||||
_child_storage_key: StorageKey,
|
||||
_child_info: StorageKey,
|
||||
_child_type: u32,
|
||||
_prefix: StorageKey,
|
||||
) -> FutureResult<Vec<StorageKey>> {
|
||||
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
|
||||
}
|
||||
|
||||
fn child_storage(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<StorageData>> {
|
||||
let block = self.block_or_best(block);
|
||||
let fetcher = self.fetcher.clone();
|
||||
let child_storage = resolve_header(&*self.remote_blockchain, &*self.fetcher, block)
|
||||
.then(move |result| match result {
|
||||
Ok(header) => Either::Left(fetcher.remote_read_child(RemoteReadChildRequest {
|
||||
block,
|
||||
header,
|
||||
storage_key: child_storage_key.0,
|
||||
child_info: child_info.0,
|
||||
child_type,
|
||||
keys: vec![key.0.clone()],
|
||||
retry_count: Default::default(),
|
||||
}).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))),
|
||||
});
|
||||
|
||||
Box::new(child_storage.boxed().compat())
|
||||
}
|
||||
|
||||
fn child_storage_hash(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
child_storage_key: StorageKey,
|
||||
child_info: StorageKey,
|
||||
child_type: u32,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
Box::new(self
|
||||
.child_storage(block, child_storage_key, child_info, child_type, key)
|
||||
Box::new(StateBackend::storage(self, block, key)
|
||||
.and_then(|maybe_storage|
|
||||
result(Ok(maybe_storage.map(|storage| HashFor::<Block>::hash(&storage.0))))
|
||||
)
|
||||
@@ -518,6 +458,65 @@ impl<Block, F, Client> StateBackend<Block, Client> for LightState<Block, F, Clie
|
||||
}
|
||||
}
|
||||
|
||||
impl<Block, F, Client> ChildStateBackend<Block, Client> for LightState<Block, F, Client>
|
||||
where
|
||||
Block: BlockT,
|
||||
Client: BlockchainEvents<Block> + HeaderBackend<Block> + Send + Sync + 'static,
|
||||
F: Fetcher<Block> + 'static
|
||||
{
|
||||
fn storage_keys(
|
||||
&self,
|
||||
_block: Option<Block::Hash>,
|
||||
_storage_key: PrefixedStorageKey,
|
||||
_prefix: StorageKey,
|
||||
) -> FutureResult<Vec<StorageKey>> {
|
||||
Box::new(result(Err(client_err(ClientError::NotAvailableOnLightClient))))
|
||||
}
|
||||
|
||||
fn storage(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<StorageData>> {
|
||||
let block = self.block_or_best(block);
|
||||
let fetcher = self.fetcher.clone();
|
||||
let child_storage = resolve_header(&*self.remote_blockchain, &*self.fetcher, block)
|
||||
.then(move |result| match result {
|
||||
Ok(header) => Either::Left(fetcher.remote_read_child(RemoteReadChildRequest {
|
||||
block,
|
||||
header,
|
||||
storage_key,
|
||||
keys: vec![key.0.clone()],
|
||||
retry_count: Default::default(),
|
||||
}).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))),
|
||||
});
|
||||
|
||||
Box::new(child_storage.boxed().compat())
|
||||
}
|
||||
|
||||
fn storage_hash(
|
||||
&self,
|
||||
block: Option<Block::Hash>,
|
||||
storage_key: PrefixedStorageKey,
|
||||
key: StorageKey,
|
||||
) -> FutureResult<Option<Block::Hash>> {
|
||||
Box::new(ChildStateBackend::storage(self, block, storage_key, key)
|
||||
.and_then(|maybe_storage|
|
||||
result(Ok(maybe_storage.map(|storage| HashFor::<Block>::hash(&storage.0))))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve header by hash.
|
||||
fn resolve_header<Block: BlockT, F: Fetcher<Block>>(
|
||||
remote_blockchain: &dyn RemoteBlockchain<Block>,
|
||||
|
||||
@@ -21,7 +21,7 @@ use self::error::Error;
|
||||
use std::sync::Arc;
|
||||
use assert_matches::assert_matches;
|
||||
use futures01::stream::Stream;
|
||||
use sp_core::{storage::{well_known_keys, ChildInfo}, ChangesTrieConfiguration};
|
||||
use sp_core::{storage::ChildInfo, ChangesTrieConfiguration};
|
||||
use sp_core::hash::H256;
|
||||
use sc_block_builder::BlockBuilderProvider;
|
||||
use sp_io::hashing::blake2_256;
|
||||
@@ -32,26 +32,28 @@ use substrate_test_runtime_client::{
|
||||
};
|
||||
use sp_runtime::generic::BlockId;
|
||||
|
||||
const CHILD_INFO: ChildInfo<'static> = ChildInfo::new_default(b"unique_id");
|
||||
const STORAGE_KEY: &[u8] = b"child";
|
||||
|
||||
fn prefixed_storage_key() -> PrefixedStorageKey {
|
||||
let child_info = ChildInfo::new_default(&STORAGE_KEY[..]);
|
||||
child_info.prefixed_storage_key()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn should_return_storage() {
|
||||
const KEY: &[u8] = b":mock";
|
||||
const VALUE: &[u8] = b"hello world";
|
||||
const STORAGE_KEY: &[u8] = b":child_storage:default:child";
|
||||
const CHILD_VALUE: &[u8] = b"hello world !";
|
||||
|
||||
let child_info = ChildInfo::new_default(STORAGE_KEY);
|
||||
let mut core = tokio::runtime::Runtime::new().unwrap();
|
||||
let client = TestClientBuilder::new()
|
||||
.add_extra_storage(KEY.to_vec(), VALUE.to_vec())
|
||||
.add_extra_child_storage(STORAGE_KEY.to_vec(), CHILD_INFO, KEY.to_vec(), CHILD_VALUE.to_vec())
|
||||
.add_extra_child_storage(&child_info, KEY.to_vec(), CHILD_VALUE.to_vec())
|
||||
.build();
|
||||
let genesis_hash = client.genesis_hash();
|
||||
let client = new_full(Arc::new(client), Subscriptions::new(Arc::new(core.executor())));
|
||||
let (client, child) = new_full(Arc::new(client), Subscriptions::new(Arc::new(core.executor())));
|
||||
let key = StorageKey(KEY.to_vec());
|
||||
let storage_key = StorageKey(STORAGE_KEY.to_vec());
|
||||
let (child_info, child_type) = CHILD_INFO.info();
|
||||
let child_info = StorageKey(child_info.to_vec());
|
||||
|
||||
assert_eq!(
|
||||
client.storage(key.clone(), Some(genesis_hash).into()).wait()
|
||||
@@ -69,7 +71,7 @@ fn should_return_storage() {
|
||||
);
|
||||
assert_eq!(
|
||||
core.block_on(
|
||||
client.child_storage(storage_key, child_info, child_type, key, Some(genesis_hash).into())
|
||||
child.storage(prefixed_storage_key(), key, Some(genesis_hash).into())
|
||||
.map(|x| x.map(|x| x.0.len()))
|
||||
).unwrap().unwrap() as usize,
|
||||
CHILD_VALUE.len(),
|
||||
@@ -79,45 +81,36 @@ fn should_return_storage() {
|
||||
|
||||
#[test]
|
||||
fn should_return_child_storage() {
|
||||
let (child_info, child_type) = CHILD_INFO.info();
|
||||
let child_info = StorageKey(child_info.to_vec());
|
||||
let child_info = ChildInfo::new_default(STORAGE_KEY);
|
||||
let core = tokio::runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(substrate_test_runtime_client::TestClientBuilder::new()
|
||||
.add_child_storage("test", "key", CHILD_INFO, vec![42_u8])
|
||||
.add_child_storage(&child_info, "key", vec![42_u8])
|
||||
.build());
|
||||
let genesis_hash = client.genesis_hash();
|
||||
let client = new_full(client, Subscriptions::new(Arc::new(core.executor())));
|
||||
let child_key = StorageKey(
|
||||
well_known_keys::CHILD_STORAGE_KEY_PREFIX.iter().chain(b"test").cloned().collect()
|
||||
);
|
||||
let (_client, child) = new_full(client, Subscriptions::new(Arc::new(core.executor())));
|
||||
let child_key = prefixed_storage_key();
|
||||
let key = StorageKey(b"key".to_vec());
|
||||
|
||||
|
||||
assert_matches!(
|
||||
client.child_storage(
|
||||
child.storage(
|
||||
child_key.clone(),
|
||||
child_info.clone(),
|
||||
child_type,
|
||||
key.clone(),
|
||||
Some(genesis_hash).into(),
|
||||
).wait(),
|
||||
Ok(Some(StorageData(ref d))) if d[0] == 42 && d.len() == 1
|
||||
);
|
||||
assert_matches!(
|
||||
client.child_storage_hash(
|
||||
child.storage_hash(
|
||||
child_key.clone(),
|
||||
child_info.clone(),
|
||||
child_type,
|
||||
key.clone(),
|
||||
Some(genesis_hash).into(),
|
||||
).wait().map(|x| x.is_some()),
|
||||
Ok(true)
|
||||
);
|
||||
assert_matches!(
|
||||
client.child_storage_size(
|
||||
child.storage_size(
|
||||
child_key.clone(),
|
||||
child_info.clone(),
|
||||
child_type,
|
||||
key.clone(),
|
||||
None,
|
||||
).wait(),
|
||||
@@ -130,7 +123,7 @@ fn should_call_contract() {
|
||||
let core = tokio::runtime::Runtime::new().unwrap();
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
let genesis_hash = client.genesis_hash();
|
||||
let client = new_full(client, Subscriptions::new(Arc::new(core.executor())));
|
||||
let (client, _child) = new_full(client, Subscriptions::new(Arc::new(core.executor())));
|
||||
|
||||
assert_matches!(
|
||||
client.call("balanceOf".into(), Bytes(vec![1,2,3]), Some(genesis_hash).into()).wait(),
|
||||
@@ -146,7 +139,7 @@ fn should_notify_about_storage_changes() {
|
||||
|
||||
{
|
||||
let mut client = Arc::new(substrate_test_runtime_client::new());
|
||||
let api = new_full(client.clone(), Subscriptions::new(Arc::new(remote)));
|
||||
let (api, _child) = new_full(client.clone(), Subscriptions::new(Arc::new(remote)));
|
||||
|
||||
api.subscribe_storage(Default::default(), subscriber, None.into());
|
||||
|
||||
@@ -179,7 +172,7 @@ fn should_send_initial_storage_changes_and_notifications() {
|
||||
|
||||
{
|
||||
let mut client = Arc::new(substrate_test_runtime_client::new());
|
||||
let api = new_full(client.clone(), Subscriptions::new(Arc::new(remote)));
|
||||
let (api, _child) = new_full(client.clone(), Subscriptions::new(Arc::new(remote)));
|
||||
|
||||
let alice_balance_key = blake2_256(&runtime::system::balance_of_key(AccountKeyring::Alice.into()));
|
||||
|
||||
@@ -215,7 +208,7 @@ fn should_send_initial_storage_changes_and_notifications() {
|
||||
fn should_query_storage() {
|
||||
fn run_tests(mut client: Arc<TestClient>, has_changes_trie_config: bool) {
|
||||
let core = tokio::runtime::Runtime::new().unwrap();
|
||||
let api = new_full(client.clone(), Subscriptions::new(Arc::new(core.executor())));
|
||||
let (api, _child) = new_full(client.clone(), Subscriptions::new(Arc::new(core.executor())));
|
||||
|
||||
let mut add_block = |nonce| {
|
||||
let mut builder = client.new_block(Default::default()).unwrap();
|
||||
@@ -434,7 +427,7 @@ fn should_return_runtime_version() {
|
||||
let core = tokio::runtime::Runtime::new().unwrap();
|
||||
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
let api = new_full(client.clone(), Subscriptions::new(Arc::new(core.executor())));
|
||||
let (api, _child) = new_full(client.clone(), Subscriptions::new(Arc::new(core.executor())));
|
||||
|
||||
let result = "{\"specName\":\"test\",\"implName\":\"parity-test\",\"authoringVersion\":1,\
|
||||
\"specVersion\":2,\"implVersion\":2,\"apis\":[[\"0xdf6acb689907609b\",3],\
|
||||
@@ -458,7 +451,7 @@ fn should_notify_on_runtime_version_initially() {
|
||||
|
||||
{
|
||||
let client = Arc::new(substrate_test_runtime_client::new());
|
||||
let api = new_full(client.clone(), Subscriptions::new(Arc::new(core.executor())));
|
||||
let (api, _child) = new_full(client.clone(), Subscriptions::new(Arc::new(core.executor())));
|
||||
|
||||
api.subscribe_runtime_version(Default::default(), subscriber);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user